From 745270ab61dde4b939cc77ad10990c316511e6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gauvain=20Boich=C3=A9?= Date: Wed, 1 Apr 2020 16:45:39 +0200 Subject: [PATCH] Essai au propre --- README.rdoc | 0 docs/assets/images/site_logo.gif | Bin 5070 -> 0 bytes ext/planetstyles/flightdeck.zip | Bin 43361 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_1.png | Bin 28002 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_10.png | Bin 29647 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_11.png | Bin 28480 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_12.png | Bin 25368 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_13.png | Bin 24283 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_14.png | Bin 31397 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_15.png | Bin 26727 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_16.png | Bin 26708 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_17.png | Bin 33404 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_18.png | Bin 39634 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_19.png | Bin 34912 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_2.png | Bin 24638 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_20.png | Bin 24624 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_21.png | Bin 26485 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_22.png | Bin 23397 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_23.png | Bin 21885 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_24.png | Bin 31595 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_25.png | Bin 26903 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_26.png | Bin 38414 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_27.png | Bin 35187 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_28.png | Bin 28600 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_29.png | Bin 31705 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_3.png | Bin 25669 -> 0 bytes .../avatars/gallery/Civils_F/Civil_F_30.png | Bin 36515 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_4.png | Bin 29416 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_5.png | Bin 31171 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_6.png | Bin 21893 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_7.png | Bin 22962 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_8.png | Bin 26070 -> 0 bytes images/avatars/gallery/Civils_F/Civil_F_9.png | Bin 24651 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_1.png | Bin 39776 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_10.png | Bin 29858 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_11.png | Bin 30178 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_12.png | Bin 29944 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_13.png | Bin 28112 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_14.png | Bin 30359 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_15.png | Bin 33208 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_16.png | Bin 34696 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_17.png | Bin 29710 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_18.png | Bin 26073 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_19.png | Bin 27502 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_2.png | Bin 31476 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_20.png | Bin 27700 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_21.png | Bin 30390 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_22.png | Bin 28943 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_23.png | Bin 38908 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_24.png | Bin 23529 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_25.png | Bin 25516 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_26.png | Bin 22141 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_27.png | Bin 22517 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_28.png | Bin 25234 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_29.png | Bin 26178 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_3.png | Bin 29066 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_30.png | Bin 21542 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_31.png | Bin 24351 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_32.png | Bin 26200 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_33.png | Bin 26200 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_34.png | Bin 26308 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_35.png | Bin 31532 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_36.png | Bin 31633 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_37.png | Bin 25675 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_38.png | Bin 24881 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_39.png | Bin 25833 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_4.png | Bin 32791 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_40.png | Bin 29933 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_41.png | Bin 28794 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_42.png | Bin 28424 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_43.png | Bin 26458 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_44.png | Bin 24951 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_45.png | Bin 29317 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_46.png | Bin 32232 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_47.png | Bin 34335 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_48.png | Bin 28417 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_49.png | Bin 26641 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_5.png | Bin 22141 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_50.png | Bin 25348 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_51.png | Bin 28063 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_52.png | Bin 30130 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_53.png | Bin 25830 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_54.png | Bin 22756 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_55.png | Bin 253058 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_56.png | Bin 27529 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_57.png | Bin 25147 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_58.png | Bin 22843 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_59.png | Bin 31578 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_6.png | Bin 28336 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_60.png | Bin 35074 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_61.png | Bin 28490 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_62.png | Bin 32800 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_63.png | Bin 31848 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_64.png | Bin 29067 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_65.png | Bin 22843 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_66.png | Bin 21236 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_67.png | Bin 27433 -> 0 bytes .../avatars/gallery/Civils_H/Civil_H_68.png | Bin 26322 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_7.png | Bin 26069 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_8.png | Bin 34291 -> 0 bytes images/avatars/gallery/Civils_H/Civil_H_9.png | Bin 31713 -> 0 bytes images/avatars/gallery/Flics/Flic_1.png | Bin 27703 -> 0 bytes images/avatars/gallery/Flics/Flic_10.png | Bin 26256 -> 0 bytes images/avatars/gallery/Flics/Flic_100.png | Bin 28343 -> 0 bytes images/avatars/gallery/Flics/Flic_101.png | Bin 25702 -> 0 bytes images/avatars/gallery/Flics/Flic_102.png | Bin 26654 -> 0 bytes images/avatars/gallery/Flics/Flic_103.png | Bin 25241 -> 0 bytes images/avatars/gallery/Flics/Flic_104.png | Bin 26302 -> 0 bytes images/avatars/gallery/Flics/Flic_105.png | Bin 28477 -> 0 bytes images/avatars/gallery/Flics/Flic_106.png | Bin 24788 -> 0 bytes images/avatars/gallery/Flics/Flic_107.png | Bin 26659 -> 0 bytes images/avatars/gallery/Flics/Flic_108.png | Bin 26662 -> 0 bytes images/avatars/gallery/Flics/Flic_109.png | Bin 24912 -> 0 bytes images/avatars/gallery/Flics/Flic_110.png | Bin 26045 -> 0 bytes images/avatars/gallery/Flics/Flic_13.png | Bin 27912 -> 0 bytes images/avatars/gallery/Flics/Flic_14.png | Bin 29262 -> 0 bytes images/avatars/gallery/Flics/Flic_15.png | Bin 25190 -> 0 bytes images/avatars/gallery/Flics/Flic_16.png | Bin 27242 -> 0 bytes images/avatars/gallery/Flics/Flic_19.png | Bin 27603 -> 0 bytes images/avatars/gallery/Flics/Flic_2.png | Bin 26229 -> 0 bytes images/avatars/gallery/Flics/Flic_20.png | Bin 27006 -> 0 bytes images/avatars/gallery/Flics/Flic_21.png | Bin 28582 -> 0 bytes images/avatars/gallery/Flics/Flic_22.png | Bin 29062 -> 0 bytes images/avatars/gallery/Flics/Flic_25.png | Bin 28908 -> 0 bytes images/avatars/gallery/Flics/Flic_27.png | Bin 26950 -> 0 bytes images/avatars/gallery/Flics/Flic_28.png | Bin 29572 -> 0 bytes images/avatars/gallery/Flics/Flic_30.png | Bin 26073 -> 0 bytes images/avatars/gallery/Flics/Flic_31.png | Bin 31208 -> 0 bytes images/avatars/gallery/Flics/Flic_32.png | Bin 31051 -> 0 bytes images/avatars/gallery/Flics/Flic_33.png | Bin 30825 -> 0 bytes images/avatars/gallery/Flics/Flic_34.png | Bin 26494 -> 0 bytes images/avatars/gallery/Flics/Flic_35.png | Bin 29280 -> 0 bytes images/avatars/gallery/Flics/Flic_36.png | Bin 28283 -> 0 bytes images/avatars/gallery/Flics/Flic_38.png | Bin 25143 -> 0 bytes images/avatars/gallery/Flics/Flic_39.png | Bin 26041 -> 0 bytes images/avatars/gallery/Flics/Flic_4.png | Bin 25548 -> 0 bytes images/avatars/gallery/Flics/Flic_40.png | Bin 23879 -> 0 bytes images/avatars/gallery/Flics/Flic_41.png | Bin 22533 -> 0 bytes images/avatars/gallery/Flics/Flic_43.png | Bin 25130 -> 0 bytes images/avatars/gallery/Flics/Flic_44.png | Bin 26536 -> 0 bytes images/avatars/gallery/Flics/Flic_45.png | Bin 24581 -> 0 bytes images/avatars/gallery/Flics/Flic_46.png | Bin 27626 -> 0 bytes images/avatars/gallery/Flics/Flic_47.png | Bin 25355 -> 0 bytes images/avatars/gallery/Flics/Flic_48.png | Bin 27662 -> 0 bytes images/avatars/gallery/Flics/Flic_49.png | Bin 26357 -> 0 bytes images/avatars/gallery/Flics/Flic_5.png | Bin 24127 -> 0 bytes images/avatars/gallery/Flics/Flic_50.png | Bin 26392 -> 0 bytes images/avatars/gallery/Flics/Flic_51.png | Bin 26618 -> 0 bytes images/avatars/gallery/Flics/Flic_52.png | Bin 25772 -> 0 bytes images/avatars/gallery/Flics/Flic_53.png | Bin 25652 -> 0 bytes images/avatars/gallery/Flics/Flic_54.png | Bin 27193 -> 0 bytes images/avatars/gallery/Flics/Flic_55.png | Bin 29978 -> 0 bytes images/avatars/gallery/Flics/Flic_56.png | Bin 29812 -> 0 bytes images/avatars/gallery/Flics/Flic_57.png | Bin 26344 -> 0 bytes images/avatars/gallery/Flics/Flic_58.png | Bin 27565 -> 0 bytes images/avatars/gallery/Flics/Flic_59.png | Bin 26791 -> 0 bytes images/avatars/gallery/Flics/Flic_6.png | Bin 26867 -> 0 bytes images/avatars/gallery/Flics/Flic_60.png | Bin 28278 -> 0 bytes images/avatars/gallery/Flics/Flic_61.png | Bin 28026 -> 0 bytes images/avatars/gallery/Flics/Flic_62.png | Bin 27674 -> 0 bytes images/avatars/gallery/Flics/Flic_64.png | Bin 28815 -> 0 bytes images/avatars/gallery/Flics/Flic_65.png | Bin 28728 -> 0 bytes images/avatars/gallery/Flics/Flic_66.png | Bin 29297 -> 0 bytes images/avatars/gallery/Flics/Flic_67.png | Bin 25499 -> 0 bytes images/avatars/gallery/Flics/Flic_68.png | Bin 25838 -> 0 bytes images/avatars/gallery/Flics/Flic_69.png | Bin 26686 -> 0 bytes images/avatars/gallery/Flics/Flic_7.png | Bin 26650 -> 0 bytes images/avatars/gallery/Flics/Flic_70.png | Bin 28059 -> 0 bytes images/avatars/gallery/Flics/Flic_71.png | Bin 29811 -> 0 bytes images/avatars/gallery/Flics/Flic_72.png | Bin 30051 -> 0 bytes images/avatars/gallery/Flics/Flic_73.png | Bin 29596 -> 0 bytes images/avatars/gallery/Flics/Flic_74.png | Bin 30076 -> 0 bytes images/avatars/gallery/Flics/Flic_75.png | Bin 30144 -> 0 bytes images/avatars/gallery/Flics/Flic_76.png | Bin 29251 -> 0 bytes images/avatars/gallery/Flics/Flic_77.png | Bin 30882 -> 0 bytes images/avatars/gallery/Flics/Flic_78.png | Bin 28588 -> 0 bytes images/avatars/gallery/Flics/Flic_79.png | Bin 27808 -> 0 bytes images/avatars/gallery/Flics/Flic_8.png | Bin 25254 -> 0 bytes images/avatars/gallery/Flics/Flic_80.png | Bin 31215 -> 0 bytes images/avatars/gallery/Flics/Flic_81.png | Bin 30352 -> 0 bytes images/avatars/gallery/Flics/Flic_82.png | Bin 25395 -> 0 bytes images/avatars/gallery/Flics/Flic_83.png | Bin 28602 -> 0 bytes images/avatars/gallery/Flics/Flic_84.png | Bin 26143 -> 0 bytes images/avatars/gallery/Flics/Flic_85.png | Bin 24857 -> 0 bytes images/avatars/gallery/Flics/Flic_86.png | Bin 27275 -> 0 bytes images/avatars/gallery/Flics/Flic_87.png | Bin 27500 -> 0 bytes images/avatars/gallery/Flics/Flic_88.png | Bin 28368 -> 0 bytes images/avatars/gallery/Flics/Flic_89.png | Bin 28675 -> 0 bytes images/avatars/gallery/Flics/Flic_9.png | Bin 26612 -> 0 bytes images/avatars/gallery/Flics/Flic_90.png | Bin 26295 -> 0 bytes images/avatars/gallery/Flics/Flic_91.png | Bin 24165 -> 0 bytes images/avatars/gallery/Flics/Flic_92.png | Bin 24806 -> 0 bytes images/avatars/gallery/Flics/Flic_93.png | Bin 27376 -> 0 bytes images/avatars/gallery/Flics/Flic_94.png | Bin 26494 -> 0 bytes images/avatars/gallery/Flics/Flic_95.png | Bin 28121 -> 0 bytes images/avatars/gallery/Flics/Flic_96.png | Bin 24175 -> 0 bytes images/avatars/gallery/Flics/Flic_97.png | Bin 26858 -> 0 bytes images/avatars/gallery/Flics/Flic_98.png | Bin 24449 -> 0 bytes images/avatars/gallery/Flics/Flic_99.png | Bin 27794 -> 0 bytes includes/functions.php | 15 +- install/update/index.php | 395 -- install/update/new/.htaccess | 92 - install/update/new/adm/images/alert_close.png | Bin 2097 -> 0 bytes install/update/new/adm/images/arrow_down.gif | Bin 51 -> 0 bytes install/update/new/adm/images/arrow_left.gif | Bin 49 -> 0 bytes install/update/new/adm/images/arrow_right.gif | Bin 49 -> 0 bytes install/update/new/adm/images/arrow_up.gif | Bin 51 -> 0 bytes install/update/new/adm/images/bg_button.gif | Bin 182 -> 0 bytes install/update/new/adm/images/bg_hash1.gif | Bin 48 -> 0 bytes install/update/new/adm/images/bg_hash2.gif | Bin 48 -> 0 bytes install/update/new/adm/images/bg_hash3.gif | Bin 48 -> 0 bytes install/update/new/adm/images/bg_hash4.gif | Bin 48 -> 0 bytes install/update/new/adm/images/bg_header.gif | Bin 416 -> 0 bytes install/update/new/adm/images/bg_header.jpg | Bin 385 -> 0 bytes .../update/new/adm/images/bg_tabs_alt1.gif | Bin 1520 -> 0 bytes .../update/new/adm/images/bg_tabs_alt2.gif | Bin 420 -> 0 bytes install/update/new/adm/images/cellpic3.gif | Bin 826 -> 0 bytes .../update/new/adm/images/file_conflict.gif | Bin 344 -> 0 bytes .../update/new/adm/images/file_modified.gif | Bin 358 -> 0 bytes install/update/new/adm/images/file_new.gif | Bin 229 -> 0 bytes .../new/adm/images/file_new_conflict.gif | Bin 357 -> 0 bytes .../new/adm/images/file_not_modified.gif | Bin 570 -> 0 bytes .../update/new/adm/images/file_up_to_date.gif | Bin 357 -> 0 bytes install/update/new/adm/images/gradient2b.gif | Bin 192 -> 0 bytes install/update/new/adm/images/icon_delete.gif | Bin 255 -> 0 bytes .../new/adm/images/icon_delete_disabled.gif | Bin 249 -> 0 bytes install/update/new/adm/images/icon_down.gif | Bin 239 -> 0 bytes .../new/adm/images/icon_down_disabled.gif | Bin 166 -> 0 bytes install/update/new/adm/images/icon_edit.gif | Bin 242 -> 0 bytes .../new/adm/images/icon_edit_disabled.gif | Bin 239 -> 0 bytes install/update/new/adm/images/icon_folder.gif | Bin 662 -> 0 bytes .../new/adm/images/icon_folder_link.gif | Bin 708 -> 0 bytes .../new/adm/images/icon_folder_lock.gif | Bin 681 -> 0 bytes .../update/new/adm/images/icon_subfolder.gif | Bin 725 -> 0 bytes install/update/new/adm/images/icon_sync.gif | Bin 251 -> 0 bytes .../new/adm/images/icon_sync_disabled.gif | Bin 246 -> 0 bytes install/update/new/adm/images/icon_trace.gif | Bin 307 -> 0 bytes install/update/new/adm/images/icon_up.gif | Bin 240 -> 0 bytes .../new/adm/images/icon_up_disabled.gif | Bin 168 -> 0 bytes install/update/new/adm/images/innerbox_bg.gif | Bin 1980 -> 0 bytes install/update/new/adm/images/loading.gif | Bin 1320 -> 0 bytes install/update/new/adm/images/no_avatar.gif | Bin 930 -> 0 bytes install/update/new/adm/images/no_image.png | Bin 401 -> 0 bytes install/update/new/adm/images/phpbb_logo.png | Bin 6662 -> 0 bytes install/update/new/adm/images/phpbb_logo.svg | 6 - .../update/new/adm/images/progress_bar.gif | Bin 1353 -> 0 bytes install/update/new/adm/images/spacer.gif | Bin 807 -> 0 bytes install/update/new/adm/index.php | 90 - .../update/new/adm/style/acp_attachments.html | 495 -- .../adm/style/acp_avatar_options_upload.html | 11 - install/update/new/adm/style/acp_ban.html | 131 - install/update/new/adm/style/acp_contact.html | 76 - .../update/new/adm/style/acp_database.html | 90 - .../update/new/adm/style/acp_ext_actions.html | 7 - .../update/new/adm/style/acp_ext_list.html | 114 - install/update/new/adm/style/acp_forums.html | 524 -- install/update/new/adm/style/acp_groups.html | 335 -- .../update/new/adm/style/acp_help_phpbb.html | 67 - install/update/new/adm/style/acp_icons.html | 282 - .../update/new/adm/style/acp_language.html | 116 - install/update/new/adm/style/acp_main.html | 339 -- install/update/new/adm/style/acp_modules.html | 203 - .../new/adm/style/acp_permission_roles.html | 191 - .../new/adm/style/acp_posting_buttons.html | 50 - install/update/new/adm/style/acp_ranks.html | 107 - install/update/new/adm/style/acp_search.html | 159 - install/update/new/adm/style/acp_styles.html | 178 - .../new/adm/style/acp_users_overview.html | 169 - .../update/new/adm/style/acp_users_prefs.html | 151 - .../new/adm/style/acp_users_signature.html | 52 - install/update/new/adm/style/admin.css | 2736 --------- install/update/new/adm/style/admin.js | 316 -- install/update/new/adm/style/ajax.js | 360 -- .../new/adm/style/captcha_recaptcha.html | 15 - .../new/adm/style/installer_convert.html | 87 - .../new/adm/style/installer_footer.html | 32 - .../update/new/adm/style/installer_form.html | 57 - .../new/adm/style/installer_header.html | 58 - .../new/adm/style/installer_install.html | 13 - .../update/new/adm/style/installer_main.html | 6 - .../new/adm/style/installer_update.html | 13 - .../style/installer_update_file_status.html | 80 - .../update/new/adm/style/overall_footer.html | 46 - .../update/new/adm/style/overall_header.html | 157 - .../new/adm/style/permission_forum_copy.html | 40 - .../update/new/adm/style/permission_mask.html | 152 - install/update/new/adm/style/permissions.js | 304 - .../update/new/adm/style/progress_bar.html | 40 - .../update/new/adm/style/simple_footer.html | 27 - .../update/new/adm/style/simple_header.html | 96 - .../cookieconsent/cookieconsent.min.css | 6 - .../assets/cookieconsent/cookieconsent.min.js | 1 - install/update/new/assets/javascript/core.js | 1823 ------ .../update/new/assets/javascript/editor.js | 418 -- .../update/new/assets/javascript/installer.js | 615 -- .../new/assets/javascript/jquery-3.4.1.min.js | 2 - .../update/new/assets/javascript/plupload.js | 714 --- install/update/new/common.php | 166 - install/update/new/composer.json | 76 - install/update/new/composer.lock | 4410 --------------- install/update/new/config/default/config.yml | 1 - .../config/default/container/parameters.yml | 22 - .../new/config/default/container/services.yml | 176 - .../default/container/services_attachment.yml | 40 - .../default/container/services_auth.yml | 110 - .../default/container/services_avatar.yml | 73 - .../default/container/services_captcha.yml | 59 - .../default/container/services_console.yml | 287 - .../default/container/services_content.yml | 73 - .../default/container/services_cron.yml | 248 - .../config/default/container/services_db.yml | 71 - .../default/container/services_event.yml | 26 - .../default/container/services_feed.yml | 126 - .../default/container/services_files.yml | 57 - .../default/container/services_filesystem.yml | 3 - .../default/container/services_help.yml | 27 - .../default/container/services_hook.yml | 7 - .../default/container/services_http.yml | 23 - .../default/container/services_language.yml | 22 - .../default/container/services_migrator.yml | 64 - .../container/services_mimetype_guesser.yml | 36 - .../default/container/services_module.yml | 10 - .../container/services_notification.yml | 224 - .../default/container/services_password.yml | 156 - .../config/default/container/services_php.yml | 3 - .../container/services_profilefield.yml | 102 - .../default/container/services_report.yml | 53 - .../default/container/services_routing.yml | 77 - .../container/services_text_formatter.yml | 84 - .../container/services_text_reparser.yml | 109 - .../default/container/services_twig.yml | 86 - .../config/default/container/services_ucp.yml | 17 - .../default/container/services_user.yml | 20 - .../new/config/default/container/tables.yml | 78 - .../new/config/default/routing/cron.yml | 3 - .../new/config/default/routing/feed.yml | 35 - .../new/config/default/routing/help.yml | 7 - .../new/config/default/routing/report.yml | 17 - .../new/config/default/routing/routing.yml | 32 - .../update/new/config/default/routing/ucp.yml | 7 - .../update/new/config/installer/config.yml | 2 - .../installer/container/environment.yml | 3 - .../config/installer/container/parameters.yml | 5 - .../config/installer/container/services.yml | 104 - .../container/services_file_updater.yml | 38 - .../container/services_install_console.yml | 61 - .../container/services_install_controller.yml | 73 - .../container/services_install_data.yml | 55 - .../container/services_install_database.yml | 71 - .../container/services_install_filesystem.yml | 28 - .../container/services_install_finish.yml | 44 - .../container/services_install_navigation.yml | 42 - .../services_install_obtain_data.yml | 59 - .../services_install_requirements.yml | 37 - .../container/services_installer.yml | 119 - .../container/services_update_database.yml | 40 - .../container/services_update_filesystem.yml | 72 - .../container/services_update_obtain_data.yml | 53 - .../services_update_requirements.yml | 41 - .../config/installer/routing/environment.yml | 2 - .../config/installer/routing/installer.yml | 67 - .../update/new/config/production/config.yml | 2 - .../production/container/environment.yml | 3 - .../production/container/parameters.yml | 2 - .../config/production/container/services.yml | 2 - .../config/production/routing/environment.yml | 2 - install/update/new/cron.php | 37 - install/update/new/download/file.php | 321 -- .../ext/phpbb/viglink/acp/viglink_helper.php | 147 - .../new/ext/phpbb/viglink/composer.json | 27 - .../new/ext/phpbb/viglink/composer.lock | 2443 -------- .../viglink/styles/all/theme/viglink.css | 18 - install/update/new/feed.php | 58 - .../new/includes/acp/acp_attachments.php | 1730 ------ .../update/new/includes/acp/acp_bbcodes.php | 480 -- install/update/new/includes/acp/acp_board.php | 1172 ---- .../update/new/includes/acp/acp_database.php | 616 -- .../new/includes/acp/acp_extensions.php | 771 --- .../update/new/includes/acp/acp_forums.php | 2211 -------- .../new/includes/acp/acp_help_phpbb.php | 146 - install/update/new/includes/acp/acp_main.php | 707 --- .../new/includes/acp/acp_permissions.php | 1346 ----- install/update/new/includes/acp/acp_prune.php | 588 -- .../update/new/includes/acp/acp_reasons.php | 392 -- .../update/new/includes/acp/acp_styles.php | 1396 ----- .../update/new/includes/acp/acp_update.php | 88 - install/update/new/includes/acp/acp_users.php | 2689 --------- install/update/new/includes/acp/auth.php | 1316 ----- install/update/new/includes/bbcode.php | 707 --- .../new/includes/compatibility_globals.php | 92 - install/update/new/includes/constants.php | 312 -- install/update/new/includes/diff/engine.php | 557 -- install/update/new/includes/functions.php | 4630 --------------- install/update/new/includes/functions_acp.php | 727 --- .../update/new/includes/functions_admin.php | 3096 ----------- .../new/includes/functions_compatibility.php | 675 --- .../new/includes/functions_compress.php | 830 --- .../update/new/includes/functions_content.php | 1788 ------ .../update/new/includes/functions_convert.php | 2500 --------- .../update/new/includes/functions_display.php | 1725 ------ .../new/includes/functions_download.php | 782 --- .../new/includes/functions_messenger.php | 1935 ------- .../update/new/includes/functions_module.php | 1153 ---- .../update/new/includes/functions_posting.php | 2804 ---------- .../new/includes/functions_privmsgs.php | 2303 -------- .../new/includes/functions_transfer.php | 899 --- .../update/new/includes/functions_user.php | 3757 ------------- install/update/new/includes/mcp/mcp_ban.php | 301 - install/update/new/includes/mcp/mcp_logs.php | 230 - install/update/new/includes/mcp/mcp_main.php | 1717 ------ install/update/new/includes/mcp/mcp_notes.php | 258 - install/update/new/includes/mcp/mcp_topic.php | 834 --- install/update/new/includes/mcp/mcp_warn.php | 610 -- .../update/new/includes/message_parser.php | 2087 ------- .../includes/questionnaire/questionnaire.php | 497 -- install/update/new/includes/startup.php | 86 - .../new/includes/ucp/ucp_attachments.php | 219 - .../update/new/includes/ucp/ucp_groups.php | 1142 ---- install/update/new/includes/ucp/ucp_pm.php | 442 -- .../new/includes/ucp/ucp_pm_compose.php | 1562 ------ .../new/includes/ucp/ucp_pm_viewfolder.php | 611 -- .../update/new/includes/ucp/ucp_profile.php | 847 --- .../update/new/includes/ucp/ucp_register.php | 738 --- .../update/new/includes/ucp/ucp_resend.php | 163 - install/update/new/includes/utf/utf_tools.php | 1469 ----- install/update/new/index.php | 252 - .../new/language/en/acp/attachments.php | 167 - install/update/new/language/en/acp/board.php | 635 --- install/update/new/language/en/acp/common.php | 823 --- install/update/new/language/en/acp/forums.php | 168 - .../new/language/en/acp/permissions.php | 287 - .../new/language/en/acp/permissions_phpbb.php | 215 - .../update/new/language/en/acp/posting.php | 291 - .../update/new/language/en/acp/profile.php | 176 - install/update/new/language/en/acp/styles.php | 91 - .../new/language/en/captcha_recaptcha.php | 52 - install/update/new/language/en/cli.php | 175 - install/update/new/language/en/common.php | 1453 ----- .../new/language/en/email/admin_activate.txt | 13 - .../en/email/user_forgot_password.txt | 13 - install/update/new/language/en/install.php | 598 -- install/update/new/language/en/migrator.php | 81 - install/update/new/language/en/posting.php | 287 - install/update/new/language/en/ucp.php | 666 --- install/update/new/mcp.php | 331 -- install/update/new/memberlist.php | 1852 ------ .../update/new/phpbb/auth/provider/apache.php | 285 - .../update/new/phpbb/auth/provider/base.php | 108 - install/update/new/phpbb/auth/provider/db.php | 259 - .../update/new/phpbb/auth/provider/ldap.php | 359 -- .../new/phpbb/auth/provider/oauth/oauth.php | 859 --- .../auth/provider/oauth/service/base.php | 59 - .../auth/provider/oauth/service/bitly.php | 107 - .../auth/provider/oauth/service/facebook.php | 107 - .../auth/provider/oauth/service/google.php | 118 - .../oauth/service/service_interface.php | 85 - .../auth/provider/oauth/service/twitter.php | 111 - .../auth/provider/oauth/token_storage.php | 620 --- .../auth/provider/provider_interface.php | 198 - .../update/new/phpbb/avatar/driver/remote.php | 236 - .../update/new/phpbb/avatar/driver/upload.php | 332 -- .../new/phpbb/cache/driver/memcached.php | 148 - .../update/new/phpbb/cache/driver/memory.php | 282 - install/update/new/phpbb/captcha/non_gd.php | 386 -- .../update/new/phpbb/captcha/plugins/qa.php | 1040 ---- install/update/new/phpbb/class_loader.php | 164 - install/update/new/phpbb/config/config.php | 186 - install/update/new/phpbb/config_php_file.php | 166 - .../new/phpbb/console/command/cron/run.php | 173 - .../console/command/extension/enable.php | 78 - .../phpbb/console/command/update/check.php | 332 -- .../new/phpbb/console/command/user/add.php | 334 -- .../update/new/phpbb/content_visibility.php | 899 --- .../update/new/phpbb/controller/helper.php | 195 - .../update/new/phpbb/cron/controller/cron.php | 40 - .../phpbb/cron/event/cron_runner_listener.php | 103 - install/update/new/phpbb/cron/manager.php | 164 - .../phpbb/cron/task/core/update_hashes.php | 130 - .../update/new/phpbb/cron/task/wrapper.php | 117 - install/update/new/phpbb/db/driver/driver.php | 1246 ----- .../new/phpbb/db/driver/driver_interface.php | 467 -- .../update/new/phpbb/db/driver/factory.php | 459 -- .../update/new/phpbb/db/driver/mssql_odbc.php | 384 -- .../new/phpbb/db/driver/mssqlnative.php | 450 -- install/update/new/phpbb/db/driver/mysqli.php | 492 -- install/update/new/phpbb/db/driver/oracle.php | 821 --- .../update/new/phpbb/db/driver/postgres.php | 500 -- .../update/new/phpbb/db/driver/sqlite3.php | 430 -- .../phpbb/db/extractor/mysql_extractor.php | 301 - .../migration/data/v30x/release_3_0_4_rc1.php | 129 - .../db/migration/data/v310/softdelete_p1.php | 211 - .../db/migration/data/v32x/timezone_p3.php | 29 - .../data/v32x/user_emoji_permission.php | 44 - .../new/phpbb/db/migration/data/v32x/v328.php | 36 - .../phpbb/db/migration/data/v32x/v328rc1.php | 37 - .../new/phpbb/db/migration/data/v32x/v329.php | 37 - .../phpbb/db/migration/data/v32x/v329rc1.php | 36 - .../add_display_unapproved_posts_config.php | 34 - .../new/phpbb/db/migration/data/v330/dev.php | 36 - .../data/v330/forums_legend_limit.php | 49 - .../db/migration/data/v330/jquery_update.php | 37 - .../data/v330/remove_attachment_flash.php | 89 - .../migration/data/v330/remove_email_hash.php | 62 - .../data/v330/remove_max_pass_chars.php | 43 - .../db/migration/data/v330/reset_password.php | 48 - .../new/phpbb/db/migration/data/v330/v330.php | 37 - .../phpbb/db/migration/data/v330/v330b1.php | 41 - .../phpbb/db/migration/data/v330/v330b2.php | 39 - .../phpbb/db/migration/data/v330/v330rc1.php | 36 - .../new/phpbb/db/migration/tool/module.php | 556 -- install/update/new/phpbb/db/migrator.php | 1037 ---- install/update/new/phpbb/db/tools/mssql.php | 880 --- .../update/new/phpbb/db/tools/postgres.php | 614 -- install/update/new/phpbb/db/tools/tools.php | 1879 ------- .../update/new/phpbb/di/container_builder.php | 678 --- .../di/extension/container_configuration.php | 63 - .../update/new/phpbb/di/extension/core.php | 132 - .../update/new/phpbb/di/extension/tables.php | 59 - .../new/phpbb/di/service_collection.php | 122 - .../update/new/phpbb/event/md_exporter.php | 568 -- .../phpbb/extension/extension_interface.php | 71 - .../update/new/phpbb/extension/manager.php | 591 -- .../update/new/phpbb/feed/controller/feed.php | 410 -- .../update/new/phpbb/feed/topics_active.php | 147 - install/update/new/phpbb/files/filespec.php | 584 -- install/update/new/phpbb/filesystem.php | 21 - .../new/phpbb/filesystem/filesystem.php | 916 --- .../phpbb/filesystem/filesystem_interface.php | 284 - install/update/new/phpbb/finder.php | 547 -- install/update/new/phpbb/group/helper.php | 294 - .../new/phpbb/help/controller/bbcode.php | 90 - .../update/new/phpbb/help/controller/faq.php | 170 - .../new/phpbb/install/controller/helper.php | 413 -- .../install/helper/container_factory.php | 191 - .../new/phpbb/install/helper/database.php | 421 -- .../helper/iohandler/iohandler_interface.php | 222 - .../phpbb/install/installer_configuration.php | 146 - .../task/add_config_settings.php | 367 -- .../install_database/task/create_schema.php | 227 - .../install_database/task/set_up_database.php | 157 - .../task/create_config_file.php | 243 - .../task/check_server_environment.php | 207 - .../update/new/phpbb/install/module_base.php | 213 - .../phpbb/language/language_file_loader.php | 207 - install/update/new/phpbb/lock/db.php | 153 - install/update/new/phpbb/lock/flock.php | 144 - install/update/new/phpbb/message/form.php | 175 - install/update/new/phpbb/mimetype/guesser.php | 156 - .../phpbb/notification/type/approve_post.php | 146 - .../phpbb/notification/type/approve_topic.php | 137 - .../new/phpbb/notification/type/base.php | 577 -- .../new/phpbb/notification/type/post.php | 467 -- .../new/phpbb/notification/type/topic.php | 307 - .../notification/type/type_interface.php | 218 - .../new/phpbb/passwords/driver/argon2i.php | 78 - .../new/phpbb/passwords/driver/argon2id.php | 33 - .../phpbb/passwords/driver/base_native.php | 75 - .../update/new/phpbb/passwords/manager.php | 407 -- install/update/new/phpbb/permissions.php | 365 -- .../update/new/phpbb/plupload/plupload.php | 417 -- .../new/phpbb/report/report_handler.php | 104 - install/update/new/phpbb/request/request.php | 454 -- .../new/phpbb/request/request_interface.php | 177 - .../new/phpbb/request/type_cast_helper.php | 125 - .../new/phpbb/search/fulltext_mysql.php | 1220 ---- .../new/phpbb/search/fulltext_native.php | 2068 ------- .../new/phpbb/search/fulltext_postgres.php | 1178 ---- .../new/phpbb/search/fulltext_sphinx.php | 993 ---- install/update/new/phpbb/session.php | 1667 ------ install/update/new/phpbb/template/asset.php | 203 - install/update/new/phpbb/template/context.php | 631 --- .../update/new/phpbb/template/template.php | 224 - .../new/phpbb/template/twig/extension.php | 201 - .../phpbb/template/twig/extension/avatar.php | 80 - .../phpbb/template/twig/extension/config.php | 64 - .../template/twig/extension/username.php | 84 - .../update/new/phpbb/template/twig/lexer.php | 358 -- .../update/new/phpbb/template/twig/loader.php | 176 - .../phpbb/template/twig/node/definenode.php | 57 - .../phpbb/template/twig/node/includeasset.php | 65 - .../phpbb/template/twig/node/includephp.php | 91 - .../twig/tokenparser/defineparser.php | 76 - .../phpbb/template/twig/tokenparser/event.php | 57 - .../template/twig/tokenparser/includecss.php | 44 - .../template/twig/tokenparser/includejs.php | 44 - .../twig/tokenparser/includeparser.php | 44 - .../template/twig/tokenparser/includephp.php | 68 - .../phpbb/template/twig/tokenparser/php.php | 65 - .../textformatter/acp_utils_interface.php | 54 - .../new/phpbb/textformatter/s9e/acp_utils.php | 67 - .../phpbb/textformatter/s9e/bbcode_merger.php | 199 - .../new/phpbb/textformatter/s9e/factory.php | 678 --- .../phpbb/textformatter/s9e/link_helper.php | 115 - .../new/phpbb/textformatter/s9e/parser.php | 417 -- .../phpbb/textformatter/s9e/quote_helper.php | 87 - .../phpbb/ucp/controller/reset_password.php | 443 -- install/update/new/phpbb/user.php | 848 --- install/update/new/phpbb/user_loader.php | 238 - install/update/new/posting.php | 2041 ------- install/update/new/report.php | 41 - install/update/new/search.php | 1569 ------ install/update/new/styles/prosilver/style.cfg | 32 - .../styles/prosilver/template/attachment.html | 35 - .../new/styles/prosilver/template/bbcode.html | 79 - .../prosilver/template/captcha_recaptcha.html | 9 - .../new/styles/prosilver/template/forum_fn.js | 937 ---- .../prosilver/template/forumlist_body.html | 137 - .../styles/prosilver/template/mcp_forum.html | 155 - .../styles/prosilver/template/mcp_move.html | 73 - .../styles/prosilver/template/mcp_topic.html | 202 - .../prosilver/template/memberlist_body.html | 190 - .../prosilver/template/memberlist_search.html | 87 - .../prosilver/template/navbar_header.html | 212 - .../prosilver/template/overall_footer.html | 120 - .../prosilver/template/overall_header.html | 133 - .../styles/prosilver/template/plupload.html | 75 - .../template/posting_attach_body.html | 93 - .../prosilver/template/posting_buttons.html | 105 - .../prosilver/template/posting_layout.html | 65 - .../prosilver/template/posting_poll_body.html | 53 - .../prosilver/template/posting_review.html | 44 - .../template/posting_topic_review.html | 89 - .../prosilver/template/search_results.html | 244 - .../prosilver/template/simple_footer.html | 40 - .../prosilver/template/ucp_agreement.html | 72 - .../prosilver/template/ucp_attachments.html | 83 - .../template/ucp_avatar_options_upload.html | 11 - .../prosilver/template/ucp_groups_manage.html | 247 - .../prosilver/template/ucp_pm_history.html | 56 - .../template/ucp_pm_viewmessage_print.html | 57 - .../template/ucp_profile_profile_info.html | 51 - .../prosilver/template/ucp_register.html | 117 - .../template/ucp_reset_password.html | 49 - .../prosilver/template/viewforum_body.html | 315 -- .../prosilver/template/viewtopic_body.html | 459 -- .../prosilver/template/viewtopic_print.html | 53 - .../new/styles/prosilver/theme/colours.css | 1168 ---- .../new/styles/prosilver/theme/common.css | 1288 ----- .../new/styles/prosilver/theme/forms.css | 429 -- .../new/styles/prosilver/theme/icons.css | 96 - .../prosilver/theme/images/site_logo.svg | 6 - .../new/styles/prosilver/theme/plupload.css | 90 - .../new/styles/prosilver/theme/print.css | 150 - .../new/styles/prosilver/theme/stylesheet.css | 21 - install/update/new/ucp.php | 413 -- install/update/new/viewforum.php | 1064 ---- install/update/new/viewonline.php | 522 -- install/update/new/viewtopic.php | 2427 -------- install/update/old/.htaccess | 85 - install/update/old/adm/index.php | 91 - .../update/old/adm/style/acp_attachments.html | 487 -- .../adm/style/acp_avatar_options_upload.html | 11 - install/update/old/adm/style/acp_ban.html | 131 - install/update/old/adm/style/acp_contact.html | 76 - .../update/old/adm/style/acp_database.html | 96 - .../update/old/adm/style/acp_ext_list.html | 123 - install/update/old/adm/style/acp_forums.html | 519 -- install/update/old/adm/style/acp_groups.html | 333 -- .../update/old/adm/style/acp_help_phpbb.html | 61 - install/update/old/adm/style/acp_icons.html | 282 - .../update/old/adm/style/acp_language.html | 116 - install/update/old/adm/style/acp_main.html | 312 -- install/update/old/adm/style/acp_modules.html | 203 - .../old/adm/style/acp_permission_roles.html | 191 - .../old/adm/style/acp_posting_buttons.html | 71 - install/update/old/adm/style/acp_ranks.html | 107 - install/update/old/adm/style/acp_search.html | 159 - install/update/old/adm/style/acp_styles.html | 176 - .../old/adm/style/acp_users_overview.html | 169 - .../update/old/adm/style/acp_users_prefs.html | 151 - .../old/adm/style/acp_users_signature.html | 52 - install/update/old/adm/style/admin.css | 2720 --------- install/update/old/adm/style/admin.js | 258 - install/update/old/adm/style/ajax.js | 332 -- .../old/adm/style/captcha_recaptcha.html | 14 - .../old/adm/style/installer_footer.html | 30 - .../update/old/adm/style/overall_footer.html | 46 - .../update/old/adm/style/overall_header.html | 157 - .../old/adm/style/permission_forum_copy.html | 40 - .../update/old/adm/style/permission_mask.html | 150 - install/update/old/adm/style/permissions.js | 300 - .../update/old/adm/style/progress_bar.html | 40 - .../update/old/adm/style/simple_footer.html | 27 - .../update/old/adm/style/simple_header.html | 96 - .../cookieconsent/cookieconsent.min.css | 6 - .../assets/cookieconsent/cookieconsent.min.js | 1 - install/update/old/assets/javascript/core.js | 1684 ------ .../update/old/assets/javascript/editor.js | 425 -- .../update/old/assets/javascript/plupload.js | 657 --- install/update/old/common.php | 164 - install/update/old/composer.json | 75 - install/update/old/composer.lock | 3644 ------------ .../config/default/container/parameters.yml | 20 - .../old/config/default/container/services.yml | 169 - .../default/container/services_auth.yml | 110 - .../default/container/services_console.yml | 295 - .../default/container/services_cron.yml | 235 - .../default/container/services_password.yml | 136 - .../default/container/services_routing.yml | 79 - .../container/services_text_formatter.yml | 79 - .../default/container/services_twig.yml | 68 - .../old/config/default/routing/routing.yml | 24 - install/update/old/cron.php | 84 - install/update/old/download/file.php | 326 -- .../ext/phpbb/viglink/acp/viglink_helper.php | 146 - .../old/ext/phpbb/viglink/composer.json | 27 - .../old/ext/phpbb/viglink/composer.lock | 115 - .../viglink/styles/all/theme/viglink.css | 18 - install/update/old/feed.php | 58 - .../old/includes/acp/acp_attachments.php | 1732 ------ .../update/old/includes/acp/acp_bbcodes.php | 620 --- install/update/old/includes/acp/acp_board.php | 1178 ---- .../update/old/includes/acp/acp_database.php | 622 --- .../old/includes/acp/acp_extensions.php | 665 --- .../update/old/includes/acp/acp_forums.php | 2179 -------- .../old/includes/acp/acp_help_phpbb.php | 143 - install/update/old/includes/acp/acp_main.php | 707 --- .../old/includes/acp/acp_permissions.php | 1346 ----- install/update/old/includes/acp/acp_prune.php | 587 -- .../update/old/includes/acp/acp_reasons.php | 394 -- .../update/old/includes/acp/acp_styles.php | 1373 ----- .../update/old/includes/acp/acp_update.php | 86 - install/update/old/includes/acp/acp_users.php | 2692 --------- install/update/old/includes/acp/auth.php | 1323 ----- install/update/old/includes/bbcode.php | 707 --- .../old/includes/compatibility_globals.php | 84 - install/update/old/includes/constants.php | 316 -- install/update/old/includes/diff/engine.php | 555 -- install/update/old/includes/functions.php | 4945 ----------------- install/update/old/includes/functions_acp.php | 726 --- .../update/old/includes/functions_admin.php | 3109 ----------- .../old/includes/functions_compatibility.php | 513 -- .../old/includes/functions_compress.php | 830 --- .../update/old/includes/functions_content.php | 1805 ------ .../update/old/includes/functions_convert.php | 2514 --------- .../update/old/includes/functions_display.php | 1733 ------ .../old/includes/functions_download.php | 790 --- .../old/includes/functions_messenger.php | 1915 ------- .../update/old/includes/functions_module.php | 1145 ---- .../update/old/includes/functions_posting.php | 2772 --------- .../old/includes/functions_privmsgs.php | 2264 -------- .../old/includes/functions_transfer.php | 899 --- .../update/old/includes/functions_user.php | 3759 ------------- install/update/old/includes/mcp/mcp_ban.php | 301 - install/update/old/includes/mcp/mcp_logs.php | 230 - install/update/old/includes/mcp/mcp_main.php | 1701 ------ install/update/old/includes/mcp/mcp_notes.php | 258 - install/update/old/includes/mcp/mcp_topic.php | 812 --- install/update/old/includes/mcp/mcp_warn.php | 610 -- .../update/old/includes/message_parser.php | 2059 ------- .../includes/questionnaire/questionnaire.php | 501 -- install/update/old/includes/startup.php | 86 - .../old/includes/ucp/ucp_attachments.php | 205 - .../update/old/includes/ucp/ucp_groups.php | 1137 ---- install/update/old/includes/ucp/ucp_pm.php | 435 -- .../old/includes/ucp/ucp_pm_compose.php | 1546 ------ .../old/includes/ucp/ucp_pm_viewfolder.php | 604 -- .../update/old/includes/ucp/ucp_profile.php | 847 --- .../update/old/includes/ucp/ucp_register.php | 709 --- .../update/old/includes/ucp/ucp_resend.php | 163 - install/update/old/includes/utf/utf_tools.php | 1450 ----- install/update/old/index.php | 260 - .../old/language/en/acp/attachments.php | 169 - install/update/old/language/en/acp/board.php | 631 --- install/update/old/language/en/acp/common.php | 833 --- install/update/old/language/en/acp/forums.php | 165 - .../old/language/en/acp/permissions.php | 287 - .../old/language/en/acp/permissions_phpbb.php | 214 - .../update/old/language/en/acp/posting.php | 291 - .../update/old/language/en/acp/profile.php | 176 - install/update/old/language/en/acp/styles.php | 90 - .../old/language/en/captcha_recaptcha.php | 52 - install/update/old/language/en/cli.php | 178 - install/update/old/language/en/common.php | 1438 ----- .../old/language/en/email/admin_activate.txt | 13 - install/update/old/language/en/install.php | 599 -- install/update/old/language/en/migrator.php | 81 - install/update/old/language/en/posting.php | 287 - install/update/old/language/en/ucp.php | 662 --- install/update/old/mcp.php | 326 -- install/update/old/memberlist.php | 1776 ------ .../update/old/phpbb/auth/provider/apache.php | 264 - .../update/old/phpbb/auth/provider/base.php | 108 - install/update/old/phpbb/auth/provider/db.php | 240 - .../update/old/phpbb/auth/provider/ldap.php | 348 -- .../old/phpbb/auth/provider/oauth/oauth.php | 747 --- .../auth/provider/oauth/service/base.php | 51 - .../auth/provider/oauth/service/bitly.php | 94 - .../auth/provider/oauth/service/facebook.php | 94 - .../auth/provider/oauth/service/google.php | 105 - .../oauth/service/service_interface.php | 73 - .../auth/provider/oauth/service/twitter.php | 102 - .../auth/provider/oauth/token_storage.php | 592 -- .../auth/provider/provider_interface.php | 197 - .../update/old/phpbb/avatar/driver/remote.php | 216 - .../update/old/phpbb/avatar/driver/upload.php | 331 -- .../old/phpbb/cache/driver/memcached.php | 134 - .../update/old/phpbb/cache/driver/memory.php | 282 - install/update/old/phpbb/captcha/non_gd.php | 386 -- .../update/old/phpbb/captcha/plugins/qa.php | 1040 ---- install/update/old/phpbb/class_loader.php | 164 - install/update/old/phpbb/config/config.php | 167 - install/update/old/phpbb/config_php_file.php | 160 - .../old/phpbb/console/command/cron/run.php | 171 - .../console/command/extension/enable.php | 76 - .../phpbb/console/command/update/check.php | 331 -- .../old/phpbb/console/command/user/add.php | 334 -- .../update/old/phpbb/content_visibility.php | 885 --- .../update/old/phpbb/controller/helper.php | 195 - install/update/old/phpbb/cron/manager.php | 147 - .../phpbb/cron/task/core/update_hashes.php | 130 - .../update/old/phpbb/cron/task/wrapper.php | 106 - install/update/old/phpbb/db/driver/driver.php | 1220 ---- .../old/phpbb/db/driver/driver_interface.php | 453 -- .../update/old/phpbb/db/driver/factory.php | 443 -- .../update/old/phpbb/db/driver/mssql_odbc.php | 385 -- .../old/phpbb/db/driver/mssqlnative.php | 451 -- install/update/old/phpbb/db/driver/mysqli.php | 490 -- install/update/old/phpbb/db/driver/oracle.php | 822 --- .../update/old/phpbb/db/driver/postgres.php | 501 -- .../update/old/phpbb/db/driver/sqlite3.php | 431 -- .../phpbb/db/extractor/mysql_extractor.php | 403 -- .../migration/data/v30x/release_3_0_4_rc1.php | 129 - .../db/migration/data/v310/softdelete_p1.php | 211 - .../old/phpbb/db/migration/tool/module.php | 556 -- install/update/old/phpbb/db/migrator.php | 1037 ---- install/update/old/phpbb/db/tools/mssql.php | 880 --- .../update/old/phpbb/db/tools/postgres.php | 614 -- install/update/old/phpbb/db/tools/tools.php | 1956 ------- .../update/old/phpbb/di/container_builder.php | 673 --- .../di/extension/container_configuration.php | 52 - .../update/old/phpbb/di/extension/core.php | 124 - .../old/phpbb/di/service_collection.php | 106 - .../update/old/phpbb/event/md_exporter.php | 561 -- .../phpbb/extension/extension_interface.php | 70 - .../update/old/phpbb/extension/manager.php | 633 --- .../update/old/phpbb/feed/controller/feed.php | 411 -- .../update/old/phpbb/feed/topics_active.php | 147 - install/update/old/phpbb/files/filespec.php | 584 -- install/update/old/phpbb/filesystem.php | 21 - .../old/phpbb/filesystem/filesystem.php | 916 --- .../phpbb/filesystem/filesystem_interface.php | 284 - install/update/old/phpbb/finder.php | 547 -- install/update/old/phpbb/group/helper.php | 40 - .../old/phpbb/help/controller/bbcode.php | 85 - .../update/old/phpbb/help/controller/faq.php | 165 - .../old/phpbb/install/controller/helper.php | 413 -- .../install/helper/container_factory.php | 191 - .../old/phpbb/install/helper/database.php | 439 -- .../helper/iohandler/iohandler_interface.php | 222 - .../phpbb/install/installer_configuration.php | 147 - .../task/add_config_settings.php | 368 -- .../install_database/task/create_schema.php | 234 - .../install_database/task/set_up_database.php | 164 - .../task/create_config_file.php | 244 - .../task/check_server_environment.php | 209 - .../update/old/phpbb/install/module_base.php | 213 - .../phpbb/language/language_file_loader.php | 206 - install/update/old/phpbb/lock/db.php | 146 - install/update/old/phpbb/lock/flock.php | 141 - install/update/old/phpbb/message/form.php | 175 - install/update/old/phpbb/mimetype/guesser.php | 156 - .../phpbb/notification/type/approve_post.php | 149 - .../phpbb/notification/type/approve_topic.php | 140 - .../old/phpbb/notification/type/base.php | 577 -- .../old/phpbb/notification/type/post.php | 467 -- .../old/phpbb/notification/type/topic.php | 307 - .../notification/type/type_interface.php | 218 - .../update/old/phpbb/passwords/manager.php | 407 -- install/update/old/phpbb/permissions.php | 364 -- .../update/old/phpbb/plupload/plupload.php | 402 -- .../old/phpbb/report/report_handler.php | 104 - install/update/old/phpbb/request/request.php | 454 -- .../old/phpbb/request/request_interface.php | 177 - .../old/phpbb/request/type_cast_helper.php | 124 - .../old/phpbb/search/fulltext_mysql.php | 1227 ---- .../old/phpbb/search/fulltext_native.php | 2062 ------- .../old/phpbb/search/fulltext_postgres.php | 1178 ---- .../old/phpbb/search/fulltext_sphinx.php | 992 ---- install/update/old/phpbb/session.php | 1650 ------ install/update/old/phpbb/template/asset.php | 210 - install/update/old/phpbb/template/context.php | 631 --- .../update/old/phpbb/template/template.php | 224 - .../old/phpbb/template/twig/extension.php | 185 - .../update/old/phpbb/template/twig/lexer.php | 368 -- .../update/old/phpbb/template/twig/loader.php | 176 - .../phpbb/template/twig/node/definenode.php | 57 - .../phpbb/template/twig/node/includeasset.php | 71 - .../phpbb/template/twig/node/includephp.php | 91 - .../twig/tokenparser/defineparser.php | 76 - .../phpbb/template/twig/tokenparser/event.php | 44 - .../template/twig/tokenparser/includecss.php | 44 - .../template/twig/tokenparser/includejs.php | 44 - .../twig/tokenparser/includeparser.php | 44 - .../template/twig/tokenparser/includephp.php | 55 - .../phpbb/template/twig/tokenparser/php.php | 52 - .../phpbb/textformatter/s9e/bbcode_merger.php | 183 - .../old/phpbb/textformatter/s9e/factory.php | 676 --- .../phpbb/textformatter/s9e/link_helper.php | 115 - .../old/phpbb/textformatter/s9e/parser.php | 399 -- .../phpbb/textformatter/s9e/quote_helper.php | 81 - install/update/old/phpbb/user.php | 814 --- install/update/old/phpbb/user_loader.php | 238 - install/update/old/posting.php | 1990 ------- install/update/old/report.php | 41 - install/update/old/search.php | 1552 ------ install/update/old/styles/prosilver/style.cfg | 32 - .../styles/prosilver/template/attachment.html | 48 - .../old/styles/prosilver/template/bbcode.html | 75 - .../prosilver/template/captcha_recaptcha.html | 30 - .../old/styles/prosilver/template/forum_fn.js | 937 ---- .../prosilver/template/forumlist_body.html | 137 - .../styles/prosilver/template/mcp_forum.html | 153 - .../styles/prosilver/template/mcp_move.html | 71 - .../styles/prosilver/template/mcp_topic.html | 202 - .../prosilver/template/memberlist_body.html | 179 - .../prosilver/template/memberlist_search.html | 87 - .../prosilver/template/navbar_header.html | 210 - .../prosilver/template/overall_footer.html | 120 - .../prosilver/template/overall_header.html | 131 - .../styles/prosilver/template/plupload.html | 67 - .../template/posting_attach_body.html | 93 - .../prosilver/template/posting_buttons.html | 126 - .../prosilver/template/posting_layout.html | 86 - .../prosilver/template/posting_poll_body.html | 53 - .../prosilver/template/posting_review.html | 44 - .../template/posting_topic_review.html | 89 - .../prosilver/template/search_results.html | 242 - .../prosilver/template/simple_footer.html | 40 - .../prosilver/template/ucp_agreement.html | 73 - .../prosilver/template/ucp_attachments.html | 83 - .../template/ucp_avatar_options_upload.html | 11 - .../prosilver/template/ucp_groups_manage.html | 247 - .../prosilver/template/ucp_pm_history.html | 57 - .../template/ucp_pm_viewmessage_print.html | 50 - .../template/ucp_profile_profile_info.html | 51 - .../prosilver/template/ucp_register.html | 106 - .../prosilver/template/viewforum_body.html | 313 -- .../prosilver/template/viewtopic_body.html | 452 -- .../prosilver/template/viewtopic_print.html | 46 - .../old/styles/prosilver/theme/colours.css | 1163 ---- .../old/styles/prosilver/theme/common.css | 1287 ----- .../old/styles/prosilver/theme/forms.css | 429 -- .../old/styles/prosilver/theme/icons.css | 96 - .../old/styles/prosilver/theme/plupload.css | 86 - .../old/styles/prosilver/theme/print.css | 150 - .../old/styles/prosilver/theme/stylesheet.css | 21 - install/update/old/ucp.php | 406 -- install/update/old/viewforum.php | 1059 ---- install/update/old/viewonline.php | 517 -- install/update/old/viewtopic.php | 2380 -------- language/fr/email/user_activate_passwd.txt | 17 - styles/Milk_v2/theme/blank.css.css | 3 - styles/Milk_v2/theme/images/icon_download.gif | Bin 198 -> 0 bytes styles/Milk_v2/theme/images/icon_offline.gif | Bin 322 -> 0 bytes styles/Milk_v2/theme/images/icon_online.gif | Bin 331 -> 0 bytes styles/Milk_v2/theme/images/icon_rate_bad.gif | Bin 465 -> 0 bytes .../Milk_v2/theme/images/icon_rate_good.gif | Bin 462 -> 0 bytes styles/Milk_v2/theme/images/quote.gif | Bin 153 -> 0 bytes styles/Milk_v2/theme/images/quote_rtl.gif | Bin 154 -> 0 bytes .../theme/images/sticky_read_locked.gif | Bin 646 -> 0 bytes .../theme/images/sticky_read_locked_mine.gif | Bin 662 -> 0 bytes .../Milk_v2/theme/images/sticky_read_mine.gif | Bin 633 -> 0 bytes styles/Milk_v2/theme/images/sticky_unread.gif | Bin 622 -> 0 bytes styles/Milk_v2/theme/stylesheet.css | 40 - styles/Milk_v2/theme/stylesheet_jour.css | 48 +- styles/Milk_v2/theme/stylesheet_nuit.css | 48 +- styles/prosilver/theme/stylesheet.css | 21 - styles/prosilver/theme/stylesheet_jour.css | 26 +- styles/prosilver/theme/stylesheet_nuit.css | 26 +- vendor/guzzlehttp/guzzle/src/BatchResults.php | 148 - vendor/guzzlehttp/guzzle/src/Collection.php | 236 - .../guzzle/src/Event/AbstractEvent.php | 20 - .../guzzle/src/Event/AbstractRequestEvent.php | 61 - .../src/Event/AbstractRetryableEvent.php | 40 - .../src/Event/AbstractTransferEvent.php | 63 - .../guzzle/src/Event/BeforeEvent.php | 26 - .../guzzle/src/Event/CompleteEvent.php | 14 - .../guzzlehttp/guzzle/src/Event/Emitter.php | 145 - .../guzzle/src/Event/EmitterInterface.php | 96 - .../guzzlehttp/guzzle/src/Event/EndEvent.php | 28 - .../guzzle/src/Event/ErrorEvent.php | 27 - .../guzzle/src/Event/EventInterface.php | 23 - .../guzzle/src/Event/HasEmitterInterface.php | 15 - .../guzzle/src/Event/HasEmitterTrait.php | 20 - .../src/Event/ListenerAttacherTrait.php | 88 - .../guzzle/src/Event/ProgressEvent.php | 51 - .../guzzle/src/Event/RequestEvents.php | 56 - .../guzzle/src/Event/SubscriberInterface.php | 34 - .../CouldNotRewindStreamException.php | 4 - .../guzzle/src/Exception/ParseException.php | 31 - .../guzzle/src/Exception/StateException.php | 4 - .../src/Exception/XmlParseException.php | 34 - vendor/guzzlehttp/guzzle/src/HasDataTrait.php | 75 - .../guzzle/src/Message/AbstractMessage.php | 253 - .../src/Message/AppliesHeadersInterface.php | 24 - .../guzzle/src/Message/FutureResponse.php | 158 - .../guzzle/src/Message/MessageFactory.php | 364 -- .../src/Message/MessageFactoryInterface.php | 71 - .../guzzle/src/Message/MessageInterface.php | 136 - .../guzzle/src/Message/MessageParser.php | 171 - .../guzzlehttp/guzzle/src/Message/Request.php | 195 - .../guzzle/src/Message/RequestInterface.php | 136 - .../guzzle/src/Message/Response.php | 208 - .../guzzle/src/Message/ResponseInterface.php | 111 - vendor/guzzlehttp/guzzle/src/Mimetypes.php | 963 ---- .../guzzle/src/Post/MultipartBody.php | 109 - .../guzzlehttp/guzzle/src/Post/PostBody.php | 287 - .../guzzle/src/Post/PostBodyInterface.php | 109 - .../guzzlehttp/guzzle/src/Post/PostFile.php | 135 - .../guzzle/src/Post/PostFileInterface.php | 41 - vendor/guzzlehttp/guzzle/src/Query.php | 204 - vendor/guzzlehttp/guzzle/src/QueryParser.php | 163 - vendor/guzzlehttp/guzzle/src/RequestFsm.php | 153 - vendor/guzzlehttp/guzzle/src/RingBridge.php | 165 - .../guzzle/src/Subscriber/Cookie.php | 58 - .../guzzle/src/Subscriber/History.php | 172 - .../guzzle/src/Subscriber/HttpError.php | 36 - .../guzzlehttp/guzzle/src/Subscriber/Mock.php | 147 - .../guzzle/src/Subscriber/Prepare.php | 130 - .../guzzle/src/Subscriber/Redirect.php | 176 - .../guzzle/src/ToArrayInterface.php | 15 - vendor/guzzlehttp/guzzle/src/Transaction.php | 103 - vendor/guzzlehttp/guzzle/src/Url.php | 595 -- vendor/guzzlehttp/guzzle/src/Utils.php | 215 - vendor/guzzlehttp/ringphp/.editorconfig | 12 - vendor/guzzlehttp/ringphp/LICENSE | 19 - vendor/guzzlehttp/ringphp/composer.json | 43 - .../ringphp/src/Client/ClientUtils.php | 74 - .../ringphp/src/Client/CurlFactory.php | 560 -- .../ringphp/src/Client/CurlHandler.php | 135 - .../ringphp/src/Client/CurlMultiHandler.php | 248 - .../ringphp/src/Client/Middleware.php | 58 - .../ringphp/src/Client/MockHandler.php | 52 - .../ringphp/src/Client/StreamHandler.php | 414 -- vendor/guzzlehttp/ringphp/src/Core.php | 364 -- .../src/Exception/CancelledException.php | 7 - .../CancelledFutureAccessException.php | 4 - .../src/Exception/ConnectException.php | 7 - .../ringphp/src/Exception/RingException.php | 4 - .../ringphp/src/Future/BaseFutureTrait.php | 125 - .../src/Future/CompletedFutureArray.php | 43 - .../src/Future/CompletedFutureValue.php | 57 - .../ringphp/src/Future/FutureArray.php | 40 - .../src/Future/FutureArrayInterface.php | 11 - .../ringphp/src/Future/FutureInterface.php | 40 - .../ringphp/src/Future/FutureValue.php | 12 - .../ringphp/src/Future/MagicFutureTrait.php | 32 - vendor/guzzlehttp/streams/LICENSE | 19 - vendor/guzzlehttp/streams/composer.json | 28 - .../guzzlehttp/streams/src/AppendStream.php | 220 - .../streams/src/AsyncReadStream.php | 207 - .../guzzlehttp/streams/src/BufferStream.php | 138 - .../guzzlehttp/streams/src/CachingStream.php | 122 - .../guzzlehttp/streams/src/DroppingStream.php | 42 - .../src/Exception/CannotAttachException.php | 4 - .../streams/src/Exception/SeekException.php | 27 - vendor/guzzlehttp/streams/src/FnStream.php | 147 - .../streams/src/GuzzleStreamWrapper.php | 117 - .../guzzlehttp/streams/src/InflateStream.php | 27 - .../guzzlehttp/streams/src/LazyOpenStream.php | 37 - vendor/guzzlehttp/streams/src/LimitStream.php | 161 - .../streams/src/MetadataStreamInterface.php | 11 - .../guzzlehttp/streams/src/NoSeekStream.php | 25 - vendor/guzzlehttp/streams/src/NullStream.php | 78 - vendor/guzzlehttp/streams/src/PumpStream.php | 161 - vendor/guzzlehttp/streams/src/Stream.php | 261 - .../streams/src/StreamDecoratorTrait.php | 143 - .../streams/src/StreamInterface.php | 159 - vendor/guzzlehttp/streams/src/Utils.php | 196 - vendor/ircmaxell/password-compat/LICENSE.md | 7 - .../ircmaxell/password-compat/composer.json | 20 - .../password-compat/lib/password.php | 314 -- .../password-compat/version-test.php | 6 - vendor/ocramius/proxy-manager/.gitignore | 7 - .../ocramius/proxy-manager/.scrutinizer.yml | 45 - .../ocramius/proxy-manager/.travis.install.sh | 11 - vendor/ocramius/proxy-manager/.travis.yml | 28 - vendor/ocramius/proxy-manager/CONTRIBUTING.md | 35 - .../access-interceptor-scope-localizer.php | 38 - .../proxy-manager/examples/ghost-object.php | 46 - .../proxy-manager/examples/remote-proxy.php | 36 - .../remote-proxy/remote-proxy-server.php | 20 - .../examples/smart-reference.php | 23 - .../proxy-manager/examples/virtual-proxy.php | 39 - ...ess-interceptor-scope-localizer-proxy.html | 197 - ...access-interceptor-value-holder-proxy.html | 208 - .../proxy-manager/html-docs/contributing.html | 139 - .../proxy-manager/html-docs/copyright.html | 100 - .../proxy-manager/html-docs/credits.html | 113 - .../proxy-manager/html-docs/css/styles.css | 203 - .../proxy-manager/html-docs/download.html | 97 - .../proxy-manager/html-docs/favicon.ico | Bin 173246 -> 0 bytes .../proxy-manager/html-docs/ghost-object.html | 314 -- .../proxy-manager/html-docs/img/block.png | Bin 2373 -> 0 bytes .../proxy-manager/html-docs/img/enf.png | Bin 3738 -> 0 bytes .../proxy-manager/html-docs/index.html | 295 - .../proxy-manager/html-docs/null-object.html | 185 - .../proxy-manager/html-docs/production.html | 114 - .../html-docs/remote-object.html | 203 - .../html-docs/virtual-proxy.html | 305 - vendor/ocramius/proxy-manager/index.html | 11 - vendor/ocramius/proxy-manager/phpdox.xml.dist | 16 - vendor/ocramius/proxy-manager/phpmd.xml.dist | 16 - .../ocramius/proxy-manager/phpunit.xml.dist | 25 - .../ocramius/proxy-manager/proxy-manager.png | Bin 19203 -> 0 bytes .../Factory/AbstractLazyFactory.php | 46 - .../Generator/ParameterGenerator.php | 149 - .../MethodGenerator/Constructor.php | 92 - .../MethodGenerator/Constructor.php | 79 - .../MethodGenerator/Constructor.php | 58 - .../LazyLoadingMethodInterceptor.php | 71 - .../MethodGenerator/Constructor.php | 55 - .../PublicPropertiesDefaults.php | 58 - .../MethodGenerator/Constructor.php | 63 - .../Autoloader/AutoloaderTest.php | 133 - .../ProxyManagerTest/ConfigurationTest.php | 183 - .../Exception/DisabledMethodExceptionTest.php | 44 - .../FileNotWritableExceptionTest.php | 72 - .../InvalidProxiedClassExceptionTest.php | 67 - .../InvalidProxyDirectoryExceptionTest.php | 44 - .../UnsupportedProxiedClassExceptionTest.php | 49 - .../Factory/AbstractBaseFactoryTest.php | 158 - ...ssInterceptorScopeLocalizerFactoryTest.php | 199 - ...ccessInterceptorValueHolderFactoryTest.php | 198 - .../Factory/LazyLoadingGhostFactoryTest.php | 193 - .../LazyLoadingValueHolderFactoryTest.php | 193 - .../Factory/NullObjectFactoryTest.php | 180 - .../RemoteObject/Adapter/BaseAdapterTest.php | 101 - .../RemoteObject/Adapter/JsonRpcTest.php | 57 - .../Factory/RemoteObject/Adapter/SoapTest.php | 57 - .../RemoteObject/Adapter/XmlRpcTest.php | 57 - .../Factory/RemoteObjectFactoryTest.php | 178 - .../FileLocator/FileLocatorTest.php | 54 - ...nterceptorScopeLocalizerFunctionalTest.php | 388 -- ...ssInterceptorValueHolderFunctionalTest.php | 360 -- .../BaseLazyLoadingPerformanceTest.php | 196 - .../Functional/BasePerformanceTest.php | 101 - .../FatalPreventionFunctionalTest.php | 171 - .../LazyLoadingGhostFunctionalTest.php | 441 -- .../LazyLoadingGhostPerformanceTest.php | 160 - .../LazyLoadingValueHolderFunctionalTest.php | 386 -- .../LazyLoadingValueHolderPerformanceTest.php | 134 - .../MultipleProxyGenerationTest.php | 123 - .../Functional/NullObjectFunctionalTest.php | 223 - .../Functional/RemoteObjectFunctionalTest.php | 231 - .../Generator/ClassGeneratorTest.php | 65 - .../Generator/MagicMethodGeneratorTest.php | 56 - .../Generator/MethodGeneratorTest.php | 97 - .../Generator/ParameterGeneratorTest.php | 146 - .../Util/ClassGeneratorUtilsTest.php | 72 - .../Util/UniqueIdentifierGeneratorTest.php | 77 - .../BaseGeneratorStrategyTest.php | 48 - .../EvaluatingGeneratorStrategyTest.php | 69 - .../FileWriterGeneratorStrategyTest.php | 148 - .../Inflector/ClassNameInflectorTest.php | 161 - .../Inflector/Util/ParameterEncoderTest.php | 66 - .../Inflector/Util/ParameterHasherTest.php | 62 - .../AbstractProxyGeneratorTest.php | 95 - .../MethodGenerator/MagicWakeupTest.php | 62 - .../SetMethodPrefixInterceptorTest.php | 49 - .../SetMethodSuffixInterceptorTest.php | 49 - .../MethodPrefixInterceptorsTest.php | 42 - .../MethodSuffixInterceptorsTest.php | 42 - .../MethodGenerator/ConstructorTest.php | 207 - .../MethodGenerator/InterceptedMethodTest.php | 62 - .../MethodGenerator/MagicCloneTest.php | 72 - .../MethodGenerator/MagicGetTest.php | 80 - .../MethodGenerator/MagicIssetTest.php | 80 - .../MethodGenerator/MagicSetTest.php | 80 - .../MethodGenerator/MagicSleepTest.php | 80 - .../MethodGenerator/MagicUnsetTest.php | 80 - .../Util/InterceptorGeneratorTest.php | 81 - .../AccessInterceptorScopeLocalizerTest.php | 76 - .../MethodGenerator/ConstructorTest.php | 69 - .../MethodGenerator/ConstructorTest.php | 86 - .../MethodGenerator/InterceptedMethodTest.php | 65 - .../MethodGenerator/MagicCloneTest.php | 64 - .../MethodGenerator/MagicGetTest.php | 66 - .../MethodGenerator/MagicIssetTest.php | 66 - .../MethodGenerator/MagicSetTest.php | 66 - .../MethodGenerator/MagicUnsetTest.php | 69 - .../Util/InterceptorGeneratorTest.php | 84 - .../AccessInterceptorValueHolderTest.php | 52 - .../Assertion/CanProxyAssertionTest.php | 113 - .../MethodGenerator/CallInitializerTest.php | 59 - .../GetProxyInitializerTest.php | 49 - .../MethodGenerator/InitializeProxyTest.php | 54 - .../IsProxyInitializedTest.php | 49 - .../LazyLoadingMethodInterceptorTest.php | 81 - .../MethodGenerator/MagicCloneTest.php | 56 - .../MethodGenerator/MagicGetTest.php | 124 - .../MethodGenerator/MagicIssetTest.php | 123 - .../MethodGenerator/MagicSetTest.php | 124 - .../MethodGenerator/MagicSleepTest.php | 57 - .../MethodGenerator/MagicUnsetTest.php | 124 - .../SetProxyInitializerTest.php | 56 - .../InitializationTrackerTest.php | 42 - .../InitializerPropertyTest.php | 42 - .../LazyLoadingGhostGeneratorTest.php | 49 - .../GetProxyInitializerTest.php | 49 - .../MethodGenerator/InitializeProxyTest.php | 54 - .../IsProxyInitializedTest.php | 49 - .../LazyLoadingMethodInterceptorTest.php | 84 - .../MethodGenerator/MagicCloneTest.php | 57 - .../MethodGenerator/MagicGetTest.php | 65 - .../MethodGenerator/MagicIssetTest.php | 65 - .../MethodGenerator/MagicSetTest.php | 65 - .../MethodGenerator/MagicSleepTest.php | 57 - .../MethodGenerator/MagicUnsetTest.php | 65 - .../SetProxyInitializerTest.php | 56 - .../InitializerPropertyTest.php | 42 - .../ValueHolderPropertyTest.php | 42 - .../LazyLoadingValueHolderGeneratorTest.php | 49 - .../MethodGenerator/ConstructorTest.php | 64 - .../NullObjectMethodInterceptorTest.php | 75 - .../NullObjectGeneratorTest.php | 113 - .../AbstractUniquePropertyNameTest.php | 49 - .../PublicPropertiesDefaultsTest.php | 72 - .../PublicPropertiesMapTest.php | 59 - .../MethodGenerator/ConstructorTest.php | 54 - .../MethodGenerator/MagicGetTest.php | 54 - .../MethodGenerator/MagicIssetTest.php | 54 - .../MethodGenerator/MagicSetTest.php | 54 - .../MethodGenerator/MagicUnsetTest.php | 54 - .../RemoteObjectMethodTest.php | 116 - .../PropertyGenerator/AdapterPropertyTest.php | 42 - .../RemoteObjectGeneratorTest.php | 103 - .../Util/ProxiedMethodsFilterTest.php | 114 - .../Util/PublicScopeSimulatorTest.php | 133 - .../GetWrappedValueHolderValueTest.php | 49 - .../MethodGenerator/MagicSleepTest.php | 54 - .../Signature/ClassSignatureGeneratorTest.php | 87 - .../InvalidSignatureExceptionTest.php | 57 - .../MissingSignatureExceptionTest.php | 56 - .../Signature/SignatureCheckerTest.php | 117 - .../Signature/SignatureGeneratorTest.php | 116 - .../tests/ProxyManagerTest/VersionTest.php | 42 - .../AccessInterceptorValueHolderMock.php | 55 - .../tests/ProxyManagerTestAsset/BaseClass.php | 108 - .../ProxyManagerTestAsset/BaseInterface.php | 33 - .../CallableTypeHintClass.php | 39 - .../ClassWithAbstractProtectedMethod.php | 33 - .../ClassWithByRefMagicMethods.php | 74 - .../ClassWithFinalMagicMethods.php | 88 - .../ClassWithFinalMethods.php | 42 - .../ClassWithMagicMethods.php | 81 - .../ClassWithMethodWithDefaultParameters.php | 38 - .../ClassWithMixedProperties.php | 46 - .../ClassWithPrivateProperties.php | 48 - .../ClassWithProtectedProperties.php | 48 - .../ClassWithPublicArrayProperty.php | 31 - .../ClassWithPublicProperties.php | 48 - .../ClassWithSelfHint.php | 38 - .../ProxyManagerTestAsset/EmptyClass.php | 29 - .../ProxyManagerTestAsset/FinalClass.php | 29 - .../ProxyManagerTestAsset/HydratedObject.php | 60 - .../ProxyManagerTestAsset/LazyLoadingMock.php | 41 - .../ProxyManagerTestAsset/NullObjectMock.php | 29 - .../ClassWithTwoPublicProperties.php | 38 - .../RemoteProxy/BazServiceInterface.php | 35 - .../ProxyManagerTestAsset/RemoteProxy/Foo.php | 56 - .../RemoteProxy/FooServiceInterface.php | 33 - .../tests/language-feature-scripts/README.md | 9 - ...rceptor-denies-private-property-isset.phpt | 20 - ...erceptor-denies-private-property-read.phpt | 20 - ...rceptor-denies-private-property-unset.phpt | 20 - ...rceptor-denies-private-property-write.phpt | 20 - ...eptor-denies-protected-property-isset.phpt | 20 - ...ceptor-denies-protected-property-read.phpt | 20 - ...eptor-denies-protected-property-unset.phpt | 20 - ...eptor-denies-protected-property-write.phpt | 20 - ...calizer-denies-private-property-isset.phpt | 26 - ...ocalizer-denies-private-property-read.phpt | 26 - ...calizer-denies-private-property-unset.phpt | 26 - ...calizer-denies-private-property-write.phpt | 26 - ...lizer-denies-protected-property-isset.phpt | 20 - ...alizer-denies-protected-property-read.phpt | 20 - ...lizer-denies-protected-property-unset.phpt | 20 - ...lizer-denies-protected-property-write.phpt | 20 - .../access-interceptor-with-cache.phpt | 34 - .../language-feature-scripts/cache/README.md | 3 - .../tests/language-feature-scripts/init.php | 10 - ...allows-inexisting-magic-property-read.phpt | 25 - ...host-allows-inexisting-property-write.phpt | 21 - ...ghost-denies-inexisting-property-read.phpt | 20 - ...g-ghost-denies-private-property-isset.phpt | 20 - ...ng-ghost-denies-private-property-read.phpt | 20 - ...g-ghost-denies-private-property-unset.phpt | 20 - ...g-ghost-denies-private-property-write.phpt | 20 - ...ghost-denies-protected-property-isset.phpt | 20 - ...-ghost-denies-protected-property-read.phpt | 20 - ...ghost-denies-protected-property-unset.phpt | 20 - ...ghost-denies-protected-property-write.phpt | 20 - .../lazy-loading-ghost-with-cache.phpt | 34 - ...-holder-denies-private-property-isset.phpt | 23 - ...e-holder-denies-private-property-read.phpt | 23 - ...-holder-denies-private-property-unset.phpt | 23 - ...-holder-denies-private-property-write.phpt | 23 - ...older-denies-protected-property-isset.phpt | 23 - ...holder-denies-protected-property-read.phpt | 23 - ...older-denies-protected-property-unset.phpt | 23 - ...older-denies-protected-property-write.phpt | 23 - ...ing-value-holder-internal-php-classes.phpt | 31 - .../lazy-loading-value-holder-with-cache.phpt | 40 - .../null-object-public-function-empty.phpt | 23 - .../null-object-public-property-empty.phpt | 20 - ...ect-json-adapter-denies-unknow-method.phpt | 43 - vendor/paragonie/random_compat/RATIONALE.md | 42 - .../random_compat/lib/byte_safe_strings.php | 181 - .../random_compat/lib/cast_to_int.php | 74 - .../random_compat/lib/error_polyfill.php | 49 - .../lib/random_bytes_com_dotnet.php | 88 - .../lib/random_bytes_dev_urandom.php | 150 - .../lib/random_bytes_libsodium.php | 88 - .../lib/random_bytes_libsodium_legacy.php | 92 - .../random_compat/lib/random_bytes_mcrypt.php | 77 - .../lib/random_bytes_openssl.php | 86 - .../random_compat/lib/random_int.php | 190 - vendor/react/promise/LICENSE | 22 - vendor/react/promise/composer.json | 29 - .../src/CancellablePromiseInterface.php | 11 - .../react/promise/src/CancellationQueue.php | 55 - vendor/react/promise/src/Deferred.php | 65 - .../promise/src/Exception/LengthException.php | 7 - .../promise/src/ExtendedPromiseInterface.php | 30 - vendor/react/promise/src/FulfilledPromise.php | 68 - vendor/react/promise/src/LazyPromise.php | 63 - vendor/react/promise/src/Promise.php | 256 - vendor/react/promise/src/PromiseInterface.php | 14 - .../react/promise/src/PromisorInterface.php | 11 - vendor/react/promise/src/RejectedPromise.php | 76 - .../src/UnhandledRejectionException.php | 31 - vendor/react/promise/src/functions.php | 246 - .../react/promise/src/functions_include.php | 5 - .../RendererGenerators/XSLT/Optimizer.php | 26 - .../config/Definition/ReferenceDumper.php | 24 - .../Resource/BCResourceInterfaceChecker.php | 36 - .../symfony/console/Helper/DialogHelper.php | 502 -- .../symfony/console/Helper/ProgressHelper.php | 469 -- vendor/symfony/console/Helper/TableHelper.php | 264 - vendor/symfony/console/Shell.php | 229 - .../debug/Exception/DummyException.php | 23 - .../dependency-injection/ContainerAware.php | 35 - .../Exception/InactiveScopeException.php | 41 - .../ScopeCrossingInjectionException.php | 65 - .../ScopeWideningInjectionException.php | 64 - .../IntrospectableContainerInterface.php | 32 - vendor/symfony/dependency-injection/Scope.php | 41 - .../dependency-injection/ScopeInterface.php | 26 - .../dependency-injection/SimpleXMLElement.php | 116 - .../finder/Adapter/AbstractAdapter.php | 240 - .../finder/Adapter/AbstractFindAdapter.php | 325 -- .../finder/Adapter/AdapterInterface.php | 124 - .../symfony/finder/Adapter/BsdFindAdapter.php | 107 - .../symfony/finder/Adapter/GnuFindAdapter.php | 108 - vendor/symfony/finder/Adapter/PhpAdapter.php | 101 - .../Exception/AdapterFailureException.php | 47 - .../OperationNotPermitedException.php | 23 - .../ShellCommandFailureException.php | 41 - .../symfony/finder/Expression/Expression.php | 148 - vendor/symfony/finder/Expression/Glob.php | 108 - vendor/symfony/finder/Expression/Regex.php | 321 -- .../finder/Expression/ValueInterface.php | 62 - .../finder/Iterator/FilePathsIterator.php | 135 - vendor/symfony/finder/Shell/Command.php | 278 - vendor/symfony/finder/Shell/Shell.php | 101 - .../Handler/LegacyPdoSessionHandler.php | 268 - .../http-kernel/Debug/ErrorHandler.php | 27 - .../http-kernel/Debug/ExceptionHandler.php | 27 - .../ContainerAwareHttpKernel.php | 85 - .../RegisterListenersPass.php | 25 - .../EventListener/ErrorsLoggerListener.php | 52 - .../http-kernel/EventListener/EsiListener.php | 25 - .../Exception/FatalErrorException.php | 23 - .../Exception/FlattenException.php | 25 - .../HttpCache/EsiResponseCacheStrategy.php | 33 - .../EsiResponseCacheStrategyInterface.php | 28 - .../http-kernel/Log/LoggerInterface.php | 44 - vendor/symfony/http-kernel/Log/NullLogger.php | 44 - .../Profiler/BaseMemcacheProfilerStorage.php | 313 -- .../Profiler/MemcacheProfilerStorage.php | 112 - .../Profiler/MemcachedProfilerStorage.php | 108 - .../Profiler/MongoDbProfilerStorage.php | 257 - .../Profiler/MysqlProfilerStorage.php | 84 - .../Profiler/PdoProfilerStorage.php | 265 - .../Profiler/RedisProfilerStorage.php | 395 -- .../Profiler/SqliteProfilerStorage.php | 144 - vendor/symfony/polyfill-php54/LICENSE | 19 - vendor/symfony/polyfill-php54/Php54.php | 36 - vendor/symfony/polyfill-php54/README.md | 17 - .../stubs/CallbackFilterIterator.php | 28 - .../stubs/RecursiveCallbackFilterIterator.php | 33 - .../stubs/SessionHandlerInterface.php | 102 - vendor/symfony/polyfill-php54/bootstrap.php | 34 - vendor/symfony/polyfill-php54/composer.json | 32 - vendor/symfony/polyfill-php55/LICENSE | 19 - vendor/symfony/polyfill-php55/Php55.php | 89 - .../polyfill-php55/Php55ArrayColumn.php | 64 - vendor/symfony/polyfill-php55/README.md | 18 - vendor/symfony/polyfill-php55/bootstrap.php | 27 - vendor/symfony/polyfill-php55/composer.json | 32 - .../routing/Matcher/ApacheUrlMatcher.php | 124 - .../Matcher/Dumper/ApacheMatcherDumper.php | 272 - .../Matcher/Dumper/DumperPrefixCollection.php | 105 - .../twig-bridge/Node/FormEnctypeNode.php | 21 - vendor/twig/twig/lib/Twig/Autoloader.php | 52 - .../twig/twig/lib/Twig/CompilerInterface.php | 34 - vendor/twig/twig/lib/Twig/Filter/Function.php | 40 - vendor/twig/twig/lib/Twig/Filter/Method.php | 44 - vendor/twig/twig/lib/Twig/Filter/Node.php | 42 - .../twig/lib/Twig/FilterCallableInterface.php | 24 - vendor/twig/twig/lib/Twig/FilterInterface.php | 45 - .../twig/twig/lib/Twig/Function/Function.php | 41 - vendor/twig/twig/lib/Twig/Function/Method.php | 45 - vendor/twig/twig/lib/Twig/Function/Node.php | 42 - .../lib/Twig/FunctionCallableInterface.php | 24 - .../twig/twig/lib/Twig/FunctionInterface.php | 42 - vendor/twig/twig/lib/Twig/LexerInterface.php | 36 - vendor/twig/twig/lib/Twig/Loader/String.php | 63 - .../Node/Expression/ExtensionReference.php | 35 - vendor/twig/twig/lib/Twig/Node/SetTemp.php | 11 - vendor/twig/twig/lib/Twig/NodeInterface.php | 34 - vendor/twig/twig/lib/Twig/ParserInterface.php | 33 - .../twig/twig/lib/Twig/TemplateInterface.php | 50 - vendor/twig/twig/lib/Twig/Test/Function.php | 38 - vendor/twig/twig/lib/Twig/Test/Method.php | 42 - vendor/twig/twig/lib/Twig/Test/Node.php | 40 - .../twig/lib/Twig/TestCallableInterface.php | 22 - vendor/twig/twig/lib/Twig/TestInterface.php | 27 - .../twig/twig/lib/Twig/TokenParserBroker.php | 122 - .../lib/Twig/TokenParserBrokerInterface.php | 46 - vendor/twig/twig/src/Node/SetTempNode.php | 44 - .../src/GlobalEventManager.php | 141 - .../zend-eventmanager/src/ProvidesEvents.php | 23 - .../SharedEventAggregateAwareInterface.php | 33 - .../src/SharedEventManagerAwareInterface.php | 38 - .../src/SharedListenerAggregateInterface.php | 38 - .../src/StaticEventManager.php | 81 - vendor/zendframework/zend-stdlib/LICENSE.md | 28 - .../zendframework/zend-stdlib/composer.json | 47 - .../zend-stdlib/src/AbstractOptions.php | 176 - .../zend-stdlib/src/ArrayObject.php | 432 -- .../src/ArraySerializableInterface.php | 28 - .../zend-stdlib/src/ArrayStack.php | 33 - .../zend-stdlib/src/ArrayUtils.php | 335 -- .../src/ArrayUtils/MergeRemoveKey.php | 14 - .../src/ArrayUtils/MergeReplaceKey.php | 34 - .../ArrayUtils/MergeReplaceKeyInterface.php | 21 - .../zend-stdlib/src/CallbackHandler.php | 217 - .../zend-stdlib/src/DateTime.php | 47 - .../zend-stdlib/src/DispatchableInterface.php | 22 - .../zend-stdlib/src/ErrorHandler.php | 115 - .../src/Exception/BadMethodCallException.php | 17 - .../src/Exception/DomainException.php | 17 - .../src/Exception/ExceptionInterface.php | 17 - .../Exception/ExtensionNotLoadedException.php | 17 - .../Exception/InvalidArgumentException.php | 17 - .../Exception/InvalidCallbackException.php | 17 - .../src/Exception/LogicException.php | 17 - .../src/Exception/RuntimeException.php | 17 - .../src/Extractor/ExtractionInterface.php | 21 - vendor/zendframework/zend-stdlib/src/Glob.php | 202 - .../zend-stdlib/src/Guard/AllGuardsTrait.php | 20 - .../Guard/ArrayOrTraversableGuardTrait.php | 41 - .../zend-stdlib/src/Guard/EmptyGuardTrait.php | 35 - .../zend-stdlib/src/Guard/GuardUtils.php | 85 - .../zend-stdlib/src/Guard/NullGuardTrait.php | 35 - .../src/Hydrator/AbstractHydrator.php | 287 - .../Hydrator/Aggregate/AggregateHydrator.php | 85 - .../src/Hydrator/Aggregate/ExtractEvent.php | 98 - .../src/Hydrator/Aggregate/HydrateEvent.php | 84 - .../Hydrator/Aggregate/HydratorListener.php | 80 - .../src/Hydrator/ArraySerializable.php | 83 - .../zend-stdlib/src/Hydrator/ClassMethods.php | 274 - .../src/Hydrator/DelegatingHydrator.php | 57 - .../Hydrator/DelegatingHydratorFactory.php | 29 - .../src/Hydrator/Filter/FilterComposite.php | 196 - .../src/Hydrator/Filter/FilterInterface.php | 21 - .../Filter/FilterProviderInterface.php | 19 - .../src/Hydrator/Filter/GetFilter.php | 27 - .../src/Hydrator/Filter/HasFilter.php | 27 - .../src/Hydrator/Filter/IsFilter.php | 27 - .../src/Hydrator/Filter/MethodMatchFilter.php | 48 - .../Filter/NumberOfParameterFilter.php | 49 - .../Filter/OptionalParametersFilter.php | 54 - .../src/Hydrator/FilterEnabledInterface.php | 63 - .../src/Hydrator/HydrationInterface.php | 22 - .../src/Hydrator/HydratorAwareInterface.php | 28 - .../src/Hydrator/HydratorAwareTrait.php | 47 - .../src/Hydrator/HydratorInterface.php | 16 - .../src/Hydrator/HydratorOptionsInterface.php | 19 - .../src/Hydrator/HydratorPluginManager.php | 74 - .../NamingStrategy/ArrayMapNamingStrategy.php | 51 - .../CompositeNamingStrategy.php | 64 - .../NamingStrategy/IdentityNamingStrategy.php | 29 - .../NamingStrategy/MapNamingStrategy.php | 89 - .../NamingStrategyInterface.php | 37 - .../UnderscoreNamingStrategy.php | 80 - .../NamingStrategyEnabledInterface.php | 44 - .../src/Hydrator/ObjectProperty.php | 110 - .../zend-stdlib/src/Hydrator/Reflection.php | 95 - .../src/Hydrator/Strategy/BooleanStrategy.php | 106 - .../src/Hydrator/Strategy/ClosureStrategy.php | 102 - .../Strategy/DateTimeFormatterStrategy.php | 80 - .../src/Hydrator/Strategy/DefaultStrategy.php | 35 - .../Strategy/Exception/ExceptionInterface.php | 14 - .../Exception/InvalidArgumentException.php | 14 - .../src/Hydrator/Strategy/ExplodeStrategy.php | 113 - .../Strategy/SerializableStrategy.php | 123 - .../src/Hydrator/Strategy/StrategyChain.php | 73 - .../Hydrator/Strategy/StrategyInterface.php | 34 - .../src/Hydrator/StrategyEnabledInterface.php | 48 - .../src/InitializableInterface.php | 23 - .../zend-stdlib/src/JsonSerializable.php | 28 - .../PhpLegacyCompatibility.php | 28 - .../zendframework/zend-stdlib/src/Message.php | 118 - .../zend-stdlib/src/MessageInterface.php | 44 - .../src/ParameterObjectInterface.php | 38 - .../zend-stdlib/src/Parameters.php | 115 - .../zend-stdlib/src/ParametersInterface.php | 86 - .../zend-stdlib/src/PriorityList.php | 271 - .../zend-stdlib/src/PriorityQueue.php | 301 - .../zendframework/zend-stdlib/src/Request.php | 15 - .../zend-stdlib/src/RequestInterface.php | 14 - .../zend-stdlib/src/Response.php | 15 - .../zend-stdlib/src/ResponseInterface.php | 14 - .../zend-stdlib/src/SplPriorityQueue.php | 91 - .../zend-stdlib/src/SplQueue.php | 55 - .../zend-stdlib/src/SplStack.php | 55 - .../zend-stdlib/src/StringUtils.php | 187 - .../StringWrapper/AbstractStringWrapper.php | 269 - .../zend-stdlib/src/StringWrapper/Iconv.php | 289 - .../zend-stdlib/src/StringWrapper/Intl.php | 88 - .../src/StringWrapper/MbString.php | 121 - .../zend-stdlib/src/StringWrapper/Native.php | 134 - .../StringWrapper/StringWrapperInterface.php | 111 - .../src/compatibility/autoload.php | 14 - 1538 files changed, 80 insertions(+), 351590 deletions(-) delete mode 100644 README.rdoc delete mode 100644 docs/assets/images/site_logo.gif delete mode 100644 ext/planetstyles/flightdeck.zip delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_1.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_10.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_11.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_12.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_13.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_14.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_15.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_16.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_17.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_18.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_19.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_2.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_20.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_21.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_22.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_23.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_24.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_25.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_26.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_27.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_28.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_29.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_3.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_30.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_4.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_5.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_6.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_7.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_8.png delete mode 100644 images/avatars/gallery/Civils_F/Civil_F_9.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_1.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_10.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_11.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_12.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_13.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_14.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_15.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_16.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_17.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_18.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_19.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_2.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_20.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_21.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_22.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_23.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_24.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_25.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_26.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_27.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_28.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_29.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_3.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_30.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_31.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_32.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_33.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_34.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_35.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_36.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_37.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_38.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_39.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_4.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_40.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_41.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_42.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_43.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_44.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_45.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_46.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_47.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_48.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_49.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_5.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_50.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_51.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_52.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_53.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_54.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_55.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_56.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_57.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_58.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_59.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_6.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_60.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_61.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_62.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_63.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_64.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_65.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_66.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_67.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_68.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_7.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_8.png delete mode 100644 images/avatars/gallery/Civils_H/Civil_H_9.png delete mode 100644 images/avatars/gallery/Flics/Flic_1.png delete mode 100644 images/avatars/gallery/Flics/Flic_10.png delete mode 100644 images/avatars/gallery/Flics/Flic_100.png delete mode 100644 images/avatars/gallery/Flics/Flic_101.png delete mode 100644 images/avatars/gallery/Flics/Flic_102.png delete mode 100644 images/avatars/gallery/Flics/Flic_103.png delete mode 100644 images/avatars/gallery/Flics/Flic_104.png delete mode 100644 images/avatars/gallery/Flics/Flic_105.png delete mode 100644 images/avatars/gallery/Flics/Flic_106.png delete mode 100644 images/avatars/gallery/Flics/Flic_107.png delete mode 100644 images/avatars/gallery/Flics/Flic_108.png delete mode 100644 images/avatars/gallery/Flics/Flic_109.png delete mode 100644 images/avatars/gallery/Flics/Flic_110.png delete mode 100644 images/avatars/gallery/Flics/Flic_13.png delete mode 100644 images/avatars/gallery/Flics/Flic_14.png delete mode 100644 images/avatars/gallery/Flics/Flic_15.png delete mode 100644 images/avatars/gallery/Flics/Flic_16.png delete mode 100644 images/avatars/gallery/Flics/Flic_19.png delete mode 100644 images/avatars/gallery/Flics/Flic_2.png delete mode 100644 images/avatars/gallery/Flics/Flic_20.png delete mode 100644 images/avatars/gallery/Flics/Flic_21.png delete mode 100644 images/avatars/gallery/Flics/Flic_22.png delete mode 100644 images/avatars/gallery/Flics/Flic_25.png delete mode 100644 images/avatars/gallery/Flics/Flic_27.png delete mode 100644 images/avatars/gallery/Flics/Flic_28.png delete mode 100644 images/avatars/gallery/Flics/Flic_30.png delete mode 100644 images/avatars/gallery/Flics/Flic_31.png delete mode 100644 images/avatars/gallery/Flics/Flic_32.png delete mode 100644 images/avatars/gallery/Flics/Flic_33.png delete mode 100644 images/avatars/gallery/Flics/Flic_34.png delete mode 100644 images/avatars/gallery/Flics/Flic_35.png delete mode 100644 images/avatars/gallery/Flics/Flic_36.png delete mode 100644 images/avatars/gallery/Flics/Flic_38.png delete mode 100644 images/avatars/gallery/Flics/Flic_39.png delete mode 100644 images/avatars/gallery/Flics/Flic_4.png delete mode 100644 images/avatars/gallery/Flics/Flic_40.png delete mode 100644 images/avatars/gallery/Flics/Flic_41.png delete mode 100644 images/avatars/gallery/Flics/Flic_43.png delete mode 100644 images/avatars/gallery/Flics/Flic_44.png delete mode 100644 images/avatars/gallery/Flics/Flic_45.png delete mode 100644 images/avatars/gallery/Flics/Flic_46.png delete mode 100644 images/avatars/gallery/Flics/Flic_47.png delete mode 100644 images/avatars/gallery/Flics/Flic_48.png delete mode 100644 images/avatars/gallery/Flics/Flic_49.png delete mode 100644 images/avatars/gallery/Flics/Flic_5.png delete mode 100644 images/avatars/gallery/Flics/Flic_50.png delete mode 100644 images/avatars/gallery/Flics/Flic_51.png delete mode 100644 images/avatars/gallery/Flics/Flic_52.png delete mode 100644 images/avatars/gallery/Flics/Flic_53.png delete mode 100644 images/avatars/gallery/Flics/Flic_54.png delete mode 100644 images/avatars/gallery/Flics/Flic_55.png delete mode 100644 images/avatars/gallery/Flics/Flic_56.png delete mode 100644 images/avatars/gallery/Flics/Flic_57.png delete mode 100644 images/avatars/gallery/Flics/Flic_58.png delete mode 100644 images/avatars/gallery/Flics/Flic_59.png delete mode 100644 images/avatars/gallery/Flics/Flic_6.png delete mode 100644 images/avatars/gallery/Flics/Flic_60.png delete mode 100644 images/avatars/gallery/Flics/Flic_61.png delete mode 100644 images/avatars/gallery/Flics/Flic_62.png delete mode 100644 images/avatars/gallery/Flics/Flic_64.png delete mode 100644 images/avatars/gallery/Flics/Flic_65.png delete mode 100644 images/avatars/gallery/Flics/Flic_66.png delete mode 100644 images/avatars/gallery/Flics/Flic_67.png delete mode 100644 images/avatars/gallery/Flics/Flic_68.png delete mode 100644 images/avatars/gallery/Flics/Flic_69.png delete mode 100644 images/avatars/gallery/Flics/Flic_7.png delete mode 100644 images/avatars/gallery/Flics/Flic_70.png delete mode 100644 images/avatars/gallery/Flics/Flic_71.png delete mode 100644 images/avatars/gallery/Flics/Flic_72.png delete mode 100644 images/avatars/gallery/Flics/Flic_73.png delete mode 100644 images/avatars/gallery/Flics/Flic_74.png delete mode 100644 images/avatars/gallery/Flics/Flic_75.png delete mode 100644 images/avatars/gallery/Flics/Flic_76.png delete mode 100644 images/avatars/gallery/Flics/Flic_77.png delete mode 100644 images/avatars/gallery/Flics/Flic_78.png delete mode 100644 images/avatars/gallery/Flics/Flic_79.png delete mode 100644 images/avatars/gallery/Flics/Flic_8.png delete mode 100644 images/avatars/gallery/Flics/Flic_80.png delete mode 100644 images/avatars/gallery/Flics/Flic_81.png delete mode 100644 images/avatars/gallery/Flics/Flic_82.png delete mode 100644 images/avatars/gallery/Flics/Flic_83.png delete mode 100644 images/avatars/gallery/Flics/Flic_84.png delete mode 100644 images/avatars/gallery/Flics/Flic_85.png delete mode 100644 images/avatars/gallery/Flics/Flic_86.png delete mode 100644 images/avatars/gallery/Flics/Flic_87.png delete mode 100644 images/avatars/gallery/Flics/Flic_88.png delete mode 100644 images/avatars/gallery/Flics/Flic_89.png delete mode 100644 images/avatars/gallery/Flics/Flic_9.png delete mode 100644 images/avatars/gallery/Flics/Flic_90.png delete mode 100644 images/avatars/gallery/Flics/Flic_91.png delete mode 100644 images/avatars/gallery/Flics/Flic_92.png delete mode 100644 images/avatars/gallery/Flics/Flic_93.png delete mode 100644 images/avatars/gallery/Flics/Flic_94.png delete mode 100644 images/avatars/gallery/Flics/Flic_95.png delete mode 100644 images/avatars/gallery/Flics/Flic_96.png delete mode 100644 images/avatars/gallery/Flics/Flic_97.png delete mode 100644 images/avatars/gallery/Flics/Flic_98.png delete mode 100644 images/avatars/gallery/Flics/Flic_99.png delete mode 100644 install/update/index.php delete mode 100644 install/update/new/.htaccess delete mode 100644 install/update/new/adm/images/alert_close.png delete mode 100644 install/update/new/adm/images/arrow_down.gif delete mode 100644 install/update/new/adm/images/arrow_left.gif delete mode 100644 install/update/new/adm/images/arrow_right.gif delete mode 100644 install/update/new/adm/images/arrow_up.gif delete mode 100644 install/update/new/adm/images/bg_button.gif delete mode 100644 install/update/new/adm/images/bg_hash1.gif delete mode 100644 install/update/new/adm/images/bg_hash2.gif delete mode 100644 install/update/new/adm/images/bg_hash3.gif delete mode 100644 install/update/new/adm/images/bg_hash4.gif delete mode 100644 install/update/new/adm/images/bg_header.gif delete mode 100644 install/update/new/adm/images/bg_header.jpg delete mode 100644 install/update/new/adm/images/bg_tabs_alt1.gif delete mode 100644 install/update/new/adm/images/bg_tabs_alt2.gif delete mode 100644 install/update/new/adm/images/cellpic3.gif delete mode 100644 install/update/new/adm/images/file_conflict.gif delete mode 100644 install/update/new/adm/images/file_modified.gif delete mode 100644 install/update/new/adm/images/file_new.gif delete mode 100644 install/update/new/adm/images/file_new_conflict.gif delete mode 100644 install/update/new/adm/images/file_not_modified.gif delete mode 100644 install/update/new/adm/images/file_up_to_date.gif delete mode 100644 install/update/new/adm/images/gradient2b.gif delete mode 100644 install/update/new/adm/images/icon_delete.gif delete mode 100644 install/update/new/adm/images/icon_delete_disabled.gif delete mode 100644 install/update/new/adm/images/icon_down.gif delete mode 100644 install/update/new/adm/images/icon_down_disabled.gif delete mode 100644 install/update/new/adm/images/icon_edit.gif delete mode 100644 install/update/new/adm/images/icon_edit_disabled.gif delete mode 100644 install/update/new/adm/images/icon_folder.gif delete mode 100644 install/update/new/adm/images/icon_folder_link.gif delete mode 100644 install/update/new/adm/images/icon_folder_lock.gif delete mode 100644 install/update/new/adm/images/icon_subfolder.gif delete mode 100644 install/update/new/adm/images/icon_sync.gif delete mode 100644 install/update/new/adm/images/icon_sync_disabled.gif delete mode 100644 install/update/new/adm/images/icon_trace.gif delete mode 100644 install/update/new/adm/images/icon_up.gif delete mode 100644 install/update/new/adm/images/icon_up_disabled.gif delete mode 100644 install/update/new/adm/images/innerbox_bg.gif delete mode 100644 install/update/new/adm/images/loading.gif delete mode 100644 install/update/new/adm/images/no_avatar.gif delete mode 100644 install/update/new/adm/images/no_image.png delete mode 100644 install/update/new/adm/images/phpbb_logo.png delete mode 100644 install/update/new/adm/images/phpbb_logo.svg delete mode 100644 install/update/new/adm/images/progress_bar.gif delete mode 100644 install/update/new/adm/images/spacer.gif delete mode 100644 install/update/new/adm/index.php delete mode 100644 install/update/new/adm/style/acp_attachments.html delete mode 100644 install/update/new/adm/style/acp_avatar_options_upload.html delete mode 100644 install/update/new/adm/style/acp_ban.html delete mode 100644 install/update/new/adm/style/acp_contact.html delete mode 100644 install/update/new/adm/style/acp_database.html delete mode 100644 install/update/new/adm/style/acp_ext_actions.html delete mode 100644 install/update/new/adm/style/acp_ext_list.html delete mode 100644 install/update/new/adm/style/acp_forums.html delete mode 100644 install/update/new/adm/style/acp_groups.html delete mode 100644 install/update/new/adm/style/acp_help_phpbb.html delete mode 100644 install/update/new/adm/style/acp_icons.html delete mode 100644 install/update/new/adm/style/acp_language.html delete mode 100644 install/update/new/adm/style/acp_main.html delete mode 100644 install/update/new/adm/style/acp_modules.html delete mode 100644 install/update/new/adm/style/acp_permission_roles.html delete mode 100644 install/update/new/adm/style/acp_posting_buttons.html delete mode 100644 install/update/new/adm/style/acp_ranks.html delete mode 100644 install/update/new/adm/style/acp_search.html delete mode 100644 install/update/new/adm/style/acp_styles.html delete mode 100644 install/update/new/adm/style/acp_users_overview.html delete mode 100644 install/update/new/adm/style/acp_users_prefs.html delete mode 100644 install/update/new/adm/style/acp_users_signature.html delete mode 100644 install/update/new/adm/style/admin.css delete mode 100644 install/update/new/adm/style/admin.js delete mode 100644 install/update/new/adm/style/ajax.js delete mode 100644 install/update/new/adm/style/captcha_recaptcha.html delete mode 100644 install/update/new/adm/style/installer_convert.html delete mode 100644 install/update/new/adm/style/installer_footer.html delete mode 100644 install/update/new/adm/style/installer_form.html delete mode 100644 install/update/new/adm/style/installer_header.html delete mode 100644 install/update/new/adm/style/installer_install.html delete mode 100644 install/update/new/adm/style/installer_main.html delete mode 100644 install/update/new/adm/style/installer_update.html delete mode 100644 install/update/new/adm/style/installer_update_file_status.html delete mode 100644 install/update/new/adm/style/overall_footer.html delete mode 100644 install/update/new/adm/style/overall_header.html delete mode 100644 install/update/new/adm/style/permission_forum_copy.html delete mode 100644 install/update/new/adm/style/permission_mask.html delete mode 100644 install/update/new/adm/style/permissions.js delete mode 100644 install/update/new/adm/style/progress_bar.html delete mode 100644 install/update/new/adm/style/simple_footer.html delete mode 100644 install/update/new/adm/style/simple_header.html delete mode 100644 install/update/new/assets/cookieconsent/cookieconsent.min.css delete mode 100644 install/update/new/assets/cookieconsent/cookieconsent.min.js delete mode 100644 install/update/new/assets/javascript/core.js delete mode 100644 install/update/new/assets/javascript/editor.js delete mode 100644 install/update/new/assets/javascript/installer.js delete mode 100644 install/update/new/assets/javascript/jquery-3.4.1.min.js delete mode 100644 install/update/new/assets/javascript/plupload.js delete mode 100644 install/update/new/common.php delete mode 100644 install/update/new/composer.json delete mode 100644 install/update/new/composer.lock delete mode 100644 install/update/new/config/default/config.yml delete mode 100644 install/update/new/config/default/container/parameters.yml delete mode 100644 install/update/new/config/default/container/services.yml delete mode 100644 install/update/new/config/default/container/services_attachment.yml delete mode 100644 install/update/new/config/default/container/services_auth.yml delete mode 100644 install/update/new/config/default/container/services_avatar.yml delete mode 100644 install/update/new/config/default/container/services_captcha.yml delete mode 100644 install/update/new/config/default/container/services_console.yml delete mode 100644 install/update/new/config/default/container/services_content.yml delete mode 100644 install/update/new/config/default/container/services_cron.yml delete mode 100644 install/update/new/config/default/container/services_db.yml delete mode 100644 install/update/new/config/default/container/services_event.yml delete mode 100644 install/update/new/config/default/container/services_feed.yml delete mode 100644 install/update/new/config/default/container/services_files.yml delete mode 100644 install/update/new/config/default/container/services_filesystem.yml delete mode 100644 install/update/new/config/default/container/services_help.yml delete mode 100644 install/update/new/config/default/container/services_hook.yml delete mode 100644 install/update/new/config/default/container/services_http.yml delete mode 100644 install/update/new/config/default/container/services_language.yml delete mode 100644 install/update/new/config/default/container/services_migrator.yml delete mode 100644 install/update/new/config/default/container/services_mimetype_guesser.yml delete mode 100644 install/update/new/config/default/container/services_module.yml delete mode 100644 install/update/new/config/default/container/services_notification.yml delete mode 100644 install/update/new/config/default/container/services_password.yml delete mode 100644 install/update/new/config/default/container/services_php.yml delete mode 100644 install/update/new/config/default/container/services_profilefield.yml delete mode 100644 install/update/new/config/default/container/services_report.yml delete mode 100644 install/update/new/config/default/container/services_routing.yml delete mode 100644 install/update/new/config/default/container/services_text_formatter.yml delete mode 100644 install/update/new/config/default/container/services_text_reparser.yml delete mode 100644 install/update/new/config/default/container/services_twig.yml delete mode 100644 install/update/new/config/default/container/services_ucp.yml delete mode 100644 install/update/new/config/default/container/services_user.yml delete mode 100644 install/update/new/config/default/container/tables.yml delete mode 100644 install/update/new/config/default/routing/cron.yml delete mode 100644 install/update/new/config/default/routing/feed.yml delete mode 100644 install/update/new/config/default/routing/help.yml delete mode 100644 install/update/new/config/default/routing/report.yml delete mode 100644 install/update/new/config/default/routing/routing.yml delete mode 100644 install/update/new/config/default/routing/ucp.yml delete mode 100644 install/update/new/config/installer/config.yml delete mode 100644 install/update/new/config/installer/container/environment.yml delete mode 100644 install/update/new/config/installer/container/parameters.yml delete mode 100644 install/update/new/config/installer/container/services.yml delete mode 100644 install/update/new/config/installer/container/services_file_updater.yml delete mode 100644 install/update/new/config/installer/container/services_install_console.yml delete mode 100644 install/update/new/config/installer/container/services_install_controller.yml delete mode 100644 install/update/new/config/installer/container/services_install_data.yml delete mode 100644 install/update/new/config/installer/container/services_install_database.yml delete mode 100644 install/update/new/config/installer/container/services_install_filesystem.yml delete mode 100644 install/update/new/config/installer/container/services_install_finish.yml delete mode 100644 install/update/new/config/installer/container/services_install_navigation.yml delete mode 100644 install/update/new/config/installer/container/services_install_obtain_data.yml delete mode 100644 install/update/new/config/installer/container/services_install_requirements.yml delete mode 100644 install/update/new/config/installer/container/services_installer.yml delete mode 100644 install/update/new/config/installer/container/services_update_database.yml delete mode 100644 install/update/new/config/installer/container/services_update_filesystem.yml delete mode 100644 install/update/new/config/installer/container/services_update_obtain_data.yml delete mode 100644 install/update/new/config/installer/container/services_update_requirements.yml delete mode 100644 install/update/new/config/installer/routing/environment.yml delete mode 100644 install/update/new/config/installer/routing/installer.yml delete mode 100644 install/update/new/config/production/config.yml delete mode 100644 install/update/new/config/production/container/environment.yml delete mode 100644 install/update/new/config/production/container/parameters.yml delete mode 100644 install/update/new/config/production/container/services.yml delete mode 100644 install/update/new/config/production/routing/environment.yml delete mode 100644 install/update/new/cron.php delete mode 100644 install/update/new/download/file.php delete mode 100644 install/update/new/ext/phpbb/viglink/acp/viglink_helper.php delete mode 100644 install/update/new/ext/phpbb/viglink/composer.json delete mode 100644 install/update/new/ext/phpbb/viglink/composer.lock delete mode 100644 install/update/new/ext/phpbb/viglink/styles/all/theme/viglink.css delete mode 100644 install/update/new/feed.php delete mode 100644 install/update/new/includes/acp/acp_attachments.php delete mode 100644 install/update/new/includes/acp/acp_bbcodes.php delete mode 100644 install/update/new/includes/acp/acp_board.php delete mode 100644 install/update/new/includes/acp/acp_database.php delete mode 100644 install/update/new/includes/acp/acp_extensions.php delete mode 100644 install/update/new/includes/acp/acp_forums.php delete mode 100644 install/update/new/includes/acp/acp_help_phpbb.php delete mode 100644 install/update/new/includes/acp/acp_main.php delete mode 100644 install/update/new/includes/acp/acp_permissions.php delete mode 100644 install/update/new/includes/acp/acp_prune.php delete mode 100644 install/update/new/includes/acp/acp_reasons.php delete mode 100644 install/update/new/includes/acp/acp_styles.php delete mode 100644 install/update/new/includes/acp/acp_update.php delete mode 100644 install/update/new/includes/acp/acp_users.php delete mode 100644 install/update/new/includes/acp/auth.php delete mode 100644 install/update/new/includes/bbcode.php delete mode 100644 install/update/new/includes/compatibility_globals.php delete mode 100644 install/update/new/includes/constants.php delete mode 100644 install/update/new/includes/diff/engine.php delete mode 100644 install/update/new/includes/functions.php delete mode 100644 install/update/new/includes/functions_acp.php delete mode 100644 install/update/new/includes/functions_admin.php delete mode 100644 install/update/new/includes/functions_compatibility.php delete mode 100644 install/update/new/includes/functions_compress.php delete mode 100644 install/update/new/includes/functions_content.php delete mode 100644 install/update/new/includes/functions_convert.php delete mode 100644 install/update/new/includes/functions_display.php delete mode 100644 install/update/new/includes/functions_download.php delete mode 100644 install/update/new/includes/functions_messenger.php delete mode 100644 install/update/new/includes/functions_module.php delete mode 100644 install/update/new/includes/functions_posting.php delete mode 100644 install/update/new/includes/functions_privmsgs.php delete mode 100644 install/update/new/includes/functions_transfer.php delete mode 100644 install/update/new/includes/functions_user.php delete mode 100644 install/update/new/includes/mcp/mcp_ban.php delete mode 100644 install/update/new/includes/mcp/mcp_logs.php delete mode 100644 install/update/new/includes/mcp/mcp_main.php delete mode 100644 install/update/new/includes/mcp/mcp_notes.php delete mode 100644 install/update/new/includes/mcp/mcp_topic.php delete mode 100644 install/update/new/includes/mcp/mcp_warn.php delete mode 100644 install/update/new/includes/message_parser.php delete mode 100644 install/update/new/includes/questionnaire/questionnaire.php delete mode 100644 install/update/new/includes/startup.php delete mode 100644 install/update/new/includes/ucp/ucp_attachments.php delete mode 100644 install/update/new/includes/ucp/ucp_groups.php delete mode 100644 install/update/new/includes/ucp/ucp_pm.php delete mode 100644 install/update/new/includes/ucp/ucp_pm_compose.php delete mode 100644 install/update/new/includes/ucp/ucp_pm_viewfolder.php delete mode 100644 install/update/new/includes/ucp/ucp_profile.php delete mode 100644 install/update/new/includes/ucp/ucp_register.php delete mode 100644 install/update/new/includes/ucp/ucp_resend.php delete mode 100644 install/update/new/includes/utf/utf_tools.php delete mode 100644 install/update/new/index.php delete mode 100644 install/update/new/language/en/acp/attachments.php delete mode 100644 install/update/new/language/en/acp/board.php delete mode 100644 install/update/new/language/en/acp/common.php delete mode 100644 install/update/new/language/en/acp/forums.php delete mode 100644 install/update/new/language/en/acp/permissions.php delete mode 100644 install/update/new/language/en/acp/permissions_phpbb.php delete mode 100644 install/update/new/language/en/acp/posting.php delete mode 100644 install/update/new/language/en/acp/profile.php delete mode 100644 install/update/new/language/en/acp/styles.php delete mode 100644 install/update/new/language/en/captcha_recaptcha.php delete mode 100644 install/update/new/language/en/cli.php delete mode 100644 install/update/new/language/en/common.php delete mode 100644 install/update/new/language/en/email/admin_activate.txt delete mode 100644 install/update/new/language/en/email/user_forgot_password.txt delete mode 100644 install/update/new/language/en/install.php delete mode 100644 install/update/new/language/en/migrator.php delete mode 100644 install/update/new/language/en/posting.php delete mode 100644 install/update/new/language/en/ucp.php delete mode 100644 install/update/new/mcp.php delete mode 100644 install/update/new/memberlist.php delete mode 100644 install/update/new/phpbb/auth/provider/apache.php delete mode 100644 install/update/new/phpbb/auth/provider/base.php delete mode 100644 install/update/new/phpbb/auth/provider/db.php delete mode 100644 install/update/new/phpbb/auth/provider/ldap.php delete mode 100644 install/update/new/phpbb/auth/provider/oauth/oauth.php delete mode 100644 install/update/new/phpbb/auth/provider/oauth/service/base.php delete mode 100644 install/update/new/phpbb/auth/provider/oauth/service/bitly.php delete mode 100644 install/update/new/phpbb/auth/provider/oauth/service/facebook.php delete mode 100644 install/update/new/phpbb/auth/provider/oauth/service/google.php delete mode 100644 install/update/new/phpbb/auth/provider/oauth/service/service_interface.php delete mode 100644 install/update/new/phpbb/auth/provider/oauth/service/twitter.php delete mode 100644 install/update/new/phpbb/auth/provider/oauth/token_storage.php delete mode 100644 install/update/new/phpbb/auth/provider/provider_interface.php delete mode 100644 install/update/new/phpbb/avatar/driver/remote.php delete mode 100644 install/update/new/phpbb/avatar/driver/upload.php delete mode 100644 install/update/new/phpbb/cache/driver/memcached.php delete mode 100644 install/update/new/phpbb/cache/driver/memory.php delete mode 100644 install/update/new/phpbb/captcha/non_gd.php delete mode 100644 install/update/new/phpbb/captcha/plugins/qa.php delete mode 100644 install/update/new/phpbb/class_loader.php delete mode 100644 install/update/new/phpbb/config/config.php delete mode 100644 install/update/new/phpbb/config_php_file.php delete mode 100644 install/update/new/phpbb/console/command/cron/run.php delete mode 100644 install/update/new/phpbb/console/command/extension/enable.php delete mode 100644 install/update/new/phpbb/console/command/update/check.php delete mode 100644 install/update/new/phpbb/console/command/user/add.php delete mode 100644 install/update/new/phpbb/content_visibility.php delete mode 100644 install/update/new/phpbb/controller/helper.php delete mode 100644 install/update/new/phpbb/cron/controller/cron.php delete mode 100644 install/update/new/phpbb/cron/event/cron_runner_listener.php delete mode 100644 install/update/new/phpbb/cron/manager.php delete mode 100644 install/update/new/phpbb/cron/task/core/update_hashes.php delete mode 100644 install/update/new/phpbb/cron/task/wrapper.php delete mode 100644 install/update/new/phpbb/db/driver/driver.php delete mode 100644 install/update/new/phpbb/db/driver/driver_interface.php delete mode 100644 install/update/new/phpbb/db/driver/factory.php delete mode 100644 install/update/new/phpbb/db/driver/mssql_odbc.php delete mode 100644 install/update/new/phpbb/db/driver/mssqlnative.php delete mode 100644 install/update/new/phpbb/db/driver/mysqli.php delete mode 100644 install/update/new/phpbb/db/driver/oracle.php delete mode 100644 install/update/new/phpbb/db/driver/postgres.php delete mode 100644 install/update/new/phpbb/db/driver/sqlite3.php delete mode 100644 install/update/new/phpbb/db/extractor/mysql_extractor.php delete mode 100644 install/update/new/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php delete mode 100644 install/update/new/phpbb/db/migration/data/v310/softdelete_p1.php delete mode 100644 install/update/new/phpbb/db/migration/data/v32x/timezone_p3.php delete mode 100644 install/update/new/phpbb/db/migration/data/v32x/user_emoji_permission.php delete mode 100644 install/update/new/phpbb/db/migration/data/v32x/v328.php delete mode 100644 install/update/new/phpbb/db/migration/data/v32x/v328rc1.php delete mode 100644 install/update/new/phpbb/db/migration/data/v32x/v329.php delete mode 100644 install/update/new/phpbb/db/migration/data/v32x/v329rc1.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/add_display_unapproved_posts_config.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/dev.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/forums_legend_limit.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/jquery_update.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/remove_attachment_flash.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/remove_email_hash.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/remove_max_pass_chars.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/reset_password.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/v330.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/v330b1.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/v330b2.php delete mode 100644 install/update/new/phpbb/db/migration/data/v330/v330rc1.php delete mode 100644 install/update/new/phpbb/db/migration/tool/module.php delete mode 100644 install/update/new/phpbb/db/migrator.php delete mode 100644 install/update/new/phpbb/db/tools/mssql.php delete mode 100644 install/update/new/phpbb/db/tools/postgres.php delete mode 100644 install/update/new/phpbb/db/tools/tools.php delete mode 100644 install/update/new/phpbb/di/container_builder.php delete mode 100644 install/update/new/phpbb/di/extension/container_configuration.php delete mode 100644 install/update/new/phpbb/di/extension/core.php delete mode 100644 install/update/new/phpbb/di/extension/tables.php delete mode 100644 install/update/new/phpbb/di/service_collection.php delete mode 100644 install/update/new/phpbb/event/md_exporter.php delete mode 100644 install/update/new/phpbb/extension/extension_interface.php delete mode 100644 install/update/new/phpbb/extension/manager.php delete mode 100644 install/update/new/phpbb/feed/controller/feed.php delete mode 100644 install/update/new/phpbb/feed/topics_active.php delete mode 100644 install/update/new/phpbb/files/filespec.php delete mode 100644 install/update/new/phpbb/filesystem.php delete mode 100644 install/update/new/phpbb/filesystem/filesystem.php delete mode 100644 install/update/new/phpbb/filesystem/filesystem_interface.php delete mode 100644 install/update/new/phpbb/finder.php delete mode 100644 install/update/new/phpbb/group/helper.php delete mode 100644 install/update/new/phpbb/help/controller/bbcode.php delete mode 100644 install/update/new/phpbb/help/controller/faq.php delete mode 100644 install/update/new/phpbb/install/controller/helper.php delete mode 100644 install/update/new/phpbb/install/helper/container_factory.php delete mode 100644 install/update/new/phpbb/install/helper/database.php delete mode 100644 install/update/new/phpbb/install/helper/iohandler/iohandler_interface.php delete mode 100644 install/update/new/phpbb/install/installer_configuration.php delete mode 100644 install/update/new/phpbb/install/module/install_database/task/add_config_settings.php delete mode 100644 install/update/new/phpbb/install/module/install_database/task/create_schema.php delete mode 100644 install/update/new/phpbb/install/module/install_database/task/set_up_database.php delete mode 100644 install/update/new/phpbb/install/module/install_filesystem/task/create_config_file.php delete mode 100644 install/update/new/phpbb/install/module/requirements/task/check_server_environment.php delete mode 100644 install/update/new/phpbb/install/module_base.php delete mode 100644 install/update/new/phpbb/language/language_file_loader.php delete mode 100644 install/update/new/phpbb/lock/db.php delete mode 100644 install/update/new/phpbb/lock/flock.php delete mode 100644 install/update/new/phpbb/message/form.php delete mode 100644 install/update/new/phpbb/mimetype/guesser.php delete mode 100644 install/update/new/phpbb/notification/type/approve_post.php delete mode 100644 install/update/new/phpbb/notification/type/approve_topic.php delete mode 100644 install/update/new/phpbb/notification/type/base.php delete mode 100644 install/update/new/phpbb/notification/type/post.php delete mode 100644 install/update/new/phpbb/notification/type/topic.php delete mode 100644 install/update/new/phpbb/notification/type/type_interface.php delete mode 100644 install/update/new/phpbb/passwords/driver/argon2i.php delete mode 100644 install/update/new/phpbb/passwords/driver/argon2id.php delete mode 100644 install/update/new/phpbb/passwords/driver/base_native.php delete mode 100644 install/update/new/phpbb/passwords/manager.php delete mode 100644 install/update/new/phpbb/permissions.php delete mode 100644 install/update/new/phpbb/plupload/plupload.php delete mode 100644 install/update/new/phpbb/report/report_handler.php delete mode 100644 install/update/new/phpbb/request/request.php delete mode 100644 install/update/new/phpbb/request/request_interface.php delete mode 100644 install/update/new/phpbb/request/type_cast_helper.php delete mode 100644 install/update/new/phpbb/search/fulltext_mysql.php delete mode 100644 install/update/new/phpbb/search/fulltext_native.php delete mode 100644 install/update/new/phpbb/search/fulltext_postgres.php delete mode 100644 install/update/new/phpbb/search/fulltext_sphinx.php delete mode 100644 install/update/new/phpbb/session.php delete mode 100644 install/update/new/phpbb/template/asset.php delete mode 100644 install/update/new/phpbb/template/context.php delete mode 100644 install/update/new/phpbb/template/template.php delete mode 100644 install/update/new/phpbb/template/twig/extension.php delete mode 100644 install/update/new/phpbb/template/twig/extension/avatar.php delete mode 100644 install/update/new/phpbb/template/twig/extension/config.php delete mode 100644 install/update/new/phpbb/template/twig/extension/username.php delete mode 100644 install/update/new/phpbb/template/twig/lexer.php delete mode 100644 install/update/new/phpbb/template/twig/loader.php delete mode 100644 install/update/new/phpbb/template/twig/node/definenode.php delete mode 100644 install/update/new/phpbb/template/twig/node/includeasset.php delete mode 100644 install/update/new/phpbb/template/twig/node/includephp.php delete mode 100644 install/update/new/phpbb/template/twig/tokenparser/defineparser.php delete mode 100644 install/update/new/phpbb/template/twig/tokenparser/event.php delete mode 100644 install/update/new/phpbb/template/twig/tokenparser/includecss.php delete mode 100644 install/update/new/phpbb/template/twig/tokenparser/includejs.php delete mode 100644 install/update/new/phpbb/template/twig/tokenparser/includeparser.php delete mode 100644 install/update/new/phpbb/template/twig/tokenparser/includephp.php delete mode 100644 install/update/new/phpbb/template/twig/tokenparser/php.php delete mode 100644 install/update/new/phpbb/textformatter/acp_utils_interface.php delete mode 100644 install/update/new/phpbb/textformatter/s9e/acp_utils.php delete mode 100644 install/update/new/phpbb/textformatter/s9e/bbcode_merger.php delete mode 100644 install/update/new/phpbb/textformatter/s9e/factory.php delete mode 100644 install/update/new/phpbb/textformatter/s9e/link_helper.php delete mode 100644 install/update/new/phpbb/textformatter/s9e/parser.php delete mode 100644 install/update/new/phpbb/textformatter/s9e/quote_helper.php delete mode 100644 install/update/new/phpbb/ucp/controller/reset_password.php delete mode 100644 install/update/new/phpbb/user.php delete mode 100644 install/update/new/phpbb/user_loader.php delete mode 100644 install/update/new/posting.php delete mode 100644 install/update/new/report.php delete mode 100644 install/update/new/search.php delete mode 100644 install/update/new/styles/prosilver/style.cfg delete mode 100644 install/update/new/styles/prosilver/template/attachment.html delete mode 100644 install/update/new/styles/prosilver/template/bbcode.html delete mode 100644 install/update/new/styles/prosilver/template/captcha_recaptcha.html delete mode 100644 install/update/new/styles/prosilver/template/forum_fn.js delete mode 100644 install/update/new/styles/prosilver/template/forumlist_body.html delete mode 100644 install/update/new/styles/prosilver/template/mcp_forum.html delete mode 100644 install/update/new/styles/prosilver/template/mcp_move.html delete mode 100644 install/update/new/styles/prosilver/template/mcp_topic.html delete mode 100644 install/update/new/styles/prosilver/template/memberlist_body.html delete mode 100644 install/update/new/styles/prosilver/template/memberlist_search.html delete mode 100644 install/update/new/styles/prosilver/template/navbar_header.html delete mode 100644 install/update/new/styles/prosilver/template/overall_footer.html delete mode 100644 install/update/new/styles/prosilver/template/overall_header.html delete mode 100644 install/update/new/styles/prosilver/template/plupload.html delete mode 100644 install/update/new/styles/prosilver/template/posting_attach_body.html delete mode 100644 install/update/new/styles/prosilver/template/posting_buttons.html delete mode 100644 install/update/new/styles/prosilver/template/posting_layout.html delete mode 100644 install/update/new/styles/prosilver/template/posting_poll_body.html delete mode 100644 install/update/new/styles/prosilver/template/posting_review.html delete mode 100644 install/update/new/styles/prosilver/template/posting_topic_review.html delete mode 100644 install/update/new/styles/prosilver/template/search_results.html delete mode 100644 install/update/new/styles/prosilver/template/simple_footer.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_agreement.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_attachments.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_avatar_options_upload.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_groups_manage.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_pm_history.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_pm_viewmessage_print.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_profile_profile_info.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_register.html delete mode 100644 install/update/new/styles/prosilver/template/ucp_reset_password.html delete mode 100644 install/update/new/styles/prosilver/template/viewforum_body.html delete mode 100644 install/update/new/styles/prosilver/template/viewtopic_body.html delete mode 100644 install/update/new/styles/prosilver/template/viewtopic_print.html delete mode 100644 install/update/new/styles/prosilver/theme/colours.css delete mode 100644 install/update/new/styles/prosilver/theme/common.css delete mode 100644 install/update/new/styles/prosilver/theme/forms.css delete mode 100644 install/update/new/styles/prosilver/theme/icons.css delete mode 100644 install/update/new/styles/prosilver/theme/images/site_logo.svg delete mode 100644 install/update/new/styles/prosilver/theme/plupload.css delete mode 100644 install/update/new/styles/prosilver/theme/print.css delete mode 100644 install/update/new/styles/prosilver/theme/stylesheet.css delete mode 100644 install/update/new/ucp.php delete mode 100644 install/update/new/viewforum.php delete mode 100644 install/update/new/viewonline.php delete mode 100644 install/update/new/viewtopic.php delete mode 100644 install/update/old/.htaccess delete mode 100644 install/update/old/adm/index.php delete mode 100644 install/update/old/adm/style/acp_attachments.html delete mode 100644 install/update/old/adm/style/acp_avatar_options_upload.html delete mode 100644 install/update/old/adm/style/acp_ban.html delete mode 100644 install/update/old/adm/style/acp_contact.html delete mode 100644 install/update/old/adm/style/acp_database.html delete mode 100644 install/update/old/adm/style/acp_ext_list.html delete mode 100644 install/update/old/adm/style/acp_forums.html delete mode 100644 install/update/old/adm/style/acp_groups.html delete mode 100644 install/update/old/adm/style/acp_help_phpbb.html delete mode 100644 install/update/old/adm/style/acp_icons.html delete mode 100644 install/update/old/adm/style/acp_language.html delete mode 100644 install/update/old/adm/style/acp_main.html delete mode 100644 install/update/old/adm/style/acp_modules.html delete mode 100644 install/update/old/adm/style/acp_permission_roles.html delete mode 100644 install/update/old/adm/style/acp_posting_buttons.html delete mode 100644 install/update/old/adm/style/acp_ranks.html delete mode 100644 install/update/old/adm/style/acp_search.html delete mode 100644 install/update/old/adm/style/acp_styles.html delete mode 100644 install/update/old/adm/style/acp_users_overview.html delete mode 100644 install/update/old/adm/style/acp_users_prefs.html delete mode 100644 install/update/old/adm/style/acp_users_signature.html delete mode 100644 install/update/old/adm/style/admin.css delete mode 100644 install/update/old/adm/style/admin.js delete mode 100644 install/update/old/adm/style/ajax.js delete mode 100644 install/update/old/adm/style/captcha_recaptcha.html delete mode 100644 install/update/old/adm/style/installer_footer.html delete mode 100644 install/update/old/adm/style/overall_footer.html delete mode 100644 install/update/old/adm/style/overall_header.html delete mode 100644 install/update/old/adm/style/permission_forum_copy.html delete mode 100644 install/update/old/adm/style/permission_mask.html delete mode 100644 install/update/old/adm/style/permissions.js delete mode 100644 install/update/old/adm/style/progress_bar.html delete mode 100644 install/update/old/adm/style/simple_footer.html delete mode 100644 install/update/old/adm/style/simple_header.html delete mode 100644 install/update/old/assets/cookieconsent/cookieconsent.min.css delete mode 100644 install/update/old/assets/cookieconsent/cookieconsent.min.js delete mode 100644 install/update/old/assets/javascript/core.js delete mode 100644 install/update/old/assets/javascript/editor.js delete mode 100644 install/update/old/assets/javascript/plupload.js delete mode 100644 install/update/old/common.php delete mode 100644 install/update/old/composer.json delete mode 100644 install/update/old/composer.lock delete mode 100644 install/update/old/config/default/container/parameters.yml delete mode 100644 install/update/old/config/default/container/services.yml delete mode 100644 install/update/old/config/default/container/services_auth.yml delete mode 100644 install/update/old/config/default/container/services_console.yml delete mode 100644 install/update/old/config/default/container/services_cron.yml delete mode 100644 install/update/old/config/default/container/services_password.yml delete mode 100644 install/update/old/config/default/container/services_routing.yml delete mode 100644 install/update/old/config/default/container/services_text_formatter.yml delete mode 100644 install/update/old/config/default/container/services_twig.yml delete mode 100644 install/update/old/config/default/routing/routing.yml delete mode 100644 install/update/old/cron.php delete mode 100644 install/update/old/download/file.php delete mode 100644 install/update/old/ext/phpbb/viglink/acp/viglink_helper.php delete mode 100644 install/update/old/ext/phpbb/viglink/composer.json delete mode 100644 install/update/old/ext/phpbb/viglink/composer.lock delete mode 100644 install/update/old/ext/phpbb/viglink/styles/all/theme/viglink.css delete mode 100644 install/update/old/feed.php delete mode 100644 install/update/old/includes/acp/acp_attachments.php delete mode 100644 install/update/old/includes/acp/acp_bbcodes.php delete mode 100644 install/update/old/includes/acp/acp_board.php delete mode 100644 install/update/old/includes/acp/acp_database.php delete mode 100644 install/update/old/includes/acp/acp_extensions.php delete mode 100644 install/update/old/includes/acp/acp_forums.php delete mode 100644 install/update/old/includes/acp/acp_help_phpbb.php delete mode 100644 install/update/old/includes/acp/acp_main.php delete mode 100644 install/update/old/includes/acp/acp_permissions.php delete mode 100644 install/update/old/includes/acp/acp_prune.php delete mode 100644 install/update/old/includes/acp/acp_reasons.php delete mode 100644 install/update/old/includes/acp/acp_styles.php delete mode 100644 install/update/old/includes/acp/acp_update.php delete mode 100644 install/update/old/includes/acp/acp_users.php delete mode 100644 install/update/old/includes/acp/auth.php delete mode 100644 install/update/old/includes/bbcode.php delete mode 100644 install/update/old/includes/compatibility_globals.php delete mode 100644 install/update/old/includes/constants.php delete mode 100644 install/update/old/includes/diff/engine.php delete mode 100644 install/update/old/includes/functions.php delete mode 100644 install/update/old/includes/functions_acp.php delete mode 100644 install/update/old/includes/functions_admin.php delete mode 100644 install/update/old/includes/functions_compatibility.php delete mode 100644 install/update/old/includes/functions_compress.php delete mode 100644 install/update/old/includes/functions_content.php delete mode 100644 install/update/old/includes/functions_convert.php delete mode 100644 install/update/old/includes/functions_display.php delete mode 100644 install/update/old/includes/functions_download.php delete mode 100644 install/update/old/includes/functions_messenger.php delete mode 100644 install/update/old/includes/functions_module.php delete mode 100644 install/update/old/includes/functions_posting.php delete mode 100644 install/update/old/includes/functions_privmsgs.php delete mode 100644 install/update/old/includes/functions_transfer.php delete mode 100644 install/update/old/includes/functions_user.php delete mode 100644 install/update/old/includes/mcp/mcp_ban.php delete mode 100644 install/update/old/includes/mcp/mcp_logs.php delete mode 100644 install/update/old/includes/mcp/mcp_main.php delete mode 100644 install/update/old/includes/mcp/mcp_notes.php delete mode 100644 install/update/old/includes/mcp/mcp_topic.php delete mode 100644 install/update/old/includes/mcp/mcp_warn.php delete mode 100644 install/update/old/includes/message_parser.php delete mode 100644 install/update/old/includes/questionnaire/questionnaire.php delete mode 100644 install/update/old/includes/startup.php delete mode 100644 install/update/old/includes/ucp/ucp_attachments.php delete mode 100644 install/update/old/includes/ucp/ucp_groups.php delete mode 100644 install/update/old/includes/ucp/ucp_pm.php delete mode 100644 install/update/old/includes/ucp/ucp_pm_compose.php delete mode 100644 install/update/old/includes/ucp/ucp_pm_viewfolder.php delete mode 100644 install/update/old/includes/ucp/ucp_profile.php delete mode 100644 install/update/old/includes/ucp/ucp_register.php delete mode 100644 install/update/old/includes/ucp/ucp_resend.php delete mode 100644 install/update/old/includes/utf/utf_tools.php delete mode 100644 install/update/old/index.php delete mode 100644 install/update/old/language/en/acp/attachments.php delete mode 100644 install/update/old/language/en/acp/board.php delete mode 100644 install/update/old/language/en/acp/common.php delete mode 100644 install/update/old/language/en/acp/forums.php delete mode 100644 install/update/old/language/en/acp/permissions.php delete mode 100644 install/update/old/language/en/acp/permissions_phpbb.php delete mode 100644 install/update/old/language/en/acp/posting.php delete mode 100644 install/update/old/language/en/acp/profile.php delete mode 100644 install/update/old/language/en/acp/styles.php delete mode 100644 install/update/old/language/en/captcha_recaptcha.php delete mode 100644 install/update/old/language/en/cli.php delete mode 100644 install/update/old/language/en/common.php delete mode 100644 install/update/old/language/en/email/admin_activate.txt delete mode 100644 install/update/old/language/en/install.php delete mode 100644 install/update/old/language/en/migrator.php delete mode 100644 install/update/old/language/en/posting.php delete mode 100644 install/update/old/language/en/ucp.php delete mode 100644 install/update/old/mcp.php delete mode 100644 install/update/old/memberlist.php delete mode 100644 install/update/old/phpbb/auth/provider/apache.php delete mode 100644 install/update/old/phpbb/auth/provider/base.php delete mode 100644 install/update/old/phpbb/auth/provider/db.php delete mode 100644 install/update/old/phpbb/auth/provider/ldap.php delete mode 100644 install/update/old/phpbb/auth/provider/oauth/oauth.php delete mode 100644 install/update/old/phpbb/auth/provider/oauth/service/base.php delete mode 100644 install/update/old/phpbb/auth/provider/oauth/service/bitly.php delete mode 100644 install/update/old/phpbb/auth/provider/oauth/service/facebook.php delete mode 100644 install/update/old/phpbb/auth/provider/oauth/service/google.php delete mode 100644 install/update/old/phpbb/auth/provider/oauth/service/service_interface.php delete mode 100644 install/update/old/phpbb/auth/provider/oauth/service/twitter.php delete mode 100644 install/update/old/phpbb/auth/provider/oauth/token_storage.php delete mode 100644 install/update/old/phpbb/auth/provider/provider_interface.php delete mode 100644 install/update/old/phpbb/avatar/driver/remote.php delete mode 100644 install/update/old/phpbb/avatar/driver/upload.php delete mode 100644 install/update/old/phpbb/cache/driver/memcached.php delete mode 100644 install/update/old/phpbb/cache/driver/memory.php delete mode 100644 install/update/old/phpbb/captcha/non_gd.php delete mode 100644 install/update/old/phpbb/captcha/plugins/qa.php delete mode 100644 install/update/old/phpbb/class_loader.php delete mode 100644 install/update/old/phpbb/config/config.php delete mode 100644 install/update/old/phpbb/config_php_file.php delete mode 100644 install/update/old/phpbb/console/command/cron/run.php delete mode 100644 install/update/old/phpbb/console/command/extension/enable.php delete mode 100644 install/update/old/phpbb/console/command/update/check.php delete mode 100644 install/update/old/phpbb/console/command/user/add.php delete mode 100644 install/update/old/phpbb/content_visibility.php delete mode 100644 install/update/old/phpbb/controller/helper.php delete mode 100644 install/update/old/phpbb/cron/manager.php delete mode 100644 install/update/old/phpbb/cron/task/core/update_hashes.php delete mode 100644 install/update/old/phpbb/cron/task/wrapper.php delete mode 100644 install/update/old/phpbb/db/driver/driver.php delete mode 100644 install/update/old/phpbb/db/driver/driver_interface.php delete mode 100644 install/update/old/phpbb/db/driver/factory.php delete mode 100644 install/update/old/phpbb/db/driver/mssql_odbc.php delete mode 100644 install/update/old/phpbb/db/driver/mssqlnative.php delete mode 100644 install/update/old/phpbb/db/driver/mysqli.php delete mode 100644 install/update/old/phpbb/db/driver/oracle.php delete mode 100644 install/update/old/phpbb/db/driver/postgres.php delete mode 100644 install/update/old/phpbb/db/driver/sqlite3.php delete mode 100644 install/update/old/phpbb/db/extractor/mysql_extractor.php delete mode 100644 install/update/old/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php delete mode 100644 install/update/old/phpbb/db/migration/data/v310/softdelete_p1.php delete mode 100644 install/update/old/phpbb/db/migration/tool/module.php delete mode 100644 install/update/old/phpbb/db/migrator.php delete mode 100644 install/update/old/phpbb/db/tools/mssql.php delete mode 100644 install/update/old/phpbb/db/tools/postgres.php delete mode 100644 install/update/old/phpbb/db/tools/tools.php delete mode 100644 install/update/old/phpbb/di/container_builder.php delete mode 100644 install/update/old/phpbb/di/extension/container_configuration.php delete mode 100644 install/update/old/phpbb/di/extension/core.php delete mode 100644 install/update/old/phpbb/di/service_collection.php delete mode 100644 install/update/old/phpbb/event/md_exporter.php delete mode 100644 install/update/old/phpbb/extension/extension_interface.php delete mode 100644 install/update/old/phpbb/extension/manager.php delete mode 100644 install/update/old/phpbb/feed/controller/feed.php delete mode 100644 install/update/old/phpbb/feed/topics_active.php delete mode 100644 install/update/old/phpbb/files/filespec.php delete mode 100644 install/update/old/phpbb/filesystem.php delete mode 100644 install/update/old/phpbb/filesystem/filesystem.php delete mode 100644 install/update/old/phpbb/filesystem/filesystem_interface.php delete mode 100644 install/update/old/phpbb/finder.php delete mode 100644 install/update/old/phpbb/group/helper.php delete mode 100644 install/update/old/phpbb/help/controller/bbcode.php delete mode 100644 install/update/old/phpbb/help/controller/faq.php delete mode 100644 install/update/old/phpbb/install/controller/helper.php delete mode 100644 install/update/old/phpbb/install/helper/container_factory.php delete mode 100644 install/update/old/phpbb/install/helper/database.php delete mode 100644 install/update/old/phpbb/install/helper/iohandler/iohandler_interface.php delete mode 100644 install/update/old/phpbb/install/installer_configuration.php delete mode 100644 install/update/old/phpbb/install/module/install_database/task/add_config_settings.php delete mode 100644 install/update/old/phpbb/install/module/install_database/task/create_schema.php delete mode 100644 install/update/old/phpbb/install/module/install_database/task/set_up_database.php delete mode 100644 install/update/old/phpbb/install/module/install_filesystem/task/create_config_file.php delete mode 100644 install/update/old/phpbb/install/module/requirements/task/check_server_environment.php delete mode 100644 install/update/old/phpbb/install/module_base.php delete mode 100644 install/update/old/phpbb/language/language_file_loader.php delete mode 100644 install/update/old/phpbb/lock/db.php delete mode 100644 install/update/old/phpbb/lock/flock.php delete mode 100644 install/update/old/phpbb/message/form.php delete mode 100644 install/update/old/phpbb/mimetype/guesser.php delete mode 100644 install/update/old/phpbb/notification/type/approve_post.php delete mode 100644 install/update/old/phpbb/notification/type/approve_topic.php delete mode 100644 install/update/old/phpbb/notification/type/base.php delete mode 100644 install/update/old/phpbb/notification/type/post.php delete mode 100644 install/update/old/phpbb/notification/type/topic.php delete mode 100644 install/update/old/phpbb/notification/type/type_interface.php delete mode 100644 install/update/old/phpbb/passwords/manager.php delete mode 100644 install/update/old/phpbb/permissions.php delete mode 100644 install/update/old/phpbb/plupload/plupload.php delete mode 100644 install/update/old/phpbb/report/report_handler.php delete mode 100644 install/update/old/phpbb/request/request.php delete mode 100644 install/update/old/phpbb/request/request_interface.php delete mode 100644 install/update/old/phpbb/request/type_cast_helper.php delete mode 100644 install/update/old/phpbb/search/fulltext_mysql.php delete mode 100644 install/update/old/phpbb/search/fulltext_native.php delete mode 100644 install/update/old/phpbb/search/fulltext_postgres.php delete mode 100644 install/update/old/phpbb/search/fulltext_sphinx.php delete mode 100644 install/update/old/phpbb/session.php delete mode 100644 install/update/old/phpbb/template/asset.php delete mode 100644 install/update/old/phpbb/template/context.php delete mode 100644 install/update/old/phpbb/template/template.php delete mode 100644 install/update/old/phpbb/template/twig/extension.php delete mode 100644 install/update/old/phpbb/template/twig/lexer.php delete mode 100644 install/update/old/phpbb/template/twig/loader.php delete mode 100644 install/update/old/phpbb/template/twig/node/definenode.php delete mode 100644 install/update/old/phpbb/template/twig/node/includeasset.php delete mode 100644 install/update/old/phpbb/template/twig/node/includephp.php delete mode 100644 install/update/old/phpbb/template/twig/tokenparser/defineparser.php delete mode 100644 install/update/old/phpbb/template/twig/tokenparser/event.php delete mode 100644 install/update/old/phpbb/template/twig/tokenparser/includecss.php delete mode 100644 install/update/old/phpbb/template/twig/tokenparser/includejs.php delete mode 100644 install/update/old/phpbb/template/twig/tokenparser/includeparser.php delete mode 100644 install/update/old/phpbb/template/twig/tokenparser/includephp.php delete mode 100644 install/update/old/phpbb/template/twig/tokenparser/php.php delete mode 100644 install/update/old/phpbb/textformatter/s9e/bbcode_merger.php delete mode 100644 install/update/old/phpbb/textformatter/s9e/factory.php delete mode 100644 install/update/old/phpbb/textformatter/s9e/link_helper.php delete mode 100644 install/update/old/phpbb/textformatter/s9e/parser.php delete mode 100644 install/update/old/phpbb/textformatter/s9e/quote_helper.php delete mode 100644 install/update/old/phpbb/user.php delete mode 100644 install/update/old/phpbb/user_loader.php delete mode 100644 install/update/old/posting.php delete mode 100644 install/update/old/report.php delete mode 100644 install/update/old/search.php delete mode 100644 install/update/old/styles/prosilver/style.cfg delete mode 100644 install/update/old/styles/prosilver/template/attachment.html delete mode 100644 install/update/old/styles/prosilver/template/bbcode.html delete mode 100644 install/update/old/styles/prosilver/template/captcha_recaptcha.html delete mode 100644 install/update/old/styles/prosilver/template/forum_fn.js delete mode 100644 install/update/old/styles/prosilver/template/forumlist_body.html delete mode 100644 install/update/old/styles/prosilver/template/mcp_forum.html delete mode 100644 install/update/old/styles/prosilver/template/mcp_move.html delete mode 100644 install/update/old/styles/prosilver/template/mcp_topic.html delete mode 100644 install/update/old/styles/prosilver/template/memberlist_body.html delete mode 100644 install/update/old/styles/prosilver/template/memberlist_search.html delete mode 100644 install/update/old/styles/prosilver/template/navbar_header.html delete mode 100644 install/update/old/styles/prosilver/template/overall_footer.html delete mode 100644 install/update/old/styles/prosilver/template/overall_header.html delete mode 100644 install/update/old/styles/prosilver/template/plupload.html delete mode 100644 install/update/old/styles/prosilver/template/posting_attach_body.html delete mode 100644 install/update/old/styles/prosilver/template/posting_buttons.html delete mode 100644 install/update/old/styles/prosilver/template/posting_layout.html delete mode 100644 install/update/old/styles/prosilver/template/posting_poll_body.html delete mode 100644 install/update/old/styles/prosilver/template/posting_review.html delete mode 100644 install/update/old/styles/prosilver/template/posting_topic_review.html delete mode 100644 install/update/old/styles/prosilver/template/search_results.html delete mode 100644 install/update/old/styles/prosilver/template/simple_footer.html delete mode 100644 install/update/old/styles/prosilver/template/ucp_agreement.html delete mode 100644 install/update/old/styles/prosilver/template/ucp_attachments.html delete mode 100644 install/update/old/styles/prosilver/template/ucp_avatar_options_upload.html delete mode 100644 install/update/old/styles/prosilver/template/ucp_groups_manage.html delete mode 100644 install/update/old/styles/prosilver/template/ucp_pm_history.html delete mode 100644 install/update/old/styles/prosilver/template/ucp_pm_viewmessage_print.html delete mode 100644 install/update/old/styles/prosilver/template/ucp_profile_profile_info.html delete mode 100644 install/update/old/styles/prosilver/template/ucp_register.html delete mode 100644 install/update/old/styles/prosilver/template/viewforum_body.html delete mode 100644 install/update/old/styles/prosilver/template/viewtopic_body.html delete mode 100644 install/update/old/styles/prosilver/template/viewtopic_print.html delete mode 100644 install/update/old/styles/prosilver/theme/colours.css delete mode 100644 install/update/old/styles/prosilver/theme/common.css delete mode 100644 install/update/old/styles/prosilver/theme/forms.css delete mode 100644 install/update/old/styles/prosilver/theme/icons.css delete mode 100644 install/update/old/styles/prosilver/theme/plupload.css delete mode 100644 install/update/old/styles/prosilver/theme/print.css delete mode 100644 install/update/old/styles/prosilver/theme/stylesheet.css delete mode 100644 install/update/old/ucp.php delete mode 100644 install/update/old/viewforum.php delete mode 100644 install/update/old/viewonline.php delete mode 100644 install/update/old/viewtopic.php delete mode 100644 language/fr/email/user_activate_passwd.txt delete mode 100644 styles/Milk_v2/theme/blank.css.css delete mode 100644 styles/Milk_v2/theme/images/icon_download.gif delete mode 100644 styles/Milk_v2/theme/images/icon_offline.gif delete mode 100644 styles/Milk_v2/theme/images/icon_online.gif delete mode 100644 styles/Milk_v2/theme/images/icon_rate_bad.gif delete mode 100644 styles/Milk_v2/theme/images/icon_rate_good.gif delete mode 100644 styles/Milk_v2/theme/images/quote.gif delete mode 100644 styles/Milk_v2/theme/images/quote_rtl.gif delete mode 100644 styles/Milk_v2/theme/images/sticky_read_locked.gif delete mode 100644 styles/Milk_v2/theme/images/sticky_read_locked_mine.gif delete mode 100644 styles/Milk_v2/theme/images/sticky_read_mine.gif delete mode 100644 styles/Milk_v2/theme/images/sticky_unread.gif delete mode 100644 styles/Milk_v2/theme/stylesheet.css delete mode 100644 styles/prosilver/theme/stylesheet.css delete mode 100644 vendor/guzzlehttp/guzzle/src/BatchResults.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Collection.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/Emitter.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/EndEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/ErrorEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/EventInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/HasEmitterInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/HasEmitterTrait.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/ProgressEvent.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Exception/ParseException.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Exception/StateException.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Exception/XmlParseException.php delete mode 100644 vendor/guzzlehttp/guzzle/src/HasDataTrait.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/AppliesHeadersInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/FutureResponse.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/MessageInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/MessageParser.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/Request.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/Response.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Mimetypes.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Post/PostBody.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Post/PostFile.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Query.php delete mode 100644 vendor/guzzlehttp/guzzle/src/QueryParser.php delete mode 100644 vendor/guzzlehttp/guzzle/src/RequestFsm.php delete mode 100644 vendor/guzzlehttp/guzzle/src/RingBridge.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Subscriber/Cookie.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Subscriber/History.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php delete mode 100644 vendor/guzzlehttp/guzzle/src/ToArrayInterface.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Transaction.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Url.php delete mode 100644 vendor/guzzlehttp/guzzle/src/Utils.php delete mode 100644 vendor/guzzlehttp/ringphp/.editorconfig delete mode 100644 vendor/guzzlehttp/ringphp/LICENSE delete mode 100644 vendor/guzzlehttp/ringphp/composer.json delete mode 100644 vendor/guzzlehttp/ringphp/src/Client/ClientUtils.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Client/CurlHandler.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Client/CurlMultiHandler.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Client/Middleware.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Client/MockHandler.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Client/StreamHandler.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Core.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Exception/CancelledException.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Exception/CancelledFutureAccessException.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Exception/ConnectException.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Exception/RingException.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Future/BaseFutureTrait.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Future/CompletedFutureArray.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Future/CompletedFutureValue.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Future/FutureArray.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Future/FutureArrayInterface.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Future/FutureInterface.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Future/FutureValue.php delete mode 100644 vendor/guzzlehttp/ringphp/src/Future/MagicFutureTrait.php delete mode 100644 vendor/guzzlehttp/streams/LICENSE delete mode 100644 vendor/guzzlehttp/streams/composer.json delete mode 100644 vendor/guzzlehttp/streams/src/AppendStream.php delete mode 100644 vendor/guzzlehttp/streams/src/AsyncReadStream.php delete mode 100644 vendor/guzzlehttp/streams/src/BufferStream.php delete mode 100644 vendor/guzzlehttp/streams/src/CachingStream.php delete mode 100644 vendor/guzzlehttp/streams/src/DroppingStream.php delete mode 100644 vendor/guzzlehttp/streams/src/Exception/CannotAttachException.php delete mode 100644 vendor/guzzlehttp/streams/src/Exception/SeekException.php delete mode 100644 vendor/guzzlehttp/streams/src/FnStream.php delete mode 100644 vendor/guzzlehttp/streams/src/GuzzleStreamWrapper.php delete mode 100644 vendor/guzzlehttp/streams/src/InflateStream.php delete mode 100644 vendor/guzzlehttp/streams/src/LazyOpenStream.php delete mode 100644 vendor/guzzlehttp/streams/src/LimitStream.php delete mode 100644 vendor/guzzlehttp/streams/src/MetadataStreamInterface.php delete mode 100644 vendor/guzzlehttp/streams/src/NoSeekStream.php delete mode 100644 vendor/guzzlehttp/streams/src/NullStream.php delete mode 100644 vendor/guzzlehttp/streams/src/PumpStream.php delete mode 100644 vendor/guzzlehttp/streams/src/Stream.php delete mode 100644 vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php delete mode 100644 vendor/guzzlehttp/streams/src/StreamInterface.php delete mode 100644 vendor/guzzlehttp/streams/src/Utils.php delete mode 100644 vendor/ircmaxell/password-compat/LICENSE.md delete mode 100644 vendor/ircmaxell/password-compat/composer.json delete mode 100644 vendor/ircmaxell/password-compat/lib/password.php delete mode 100644 vendor/ircmaxell/password-compat/version-test.php delete mode 100644 vendor/ocramius/proxy-manager/.gitignore delete mode 100644 vendor/ocramius/proxy-manager/.scrutinizer.yml delete mode 100644 vendor/ocramius/proxy-manager/.travis.install.sh delete mode 100644 vendor/ocramius/proxy-manager/.travis.yml delete mode 100644 vendor/ocramius/proxy-manager/CONTRIBUTING.md delete mode 100644 vendor/ocramius/proxy-manager/examples/access-interceptor-scope-localizer.php delete mode 100644 vendor/ocramius/proxy-manager/examples/ghost-object.php delete mode 100644 vendor/ocramius/proxy-manager/examples/remote-proxy.php delete mode 100644 vendor/ocramius/proxy-manager/examples/remote-proxy/remote-proxy-server.php delete mode 100644 vendor/ocramius/proxy-manager/examples/smart-reference.php delete mode 100644 vendor/ocramius/proxy-manager/examples/virtual-proxy.php delete mode 100644 vendor/ocramius/proxy-manager/html-docs/access-interceptor-scope-localizer-proxy.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/access-interceptor-value-holder-proxy.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/contributing.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/copyright.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/credits.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/css/styles.css delete mode 100644 vendor/ocramius/proxy-manager/html-docs/download.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/favicon.ico delete mode 100644 vendor/ocramius/proxy-manager/html-docs/ghost-object.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/img/block.png delete mode 100644 vendor/ocramius/proxy-manager/html-docs/img/enf.png delete mode 100644 vendor/ocramius/proxy-manager/html-docs/index.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/null-object.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/production.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/remote-object.html delete mode 100644 vendor/ocramius/proxy-manager/html-docs/virtual-proxy.html delete mode 100644 vendor/ocramius/proxy-manager/index.html delete mode 100644 vendor/ocramius/proxy-manager/phpdox.xml.dist delete mode 100644 vendor/ocramius/proxy-manager/phpmd.xml.dist delete mode 100644 vendor/ocramius/proxy-manager/phpunit.xml.dist delete mode 100644 vendor/ocramius/proxy-manager/proxy-manager.png delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/Factory/AbstractLazyFactory.php delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/Generator/ParameterGenerator.php delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Constructor.php delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Constructor.php delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/LazyLoading/MethodGenerator/Constructor.php delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/LazyLoadingMethodInterceptor.php delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/NullObject/MethodGenerator/Constructor.php delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/PropertyGenerator/PublicPropertiesDefaults.php delete mode 100644 vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/Constructor.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Autoloader/AutoloaderTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ConfigurationTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/DisabledMethodExceptionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/FileNotWritableExceptionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/InvalidProxiedClassExceptionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/InvalidProxyDirectoryExceptionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/UnsupportedProxiedClassExceptionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AbstractBaseFactoryTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AccessInterceptorScopeLocalizerFactoryTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AccessInterceptorValueHolderFactoryTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/LazyLoadingGhostFactoryTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/LazyLoadingValueHolderFactoryTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/NullObjectFactoryTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/BaseAdapterTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/JsonRpcTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/SoapTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/XmlRpcTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObjectFactoryTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/FileLocator/FileLocatorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/AccessInterceptorScopeLocalizerFunctionalTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/AccessInterceptorValueHolderFunctionalTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/BaseLazyLoadingPerformanceTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/BasePerformanceTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/FatalPreventionFunctionalTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingGhostFunctionalTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingGhostPerformanceTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingValueHolderFunctionalTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingValueHolderPerformanceTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/MultipleProxyGenerationTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/NullObjectFunctionalTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/RemoteObjectFunctionalTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/ClassGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/MagicMethodGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/MethodGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/ParameterGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/Util/ClassGeneratorUtilsTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/Util/UniqueIdentifierGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/BaseGeneratorStrategyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/EvaluatingGeneratorStrategyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/FileWriterGeneratorStrategyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/ClassNameInflectorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/Util/ParameterEncoderTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/Util/ParameterHasherTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AbstractProxyGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/MagicWakeupTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodPrefixInterceptorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodSuffixInterceptorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodPrefixInterceptorsTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodSuffixInterceptorsTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/ConstructorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/InterceptedMethodTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicCloneTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicGetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicIssetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSleepTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicUnsetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Util/InterceptorGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizerTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/LazyLoading/MethodGenerator/ConstructorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/ConstructorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/InterceptedMethodTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicCloneTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicGetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicIssetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicSetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicUnsetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Util/InterceptorGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolderTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Assertion/CanProxyAssertionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/CallInitializerTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/GetProxyInitializerTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/InitializeProxyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/IsProxyInitializedTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/LazyLoadingMethodInterceptorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicCloneTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicIssetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSleepTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicUnsetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/SetProxyInitializerTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializationTrackerTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializerPropertyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhostGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/GetProxyInitializerTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/InitializeProxyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/IsProxyInitializedTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/LazyLoadingMethodInterceptorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicCloneTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicGetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicIssetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSleepTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicUnsetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/SetProxyInitializerTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/InitializerPropertyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/ValueHolderPropertyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolderGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObject/MethodGenerator/ConstructorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObject/MethodGenerator/NullObjectMethodInterceptorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObjectGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/AbstractUniquePropertyNameTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/PublicPropertiesDefaultsTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/PublicPropertiesMapTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/ConstructorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicGetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicIssetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicSetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicUnsetTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/RemoteObjectMethodTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/PropertyGenerator/AdapterPropertyTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObjectGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Util/ProxiedMethodsFilterTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Util/PublicScopeSimulatorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/ValueHolder/MethodGenerator/GetWrappedValueHolderValueTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/ValueHolder/MethodGenerator/MagicSleepTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/ClassSignatureGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/Exception/InvalidSignatureExceptionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/Exception/MissingSignatureExceptionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/SignatureCheckerTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/SignatureGeneratorTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTest/VersionTest.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/AccessInterceptorValueHolderMock.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/BaseClass.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/BaseInterface.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/CallableTypeHintClass.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithAbstractProtectedMethod.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithByRefMagicMethods.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithFinalMagicMethods.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithFinalMethods.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMagicMethods.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMethodWithDefaultParameters.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMixedProperties.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPrivateProperties.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithProtectedProperties.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPublicArrayProperty.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPublicProperties.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithSelfHint.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/EmptyClass.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/FinalClass.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/HydratedObject.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/LazyLoadingMock.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/NullObjectMock.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ProxyGenerator/LazyLoading/MethodGenerator/ClassWithTwoPublicProperties.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/BazServiceInterface.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/Foo.php delete mode 100644 vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/FooServiceInterface.php delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/README.md delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-isset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-unset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-isset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-unset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-isset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-unset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-isset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-unset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-with-cache.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/cache/README.md delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/init.php delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-allows-inexisting-magic-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-allows-inexisting-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-inexisting-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-isset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-unset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-isset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-unset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-with-cache.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-isset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-unset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-isset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-read.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-unset.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-write.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-internal-php-classes.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-with-cache.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/null-object-public-function-empty.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/null-object-public-property-empty.phpt delete mode 100644 vendor/ocramius/proxy-manager/tests/language-feature-scripts/remote-object-json-adapter-denies-unknow-method.phpt delete mode 100644 vendor/paragonie/random_compat/RATIONALE.md delete mode 100644 vendor/paragonie/random_compat/lib/byte_safe_strings.php delete mode 100644 vendor/paragonie/random_compat/lib/cast_to_int.php delete mode 100644 vendor/paragonie/random_compat/lib/error_polyfill.php delete mode 100644 vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php delete mode 100644 vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php delete mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium.php delete mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php delete mode 100644 vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php delete mode 100644 vendor/paragonie/random_compat/lib/random_bytes_openssl.php delete mode 100644 vendor/paragonie/random_compat/lib/random_int.php delete mode 100644 vendor/react/promise/LICENSE delete mode 100644 vendor/react/promise/composer.json delete mode 100644 vendor/react/promise/src/CancellablePromiseInterface.php delete mode 100644 vendor/react/promise/src/CancellationQueue.php delete mode 100644 vendor/react/promise/src/Deferred.php delete mode 100644 vendor/react/promise/src/Exception/LengthException.php delete mode 100644 vendor/react/promise/src/ExtendedPromiseInterface.php delete mode 100644 vendor/react/promise/src/FulfilledPromise.php delete mode 100644 vendor/react/promise/src/LazyPromise.php delete mode 100644 vendor/react/promise/src/Promise.php delete mode 100644 vendor/react/promise/src/PromiseInterface.php delete mode 100644 vendor/react/promise/src/PromisorInterface.php delete mode 100644 vendor/react/promise/src/RejectedPromise.php delete mode 100644 vendor/react/promise/src/UnhandledRejectionException.php delete mode 100644 vendor/react/promise/src/functions.php delete mode 100644 vendor/react/promise/src/functions_include.php delete mode 100644 vendor/s9e/text-formatter/src/Configurator/RendererGenerators/XSLT/Optimizer.php delete mode 100644 vendor/symfony/config/Definition/ReferenceDumper.php delete mode 100644 vendor/symfony/config/Resource/BCResourceInterfaceChecker.php delete mode 100644 vendor/symfony/console/Helper/DialogHelper.php delete mode 100644 vendor/symfony/console/Helper/ProgressHelper.php delete mode 100644 vendor/symfony/console/Helper/TableHelper.php delete mode 100644 vendor/symfony/console/Shell.php delete mode 100644 vendor/symfony/debug/Exception/DummyException.php delete mode 100644 vendor/symfony/dependency-injection/ContainerAware.php delete mode 100644 vendor/symfony/dependency-injection/Exception/InactiveScopeException.php delete mode 100644 vendor/symfony/dependency-injection/Exception/ScopeCrossingInjectionException.php delete mode 100644 vendor/symfony/dependency-injection/Exception/ScopeWideningInjectionException.php delete mode 100644 vendor/symfony/dependency-injection/IntrospectableContainerInterface.php delete mode 100644 vendor/symfony/dependency-injection/Scope.php delete mode 100644 vendor/symfony/dependency-injection/ScopeInterface.php delete mode 100644 vendor/symfony/dependency-injection/SimpleXMLElement.php delete mode 100644 vendor/symfony/finder/Adapter/AbstractAdapter.php delete mode 100644 vendor/symfony/finder/Adapter/AbstractFindAdapter.php delete mode 100644 vendor/symfony/finder/Adapter/AdapterInterface.php delete mode 100644 vendor/symfony/finder/Adapter/BsdFindAdapter.php delete mode 100644 vendor/symfony/finder/Adapter/GnuFindAdapter.php delete mode 100644 vendor/symfony/finder/Adapter/PhpAdapter.php delete mode 100644 vendor/symfony/finder/Exception/AdapterFailureException.php delete mode 100644 vendor/symfony/finder/Exception/OperationNotPermitedException.php delete mode 100644 vendor/symfony/finder/Exception/ShellCommandFailureException.php delete mode 100644 vendor/symfony/finder/Expression/Expression.php delete mode 100644 vendor/symfony/finder/Expression/Glob.php delete mode 100644 vendor/symfony/finder/Expression/Regex.php delete mode 100644 vendor/symfony/finder/Expression/ValueInterface.php delete mode 100644 vendor/symfony/finder/Iterator/FilePathsIterator.php delete mode 100644 vendor/symfony/finder/Shell/Command.php delete mode 100644 vendor/symfony/finder/Shell/Shell.php delete mode 100644 vendor/symfony/http-foundation/Session/Storage/Handler/LegacyPdoSessionHandler.php delete mode 100644 vendor/symfony/http-kernel/Debug/ErrorHandler.php delete mode 100644 vendor/symfony/http-kernel/Debug/ExceptionHandler.php delete mode 100644 vendor/symfony/http-kernel/DependencyInjection/ContainerAwareHttpKernel.php delete mode 100644 vendor/symfony/http-kernel/DependencyInjection/RegisterListenersPass.php delete mode 100644 vendor/symfony/http-kernel/EventListener/ErrorsLoggerListener.php delete mode 100644 vendor/symfony/http-kernel/EventListener/EsiListener.php delete mode 100644 vendor/symfony/http-kernel/Exception/FatalErrorException.php delete mode 100644 vendor/symfony/http-kernel/Exception/FlattenException.php delete mode 100644 vendor/symfony/http-kernel/HttpCache/EsiResponseCacheStrategy.php delete mode 100644 vendor/symfony/http-kernel/HttpCache/EsiResponseCacheStrategyInterface.php delete mode 100644 vendor/symfony/http-kernel/Log/LoggerInterface.php delete mode 100644 vendor/symfony/http-kernel/Log/NullLogger.php delete mode 100644 vendor/symfony/http-kernel/Profiler/BaseMemcacheProfilerStorage.php delete mode 100644 vendor/symfony/http-kernel/Profiler/MemcacheProfilerStorage.php delete mode 100644 vendor/symfony/http-kernel/Profiler/MemcachedProfilerStorage.php delete mode 100644 vendor/symfony/http-kernel/Profiler/MongoDbProfilerStorage.php delete mode 100644 vendor/symfony/http-kernel/Profiler/MysqlProfilerStorage.php delete mode 100644 vendor/symfony/http-kernel/Profiler/PdoProfilerStorage.php delete mode 100644 vendor/symfony/http-kernel/Profiler/RedisProfilerStorage.php delete mode 100644 vendor/symfony/http-kernel/Profiler/SqliteProfilerStorage.php delete mode 100644 vendor/symfony/polyfill-php54/LICENSE delete mode 100644 vendor/symfony/polyfill-php54/Php54.php delete mode 100644 vendor/symfony/polyfill-php54/README.md delete mode 100644 vendor/symfony/polyfill-php54/Resources/stubs/CallbackFilterIterator.php delete mode 100644 vendor/symfony/polyfill-php54/Resources/stubs/RecursiveCallbackFilterIterator.php delete mode 100644 vendor/symfony/polyfill-php54/Resources/stubs/SessionHandlerInterface.php delete mode 100644 vendor/symfony/polyfill-php54/bootstrap.php delete mode 100644 vendor/symfony/polyfill-php54/composer.json delete mode 100644 vendor/symfony/polyfill-php55/LICENSE delete mode 100644 vendor/symfony/polyfill-php55/Php55.php delete mode 100644 vendor/symfony/polyfill-php55/Php55ArrayColumn.php delete mode 100644 vendor/symfony/polyfill-php55/README.md delete mode 100644 vendor/symfony/polyfill-php55/bootstrap.php delete mode 100644 vendor/symfony/polyfill-php55/composer.json delete mode 100644 vendor/symfony/routing/Matcher/ApacheUrlMatcher.php delete mode 100644 vendor/symfony/routing/Matcher/Dumper/ApacheMatcherDumper.php delete mode 100644 vendor/symfony/routing/Matcher/Dumper/DumperPrefixCollection.php delete mode 100644 vendor/symfony/twig-bridge/Node/FormEnctypeNode.php delete mode 100644 vendor/twig/twig/lib/Twig/Autoloader.php delete mode 100644 vendor/twig/twig/lib/Twig/CompilerInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/Filter/Function.php delete mode 100644 vendor/twig/twig/lib/Twig/Filter/Method.php delete mode 100644 vendor/twig/twig/lib/Twig/Filter/Node.php delete mode 100644 vendor/twig/twig/lib/Twig/FilterCallableInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/FilterInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/Function/Function.php delete mode 100644 vendor/twig/twig/lib/Twig/Function/Method.php delete mode 100644 vendor/twig/twig/lib/Twig/Function/Node.php delete mode 100644 vendor/twig/twig/lib/Twig/FunctionCallableInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/FunctionInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/LexerInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/Loader/String.php delete mode 100644 vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php delete mode 100644 vendor/twig/twig/lib/Twig/Node/SetTemp.php delete mode 100644 vendor/twig/twig/lib/Twig/NodeInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/ParserInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/TemplateInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/Test/Function.php delete mode 100644 vendor/twig/twig/lib/Twig/Test/Method.php delete mode 100644 vendor/twig/twig/lib/Twig/Test/Node.php delete mode 100644 vendor/twig/twig/lib/Twig/TestCallableInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/TestInterface.php delete mode 100644 vendor/twig/twig/lib/Twig/TokenParserBroker.php delete mode 100644 vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php delete mode 100644 vendor/twig/twig/src/Node/SetTempNode.php delete mode 100644 vendor/zendframework/zend-eventmanager/src/GlobalEventManager.php delete mode 100644 vendor/zendframework/zend-eventmanager/src/ProvidesEvents.php delete mode 100644 vendor/zendframework/zend-eventmanager/src/SharedEventAggregateAwareInterface.php delete mode 100644 vendor/zendframework/zend-eventmanager/src/SharedEventManagerAwareInterface.php delete mode 100644 vendor/zendframework/zend-eventmanager/src/SharedListenerAggregateInterface.php delete mode 100644 vendor/zendframework/zend-eventmanager/src/StaticEventManager.php delete mode 100644 vendor/zendframework/zend-stdlib/LICENSE.md delete mode 100644 vendor/zendframework/zend-stdlib/composer.json delete mode 100644 vendor/zendframework/zend-stdlib/src/AbstractOptions.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ArrayObject.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ArraySerializableInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ArrayStack.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ArrayUtils.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeRemoveKey.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeReplaceKey.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeReplaceKeyInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/CallbackHandler.php delete mode 100644 vendor/zendframework/zend-stdlib/src/DateTime.php delete mode 100644 vendor/zendframework/zend-stdlib/src/DispatchableInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ErrorHandler.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Exception/BadMethodCallException.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Exception/DomainException.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Exception/ExceptionInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Exception/ExtensionNotLoadedException.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Exception/InvalidArgumentException.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Exception/InvalidCallbackException.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Exception/LogicException.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Exception/RuntimeException.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Extractor/ExtractionInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Glob.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Guard/AllGuardsTrait.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Guard/ArrayOrTraversableGuardTrait.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Guard/EmptyGuardTrait.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Guard/GuardUtils.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Guard/NullGuardTrait.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/AbstractHydrator.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/AggregateHydrator.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/ExtractEvent.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/HydrateEvent.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/HydratorListener.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/ArraySerializable.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/ClassMethods.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/DelegatingHydrator.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/DelegatingHydratorFactory.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/FilterComposite.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/FilterInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/FilterProviderInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/GetFilter.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/HasFilter.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/IsFilter.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/MethodMatchFilter.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/NumberOfParameterFilter.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Filter/OptionalParametersFilter.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/FilterEnabledInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/HydrationInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/HydratorAwareInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/HydratorAwareTrait.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/HydratorInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/HydratorOptionsInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/HydratorPluginManager.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/ArrayMapNamingStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/CompositeNamingStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/IdentityNamingStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/MapNamingStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/NamingStrategyInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/UnderscoreNamingStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategyEnabledInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/ObjectProperty.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Reflection.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/BooleanStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/ClosureStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/DateTimeFormatterStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/DefaultStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/Exception/ExceptionInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/Exception/InvalidArgumentException.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/ExplodeStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/SerializableStrategy.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/StrategyChain.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/StrategyInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Hydrator/StrategyEnabledInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/InitializableInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/JsonSerializable.php delete mode 100644 vendor/zendframework/zend-stdlib/src/JsonSerializable/PhpLegacyCompatibility.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Message.php delete mode 100644 vendor/zendframework/zend-stdlib/src/MessageInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ParameterObjectInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Parameters.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ParametersInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/PriorityList.php delete mode 100644 vendor/zendframework/zend-stdlib/src/PriorityQueue.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Request.php delete mode 100644 vendor/zendframework/zend-stdlib/src/RequestInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/Response.php delete mode 100644 vendor/zendframework/zend-stdlib/src/ResponseInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/SplPriorityQueue.php delete mode 100644 vendor/zendframework/zend-stdlib/src/SplQueue.php delete mode 100644 vendor/zendframework/zend-stdlib/src/SplStack.php delete mode 100644 vendor/zendframework/zend-stdlib/src/StringUtils.php delete mode 100644 vendor/zendframework/zend-stdlib/src/StringWrapper/AbstractStringWrapper.php delete mode 100644 vendor/zendframework/zend-stdlib/src/StringWrapper/Iconv.php delete mode 100644 vendor/zendframework/zend-stdlib/src/StringWrapper/Intl.php delete mode 100644 vendor/zendframework/zend-stdlib/src/StringWrapper/MbString.php delete mode 100644 vendor/zendframework/zend-stdlib/src/StringWrapper/Native.php delete mode 100644 vendor/zendframework/zend-stdlib/src/StringWrapper/StringWrapperInterface.php delete mode 100644 vendor/zendframework/zend-stdlib/src/compatibility/autoload.php diff --git a/README.rdoc b/README.rdoc deleted file mode 100644 index e69de29..0000000 diff --git a/docs/assets/images/site_logo.gif b/docs/assets/images/site_logo.gif deleted file mode 100644 index 2517fbedd691d93bebf31860a8b75b8de8b450f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5070 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 diff --git a/images/avatars/gallery/Civils_F/Civil_F_1.png b/images/avatars/gallery/Civils_F/Civil_F_1.png deleted file mode 100644 index f17f1257a005ceca6bed69e1714e829b5c55e435..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28002 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 diff --git a/images/avatars/gallery/Civils_F/Civil_F_12.png b/images/avatars/gallery/Civils_F/Civil_F_12.png deleted file mode 100644 index c525dfaadf8d7e9d9d80a0fd11162dee3a8dcb7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25368 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 diff --git a/images/avatars/gallery/Civils_F/Civil_F_13.png b/images/avatars/gallery/Civils_F/Civil_F_13.png deleted file mode 100644 index f9dda675e59f6d271ac36e11d99222c8a0e1ae06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24283 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 IM6N<$f>A#pJ^%m! diff --git a/images/avatars/gallery/Civils_F/Civil_F_14.png b/images/avatars/gallery/Civils_F/Civil_F_14.png deleted file mode 100644 index 92df8346e654ccfa0cd21eb85b5627775f90fc33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31397 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

Gh+$jrlEuxI6>Nnj6&Ii_Ktc#|T~9Vi7)GOZ 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 RXe?z+J8@~8FyjCJkKEenDHzZuzM+zU5YDJh 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

RF^z+CzctzIPxwAzgymxvTl6;4EK<4^TlDXG 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 ifbGG$)@&KjI{yzjQ4iF(AFzP{0000j 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 diff --git a/images/avatars/gallery/Civils_F/Civil_F_23.png b/images/avatars/gallery/Civils_F/Civil_F_23.png deleted file mode 100644 index 866d602c5783fd6eb1d348f777c19674d4bcffd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21885 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%0AHmPPC3yOqYw$Lob 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 i^^9lr9TVLkg8vUD$qREo-ef)i0000~IZ^HYZN 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%0Ad0fQO3t)us4%A7LYDHsuTQ+c}xyy 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

P_r{O! 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 UhXfe><^TWy07*qoM6N<$f{ZJ2<^ zL>+WM4;mbRTM`NotpW%z!v<{O|Nrq*d&mp07W*%0cQoS;^uFD3U36W12YPhJ7WU>Z z%1}P9C*AYEOs`YoDb#Nug-Ay3|?GlR_2k>K%)I!Bmm&a6KJmiGFI;;(aMH`*%j4t3CiDs61a$@H~f0UNa zYY2Y&3+)A6aiYt@<_}#Jz#kd8_oh4GpQ*n?9dCB*C>n4D6yK{*Cg@n{v-SLMtP*t4 zKNm*-EH!vj?tU7hFlVdJWorhS7VEM4tIW}lIlT`dBu*yYHhDpwPn58bjbF}H1e-|n zRIHXY00Ul1W1C1%FXyq7=g7;a`r!57$6m|w1Z#yp1wQ#1>TL^B(?6W-+y=Ztt(?Vq zs>M%4eu(Q{GL<8PAhu@9V{v|}p&F_>iEX&E0!|fDH}!QD9YrtpzQlIoP*IcQ`+OG7 zcOX87B;l+uAA553&SDECInt!->$@@(fe~o`e%*`A377U?zhW8b#sLKjBP>Wn`wP^6_MK0<%|5xrOyi4I&ZfL-4o{pbc)OE>C%Yz$@dLUZob1H8~@u- zi`GT|VwH#6jejf3b9izz+N`e>Nu~if67>Dzslt*BZZ_obW-C8+xo=g zCBiHWO&9ntF*a{X$5%vUw^(Sl>NkzuyG}~5^+z3&hBWB@3c%s23=sx-h!gf&lL0}! z{pS?09njEMp&laq0gz9o0IMeiZ6vCKealwIp0dFE_LKla0C-!2js?!CGS1&d!_yc*vZK!*P%0YZQOutyZMH4-O8hU3}?!>@ksGT@k8q9#d zv*;9EB?X9?Lw8u|8&J?@!a1pdfO8}ZAo7FFP|rzj^LE+CqEFA}=Ho{9oV?uij3rtp zbR)nTb6PQdY#i7r*?sb@Ughc^7~LdZL{)jZfQ-tNh`!g#g$PqK$50!gk`u<%Ok2fh za*!i)2v^r!5iIOH+Mr8z3l-y!p4AdWnrqc!hdtZf4tRzE9_2we_P zlSq*ZfNGBKd^J5}{_kYRHb;shG9VWT+Be#0Cq*0_W&m#TB~W^V+U#>cOg1R@PnqDm z0XQ3_6G2Oc8KAhh39@&Q%2OSf9!2|3xknzWIQ$j%kq`jX#o}p>n0zOvK>j#Wf*BxK z)h+B3!H0%pWU~*orRl;=L|OI5LgEel3=D}b(f(8H4cB{?no8kP4GrU zU76?sn6yMa5SL(q(lk^Gry{}wvY#(!!Ac<;LFGBPfT3pth^3`NOW)IRbz@(vzKXAP zJU=XK>qsoJrHtg4drym;*PE%aZe(jH_PeZ@&jQ~3I-f98A1jeq!_#JMFgOy{Wa$_ISefJ~$^`yT02Vi<`3Yn?`LXTw$ zKP*{-OEiTUouu}y-aJz%;J&p6_ccj$D@K%6pdbw;fK2k`D1lU0{Z-L?`1_g3lr@}g z- zDsNo;1U5p=6i4L10CY!#CkVGPDD!auz&JN%0Ab#y_!>$kq->rY@Eu|~L1YdUfH=R2 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 z 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

7^=S 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_20.png b/images/avatars/gallery/Civils_H/Civil_H_20.png deleted file mode 100644 index b46d55b3c1a8eff840e9685420669a49c2e881c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27700 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_21.png b/images/avatars/gallery/Civils_H/Civil_H_21.png deleted file mode 100644 index c1fc92b61efc612ee6e574294717c610f60de5e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30390 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 c`Ki~*O31|$!8h=L%3AP5qC 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

uz-QlK*wsia+3Pap1oXeU}4m!qk184Jm- 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 Eg6hvfSpWb4 diff --git a/images/avatars/gallery/Civils_H/Civil_H_27.png b/images/avatars/gallery/Civils_H/Civil_H_27.png deleted file mode 100644 index a736fea8c2bbf702d95124d33b64e85fd4271c37..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22517 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_28.png b/images/avatars/gallery/Civils_H/Civil_H_28.png deleted file mode 100644 index ac986d3cb8addb91a9a9b53d4ad57db6773c8785..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25234 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

7l{fztxd5tWRBCK#XleEKV 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_29.png b/images/avatars/gallery/Civils_H/Civil_H_29.png deleted file mode 100644 index 2e8a65980a84b576d4570cc455691ec4d1ff3456..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26178 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 N002ovPDHLkV1ikX&j$bi diff --git a/images/avatars/gallery/Civils_H/Civil_H_30.png b/images/avatars/gallery/Civils_H/Civil_H_30.png deleted file mode 100644 index a2f2d7d20a5bf776c2188ecf488bcb9d7d6d5067..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21542 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_31.png b/images/avatars/gallery/Civils_H/Civil_H_31.png deleted file mode 100644 index 661bf9bc94dc232ec666f261b73b4fdf78b9327f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24351 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_32.png b/images/avatars/gallery/Civils_H/Civil_H_32.png deleted file mode 100644 index dda9cae129cb8a65b3f6aeeaeb3f30cb74e1bb27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26200 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 m2&2;pJ>DCTWfW4Mf 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 B?biSR diff --git a/images/avatars/gallery/Civils_H/Civil_H_38.png b/images/avatars/gallery/Civils_H/Civil_H_38.png deleted file mode 100644 index ffb804cc01bc8704f423d5f1a41bd0aff5a1c955..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24881 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_39.png b/images/avatars/gallery/Civils_H/Civil_H_39.png deleted file mode 100644 index abe561ea60ec383f03fabe1368191f2a2e8dba58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25833 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

D~W!LhC28KRWkd2!FU# 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 Eg3~2m+5i9m diff --git a/images/avatars/gallery/Civils_H/Civil_H_4.png b/images/avatars/gallery/Civils_H/Civil_H_4.png deleted file mode 100644 index b636dde91ceb41208e6c294cb0159ed622c2730e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32791 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 z∨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 a*SJxq7D`Xs;n=IkRdW8<; zqp3$|coAJ_aCeJ4PB2z1&>d{P@1staS*^L4DWnLSh25yfFzHNP#~UO}0;2Qz=dLc{ z8_!=ugX24NF#+wUA-a3XSUSctHtwA+A)j{O2O-8wIb`W(QM7-QfQ$2X*i(&6n%MO0 zES47*)V{T0I?_&@)pg?&x~|Xj`)8mW?#_<85i~g&0qm_jsGs9Oy~{Ms^So>f-{N;7 zrU)#{QlN<-5(9|g6S9D=W@=$)>fK#FiX#-WX?5?$dYR7!%7JQbKoAFWHW`O|Kqiw> z!ZY&BIHkCoK+~C7<_|M}h51hAl$nG&*!TqHmBX_-juv-7lSmv*J5-4DFO+f) zPq&C`t6N+P1*Kc45H>fEu8l)RNahyEoK$KDawKrXJ&uPS)J4Q0dhFteAhR4tLy=(Q zvl*8MRb)z;)iE{XZ38J&$NWSA6Zx!yO4c-1%)_=Vs@$Qp+q|$-zj)=PfG&!dk z=3AH_WWJp_#?(b0mSwZ(`YtgZC*=K<;~<;MZI2}ri<|j}Vv>kb#8%2W2q%lUzE*)n z2qw}Noh?M&50&8b1BQ{yxolR6PP+Wwd)k4vs1037X(BSu-0ZA^dtq@A6e}pwUHg$| z1+bj0t3uC?5s6eKgaKHV~%%k zN}{XUvu_NSD2GW+UE=&=y+3~!3K=x!%;NoVcDUBgI@bJV% zdmT+8B-FCsnfZBKzj8%^uk}DaOh~;9!-V5x&}ud0lEF(8Y#cwqhV@SF@!N#)uel>8 zE-}luq`-aRP6h1&=DQ_*-+wC$m+#lrP19yqGe#m%5nq;K7ZL1?7ZV;09*lv;NMM74 zO*;P#I-59@xPpkc>V;_gk$R@}poyAa$9#hMlgu}=h*>FK98>PvPS;b1 z#V#lZHL8#?GX%|6hZd@9iMTX6ny#D(18^YY2uPE8IuyU$ST8FlOPLzR*?k*Eh#G+t zBM+Ds+u$`#In_9UIx|sFzXht8X;~&p zbTggjAx)xR$VpWR*|mDC9L?C@BQY^GgDWJsR28OMeQDR)!s3_PB3bv3kVN-ckm+ltC98E*pb+Nv&fiv^- zN*t#No9t5n+uYhp=HmROtcxy|wRF`?d^VafI@Y<#A}l^1au3}l6>=G5oP*t0^&|fG zVg*=f@|^Y`opP~!p@1p6+Q#}ibdHsn(DBbt8iv3oO;T#!9Zx>#Y|6n?DQAk8euDWp z^MlOKGe6CIidn}gLT8*kd+%wDeN<$bk1~Ik`3dH`nP-?*(upE=`R1;obwhqTPDY7l z6cO=oEV|?C9(hD{+TKpBYcbmFM*%S_>7Ifu9sssPbQ*H$lv;1C__FRODr325Cg46_54uU4F3 zpENE3(6Vd=BqPO~Vg4ZVJ)KWE^bMxG9FDs7x5Lp&%!imCVE!ZKdFH<3@H|&_qP+(o zMH4qOdDuxYM-WFIvWCSdr@oyxsxWva;r=D>i!N9*W68S<8&!nTeR-88f)WL8n;~j0 zn~E1;V{;SPOh)ak7xqzwh^$XC`!y0tjWUT^K*0FJJstAWQ4mxXyJNqaW zvT)dt4qBV+i6)KjZ^o!mt{nQn6Ou8erl*n3X4z2NBWjv4Y_2a1eYmc>eXKi;yM;_9 z+x13Q6#KOlqyWS2digX`wGj+gy z-7HNpS|jWHGN#9a5jVT%!i7XgJ!2;;pew}`89xhjHe(29L&w=<$a>37dTnQ4DXKih zwlCM3ZBIca;=_ntO~CTmxE7a}5e6Q{(l+u0T~ADoHII-^*|;!MLWa&7_P``{PCF?~ zkC)Uq2i2Vhh?grdo+fBA?os_q8s?3wSCzAk2DGHEGFBJ{>KwauPIMKh^(Rew&jE2c z%nQtSGT+WT+qqU@Hcq;(Tj6K|m_YT@%zuESgB%!ghT>)dTR%6GA_-(8b2B7|5c5#V zbQI6?C=zYo=z>Dj<80@Q8jB~+b~J2VN0=MWt5KG>>dHZ69-0U&s&YJS@zY18vW09e zi%dE#ZU033iaQ0>I{VqGlo5GtOk`}NNrkLSt_xHt+fq&@4Iv17A!B`HeWd~{);>I7 zP2!4GFM%xJBi0dyAMt!Mxg4fvXBBMLh|W^>r0WKoaR!Y>ty6`aGjiRw0$iRspkW9T z4|nnxnO|o9Kg_Q%Up(%*PRr4x%mUO0m>*^S8uN#lxx-%Sb{(20Sh#A=p4IVt)fw@Azv&~f#Cri zByqOoFiWv&xZm8O$YS;Vs8B9ORnCnU)LxgiY8)wXwhkABfSuNBpuXk--5QmzC3=yj9P%7Jy11%E2R6}|xY`g6TQn@7y@~lN%r7zjg!xrw z3j;tmD$t}&pJ%=YiQT@QnI2{UDL@eTEP{97Gg2IZZPaciAp(@S%UfHRKX>j3yB4>N zu^MGmiSIMZu!vtcfW$=13bwJl67G7np+05*UB}euULhT5kCi5L4Ab=E?f-;QMTNi~ zcg9KE7G_I1jOWv;roD9)MP`Y&UP&XS>~2S`xP(LQkUU3rL(zwElJGpE19{Tt)(2-#95~GVyDf zKh1oC`9`LcT02e$aw)DjPDHo2Xad4%xfwd3N%1!~Hq`f{LRM&KQ36{S<36K8*m$5g z`rR&UXC?|LWE?bH7xk8hwjUy(D5B1}i;L{4#jsV?c4`}S#AI=AS;s;#n?`{Er7W`p z*`A7X5sq!6l+W!j+sDZk3E5YcBW$uSq>SO~ZgY;AxjDS_!V4I6$i4)obUKYjqp__m z$uLZsx`23$keyC2e~S4|=2OhSVt$_aEOTGiI4)?ix;J$udLQ#490RUyBzEq>_x(PQ zbrx!hn~lnV4+tKNbXK2h5!m{5@xHKy8KuPg%*x=-7AMU^++-}5hEKp+UVvts(6v1@ zU7yf#EJaI~hhkV&CPurmbBq5x&+etT3Mo^zGxW~r1-==MJ&kS!3h zuPzZX_jr(XBM5>~oL=9My-0&jr2;ncR_{@(#xA-tO>-Dm>kT=O6!R^e{2=qQ%+E2u z&Ai%ua9HKapl?IsU;^0#CjqPrnQYSY#LeOZ#H6WWb)P-0kb;*9TBBY^u247n)h zwJ1wx11`|n>;Ykuy#!&hAJfp4!{pO8CONN1cWbnLx}C>Q4<5ysJj)vKPvAMAR}i2m zshO!G=Mb)Jieo#lO+z`6JR=Yvwyq4HFAy}DFW$3X%Sa&m3L)F_P5>Df(`q)cc;g24 zS?Y*GoGWBA^L=mI)#Q8yK3&gsba&!4TwwkN^B*GtO`uaQXAVehj`?HEpGN}Pc_j9E z;z-=gWdVY|kR=@{={lz!2D^N{T1CB9L!nd}qOFPJ5Vnr9-A`vT>2zT{cn^v?&ZX9& z>ByvXq*E3q;Ll(b-!pWf0-dXrrF(G>Aaa|XEjjR)pJLYLGigGW>bO?|pg=rG<>JoV{m!QMhiqOt->nD{rccl|*4K~OHl#=qR+Y2GgslQg3klotOD6~4J$o77;2QI3 zo0+16CD1ip54L3@=h(`<sONBBYkK&ANpF+U>U5mz;U>yM=5vcUn^i<{rQs;i2%5`-ka;7DZ&=t2jj+XpjjtxK(b?jYm$6%cPyrCDnq?dd zIfAF0EAHMqX2+-Cr^ZVZqe<~a`u&Za5L0Kqed3`cNjDl};z1-O4ab6P2wk zG#d?!jgNDU-m!Ma)_}Drqkdg5$}A{h8*$G{OpAcwWWtC$^&X>><|3;#dm!8L zMgy5FT&eVuh9y8w3>eed!t*@2fZ8V)h0YwzG- zEh}OAw1ToAmPj@^pk&LBRA&W~ZPP4ccW0aE76}0}G$j_4}WN!W#AaXx8f@L8QEwj95gvZon`~k9_XB4m{6C%!KqHr~bqx;Gue+N0+nIarnwJ z&62of^7T3$1ax0l>HKS=FPfo=dp?Uz7VnDyFdNx^Rz4G3Wa4hH1CPdDgk{|~?uppqAh1(CYkd}-1920sXk?y9L4Rkl$s8A5cNWNjzH9THjnL}XcH4WHZVbkOhhAYHJ?PS1md zrfJ4(HarvCwr20wMQ)vPt*-0B_ZOuZJDfrdYk8IR#V`(m+Cl0+u%lGwaR$u!w`t~)zh*xocr)Rbg4 zB^is15=~dKOR|Iqd^M_7jK^cK=i(urJqt}CQ{Z_?k}SCEQWCFYxS0!$HRE~i()i`C z*i9}v%}y6IAwo23%AHtY;>L!q8*iSFQ}w0HYSKl#NOZCfoW($Tz9IWxNCXwosEl3ixaINR=N;u z`VUi0g714mY)R^!7nvto>;%D5qH3Bh$jyxv0SeXPlLPlU9WmOhla`;($<_@^xEoNi zkyY65 zmAH^u$FU3e@H}^=rY;;OqVM;5BH1)8`?M8eqh#wwC8+XKcv&A|Q}RfDtIL6V*w`>} zaCHyuae&)ZheQS#c_rB?ld2sZ!LlrrO*6m4*8ry)^EU|Mpa{cI1PAl=ycU(IwLDC- zMZp;f5+^ZT7*H)T)ifTBFddJvbLC1d$I7%nL)UP(Ilvc<`*>EfPF5z zzipy#K7$@5rY`%rj#4JmnocIDA0MBPwD^bvKqavmWDZmD8H>&HJW4hfhEX~fUo#OJ z7sSQHX(lafMwSbhW+z~ROh{;B5?UoEp_R%e9(?@`-hJyA`1YG`psOlQ0%2uDuP+l=Xs+wbQjIxl+cs47eBmIcU06~K7Z*jL zc)tj7!D_M6?3BBGGGUUB)j#sa!(4*~G24-@^T`zJ#X8VunGu-bGuWdw@@G ze~7=|{zxQsp2@;z)vHxZ$*_2)mj!VU$U8YAmDrjJPMCg!v+>gS8!d!9<)mCiK7RP7~Jdy;0$59cLtniU;`eqWF@ zD>v3OO)T+)-`&FJpZx=dVWfW+t%IG}Cer`@*YDuVFaCwHX=YA*MOD%7bkMBT#Ouoj zrZIE$bgCsm;W##eAUM+uQ)iCn*>rhJ59jaMDVR`2OtSi@t3fKEy|VdS4Jx zp_ycDJf(68O(OrhzkE}OfDJFJ*?F#u+R@Sf5%qFF61$jAC&X*#iQ(b84t?h?4VDYD z7){fJn-@9F7(75GORwEd{keu=;PcP^i9g=@4Z#K@#pv7gJs)d zA8CX88IwWPkB>#a%g9(H#I;7Stf>$ai|$GP!~Eq`i=uF0f4K`SPBWPnn~jU64IZ8! z1n98PQWSwKOPEZiI6kV1MP)(sWqoOyN@sg$H9O?We(FNt=XF{wj0OX-^UH!nK(?KT zOkQlno=0$2B~C?M1wB<0hr1lWR*M znTNT#h3hw8#?-RVY&69_(h?i@=o0~JM@Mk!E?pX-JrtQuNgs=8`LEb4eSf}L<=lO| z$jg#u2^2DgLBEgDa3~C79S8!_LK=-WCE5g~vWb^o`+>Lz^m!g&A_ZZ9tIu4+?*4%g zU9UetyWJK0NkeS1qQD`dHmX%|-epL%xa|m*by{R+okdifMB@OvbZLf|G?UQ?V-lJ~ zuU7>xEeu1nS{)&>*!5jJb@(){zx0YAe;(l38>O;HQr-pE#I<$1J#jI&*3}yK)+cl7 zbxFLrbhR!x$sk0=>2yAk0lHqISt@gRox9D*vNUTV4d=`QTqUPXuhT&ktR{w}*G{KL z1RTuzj~651<}0tEvbzV5goli&$%%S!^$-UnaPI4LEo=gV!HC|=EAL077d@+fbOdWU zg+gL3Hn`7-QY;qPdAP|lW3w_0W8vO%6&e@sI4-&Q7_RG3k>RBfT)YOL-D(Mvp0{59 zenGL9 zX3}W1Xh)V1}Cem}) zZ@}ExLNF&exkkrvgxJ{S&y#E-y-A!6N;4MQDniW<5iH9R*P=9<2cDB*l&EKU+3yWz zOph)z?-m~liUsEhqA7|a3TKxn8n|8-*_e{)aE@3W2NTqFJ+xXKLEMF;<5VLdJag?u zTz&RA9DRL{Trgdd@{G4CJ9NhLB)TBBD4InkQUHVzNJBi^5djERXhYBjjjbJ@(D wT4w^+Y1?s_=;^t2`=ZY| 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 V>`t2rZBPIJ002ovPDHLkV1mmmus;9* diff --git a/images/avatars/gallery/Civils_H/Civil_H_43.png b/images/avatars/gallery/Civils_H/Civil_H_43.png deleted file mode 100644 index c81eece6f246ed7473850b6edbd94441c2de30d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26458 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 Hu0mjfrAt>V diff --git a/images/avatars/gallery/Civils_H/Civil_H_48.png b/images/avatars/gallery/Civils_H/Civil_H_48.png deleted file mode 100644 index 14615e5b72a9502d015bf44ec8e0c523681ed6ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28417 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 JPDHLkV1ntl=rsTU diff --git a/images/avatars/gallery/Civils_H/Civil_H_5.png b/images/avatars/gallery/Civils_H/Civil_H_5.png deleted file mode 100644 index 013010510ca135e6cb062fce817e6b21c35ff4c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22141 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 Hu0mjfI<~n* diff --git a/images/avatars/gallery/Civils_H/Civil_H_52.png b/images/avatars/gallery/Civils_H/Civil_H_52.png deleted file mode 100644 index e98b6a9e02225f63bebe8537c4188c8c01393a31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30130 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�ajvv3X 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 QBLDyZ07*qoM6N<$f&(MRasU7T diff --git a/images/avatars/gallery/Civils_H/Civil_H_53.png b/images/avatars/gallery/Civils_H/Civil_H_53.png deleted file mode 100644 index bd08bfd522ea5600a8c8f409f999ef6308ea98cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25830 zcmd3MQfjBUHk zx}4{H5DD=5aeNaTSO76{KylFS%Vd~OR;^zkZLkerry14#hFiZ^v+%G_&^I2??q5#= zV9g(u!WKexD_9}cPBI(HOYhYZ0|a`q6+kAm?UJH^vCx@OA7Xr3^pp(Y$ zD=u7?&c9mXMJNsTHzZ#~U$Kvh^U&-NjJZ#8ijNhicVb39B`=hTK!ckiiV+bJhHywzHHuw=c76_O!zOdNXo8@`Q-cpw`H^xUx74O69s5f zf=EN60g$-3(Z|{V<{@W5A$i z?W?ti&(AHLGr_(XzhK{U&MfDny4H;OFLXWLP2VRT2Oi-#s{oPBi;IitnRu%BqtHG@ z00hIAfopXykQH9ef-h9D`in2}rB~6=(RLZOh;nJ?{p5Z)0t>CkyIwOyz#5|~_;Yb2XKh=M0gJIA%@c;RPYljJ zJ^syP33bi2rVjoS`#}cU{Z7=C@|<3&{}n=8RvkOr69Z7safa;e9Y})ITMW610ytsP za4Yo6+Th&I5fgOZ50spoJZss65Lb{h0}Wsnmn zu1$eL&%+ZeO`eRzc!gVpNV59y zNKFf@uB>P-TNTQ1eeQv_PG7j@`Sxi#QLkK|)Vim>>3<##rdgG&-3+-2hsP&+Q<#DP zz~&8Y!rvhbPvCF;E@_*r{GcvRQ=E2ru4p_!v8GS5)v!iAJTk(dNs&9{5+9uC8^}Js zab5f}pWtk_kW_er+X7=AAo;k0*y}okv|567l7nC+&`m<#&O^3L&IjwS>p?rK9>s#sR&`eYC)LvmrT!5TS~uZe8I z6%)i7t6js~h20nG3j9SD=#2d;!jucx@VIgcjP0SW@1%pCY*LoBd79;%7;W}zqmcM` zf~`%0-d58BZtuA7R^~G$XPPsQ7bP&}-G#>oXIo-;X!Cq9=rVZ<{a_K6%d%q93xW$K zPR?>x!nMCx(O{jbQnVYLWEq)-8#a$nJaS$VGadL?uCvVxbhA!dFhoO#9(e0l&Fg(O z8?3b=Bv$cL#_~kgKv|WE0OVr*DSI^d{BgE$KL37obgE&Q%w2mldi=%mMjr?(C7z1> z5D|=NiliMkC|P%*7Hft|Zd0H$vIHTNJ>3GIoM(5}GJVi9@B7SYRu_ge|AP;{%!){v zvSNs_;?-6Hi)6_H)f?01zw(L-C{_(V%RpY)ANVa<&+4v!Nsk~%359D5kJ@tJO*ZT? zL2phc%6o-t&D2sF>+1tlZ>}1|67_Fy9+@0YVA&^SPZ6gEkLC{@$^T?Mfgml|d{U=h zJoPCHkB&@Msj~(1{H;l$MQ0CFeq&;?FAS~7(FgA|;}QrfC`MJlglWU*oi_D};}%?^T;W2^ z00RgI<+N@;x{UHuHeT#c^$?suInxfERqoe*$zFl(L*asCzr8cdRi;WDAAE>`Y(rL+AiUnQF zPWcWN>+JJF?7V7^E&=F~hvK9(v{tXd-CkBOWThs^g(8HCzypQIx;1N%ETDV|L2McV zr$cDS#xtloP%~VyDnwSc(qgxqn>Wjh>4Fehq9|_;vAqTg6lnHIlGv&BYc>pE=cc;C z8Ar8hMJl;II<0nVYWjXfobV<2S;pzg$CK7jnE{YZf^T4Vo*rFXzY7mMS53~)!c`Pl^9<>a(-BXe(nY6=qX7pj43j%v&s$#ayR)FxCLb`^=cNo<)s=H~ zr}I({nabtB2Nm5!v-1kL^Cz&qvbw1YD>$kpmi}2q2~srvq^{l1t`np}W2%I}1PZ*7 zxJOEafzqq8@{`zzx0tXqw57u4< z2Vk%jh&+@Yf2BmnviylkAk}Vltz5Q+6D^)nMNvXy6+v1W)`$*%Cni46E#c5)KZZ&TxFe$ldrKyWJ$>5&Pp!BtXkjlIBYkCE9}dmVr0u zNucabwcKk!eFaGUnYo?lD#iCg1Au6iVDi(R{HQJrd4RPZZm( zJI~y`z7!y|(&Y*#3!z~Jk?KAr{(2iNz&J-ga&HR9O9W9+Qs^GqxOrGX74mQXsuN&wyk*U9f7PocX+< zM^e2{=#*93*E37_%{Bxg!4j|Ax+VCexV|vBX<>oQ6HMvmUY-o;DM?HA%D29wn<>F=D&dy?pg^ zfV>pWv*t~dL$*qIt$Yl@BsqOT_`+36fd0mklqbJYp4l^dqFrt8RR;={wWIW!? z?%X`}I#|vMBu09Mek*x4ZuEKg1f>&Gs`e*_@y3v6zcX*o6aoM$iDdp`&cq_%C=NVS zxqS0=GeTZO0hC;0<$u)#sp}uq=5&GMGadgrU1DhYr%#_=eHF9@(U9StY%gmwD`cfI8Xp8d0q zZvR>*mzz41r&LjZzVX-_ZZ&7oMEY#-pq`oC3(IyhSoe$8;|QkFqx!9GLK&~e7jyEn znXPaz)JB}Ijz=?#3rl>o*76FtW}B>jHQx&b?vKe6`;|>ww1lXbi*lXKQ%0zjq61F~ zG-&Y?#@9Z-FBF$*EixlFu6NdVy)z{VzhhD6(%h?ppSbL{b#SiDET5f`5xC8W8or+l z_Q%n$RO&;ONEe9QfJ-Qn3FD$#mks9cn^(+E*Gm+}Gv<`)il#rasPBBIs`EMSP4x-c z{P-jm&j3CXqIj-bXvHPNcbhjnAs^Qt^o-GDpPE4cWM3K?;)i2qkuv{=?N4WcQ*rQx z5-C@Jc>)R6ShK(o8yVhp2&M?AdmqJy|P6G;6Lg3Gk1+1*zrdwQ0+?jiHC3 zXji939O8SQx63W5K#l1zRgk-POb8ajYRZE*YR;PtZPn!oOFc4^t# ziYx79$_z~wTUm{9{(1jLTqkC zM$>Y8c!mO80F~b0^PVpEYp+-y5a^11XrfT*<>$0cj zWaK9>&A>H{{{-#lL1;=5g$8+vB1DOdZlwz(f+|r-f@In4z?AyV?i!r!&G4u`y!Xz@2n%My zBd6j8&HqlWO#m!tP7uwzMk%c@N~CEfLi{R`CrQhBYWndK)5|>76j(goc2wXn3zfr1M=2l0G`E#zdBo(tMUdlo9p6F}y5rm>KHst@*q zjgQY?P6>R}-n6as6(Y^l-{j@Y_3p)K8`umg)L8;;bxYtF>dYA9!xh#Bm7>6QWxXX7 z({z~MP=WgK65a2>1LAmF0j+XzMa^~&*$C2LMB{bujelhmje%dx@NNk^y8YKGw8YU zRg73^uua?3j``XARzjzi6;MSeA9ngLs{ll>7CbI?!(d?GYt7rTms?%HL;K}n>1`^^ zourZ4rr`x5svor%Z{}qB;I8lk?T~AsVfj&MV<2!h*dZ2J5I{}kCjZxL7bc==54nBL zI`CUMHW*l|U<+N4>(LMmhr6@ch>xxkEY=&!-7SU%zj&+Y43*@_${rUit3^q}&y7UVza`g_1%VsopS z5Qh>P=1J!#rK?`*GE32C*HdXKd{!U4tuL%aUV2&U*ecB%RRa{3n8j-h(hb&G|3Wa0 z{}nM9ETBhbNG)TZbQUZz&{Dr*->DpoZ)w*Ihs)0Z#D2FUQ@H8*r_VO?~58KtFUu?&o=Ua zaNFUX7yez%D!k87nvbk`2^NA_C4EPJaL8yLN2Uvv*6_Nw_f*L0CYb$(d88}z$Vez zjsm7_9=u53%pxcE2nciJwA!?W_PjQ}Pcnlo&9_zclkE) z`rh*n)%@btM^MN?g7Pt1P5!%h**HA6?|f8?+q7+BEZ$^ z2lKMo4*mft)LsP%S(X(fQWdrUSvz@Euu<1lf;-d0?(!Q2ad6d(3L;WDH8W;eYH6(7 z@m`Mb-`4($?#{z*^LQcheQqbde&FK{l)X$7_1{;*TtTMH-Geq-!zu)ZbRuif_b2h<@Nt)4IB!N;{gIZQ)<+yJ zABtG$x;>}#{`ldJaA^O|5_3Js-gwFLJ0VzSk`M;r>@Q}o9lS!@d3DL~Up|Hr1@pR_ zNZFacsm#1!H1w%-3Hl9UQ8kZ*SG=Eg&ZX#EGMGF?Cj!G`p1xF3JwM+{uiLRP`-j*! z7dzM#^oaeO_PHuVy{xQ-cMp1uO3pkhPj^6s?q^9#uW&O)Bl_^y-8S%WI2a?h;(VM~OwQKC&YbO?uI)$t z{f^Wga*WeXECcV!@S4U~I;*dx;IoF4yp{XC!0jm_Y>2bzN{|#ajAv_RoT>{k- z$leD%KG?du1q_LSl*rou@{Zweni$D1L@UnJ3X~uE;g&T&P-2GO^nHQjYatMd7pT5KwS@= z90I=;&zc(|6^&P`sZr2N>I%{v6-0 z7Z1}9L=?#t(5b!k1tyQL7}WGPPU(VZ_>Pv2s%4f+LJ%0>ar&5SEYi;ZY4 zB7illhZsO~{0?Mcr8c{>+lbc0y*1gKLCQqMFM5E|*RV<-m7$aMFmNd#ien)22{`nW zzOp0-=GNkbV;3#koY5zG?m@E3yI*A1*(%IPArpl6)Bba-oJQJpbgta1yCBzxo%=Dmo8NcURlf z&!Re;I;C>DAtI}p(hCqAj^!~AaiPxZL7^(1vEVohdO&maGolR8K1cy{IgQh2%2a zXsR}lF{sTmCGvgEoAG^QlH4IY%AvE_~J@)Erb zq1y}#$jhFsIu$R4;-@*pjjVQ=N+o74xMbgbw7WjfT}?cNe&sfxK{D3ENqmaH7BO@X zrm$}Unr+Oe!z0(5y>NHNNVNL7KDp@we!&xNZ-bQCx)Mi9cV7&h+JTvX+EV|95@%#L zmcxPA-<7nSU-_Jdej$qUz1${l{b=rD7jfeisExtp3P7go3VE5)?X@bAJ$U_Hv+n?T zdLOZ*U_rlGSrSF$T~{xz)UNM>dMQyP&4BpqSp~H&Ftsumv)Mp>Yp&jZd`o*So&&mN zas2k8j{=5&j1yw#=8k>j7)(y3U$%Vsqi9mcLu~8oDZO}zt2N6JBYLGv;(8cC=~5Pe z=6{)+ntxOM#TC?I-cBJGs8Y9Qx~Ogtt*Ty5z@8nNh&C3*I-)}Ufwgd?x2F+%!8sK- zjA&S|)~(J2#Ukt@q3`spo3T5euQu#&#~RnbsvaXy zG3w6)U0L7bH{S18eF1oI$x}AgTDXn0F}-{+j&B>t)`tjNCu_*$DNni5Z`s$Z)+fd* zw#+SKnU~{trbErXe|1oS5@l)^s-`HUW%HC>^Puc)>q?o@r9G*7eF6m6f8|hdKJt$wv`lX3@rK%R?VS=W~|m zey3))8`A-o%VKDiTkRVgFfX0W<1kk4v8DE=EhM?oW5u4+#l6?<>|rQUv`qB-RE=Yi zHhPbFuMzOM&40rvC02vFo>q(;G*Di@iK8et6e+D?Wq&hBH6vg5#lYAJf;%2{KhXrH zCbMH06evkq|Co(v!TK0gU=2)|uoE%NMB#1yJC|i#jB21(Zbeb`fu%`Z$G&L*AD8ub z?BHo6t3d{vFxn>5jN)mc4W(O_I^&Zm;o?!1o*XwqeIp!K|54A6!j>0dg zws*I!P91m`-z^p7qrpf)Ky646It8D z5tKF1MUR_esEcW=*=wTk;cXWYbAZH{0~?D#@FufugO%h33C#yCAdgx_uSsIz+*W z)?*Y<0BUYKnOo9w;n?0qDtEuEqKu9Bi)|z)MOu^)1Urkt(->ZyuQw@F8X7D-?1iPd zzkA=b7~ZlpFE*%vQ2HWaaLJ_l9`kCS_0QaPwAVztym@I_VJJ`e05>IeQu&_@%pX>Fl z>}>rl6$uxk1dG`#p(q@5l!_NvIEgkA0+yz}Z7wc4M*}(be(TSZmv8MceeIlwB^~LLbG$@n;NaEzswbj4sQs}gD zM|V5;K7v7LQ6mgWkMu%&(Ck4z8}=953a=pmelM>Lt954h@AFV?Qt0uPR>anI8gt_p zuP{`#w|4vt9KoFF(#l)TdHN;*;y(2;0_G%#v{!;a=9rug<@1lsKr184alLvzFO;2+ z_kYA|O+`ljeSC0k%x)#jSsl0T%=ldc;_!L{kS@zRIzo_ zSS#iN2$090;ein15v$-E#v3mp8bFk_1H`%VwCA z=45}`4tw=KIZ9`xo%O(fUA=ODb;=3u`=CQCwflV9>9;)}&hz4h`-3;zr_-8fhN#UO zE35=e6k*(ST_mY>-Xb}w52>Rba!KRRF`_%#Ry$J^YWzuk4~oB{>!~EnPd{6KF-UzDM4Xo1Z5CKs8Hr ze`*ih#k1OAhW@>Gx)3e`W4w>p>aCYu{d}KsliN{%N!czM7{lOU0z@?jRpEuc32nDv zP+zNgIUAv#Kp8`Z`MT6*w~qERAHTQ{N7OUKWC5#0nX%v^cIqE5ti5t}2pw#V#7k7m zDQduCJ8+aZLzt5#$cZY%P|Hq|pPFVsv$=UH&o^C&Bu;AR{;^2u%NHFA6RQDWdlq6R z5})x2014MhVW7Kck%Gwq*J(I5_n~VYF}@qeJ4&$8U0{b)6`isddeX2qQ0W4Afxt9b zsZ9~MFdJ9w^ynlQi9Ly4c-rfr?W}M+05WB4RD(_A8Ob;8k~k$J&LZ#b3OMIq1FKB~ zH5a1fIJdnWFvEQda48N1+AcXMKRQUwJ_PiALA=wK^ZBN?NB4b?__;sCX1_ZNC~WOO zi#-?PE1a?6JXN2|O5VM|T(!p0w_gOOZRBmm;27;L1oo`$M*Ty!;z|VDVT3`o1~hY| z;q0PsZXQnbqECfimKt3m_gk91&Fl>R_}rVl{>1QvIiXkU|9tz1Ba+3^R;BFEVMTAr z%LI*@;G$G(2jp*1pS7+;5Y0?Ds1G2`bOf)F8`potG@JesF><|X$Oa44Il#qyxh z3o%uz9d5zZNuqV?^VbUTrmbcneciUknplwI_a$~iZ!pBU$j1hA;>4mjcuHp;BK(nX z*PM(oeD7a$yH9Mg7B47!qltJSiquJQ(xSH=@P0^PuC9I5nMK$rk36D_i%%1^2vuW` z%hjs1+PqrMjTg&fCspDg5yN1wAY&)`h+&Dp{Zx{yk^BNwh5O=NPzURs?I^zYbv^-B zt{^9T-|%8-e`-*_yL%JwhnsHj9%bQ|W?JvP2Y3RkCWXoQtH&5043zG){NPEn1jd4y z(avKEb;AUPbS|y4a>z;Jhj59R@e>+*(z8c+Ij@cl`q?ek0L8O$Nl*2O z-*ObBKC?UF_;%MT)N^)YDRM8{2lmw+h*ibkUdv{QDygUT*`T|6X02|q8p!C*F zM?qmMi9tlW$ytlyii>v;+TA9T3~^1kPk*tLtikxLtylP;XDfEMXPivIvP(%Q+Lu4T z`5hg|Mm!Rwm*C=*DPEA{vSa`H5K8{;M?``ra|L z=5C!c5}APV9=Cs4U%nENGh0wwWw}OdC}&nNF{1v;+z09%X9y4w5XuCJhTp%Z*3O+? zj1b=D0=sG5@(wsF*Lu(JF)<$Q#x*1s-V2TxSGls4NKvyDbyJG|o$;<6j}P9@$20U@ zq-%4Mf5nxDj{J`=F8jLy4%{NE?Ot5|#@>o14@?)N`Oz`$z%mZ+EOi!M?6`iPhYs$+ z2!xDLngu< zF-FZC%wI!hMgD>Y8Njt-(d&YM(BAUErmDdZHh6$3{#Xj)=!C8Y2yxA=Y=yc_XMz(o zoS5CQ1^J1+MDNG`+zLF}?F<7gY8<_-HBFoh|3>I!Gga~oBK1(zkr*vkf<(#Papz_z zO_3r{MDPG@huSqV&>VAX|EaO8oJtQ?RYv91Xj!A=b3;I~k~Vl7dqK#JCnh29ACH}0zjUnd z8&FrV)nP`ry3-(Ux(e#1Ki%6|ID)r|R#yb0Dqr z=&f{mIfI>FfEt)@uvv$g2Oznz^W>p3|5i9Qg7!vm6>4fWu7ZI43*lx%kHjYi)t_*$#qgjWB60u3B@o2n(Igdhmz;c;w=i%E$bkgy^%oqa{DIE9ja^v zO(>PzQnb7(!h6&HAJsD)`mtNbcXS}gjU^CF8HRY9`C3g4-Ifb)A7#wrPsR{EyLJp| zS?&G@Bz?0{3Xm&=XvwPbtOyIOI)0Z#mX)n9AER;e(B8x*QWc=A(4W#`groq)3)pZS z7A^c=Y~+FJd5T;3L6zF*+NdXFw_Y!lJKlZug$actry*w%VS`a!?QoNzDle0Y<7`tE zZVTQTXc(MY8B4K1)O1&d>feV8R{}PILMw$mIwYl6j-c3PD5X0y^ za*mYAO*-DeO@m1b4A8$beIazSVffR+SOG*f`>DJKgX*@6*V^Qwu?Vrt?tt?9-8f)XL>DFSkC!HMt*A^C(zws2g4%ZpJx_FBV&eC1>j=5Ox1~I33?3*5 zr#V4oQk*15xLoT_8K$3|{;2{6jp}bK-_KNuV;7R(pFqu9hHm884F@n&3fZBFm#RJh zhhX12S+=fZGgpZ@UaUMe{&oFPtCjBK-R{Jx=+>8*uS?C>YIYsw{yq&`+A6#o1}AK_ z!T10432BQN4m~BKsWaGlQE=2Qooe-xb=i4A0P$T?mR?w=pJmk&pP>fwox%0`4GRH+ zdBN<2QG-ON=+jJkI=ej?yyrz;K$^bK1&_Vz-UBF=LZih_9)YHo26oK|Y|y8cOX)O$ z!<;Su>X#A9Pjj70(K|-KcJHYb%h;*Egisq-taJ_}e`(;1Wwmy66w-`*r@rV=i_>FN zD7ZzkVClg_uj@I@2ao|-{G42r>5 zhuR(`p=9YngN%RWiiQvSrYBZ9*OCRg{10j9sd<8HvBuPq&YT`g(Rq{@6vxp12bK1y^W;T?=W@y)ogw+zoUeaO z1@y}5>p)R##8p{y-ZBeOA0dRi{*+oIK~+14q$xZc8O zdUnh%EI~yDiTafga7ZGc@g(=SzMXtqkoYQ>^Mg-gLB3gjMT`Ts~q#O&(Ef;|JbOWi28Z$+Dgf1y^j+o zF~20<1y_0R%D5bMw!nW|G>9cpI<3qREpj;{r>_7=5v^de#MY6(3#COBcU$|_Kt4-4 zZzHvr>F@#3n++$eoKIw+%$QW~VxUn!F)+`$Jr&VgPe&Jej9Ho~UFpAvA#)EYrkz{ah`6p+#SBOOd}ZtpXg|u|=AU4SRpqPmqDmRL1~zhk zeR%12;D!^$Czs0-aHY~(sxegCQk3`!#cEB5n5045LyK&0Gb7J&)>n!e)QIlzI(2(H%Z> zO0nPT2U*AZfK)?h$HKl&!ATt(gr#BkZVB68{9Em!YEG4Tef-W(7DI`EjpDRKYl%{C zw)1pqI=w`zmc|HO4YT2y$YyM%`HJsNChqrA*dv`VaR}7n?-(iIN z$%9D?Q=y{?|Ao#n!ssx(ZxUb6Pm|8a_YUU->iIGD%-)q3@kAaV3o#zfj4HsbQUo=` zI#jdzygXV29a805yut_xidAQ(wVYnui9);1iZS{F`-jYgP>bzs51N>2G#H2=ANQXv z$OA7vU(Z*ynoLQ}^VGi;-WSh3-+#JZ`zh9}&vw#=hzH!^783^|#Q14)p^l zk>}rilZy14BD_!(211-5;7 ztFh~FPrA+F1BXtla|Zh_@&hMQi{WB!j%3^PJJRE#leMAG6vq8E>Sb@0iEek$>PFvt z1wr1vJP-x&H9HI`?=NX0Jq;7e2WM#Kz}~xTwLb-}N^r^NtO|Ol76lPjY+oE_@>wk^ z;)gCookiGnrOqJh*|Gvkv6=qd-le$l)=P`B3?AT%BwVZ~udIp~+sTZNP$+@d-Sovx zzPz(1W0`P2z1^d|dQK^>`469$4i@p6i>}+YkJi=F78B2(u*^L1NEDGcGUAAQf)FH9 zk-2l>=7LpGpb-ZI@^G78J`m!BAa?uR(LhkZ??e#Cz|{aGGeiT84mhf_ovfgp_(PXJonW@vK4WRgn zAr_-ZVtqK5?UPU``o*fD;vRCtX*$8@)6{Y1cx=o-%D_mYDa*telCZd@S_)1Wb@QuZ zRC@BRXK$0siXI>QV zV8=-`+d{f$cvhT&dl_A%UjmrH>Mw%A<^p~T^ELDg6pw&w`TGXyIbkb!Zq;7XApx8l-= zhCD%d$vE`zl)-+6|OlBNh8aaohF;CeVigZR9G{l3&{_U4x?jG1Bv&Yqo0orh{~tTBJ#__{`C>kJq4 zmkRUIv0#qdV`e)`?q_nx11#tJF|5{Yg*7-DOjK-~IXPG`DkUqIhP6gBOiMju^^hy) zVbxhJEKs7gI)Bz@Kv<9g2Gxn(!57G`lLw9tLLsk0C!_on=jEFEz$aGIe#qcp`JHA2 zL5$HOE4^%YNa#eq%4^gqdQTAzzRL*xWJ+;U=9o9^aui{u@wAW(2ug8~Oz^@=T(({f zN?JIZ+VNbLkVt5FsO`?m{dj`_&UT_Yh#0jg^$jp(ZM6) z{fwUv0^g5|AJm=ig`VL%CG;n*l{$kcV7;GD#=DZ>9X`lPId$x;UQdx_mnP&+URNZs zm>iKash;4Tr%5k_C9Ex(-UT=b#YG8eB$amim1#0VNMfSJY6>7p&1#ZgdT#6fh-jEj zjzH{%gCD(Ii6GBg$RJcWXupG1X+WG~;@D0}x|od8%>N{;)!im0n5EY1B@V5YU7OXY zAax>FV9q16Lb49-541>k%NsX(^4^lACvH@Avu26z<#$32TH4KyqW+b=HL_W?^g(R5 z3xb$ztdUolKMbyQ8Unf0yI{CW440@mQlu~rPCbJjsh>Btf7VV2;>HfyjAG0FA+rp#%P=Wy5KYT3b6!ae`(GCJ}3SU?>hJC!bF zFhVkKfbLU&9zArVgbVhVW(9jBZ zMA#4uqvuwh-A_pqu?Euk13E-Fy=>lJ!zQ0mldn)kRJw$4t2YqQSy^=irxoTOsRzxY30PQ6@z++gnNhwRTss7xzx6ApE-RT=Jq_`6RD~?I52xdEdRyj2IEO>s zjlbI(+dF_mPx+frWpcY=p3uqlH%?`r#L;%!!U>MB*g)G7f}3chFG?g-(;3{SWw{vG z%c-knVRC{aYN|0F5SXN~Gw}u(nGGAEw&{$a^vcR`fv zwBl=%UOBD*1I-bvy-y$sTdaqPl0xXjRN`+t92~#X4GX#Qh%FNw96mj6s;>}?^Oru- zz`iq1qeH8*iGEf*B-y#?ues#C*Tt!Zc1HRVi=J-6#Rel7rd#u@xZw=^?Q_IKDVtAw zpdgO0jvpP!f^qXz_c3WT2?F7Y72Yv9Rcbe51*qD#uCPO6ur@=KbQwYH?gyc1$wg`h zW7xPe>d_pL>m|Mj*^Rt83g8gi=&WtBb4zHeW7XbXbe)p9JD?+`TU#DzKKtz83d6N| z9wn!!a6+fgJy7-JQmx$x{cO-Ii6N)Vd=Ydt3Rnm&+%X%_q}+_r^EtI?^>l$ko>$X- zdMiCJxm5wP;%wl37lIS=L+K3L;|=>?%5e|rnBPjLs{mt*4T#)`c+Uw@xJQWE%s|)3 z1Q_Xr$IApOEH-OpXB?9n`4VaLnP(3+l1s$=T-C6{-UBIRnA~1}g%!kmIm&u)PS{)& zokWZEwJN-lVI`N}l!BIXK{~4+k{Q#)c7k!?sZ}+Rmb}%~pq)h^|0J#}wK^n~mX%FI zz@<4W$0IV@#?jP3ZbD|`Kw)#)fgD0+{fd&> z$-LUes9SR+-pK6k&0!Im-K~-)Lc*?0tr@##sV+W=*UPSiE2?j=A6V_hS(kGo^*K$6hwdYKaS zW#Lw+lfxA&$rBmVOyu1LGp{UKRv)*Y{QF<(&7 z2FW!@o&*lL?%AWDJC!q+uPILAf>Zi#S8$^? zqGnB%TKF{!aHhu>&NNQDe>j}cU0R*%wHr#N%u9INa9f>2ru!N5afuZt_`$NVp2v?h z^A>v>Gf0Na)&AN9JC`pk8g?&~R+6mzsUHg~*)>Yu6r$hUS%|$boX_Vtv#gSJq%pmx ze#hUxMx2^RZckZpy77-oX;?8mj#%iidP~BnW=U4(2xU?b?Su~GDRVnpk5#UchJn|v zhhpURN0%UmjJ>t062NPA^Ifw*F2ODe zwVOiOhNpYw6cwFuaWZBp2Wi@|Cdz7bGW$~zzBWlhQX=Vms`Td#a5jh#bzmJp z^Lb>S;~KAzKEkW98O7#;!>c$~a%X3Dskati1g~tnhM&k1D-UHkbJ`?vYhtnld$pC# z$YszXq)K9GkW|Z?Xc}^~hA8*L2IaOt1uYCP*&W}BES*&T-D5hBS>djSh#M}n59K;T zO6TMZg|rL@0AOsfO0%Ilq-p9GTUY``wn|s==bn9(vZR|M=pqp45;QqvCDNG1i~S}M zM}h(~=)rqL@gnP#8~M>w7y=0Uo2%?p&MRNBn<4Y^z7f#X#%vOqoa>TPWA)P7oIbE( z8b(pqTLxJY``E(K?vd{P6wg_p*eJ<~UFZRBc_J9uzV#*|ZfWi@uQ-ayw802NF4X_! z4hJdZ44>0p;`5~+X>UG)M0$3^6Ce_4Q=F|Qy|%(n$;jauThjArkVk$a&6Jgg5eaxg(k=*7-fQQFH3{9iVx24B-P2tDWVsV+V<&+=c^F9Gcu) z!Pz{zZL(lLNF&2}#AXivC$1w=+<9UK*^JYvQqly!N>qpfv7ea0770t4c@|fihk-Dd zMCb`0Q1LlDP6fA&TS|!Al?!vh*(;;uw#(zP4aI$k++T-Qn5_NKT>{2@|TlkkYCtwcgA zy`&qr>`{G9qB^2*cF{p?nf)Fk-a-eVnRJ9ot%0|Wox@MD(<_o8ULfpBLI2=bfspu? zBRRK}GrK(tr|hCJ*+BhroeeI8vX&6=2Ej!w5lB-o+GZuu()LRE${bo4{O6P%o@gEIC=r z-T^yvH*9yWhB8ZAW4~!!Aznn!=7X66msTGEKb&Av|5v86)lnZUHS!4e&H9$;|5D6x}-+efh#H#+Nn#t(?o zonE+(jg#lE;9Jj%7RBYv?q-zk&PyCeJtdM*mr>J)nFEIIFTI+0 zGWSwD2VgmSXkI%z39TKPI^>X}9nQ(#&x6YF-t1(An~^XyZn;m|6jvXu@5Ql9$3p2II%k=7 zUaO|=+wI<#iIp7OQfj_FUpw~w7v3DXG&z&AEo<>>Db_cUx>>NML^dSSeTyDaSXw7; z?w!2uhhm{kYpA7{80MbQ`&XP&Po!*qI81ep!Z2MHxuPdn>tSs`_{3erQ-pK#OVctj zN8+Eqcnv@C$o<&4V;Er&b~iJHYSR@(Jl%$(YbuU!%*@ddL*%xL+n9)hI29bv(^$mi zWbq*{s(rGcNJEcLTH-eh1v_UUyURhWJowcb+(I6<>)zUpy4Y*v`-q~5KbLZV&jKTk z-xxc3F8Sv7o`3M_^qeI^YmF4*{0Z?T;v60Zy!VIBn``^OBGrF44lkeu$*0N%H@`usZ<-c2y3;Ao7RZ_6-Ra5S(Aj_ zEu6(B5!)E?I7n9xRJy^4h*&b*o7;5YV`*4xs1FOk$s2wm&DO^ zIOkQy^#W<0Q%vGkZO&hR-#yo@wIm}8r;7{80)36bnav8QK>cX zhu=DgM<3je_dI$(B6jeV+=(PZ;`UlfE=Z@!l!}P_0D^TrGH1^+y)n{ ztHfU*zDLj|@Oj+iY}#cgwyC))PK{r~}2Zw%T=w)5L#hU8OVpVy6TxI)F!KsWg0K?bK0{TL>v`b$X># z&;3uPb#gg`bk62{CDqen!ijh~mC;zHvf9-WIQbmhe10trxwFu2+Ir;shm>up-0;u` zOw%lwtU)g8Mr=^u@q^%t+{=k>=a(keU$M0}FK3w2URh;wb%(B#q1;7ENn68bH|CVn2N!|6~w=rE+ns&zCewm3?V z&)8||9Z0K1$T1OJO_^rz&ej_577K`ikahD~kK@*Q#>%C;X-(5{=#nK8N%hUmB*fX1 z>!~DB5FBFxX7j`4_nMYfOjtJ~W8&TKy7$E|eD>+zG)>jD$O3-*f4=_;e3@fSS+;6H zVJQ)kPFT^s_O*DbZt7Bf>_j(3pM|z4^d?AFv&b%8)W1XjDi6D<9WIV4H`(`wL|gS2 zh~I1_B4ShR0m54$mAt7o1DMJ{*0GlDc|t!SS>miNA#orPX?}PJQ5bM-I%E{HUYwJN z+rLG8t-6W86`hy=kx+&fRSE-^?SRDZo5*A>S)amMc*grnTy-*AEZ}IH7e~%-Pi< zQ^13os+`_lem&8|sGN(om!)^vBWSu1k+3NC$gAkVM z^vz8c-09}#yk0!wzGP2fv)Rgl2a_Z-6xlY4Z2J4HQ~Ct`{T~9j{J?j<<`iA_UFz91-c?;(BQqeOo;y zK>|Ox`SDdQ@s%i!jVO$M+4Heq2pCwbFuXBbP)xa$Z4ADL_(JMTKs zsRK^&(eLn3Gx_rHKOvdi_6reR%;A-W58E_g-Xtb*wK$R{;W7VQ%b7Q^*qFaGj;Pg; zxWB~7vcSS_%3DkHhtmsF67?9cz?c|8BzOGtPSB7URY32)Q5 z&4kt|QX!evkcLFyT|tJl&$=zB~njExgVPvN;|e+Z@0^SIqbCb0>G)*)$U7e+>kxbL1k zj-5P3M^Sj_(RZOxDs>c0r*K>cpZM(Od37;2JG0!dy^fpxh*cgfMD;lyXhOj(I#gw# z5k#<>0g73Nw}uv!&Ow`4q6w<#cqWCNY%*8V&ddhp)f?J1OxuFPreQhV?Iot!(be{G zg@ZE16#Q23Pn?hWRV^a!E4mnODWHLGI+5HY!wu!&_(Z7vd`}QIs zA-bA_Xf_*YH0rk+_93?L_eP0>Sh+A`FSW8($S-mURWBr=5@a0`(NZuez_uWTph2^# z#l{wlo^1CvsB_S0>YBQ_94t1crOw?sWcLviLAM7!#@qi+TwO~p-~QwOiys_(nP*SY zOFcJHsEtlw^&w;y!Nr;g2fud^mo8jFty)761S=v8(&j3iaTyE~&yXbBBEv?YGDzjQ zlu+`t;YXOMd6=nssM6sg=0v?wTLz*a)XrvX9*yaUbd3yTiUl~?j22lhjUtNZh^e{1 zpSSm}CI_is!1~py4IDpuMxXg+6Pd)ObhIVGlbpOZiQoIT-@v1f-G{&T3!lez-&tL- zgFej5hebw-q2Q}LvY724wNz~F1-&pLV$|t!S;s_%E@zRTk?$k2Ett05l_T5^AucTW zii@u%=O~u%bYX^wXNcDbzuWJ9KfwH4MZ4H5FT4rQ^C`T|=?z;$XbgG~YPANc^A*%) zreQc)baJ3>LK!OSW}Ii}Xu1n0oI6li#Ky{|DMD9h4L zjN4pqMw`^DYz$$d5bLu^6ovY6I??Z&rt-U)jpK0k^hNysSN}6&+TvzuPRqrX5t@XM z+^<(Le&Q(H(Yseo5ZkeL?%BKZa|`owo{&O|lnXnqlRVuEE+R>)UVw%l!r?U^CMXOQ zU{h?`1(OXV5p$F@leoX@8?6=>#7aAwG7`hK?RTF#aqjV>W2X)}j=f@!5$Bqkm_fvb zwH0DZ2~9!{=<4Mu9DDgZf2Tz1HiYoLA6oZ4aL;G=-@EVKzUS-b?8t~ z4cv@VKJwPdU;j`4{(qb)4HeIea!W}K1VM;dKg4{c zfqc$Ikq&37)y>;WL}7$_rG|il&lYlhcQdJ0oG1i@(H3?TV`TfVl`rIfu2!kNX*>2G z41A-vQEW+}tsrb=DS?p&iu8W}xW&bo2hM!s)23g@~dEL&GIxGVb>IxyrA&$~ew3&kuUHw@avv zPT)3)j}yN`hk57r9V6_#Lz);j2D>!-Qb1S3D&1_k5QkHAGGkq!G-L~kSKD#=z8{I0 za|W@xL3p`b2IZlml=4yD{~90f?)$>GY24{T6NWua{2St-&=0V4*LIZ3MTFsvLNi)U z;2U|whFZAqS0pVm4&2ZdG2e1*Shkri+{chT#EF4Wgtjns0>^bQJW_6N@-xIQ5bk_U8HD(bBN zt40)A+*Vy{a}I^A9W4#9(tkmG5_bR(xBLc|2|50!h_4fWLmotNgj_z0z5902&BA3r z43&e3LNf+H&UF)+6hN79GJ`XdFgCQSEp}*|?kPeu45Pi^A`FL>f;A~YjipzWH& zBV}YL@F-eX_)(-{%WrgD1{rsv(Bxo6WKS%9C`52c08PGS*k_2)3XHEh0$UTev0^KgtZRa-;mg{8(SvC z!M;L#1UGU(hY)Zj;>p|4$RIK-m`TuSnpMZT_@j_tDL5HNXWq{>#l1paFIIAx_ib1z zxuKEC-|%pWj^lJsBqdiFcF7Yv}K^+E}5g9H5 zBinanBrWvQDLXY2%eG)U4%#g5SBTIi8yQ?}WMOvLgorI)%%M=sx0>1wukRs#oA?IO zbNcDlvn>&KilfPa{TA`jwN7NP>Be-khP4fDT*cs}(cciVi^xpNT+zLI6ROEO=uP@g{;Sx`@@RP(b;yI))_Xakx%iRe=+e`c&@#+3e8KYsA z;abDUhm*WB*F2+^>v~ukiEXQ4h_IB5RA>vQ3mIG^G=`8GF1}eG%Ir znUln93AUw$hPaSTT2r$IXijI0)0IkW>6L{C;H`Px8$HzBUK9Zj8FMjjmQfHk#2cx7HY>s~Iek zOE=SQ(g#Nqkp+pucrAx|Xu(o(SB+4FCVAAVb*%DuM07*Mr-)AyCyBpAD!f;S6GS|q zGOj8%wa|EGJC$KPJUv@~vRe1v!&7|l(zVKg@hkJLWvO*oKjCSbsMg)b0q5ziCPAr;-s zU@F>MY$l;eK}9`9cIJmXKm6qJGgD7a&(sgpo55b5VMaQ&Zkcjjx1?hDDvz4I9Yy~V zQu?ia{bUh|`x^-?+lFbI{h6F@Hs{;g&1AY>N?t4$kj-Ya@cJC$avvn#k5qJH#6jYF z#AzZNNNKx>%^);s!8xQI>lxz1)Y5~Mnm0N-*T`sH@s!m%ifeI*t4W`(ncLu+6*^mm z_p5WYfiZxDPFN`0byz2*GhWl4DY76|I9DmaHk@9^z_|a!|E* zV90CGb|X?*t;({KwHac^&{K-g99!2biPy5%biVOg7IPjQQuQX4Yqa|jayrqTOc+QF2KQ z{4DV~VvP6^@t4FK#KnFuxDi5AtxbwseSr80;sIiB_f!18_R8kBjq6uo6^;?ZD{l_C(5Hp(<1bwj>QcR>phd6b(l&c6pLeU2(+!u z?Syyy(DKMH_5D-C(ETU*ZN$*^l2~LIpfOlHL8|0$_sxKflWUJbs_sf8@r;P3zEOfL zH{b>XLo>NsoF3IQ7Gl%dag== zN8flvaOsq4by%_uU3L-C^+A<%qDk6|V_Psy{h=e9Ut&bbwMK9)w6bXVhDx%-4go16 zcv%pCfM}hVH;h8niLQDRmk#SU)5`)nDha zNv^xa{l{)JYslqX^m_iGo~Kc&`I?6-JdlqrzK5+^NwA`47=44$p!Qnw;UL`_dV$-O>l-rbY z0V1Idbzf3SN;3zBX~r@6!0_WJjnMKivRfTTLAL1|1enAi+Ml5c zD9MVY0=%q?&UQC$-6vBO@{h>hBmbN{L;g47q?;oL{G4S|MSkDd=f?%|1o>t1YvdQn zRkDL8dG6dplE%Jn=%|lZVA(bT-%s@UoN7`SST~OmY8GKp1kIpPl!-XF zUS-IBP5ut~1@bgT9IU&=FFc!d(P(mLa}W$>niIkVjzHV2AkZv~`PX5|EyS%Y5?xEu z9)zyZ0I~K3RzXJkeA`h;wiOr(vSh1xaH2UG8x;aA2*V++oQgUO+Hc5q+LffC9jL1H zGO~FOp&aZB7u@ocZe4v0tCVbGz3Z^$8hxWF2*0T7aP0BEbW4Y6oBfCFsX>bnNP+8H zE|xZ3_>_ExkOSTKeqzvU+eU4?a#xOzrg)qV|CApSaSsYjpx&q;L(?@3hH(@Tv?zct zGFY{y&^F>E75&!`?eU|p0D{bdt}(#zlemR7O0w-h$NWYPi^uh?nV*uEm&BOCt zO0^;`%`K)~%|LZzL5qkg2CdPoB1?_w`@zs5+nY}s0(7)2gnJTJa08w78|s^oz-f2= zIH?c=)uUQFJwLv+458_nN^En91z}9LDs~rngaT?8L13A}4$kXI8V2#VrG!2ep zp-%50wWA-Bjx1>0Y}~ZX$r@ZQgKnpnI{22UAu_Uf^UMW&@a`Gtx~2fz+U_Ypc0lVA zXzhNze9iZ6(KUm{!$N&Vfbz8;N<4q+t9bp#ui^CbFVIlQAqaxBPd^?mRHx(EsMgA9 z7c+1jS?mS{>{H)qqPOoxbyY&!)wof_IxMq zgqEcVjeaUIcj*#7{HO}saq#S^=cu`z#{xD^G(p3pRxiWJ*pO1H&qh&47Bucu*Ub=U z_4qPH$au25nGD|hum8p${_@+=QNPpx5i+?D-i~DrHJd6Q`bemeNv37>4O> zx(}M9#I00|$mTq(uB@x!H;Nj~@o@n8eu&z5m71@JFi5ZA1VNT@U3`4*9NzfTAF;Z& zMgt%z$YPlU*XOraFmquRR~8p2;bv1!4-Q;jTcxY}Q5K2kJaVQAZZEUeCwW zi6)Ar0zns~QUf=YWm%Y=o5OG4_#Lh;EvaN1#5&yAv-9(`#&s-Sy@G`+^D5QSfi2pt zNk$U+u`IoZF#<4B9z`8V(D-F?lTA%eP@32X!*mjjAzNQx!<&Eq8)hzEgy(t#TT7>= z?sj@;ZEmVY=Ty5wz;Uyuks`b#uN_H#7Y3@ea(w+IXrm(rE1&mp{CE>#z>p2U(G0`D zMr#8z7tYh_5ha;RpAN3c0@`yfpT%UesfLX2`?zpn2Fo{Zs9J^%8$+dOLV;zN8fuLS zbVL6Vv{6zRN)*clG$-o_0*PS{bZ+cUr;D@a&QhZ< zjep|!6vpy71!2Wsb0x5ID1juv$wthoCrPt3z#J(uH#s!)yojH?kK{>r)j5M#IVFX@kFmyOQ_U} z>ILsWmSl?D-NZUI)%?OdW@l%4q1|b|S0Oc5rCh>fv!QB9svd6IGCg;^TD@-r?+%0c z%PMgPIe^re>^TG8JEv%^UZJyM&<67^Qj~4bU#ny{?Mj9r?p=P#QOV*sN__A_8))c!vULm3{dDOvUa0000C$=-WdGGxb_tQD+tX|z!wF{?r zbw{fxNh8AH!GVB)Aj--}sC_@zK|nx3V4%L=mS(J|KtOb=WhF#4yg)C~7c}6i z!|VtRPa3~dvRjhvALk@)S?IQWUN29>w2xnU2fif{nR^WO2x=^0VL!2u_Rw!6z3_-^ z4)}S}j%hM??>c5*s7E<>+A>NyVRnK7BTr}Q693~w5C9&4NmS;mniWQV z)W_5p$l+IVt7rZWdTBw?G(Eto*yos%UU;V-p!ve&xDUP_&1=Bvus zr|Rt0c;k4(TzYVD>IF7YY6}i)?>RQ;{K7h~ei6I4gQ@WUrN0ylobxR9Ck;Q-kp&p7C6~0zJzqA-&SF@^hMl?09PK|>2vJI)gcpH zBiM*N7rVPTD5d`B-R=4wMUJ-qNf6o_qMVd(gtqcjx~J|$U=*fp$6UFQG|M$mai_d@ zPZ8W4Bkl7>9DbdOq+~@>WPivY06wTCj3WuVbdZ$-5l*H$3S3k2{w)Z5-REig!&h`G zD9j^Kd60N;PD==56n3dNORk+m5g~KYHkO|AvBL&2P>^oCip)vv#x(e-+BeF{tIZF& zmXJXF#`@b(0yXPB+#51h*{CmYABRf9NhaLOs9D$T9K7?&)D`q@R!s$T?{{f45jLSr z+O};{#HStYS8@rVVp_yf=^SM8uS7>|pz&$09E&^Bo|#%p-5s^Hy&%f{WPZrgYdyv} zGFGeFHwYh051x0R+iqQ?lfw*zfi+^%R8Tbd<&|2Avm6zJ_er-pwc`4IFrkClr44wS!{#=R z01$ySsXa)qt@U{Qk^gn$Q2QQ`KtyCachqaHjJ>0x{qIDEDO#6{bWZ6ARd(jE6I zz1Y*^O|(@Nkx|#mqV`X;JdegXJsFO(6 z43wIL@}jb9{ka_eRq|!ntw{UPIaT$6^nv>UE<%jt~;l{fI$Sp)Jtb zlXTvE`bwh?J~^{isa>i{knPVY*qZ%S^2a@g8XDkiAXt^Xx5A}>r-?CIT7d}^rmORS zL0PG7x4_)U>!gpGv43X$+uwNOxk&CMKAd~Wxw^~x0?*UEmSdy5|HnTZfv^Cth#Va} z4c7lRd7TG0&}V;y;?_X$m%z|PM^5EH(Yr>!UGdwtSKfGcLHsn4!`2JHfUB^_O=QJ^ zxiU25x(IRJ3AYC-ljtp22&}CI+ay@v161I(5Z>!YdMvKb&tnk6-)W0TN5H39{^saX zRD*`H90^H&H|%|z{JUm7h4)EsK2}ZAoqL*?_57=u{!!28XbwKF3i}{@T)bhh=asT6P$f6IIO{#s=nr~U%KeQ_yQ0`m>a;s$ z{b~h#17-E^d!f_=uDk+5A`4~~G5c*>gQxU$=I;Rtv+_lV1MH<{z9gthCt_TsWaYYP zLoF+t%|lV}gK_yhJTmBml$=K?%VxeQ57&eB{=#`9N2ykS;00d5{H))lQ)X2H6WEHB zRVfba=y?Ecy9>8faEJ%Lmd<#x^nA^6z3`w~uFDo)?k6=jY)=_@JYs>nVFx@rgS`W_ zOh;7UJ0<-;u%s{Yh0Q&~^#qIkxC&DjFnvA?8aY~Z%F?c{9uEBWT%Clwtlo|Iq9>te zjj$dMS(gH$?8;kxaa0M+7Qz+_W>nI~I5udjo1-Se8S+Hze$8s90wAS!GwpZ8D{dQr zDtU*#OFTu+FD|Fvkd`^5nuAcd#7wgiWnrfjOWLv~(xGL!Z=Pi6wUjU3OQqkb||KVADdn&f&nH$BvWcV3Btci))E3H5YQhWE*#WlK;PHqzE?L=%>S zln)A{K(+hpkIJe~jyC-;nLJAs{gGaeWLJa$Sst@LlQP?s8YH7mZBRF-SUjvsP~-rN zt{{wYX0oa3>k0Uzc@k~}v6Vp{BT zL+RxSCKFc-H`c4iP%k`W>`i$t=BrCo{T16WOKQVso*(O?z6iR&UX$G!@z%%WCSEYh zY$^y=-&E&^i(%BMqZY4i z#?#gMRj)=$tMf*zLi}sNq#J9=3k#Cfyb-DWeAb|kQ<4PR-@vPJbpj0EgZKyzxbhFK61vA399x%hUh3Aoj0 zu?a33!yTn?*>pKqZ{gZGnP)h|L&P1=- zIf9L_l6L7!{pzu&(sLq#;Z!==}xVtUSJT8M0xaj6ExW zeU-nU6^#onu2RRb>Ig^3vg9`J6~+3XTC`aunPB*3TR$O%Ic1+mSkd!0v`T(MW5`M8 zdqB zw6#hWe1{1~s0aA#yfal12`rdtW8*afeBQ5+BW6h1VpD|_iNsM);W!ErpWuHFx7O-b zWg!}qkhGWtoXDUp2<+$u`Kk9#JqHoL7Z!g{pTq6rG>0{8-IX3d?yqO0?XgL&psv&} zcD%&>s-4@tmomOrc|;w02+qs5tw|$jM)q4KP}&qUKVOX%Hf60X+>#F9iHWAEgxO~h z2}6jfTe>yx-c|(x#$oD&$@-HWWDO{Juqlx+s1x7=S5aCJ=i1rSndEQ_G{K@6cKO1s z^sz)(7aLLY{bx;5cN=RRXf7Q{9<{X3?3MjnI(i@~IfuH!RC|%#_wxJ#Q5A#YgE+Ao zD55A!n4dwpXAi*7`!J6F1F$=*Kot|bL+NQOJ{Gye0&$( z40Ue+{g`UzZ|K@iqLHJBBZD+bVU?#YE2#qwtE|%Y{b}NT>BhBOVZz~_N`q;46r#<{ zFwxG=d6afrG!>Lo79^lz#=9fbPvs4_PL9!A+yps7v)i}XTW|!^_`7pnDO#vWJUpqU#J=WjrYQo$5Z9b)KdhbfAP(M!u z)Kdhd380|6iabwCoIb{PXE;}A$h&Ni73V9F?7E%a3^lY*Z~7}T**%Pp(iI7a&Yu{@ zR)KEM#W#N|_N#VaDdlCBS63Z^C1d6Mw`iS`SplD~NEyE^=iAvDt?l)FSQ(<{+pBM@ zxqCG&v;SEL!`}>KH}2)7yO5&$qu}nI#43M4iJl8G-kVJL=c<_dJZBsSO&S-HYxj1$ zwf-@o+ifpSRAKh;T3URP1#toK419+oV7zX-A{{QaE zVq=@dCgDH-oe)3PRanyUsll9o_%*-%4QE&WT-w>z`vCH{7B9+dMPhXp@xT8pq36D~ zuU5*-syds%h=a8ZbrtK%Xltp>hXtX8EGWc+6AU(?%_ivBw%p*$Bq7j&!E9EO z6ao?;Isvmxu&I&Cga+l8B?vEmY^2WyNZu^xdj8v$8KVJt1^GvcKh@9T<>m#chc470 zTX%6>yNk_8YT}&q%mQzNP+V&55Qns*69LU@R^x9T@+OA+Sa3lz!~WpApjfRW zKNSb1ZxjTi`+Wl-KnE$=`qkPnXiP0esmCaTwCL96FMQZSJuwNSQ#9l`3Dy4mhJJ>H zCd??r5sX~Kt%$C%=PcVkyWsJFf(tz_He)4Q%rQ~i3a1;K-q=txRmf28KEq%(JG@UML}J@^}$(_VB#iYHr`i^e5Ebx`%kiN(&3q+$=aj0NULLXiusIL#{4}3FNK6vDVce`4!~D2{U;% zZTfMAG8*i7T}TwsbFbhKhT+D{=_z_1b&=Zh`9kNowUvt(zDc&UcPbyNUeSedEh@%J z)#0Y#CycxF59m%i+{l*;boqvktq79^qgEjruZav$R56Tz<*L*;h)02*Wl#i2eaGfQ z^@0vM;eT7i6GxNSM?3#=0;#XNK6@}?odozGhmK##j9>QA??$e_WVZe8zb1_TJr~GT z9E=a&$Et-*`lVw2Re_hA$c00z<5GAW(>m)9 zESK`HA3;pMkM)r4Z5-8`gFO4@35eX_=5DD5_!yXZCWs-Qr_(V_e1@+R+C3D3H_%@? zMggys?YFn1cTXF3LnxX0m?dsfaRW7IyQ9QgA-=13zCo9sfp_B33i^PpHhLivdTe+( zr`!V3aaAvGn=cGbtvC!b!aPXn=xinXpAPb>&(`fHBHipqSr92rDyXq8&X5;F#rLwa4 zd9g5drd*c~;g*BjW{1$Ky4 zME6w2`sn5o%xU;AuJ`_Cjg6H*D#;h;-GOYZjfSamM-VDh=kAwO@n!5nU?{W?Zi2__ zMU6pkDovWK9{4X((?z-n5;ML#7Fg-<+#o+O* z;TdLBR)xi|C(FK)Dui7JOJp!z&u9@?Urd$Sgya+s^{+YAtK3mhoEkf`bgfJ?z}0~}5W3Uq`D-0z?ZN@I$hafUbk&34 zlgm zaMwyQ6@uj47>`k zcdDP1@svH?rj|}Szl(y{xR@74MjCz@>C!b4IceKo6hW7!U2vEM^Wen2V z{wg;PbM8ZtZNLe)?VpXbU)NIwlktgw$;JX-QGkHICc$X>k1CqpuaW1&duBmucM#*9 z?G%qr`aeBS7Ozvx{;Esx_o4KTlb=hPx;_5-S3CO2S|v=_SSL#X4abDi1C}-yE;Iqu zt^n}ex`GtW5V<+fq~$vH7nO1twvndbk-=A97ku88z`;?_75<(#B~u=!L^dR!tU7PT z>%}8AQ9Kl)Kz!W7i&?kOpCzP@{~rDvZnXxIave9?OY^GLYlK9tl}S1$gKgrk06=#o zz}lqDZ1rKY%RYB%^bpCEQfIVpq6UR*wFB-35;M z_I^+8+PN_@KFKUq>HD`l(Mvyjdw5X)}BHxcg| zz=MPmYFZaEdmX;EH!fhoCxodo5GE$!b&jC5;E+){%|lDC|LG8j%d4RE8pskKZgQ$c z*z*>RdZz4z=sK`EP9~^bQ2-IEHAwU6EE)RCYq+Se+q%r{dta)HU9Z3e4-$Q{PqBO) z_Ks?hY^Jg0wq4W0QPFXoM+qVq^fno{)VXKn^um#|AckI@4*$EIq7#1-@9uz{@eVb{ z`kQ8aZ80yr?E*qPwm@sgrt8o|g@B&~)1;81A0`w(T7m?HeE+$d5>)L-?eP37r=HSlI13v+IFpJBMs#d?!yX4h|u@yhYp>F z8o%L=^?~-W=qn8iZa)ExGBT~ z{*~yCY^Lr!5@brcm2;6)9p~Z>BM|S}pC?oI>-HI(YE7^V`ACa@#m6H_v95&wyO1)# zr1MW}G^GN4BhU^Lh7ovRckWRVGFFs=wReBIsdB}s^)H<(G&Wl#)kjExMqSrKB}39w zCb=AZf>gjtD zKNyKTMiWcd9@AB5VX(K_^jy-=FJa@N(|Bm0T>I8M$hJNU5MFr~y?;baBa1`oNQ#z^ zsy<*mvCO|r7S|p1Z`z@>6x$At6I@7x==?Plp=llPl!rH5u+l=HYj6Ly11%SX7I zQa~zWmx>V0OFSV?U#`D>3Q~`4_fPj0cqq2P#Cpq2`|Q$Cj|v3fRLu}t%^OaaF9Sf> zHJ8<^#Q8{NEvMh-bA5K{sVoD02on_^v(5hIeARc$jxzn64v9;ZVvSq zT{E+8@4WzsWngyyqOPw8s8gaCrXZj<^^|x1yFK6SfT=y_L8H87of9OmYo=f~oYt!=5Q!LM+`vytn;s z->#Em>+^JJK^Jm3XSqR8(&kn`CKE#9#|XutL+Z0piL&vq^MBrGm!jLI9 zX^@g!eSrcLtszmw?QeE3K7#bF!88_@G>@v!ntyZiW}cht4&M7kv1-a4lQDK&f{;n2 zk+E?zucoCCY)aZCwn*+eT?=73zyx8T)zJp33)bh2F+A8UTWxmMhb*5B>LgY`&39>D z5lpBft}XE`Tn&=Bb|}%8;!&7f6bz5-S-X(ifHyBU2m(RMml*sdml8KOxA^gn5#s9x z0=Z7^qGKns>B>d3Y*!c{9EWMup7R)q9k#i{wcN(`-8aE(v5)^Fugs$s<=MV{=iesT z-@;*qh13xbZtUo00nh`px=p51FN~Kxy|^3i8N&Zj?-9klWdTjizKV>t2!sR`LWd+2 zz5kHu5UsgF_FxmkrIa0Qo_ZTM-Wv?xdK!>jVd;^vDBHg6M)0uC#v>x6b-*wKQ>7BOl^KRI zZ~3$el8OR}gHWaDj2c*n(ThWLvvZwc->^6SU~woavQuWX683$5`liz?!;DZUTbkdU z7#Gs0kOHcYWNQV$L5HAc#BeaIXgeCcIp76;s93QQaEao9U*fd0g0b{pz z7P-=caK*o>%1U11-m7(a!4AR}&ZxRX9)l7UhK_D!=n`sSStUHYPGtFCm69TRkSGJoS?uqj#(Or0|-Prxq?TC%&X5NWC;x>Y3*n{00}_3h@^ZD7F1-weefKhBMt zN71{+Gq&LdpE*)VEi1Hnz$;#VZk*R{oV$M=dZtIlez%_x?ruY&UYt@NeWa&nv=dke zC6cMu*QHP(CPPzMBili)u?eU%52<^7k#PpILHlEhHL^kCpAj1!^ClqCqrC_Np8Q z(xB|inF!#BChnm!>swAb%&JV%t8FrqEYrH>&0&+=)ZO{cVZ7fB5S)`EklDM0SSC6~ zH-kxn;xI!~8rG_5dxG9Jl9=SVp66FQVlqYP!@>iE<;tg@yL_!xp+5(tej?c61xf}n zDEe&h(s%GGStzhuxsIKQf}c_l4Ry_3&=nDkB^D7XdR`r*jwk_2tuNTI0q>?1s<{a6 zU8xwG$r!#1%6Rg}Wk0EdTq%7s#{D%4FAcIq^Z(Nm^IK2F!|%yfEohS-rKI8CK(r4C zFReyL<7RTot2+JoK6;Y-Pa{pQ*F_OS#g?rRrko)y%S(Xe^}ddAk!zHGBG*#*~im<1P=OGYL24W!otP7c7u2*Ia)YF zmBNek1SWzbLR8lCfzb&b4yD6+h2IsyD<&}E1N3enAe3eTKrGvRG;Y`KbXv+fl#J9^ z1dVVc^ve?!X?mOwua=3=p8=j7lNQ^Ma!jhTdb8Gm;gE<-%ElzP%FWN1FDUuS^ygI> z0aR5GI-=2>J4Q{IM^hcHcn)&)!(3NexoH4i(Y85vuED0{Ty~t4&Te#+HB|iV%9!Uj zybK=OG#MMVioCrl>b(b_2Jm2I2k~O%5G0UI5P$>dhMuhu8t@|}x2O#4v3Uc{Y-Zc3}=~$v+b^&eq>H zV;x4G=eIl@&3-@gT>f$)iXDS%5E=keme5&JbN;4i*aaxCUpPxUcS!O*8_{W0nf|6B zIWdR_pRPa6GWjp6I7ED%8rbioa*DKUomIB#Wzce^AT3?_pcTTlC6oZdQS31&<+>C) z=t(t9Jp6S3aAVd@wN!}Mf-l3&Xva#@f-o7Gp|q$%*_Iw$1xaOM>26z%|6G{Nb+^2P zsKq~x_;Im4W^ovpP77hbP8ffSJtiz6)Vl*RAiihR*+}Y|9>Or4zUwl+9qg7IeD%o^ zJi2t>=tR#92a2lq%8)zBvBXa!ucW*h!V;mQ-=I=0gBmZwMm`ow23Xl}@w7*82723% zqT#RDPp15`kyV%svVHp8Y;S{GHWiDP^396UN=28B^UE-*SbD2 zMG?vn$w-T4*C7RCa%030+^5rKEi&tzI{+l3#j>aEdnHh@1!VwGJ3`s_R*x`FFN0Lm zmx$H`3VZyd7^3AmeY3DGmVHEjCdsje){fwW6zo^$u zzH;p_&Yp>_X{nU5)u7-*_>ooW%mgB3nx9voK49zKd6t*E15XBm7IPvEmm6XhyTt|B zRcXnS@TUS_yhY7v%cz!X$R6i7VPQ9PW=3lQZ`+)s(s>eX4yoXp)Rxk`^_p8V-Zzd| zyd+B*@j&4?xsjaqDs1=*TKHBrxS07}V~ z43|076|N=z<7$hVsw`11GG%r*^;u&?$d`$q`a)nqY2Jj>-SRevy)ZH2!B=1SWJcFG@2^MvqHC?pz9w#y8 z1WR_Eg4juxQ!RrFgf2)EPbEg02Plwp)!0Bcq8{eKr#U)@ee&i*MYPor=Cr}l-d8yl zI~7RC=@heH6GYYeMt(NB80j&Sr$cGF1@CmSN7s;0mZF|gf~iXI*o9Jcml8F3#JBgG zrf;H|>Vrj&Kxsj<19k&%993PV;O!^$>_%O5HN}neL_q5EUBbdFAvxHtskME6LW`WG zt8+k2VOqnyFHK~O=A6}Cm&0^T;oo+Mjy%3F)yip|jgjg3tU@*(i$dJjINwEEo|;M( zv&GRmMOu4kbPlU|D`15q*SnqQjDe zlPVxkrZomk2<{UylrykNWnxg_HMO~{>p#@lJZ+hhdCsamkL$JU=l$dIk<@M5i*n}% z_^xJZE5d(RhLn1fESWrq@+(_7PwX@BW)Cr|6qNim)MwSD&?V%z)~b4+0Br!&5{MM0 zLM(OGapYV=uCH8AH}>|G31_6SRq%vKG$5kO~K%5=9|qK{Nek?mpM2+oA+off8mYO!yGWhE5?gI`_#216m08jnBk6G zx$Ect*@L$E>;$0={UCaTsi67$pM|9IeKK60Y-ngnWcTL88p3L~A8wyIC%yhv!5+bo zZqZ!MOw@;8{JJ+LQ7YsrFsnGQWbj6|VaGR#ouu;q^@39v}S-qaB{n3=w-yCZ;VS2!1 zmFlYVhs!DTo+FzSKCy>7i}aE^#v@#zSP3$;{q6wW61GY8Y@|n@{Ukd8CQ?O4jj?v+ zc6t!gpqpi2XgST*N}yZNHI;Q z5amv;?huPZ-DgapLsD#3gS{T8^(+OZ^Iu^ZJ(PJ8Uyc6uhvK>7g#>jEsQn zC%BE5ac%REH3ZwF3_+#A{qC%VoEu^2wSxaOL~4)i64k$pWpPNr+!=X-tVjgUGP`o_ z;Jr4rvja`+&%x1>*Kb2EqCo7s$oeMw=O|+Nbc9fyCb@;qKovY<{M2<@fLEm~RU=_i zNZaMh$nFI~j&Bn3GWBur{LJgk!ym71zB;mDOAPvY%Y*!m60MWQNb%+pB_45rZ{kxy zMNfkIvCW$*^Dc_G$oC1RkrcQTH!x|8VY>Fi`>R3D8ZA7!_GdU*x!}jAP|WlTscLjr zU6LFU9pSG{%FQ-`h%A*YUr$JOWNqM&9v9wU>O##N?cu>JQR$(&A3xk`L~oK>pp2!Q z!;Y5lGO*}*q+5M}>lh=Eu5NWQwH53`Kq7`T=lg$ZzJRSKv-$2Tr+9A5jK$|q5h{DJ z>1vWez-9GfwT9VjX5gZ;mI(SrkLcQ#TS{8eVbV~#rR)SA;mOkloQ`U)m=> z+?uxN7kL|0E~jxFR6U`6A4kdmH-aQ1d|EOSQj+qhNMvbmy6#Ody;oGn%X1|b)Y0@{ ze-E08$%C!n5iu;tkihFD8Hy}(ITy?VGV$?|THr;tq~Nu1cW%W5+#PUA!Wp*PdV@GS z8j8+slwKcT4{SZLSPaHYXs*c$-(_J)dWee#z#7#62YHbUFq_KUN%dWow?m4LTZA`M zoa}{{#MM0Xg-2DEK0q2-X4qnx-3p376l>k>oK!~Ox+@{_CT!CqmI)I)R74CJteqNK z;|!$ZTzY?Z%g)u$cCV)yO6DFg(`;VcgzO{TFR=7Z#JlEu7NPe|`5P>kBBt>3JcQC9Dc1vS$sJ`B?bJ#+DRxfp^;A=J|dIUqF^?{0yC`F?L6+KgX78xR(wdX-Foz$Um3h`MIKb3|F zh2T-7T6)`YgEv}W+da02%$C~cH`FMn{b{)B##eBU{9}8$pR*gp2!$%L&6T4{yYemQ zr%;9|6?QD6wbNM$ZkWxVyaTr&BQYgS1MxiPE^ifH-$_VJgy@YfWmZ$=<1=xCa7+85=J8z!6XI7wg{4b27VZ-P5z(bMGxp&(N8B5bmGY* zGR4_VJ6P4zL0hc_aNhL3=n~C0T#~E#aXl7TnuIE9%g#X*MPZS$H5HRp+z#atDFTW< zNU(xp0a+dYoKnR?yL5+=V0H zg(X_UYMg3`cz83+umO}lVsj%7OjbmZJznFDt(_ z^x~6TN#?FO9LrH`>iEHCnWc)M@zB79qSl<$dz&(>+rE{pAhA)d#y=wkMKkJPsp!T6@#^N!0pS{5yHqM_)peH^0Tshs3;#`dTDcR ze!n^P{D2erl5Lnmii<6)ItgsC-PwDQOD9#4K47W-iW8k=mFn25IVe-#({vTgsB|}W zh)@$BmppiF*4>S!rd9Pp=_?W-679T6@q}) z$!>iq-w0{WoBx^hS%Lc6Rg6{*)NCgMCzx#d_(w@Akx4*v$g@#?pA75ZVIl^GeW)r^ zi~rc%8-%2ZH-Qu)XUGMr#3&o4#zt*FGFVzQA_8Uu#G*}Ig#rsv>)>c_9XO7g9+0Sha;(z*#+&50`zo)Hh(!@#6 z>)7Ur3u`w&Pc+n>w|s~r6*T;t-*$a7lS zxm#n1(f>utV{%4pALLmB2{ieNrKQgsb_0UnzCANb`mflJHQYA0+S~h;QzOaYFaXI$ zr_8S{rB%Ep9v36o1iejri#>pk@gKlIb>>Fhr6p=4!Q`T&dS+E`*G>v!02aMcd_GmW z#Ij=O)xqA(c0gG85}tzr(cp^;Qb2@5-?QS5bRWEZ*>8|jXw-@P$l+!_LwdEOD06{@ zMbj}}_Jzp{VFM?iR#zfTRTm?62AJw!%cOcn2K1+#XKYsXUa3q3-iY9y2{QiJ9Ins8 z4KVsh+61jp)_5LX3B2g=%~@V^c(bugDz%fCPP|Eiu)GPekr`ucXhUY^5>;dMpy

&Wv$@lXj3V+wk>``;x+bH+CHNArvk#VtSY1AK85Dnp z`%k&{ghxH}^o~TntpQ~8QQJSFn{luXv+)QWOLsovpF*r@ngGm&*L@xJ8S(bGvq0CM zsE*y8ah!Z5q9lxst;O}KfeJCY1)jw+^K6?`u!V?#1_)YW&LEF4v{awO+M zP#}7?rm|$_cjAk6KG>4MJ^%o7Vb`6Ep@Kk^9if6>=G)3*V6mLZUg<(FARE%H%X=Q*_B6p&G})$xl=j(p*)H5{5deSy`&3uwB7f6D$3`;p`E&y!shC4g&; z1?aF3k(fc3MQ#H7x1LTWr4r8CTMOc+w}jF%5JZ470~re7;xi z8ndSyr(kLocuoKVxa;dZr+*)tQteg##CsetiZ20oGCP8h+JCS)@7QkKpb#I|!PA;V z{MemZYq|l=utu<(VoS`G+`3=-d~&i(tYlWN1{a?7mpE5|U|Dd{39>t`488?E_p#VR zZWbc$elKmnSy*T*Y5fqg?$+H=yvdB<$6;d|iMWxoh+R)@#j3M|w!ssGbC{3m1jekE z1l_CGVG%`g0n1kP`z!D509OSH zW8HMoLLNj-eU3t*1!sgsCk}rg;^Tzedyv-gHCfC+s8N`~zm+Qd zRZ8LTMjm^oh9rCg86hbF80RLU6xUyGglCU~I@KcPYq(hVv6mC6%u2IUaa<;mn4=&~ zwa}^Ig4wp>R#{wF#9d25S<`16eK%FiYJuS$4f3)ob+~W1RPk$PjW>`2QB16_*2*#%ffQ`8EQc(df*!!8{GG@`+$h|W>S#2GJ^2qS z1s8Qsr>lKmpo8bU+lopx135xhK=3;hn)bUpMavRW)pm-}Quz!o2Tyqs-KlPDP?F@< z^*jCI32kpddpf(b&4SDBafAv^zC;U4$CMyJuP?7@p*zE-3#Of{m5#A@(9iCW$0J>L z((FP}k`9Fb3ECGW=&8K_jrt^2*!rW47Sh!!4G(ZF!e$<;s(FwhdzZa>VVIV-eaAiO zKT`9(%&Xu^S5O?8rh{3qoh%ANQ_0z%kn=yWph;{bd5q%ldBj5@+-y-fPGxPLT2Rkj zS!UvB-=#ic3JSqnzy; zXl>Y<&|C+$sh^a>+E@5t#C^x;qIP|i`d!M~Ph&Y(P16-urfK8cg&S}(#rE%V$8mJB z0Bgmm0j(7+;0#ti+s(lkyR6;^UR^;KMIkRM+^rUT=iTSnL=@Rsy&B6*iM>r?G(nv z%h!*34Fit^f&jix$I*2q!*Y-*j6m0oq%y{#x?IAfl4y&{tgJsU3=O)bT@9ir7ZWO7 z-v&1J=kG8L&cS(3W5_-Ox>?;12;IIQ`zG~Is8>5*ZWN-Ja5*q-myT7y^ph{3Go#G6DwtZxZ6Ouo;_N0UJg&pCjQT3_eJSIo7xH+?o`PCYlehAal z6?779*qSM9rqNNoPksmjUKnC?(b@>vDqY==qWBN_?O(9X>#g53_L1``j!Ys~no!Rz zcRTHHb;g+mO|qjI#CUhb$Czt?kJzbL+m?Z=(_mm4GKbWM3W&OBls%NIE0pCgry)Q^Rka8_NCrD2g^9WAg`P9V-nT*?h4L*jbFT z3tAcmlR>An?eD)ytqMT8rlXk6z|eJ!7c-b$D&w6;Ygj2aVQ>&}H&Ga+&ZgN4!jqm? z0)`ia>T@e-DF zE!JGyQb`vwxt=~hjH!`4Zoa#MyK`$Q;Y<=M$tb^9TFzz|s_LJ_(9*);hvBC8vKx6H z1QD)Z9L3AeKY^@k`E@UdS}02KdQ^_^V2zOBWbS{Ep&#`Ej(JGl7*v7^6EB}}V44Oz zKSb8C@V=)e@H5vYF`RP|gfSB^sr*3-n*bYW^q_zOqdKBNG>Kz)MxMYQuShN0^yWL>OQYVhf9 z^8Mm?5v8nyw`NyxZ+=a^H|b;o*?PSR*D_%fPQ%dEz%tHpuJHnu08?xFX!wBwPWB@2 zGIaF|+^;zLrHLUpmVqYs%LB@>Yxbzueq7@(K-(NP^*-ve)TgLtDW|i6B%4ie@);NF z)jBIS6Oh;xb2eV2yNwiGy!GxfR;x|IrYkq7dP%|xY$8j56Nfm4z$wVMr%DQ$xK~7% zF6A6toG9Vy`4LQwI>Ob8muXK?u(0h=DdSSiOMVX)Xl+)J=^#lzHJ zM*`e;*!6e$`3)pF_9FF>^jyD>1jL#24vv1~hY)88Gy!J}Ng{llw>w8JenOE1=Hp2S3{jKy+YLFf}Qk8M3)k~BoaOB~Nu;28>1 z#a!wSdTJ9|^0Mm?_$7zsQyyg)&VcQPOQzKnJS%kKkRXi>WpRz}^)xk7$f!af`}2Ze zuc@cw1h@}zTi@q%j?XVpqm)B^j{5u5m#9CWZc=4z6una!X92VVb%FXM_1CE9nS8FP zYtf}4J-9rq$IKt6+p~}a76=O2OgjN}ewX*+3iABqWC>TMhWIW@U<=bvx?Gd0djedb zzN_*07e=i%k#f#B-dyk%FdeicAjLcSf|)v~jOTIwRy(a@EKWlQ^H62Mm>A07J(tFn zGZ(Wie~ZP&RK@KBM zGia04^GMw46VwgLkbIHEx-qWfnRBKsnHTg}O9cW+*Sj>)-9 zzB4$lMp$AsR=Gx?8lHkYN zu1}h#O^1s=%~wC9zDj)yiOVe=Zn_+7oJPuBfV~tt-ac4QicwWO3!#Y^p`;3?lV$(Gu)Edp6%D+Ir!Qlps0-Z^CY&ugxIf1K+ zgTN;s>4a1LY3Ueo(mhHYabf zy9k0N!za7{a3?Z0Bmdjh(;~wLy_=OyFzH z9mP>sR5j1hHDe5!SU!|Uf8KX??bOxp=Zl>?&++~4J zQkSVuP`9Z+LIT|_szOBrTl@jVNdj#g2~?k^ewlijvZ)=@IcB9dO&gZw!1LD=^UHAFpN@!4_! ztpaFSwmO?Grk2YaqF$n2r2ZE5P3jMkxZNz(Jko>RC5(%guOIaqc3mHJ6$xDbi2A40 zFHsXnio`zBSW_1phQ0!?vx_`6d~qTUSkT+>^%IgfHV2e(JU>vR9VgZ#(Q_FWd4kqj z?;u0q33<$KFGg6c%h_s={cc$~mOc!H}=QTuO|BH|LmvbG$9ii6r`bnsP zhCpWMI$XyZxRbR)=T=u5F;)nfp>N%{%%`PpHn906S6)taoBAI0E$X|}+Xr}@UBz(& zt%L-w&r&}}Jw;iA7}&Bh@O=+K;BQKNgSD~d#dv2q!f?h=i4ygB|B^p4M?UMax<|^{ zjtgu$LDL79?E%1cQUZj4D`hV0HkvQElH?KLxaoNDrmZg8^BS9e5m##xu3L)%#&Q-cy?<9rr-Wtd9A8He z4uIYPgpq=F5Q%OOtmRsyv=uTr3@LVU2ZtCLBo6lk^()jX)R(9)Q+KGf!*aR92F*w} zEtTfisgF|=7@&LY6fH*)R|^6k5pAopvfEt2Tsg+fYJ_WJ2E4HU^N%IDG@Z$1964yR z8`-Zwe^4Q(xloDG@M8ttV-8Qq48uHVH`^{G@A61o?q{jLM}3X@I`so;h6)aH0fz-z zj(U#zDD_L!2dKg!&D{>UV7X}9&Y;n#Z2C=@6BoO+6ykhQN7mxWNBz#1B)4OlXnKB< z?1#PSj>TwnGt)R2(1fcdi_@b@#BSuQ-UhR)=dYFr}^Z!d-@xh9ha2>Uo< z=_+n!TP7M_aFn}-N#GS`12z>oqXxG&M@N&h?Bq-enPHf8GyAx?*-kN@>Sw6GP5mG0 z52$Zb%aqs4p#6eoQB%|hkvQ1L(?wcGeOmho$H^cFJVa5r+12>pgY^jWl^7R>G=zQf zA?YQKrgPwK_NNPI+Thn9=e1govD%2Y@#|PYrqfMN2xzUyP#3AcLH!E#D)j~G z>(p&(y_>;$1x=jlD)kZSSE&zCE;_B@m`AJ9I*yA*qq^xg<|D*>ZZCxx&6%(ax?0rV zT&7_#;dDA^(1!XDHw%qcZHiqFIP}! z1?i_A>m1uLO$FLfgv@Uo0BCY#RS$IksQtY&48u}7S!T9l$N@e@{X^D}Lg}@sO&jbQ8FNje9aLt+U$6k)Tm5zMR!iQKYf1bl=uc_ffy7 z7yB;i?L+Tw7m1?8S*`IXbhvBz9n5VadR|GP1Clfl-l08(Xdk_b40elPg1KFAcpjmh>Kgd-t)Vq4v#On!DHMhKrOUjVj7= zZ~NkASF&f&09jEHy|^|TLxZ{E!Ns-R7qokxEFwJGBtEO^1z+GC217nJ##m3Y?oLwXw{xJ=B+GywkHptvujJ2DG!g$ zwWBC;!-{{$5K0-elS4nn>k?<22*l81%JUh_R%}e`2Dl0he0F2#VrJ<1rJ!#gD-T@c z->Y8HUs0q3pijrY>uZ^eeMC@b5b@pmYtgU#9z3|fXt4*evrQ{p&r zjZzeI05=D4rMtcg9QT&04R=1ZG?|t3(WRuPfbH~cN#j_+aMnTBj-UueQ&2+bthRH~ z0GcF$31Lk?jjyrR%gn&+w$qesGbvTCV87{M(02cye#7D|CMikAXqo|FOI;aL)v&b< z$HhJM+0@WEEcb61?%5MX-vo5y*u%)c@jbjYH)pIhKr=hv3xAiAlKSd--nkMMHn((> z!<%ZLYkb&@LAy`*xnz5;U@bxO($Xha6?L)8kSV2u&DIh?yE7g* zZXOTZfU+!wjWS#}8;0YTkrJ*68Mx0=OV43Awi^TYC=r^slPQe`rTh7!*?8 zzP_lRdHu*|JQUc*5IN1c3QGkpu(>BQ{3dJ5@^8TdiH`xab^>T$Fiqn$6T2+E;mR_v zfoofXdys+SMm?WenoKMD=+e-)0Nc}JMUMxtT&(D2TJ3N|05mQAFmQHWg2a$8f5rkR z<4v2xR2d#8E67=E3b3X*(JZ%k&$#yr+*o2$yxUcN{V3+dS{?&7_DpgKEtaiVF9zGK_saJAPf_D0WbiH zp(+7U4bv1b%?m?0gNFBt%EM#5(>_NC(C5JFOtjA6LM0ap|$ z8DrcX>xSc(+OyzH@?oy&(;E%oDmodLG}in%Sgs4I#kcx%z9+8)6-K(_oU4>L;(E!~ z0UPX9n7oE}36&JyPtvQ3?&s5HBv@y6iAfS<)|~)a5Ajyusjg@^9K&)6Wm!sPnE^O- zJ=%B!IFyq9JOdyfztr?uDxKX<0Np6^YqFu(P6h6Pgd9-m8ca*l^scGr%>wQLfb)D2}K>@?hZ~C$?>ByD;4n zB3i)2un;vcHSnkv$eL=NU9_wgAbWKJXgf>Od;*{)fG&pF=9FbAOjo))x`5*=Y^A1c zw*l%^&F;Zj8mSGFYyq|UY`i3&Hpk{#8{Ck)59PkzXg!^tva2cHnqW1k4t9 zytg!9$eSH`=m!Ylc$n5JnCjsqfEE(6hXl|F0@6_d=~XGxQIr-bLg-aJG-=YC^xmaIAb_G2>4YM| z03K@SB@n9IwRil#?|bjZ`}^H*_k1zzthHw5nP;Avwc!M+tIAQGr9X>6AgC1NWu71q zCkGIS(}>e2!ILV^;S-2szZ4W?9%;H9SscVzX+2{6-dC%CQAXo*q&w`(LX&pSgl`m23QP8smnYurN*TIYYH?TFtyl5#or+soxuk;j^MC8D_m%Y~`5|Jitjg{0N0hF< z#NUtT!XoCs9}S1JsmULGc>W(9yPyLs_=sS&sa+_jT7i#En&d|dFRxcx#@!DUoBcKU z+qK79Es@v7W~yZk8C%Y8jrr=CK^h6S(VLVo*N9ZjiS7Tfy|#&BWx}*H-raTHHs2lA zGCKU>(i+_`+rDOgFYl44}V&lQh?Rr^rW2WIkhpmC*D-!k|?|NSI{VC)z z7ydnKPe>Ho!w_deigx@HHf^pV5OJ~xP?|o+41O`$D`-`f^e}UszS#VGRl?QE9DUbX z{-8n~6CVHhH+?Z46+Mi>>}HpIv8PvcvC%B=uDwVYIPSetiE>NgFUiSRSQLviQY?sd z!HBGMnsgmg!HPMpZ%%R+6!22}BM*H&yhDl)^mp9>{BdVsvvzN@vMrrh9&EO}HK%Ue z?#s5u%|B}L<^soCesvhlx1GD7&AT`MxmuKtGFGn9pwRMU^OuRv^&iF?6SZ%=Ro~Ai z9tFy7)CiI4)9f@hRtQO?G{kzPXy^L_WFld1m=s$pxntj=bT;XH z4l_pkWBVJ3Sfb{xv|ceYXpDs=5P_Qv^pvSHS8_P8hJ)`BW31JgJ(*Yf(<;QQ3zvqM*Wd#<+J#0B4 zo)`-+3L`JNU7an5oy9Ho&Ts<8t*FXx}h;{=bI?q zj8_(&7k?8&h<^q&!;T_+TzjDkH_5Lg{2?Y0QRr&0iqXY+*J{^wR~ya24KLD#Wx&J= zBjm|{z$X!9lgoUZ&)g}CH#;SZ1BAj1>=}P#;Z`f|l3u&&P|4eRo zJ2uSLB)uLQcpa#3o%vmFnO&@A@V+^Jq7s!tPPRR+Ea~-px6O12nnvb4EB9%|*|Z@8 zn}w9Bs_4sS7I-x;od`s+ov*m{^&cC$m%I!4O}jgzDGuFxyBjV|8y$|GHkf71+jv1C z!{niCmTU~+H_;!8u-7^PDq&RS2?CyQjPP#$F5**!tEH!2WL0(^N?1Y{;uZSwQ=qm! zq4$I^+)MIEtjXpzM7Bz#c1|g=pn`)*UQLtw7{W(&I3Ez}p&Xq&Cw94lw@B^%UPdb-V*M9>1h)9hTga~u1`j$%OTE%BKN<_KYHE!E#!6hW=nOm_NBk(0c8_LX& zPvK*+=d$Yhzs^5GMCm3-MuldpW%mu_L*pkJAr7Q4AwB_Fl2`1IL z{%7>X(3(L#n3`HwvU)OkGdrFA>}w))<7)Kw9E$z%g5QRG-;_XS`FMW zoa{tBMYBpoFw2jtdgnpKP@b0uRZMU~O0j}-W*>kERdmAA0e#Pt1E0vO;tf}Ec^Y{U zo#F!aC0c+=hx%wLM{uTd=gzG4jz)r_v6^>2bQnMRunKo+G(UzDQwU5-Sh5$X*{VK} zPf?QVe>&I<2!2xl_WeEu*1g{yi_C9D^j`79qKPrYAc5$HsN_QEC@lG?+hP(JetfvL zcG!_rUaIWA3QlX4Q@Dd{H#!7D**_anHx6sQA_Xz*Gzj`U!m}h=yMjT@9q7hi#6K0n zh^zis=$9Y_5q=05NSsC(P3#lHi6JOwJtOcFLRA~)z{T|sD5V5>B_JD3Z=OXtWp@!C z;!?a4{^&tO3Dqfp%(cE^$A4@{kW7vNvf*2j_yTL8u(Oh}Y^`k*a&Y zrrw~}F&`U8ZCnJiqC0jJ`)ghUfmnS3({ew>D6uL_zkdWshDkzFbg>EpRtT#p8j}oT z&O4w9)L^3VQ<9Bxb=C&t6Q!7hVdVYnl`K5L!VL{Uu&)F=?wy!;KdZgsPG$b7BTZZh zvG+3t3D0nVVBNGakP}q+?8=NBwvSj!+y!(;5dEQy_(-m2qio&ytmWT>o{*}{du{ zmoOhgNGyI52rpI%%iQZPCBBAyc9VvEK1G$KgiW%P-g|)H+vrvv&f)A22kk5&87hK@ z&Pdo=++{))%1|@|vX-|4ir|i?5I(jc`tKsLO931GF6hbw21Kq9ueI_*KM8w`fFy*$ z!SkpULwK~k`qXr z2c_F|n?c_8b@h!UYmy6OOBAL@Dn&iJVYH3fm7KQ#{-z532+2=2iqtt0gjs?uN!Zp)wOE&9^e6DaqSbft*>|l{ zea@?<+2N9_)X!qx$4HB0E!Ea-i9~ac{P`1NF>0%}=asdxkU2gcNi8lj2GkUB^J2Lo z?T4)X`tGqma zzmpsM^~BIRNp#|_@dThM*_9N7$E-@-l&m#Z@*k}LoDp%tr6lkV!Zuv@R*cdW5@T2K zPrS!OU&CV4V3xf|+%ots#~?MP;Kn@DW`&zt(kdiRK5JK?X${me%R%S-;*zo6c*SAq zP-rp3hHtt;?s4$VU9yCOOFN^%X{p#J4)UueKS*8;pLmY;?4< zsFAJyfp-Vq=bqyqloB+y)>s%E*QzFgEFyw2Ki$DUO)?)kUt6$y8|GVjFKtP5DY@;1 zr7%RW&n-$&0kzM$YV{VaFj%lTFE}_2+cW)ZkEWCB(ueN__m+|hsxs+W#D9*sE94n4 zV-_YQKn$9V&kPG1vY0hWa$^U)U`)36U#x&CMohMMN=2|coFfs7e$^w#GeY*LyO_GK zNM*WD1B)iXkFCb?m^FEGV>J^M>!Az7M0p?v)GZ?T6vM&K6RjuhNy`>(;%H9%R?=%5 zbqGE0|TeJ;P^>Y4_xj20y~-@Te!J!~9hS%ifQ*i|?tIehsfPQq2sTr$PluR!O_%^IH(Z`3(R18c0x^dF8;7BA=zdvh(@6!&vECgK2tJFof{= zexI+K*Q=DZ*5oaCKh_Lf&rT#`bI5V8&O_MPMHoL+YOi$1Q`g+qTRwt4E*{FGPvE5j zr0Qm>n-L~k4+cj03S5Lfhp)_HV}4BUonu_q#oQQld6kXfp9=bZK3;1K&Y}xi??Agq zo44SKCe9s7b(WZ+i`_A@*B`2TBI)H~ny_ zPWfdJoIZKCU^uUt%bHc6qdZrHkG3(aF|}1vF?KQ`K5|~M2HPS>bOs}>YTZElu%baLgI?tes0`{%+^GtQhaNX%HsP-RLCKSaKhz%spKi+Kk;R+Ev z*9=C64-+@Sc<{@c__L{}YQ?gFb#Q>zp2J`I<$ZeKYRk7Bt6H=YCMWrcZNVovLaR$; zi!HU`Blz0L=CGUuTrs{OXC#!FfzGoR59w!&M;`Kl|tTk0p9o2C?p#^u!k)Mw2Q61B%b#RD;e_vP1oVv|Zw#wNtC>Jv?vMD!6fP~8AUJ#@jK6$NN23aff zKzTnfx$E=bqHU;-y_de;FMR{VSQ9iTIPW}veKUPG(rOJ($5oi2O;Pr`FRSeBT&BYP zl=prWZHA=f@QUq{Jw@yrXBUeM_6+(xeMM&4O){Q0KC#5(4R6IT+b+-TZp|1H>{81) zq7n}n-`A?fG0 zQmDgqdlN~LVC$!b+IfXaWlZ}0+^8S!@J=$OTDQy2+fbSz%Z}C7RSCT`%kH?J3mLu9NrOAn$8oOqH2Zj;jPkb-8ugRxzB2v+iY7jc?2Ff~zJ4knEP0oidHVsSlu0+GhSb1~ zfSYDzRbr*gRa*_C#r{Q0L(M~u&ckCE>fveg%NMDAOc%D0?v2LndkqmQEA6u*REQ=4 zjV#&%{Q-WfpxvbT(-6rgUVl%6NN)N2j`Lx0L&2#~W@F9axXP9x9)=FJXH$~kofEU40PP?%G~hSIe~^ZPe`J{6aIx0gdur-uzn^l>5^mT^E^HR%gq0vdoa=lo zly97CKA1SKRr!DjuH!yxcg{f#_4r*K{N>t`o+}?nW}@yh14HJ8Io@sk0)o!eFsS7n zjzDVyc8lDkmo&0^AqiKNV}$NG!Yj0OdpLH527KSBx21|_3l6j4oXZ$1sU4i_v+**`P22P7 zfi5PyD$ir?Ie5l$6L$8KgHG<{@I8mx(zV2S{-i3TaUvB}n6l(Nvl|Oob!S*=v&QWq zCc{X3REviQ>A3e5e;}KP?s$s9^|phZz!wD0k?!PtoL?}L=)IQ;5pi|?kmexvJ8l5w z5Uex=HIjQV4Wiwr3-H!#gUn?+(xyU!7pA~=;%mY#ZHLpQUfQ#=HawBmjScKweLj=7 zH*jw=8CUox_oOsb(9ztmzsh;MHKU6B-ivc<7b%>Vkmb9|{z<|jHsQ>wpgSTu5h+gw z=b0<@tu<{6zCZvyd_~UY(|;8=Wu_X;P~zUwrpVZ(*PXbg)idP+f_Ui_a6F=0CK|26 ztx+&YyXhxN2k{`6>&+Z+dZN&vkU98Q3UAC0B|Wrz25?vGr;x=o`(0q^wH#4+guX@>>+dqW-*AEzlE2mMm9 zO%no>8RBWzVAs5kRmg6Lo8c=dDAsa)IH%j+8s=@&haPHI)bAU1q2KXNA!Nvd?zHC7n7X4aFP4r>XyMGU5EXmHea+WrN4VMN*% zjMxaNx+fAj%uiPGV+WnI;416%AmhZAw42hu$a7f;=g0X zc9{=M&U;mAVY0`bX23qjbHYA*&8nxVD zuF5?1{4WtN&3jtf3USB9E$sg6s za5Kc@xxxI!>X7%o4%fR_`#|EJsMGhouB9rZcOBD%yZPmb%W06vBg#h@E1%)hleH58 zl_Vf4@g01FL`?lHEmWu!J5p;c%CpxC@_L@x9%?9I2Y!*|C^bT6UWuhb(fUcF_7V&% zfeixI=j=T>t-8ISX?EQqpzXs0)z92X&pD$MX=@Y5q~Mg^8JQha8;qQ{-b}F4RDck= zRtVGK&Nr3ihA}SB%)`009kE2cqSDF^)zDdP`xJmbn91I}$E7lB+vcm}Ke`MD`5bnY zufs4qIr!J`OiRm^C2PXxB$Xnk*X%j}72~!=iq^t_sZ{|k*D3b}WN%_0E>e@2gp7PP zQtZtS-(QUskLBZbAx*JRh)DRWDHB9)O|?AR+y{AGR*Cd54L-5JH0YEPs@+4gD`=yb zm_HepSAQ?VW3+F@aM=rCd|^47=rqVqRv&-jt-&yOpUj|7`sA&w8~B6Up2l?a%(@jB zrGxbPV%$P8)oo-Jlz;s`|H!cK-LkM zI>Lu99R2l*hVty^9s!bDk-fy$jLs7Gnt_CvJFVC@qSPGfrd31rGyR`J#&TUa2WU4* zz0x3^18`NCWZPA@b*+fSr);}EMGi+Wh3GN}-+y75F#kom2NFs?PlICZJW(x52@ujJ z3``WWcemDq6sM*b-oi{i2Yd^)+sev`%Eyk-_w4pVH1kjJa8?pt3l%Ce* z&bIaTYzeSD8}^tm`NVsP+g?ZqTE9v|n;V_4eOVg3fkBw(SP}a5rENh-ID2Q#OF>~3 zDB^xufvt&ZL}nzoF9OJ@hI5zl#faxYa-7m3;fHum%!5B%T!+8Dxq=+Zm!^;%mN2Q?o4jTV78Tyz5z(T}u37@)3Gpk&V?}8buvPtUAHpyw2Oo zy|3&KzIci(-O9Y5a_$Hsv?S{oBDLA8q$rCG6lPwv?x?&Rc)K~=e+1F1aRqs*@{uTj zD9&x8@_q9uM7FxpDe(GxX-FGO1Jcv^Qgr6#|ptg*B0@(X50u0 zG}Ks_3W50NKyy?X3JW7pC{fIvC5`YIMuN~z@1|~LR(*s#a$C@|<^Uem z8$pouZsJHFAVli0-jb2^ZKk7$dOhfQn}6kdoB;&!9HtWX!KD(y?c)Qh2bmxOgkk}{ z06sq!K3`a8v?NIZ3V>0sUeinH`dy}D@^F6wPbcS+^C@Foi2O%mBF~sEE@-PpC zC}M2FX6Xrl$|W0mEX6bI1g~a$mWNjbfb>)Vbd=kSmLj19Hw7#Y@c?4^`8ZGAJ#L5(c9b2J7~C}wg(vK!tV5+- zr32sr!p9V?TNe?E@M(bHq03mYf_Q`Qss3y*T0qr*9notJ+qkFWuI~N-h9Smgs2Bj3 z+5`F2GUc`u3;T5DS@F`~NpR*|0hEBd!usyd^yML>KYi4%tORR_T98w8uZO(g)PG8) z0ABDzJ2Idh7q>K)-Yj8Ir}7hhMnLw(N4oU4%-&*R_>U*k z3~_(V%t|;nM8L2=+c>@yc>)pV&5em|jgSC&o;dsSN>ZTch%~~a zIuHJ)f>-pSAov;lQupH?dC%W(P~Ir#EeJ183uDyH`Ipp3eDImwV3v+;e>+#2+s+Km zv-8DYVfw**1W~7u1e!Nb-=V!KcdM-!<-u7(=ibU zY`E%q+x<9Vk=Ahw{79+#I0ZTbYzoN;$xQ*e>-1jK9lVf}uYOEz76yEix8o8`00I1c zep;)72A=@w^R+L+xPV4S^c5ud?pS?D|ebX#-CO5Cy5^b%mt=an|(GSi&wgAc_$P@H_HTKX>b zvAdr}a1}tFEjIn0bAiDTv1dmM0fXe{2I*eJW(x_h4$;I&c+5cFk^yZoNH39TEr)cW zGmWhe110Aw?D7T5j1Y^DP%tLvHq%2aBEZKO6&TJhm_7-x5P_Ka89s-Ewu}rwQL+}v zsmZ(t5g-r_g;yk)m%4zH9dL545L{5g5CBa_h3P#xAEKe z4DU&Y5_;wLOQJ8p3W1=QDxQ-8aXo`GvyBjv$w|KnM|0FN9ott40euyA;g|=WgB1GC3Is(3Ud^p5HlehTGNu40$LB){y!`7v~ zW;je*gNqWh_$UAXtu6$>nDk`{dVCCw%^AjERVX));oOi`d(FBWH~ZYAgVteXory5_8_W*D19CeRbi1M=)vAvhT|znPVi78D-|;2@S)>ODc^yqn6p`2b&WdKd?PX+~&rvmGuW(VsA8~4;GGy zk>rWxb1?fXM4?<7-aq6?3fwXWe#SX35&OHBHMA5BwX!Vd%g|*{b}`ZS=(jp>7V1N- z&1I5Tzk907zW1uo(?;X_mz=Uw0*8mUhTc_ zu-n}2ee&6@QyF_1DP~YuSSYL&dto#$NLf?8MNX{KMrBcPLBD{bF2U)?=SDqnzAgjR zk6o8%LmYiBmsW~mo)0WIDOF>?na@AbD(5#huPpc9dbh!g;%TUHZAnVmciEZS-0R@) zX?&J^*v!(Qf4F0t*TZs_D+1fslM!1EG=P=x5)@Rt7je?U7*NosATP-X*EL*)E>_I3 zRIJ8EJ!;hPI~XjxPajjcmRhJL`^rYxnW&z-d0kX@{lXJ+2rZDmfqbYgbJ z!kp2rD_LQurB8Z#E76v#(PiuP&IZyurNLNBYs;I>Zf!Y0^|2Zpaz7L@zj1KrD^TP$ z7jT3ud_!#h9W8Muv83GF@4ZSW_X=L!qmPn^)X-(1?r;;hx|L(RKyu5%3V~0l@bnLnadnU`g|1(cq z;7n4@TM(7hvrekn{4klFqqikzGh}QJu9Pl zeohUaaOr*$thzq*~zD%be>Nvg3(6pwVcx%_0VL^mDxtl(^iS*4Ls)uv~id2_+E=)Kw* zQvFg$%^%ziMsfS29Ny~=!7ZHj2X|2JGDQES$oDZgk z-3$l_uvl|h`8}#ot)cjZjta@OE+89ob1quM&9^z#{%1d@2AcA5@^zILGDB^pC-X%N zyT4muY+f%I?;c6SEuv$qs8-jg>nVhIR=$x!lfNDA@9xaRV*j`WSnzntuG>aDO=Gyu z%9`MOA9V~E@2yg5U{#QU9Fa+kgo90qJ{o-Yvn-q1#VOr)Kc?rR&mG*1Mn1UW`a!uN ztjIb{OHYMDRY_&RD1SxTc;3Lmi$&Y3(bj#E>SrDD)Hx8ETi0R!B$U{2Mx{vUU<*6QZ}vNn?Ho?#{n|H@B{B&*AB#0SiLHNRmT%XkjTVV`(;8pAc#bl*zpb=SZ%a9X<_tQ?>gB{@%66w&Agu~z{r z{jY$@_xTSS+cYk#MqF3A@XbCre6ms-`)=v5YNCRD9x|%}%nCNHB$kZ6Hx#S-SFW{3 zzWZO_Se}Okgz>ilGhfcNAB)KNPpCi0p$?hfsP?sa2l6`O4??Zdzm=6*Df^NtLikw~IcIsl*ozZ(+`fn!J zRmJx+CWZGlHsX}$w``SV9DZMn@DBeQYke6x)(S3H^>mnCG7BAG7#-z~deW=cOdlc; zI7(C+&gQtPdE!oNTGUI0cfwWng_b?Y{!0nkpN5Xlo88-c=7-`&rgIVI> zDWj;<*&fX5A-a)`#x$^sp@>I$%4vM zpp4z-DVh;;Pp%O)r*p#XaVTrgMA`8-m#&wc)N2n^naHU$GbQnxJ@CIDI%6BtLNm4* zBQ$}QP!e{TIv)C9=Tgh$<(;Pmy-PIQXf^piTK2*yHi$%RWMsP;*r~}zjaXJjmr#pz z8P9JhFgCwBW03qpU6javQ1XQOmFg`=a$_!#eyutE`doi;T*8ALlr5ZWP z=N9d;?0c{#R9FC;b0Dz68(-mL;cC~)B-*?OCM!KV8$<(=aXV`$i ze{9xEuM=Qot+mIh^_Bf&hR(_&+28yl5D4@xx}%SmX*XJ0t;HxjqwVQ84faxX#Y#)0 z%EC4w^QyT+dZl{D!QihPXUqnzL8JMZaS8jQ<|(3K?Jw_Pcmpk%h&PNsGDiH3l9wFi zbvjV2ORyN?=ITkSOPPCxmGAoK6&SB8nbvSUE%* z0h~zOX^*-!Z0TrD)H^|XjhEp!?tT#eo_eR3lW{jX6Lrh*WNeoFv^$bAn2|T9h}K%s zb^P+{7DAMT&7gf`_M3l3ZELS~h&fL*vPk%Hbbo5Lt3QfybGX zm6_aCvSZ~NZjD?((?G@gdo;wDDeY2}a*<#_;bTZ^FJ*P~l`x*nk}gpQXH&X36)_`h zigK8@>dQ{HomXiEMw=5P*px<3ZqFH>vIFAdvC^inzaBq}ThUqZX4Ru0DK3BX;2@V} z6I_<}F=97Z&ft&J&}f_Rttrsb3=&wCOl5|? zT8OAEWVbDP>pNFAP%eRZ3hn&GvgA&!6#rWHD;LWoT+$$LN(2p{-kCW3- zS9i0ThrE1^;xp_;43b%+O{xsnZ={8^MKZ&Up7B4Jx>Dqxwz&O1C9~_lltwNDsXc=WeOl29%uyct>-KYIptVSm zbzh}Jftfz6)zWZyDfG8pfPhL`)LA?OfMR8JthqYU23ubO+ALcTS73O~8MiEHttmRq za|dM)r|(^Iy}43NS6cabDAlt=a0NZ+hX0wJ+!ZjlnLj;Z@A{!`%$35%U@Xwz8^s7! zR&;x&r&r)yey#rc^>!gxu`WfxOTof!@!F3c^Py(Nt)}d67|}wkta|Ez3{L%? z+GqLnn)TibKpub&q$5h~IC_wOmFa`Hbz@MWb(nSc!rA|tF7EV6tzylsT`k2VU3-{Z z7KuG}b3bp3?|Ji9QP-TsU+bIssK6ZY-zb#Am8N1@Fx8Q#=uKnYhRLjI7r%x33d)Y@%$FtLvl;fS ztXUJNE5)NMFa2&R5;7fMMgj*E7$59i;t6f(o$oJKmMIxAjG$I%xC)n;I$2wu?#{iu zC&I@Z<~>WXBH`D3y<&*(0;s^@bk`J=DM>f)=GiwdM?va;kf#odR-^Fhy>fQh3!q_i z?8$>k2VXo?h-BHl7dWRi$NW4DS+%v+S9i|ja16h_{CiUPuwWJ^n4!xSFeli-4$O1A ziogTb^}l6b&hBa9Ys=Bx^*D)RmcJM70D`nsl4pn18v<3N3ArM>&2L7wzm1NL))CL$@e-!Lt`gCEaDhhS z;n<$dqU6KdCyFi?-dzt32v^8wwdE%_GNst-APE}(v?XlS-&D!6Y#+oq@^?F3==*9h z3iRrK?As-aSJsL#$G?P&b!w6f=5SWIRhVEkZZ%z`E~&Pts*LdVJyE5bnkU8 z%khihf}qXR)(vgTRX?vL96QI_gEg~;ft(p(dXos zBR#lbHC*T-t6_9wyzF;gS3EEaK)bxB~$eT9WCq*bwnQ!+2cl=qx}TmL1!h2CK> zx0R&ok4b39x}LDeGAVj=L3c{`gH%88B0AGN9|^hs?r;L{miaxU0!@Rpqf?Jx(lLr9sT&PlYV>ZH!vzqDjU zx>6zqf`^uBt+^i*;QtO&0km4>C$pf2I1=Vr=QPoqk+b?O-l0aAUb=dLmgayaeCkMh zHG2=aA!7bk#_G+L1LKgE$zcN%u37pbn$|aS$m^^)BIwBlY*FuG=rY1(X!_Y@r|(5Y zJkkQ!JmOivi0~YRJuw%cAHCIU}o4Q$dr_(F+`r?F)AV7(-Gk{VF{qXlO7- z4ft)s&n2v0<-+R=x|x>2$sHQBBA{P^UJ>bfd(R-b?Jms=kzx^}JhQx5J*=pgsAbE@ zrvM8!t06v90ULZHb%$8>q<`2UoxhrRV62w|4cc%oV2(O~-8g1HXNo{3#;LzP3{G+du)9kMH3rlge z3W8ZkKZv)ez5LC64pv;DmF}!tnXK0;-uC#%La`xBah{{%{38FM2C@5?^*F(GrurY~{(adnYj9tJRRy4T@=%j=ImFWim>- z(mwFmr%d)fmE`$_L7RQ&tA#l8 zfTQPNkdh&|nLgH-TVQ8J-}%eTh`hTeO9jCM@i;lXlbg@9(gm8n1wMTpl0i9@_s(z9#2QOVbDAl~TBieVVez=kfEBZUk3z$B z5f=CwS4qCcF%0c3p#N+{ueqpva9_C#GxP3EV&w%;@Zf*8X@Og3C08gLd-!7l7#aM$ zrulAB5EVgvyfXd(u9l_=m1;;q?w@~bDRwOlSD;Z!rs8~pphOvMHD>4L;wa|Wsj%d4 z7tOnW|7$^6l)WH8gTGU2ygo>-j~irSezb4bk|RLtugR+b^2 z5=5p&cv~`FS75E-dPJ}%eqel`-;}D;_A9OJX{JIjds(lZQbMH)>uhxa;q~j`rb>O| zz<{~IwK7Rt2BO{go^2}_sMc1Y7TQ_9u3+{ zpDI$m3H*@93J?V^_FdjNTpZN5V;J^)u(~2r_w3i{3+%_=U3+-`xNZ7ljR>ZD+Mj}= ze`3G!#~aLdqFN%e6+S5?-d}o}vez%ZiJ?v+D6>TPOA^ztE;q4G|0;RpakrM;&@Fq( zSqkRdC!=LNQJ-TS+-S=*4-cwM4R7r~T;KccQ9G3!z51Q!jn}BZiYeE<27g({OLb=Y zarrtLcc#L7PMp5yWvf!ld+Q3){cz?--`#9dqkQ9KR#x=cp{4QUoKo>&sdDWv7ke;1 z@8yiY?ND4v!+IuLxQ|Y*JH|Ff^MDsXsPgUp6X5EAy=uQ>L-+Uu(%RUl7eiYybo$-H zUCc$A>-fEXe96a-bUa<_4-bZT>)7#lh%B%Xpsqmi!qa68#w zFDp3O_dYPBah1t0N7J?|?$5G6xbX}3i>SA~deho)1C<~szE9L(6x-zd_U7pH%<;ba zsFV(BLsi8qVAjA{jNx$ks8isRc*6ybcG6cqBD>Kqz0shRJ#|HeaSB%4SGTiCWKdinoKKK0JFZ^x3^3WJc!1 z$hFBKo}!DOsjy6%$$VUUv%p<$G3Y!|Dh>MG_H9&iu8@8}RrsEP*PQ(mH1wKGc713_ zJ4+0x*UW0AaA+fqY_7~TJq$aT%sSs+4^Z@ zW(8#$TtU?VwfjwYn+r}+N5?*M?leDEF|W0#`{~Q#z;VUzU!xr-A$k_|U;WoI#IT%O zpoMe0q?yBRbxz@ve&gw)D3nCH*EYJNu|}N35M0SDGF*_zf_^6OY1Q+=hx9#zOm~Cl zMN8jFp1`Ap^L;lXmYMRxpU`jy@z?BaVQNgrFC<(PJOA>Y&QM@LfQ_c8hW!X4Y34Zn z{g!=0AxgQz%6>yh^$7M=32Hqg;f{>JHJ%mSX6X})$tf*{d!&Cu z^<#VUb;7BRQm!Y<%E;&&i>A!vFx;ZP0zoER?R7-`tRkAOuLW7V@87Y|{}|jLDk`(6IgYcA)Fd!AKkuT=pV2^lfC5q8C&@8}4)@kN5I=4o^4=de6ErO}0`&%h7%%LpWynO&6Lhmu#UH z1@~IMZV2R?vejhq`x-iM58Qc0swKH0Tl5GYfSut^^p4gYTD##T_q)Rh-=x);TJnrB ze&6VzTA;z_^49K0cCf+8DURhe1h3~$s){l+(D?p7hb%(HB4eByelDe_3RY0iSW^+q z#qbgKBa~2Oa8=!XfPd(ki?}tYFJ!i{qzjC##B`Ty=4eO*%+gGAR)40MLeea>43#Lu z-I;ZjSPlbL!ac~XX7JuzM&{UTHxL^}jzCn{f?4pF?>1L<41kysL}gIN3M(6f@KL-!cGeTZzA*SVfvU{d6G0u9ZkmgwQT;4n|6^0;KiR?{BFX8u;S-%>*VIBkSmMDEmgEb)ZNLmdaL4QnVp zUGosGkut+V9^EGUX5|!~?;jx5vkJr4)2TmtX+M?r6&LNI*QPb^O=gt49_x##|I;l9 za39qYrEZl~-2TO3)4We)XBKriUa~&}-kbu^-DGr-ozsatYBe(buRyUD`;z(4VxA%V z2Nl5%B8s|u@=BfIrFB=blGf27e_Q%8P17tc3Y5Bg(O3Ssb?++m(9bbZ@Y}NkmIbqn zA$l?Mgg8c)=BIM1|F#3wp4kW2O~5?EBHo()-s$lys976QkfHnMIdZ8wov%~zO6}DM z_D9vDk9lH&##JooCbqCLY{xN{n2`1bXw4ID#eV2j{8A%mT8L5s1@bngyW>fz&oLzD zoB+q_Dpu~z`m_$7Qc&F{`2tlC#?!IkC$rCF zoYq4ge{{{z*FwK+Xe;!8!%i|5Q)V+(>j&_V{53ryip@>azCGEy_S9vu_f7rUmM$EP zXI!1Zxf=0nFypLtpg~IBV32MD&-dXdfmKLfh%&9xZ^dDsW;3XiR`0f^oZRPf?6>uO zftyajtds7aTfU+lSwV8W2!&m$kZ&a#Q z^B?WAEk&UJKy&d_;n)Cu8TPY8Jhp6oN^Ic3275uVik z8p@BR+c1BA$+iFS?stqaXxdZuA}|T8Zx87`b7uT8%ZJT{+M9-(wv3RR zDAKbBhE~SC0??G>=6LB*iyXS~b+rV@4fu=1#MU1-er*JXnWRYs z$|XyFF#fY!jfpS()p?WtnscoOZn_l~Imuv{)Zdgj6xLfcE-8@C)1XO3m9jS@!vWE5 z1EQgOKKc*2oPhea2)}P>_;v7lCVFu6^L~o?g%Gu!IG!F^p`-gDp7Sa7d59%-T=FQ%QqS$2A$nl&&(lo~+R}+iN)l zf>{c^xJ+7%b}UyRfssA^QB?PI+6!iAQWVo_ZB}FX(jM#mo?Rgonn9v=Gdm=B9z;O7 zA@0FbwEVYjVTA_T)>0I;MhhLP`TSoECAvf9iQgMRr{o>>o2TMuU!pSq$%?<}#H*ZP zRCKM)1!Mko7Mvqc!_!09ni95(4x5ah%vs$Ax;;tMy(Kgr_|FL*Ql0pOy&haVr{EN6 z9O_OWpVO)8BeMzuf+p$kd@?+V(Zy0L;eTASy)#CdS_fn2}C zuk=B|D`^@`--}0RZQfkvjGefBVlp}G?k_n|Soed#-N+&Rrag`@qojj->$d^6{&U zB##rKKhU%_YfD4p``)=HSr``*${{fxqmN)xZ z!U~!0l#EDj9;dptS$l8?9v;ySt|KMa%}$!K{S+Mjy6(X+*!O!(efA{Moybsqpv%^!F%%;-nD%uUeL z@6X%1&ql-Uw4;Bmto!`s`wDqRX=n#`l#8+&D(JRU#falDHGILa*&SnseFjlL(CEup z5))Si1Ca38A-tYj7r64cthUeEIUO7oNNM*&dxUMk+`8qT&_mz5P4ST?Z6i{`=lw0xp(PaaCNUb&#HIw+ei;W(a6(Syj z*)pukKe)r$;LqT+BP;|fGw|@%a60(z_}L5#8FZW3dB5x8MZfnLBN@Kyjf#a*UgjIO zF?p31G9+{PQH#H$am&xcS+}A~UTX`(YugUIO*P&HzgAGD{qBoIh?jCi z)sU)_$0kXV$3W}AB}4NPG9A3SX*kx?uu37m+j+PC%`SZRws8MByZ$P+F_uSaK$P%{1Z2p{nzw?8oB|&tE%o;fm42Cl?;K^PBcK=9uv(t5{W=IrGP}yWd{98Q=aA ziR6sVnYzBR@hMg_c_YGgv|2pdiAyPTIKo1S_3?t4LW2dD?v)_)$A``--m29%ikx38 zd>y?Wu+q9)-sk!7-)3iecA6!(Up0}3 zDT~j5?%UfuQCc$&b^0G)_%X7`zWw{JlD)mHnY>9`mcQIT(;kXjE2DVjsLY=z2o${P ztWJn4*5UiuC9Zo|CINm?&f3o^pL1b*<||i%=_^Ke^AqOX#*ap+CvN>Ovc5YUuC9Aq zo)l6LX+)HeL`y;#eUuQ15G8s@kPxF2W%QP+M2R3WdWqg5dKn~IbTXJ|qlLj3qqkAM zeMa8*eSX*Xr|Yu!Ugci*T5F#<>zKjWh_<1qMAX(}7}nMw)KVVpMXbP`rG~Zr+xA|g z?8U5KVn26&#o1knP`krx23N!OaNaNHZ+dX_M!VWmI}?_--}lNN2wL}SV=8@D;?Fg_x9LvjFAY%4a@pqH@SNDU?J-?p}eD`Jnoq9UqM&uX{2 zMCM=SL_FPAPSUtJxj1|^-Rk_Q)ie(E{;90mdW{o!+46T~(fkcvI@56piT(d{ISFdE zKl7=4S<%9*{8p|!^sw!AFx1=z7)1uuIT^CV#NW=-{P8#gS3fcE!0jvUU1}uJtyoL~ z;e(jA?|4$i3UVsX!~h*A(TDgL-;En@)g%_OetEnVPxqu*jx+o#s~Pr8_~!4?Xt^AX z??2{`Fh>dfYB`c}e%E4GKT@-tJjUVU?RA{KzkmF*lSgUhe&%>4$s_H}Th#F)dYx0x zVe0*fuJk~jfP{PRlWzSE^W7dPc$TgEJv^eVe0d2OP>~<`jWujNA-a91x81jl6?)YA zSDv{c}asoaBjjAg}hc9zXIpPEbt1&c{dp8{G_UJ?~RdhD|R3}gWhpo!G{Y#aJ4 z_esOh1H8jd`%y2K{X;BH@fIf~5PO5|`=U;bE=<6+T`p80>_qQ8W7-?0|7S06^lF|+ z|B&r-p^M_m1EHqz7hdAUnRsc(pXR*W#URf)9d;1wF%TBu+a6e9-#NzpiT`$c*Y)+C zsAAFGDmvvxDZ0-K8>;=cOxUUr>Y{_P(C^RQ|Kj|)p0@Nln%)Gm&DjUyzH7`sZoScL zb&(o`ug7k|V70}NZGIjAxubT@S#tCo!;r-Kn_H)P?8?H`GLmil3oloOq;q2*LdTH`)&WtTsi%BDLuLP)$S%0oVzB*mK~54?cb(e2o8|iC z%!K|8!}6fDPyQkK*VN72Hp4I2bg*6Y%eh_(&_txwmF(#%3W1{xWIa$=+{F!>c_P6 ziMh$z?e$Kq7B`nbUSc3}o$);z>A$>LKf23h5WA{1 zuO-!v`rAbnY>v1%Mj=&Go-1m{%f2+(69Nq}{q6_$pA#E3WRYTKQ@7pCi%%+C4jWkW zq}ep5F096&j8PRfaBvB^#&r-=`^z z-!GWilwrZ%{Xxk0&EP!44iU!?AQ+poB|Xoso@G-wxth90Oo{vv@42x=m^A;|zfdQL zM{~}}WQ)ZsKh1p-TxBoP^g+z?Sx_Lh1c%#$XxJs@f}ChX(?+ciRm5bf+vJ}!orZf% za!m3d>#!lCvF$qou(s0Irx`RzOO&i|(@A`B7b~AEg6J{BK714hH z*h8hy;b~ zkpn1-G&ZNhHy^RHHi5Z+t`6HfW-NwJzIVV~52Yp9P=B%0fUQI$_KGNB?RgN^55x@! zzL=%mY~p2f(`qQdiwf6a2rtIr8XxYLGYQa+FU}u9a5rf%wa1)4%J5RONQ(v2(@JJH zahTHF+4eN-%_D#*4Nkwsbn17U52x0EC-YqVOa4~@ScQ4b9>c~%NZZzE|Iv+rg2cs>#AZ&Aj;P@ez#Fa{YM za&BoOqieij`KZ(*>v|0+CyeZM56kX%uoMhXqPw0F-J-|gQ$k-GclHvC0_t&FS&gSTYNY5jDURaT6R}F0* z3A=Fe{?#Wx`DYR+vYci3L;Y>Dr;Oed)HWb@yX~i{g9qA_{PdQkxrGswMOdVbBA`CD z182p4JW;>M=yUp<4K>GYg>JjD@h_McEar+vTGnzuoCGDG)Omq?sU>o1>ev|1QQKt& zLMd;=)O5Vg&d5;4SKLAaexy_T63LZsHrarG;%QFcz%jA?)2s#>Nrx|$CZW$Il zE!M7UnR@R=Se5W{Awk)D=KYz3SfkIjpSEGMCr#ksDroK00o_FE!E5%LIZfcy(r4ar z493&_$~qURIke2&T%diiKg4Ymf9eHAg5v|D;$VZlF}n zrFF8)Ks4f>lTCxOY#^c}xW@U!x06*+`8OwOaAZJ*d33+&5R~jf8qKO*x2_zKqXEI< zR{X$urw(4}Rw__)t-*yE{P+2T0{NM@9Mc~8GR?Lvb+T{!hPQa=Yi*&5v|2rd2~%)R zjz;4Tm9rs*LPFEXKPL%Qftn}G1-$*V@c9j4RZ*fNl3c!mvH=x=f>73sJaM0^y4)50 zR~}u!VAiSin=Lt`-)C2%9p>ZDdwG!glg>pF{hr4Y#8FG(CcLP{%cb>zd%6}W+!MkO z&h8=^uh-Gza&G$!!hTGWPRf2|-%57W^sRh8yVF?_sGdyIzWu`~x#TwKmnXngtgEiW zpN2D%HSCG55t;p&QYqwP;c3ADXw)bnQO?Qch@yHz zKS(=yQWw&MpD;@G-%YF~@#i2jh=Oj{rgRCcjY=c7Wp zr(NBq&D-javV6`r1@*6q&*eSuo|t|UvaO8H={Mq)<-zK9xR(H*arg^F!(JO-u8`^9 zG;|%Jg3m&|r+1b-dZEILfq05RF6%>mnD54UP%N=XP!f70HcGQ}GW=S_%lVnjnOh*9 zQh|}e4vfUe%~?CTv`Y#kUS8EUur3A?{j%gqOCXr1NT0uX|C)4g*s00x;UfrUQ>J;6 zXZ1$+H?pgYM{QfQOkLKBUdq`ahlB^cIi}w(ti1jl&s6_i_iU8rp_Vs{8~ldda3E5T z(KXH&tkf%c$E<+=$S}Nv;}++F^pn?6>HZvYrax3T2^xbA82+6S_(qQeXt8achj`%0{_N;sR#RkNESC=7?!x>Xu3xa?o#WxpmZ2ydC?Vf{Q1-a>U0x)ahP02&EHQ=C*s7d9@{@jbJkgtU3A6{{9bYa_R|agcsYVkv4~51( z`q2T;f%ZGQ!CW#Jt(L5R(-b7Ktfdp*yl1%y9`vhf0HO+h0hgl|7uR+%7TT@i>z(>> zlCBqtq4X4Dq?OMrQtEn8m2V0^0YsoV5JAR(AiLu2n@D6Sc2MSpx@|$xS1OXnZ<@e= zeX1$L-~~))C;B!ERW%A)y=bS7-7?(00=vmgSH$mG_tf?+ift^DR=2A zC(}>F!<+Qu>mxeiq4LIDw($N>50%Ha^STzBTFj2fF(s0O1Mi)b>bhIrZ$A)i|a1t0pskJfv@cw|ZaW zOkq7hY1bF|Jl}EhUNG@;v4aW1x!iB~_60en2_S=8g8%ar^8R_(9V)0Y!N7A~L=N^~ zFEGGv8%qXylmx%d<4Px-r?lP3)gzDqa}oweD)w&pZ06nhoEtI`0^07?aqeyd=-PwL zR`c{bRG9rRU#^TBO;I0k)=(#fP!cS0Bo; zmSQRD&x_O)_udow#BcQ0l#LYGoan#vR2H;wEH)y7G6o8Ks9VJ_=5je-^$S4 z2$55a$Hpb;if1JZpd8J)ZEJAEd-hz7lLcLe)kQ_dE|aZa)HJV7L##1#^e#NTX{AJDN@q&HP}bF$J|O@H&?+&x_39VrZ(RgwjWfj@l;GmJ{1aimo3>CJ1p>m$ zafObOmsjO?E;rPdxJV54HG4h)7ijU6DtzX8h1}^KYS{T9ISVInE0byv8fNf^J?}2Q zOiwTTzT5q4XG>FM#M1mgbM&Zk^QC)k>6FMH4L#s?gAP8xvzZ}u&C+)tEI&2`PlOm4 zr0H+IdV`;^CTBb>h+Lemx-O1f5b7Ufg>EwxyOi2x-WlL+@!*CEH%_5VV>Jb%+08w6 zR4S3D_;}CW)HeCyP1^As7ay7kRKZ?p%)4EH(8_ z;~Dg*dW}_&3tX|&>CcSKjCU4#3GSspfPlvR7@3@qOUPI)qu!NWpKFrH ^3+!#hz z<%~qRtW{pmd#)6kdzEYQ!^0EDNnZp$$YeWr<$80=3)kmWSIU7$xaR--A3$E6^}K zmFA$r^Oe+84}BbFz{}wF7atVOv#&@c(y+dIY>JpuDJ~WlyHeG%Kl*!6Gmkk(P?tV_ z|8bm?2NBE+-I;ab^GU4Vpq@hW=7Xs*YO{x}xq}LG7n~KNcs>fOKf49w@EdAre^=mo zb6r>#mQ{o|{^wybj*S|P;j%!J?f3t)1FoZ;O%=1+)6H6r)D3RL1sik} ze)mRab^WQpPUXbTHECrxDdGi*L4{?BGehdq8P{Wn96MS6lo_7NGRm<^lg)q;atw@T zbEI)z`0CmgZ}2KP72SI=Ez{ieFzFWtt~WafvRw(7t!N{Sj|j)kx1IIyxP0P*Sdo-{ zbCmK76IGqyX@5E@s_Hg{nDo)smFn}7N6PXIvMka@b^gRv52*Uu$toeI<~|`ZB!g0T zR)uiWUor%$b5F{;>*PP`B0sBrLRQF0)@t*P*EjB&Gf_8PvvOF#;=xP-ztkV|MC{uN zOYg04|KghJBvOKOh8V6=lLhI>@62)R+YRf_`fz7zsxh|!3MM){_booAC!QL4`PdwC zM{g|ZBkS185WFf|*HpEHTVCL9rv!R^`kJ)Qdfc)Udrj@dn%}RL&t<_!dS*+`R@&RT zm$N&toUcV*0vb_`@xWk>4tMDjj4;ZzIn9YO1?K$Kxg)y@ofX~g&4W+L1;mB0G<_M3 zoTf(f3Bw~)JXPXg8pjxGk!8$Y&PENJU==<_eqwFa36-;M~SjIp*QRC*u!O@l;SGvBi-EGAy@W z%+LkjD`B=KHoW4*|LLG}rX{IH7ueAj=;Y|W&Ncn8*XtxO)2Qdeua`UJx<5K(9cLlp zY*kSJBV0F_b?wW_(Y%m5j@$bhq*bteP|I3O{IFsg;P13m(I2|vup4; z0qdIJVI;6OkDS6m(Mn=+XkC7y6m##7~$Rfzzm(gcH)@VVr-6J z2S&1KLr^zGfmMrKBWr<_2| z^2)fR57OpowM2T!*^>}y^)=?lm?8(@c*PP$$Yh+;t6drhEue+9? zT7V%6RzC`37JP*CY+O_kN;7O!w<{Wx!EA)`wr}%=Cc})Chf|*&_(NJEE^N6{FW)YU zxtTc!ONXQlciNsMFs`A^`G0yAeCOlS_%hH^s#Xx+?QPu_lNifqz$awCeB}u@kl{s! z;HAC3AH&6a^Wpx^R_=16(w=Je)yOpQg+EVbek^}8S-}WfGZtAbi5?#Tz$}A+$>Ox} z#d4b#c5>t;gTaDpA5)HHud7I#lOgW6wktx};fX|~3;s(y+IyFLR<<{)!&YQYWUUG& z>9mo(U^Hu;EuEja$!)xYK;vCO_MqAcLS-@Qfu9mv1Guj3n)`ey!W;E=`lLXpOcVaS zLX00lnHXGeD(RM{@^gd|NS(tcvw=}FcOO1y>U$YRIdgwZ)G5BG-81?)vpoH2I$hGS z(KR?`Bb_^8w-Dz>2x5~$r;|xWeO9$O(~k^a_dP01uYbe{j(>Oor-F$;?!7R{{%bJM z-5c+lfbBA><+%<%+#-*UQu{=9KuI>PD$iW_uMdQZJR^j?bKPj;Uol)9ZbP-Kzu3G} zU4YFeW*UX`p_tfbk?|3wuIt)4x@&y`KKD*KVX~Xfqss0WLR9cj6p_y3Sh?}%8;_Djhlt}b|fCaibj@hq!OfUhK5RPG8lO^#R$0B&y=tA+dO-agOD@LJ!=3u)3uoP z`R*Fi7gHb`WH%MYgcSA|mX*KADaYMmuT}(hXgoxsw+Dcwx;@|yQ!QrRo>%O&AU0Ij ztn@m0j7MRk@J0{`rhS;IvHhhzLq~Oc>n;Q?aiJo55btHl@LL9J20GjqrtR8X-ATx; zxlbR3F9D^T?2Sj~OLGr{t$E%phFN5OZp-!XqfA zPJ1z9FFZ)^gX$lqLf0Lp|L$0U7QNy&(NsJU# zW;V0!MnZIJ6(;82>|k24(ds0tqcRDVA&&3mp=b*C+*h=W@eu^k)E3l}i7ghEy(D?p zlN=~2T4shw)`Iq{R>!GKb_jY;Z*HgVwME8m7NBl zY;i6F%a305u_C~n#qBC9MOrZnDyQ(twuVDJ)9Y$8(Ck4f>Zgc$Y?O~4yYFK0MEM!X z+51k7_lurb#)L51TP1_>KvNee&c58WBCA?7Uj#tu5$+^e@mmYc?5}oF2xekLiO^gFza0|i5$v$;Itf+YU_rTH$O7}X1ymj5X!cq`&+OYLXqN zM!gN)qOI7dEH2CvZj%Ri0K!wj!0mZ*pHJCm|9pu-uR=L^m8WTAF%Pf^{wa~ST9w@t)y+$?lvOgr`FBFXyr4q-(zL&ai4Qcf zOLhvqK|%vs$!>HOaz06wG(1u52CRLr>-?3rmF8tBUmoX^_qy7JaW)o(V%JZyuD~}Z zF3P%fDr%gQgz#HOevXK-5GffX&2^NC0)9_Py}lvCUuw+-sxYwIjW&5Ps@wW&AlZ7t zoRaU{@}ShD>4P`VZ-_g0dM-}`;^-51J`VQsdmX@;u@+U+nc%DBzHkT6qM-&#cN3B~ z79_7@R1ZxY(ln2cP*J5tnhluZ$mBb&V=uH*?&s_-jLGrY0~blV+k;G>|Czl*9#Rx* z%5`%c0m7rZ@xdifsH#bR{MOFsX~w!vP4(jQMESvHrihI7qWRdy-nVw&XU=cv5p}gr zj$G8A`F!c;x1FDqS*&jMh;)~ntUez-`SK6SE7~|9g$F<-sllz4s*dA6 zX4T%2goUJfBsh&v@3j*FICsh)LQT0Jz_aXfP~3u%p*H%0zna81&`YS~nJ~Y#J46+! zS6x=iUU`VBb$S8dfLZb%|BN$tLFziM$LU_wErE@is>ro)1}Z=x01ix_+LGu{MXt^@ zJ_w3C8Snh%RH><~QgQUvlWPVd{Oi}ji{?~389X4dMh3U7?8M^8TFG}_h_|Z{m(nj( z!M=41ij4(@n{9oCW*yhXx2RZ&&Vi2UWW3{ZGu-vAT{l72lOz97@f3)+ee0$L_0>k~ zfbrYVy75Aj8*7L@Hv8;yY_gLbs0FH-G|v4M>$b)ps7B;Y@Rqau^tMyNB<|x?t&fO^ z#@Hnjn|J*GP(^Az37LepJHe&%OL(^uwRWd$Y_TCKNO#*%C*?lwhI1#aI|%?nhiwCr zi?yx2_?B2+MOLX%m75YsFG`9{Pp|*Fq4jBsXfpV%TaL=_S5V_&CaQZsP|{DTcaSr5 zENn0>^Xjav0bbz2*gx;5Z*+;c4UY15fc>a&9V%8Lke-+vMuC>Mbdn|@6068cIln)r z-*Be=u??DAvkIaqJarQr0(U!f|1{NcoXY!*<o< zaHO)?2W`$kD$#)_vc2ZE?Yi~ZXQ<}YJxdJS0qSWb&GxlLm*~FlJsL0(?OA$p8Me~7 zg;0%Hb+Ll{xMOc}%A@-6Oyd5Oafu}}DNgU2ImWSMA1`;f~pp+C}C$QN~3z0tSai!%7bhYK5<41!! zVJ!%E2#lB2?gxkO+f6e{GOwCV8!mfmD!1C-WCm;N_D`F3Pmai=)tcc`efsvysDYnV zhyNZNwb=)!BKKLAA!|SLz8i~Q9?=w?ibTV}I;!dqW|%dbl(zSU-%zfdIm=t_ys%hL zS1PKx^JqX}XZELA{dNUmA?jhmvB75Grs7XrR4Zknt*$7`>Z)7W!^Kc{GficoA|;6} zODZZ)2Fg0$n{7CT-}Kk3P{tO&NiFSF)70A!oFhKIa-{*Q{TNT0vD*psk&tFM!GfQO z#tBhHs;vXdAo_ZFJ-{5uYd!))Kv!9h_)?$BgzJ#d^`fd*R=`|FU?>wr`quLu-_0n$*uefB$D4dtda5L~9#DetEtwDeg8xHy@RaCF!bZ9KSKr25MWLsl zQj%&@AbGx?7`2VgcWuoH?|6>DPf4x+PwG7$@;vLy5rPZ6vMPqp&A+;?R5~r!W;z~f z+n-W{OxdzYaID~v7QhlI&^Rnj!3dN{frqTL1s$ z7NG$zhor?(PYw0LK|;=euod+vYIhu*T!oIa>L#>S-!bCB=W0WfU6bhkD{)X2(LUU< zf5mF#=El#ee=YT14Xv|V^E8wmZb!phezX@`G9M*@sd-?Y9q2*Sn~bB|c5zcSU~sMB z(RlYV0FHBzlR16Y=;{`p!&JNORWc>Ewi>=pSIVBe2Cd7r=_bvR*zC@=;?WNztSfMl z*W3T6Yq&b@(C_$%E@hvyhlp+&^KYU=c-_sRb-$Azt^@CYFleu~_L_<-d6HL#{|SW< zMa}bDY3vNxkT?oHXa1KyiE zd!T8gw5Q_OlnG5`Z9*1BW^HAC-dI=2!hWott^qDV>L7= z?*1OGIzYlPY&z)56tz5>#9ToEk}(qI)ggl~f>4b~6I|gQ)m56o-{FlN7{|0V1Sa~& zZ^+w;6i{z9!l`8W-z6pH&_gjAG@iU9tIW?>JOP5-7;mX+Ij-V0h!Guf5?)s@z`3OHb19biC6G)mDT2 z{;3nu5Ql9mKpfUiGP5Spc(KDUOJ55bZ8%p#CH%NVNE7kk=sHhRgd}_7jE5+1nQO;* zT3m^NeJQ>?mpB4^_5ku(>yA+=2YT@dM*$>a+wf$i|=+nTN4;tn#-{7clVmsbj5 z;L9*hgxbe*009EVVN1OWVx;H;zduGDBs>B9`WjJ)Qm zwy#8kCvb8tLd|9IG@i+-8ze(Q}ti#3BnA6)tzfU zM-5d?`^k4>Rx}B!PMS5U)lPuPDZooMu0FhIn>&w?>1m-<84{UXA|A#95Le)$U8>S* zhi~>;-6ci7w$juUwLWV32P!by$lHwPspuxlgjPc9_6sm}v-sHSB@^Ure0S?;XSxy& zDh{dEf2vd(tB6P*NY5GR?QUdMWSJuWnZi|PAg+>UZ_@?VuSKDnxD{iJp`@Mg=CTMc zFMfM;mwmp^-Tq3m>%H-^m>dPolneQTH#|?_$-cbmQiaX13s?CKky?>wnO^VAU-kQW zT{qEuF(`V6;9TzqY9zmOAy|mwospYdTkH7}agi#sUDRxzWuV8_bO)e+>C*yo_E@4m zu4CTdbwmwda5{meFV9=xkl*UqN`|6*s*ORvU9ClT)#5SMLqE^eI3I0IMP+8$y03a@ z>_g2o#IlLV!JE=IGP30t)f^bKG=u-M9;HOz7TD>Zu_X$k@uZycr{cWSWr-Hq5_Bx+ zB{Qpm?zh$5LGoYRXjhr+xm}b~cw^r>Wdt4|2vRX*z2BE$7&qbG5tEPhq?r2OcHom4 z*1T_4c1ob&;Zd9diS+3971DdxBYOk8CfVPWj1jnNGB;%1SW}s|H^BzCO^g4f1ZVme z+u$mvPuLX@_>rj>_qmVy)f-HCFNM~P5}+VMWt{-b7Bba`Ts=tR=7?YQjwvhSmNgx4 z{ADBE*pZ0DX<2U)xOtM`1Ch`3Fn*&5oGt>xOl{qdXj{QnwUi2G574N-kk&vOYVROc~n zk4I`NM8hKAAxXZp-cEcJ#1|}4fN;*uVXFt>|LkKXJ5;!L6WZZ_SZ~1^na)?=fwZ1C z%+Z-`_J1o$1SFbpRJx!)+jLlZCe4-hzst37O@J-tHY!1ARKswzFfG>91D-#8E5Z(c z)-aBC1yB|F>=!1?g8NEZ1(cir9{m8PN21wjY8(LCxchyu5a)%5aliZiRikZx- zj4uUQ>&<1`(vk$d*qyueJD4ojvs6i^C_dwx1~lpS+?^YpZ->X?cu60p7`2--$5^3S zZ0vITm#VFje1XnoV0X`O6HQjrnjbv-7a^8veF%}ocb^qHKX6+C9;vvCdZCx{M&Mb5 znRrP4vD@t`^_Utqdj#l%q?NWVCMFoWsKZ-*??Ffxq9FZin0pI6Wj6aXVB$=SrDsO< zgHL+R+iPdR`r9yVoo;{fTZ#fWo3gcq)I_mGP^2H|{%ZFlBl=2AyNcxOhO=0rTSm1t zlGO|cje@44Yf>>#D{z*UX)ANb&yR1ZbmgeZ^mZ6C{_Er}_e-PzuA&`#iHcqjq=@PG z75=x?l3e=AI9|#g4ei2GM8Xn+YbA65vjT;gdCoHSB?OxT+s!)x&;@Yi$amK}W~)_A z#V_YKo{Rc;P#lOSWuMr7QTwnAv#vJq-qx_K-C!$@Lb3;T103nDC>({dbQ{EW%qvf` zu5_k75Bgh8ieH9VN}zwOZQcNZy3+J2!MHz2kXRE;Az2FSp8Ecwte@)0=XaK2{@Gsb zgcEt7gfzT>jmG;uUQiBQn2LcRLk5*ra`PnYa z95>_Qa}(4yXNDv_xS{3Zw_q6Jj=@S!p=QkkhGmzom2DL{#x3iis^e5Ib|?h-sGa49j@ppma3#+I8Xr_M80(C3i;_8E-@O^E7d%twS2sN^_x38EU=%_Jx zp~grTa{>FAe@VVkZ4Q=O>P4~HAqo;VYag_nGu2+CgM#M83y%Bj3m4{)a2&5aSK5~h zeBZ+Slq$qG%>_`%|L|_{To1K40mE!rBn=HjfufAY*7Oe=T1*Q9QJr5H&2oLJ>PS__ z@BX!g`9Fqk|5ls?!j1O^3E={UU<5*fXU^kv4HXZ_j;{R+#z%d0wBvlWDek_ql6qIp zi2l^SH+T%L0~LkuX7qvlm(6#C6q%~s%mXf9z~O)`{&@e#>c?Rim&f}X*tZ~B#x`}J zq*ktj;|5yag2jg&i!nC-S#28n@aKEMni@rDafc~I^eX1-Q{>H~AlQ^=*Yw}vME(QU zab5TQan_zApUUFEvzNhW02r1urU(<|gL;bP5zewUBazJ>lKiI?T0^;t8^c*J1sUCr z0vGUAq{z z)WOHqBtov()^AGJ%h9~NJ#qQX^8i!N{ry_LEOFfLPu&6aDzZZ#+^k2l8$L}{yAQXo zr7mcSCFaYqAER32c7*zXmx<`Zq4B6$lWxq~=JJcCl{cG1Q95bua4_qh%J2Qt^jV9f zflc`fz#XyD=d5)&=EI^Lq)Fge;^4vhGTb5L3r~@L%Z!^VbV^V3b$8x@mA6CUi-$Z) z%5^`vM|-9IHrAEXp&^^f`e2sS{-OGEa|57-*^N=pU6G|owe2M@4VQCW?7 zKN)9r$WiLQ?4?GgfTJ1s8`h3Rc?Glv2@^Et3BPH?oYU0dhb{_S`-)_)y-&S8H& zRQw(yy=U=B#QT@>Qj*>|UX`4n)62iZjp2P9je@__j}WLXl?Kh6Yi7 zOw@tB`bucu`vC>$Az@R`Em)M!6eYFQ>1T}e$4))bPjJtWifvTS{EbXCblkP*7*2W z?100sLk^E|!?V5!{1D?b-H3|bsl@>msZ^yGRMj1*~pz5g-l?XCk8 zb_qKBVC`lLeC+e1VN1M%?C=x!43@O)>~rnal>0^TqVi}lJwQuP4{fe*UwUG^+lS3{ z0tDE7y#+w3B1?~lfzppYqqrCk8`63B!}g4HXtJ}%4h)6@HLn!bOESou6oUuL{qX_( z6OvFma;CuSY;9v6`by~C3$pLG6rf&pis$W9zBZvf$|dDo{)pAw+Ju2SWbX%s13aIJ zVd(Nu$l`_+i#HTFSOb(kb;yV>HEQR=@hY~pJMTZ_X{d!1pX-<~!ad2t5}`C%W1#c4 zKE-bMH|SG8pm1zvBl3y@p%Q@v5b=7kYBp|+Ag4ygK+t)2J6OmI4AOgET-pSy^lJmXtYkc=E$4r98@GP zo+Frz{{E@{44o&Go4vG9k&D2 zg9~}4RcH96<|5Y)Oq5P{_M>L4(pohDAiz_?6aZbZpL7AzTm7l<@eikHb{wR>5dUXqNER@^Zgmx9i*9ms!lWyzz?pDR1{q$d-5ngDAyq8V^;q&twJ#fyu zAyQaJ8J(i<)@>1}*~wjHjw7UV(D`crHvjehOQ?ap-yv0tQ1J4`i?LIEDF~=q3B4bJ z%EC(bc}aeBZ@x|F(9N0XIZ*%XzoqAG1b0o_sl{hqrwxx#-PfYTuOs6I4$diZ!4-bV z5?nolNI5-{cjCW{2X1>DyD{`)dQ0<$E9X$6Rhnk{M1hg=WLE~N%c_(hynhkU9;Zmh zy?j6wR)4C$)i4f?sBO@{r8IF=+#QHJ``hDOdmU)4ni~0k-vTJ9BR``$Jv%OwrQ$VuK5<>R6~7 z{HsR0J?;>%rKsagyq1Wgk=|&k&Qj(Yf^fiNa;f2jHOG7eY(s79l?un_*6i)o#=0sR z;6>7I2sKsnv@M`P&ZCHQxqTIE!~>M;sXc8PId+ns|NeR4Mn4b1hzmu5?{hIKo(ZS0)g!Q$vtBX)~*61fbIeyC~f+SFjp7} z;H^ZRNReHGQBk^$k_q2-ku2DC2+Vl0&(NW|rHc3DG1etC3`X14<&2bwY^1NT{}-a_ zWZP8?z_gQf&m|k2L?SU)e$!d{J;4*A#0ZEIJEV35y}lFs9*tnmqTIm*js@Mft=R|9 zZx-o=V6@wYH}Mo5Y_fFe33u#!LkOOX|6QFsu~2=b#uX^>{y>SRB-we4xBVr>Pa=z2 z9f;cSNCl_c-e&F{UgF^v*Z> zk+>lTsrbBYvzQtr_{I02Od#?Q_+9;^h^&6}Z|7+I745sn3i;)I1LzOwO$H)qp&x~F z8eC!co}@Q1kb0K&ahbdQgWeEhRn3mK$SeQb;7W`hkU_tnII+BQL~Y-K9Gn4bXDs>8 z2B}vaHYa9}ezUVOoRVg_fIQ6p<6C~Z`3QJ(u2kIwjM}oGMi=vc%~Cj`NPRf?ooAb% zZ6ebZTqyU>F8CMlDq#T4;>;f!fAV40_sIBBr@9oou{)3ACCc)lU*sRy;kD1NBZM=t zb4vq)t(>nPF(%8}O2(Q>8b889qYyY#L>L%Od0b17mh34+#*RA0+#R|6h6X=)@m)W7 zSa_OdzX{v1CYAxbVFp8_2Ww#Yz_&!7sln?ILp$KB3`mtgBecQ?BBfXWa z=xO9(QoWT&=0JN2uyf%V!av}JqnSK}iJ=K5faab*wRn#LD`+-uSgE9gZ@wP5gNw5+ z6?5gUJAAmCXxM*Pd8Eu5fMLif#E*}_5Vb)$y_i5`psKUGjC=wz&$?Uja!k(B5t$=K=Nn$bAfkD!L!k#3A zM5P9C? z^5pEPmAkfvuPNT>uaofa66n%+Zb;y(<=`x5Rv(gs+qMz)|0RHitUlxKbDXa*lN@yP z$JzwFJxqe#;0cQx*C1339^!np(!&wz?-?M8yUKBISai-xEtd>ld;V+0O!nN9HbD(w zLVj4csuqE7)i1qBB7Nm8lGXs`YR+P+FuA)72BRq`B=R#P=}m9WFQJf8qidB3?YbCk zr{^QkYZ4DA2v_+|fG+MNGgc|!VD4?CH-#w2(TY)dt4Ye2MTl?TXvAss*7 zF=So6Jxgn}zkFfkE^Q${c-KKefxh#9>bla*HQiCr<$l*60?=Fag@WGRF6M&SM~sD6 zw_P2b{l<;hIZX`x*?y(lK1J=Ffw_>E7#AA---2W@)Qm+W*c(vZs56( zp*yDY)~7&0Of`=Hy&cuV96-~l=r7I&e$psle8r)&@}uMD4#q`}%S7kFv-tmeY>c(4 zoneFK1Ph3oq}cS+3s(+C#%CpG;t z^=*W;nbiTiM8d9IppOoJGo)uRT*1!>HCfc0vDw^)?MM3Pc!n{RJTaFbTAooYUbqWF zo}&b!zEqzcmAnU!&Vax^pOBFFNH19=JN6hhg7=;0VFI7CKjtUV>0)Y~|5ues>6j*g zFrrjbxfg30w#suM!u;Yk`izb~khb3#m@pt9SRB8&H6^h}sI9$+aU)0?&^)@q{Dx_W zZQj+MSpHuExPKhh#3pId9S^&kB*YeO@<_^^~` z9@CXqO=Q0&a;z|$%#k;z8LrJ0xjUgfyU+`*Ya8<$e5*PC#H%%L=Rj|qgbOl!-_{6+1)C^?(KDbB* zPz0!^2l#i88ZOIUZgDJYUT-<$T_Yb%!;xeujN6YnJ+UlO;eBkX({mJ!B|jhGKZZWB zn|)g`(VRk#pJ=+TpWJCKI=Mrlmo>oZFLR{W?O1svU9`y0^Zb|M1}jaKZ_YEw)n+fw ztkRemzEe?2hm9P*79>@a|7|Vqo?T*2=5dZXptomljLR@rgCCQ9f_R1ZsQ1QpQdjTE zBD>NZTC&bdwG31ADT=RO#!YWUIC*WA72J9(+*V;0+vIs;&ST(?Ukw`{K?LH&a07@F zHBLfYpsV2IBGuqi`zqiOmg6wTy=qqV59WsA_*{a`TbC$Z^#{Qz)=a166(E17_NQ(T zEBrFMbjUU>@f$Us1+sl|qo2($0@cyqZhySm-v(aC1Ycgd5j3_sa~swmCSdeK!d&m3 ztmM6y^bSZw(yV>~aE@(QFPLW7L+5E`Sf|Xbv^X#c`w~x=5`bhC5{mB-j28f=Bk)~n zwA599JF~)I`i9>2pSg57AOhFr8L1g-qKG3NO~MgUoqt`L(tjscV6bNtC{qs|t-zl0 z6DH;B_|D$AT9`O4jKn+@HJ(v0=R_q)7J~5Q9AwL)BU;2KS!eP33pchlq@mcG;t1)D|iE$ z+_b3iA3(vLy9vlB>OPr2IU~3Q@@Y;l8jI>$rO9Zg0=#K(oAnCD0jP6o;C zu&YWY=r@qU#c2vhG8C!BrP(H883o4UV1zRzZGF%CORX|c(+wWpfXqA($n5u}4tcFd zjQSbEN{g!#M_8rr0ahtKl;5PKZT7MlQ<%T3A+B0gba%rw_|@sd%mtR!Z1xj(y0H_> z$YCSWLPghL72IE_s}Ni8@SMaM^B(BSQvov9Qh1k7btT4)4>1aKRJpO+9TQu((enqf zr9_D>e{@f~@LOa!5>yMvq~pTqIQq>jOnX&d6I#yIqhBJUWE(7>M=>!7gWi`+6le~G zV1D@jZTpliIJ;Ip-0X!N<`N})h@MpqH-~Dz8tqKY(!ls*=7 z--`)tdi;Nmw={Yj{fLp_`}ZXO_YrpjkQWET&IT+V zqDZuF;&?YjAnrvCZH%}U*oI#{p3T{uWSsm{NW4sy2u&2Rh?VGIR2NvB8m;;9ywcA} zRN9LD^xY4`D)hop)2$SUt)x-%xv^Upi4Ell^$M@IJSG@?kDf!HA+db{ZQjb z>Np$!J^#(^A<}rXCc!eK!(|LRw*D?ux@Xt6nK->pSulq+k*9h9)&m6jNfnhi zG~OsNMvYsp;D+Fg&d;KJBr7G4TQ2-D z$JLw1L-~IH-~Oze!u?eQP+K4=Q`(kp66WWI&;OgH95=t_pHm%PmZAEY*cnt3>Css0%a zm(uktRDwc0axNb30(HRVis~(e?2>_A--1W0-OvRPS1ZTv{D>yELNE&9J+Yl}2)3vR z_0mYW8~c-22!0WAM?f!9-^YPBSv1kmi2Ooz$>Dg(R?u9ecq4uabGuL}kL|ECCYDMH8+G93Nmnor2G>mit+8PvaY$oCzn zC{5&xc^5ZX1{R)v2Ckcq`AN(c^!NJC>gPU41g$=xpXB7D(YS$y$>@Ow1#*A=DOjm9 z)O^G+_8xRlwCW3sq7~po`Yk(HNKw8MeURQP+c$810c{rk@gpNQQoO4|iLO4{5I%2l z1oog2>N`5ty}a|AbIG7lR?!gL<$&VJ!#0zs{M*T{I zu8KHPU)7AnphlcAgYSM8bs0O6g<#FgP`hj>VG94Jiog^9Wm!+3R4<7{>xZh)@#J-l zM|x)rRuxBG+?U{(OKJ{H!D$%|Rc-%W-i+W)cI`AmJQZJR&uAmUQ3Oum$q@H{W zTV+aB)6ysRK#wN!y!hDVGj>DqhjR$+2Pkrt20}Le$mrh`pelE?Q$wqm+--@-g@x2z zJnU^z2t=MH-|n!3p6#@@1^B=ho`kMn_xD<|vNOfGbpEF%5gG4Y&b8Ll%)=k`vBU+) zJDOue_XX5cp-yV+WV@i+9WSb5n(@NUAN*0+gAxcGy>F>mzO9hRSYy9f*QUF7T82{kd`Wo2-j4TBT?z`Mzk13WRInYmT)!uoqD9EN`tGLwYqxPf$glPv4er`X@@)k&rwp8> zFT4z4bD=m&S2?3nJ?)X;zR24uN(3qG^Y)zO3Lg<&Zx=bo;r5k)7cAk=e`0 zY8SQP32A%h{<*Ah1&4Ps-yZDqrF-c}+^8!cOd>>>d;AfKb|J`;Um_uZ7`g3>%xyob z9)z9pt=5mp1}#hA&kdfxwz7`0aVIwHo5s0_@BH8Ra={*c*kAd_)_1V79;P;VQQkvR<#f8 zB;}L<>jYu*1yAnl>g3IyiV`;oy^doz%d{zR5K?f!#84ABtS0zp%E}4yD`Xi^j!DPQ z`opi3=n4w+KIzQXYujuTHEKhG?_8_^UV%bjh~f}sPC+g2p=P@s>?@AsS6e4Gi1zQ+ zbQ1iDze2-K4-Qp@Z!7q?WR>$byn!AT92V0;ZLSL_hRNY9idW)R2>vzy6Fs4(s}QZc zP{{wxC|{p0;e#(dgKozSOEWB+ky^gXvaHEIgZUj5bd!zC$XJ_g=>9Ld-ANh#P16(t z5A~dNexnobiqMx&$9eLKo#+8~OI(fmx=#t7kNT(D0YHQ5E&v9EfO2h5Z5GoO{;Fe1 zAM#5wHwS+-Si1`=(anzDRi0hTQ2Cd-{c>^~8WA!6?U1Ga-FDNIMSyBx?4TGh(9IR? zFDF@*?qelPsSdj)e?<3w))^WhY5})!lF&c%bs_VoETsf^1oR6O*x2YF+8<62%S3Fh zk$23N-LL#X!@=);rWQE<7o|;;X;9sy){7QSq zS|oVV+vSqziZ;YKi_cy(c%+JTt&k(e(ciD3Ay^pr0Z8q%fF6J9Ii=p--0c~QXGuSn zM^Q%Svi3WOS^sX@W_9`e)cM_M_~RP7{(lc`$*siI#$Qb|rQk*LEuQUKA>k>wyWMhe z3iP3eZ&~=P8GR4lB_|HHS(7hwslD}^aS^bNf2=my)%N|6KGA>{dADg3ee2wY*}Lj4 zITZn3sJ&n6c0G+Ju6=T{aM#hy#`i#}riBl1|LsrnuQ->)tL_$s^K?&(IQpF8a}r+_ ziMRFv7jN!S>XDO6=W+EGZ!O&22?aND-pjmoz8O zxAfZC0cG&zRnEt^4-*J9$`n#)RHy<6dypd}3k&7j>Gw&4)^bT7Dl?_mb@HLl&3ns~ z;vba&^~J`tAMjGNWtcK_8e$0)&0HL$DK*Q5GF zrfr0Kg2Vu`g>gCP3<%XXb_#4jHHOIfd`LUeeA9d608DPBeJ*rd&necQ&6*1f#Q)ex z;%dAB28V>Vl-(_+EMdqv)SM73u|4BZ^KwHc!}@hdr6MK9x=vl)zh8`nXie6}Q5-uU zY!aU7P0ZS|`_|JYaUo8miUHVzbjTQXgeuPROTnGrY~wzWD@3J4vRy=Db=AM`J@XP6 zy=sWR2~I9k%E~ugtw7W(%3z?T$k|fzaj}Vt-?5 zfWqjKG~xmi)JfumHH#`%xl~+&54>ZtTVb9*Fg_?2SH>2;ui24#Mh_`2Zc8l}Yadov z=Kut(pAprCb1$*07Obpxo_D&0e!qRIH{qO~`8Wbv=3XRi=d>ga*PgUH>hs#-=)Zz_ z4y-B2PKdYkwu9XybADB;+bwCM{O|>+-yV3&Sng3D z;IXqBk)11AK1cZ;nkwfquSVO3i#{F_)wmTkK`Q+Q*%KSu=wZpq@-9xQHn zo;t$wpNSQ!Eo@W+9ZZqdY*>I+?ccJ#yGQUL8ZE+)b0G_xL=JPuf&UOX@bEWeCb$=V zjYoE(Y}BXv!y^n8ctdE(9p`BQ_3uIuxXb%}yeneyJEybX&T+t4iuSZ(?804sDLwBD zK+r0>iD4(WMYvV01d<3g;V#uyHU!|uQnEMH*M+;{64y1}2|yKi+JPPI6{)sfDr6p5 z8IEjSkM8V-{YMbzEoGlpYYXFvKv5ez_k-#JWgmhx0HrX!mEwpiljRsa4ukJ0rGUHQ z5Ep4npiW5th^qNO(RN3SV(RZ*Cv)T@wCTTtonlkwU1T38!Ac+R57)=J z__RJ}^N`RHSq<_zK3>-)redrP!MoY63VbI94<0Oa-yd5y-!pQCsvapd{&U`>Tz@@| zKIlJWAg2qUnu5!NjBW~{sjy^pCxO!g`Ic$-Nm*n9=U3mt>exvcBjpSz<}UtRaDQp) z1eQ5D1VO4G9x~qon2(quE&H7Oz(F=8_wPP2tt&+ql3eB(Bj!&3Yiz^%YU;=t5WS3* zQ@gAO=gv2p6hEA39^_^zgr1LQt#7uidL>xE1j28&5U@4~HTPAl{q>d|usc zrTDFcoK=;W)^hG@c586*KBWb!m=K@Twf2u@gut4O2La-_D7kZ?_Gcpeqb$a4lH9Yy zEx0G80)yWHJV?y=1-z`^nhdxKJk{9%5=GZ-$iL$hKko#iWJDf@@41_(j%D`!PYrup z%;k!huD$tnwTo1*@AMs-+t0wvG_auw5bMJhM*!gXfTr#nCY@$ZA`Hqu2j0^-YLzUE zt;u*`t&&@2yPP`2|4FPv+D^Don$dnfLc!E&r03bSi}8uIafgPa8lH8M*wx4`8sSFB^ezL#B|*3?Y^ENt#6EXINu-%e2v0?hO9_vw=pT#fDPwCTYD31PTU^V07{Eh1}fg#G5_En zWQQu*i@n=dG|VyqtPV8a#Xxaw)io{tLNw7K#$#B;>H5|McV0&zMmrR8L&rZCd4>eO zte+H67Z{O-Ip2pMq(;VWERJg6WVSqB0?3VLT)TOy{=9Gf{u9n7iM8NGD3Qi29&^}npl=kEO|$vjO@eT-YjGUstStW<4J4S3|riqnnjq;24ZjKoykp}@@aCc+$B+=ug!}*J*osF`_54qZhDM5R9 zmvqvI9+&~x_*aI`6mKD9RZ+3$``q(Bv?NivoVPFi*|PR>lx=NlZiIa?M3uK8RoMC0 zcW+>-t6l>9SP(_O4EO+|1pe#-q$nB9-Le+!1c9~r=$`GSbVv;$#WvY@#<;Z-;yKGLhzJzuhIFL>u6J z51&IG*R$Ly!wrTSJB@MV%*lEl3C9byStae^_o7fIQ)fTqLLVWVRg585ro~yRSVT?* z?YVOCNP|CD)==`^;QDt=9=>wlmR3vCHGCLg?0bkvjPNEjb%VFw3Af6{T6Qlwp-in6 zwe}>wVQZ3j;}C4u3<8-+9BF$AOzq9E!mK>5>NJA2?QFARZ7JDHx%_x|7Z$+Husq~Q z`)b>oF|4k9*&=rryK!f+);~RSKmS;~soq*H=wXukxCT}#y{F)<8SzAr{ zp47SOp^&jVk+Cyn*)Hi85~ufrYBFFNQ?D@X@Uu~vT_WCk)neab6F+2j*T{-(8&4tu zo9xX&v835Ra|n1;>`k4AcYa*-uDRS_?JOYjXV}5IHu8-O`XIVN;8dkbFU*x)GUVYnYY>Ln{^>#g zzJrO^^;z{VQYDD1KigPM5^dB?7u>40Xt4Oo7Q8%B`uVr*heexsaS~`f0qBNFG3zqV zG=*%1WC5!DIOy*NSbou>VMlCxlGyjU=cs0b8lYO80aga421!1Z1p2k`Zx4*h0^3rUPPC8bHkcfLBj(K);RF} z6{B+0>_q{_FejqKP>(b@*cyKvCM>TQ*Wb7)Gwi1&n)5xS$;3D*3npv}=Fk?mB(Y{b|&&Nwm0 z@deQmoqnyy@wdNJ;|P#AC&CvFv>@X#*Rf<}(#W~9%1+XTh0dHYV+EPtP}QrZphZT4 zhX3^eb|kz%(pvRv6*tb-gE=3=|G8sx`2AfBx#R>4yo|&MPpqh7i@>DLGaf}%AauAx z0yHEQ@O^1L3$Z&A-4_7y&)GO+CRxfAHzXP+g)sM5E*yrv=PL6)0Bf!(h}hQX*lcn0 zBV!ySDMOg~zFiDO>aj_|U3BmJ#FiKb=CDlua>x_~Y)@@W6qev|u;Bn;H>0;T|d zst$syG0CswbOn5p>%2=k$XGxWw{du6aR_!LQ&5BRF>|np|FIUmdMb5wsoMo#TbE_# z>x-GEOuYy3M~*e{{YaXTa#D9{;CgXJxS%QZ5KJ>-7zKoQO<=4G?qzIRp15G4P`{zc z9&iIdzg)0NK{n?;y5pScYv2Y_UP7nt5F65`UlUt=5wxcZfz^fV8HE0J9$zxvI7FDE z%OpJ$2Gh(H&hd7&wopxCxx2D`z>MdH+5Z+|uT}~^!^F9I(j;+q^Ii0)x#c_RPQFC! zSJ!zXWi<|y3~v1^8v2+Oa{`JErg=+THO;rDAh zUfgCk89$`?Au~@v>nw>4CVU2S>UtVGDY>P5aDmXMFj7|>uQ1ZromM|eUi;J5zzCAR zC*A%oMa40C=-?L_FNz*e55tC|_q=s_{#8?8@{Is;Rry$7igC?g5o;ES?@W8yXjgb< z$0p0etWk6pI0hRg4fN}H5QPJg#Y=uQ*CXm4;JX zn#I1C8~DQ^syVBl=qjeeXjau8jLbzKwuV%X!XCOBuJ}T+1u3I#4%Y z%|^}^fYP#?==>2JCxP)l84IN=EE3Vw0-F!Xl&_my4}XY7nX7S_VPT<>FO^b#t%S7g zoA~u=u-H<;;&=vF^B5{{?K6uhc(o8WwX8;Ys2Kck&-ojK-%EDN3Uq31We*Zs0d{W# zD*A&~?Db_+(W(-B$FT1Ivr#Ipg`8OmM1FHtt$X88Pq)YU#OzJl?J98??EObag0HC- zkjdj!e8zEqJWBLmafJg|c5gm*GCvtWHtcZ6GD=j%#?u1tp*sva_2hTnyyx>z z%s1*R0{qo#Fj+3xd7L~`g`F1(IRJZK>bQ`BdoVEj#7-=}N%{I8^s82sB&=B*(!@s+ zPl)J(3Yu!_T(dfax$ZsM)km2W6k}I^)ON5@@5YmFp#Ks0+Yf2QCHZ=E`j7HT1sNF3 zGrL37C2jnELhCWw4|0UFDfK99I1=EaIn^mV@cffiVHPTZ)LNDmF!_Ubs!GsYann=x zUcI3)v&sTpoIXlGSV(y*VXJ$tsb#7LUx~A>N}*SIO_^`5PMamZi3Zon_8h7KY550YOM|7! z?B8$te19^wNm%7>lZ*rZnRkwr2YaRLHDkU_eu-t>=h&)q{^X{B8x24E@5ElLY2<#- zWRhIa;Tc4^b|7@)ewQjS?K^??QFbpWf8IyH>*<8kQfWMZZvEPy@(XhI7_+;6ZXJ33#N(U z5KXv>Mu5?um5u}5qEEeMoZA~D4G~#vD|QlbPTqAZ zf}*>WSJ6Y@qCpc5!ECx0!4qOzRY!&AT1u6Wo4js2BpZa>uh%u^5M}yjs!CG@{-#Fg zAna(tg&BJ8P}&!F@Y4@>sb$lGr0z7m0{*1|IHaU^uyv5w zO8dvN%W;&t|IYV1Jn;0BQB=osFvecIvbOgGvKZH_p4Cw`>?!~xy$XByL)y;5YVZ?| zWP%04O*fRHiZ1qCCbw7p=~0S%kZ}?wEWM}2vx+A+K;L6?3&`50z8&FJa|W#hKi_qK zN03qE&%;DCpe?V*WyNS(Nw|%4Np=d4VzmPB z!Y2^p3m@B&`NIhb!-BgmJ_{wH?-{@wcXK;Xs`taW@bGaIC})ZCL|UgwduW;@*b8&S z+0LCO(&Cll%refvgfHxE$s<=uf$n=zG>p+vlHJr^63XZX7YT)eY2LBp-p6Ow0wR9uA!8J%5*8F(S%fbzNhC}E^%7qTf<#jlj&Q?Nc z!8zD_Ho}%}&TWd<0_7OnDGi`*m>g9*?SY{@GCz446EnZI$;J>qX{x}u@tvq~2xe;z zIe_gj`-%t>4j&Xdkef2R#n1%aP1ZriZ1u-a}eWkt)NDi=F8 z7QT*w7n8KtO_9S=%M>JGzucj~`|v25dwJAKQ0_c~H+iRVn}}_3$8(XHXqyp(TOoo)#Adw=XO6CFLH;J}32??_25KN!zt!s&y9Y$Emnwy2@}A4Nsx z1y5qTE{);G))3NE6vF87P@>5U3-;1P;0L~+_^!Fpvih{iZ)MlbrO-#Q9*wKXY6+Qw z-!i%U(&OVGOyEIMZ-+BMl)T>2LJtph;kMh7d>Se8&)ERK{{!!+# zisEq;$9i3j5vd-G;+rMiEamSPRMr)=bd3>d8!k`Kd&KMfdoI8-XrrIB+|cViWct(E zP}EItP_s!9EHXR1zesD=x+Jq*p?zS&<$DRMo=v$Xahd#@O|oW6i8i0utNRv7Ir>&H zW!Zc$UcAkzSZ~N=zPG}WICJMbm_zx`*BQgZ!JL+cqrB&K__a%$mv=>@lC+v+|IY${ zjG1>oMuo3rHcLhEH2q3FeNZj&L$Gi4i_tEaRiTv(ecO4nfP@pyY82+g8O=t1$w(=+ zf3*0%f(1Aa7Ua~hDF~&)5e1|-Vk&Uv=zwj9s3r##Blus#c8N3?7<9&oc{eVz>Th`V z+w-bt-`Z?sV=p_L;CV5l@KED&9=41ryi~9g(vuI}J&>P!x5o^eQZY%^elF5>UiR?i z?jp+RYPMH;!Sfh@-HV@Oz;}J0N(vktKsTSaE@G>mIegxF?&bQWsBvWGZ?%Mf)cTPP zIsEF6{jE@p!wGqHLIL>GaV<9KB5mp6Z<&P3lQ| z;eyi%(qZO1ttWIfj9cGa1kVV}RA7~&9V*fm7i!GEbMES}{=Z6^mJ#4h5EI8UIv*dd z4tuA~?v1pSIR~T_JB-og`8*@mI9S9P zFUzmR%Tl=Qd||kY%mMJ=AC4%+oZ5yx9mVqTcP{6b=v18grVsCoE72|tGrA<4b`+@c zYQc2D16#G^Oy;j%Y!Hn4%U#%6drGpVQ9WK61xSws!JF?S`A2iMfbxbX_HnAbki@)O z8x@`un$d%X+;yEt6=H$a=40Y=2_C1ij1w$6u?a zIzfo(Ek3mqJgu4i8)y?Cv+N`1f#bq$!#qPd>*C*jWU_ZJAMAU){FBP-a6%w^CfMre zAet>8O~M&>GwlQT>Cs4GZUNaNVc)D~rmQ_hpDwH$h-T0Tf}OAR1n=Ej%9+`D z2%N=l-=wFvRGHlbQMx?5ZMrYYnR^1=5?MP0hL{mLLD$s!@= z^xJDd*=-70>V7TA$*_UK@ml)Zv3ESmJ1Pku|E4Uk17k=@oHza_lpwO0sQ&~% zK@2Ym_Quk=?@&sL+3UH{t_JraJ(xcUe)Fu-XXfn}6var+!HxuT;I7K9wa%ic(bE&bFL^ckIOB32EF2k(HT` z-uDdH>yal~e89&dG@nmknfX}piraSMZ;B zTo=WmV$x4#;!S&FU^dmbmF`R|#j&e&%%D?ZVZr$4*0>z~N5BLze!mB=n$l-D?oN!R zwjLiXKI+_QddD;5mPg{mSyA~`AjoU;eRo^#5eRPhdv_1BEa}b(+4d*6t6jM7jF%qj zcRoyq(;9FP_W32)nF;%Bz@wGha`kanoa0-}gCwPof*OBRA_aS16K6d?g`D+*TU?^z zsgGq4%p!4XC$3f(D=9zW-^~N3N0j1yPzG@C2Bsej%f3By97#*pqI@}n+s*SWV zrLfkFeD)6)?EH;ItBCo2m|zsx$%+gH`>1|UvPZ1F@%?omdb{aP&uj9?@XJ-r^7e3Iui>yfrMcT{WecZMDRdg`eU?o#;6)z!VDJ%7)9yz9Qj#N)A%uM@?P;%u}<$(s%HY5;%t9i%0swww0i~2 zoiBG-F>>-XH&`{AwcSKRqZf6_-U$ zasBOMtxCA<3*UI7oQ@631MFR$NQR;t0|=)(zcbm> zT167X3dNShI`1>{nq%`1mXx0Vu3YiIhk zMRzCGl;@vzxV{}PZ|KEpk<$ps;c7~q&pGe$T^jzF-&RXXt=Gck#@%J!2KNB^+xX{> zD(ViXlW|AH*;dk728qvRwRIB%OA&=VU60|3y5;gYQKUWKD7c6?(NsT z#SU_N_iT-gKALmL4|*_PhO1W&^qXWL)cKrbtUlV|Fpu-vTwC06pYr@H#IB znk&0R8mnIN0!mpWHf~l#jdtb5E!`9Nc2o}Y0RIoY_+r%EeV%!uYt6!!&w%wf4Y0(1 zAP{+%lt7|Kj0MJPRd8ew#=n|z6Pi^s##;EJxG{$jaOU*M3yw9zmS&k!81X-ZHU>g{ zaLROnmgk`Iu;WLpgEe~miz%{@>PIoVPyN*!SZ$kLLWZgu~pa-_j;i?%fTc)J*+4t11 zxU&ORS|pO;Erm%vll3f{xWS(4cUxJcsas+*J~+iGa*SLF#FSuX!v*8Q3_jBDUork{^0A_)!AHAq4;t@yzF*=)i%ajWpdSdMJ( zj_J8?0&NCw7F_0F*aO(I-v};n4&^gaDp~_!?mx6{?iM5P;_2a=EFGueq*R0G!O8#76E?CQ#M;;u{1(}H*hQb8G{MEX>qctzZmwz+b zSvczKXA|2$Hc{oD?TGe=<6aXh>;@bU)0u&MO7N}C0k!1cA-ijw%qo$941#O4$RoGv zFEk?&d00oUwCqEAN(Jmh)$02L!Rf&)5XFsV>FouAaKBpd<|~{S-zr}l|4+!2_-yg| zk?QLM$mJ?>ehi-o0TpnTo6zulCD+Jf3dg!Me=?V1s{dIoph6Q}mx@kdtJizm;lLrv z=HzW)4S)Nr`*=`nDt_fL``o&~52j0|qK@+jan{&o)fOs+xRLxwHGZ@wTIr#+U8rvf z{_8PG1q|g@@6N-4+8d-`q*KCZ@ft?VuxD@^-6Y*hOsaDa8>#OxHn}j>V z&L3}6!P$~yma(&%t4ds6eE{jrpI7%85w}AJrIMLa`?!7?fji{9aB43v*$Xc>xVltu z3Jso52*+meC3sW>yD!(oM zN(bS+WaJ2{IdAMVRJx9dXY>nVML1LfkggI34|{omyfe!Az$%x{?jXT$Yv&4xy=S@c zjS;{7mhH)v#Vs|mn)=nYss%w}Nm**@uYc`K-`ZUmu1+7YD*WWsEQ5Jb1wTe}z1NiQ z56|^?B{}70-=27t^zx7>vTmhYpN5>(RYH7!-}cZ~tc_s*Y#z;X6k&ZT>wR!M1)epX zSzw%t4e*=fLvlxs{$x?@3OjqP60TEZpm1Ysc6KauB1`=ZIOY8(27UJ7zZ^zspg+zd z9Cc;WUJo3nqnY5bH9Izjo}8=ooV9V*GVj#$j!-r`liarmM+uvYM~ja~swG<`d>$sS z_Z?wMwE0qfefA`4Bk>dd#Aylk2Q!tuR5Xjg|c!i&+eWhu~v_k zi+H}1x6>7UP&f6FuT)#xLq>KSVt8z%CA3l1Ba?b$KVkflr6B)ous)x*zR)JI;Ii)nRsj?<)C)@->=!;Qsg%_S$A#HKLkW1WPS_^LN$f3%#LkyHs-zJ#P``4>UwI; zUwCu*6Rj@18A%GNUBGb7v(GKQ$DR<+;SSk^xmlo}n)yne*4L`GCB`SuTr;V-H2+C& zb~A7D7Zk^ug4yG&Tc~m`ijRW2#n6^T5k=;&ukz;gTlcAd*&wDa(W9AlKk;a$Ip`|h zL+j)PyzP}^Q#pGo{EUz4nQGsN;q0C){vleLt#nj*;Gpk{i0+DZ)qvx=-()T_3+qB6 z$8_aOKUw;TDv>wrrWfbM1PhzZM*Boh_}F|G1!bUAC#Vc$rpM0A%TlUy*W;O3r)Cr5 zi_`Z8nDNM5%p}#?2z2&(!b~##=l5~t9l1b;Jv8tWwLQO zioM{}R6_bIF&Yb-w+($)8V1iTj>r3)Ee?+d>LHoq+A4oLoSlsq!yh>LdDC^srm~S2 z9M(a=S#XbuO_S$LVLr53vc`kSokjT@n^mN^;BL~cwr%Q+jB-v$hAeRfQ@^zPEp0ml zlBc4je4m_CDE>B6DI)4*;Il$J8C5Rm5Tn7?&LJI}y=mU-=IFLtz!6XUTV9|^C7QSM zCj;)ZKUzs1%H0w&a}5~Jx^3Y7d$hRTk2I?_Ha^@(xs5r9fE&a`&X5$~8it&P;wxN~ zP6XDi#oM{y7}r;$LuhSw5{+Rfz+$zYhsM%7M*St#T}f}stw$5pm$;fDI@I{+Vt#y- z-alPWG!vMWN00fe-5uss86HXFYJYPlLx085G)rN89A!a@&Y(WW!do?1yU!OkIZNkn zd>r}>($1?PiOCTq`X*Y4h(|TcNuVlabYVY{15VV&j3+u=?tF6R&G2fyT!Nm07LOG! zamHZy>{p+Y#djad#Qsnd0H?jy8^McgJGkA=kb5f!EhX5mcP6J-DAZ^2tN-y=BVGMM z>-sV$)9lSLXnw3K9Jy77bIk-f6t6Q#q+KNd9eTx{Oe#r{RGZ0bs+e5v4-)A#>1FHQ zb0%R9Yp2qPh<#^zC^i)IMz^VeG)=Saa-FW)^f=T94|ieIQvcpZIJF?N z&aCGlxX9ufZ8H-9NY@I2UDl5* z^Gk*y5E)*Ixz&VgGethH3TCBgrvy7)%)|cb6-UvJmSRdQbdQ_ZU$0y{$4em;9R22S z*GcZ%0{_=;f_=akrBX^6i`fi6VSk8WpWB*bpi}n)aW5 z;TRHJQ$X)XU{Q&TX_LzJFt9FeOv)UzzPeYuiMf7O+?U#RLbmIYUt@(PWC^}k} zO*%l+-|Ebz)+}~cnbrDi39a4j%aZR2ZrendcWpgs+$f-#VWvbdzksIV#9jTc`|NimJJ$1#0vE%M@~6rssmR{*~>A8R|Mmr`N$b5pQHTyoMeJYK%`l zaW(D)X47vL&p6pFQcBT_%srGEYphb~h_ICFM2N9Z8tJqkT@ev;J1)Z8b# zmG|ly1pmtT1()ANAoyOj$&+ziR?_IA!Yp zdel3;n8ul|y;Lq|{ONV+_Od?Gi@dsaB!`AT8B_IQP4Ke(HgR_;_kHUH!9o<#WU$sX zcwF>{-b3bZGF;B{-6dHbWiEpx@x$JX^R|c5j1FB(V*y1QuTiZRT`>BlI25t3YOqA! zso1%|b@Rm8q8H58c~8}SL_{KjS7vl$2|aeVt5 z6rAWAyndf5Y4AEg)Go<{dwx=V*=F9|*2t{XQ=Hm%BTJ-vCAAIpd0c}{=Mym!wf0^2 zkFJfX*6o#G15M%d)=JAE`|;I2y4gI8quls4VdNP^79AG!d2M0Pu`UI?*(Lfu?^F^U z285v0j#Bws_08LhfX<)p;LBXr8zV|bZZ!?GnKng3$=$oXvH{7R!_4wp?h#v`?Fo^Z zX~vxBL2xak)~|`Iw_>&~mHaxiaIYuYB8p%8Z$p7bSR-6g!O2b`!mIw6l%)X|^1ci0 z`@5u7G|uxz!t>Di>7^gCT1IV;sl1>OiLj&shIcj-cbq~011dU$1dug!eL1~% zmaK?45EMUg7~~?}%eq1<4LL5t1Jje>-7V|$Tin0Vq#BRkt8DO)4W{mNxdRbxYOz*{ zME)oy-q?+Xqj|bPPni7;Mm#P$FlvFLBVqXNePq@M-7f?e2e?Wke6kzZ`Mj3e^@WRo z_F)g9E%6P1+{_HtC)UQj7r)LuG)G5g%Gh@~`<}a-^)VLA*(!#?06H`JRT&q+YT$6u zYkB;P#38ippm+gGKIL?6J$8aez%N=2qn&8xG~T%pjx zF<5T1?=(f>+B{3}66gy1jrHCYuFgolMALrxh7Wa2Leae4zfzlJ?t0Y3E%-CQWH$ev zdDI1b8o$Sa+JRW77O^MMyndwDV{D{4HluOp#Dd&d8%2lQ0*c`R4l*Zy*aW9`E-N9) z=%vGc|Kwut4{{uXcc~Pf>8(Bb;CKp1MQcl*&wn}1E{iySs{Q4}of@7OsR|Lv)wc7v zwI>a-TTh0ZwezGGzr@N0bf%HdH3 zHfG0NgRLg9v|l`**3Lyc-c3)crMaIZo7aaGN|GP?-l>WV(4ANA)YBOuYDKgqa~|Ni zTpVeDjNS|In=Z9+^y4ewQueR+C@4L9$6kozgN}vgwY*x@!W;NkN0XD%Y4aphRjd9N z5033GjE&DdbG2{X17G7J=1T|8%*kw{R6QFur85(wl}S3BtlO0@CXiP{KniUA&U3#2 zTk!F`0!hmu(Tb@($J0(jXpsZ}ymwLDrX~RFxV_wNyy%W#om6XBrDZM;Tv+I=;D@d` z__Y@wI)$p{&crh>_fa?MN7kM+UD^t8Jk_c9cge_;+G6Ir^fh1HT(06Ssa}ofBHwhu zI$pm%!<5}5ope6#(jbW|`6-f=MUu+VH#bG?+&`v0!7NEuXa(i4)-GAbytU6;j;F9m zE%z8Xb0!Pvcqp}TlZT-K6M=#&o%wvk!B-)`MR~2vjHxr{z8|ff+t=%t3_>fJ6guU#bA*_ca8Jtv~F}e}H$YNc8cR#=W*#A?{ zh`C+dW$`(d)eKc<(h@o1T|so=HO}p2RpV7tqRjWkpI~-6v)Dr^mmGDxIdh|Oka}bC zulADU|5Q7xGo~i&nJ#sD4oEA$+wFm;D7L@8?AtglwJex=+3yX0u0EICw_0gyBzq~g za`)Tl=nkSjhr4o(0daExk;8|$`Q59l&vR7-ujTW``PpUH!PmYD)V!;uuxFQV8StD8 z4LK3_vm+*E@umANs`r$sQ))_v$}fag{Y`KFBirj}$;Ek^>iS%YZ1481)7qyUPgmeC zw-9RR6au2Qv~^51>^-de#Dva^IR;AYJiQnzAWYo`jr>wL~c ztuE9~yzs`Hk3If#O~8cwfQ5(d**}`hxXMG%{-M+VdDBEICmk!ICF+Gh=g`jOq;8C` zn0gFWvg@m9eP9VY5WMt#%dZyow5rR6KRek+<1~YoqVu`(hGy`a>aXZyP7h2|TdrY+ zCbF-w_C_6K#fcw7|MUO2dJji9+opXuJtA5{SS5N8UG&%`f{17lb=7E5HhS-g9yPkC zLA2Go=yeHUvFhrC#bU8~{av~5=Xt;P{r-a8bIzG#j$>x7ISJ0*X+COD*!W!)ydm@Y zCpj~L_nP2a+G?#{{6jbTk|h+M?J{1^t)gPqp`rcMf%5Q$ShGEy-~J(&`&DF8E+wIA zZuVroqwxd9aHk#`c3rEH_mFL4#mXzOS~=j)6Oea{Y<*%R=%A>QPK*sgVw26N;c#2D zk#X3U95TG1pmL+Y*r-b+HYstZilI6D3eRv!Y_2K170XC>FE>7Xc_qOGtTWpNT)^V$ zSa`k1)(y%J7T;?e9r)6S!7#EQChOB&D`2SQ?eK}yt%AJtRFl1I*}3iSv+K+|KJfhO zCTMwNm2#tqmJXj7iKkVt-VyzRsL@P^s9WOj_LJ?OUS+KB0^^8bb7S{0JNW2%Cvk4! zx9&6<0`AMXT;GF-rsCVpMoe+(zPB~8W_W`n*iO&0j{Lpb-7`UmGg-8WyZ~wp%A-ff4gno=-W{8OU3;=#G0^|OD&q5q>BOvEuPwv$OW<&UUrbV6Uy$80 z4)c&5f0F8FC_j&1fQEA;QxBoZFTr8a90YGgw|eh=I^x)YoUdg1e!9y=>t0`bJy!!| zd#^(WgmBDHS^_-A;p{BrpLj89@bAY^>2EqwjxtlS)8`0x@V6<^#ax~Zjn19T4dK5Q z=iTJ%dkD}%CPfqxRP8&QGyhBWC)JL#n%VX2*{$|`n(45YU24~mXmWKyp%duvl$8E- zmxYmEh-zz7q&zmYy0)(w#cuZ4-~O%G4=LXxm!^vi;(Rav9U+~oIj?1NZl1yAv%6dz zh4l1P<7*0|v-5E_^wZ4$=d|mw2P7kEupkbiuPYuX$@}WB>4NxQiEbgjWR=47!F8W9 z{mywW>sqg<{>V*LEBf{h z(RB#bqG&(jew^dEEjkm@il41}0Eas^Bz>Tc6>@TT7oXeJDY=ueBUxcnE8M~Oy_xjE zu!}CXbi6Me*DQ}c9!RR&IT3ZMXc=>bE$R&24W*VAv(liL=QH~G>1uzN^nEoYggk?= z2l4X++T?*xDT)OAC+>$BiTNM#Vu3i&>AZ(kPdRYVTZ^D_WeG+CfBtUgUs}C}kk=T- z9pi>O=1`HXI(|7&jsSUxa-+ji0hR{W>Ok(6sJ+9N>HGImdGB?|E==?EVpm4 zNuI6J+Zr~8rfT!OH?CcobCM)Lh35$p0uKR}5U7FLXz(wWiBzF5<>d;GRYX~hMv@pL&Z!u2^Pi%~O52YNj8iF0rr4$@}VQXf=? z<2Fq_*X%rchY3_CoG7R6>ux>$6_T9az$UEhPD%IJZni17`vjUFEzqqZst|4CDMST={U?R1bh0e}0FLD3ZSbDnLDTC@rC9N_Hywyx9=tdtY6a;?_=a{4`a&Zb0V6 zFNx#rOBU}dOJd!^JcEaUU$Qt_unh?Gs>paP`grdU(&T({!?4-+9)`-oAae1jW53Pf zVbFD5hrpqutOGNlFw8DEpw*kk|N*^n_92Mea6_onL2mOEt9GKcem-19NiZ zbT2MbMU6RZ>ucq1Zt?axF5#UXV}2s&a@~3_#T+oVfq*sb{13vSp6E&ZzH1Enp2}K) zZLpdTdivsNkQPNlk-fWE^xyz;i7M0kQ|n3V)xBn+kdL|cXzC5Q#?&R!`I+_!wjB)hd{^ z|Lcl)Uv^-iJi}b3EuX{cFtnQ~Q*Uk1KDOpt&niuAWlIo}BU< zVF&bkHrO4z0y|!px5NDjVgyGvz#Z`DC;H9qgWV*ikxT=JF-M-s)sCFG#u4;KXTtFONK2>UG1x`W_hXS(ZGwBl#hl;K6!>K!ciJ zaK3FXpNwyX9o>C7DD!}0C6Pi33m>6|=E`YNo@j-!V_)t-Q{X>grCWpA!{U&&Ew8EH-8Seh2jPvac^2!pM71(#j(A%|^lw9T>R~AZpi9 z=gMxVBcZ4ENu^A5_k`F=XyQx&&tP`al}-f&ZWQr(=nWCTbeOwa@=}o*y4E|FIeGa zG~t4>&3IER9NI}H=n&X;G-IgBwV7(cBk^=TAJcC zw9qibx#je>wFpi^{x%K=ye|Qe1H0uSTuYB@{?YLTMNcH75}~P(?;$(xFU5G9?lAix zgS4mjAlJ$L0AW5l`Iyg`to{@sY!eGI{oYeF@pQ_LZKE29RQt`zyvIOlO?KR7I1Fez zGA@x;i&sA56$%x;<3J&@g(&=93giA=yQA%Qdi}EJ>fkC1rT9JG8qFgu<|?)=&Y&e) zTTwfOpsK?y0>8Y|R}-$In;gV63k2)%g3lp@RM0{8IX$pa&?5A`$klb&)!fNv#jw8%+b8XRcKIx91ofY21?a&F`?rSV-m3>b4u4$751S9Tf zb4!6db$t%ZL{i&I1hkJLjM2Z5f*X9%&5B;ZJoPPn>;y zDO->K_yo3K_T1kp$xB z6|o~wlK*?w`B|g(plcEr?@-w>KFpR6Me!c!{RmjMH`j#{g`z|r&4 zlq)yO8J_+NS2BRhmPw0!&{ext0$@+t8_vG`q*DDhzsq5X<7vP1Cvdnm`iXQhXZ@vp zMscxSj19{U&#HxqzM*bgF8;n)D}Ol0j`8c9`se92H0F^G2OexuWIK{WzUd{8-6iQ{ zGHP~yxo7HF;Io0LE@0}F+913VoKVpTvv6;oPQOJuAyUy)xxH67tNeDzupq|QpAj4^ zYz!C`*W!8;mO8D%PKm)VPBDYS8{oSm2jTUuR`Q`|zw^_Xh!g-V_ZFG8 zK5onbT=?bkf6)qU1~W?{IWu1HDj#P=hUZN%(y@52I#37!i1jMwVl92b;cQOke7ndl zE8(9bJ|AV|dj^*V{!%*Bi%QTTG&~$%UtPUWI`d)HbR5RKek&NKS(bWezqIM>>Y|PC&Yv|_=DU5W2tYsO($6uG&c6i_$Q<_ux^-DB^ zo)BA|dE&7~fxWFZ;06QLgZ~3g`SP^~%na5g4{l%IYqInt?hpXD514DkC3e*8Gj5UZ zYX9b6f!24*_8-^n=a=fM>_BMsOli9%7QQ<9dw+@;D*JCAeMMd^#Q6Ta6y9jCLPp=2 zSo}IJMlN4UPn(nKy57~9WgPigo-%}qlQ1@$BE>lH~TEddb3_syKH1t-}wFo+@3JSIK!L6UP?eyEF`+~C? z25UlK1NDHA!&You*!7C^Y#03XRv1dI~V!%tJceUc%+yKG$hD2JQN zOfE`j;Oh_ZN^mBj4?W_AA;skO{*JxP{eCX24s`xy>fU#{L^2^M9(bD5@j`V=+)nVWCN-lcQOqHf!SjRX))^xBD(<<(*#Q(CtaEfAxPqQ0C9 z=NKJpIVO{5(Hmv<-b5@Npvc}^q5f^%3Tlb3tJ3x)a$rE2P~Q+|*%1grh@7?I?LNAd zH&uSVOEC{iwb}2@44W&I-h6$rhHsjg!vWnjy_z$94d`sEAsbKE3VE)481I zZ31yr#a9V<3%BBe_9;TtjZD?Gv*WcbZGI_QQwQI{l~zVDX=17qUa;QX_VVpKa9bY? z45-1Y zif9sS>0xED4BSifM=7ghnl~~3gydbUnbADd)xyQsm@)~;x3F~L0c4Z~_3eW*++5Bw z!cuuxw&IceplZq4E~^k}&t2>%RS_ACx@JQEv{1jncAgm>>>&AuC8!mw+L&r$<3#&c z6fUAEMW!F8q#oqBD)d5BUp7xR3m@QxJxIMK3SObTEfjL(&*~3flk848l#_DtOFoOMZ7f@8y~Uce_IUXq)#W+er7YHKX}ziyC@ zgDem`6Mc~a&o}JD+UgotGrnYke+{!AIGqDG={Xa}E2jzBmPryqs*MO@$ZG_{GPAkQ zd`CJX=GfO?G_Fgl;Npb5z>+>#bO4h_F?|g~qZ$j}8;vp3*1hb>vC?{c==?c+uBu@e zBJtXr%VnQ?LE!Z4T@Fg|*TWg8;b&D$3;%RSw-dg;vO3i1zF_E$`R;CC3;w4%PI?Zn zcPYg)5fvYdpAoV6o3j4UF-`@Za*hY~F!g^m`_|7ln3Xk77r6M-DZ|FC!M(aA=q!31 zC|^d3bbnmm^B_ZRe5ZD96MoD%j)j~^q@X(KXeHO`7|t*;EhPA`ict|SG}AiH-Wzs$ zCh^f}K6&3=EPK4qN;vvgDc;w9d&f;i3OWHT3)umk&ytN_s%4()!870}Rn&%o=KCKv z&!ncqToDC#Q#y19Eq>7qq|D^Fuah_zrkbriDQw*H8lUucNorZPbL)viV@vICx%-tF zf`J7cjh|1ZsDBSsr?@JJ88=yOMfta_lTSoAw4-~r>0Y2oI~aPk5UXhb*7Ixro3q8P zf23bAEuqL}eDR-qcc5s~MOD*U!~(i;5GJ}ayT@{lFO#xEr<2Pmdtpk=tap@P%6SXa zH|LMY+yR1F4|3D4q@2Bb9`*Z(h{&h&&Pd~;SZB;#b)wRPg%jTv@a`?7-`>aK;YKvQ zD~6-Yif@C=Y40*Yv!)1dnL2Obv6xZVuG4w=m31J7s#`^3fN%p}Z}>+}0ZCuiU-?pW zz*Qsy^V;fnR!&nVSYEg?>(M}uvT&^6K^*Pns7q1IK{;PP7wun}X)!<3t;E$e(m_{h zsM7@$5kD+j%HPiv?J-{Tq`4*e!7?gzX^3WcCN3W|oN?-IukP>EW6P3c4U6w zN*L*KM#Ov&MbY^^zV@$_-C3=$i{jj1#1^(JJNYpE1M$Hm%T^6~(=5kgOU0IWqQ^HX z%IX#RZ2K(Zu!Z`0B?j5Q;K{Hn`DQ$N{D+#m(WJX7=0kZ-J`olw*Ps)hi|X(tGG9A< z=iJ+%F#phVd}5;IP8IK7UE`7LRv7K#`i`0dk>CC}SADrywA^#hlT>y(a>;em1ux#Z zp3g-JKc)}VZhaJOW$vd%(*p$qUAOJBg~2_Rzr}MaP5{IGp3rU+;35TRf|o>gAQoy1Oe8YZOP@@{f1G`C z4xjU&Y{C3&(Jk^htUYlY3ziKX!`Q2loLwv4r zGpPuU_CVq)o7OUGu-ATc9=?y96_SB!Ntm*FY`3hRWvxld$F39w<$AGurwCZqd_o^~_OW8}WLingP*Xi2q2ci+3*1nS0wQF>z&BAG({ zRl&ba3SOnsG1g|c+kEkFy@)Fnvmg`3XY8@+n&l6wVS73*TzG8?{K$6T&bk=$l z*9jpk)ArKmavpi9A;+>krGBBc@ubC{*&~KiL;{Zn#)K-f=HM}s#Yvi)>S^&Rw9rOR zg$)xRvdx~Z>ud;ponMh#6tXM$mU9qyQ+YI>wC9M_usJGqf;V;>2@!3%ZJbt)K&Y+l zxzX7}-V;-kZ;qCwplSc!?B0KGwm8<@Y%ZMSeS|dGF-Jpl-UPGKr=cUVV?H|i4iG?K z!mD`BlQMlnuTJW<&jz1C{u?DD&CvHzN8xWz!&H#fD`)Mf5Tgb9g6N3CDNXCyxEu zv7=(a?V=jTd3d{f05yNI$%J=D`;;A$q%qu+HSt6X2K3>i_bvAIk3QTSQ1Y*spflUa?cApaPiK#SHEEZ9G_gXR2mOkC@!{uRaB4HJ=;~s^ z)fYG0Xeg=2;cY8#r7K*nhG|4^QEOaA!53Br6Ne9V~113ei)ITxd;%QvkO%)@0v#Tzh2gvh~<_SRTx%$ z=Ir?t`tmd}CSzrvH%Dg^rmrx+Kjx&NKE_|HBHV-&eLXGZj%OR>`;F@pl@{X#YSB$1 zybRG{67wb%E?;%kMPz4C38e4jWuo2)5J}37A?)lO70k{C&g+U zVK;8qoJ>!Nwat9Q4xxMTPGIEM(pS>gOr25FTtY-WZ&NT7(T{BP4WBP)ACyj?UK3|U zyPZzysZ&Ss$(%l-Wnh&|W*9{q`^AdqTT!pm!VLI+4JoR-Z2??95KaBCQfOK7=Hoy2 z?l{!s_y^E<$1XyQeE`{7wz$!aC-5$_N(vMVvmnkbj#jC2`%@7yJfs`lU&Hr{Ug)PN zKn*+0{w-J9->{6c`N~6QPKMM4W;|F2QVgT{UwI>$Ndod_$?jO@?x0BL5$P+Byf0>b zIIL9#T@0jJ*iG%GEDS?{J=u|;oLLBcWIso1Q7}fm3=^O4HUPPokM;=O(d9ZSp^2!$ z(K#E5Hd`8R4C_i1!3oWwKimE!|M@%V?O_N^Spd`Lm7In1acbsk09z&n=jXcH1u^M5 z{4w!GJ86qa0&a;$PQH&9wsbGTKe*`FTqA@ESbtn~-RIt*P zPcGUdu`J!t-*&|AC^llQ$~93%`()ahKa=L$M|1)b6hJ!P@I}#-Hx;LDsyT05ol;9}IyA>d8~5(7qIQyi+I2`#>g2Yw!M5-^auD*3#`5zxVd4_vsJJS*nu*ZI%|=b>r|SX}k+=JJ zeG6hOy{4eu{oK!tP}FF4(mDtwt2t)&2oTOGE3XS(6GkODT5#>?d>BhlVV*k)n3Sh) zN{oQ8nHK@(D{rXylFgm!DkrvFkABWk?}g=_u#Dy=1kAA%Lo=YOt9D+QprRNj zBp6(=~V_ z?AxbOrtCIsEBkT_!jj`OQH>>MoaK@f$6m+0$lYPAIrgXzc$kK&^i@TIc@P}#YElNb zcGC<1F(9zMfuFBN-RN)+FfZxU=#NztZyWQ``4!QozOHJr(!RC$b5urPRy_yG4uLJi zb^q}4f_W>@=&2QBezekI??L$#hPQIp>S4jW25~|%&xb6=O~zL}`N!Avh#Fy01EDZZCdUKz%5hPm6ZoNEN3>TGv@z;J82(bbT_I07VG!2Ej^Vx zK%r~gK1djv*q9;yhVS_tEs!5&&KHX$hIE^U#9X#6QPBuG>NKaRq2v~e2geyzKn#)G z6{*Kyn7#?5cr&VBs2%$?3(7;D8C?ONlHCkaC+>klwK)22co^2FXvF7wiO@vna71~b zqUYgo{rOA53t1x=(Ms@Dm(yU97}0PTiyQKUv4VH=ZqMTBDrJKLx|++MpE7NHOMMx7 zw?=rUcZuJ9sWEmxQCPH}@P|hfYd>HUUeRN87L4!L*Ab^$|7wrp0efCyx`@?xd}~tJ zQ&ma#`v8P)RvVG!U61M#BOKm7)Sq?F63~!p>FKhmY*faD{~tdgtXy#*ro40g`9GD^ zX5K{tj$D3n`E5=m1{Y!gH;m4Yfg;UR8+!Gy#X^%*f^_=~LJ^@>ju5+llQav*Lh>v7 zyPfg;jrjmOVleV0>R1;h`l`7<>GaE4!#eT9K?;4luu56A_+I=C54G<oD5@5l1NjRVI>XBulPBOaLu2truDb~CkPp0!bR zJt=_(P0|nLGDWc)lIf_`zv~%n-yRDSsqhT6TFIB*N#?^#S={*^j;LcH-lIoD{al(Qzz(o57p%8 zk2Ps|VOX9}P%t1apb|06D+#ZBDec7ZhD;HuLo4126k(L;n7)HY9*TBcw{r8GoV3p5 z<$07BkG>$@K6SBuQv>IlKZq)m(a{531|m~J79QX-8sOQcRqy$hImdGd$l!6+cFh!9 zhD#YwpmSx^qjjvxZu2CFde22VVDRIv3JNPQ@jzOPa~wpKO5KeM|6UU;;HkfTPS~if z0rXbHg8pL}CNSN^i!g4&n?V1rp)}PnX~)0Im;lI_wgkw}PMZOuM(r2!SoiAM&sr3* zw?ltrx4Er)P-X~}kH1j!=S<4o-&&S--4-`zs8f-&h3u;yBq?dvI0*+IJ_&svK&A=J z{w-L?^<;L!C8zICE*A)R zrxXW)AN2&+(oiA!Ol8fv6}3NuHb5rYV#K2o-JY$X>q%)nE|Iv9gUESn z_{AHT=ZA%p>sC5Z)zhyQH)fa7<7IK4`C2M0KH6CJL;ndZ6uVy^L>BIJ;Zt}QyQJ@Q z5Wqd)xIYrH$1jtg^fmW&!Nsq;b}^-Vbc)Ik0;!k?Wj@w4@=@fZ2z|04`WSZsUvK_r z;v@Rs5)XOD&B`#PXjA@q{QDB=3@X5_+^FvOBhKfYY>S}9281}mf#P^h5UEaf7`q}4^m5+5^}cTrLCCtA=RSfwWQ}bUP}3Ii!6!$!b{^6MfYP2HiaBwH0or`pcF6{D&*OoMh(uwJ&xD zrOQGn^T(rc-32JOvW4GZ$iN71h1tIVhIpDdzQ?~bz~4JW?tWBnY(3+`*1O=^2Ym~M zd8>_PYR4Oz1rc9esof%%L2tMMr3vOqzegg@XS|K3*9^iVzNG_8ndr~I%OQ0O`fglb zA&oB9i2T&T6CUqvOllqPL0BS0*f6fCaG~gi#3`O8X6{la%59f+*6OKgLh$-yy$vda zwk764{)a#lJZzaxPA&US%{Yp>I}L`V)l2@;nP>1og^UgZqY#B=hys6^VJIqe2hZds2I~gjbxZXc{No2w$cuWKy6oQUFcqGCg%dW&C2Q;azR@O zJo%B$hDfNK?$4h;*Gr*^?~LF)ES2lI63E(G5sw#}btU2lNc_x7XhmXaUu2mAu6iUi zJ9HaJGcsg>Z{yXSoSe!>Cys9Z{{6eY!otF05lT85n0XCR(RRJ{Tv?1bmnt9-rW9NG09 zc+3A|S(o-G;vgdvI^xicEQlVdH8OqOkJZgWZHCTtrVv#A z#rBa&go9J1Rms$K_iBcYetRT#V#s=+EkCV#+{D#&u%vFxnu$OLv>_oXDo^{i zGcyaaT38&QZ^ucMudi!&7}cqQ`yi%qUT5xmSxg~}=-U^L5OjCcNsUrJQ< zR7%mMlinl5qjV)C`nx|=zw!Lx9=9BNO4h<@jC!6b0G&l|cU;Ia;0QD@-&;9czrIz$ zs6^g^VcPNDf1N`@XaN@}4p#|_x}kcCQ^tJ;=$k$GzX`eeSM9Gvgt#T>6gVr;1@!a* zIKsc<9ZYmzRmwst;VG`mph5-JYq=B=7?udkP>NLac*jHkak^rvdbco><7lJ#j#G3B zj3Ee&tf-kqtd3KT2th{ckSUF5%*?wH#kx1TKeVcc8fJ1cJH3>#PFQEe(I@${MUQca zo<2C_>U926f>*y@WgeW-;{ySiifJkPYG^JRYMC!)OlW>##+4X5=BW0-BnoDhrIrSFwbJO?B?Z%DKG2oSr(^ZiVdJd>k0(F%}ROg-bp7p*@%d+jK zOyFmf&rP|j57GvAoyI+V5ojdNfcU$GF0D38@cjGl2`RuT5R>|0 zz`!A;_cSvOAt1wJO1p7n80ojO!z3aqk_o*@q8pcyn`)J^xR@iakt8A@B^omIjrzFd zYN=64(x$jzRz(WAcN9$i*J!FK zHYP6ZK*sW7=L_~?9S?kW1Lo;`D;|?bY&Say&oZ_veB9TW9TQH23u3@C%~f}Wt~=*6 z43?{A=rWX_5+zt*&=N<6;lG&>6qAYfq=-l_QnR(-8?3gi{ma3d!i<4r&uCLNZxJy4 zU_AxjiK8DKI$-YLh=oWw5~RR8YIvrszRCbQl`kVL>A)(Y!L{AQB^x%~RPN$fkp7`LGyGI6-BEzhd zBKgeem}&(cn>lD!V)hV*UO%X4LHp+wR-%}k`bcHyc6?&Ze{O2LQAn$@cDfBqnp>)w z|1-bi*^52NNx4)?c<8c+_q|dg^=LQ9xP+=Xb~V}79=Q(VjxzQ9y4~QXCm6%gE!BxV zE5c5KMlT!Z2FNH(n43>HdIsM$V>fpWvTHtA$;a}AUM^^)%5j(2Fp{{JQM>YQ)Gi)K zgq|C#UE!$*y*98kyFNqf*<&Bugq)|=$@b!HzP-Im1nkt1)sxR_K!(M|K~ zEDGvVh4G06PfG-ojDNcLA}TRP$A$F#ybdjyvQSyIuCuXg1FzDL=O$rfNri8I7m?LAFK4o** zKh|@l`SZ0B+%tqX&livuKaLOcDX@O7RClMY<#*2Q@YV^UqGLTnea_N>Oo`a~(&oC5 z=GpY63pFb^;dCw8tmoyg-lKm{q8X83Mc(yJ2m`Rum?>ZkohZZxb$#R`L%nBHzvBH(r-y{LdRwV39PR9=8k^h<>+N?>e6;o#dhCQ} zWnI>9aSo98j)1a6KTSxrl{bdGpOkrcyNSw-(i^Z{u9Tf*g|s*wiGYy-*&OmJ zs^{Y_bo-tcNexF8h>7(->%^OortsObI)v`kv$g#@I#Lxk3{YnIFINK#9z8Y`Y+{U0 zf8(($EHq1#sA?40adxxd(w9jM_PB@FFdALfWhXb^pt}3oJme>Xy0BPHE_34e zAPWh^J%HrZtVomZT{ZrfiEOGkO-f^m9AMn~zoBtsS}3cKGgioF(PhaDe%^2|t&Swx zs4qj5De&vmuo?Rc0;VT1cuQ57eZSDciDV^r5=3>6?orPjQ>DK*ADj^_gv{zy`SWDu zB!}iZoW{BTv$~$Yo?UyXi17|mNmJ@)RF4|xE4rR~7c5(u=#-9^?w|L1ltRi}2-c7s z+B+hpO+lCKyf5ttILxPWLvnUJJfuV0dpjL-E}iY-mP+EZn<>6{}4D``Mw2aD2 zOQ-TYCM{>Opl(aI21{XDeqsaH=YNt>CsRVoH!CoHi@%075;7|)kP|%gZsy2T02ns^ z1%`)HspD-8dF?~Qw~RTwqW(BprVvg)GtZYMc^XE3EKMNi${Z4p5eEi>;p_ZcglVVG z0Bk6J^SHryuT|hrG%t7Qa>4k4l6ti>J6c181HG1hlQQppXWg@h@qeRuD;EL?SIuL{XTYKGIDbU1w=|@El zUnJ{lY5;u@kT5p3>sh(B9zAaz9E9G}-TjDSeYHlsa6rnxvCRZJco1^E6)ZDsj;Wpq zR*P`W57(-?jv6x0mx&TUM2B`F&wKGk?&)F*DScrR0!8b5?)zr{#{%m+y#OMR7IP4O z?3X1AuEe~S3^9cc30r?NU%Y)iRwyAIfnO1Kyv*hxN-^#z9bFvPv)}0FPv_K7=Ci)h zs-*wh2>)ePH{xvJ(r5pydFi4aWNL2{5-s|*HqE^27@gU&Lx`SEU1Qi(`UCx4H1{3= z-1lo5GSPxkL=Hn(mVP#EWE9J6`OtHx!Zq@^P2zB+QSAwbFkj*AlrI&sS2In1q($s1 zO8eAcYDKVKU5kF#-l>P|=evGG?d8+K6H+heJbOp>tt9cR5hm3V2GuFV$-%r5j~$i1 z#F?eCIV;PgvGO%(X^tt(?BU$aDly6gOlGb^Q}@VTzW(wN|Jogd0?i0HucZWwDVQPS zzyShxCMwMSdceT52(XbWO=b+nW4AAvaMpEUG{qjv)m>yP{vLivI|1=XuZ}1~4(Ktk zL@k@xshSwp+Q=-|aAl!gEKO$V>inIO=G*u#cdtPkl41EAgiVaHeqtSc?@X=FQhwI~ zn^^yw1Pqt|K<6ZMof8fH;c&Ukl+lzghHlt#p7TSytL;%o-`JuKjbvM5%IMP#YF4#R z?h6Esdqv>fb*vb-06SzfRua+&x+(HPVdp67yrf|Bv1A#bm>G)#v?;!Q9&R9 z$COW)Uwf-=*x$hFg(x@2`EShM07ySQ-7#w#COF!jOJA!G7Gq&6GjPzK380H|UoFZX zG{!C7sm0CeOxE;Q5~Uk5lzcF7<&^dR2laOw==xQ1XWX01-ElgGt&CwFyWhM8)GT=B zGKmZ_*XrGHGl(>#ulP4uzW6g| zW~aX1eEJXk?KRAQvQl#0x+l)v^Gsm>9Fw7jpeW$%OlCipjE*)(Cj2i8tnaMh?ekr3 z0{G`4Il>(W(caVPu4t!_1MrUw$b9yHm@sAUcFw{ixV&2}gYWg1be7b)b9Xuyy%o+m zp3d3d`-XYC-CR`_F#9+2vG%x}h*L+t5=;#*wX#2k^s7v`d~DidYdD)GcopzPGU;bK zW|Sd{?3KXZ%uM`^Np1Ogv*bT1VErjPYg%WCQ337tp{xoY9HrFMyCKx3 z6*;f#^3%%0!2^enOh!z!SY0~-)aS)SLxsUr}%IF>-`!cH9)(Tat8%ug3p^j zAA&vUYpwcJ0_fg>dUiT3^NxPwo7~Nnf^4VCi-mwPrFp9n!@O4tSJGyvwa(qc457 z$kwnGLhd7if0@=FU`tx^!G{SWFA3{~NxSiLPV`hq;wVLnZcV24<<_I%K9_g4yw7YQsBW7X&F{5O)Pv=1bw0D(7 z-!}-?A5a2nCQ&`0ua(@7d;;7clGIF>$+U-cCMmC}(QL{TO30+@sXYwOc(x0)Fg)O7F;CiLD*Rn19>U zp#0>YTjNw-qztxwmdpOZ82`My#r2_=m(Bj^#nUmZHiwS|@aMY~a>~=5^+5pvK55{e zA|XCfehmg1voCThZY0Skc7^&s0MEf*HH(}}-*o`(RHf{tYbkx?oC^FO-_a?iS6NM+ zv}-7RaM`O&+?q zw@%B%=2facg{V=bS(6XMVNUY1mwQ#L9G#Z4U^FTjIzf4`H9F_7%Jsbbh_hH5ssm>l zA1g5sg^!DkjnC4uDmv~w84kGhd%R^SpvioW0ovIt(ljTT{XQ@vbMbtaj{WJs$=6*< zl-S@f_N%GCz@6!5;TK2T6^+6PkrL<1^wR*f0OIQKKXD}suC;JrK?!~L0QhMF1Y`PT z7nqU_%LYUN-OI!kkVpIE@*fY9-L7x&c6&~HxH2FNCdckLqwbh)ps>eMz2>UtPkuBd z&NQ6}#Ii2p-;*;K6@M{L;U~H&z4NOIbVO7L4@($-Mssl5ktwfvUyat!sAXTs=Te2XVf+`ofWAAvzCYs*Hc~1Exz*f1OSCPkaSWO!LhF z8(WI!bJioJ7?$=ej_WeQRY{M6ImAAEQa+S@U={$dG{#xT2m;TXn(o{J3h|2s+)8Qmj&Z5?QcmDEIuF4R>n<|pVdv%QeZM8 z$_nmsVGDT55^9g=5(|h2UgfMY0lI!pB3q^e88;sW%<`y@nGkgjW#Kby^|W?9QatQz z=eSN`C0cyzPJNljkfCv}vSY5v%s}Q!Si7^?o@$Jv}*Z7a$-q z<~3DI+~W}DLLQU%^dY?i9ZQ(WB@NS`G6iO4AJ5r17s{W6BvJwFT3RRWiJL2_Jd#)H z7+^u?4*l~+(u~rc?9gM$HR53V$EkjtS5wTHYow5U`HW2=N?DRl$8zrtW}L#t%l)j* z0xixVA!3O}uN|K&QP1*%Ak~+s(WU1y6ULxd51#v#?bf{W0ROZ_W7)QuPB%JBct)|2 zLGCK5t8E&@DmBoqk<&X%Lm?Bm_oK7RWp~f30G~R{A5I0FTKOP`Ta6cBXZfI67!0HNtWbaD1X)nen$ThEjr>t+>pgW#4_b1silEfm`wa@ zI5`I*J_5rHQ9?gNe?G5?mCelts{nzTV@agbE?-#EZKtE{$G5!GL8+eWo=s8S>5p!w z*Z@1AF;#O%WGQazm7rBw@__%p%rwN<_r)UC05{tEV>el4lwDWF<@T@~k=| zw4kJ{^^$Gl0Acq>m`_%vgd8j8u*$qWe=d&Hc6}AcGVaU2zi|6Hyi_m=t7@nM>IRZv zIPi8T`=D&@@JlC~0KbPJe!hdDy*5@>)Mc%^Y?ql=XICj`A7_Ie^e^(Jy8O4A2Uf_3 z2g@j7nGeJdjwD?+gn0KZ8+K|Ukhot&%WX1lILTO!t{jM`bG9#_u8M_d`H2h;xqsb2 z2@|u;n;J46^3ab_nipT3snb86!ZQbwF^70wpf#t&0e$sN$Ro7F3c2(lLI6me-2H4K z8K!z~DaP{$Nm^CIsYq_*M2gcO8kcsF|t-JTWoR zetpDz-_u}odz%S~|5-=A@ad02yXESjA6_#{TO zx($t#*%#~=dRwLilv)t+tWN>-%@#{c@9TIg{Ft4u>3Tl83p~!Qj4H3F_`LZ3Q%T8P z^+wfUQVkbg*nHgO2^wp+5Ktu5F;#^L!%@;?+9l?Sxx3#bwe!8@H}q|C$SQ^D&BMt& z=)UC3Jn6Klh)i`pf)kJ1ANvEblgmUWIFIx6O^*jJ31VcLeYfD7bU^7>X#;$jBJV;e zYN{liVjjBW{&HDBtoF8?+J_k5_2l5FSIva4u4TqHkZ2-S(YiqyetyjQrFL|^cqOr$|q*5%ZOk$p2$=@|)nIRSq$c=Nt;LF6Gkz(6kieScwub7i#Qvtx|zjO2z zkMJdUb_bb4D^ZLgjDs@yQZFdjL3W~Cp)w4egS-qv0W0HK@RZGUWd)K>{=W`UUmAXP zgad{dP1Q)dd_4}v_!gUw%Ce_Es{F`M$-GggE8psM&2Gpb8N<37^W$ks4JSA1YdVSe z4F~Urfa|9+s;->j0eo<)MxDlEN@rAJ`T*54WpWE-M(5l%FM6vvs8E$J)|{GijI#xw z-r6P#)OU@iT@^fksXgs(*~Ce8jYnp_cP~Ht5vsak>kzy5+TDo19TW%gsQd&{CqoD@ zw;9HtR41@>kcwz_J%k^tP9?RoT(M_S4l@wdLOtoNdw&nrLy z{{)BDdQx!Tgh!#_avA(@Z~&3B{hr{@$)xEQ{8x*6ubO=V4H@zbf<8=E=8FlNL}x<0 zNMJCmdworiZ)@w2FjN1twCTyV5UEpGadGh;kKkp-w@1n-K$0BRiN@p#TzwG8P)}I_ zs+$Maa;}_z2!b<0RO}cfBD*_4T7xbAx-ex|wvhkF)q4k0{l5R>rxKFPL}p}Whs+4a zCPlVmCUKHYHc2+wW!90AnVqeO?3Ht}w}WG^WBc7luh0AS`u_auKKFgykLz(guInDp z=X0Tk>P4zdGy&OIQagw7t>U}>4{;#Qs-|q@X^;q8+wcN2^mXl4?j6U z`o7aLHZm?=>0+nwL5x{xQUK3;4v`L0Iq-7Bw?z!Dxo6$8GF!i%_J)$lh0rhW!u71s zVE@tT$E#!iwx0&$k35cP6{q*xh5kp0Ye~gwL$0!F+9dVg$z*9X99on}rFZbbZgQ4eazc&>XyED$i`VTLgPi6Xj<(5on z_c*3cOxZ>7$82o`lC8cZHPCG+6E23r@`QCAwvOS)Qn{sr9$)HURj+p|wEv9N1)CIK zRe1a~M5hno~tx!#2oF{4Nk(U$$%m%{i}#hjFU5)2?i5S9$%j`h!O~EqYcJMLfGan z4xZ)*nYy1`xk5josRczWnC8Tf%?V5zFO8R*|0!Cr(NyR`+Zf#7Gi|syT3S-=LF!1K zaLN%Cn!lO9ZysAh=N?sFZ`^knYlUQm*uvk>M%-Np%D{txqRV#Dbbu@V| z_g3(q>J#Vk^~ndcK?51)sh{iC1^*;+d3pT0NIp8!C!Bjna+%TZ*KC^<$yB z*}g3)b@~)3Y8Am8A~)wDjiiaP0}sg?{hQ?wQFu3yVsR$xk2I7`|c#%-1)CIrlj9Co7;eQ@5Kz+QZadNFq?RtM3&etNIBjS zA@*d5I7}OmPMM6~woI_BZtta9*Ldn1D#W_HhC9tE)!(m4en|z+@LoUDFD<+26wEmtHPU|xNr*-#=H}@wB>^o=x)k5N)76{UhzD97C zJ@k8NlNXkyc&Gz-{u!+cNE>Z@Fc-bB>>+{?`9`vff7ku=YV_G1$t$>m@C&LKmXLM{oFa95 zFs^SudgfypbVmKAKgJK-qXwcL{~<@Z>P}H)9_AO$zdf0wOt->jZ%!Wcdt9l%pg4YC zKqqis_tVC9c}Q|MJD~LI{^xJfR_&e|=!PZ7pvBb(f0)*9^MUA_OiJr{@+Ybj>-T2j zG-~AuyW9$|JgPre$0|oIy_r-FeC6=h{sBwe?PVRSB|P2UdZJ3R`loh23`43^RWHY( zT}Q44hrxMy`{TvlRO|JAR2WPSC~rQZ+fI`UuCJb1=7fue%?D>tB5H zrxuN$9p5~5Csn!Llw@S)=_k0_?D@k?nOa|T7*l|703tTuNf6M}AgwvGH0 zHQ$yleSZCP^6-ncLVb-7hFz<{Z=qT@^wiwo#_619Luljv1om;EZut5Q3O^E$L`0bn zDXGjU;ps;q_g=->`j0~|9-wkL-c^_Ng7~ep;s7&;^6eg0kLcS2vEf7M94!rh5K@KZSJcgWI$0KFviN5A?x=i2qokHazx;T-rj(EP!UGV zZ<-}pP3_Ov*c-HmvxjcWHdy;j9wMtYbNmjie;z43qhY_U(|p?FBaKyeldvQoh%;mfFJ~Cb?cM6ZTphCyZ*l9x&o*I!CQLSo z?GNX_i0ufjtX%ZK?<|zp5gF#vNX^A@%;B)>CMe($qpMx86EfFTY~$%Q@1xO40LicD zM|7R7Uw#X$xC^c@bd7JnGMMqONq(DE6Q8J>E>EBN1_gWURrX@D_jlJuP{kcrkfyFC zn|Jg)%X^~pvpRB{@CTXu`b11xkM&c7x6bH$4!eO&(~+W+cYJt#m>bsd2}WOmS8)I2 zZiz{6J{U=C_mXuj$+*l_cGfy8)A{f<&}Z*|_1SWJpN_Hf?#mvaRoNl4bIOgbFL1k3 z%05Nlh$zdmP@nSdnWC@%^sl(IR(mouXRj7GfG4b%R<9-M{%VyYLe<&HYh2@UrTIIV zq~z$YZEwEikY6|rjaomMm;B0;{|h7bNQWwW9#QYZWJ4bs^e%0ne{-yi2ONr$MD~Vv z5ja+Y-3y=^9vSL`1+N}Hl_Ju1w3t=P71j%|d{hiAlyG08_wH>AB*0qbXp{N8-n@T; zG%{^HTK5YPvhL-3u}+2-(_kqVwKqfW@sk~9Rxgf&4X~TwHh>E(E{zB*qL^NR#R)6U z*E#?C8pQOg)WigcCDCgEXnNzy`rn8y)ykmLX;b`JfjbptM$^>~(%pKfHT*?NZ}A#9 zfef&r<;fum%BWCaNe{r(eDj{CI+bn)w#8&`WwaTYp7Pcmt${BJ&+ z0xZJxp`xmT#0dy?NpQC$1F>cJ%!r+S6wi{VxEZ{^93IDlEUfXS$VZz5A$WA7Uy;K^ z9j1R=cBzHEu)7b+c;e<3rjyOaChX+F1=`3gL=G?e<R;Q&Znl)S7iPpr8ji*rq4^cB&kkfxC8g|H z*=1&-j3>@uZE`$CATuYf_Pq8y{|&SSThx$gD2Tue3twI)anTU*Rt{ zzj2*ss%_c7hdqy)W*cy+dfi}O%PAU(U1Ml|T(BJoKpSayIegFLL zn)mc;FeRO-TvqiR$^6icZTh^t862Ov^-N@G-gr+qf&5430IT}7Bu24a`FEo}T2Kul;l^8CE(#bDE>H)7t5Rw7y=uP6{)0{FEZ^X$V)x#|Pi?KuOn3O2`ARvbdk z2on+7Yu@|QrkN;=YG<w1f86H4jXKi#+0b#8)n9aw;B zGtVjbwp!}BQGf%jg+O-63vz^9UwDVF(A1D52!1wTmrT%l{OVg2SZagK0FriLV&Ob0 zprobR;=;v#{@tc0mke?HS|=Buj6=4J-3%!!>c(O{qnsMj4_+58Jw}?jo)GUn%xG(t zJTqRd0Vl1Vfy^)99@9M?EO)P^DKSvBDf)@MrhfCQRNc+cStV7wcBE-w#N$*YwSTs{ z@uvh>t*U0p`B=`hG<5V$PPVS4nf_pMWAf2^o&E@Y^!@I&VH>h71>YaHW76=z2Jpeh zzYNU_KFg?=aEur zhz?}of-zJpUPJXW--GlFpUXFh9xzBrjd66*T!Zs2=fy_dz0(tIKp!+9xR|^pEIW-p zoOWVkm{*P0%0*E%9BgUxkebZ&D>W*__xe{RM7dcS`th$a)MSi)@*ZEKF~Dr}7oT0N z?M=6E{WjTKFKC;L&%d{~>EIWA@G1kEPjagC|sT=ywopoC+r@+B-1H{Z2Z_! zdb{iFg6oNscEYREV!x?_IIwuhf0^S_z#W=N7RM74CA%Z9YTB4YA`68!n`d1jBai%z z8n_UzMR*Zhocx>_p-Q3jwN<(8BYeQnT)O?S4!l5=Zb?iJRVlW=#?{e$N$Pk}^u6>x zSzd~tuZ+s0lQZf)VP^P`Xcj7SMaP zC6k$EG@k7CRo_AZM-b}2gH2p(LQ6n-`A#6PE$Y4wNIxfW2ca~G$u!> z#f1ZR`|7iclimkhH~1UG$3^j5pLcOon=)0nTt_f%fvr2W;9D$+>8}G9LP8Xmvx=|1 zIeI=tAFuU%RM%5V@%!^gp3u*heMUs7KfPmThdaj|yFJdLbn`E#d+#anU`?mKYx)J= zQf+l5ty0`QGyUUiH~y&7&e`1B`DH|HV@fxzwNm{T(bKPoV}dDpVhxEB_n(#V^%|o@ z&s?Xm8REq@Q9Y8*yU)sGXN&EO{clB(x7x4j zrteTA2J240*m~ezXq4jCctF(Ka44BKG`)CuD%?qS;43S9(QkVfDuG8%el0kGhwu*NCLnY;3YE309Ih z;w?RpUwUHSl^1pPqBdGjs<3{)+U8iMc&~EYZ@fV$*>eyzoc|kBA+x$KbvC>EY!$16 z?lIC+kV!8t(zXPk1bsO{kC=j2cbA`3MBQarwM$;ZVo=T*)hT>xUJKGiBJpi{5>gC? zGL<7uG*{`~G_ZUVcpFaf=J9fsV8r$j3{q(4S0J$siL$6m&+4T9dBt}x<*XIFlybTa z@vSwk)?iuet3>_eOX>O%+rlHS<;t2Ple86WUt{4J0dLG^w)tYZ6@^krCRsjWt$uoq@-T3@*L)_u3!pV!$(kfSsm3hmtFR<$n(Q zd(C0~m3F-o^Fb-TcD)Jou&ou>fb1{5tG1)r#bq3J$f5T3`kIN4UwU_F&ceI!u)wM-@krv>G!5Rwk_4f=)i}r+||c3a9pqZ*=nye-4-W0|M7GF2-MJ* zPTFQF^!RAat7oH;@_OSm7V9p4sNRHo0?64qPueJ_MH;W3_=F&AQN9>0jZN^u%1r|61*Q%Bm8KWB4qrr24O1)<@yL@p6 zjA_VlWSv$4C(X?b_KmAYlI-L6+2eR$+&^9XcD1hae!l2hLl4}yJ=UQ& z(oP_1q5srfbF(`soxqvl06h84paSBrb?X2*%o@oY^S)Ke5toQM{{O+ zc66#wziyX2;#bgna;kz9^4b_F%8&TDB!k|oll6K@tkgRhSR;^K=x3r)uc*UQBJsz^ zwHU;+KtuHKt!3^I3Oq+5YIcXyGDqeD=l#W`v(ThT=~Z;1#6jfCQ5e1wYM|x_^J>%& zby9d#xH-D^)z@p9#x)gvueI^0UL|oN(pnAu{7k(}7~Cz@FH&7$Vnh@mlXhZiGrjbf zj(1QeM+frQ;ayZG@~-O`b@J5{?2t!8j{P0uii71@MmeQ&!TnPaYq6S!KZR)ibl(89 zrnFLh(V>a7A}k|1^N|F8zfS$mZm0_(3k&THZU+C5=bvvhq#qr|xR9ZFBKmVNiV__k zvmEEz+JVy34cza&tM;|F@m|C4U01&d&N=yQdRWX%{7vc~)z;>})N% z+q!PgZ@hhs&MY1s#CV&=ZcF|)8t*kqQ%w5yl;@z8=bMa}K@!I{iWiynYZ3)*^Vd}$u@}L@%%wgkuBzfy6bY~N$6PYbYw&@=qBEX-aUn)v_JfPhxEWrDguMN! zN^pyX_Dfdr{UtJnOp(-zT#TwjhncHod}|CKp!pz=yg^aP9knG+drhu_PPROY16vf1 zB*ya=)cih?&NkPNO&IFQ8gBt*%shwj0h(%Hdb zb+}GIV9tg)&vmt}3(zhGCw&qM(YxNnL zPBfWWnPjjwQ=e58T#_>{IZtx7OK?32s1jFDllXNjHU_JAhNh0!e~9yWxPzB(Y}-UF zAJDpvE4O(NbTqaN+)8w{7opip5RLkS3Zzp_X}Ljs8-3n56b1A_P} zM~*79A+yd(3g-R>=_+lv5LNL|<^k5kDB0H$g72SkF|NO`lC9 zKLiywDxc@<{`2YN?N)Fz%)AlF=J$k6(a&(kN6A)kYHELWWMv2pDQbTnX_GF?&BhRf z-((ngz}hxTVDw(oSqz?ao4j9gprO}&y+Y7Xf~eosXC5PTZmQI|sUat75=~bMMJ}R0 zTM}#0DxK{2jb~N-@J?>Vfe=!}tVszqzr_%U-)a#4Pq!L(X__Y<3hT!4DBw!Bkcrkw zZy%0xswk=9s8Zsy1hKvx5EmsNhNNM|88{KxB;K`6ugbN=33a&~Q1<>Q;25odHE(4$ zrT2!})j_GCO}GSkq!JC@`)8p5(W+fZQ}}<)^ugrElQ{kmziRmh*&CMmm5I8BsZ>}o zu>}~gNWf_t#}ingC_xnYV2ZxdTKk_q`wb;1$WI`vlY_&ofr2aB!m0_yGJiQTa1QFq zhhkNUmMb_?13$@g1qp|K{2bWlHF$q}m{kds0@qm%86B^)Y@d8sl&G0#xSul9-*aP2 zIN-eJdfD_=Ws5xz+QMR=6P@$IA}$eESXdl2AP1Nqa%Pc@M?F+qnlGpMs0FX3+U=O~0;jTOQ=Bl)&_7V-$B~&Vs9LGmm@hpE%;;%v()BQcV zlUSXqxDcpKp+L$UC|Q-5J*gY9|D^Dz=ZQss8qUQq!vj}0#dIr5gsq6_2eL+ewtV-| zApKLp9bD`Lg+z&43$|-5(YOS2UIy<|5O{B?lPIRoQ^KQKZpY0KxoFZch^ImisO?D| zSuFFHxBo!ggi>1~v$iQD$9pL8_8V*16refaegAt9xMvT^Vx;Eb$yO`fF5K~2CnIML zUQtSt&a95V*KZ@R9K`h59{3F&!cM(DCkE#LC;bJO&a`%bnU5$nF6x#lcaShJw-3_t zIK&1QT`c@jEKjd^361k*U8j&iF~02GG=sktBR=why405IzSnTlxBQ$*R-e!BbE5sX z)AMrBg3h$}v%K+jv8$HE%QcBnEOK0z3o8JeAu5R=#h=TkvSOoo4>RE!i>Rua0v-7M>-&t+sL#< zujwjqfw)3=F)hT=BgZD)Un?7e+g=Eem&WDCY5Tex0T3%)IfR!u7(y3&uB0{#cLH*f zjYmZLhzu}?ggpON?gC*!#CY*BOtEBLe|_s+6titLxW5sJvsu95y+-Nj_$>ss(;(a? z@wGjZ%7Ec*O-iYW;np7Sk>ab+owaza_ZoNg;Q);BHKb=hlviHrOtaQD5$n z1EM0YUTu=e$-P7)e9I&GmWBl&8@7j4ZTdJFDvZ~<==)Imywk8I@g-$wW+I2+fLJW3 z6}8j%4`t3R{qxt-(cOv|62};k8?CfUG#1H~Kd1BFMaf=5#Q*S)Wp>a7@>EZ*#JnX8 zgmH(~QkdN!tWDDBPx8a5Z}-SxMpN|Jam42mB05iL+M6X$M&AF`W(fj?-o_RdSKzSK zB?OFMRy;6FU_+)vx?HCvv*vvk_g8n^(~-1;QkW{Jyj9^QM(!=CTV;tzT9Y_8L+JDC zfP1yGJd-zTw59iS{wl=axk9{jG!CQ$Q7rrWnYN`t{D9zdvjMRmtZFz9dl*pMj*1Dj}Omz2y32)aCKI({1RExmDC_XMTxh$ z^LY;jD?y(RfF~AiB7g_w-1RAfLVg@cwxx=^f65gP-n9rX^<8_Z!SU+Ytk#sfKyV-? z1fRppP>FURWmQ2pIE+c&c)N!ZOt=I!6*M zWNP|%{rDG@qOFQ|B#t)$=bBX7$cBV@6FUTtu5OBm>kLRTq|U?ChAzI{#VrPr+t%z;ZDKX0j#mh2XKszN+}WS4{arU<9^ zs}rr+eYVhssC7rwvJzjE`a|?cmuin%jYseDa&}CV!j6eJ{D`r5ZFEKvE4zxZJkK>G zy14B9%g+0L9LXj-QePkbs8Dp^aZABTeQ_9tN3ycgrvO1iOX;+I?Cj-xuDlGvia-Ur zunC}MFgQBI`udKG+WfUqf`!YGxTcHJ$uLgxK{fOjPlm7P{5`AB zfyS){S2IO$uqmjI3yT?3;gl^1Uzs}yU*@7#hnB>kF3v@5I z``CHkT)LGc*xDo>zWeMpgTn7T&PQmj2qc)8|HZSYE{^k6(`e;@z@XtL!3U!?}?PY7;Y~!Gq+yYvppTTVkgFO#E zsREo7OPWpR?@*}{c*He{7ldhn0Jp7|oo>S^CMUR2OaDoka)qBHE3*&6nRO^G*e&!1 z6iGt*<1}oWW=S##@FkZ?$ygf4>(dSuTksAFD;nEpOQ=P{mtE=^Ti7(Zt=26@@Lz13eLhXr*RSeF(EdJInU0BzKDp`5zn=^?KK~& zJA9Z`-k{J&XTVYU(G*X%$6KDzVg80-@JUjRDDr*`_&y6RiJMp7`P!)OWcLZ1cYnf- zp$0PuyIE+iu7}@~RFSiPO1JZ_NLKHK6KA`I8Mx9{nd+3FK7>zQtG2hm^&laKy}lH zeZ}pO8a#-Z6vFiapgnfs(ZPm)_kBE2M~j*^Rm+Idq3@^*fkB=a3tR9m)Xp14>+_ zl!WloS3T?j-(F-LY{~7nl+Z-g55B?<(ysMLU<f5TS1yQ!jYFDW)~}y;TQ_0 z*|a!=M3uoxq>efR2?1BWp-lK#4N=b@TfwAoZ?^R!@Q)4m^7q|Oonty}tI4ck&+rD& zIt3_TM?c{N6E<o&-$9p?!Ig*m<-1d20n~+QPu0{my{p@X*am>jq zd|gUX>Z|m|OR)58un!@O<4Zii|&gSF@z3^~OVw|LpZE?d9Q zo*NKOd!k_pyUfqC$iwNv{$i`*4cWue>{^(6UaIpUok|AEW%Blh7NX~a+PLM`kXEG? z+bE37uBxi&vSr}d3WJlRrS^by?81wY6kyEs{)q~DsRnh_hMMqj+y8Y4IqiUV`xz!d zAQ5Wid=LobS5#dU-{w1-OgyFn_f*EOU<{UHiWxihg&+3hTsa~2|vLJLan2Y64a;o6AGD<9+ESppxzSXum{Y%_k zeZxdf`AV#f1##QDBF;e**tG>Nck8qxB>u*8Kjd+->lH}THz)=Gbiu0|i)3S@s7vCp zTp?|~Wu?<@D_B+ZTBz!M?_8;VC+T|8)31Diabe8A6wfAaU=m)XMee&y?+?$1*J=HZv=+RK2%TeG{L4CdNAGo(Fe%o=>mX;R1 zrc`!zs4)JO&yqCEQ&uFTN{vbAI#}_K>je9`FZe$9P5v3GjJGrBnC>$|{kZ>jG_!VG zPwO?7LQeHvE-*nbEeA7UQ+KpfU5gp3y5~>r-go>R7c<`HF%!a6aMe4^Alq_M97DTM zb7GQLlgMLg1WedI^zv|xQ5$t@Tff%IJ$T>_fGJ4cX=y|ih>f`C0+hR!qr$$NUG=Lc~b*HV)Cx!N56;A~X zQ8x>Bx_e7G1ygtL5vaF%C)(W8T0E|qNGRpz7T>9NEmS%9npt~&ockXz)F~~+dg@)$ zi@fUnyjRn#g9(rX4vD8~+mq)Wp*;79vCUqx84NEY+osm?#`XtSs)z>-hN|P`PW9Y{ z`BUTzWgm=9=1L8_eu`Ve2q27h(w)L7v(hdV<0=NC16VL~Uc#eIBMQM%}tXReY~C2eI`ld4_*S^>=>A$4_K4@^GZ6 ztSFEGZ$0am9td8xw`O42bUVR}cJD-$@k*z9-mC(;rK5=&qydfa+TMD(Y0hV#TW{hW z#t2GZIpa`A9Zif&&HqK6eJMkP_%Wm@QvnwQ8q zAJA*PM!j)R|NYrVVj?|w>ZfF6qesWM0lJ~$g12sEvWx*v3AE3Zz%lDff!dVg-nhwf zO@c*z{P!ASMRP#$pPszyMO8o+xdrituftF7pNka%#3aJ`Vd8dmm$lHBWyPYZtS1_` zn+5dsyb?)Q$5*}7ub5J??AX&lg^z-BtTMZvOwG&F0!);qfOpHrPHVdg|YBd+2Nj zyBMt}T39}AvQXAlL!`)p_gDQS#pyjU5*Zad;W&vaPQ=-^ef3Lk$sm}k_=g?cfm-om zOPq2u0GDYB3>g# z?M9|+TJP&YdJ=*d^FB(z`KJ2=FL;pL2K>~e`L@*)2?N4~#QYofSt2s(7juM|*i5f_Hb^*Ma6G>4Aq?a6I;eqnP z7oDoTspn%xdq{)mN4y)daFil|9LHi!!gf`Wok1W*CQR2quhu9P3;pV?O&JVGp>SCR zLIb{3Vjl%!P4ld>k)h{rW`^K53?2vLg#Xn!=b0xBsG9}>_Q}}^Lr&(f%eQChlk`&L zQW=BIzZPv9ytjG`MzJ77>OiJevV87zcgeWXc|7m~8z{&k9_{QOPskhi${i#zh$r%cS9Ah-2btc6-e&Z92Vz03%8OiQcwP zPW#Vn{>tX-Ht_Win=H&;tksK12*k|Og0Pee2`F@T(Qm?IbK=BB=0s#{d&~?*4|$l0 zI?g{&gdR8zV73>|a=jweed_S8w5Sjcfk5hV$?96jTD-8~m_S!S$SVVTk+YXLwR#C0 z22uZ|J7}2HG`N~)c-T-?bOHPTB31~RSpTO9orVqUq9&>`O_&zaWQsYGJp|Z-rW@A- zL7CRH|99kyg^n7$^dbO^PKE0=2<22gH9FNbGLF_oF&p$6(Pu9b^dCbb7r?}&G<8q| ztE5N~NJOgp!&H3G&YBtJ4Tk$a`;@Iyh`df*BYAFM_|+9uz43AhQd&@M`h4he2{4BP&4IU}zx@Cinnq2t;#FvU>oR z^XmR~Qk4vZA-#B%>9egNuGu}%p)W|FpsCbQQu5e;nsRI4CM8N7xRQ7H3J)^YrJ%?H zfzXsp+7e+XApVIEp8;tX{+0#^KP>ta{>7Sv{Epslc zN#~H34c3+M1q|BM)`RyZ^wbdgKfYOT6%0KkZ3^&&MEq?v_`C?{zRO$lcQBn!kYzyw z$cC{gJQe3=v2#`k5_DIAIT-4UD_2e8jM8p?cUK>W@vEpwo5XYD=74egV<$3Rt`lRe zk?xQ8QMb5KKCkdZ2~9MdDbXoi)r+YY6?oJtvb#{ode5q~*grML#Y*jkF2gDFEj3A3 zNKZZ!e*Usz+69PHAXYc`Ht0Ql4K`-XZ~>wmr%eEP@K!qil7nw>>D~1}iA#_cF@g(_ z2Lrx`cOj663%@Tw-hHx5)l-_P8>uYIh7aAuO~XIOiwdjzZwE-nG>MDodHJuUdH>g- zHtI;{-v(6q!@H)Dj5H+aLf3Y+YaJZI->%_pg-`}wB#Fc zWPqDy^f{1kzeP%1Od8y+AJTvaNt}D!A&+Th0tfn%<1z&D>ru#&217vSCi9;XutZ*_ zIPWF&hU1x*5(F|Zi-Y@1f&?TnU*nyf@%)&QPQ zBo{V#G}wE>x=2ENHj&@g%7(G7^vtA|)G=pMnH# z;ez-(p3q>+BrZbU-M~3o-PO^{6|eQNZp8uFZ@{`KsDd#H>()4IFuJ=;4>FudOTFH| z7D}(_G6XmZ+rjNdzkpGjD0vq63)cy1VTFYSwyq=)GkQHorXg~Of4LaWioEFB$4X}O z69kgF6~GR~N4b~$%K+hui>Z-r_2WfVmE%mljiVPJ!$%)+$evHl5=2w0wr<64^T!^D zfB4o!KBa%SewXP;c>afLfmORN?Xf9^u0F**7a_*ToWD#ARJ#P>LpvKk0;9nujdVnT zOTOiP_qrO8f9>Fdm^CWAn(C*YpLBe}c+tJFRmi)lXh$I&H5tySIr{V3GGRncf$ddh z;A$zlAPGp*mBjFBSogEDqiP$;TA2L{tizlyfxpxV1=bKp#b6v2TVKxN1N5{-3oBqb zJ&+CJ>yB}u+SU-U?=E*s^g0iid_{>TkhS&W_HIaQpaeOPZTlJDM>ssEar`Lp8GFnS zut_{&WFP`8?v*8P43mRhn1Xix94mTOCUea9#*DOW;3bMKKSei<5F(a=aM~>{@l&~44cuQD_S^SaIaE^p7+hihnFGVjY*E{IJf-$-3vPG$Ec=n zBSlp;FAE+819EW~@GZEBq?|0ln+5*Z)<%ySFrAS?lt*;N2>wMWf5r`<)ER8nmUpk1 z1n7(A-8A);A*a)%;^0@Pb_FUyv8>@z&-*6r6s_Z)b5H{35kz8uo%;lkPGZx7T}fJWXY z0{S{A0FziP*^gOKS9}M@!KIcW>g{4_>?`!7y<6qPnjKA@1RcbohSZTC2b1tQOkHh2 z%lgE0D?D(zpm@EpPmcd?OGTT6}6FJ%`XIR|WO3ApIM$3;iic!skz1fgpj1j_3+D zs|^kW%vrt;nY6i=HnMBsJK!ZJb*XZb_?wYk;i~5@`0a6hoBSzA3;$;@!;GOTo^VY= zRo+Vw&WaQ>jAsk>YskHWmsZVFLn@G-DNpgLVHeM>qmG)&l%bI*tHM)4h<~FS71jht z>p&c>7m$v??JiL|cFcIL`2JVnwLQ8ig(q%}l_%5BDbZcka%rw^(QO6-J;KLjUD?`3 zJ*Lu2^)S>ZOp5MaEy4Cgz6_DmHq+iRPp#wa?u#3d5YC4zTwJTAoo@BNjfxAX2l5wx z?x-HtM~i6D3*eE-pFPN4{?pb|n#Q$B5Og%G_mPv`;Sv-|)(<}jcDumBB0;KK3%0{0 zs}in{uqj8wN2H-U(m`Zj$C);^Pbl5mC^SZY7>=UvhY702x?MxWfi=~yQvMXwc-;~* z^eD%=d;(4y6cXZ#;aI&0g}N{nfKCzaMem+~-ZUe~6?EXJTL`@y+CNGPHny87D{C)# z6B0@{(FXFAjqFaS5AZ$s{M1wMyOZ=;p7V8`$kAY4RdEXP{*T`LAK*#2%WP#MmqS7( zstuj;VXs|uT(2>`cDu&n$(G>!&1-Dtbm?Z1%@I~krj4?cXRrvH9RY?{$e)*6_;!-# zENmApX&{-7Rcd)(9t?#-nNBpEzQAy|9eQo4Z?Sly4cldF@s@0jqDMqVL_!w1MeZgs zRZ5OYzj&-GqNRFrB&Z1WNJCe#v&*=9ozR$zLaUF|D3sU;#m zxy;2z-$_)3)qLeS(R{R#(ilwk4t+C1aKtrq5igsXk_Wx5Cz$~^9J~LrM3VkU1i0sk z@&9$11P3#x4Uk;D_?f>Yq_jw|{{3@3W`xWqw`*>}nO#P~@dNg!6ZL2x@S+ic*5@cT z1f?M_HD?|XbBmt1X$ZMy?Iq*EnP+8+>DD9itSq!C##@1ISHRsG>3kTtTZ4D18C$OQ zuA$V4P|y~5-Y;{PF?y8YB~$t%fXCs<{Ae&F#Xuik&YkhZU4{iENL#)16EA#tMW=VT zyU@~Lde1Q&I0M&nW=1)f{XekYc6j${mEv=;jnVI-{vugu?Sj|5S;iuT% z&535(z%Ikp5soBQK?Rys7HEfV=j9c;f(ziKI7i=pnjpau%bq}JNbB4=QH8zFX-_Dn zstUU0&w7K%tALaB^Y3hz7C0PjylF!-7_OhKqJ0Rr25)uVT?O}80kffbI?+T_CmPf8v<9#ZBy znMTV;oS@mo(fs{?Zd!hAFh<1t-0v9K7^$gPcohGv@Cu<4aoHEN>$Z{oBy@0lp4A+@Ir5Hzr$X$mOBw^CP>V&u`(#@N7`D zUU8Kckin6&L#9HPoV=g9_VhXn3!=9a7g~xR6Qyun3S@@^V1-o$6#-3OGBE<`kk4Ud zZfD`xDs?G`pS*r?Z+my10y!dDA4PhBbd-TH1AAf!;>zBF?LfB{cjeNk=$r(pb01-^ z-~MPa%!Ivu{zOYP*EV?k(}Vdj)6=R6f~Ow%mSXOqi>Pz!wCOvSHHrrd6^<+ekX~ai zkSDI8A&WY^Y?HRQ@Hg)~pY{W;Y80Prvl;QbVPch9!hYp%*+17Dpaw%BOU1oXOczVL zez?UYoo3b28MlSh_>7xX7<+HhZtLk(G#C2)==O}9w;HF22KY~)i-2~8}y90v%!jBAsVi%Xl$8LYpfd`!u-7kzd(w{W8Gbq zB2=M0cGUV?<u*-`T%Rdr^&(#F%eGd=Hw<3KM8n zX`$=7Kp71z-Ff=TSE)1Ff*~|GIh3bOjgNJ^jF1&9)h$T6`lLc~_;|6XOp?CeGdiW4 zh&nEG&+cP@VCW=(UAGt|AooswY%_H?Tz&;YJQ3G20lY=*nYoYT(t@ zk4MoVCVHw@65wAY=^vv=mbiPU&*#ectz0wRLyf ziy16`Y@hmP+ijYcwLXo7Pm*|As_YdYy}o5D7)XktcD&4E8$XzO^OfB|VW{rqXSrD+ zoE_K>Zg~ux$6)+j7te>z`&b& z83*HY1?Voyr9j zAVK%25?%;K;DGMLpcZ`m1@Uj97cv&)e-}LvejYx29jLP{>bc(cl7c>5#Lzk~DKrBb zjCww)ke{bF9%N~4Y?$cb+I&gv>i_Qk~_&YS8tNiW`{uQq$Vl0;`c4M)zo=7sw=iQ$F*^{vv2b3r&AH zqt)soNmS$7#F19n(&dKwh97`wq>+oMC!8g*xv)2&{NO-=afK-gpBBSj$KM2bi*=O| zdPz?lr;;E#cJ2wWw}x<{)90%996}cv47+mP-=M@LzJaTy3w9aU=Y}{z@JO`Lqb+=S zw$u=;wfD_%pxmyJ$)|AM`z>J5oOq)VqIf6p>76gYV<3yporepHsxOjHwkDzlD0ATR zugOSDKOT@cT4*L$B*v@dLw;?mgS@lz&;VXy!Z)3KgNtodqQ2;731@$Yp_enbF(@%q zBup#2m$qh*YfFHp9bPwV(evixqjm=Txz$;)_b7BCuuS?eav20@ zB`NudAt8BNY0IfTV)s;|I6-T^0TzYxr@FjRk3t61An{4M+Y`0Ncm3>C8T zGU|sOa=e@MieN|m%f~|%pO>&zFG)S^Qaag+M7eSL{BXy_Smh;a^m&}T`YT4DSoC+f zY1wz81ZB#K2c?Hw@WmpVhfep`FO_!fZO4Qx@}5u8$_IY5YppC70!pb&J0s&_y;8ns zBMCi*Rhcf6Ur9fmHNer2hOQZ|Pp;Ii@0H{avE9R{>95&9iN#)3)<@8Dvb-*G^+O2qS=y> zI7N8j`3bgEK%-LS--Gz(_-J=_+6|7g7pQCO`(2XZM zgRpdqbW7-6t{Df_K!u5UMQZaeLzTwjTA}eCDsO){?UNoA+F{F!!0x4Y?Lw~36|M75 z7kss$_A_$-lzD%XOURf?>eFo4n}_@=r95#NinT;BVPv&lD7!SJ@?_V^`Vj?1)IqpADTA4LVjHM zWWs5A{_AL)v~i(h^?Uf_4Fq;g372Ao|CzVAGEuuCnD^J#2d5mKNhXY|J5K6XO4QUH zG;l@MYH}QwNO12yPI1D)ZEx_xYTN22%d)|uEqhnY-b3VatCw*hpLrpmGNIilaFgwD zXC3K@wDomQm!m(TD7r3d?NuW=VSE|Y8U+DcYEa;rx1USlug9fv#~)#DuCoHJyIn=_ zKa)ODUYcE3F=^owWNz^%L$EdlM;Dt$33eRC?rf22=GMB!lX#@VC#6|vt2+;fgAvfd z@)4cWM>-(eG|^j&l3^NgN&p3y_- z+1z8#`uOB>tclGchl*r(3>F5X^UzbCVR5`L2LWSVMjdqYM(Uw`V%bviTY z>%Ac2dQ$7_k^aSHT z6G83ppIMu1na27lpMHV8eaPR*6G0#6Mo!DN9gZ3odat!iX(<;%&WyLe;Y55=;%7SG zvoOEC|5NCNv^#I6B(f+6E4yIK4vX(3BlmF<&zJ@kZnADIQCjHF7h$9*I`u8%TB80x zW6Jkpy+An&?pFWR{R5_UKh;yCEzQ-tE)t3sz*n;C?+;wm`P<@IAE=WHLf_C#%P&&? zXhVGpuVb=2+&S3EcYZJP4f)8`vhyyt^UFnzUdr`5{YmZrn=w&Z08SfGbaPu{Wc}@S ztfC`qpnN%3jGa5D;IX&Wn7MC*mrkKikuk2WSYfWU4)}hM`3m($ted9RDmDI~BCaP7I7^tMc5 zyy1L|+;v4!8%wFQPdxd3S$z~3cS*4-@dqvS5uEXrbDf{UK}kJN8O#S(Y8oexw)k27 z*oR4A#JuTRM20rs`hxnj;><6)qi&TT+u>I&*`5^_-U;lW@vvK~vz||`hhwF^H>j3n z8z~PJsavq&>n)sNa!F3l4oYU*Qkmesu-k~{P%EEhSBjM=_D^b`*yd0}vc=(rvZRKX zzIn33vh4rYgh(Gv1gqbja|;r6i461mtR9)&C7v3yE-tKdK>pC@5EM|1ij>u{UjNf* zodzv(JYp)MtEloH!@A2&K8G}9c(=7U($~a`OvzC{C?D`l!y7aRE6tNjl2e0n1$Fz9 zrUaV!s6)S>JY2j8Tz$~;>FO;O@OGhb`?Dvd3^g={^jTEp1D`rSUe-Q3OC9xEoog}- zEfZ)(+*LHxu1cueYdiJvn;1e>OHR&{G_3nJX39-2Ih7!hHo`M~S!Cq*wQfiCW7z*N zXyAsFgGUz1G6k9_?Y(-r1yw`btbwqw7)m?h#wMIhNR2x-QlS8Y63?GKS-i9OjfC-& zm=V2WvBx@#EdQG!Vq`G3atLTc}HKQ!gMO8!W`6iHK zj>Hgc=2K9peG^=M&QrD6o0$|veplf>n-{|R279*H_xB&5XEPM&l~PTiIQdQ6#D??OPMyjrJ>sZ0(+IhfDNZeAgD`f1o|cR<(e z9vVdEvfIe}u7%xn1q`!I#n*a~2W9<)Fd}lF{_WWHAU;ri{LogFRgp~3d9^g4BlZ8W z_1;lUbx+u+ii#pFg7hLyI!Nyz(m_E$T4-XV8R@-?NKtx!rAh!%Ak-io#1aIA5YQmK z6N(}9UhYPJ-*?wt>-wj^CheODfyZH$g>>(9#2?H*pZ12ZPQKp zHok!ZJ#$9gnVrO37FkET`A^W;ZgU1$k<=kFOt|`TU(?*-(|#+^vj|EZW+9l;wCV##K&1bACfQFwiDmr&E?;ufxqj^{?iSNu4?W;)rw&uA zp=qM#i2PtgR881b2)VtZ8%cD?c%_G;`@F-UEbbAh#;mN z(g}S3Pw)6R_F}K5+GoeR-VcvmNoxa4i2>fe+wxcYTqvov49~pg!M`e+=maPg@kRH?fn=o9gn)e(<_B zWsxr{{&G{Uv}UTsqLI`2qwe2C->N#fJ4HT=o?v0h8Nqrf(PuuTpNV5aGqmhx8?2>X zbDP>0BuZscLV=w53!%z`Q zYgq_HX@H`OeU<$*bn)@x+R?4@^r&mr+K+S(3dWz}#NI`>2qn+U4V2&E@5CX4sIbSf zjPxe<)Eb6LQBM1Nj*=_}U`zsc?-?l+ITVJwmc(P9&^6J@b3k{>dsW$)k41Jx5%a!= z8|*y5Gt|{l{!sWslgRps_5{a1+fRC#6^|uze`Vj{# zMzOAy2lIM`6>GTF%=%-&LMh*=ZeIxwzx_$Gof)8SV1w?4a98DDyooIgM%}ewYS}*V zQS>^wVAJA%>B|y1l%FrZ^Qc00s}~p$)-1A5(&fk9PT#~382mKM>s?Ueu_-*h=vOK1 zkj~zOqnAu4p+(3JiLA7zs>m-D?-%zwVknr$_ zT;qL|WiN1T?CgGiO8(2UNY_s=BGVn2_KrG3Akp@HX_3|-ib2UpQ>J8G=SjTm)_oA| z$t^tlB`NJmN3LK&9XV>Pc8B+K6Z&>-Yq9So7JVL=UJfvPls6BiSEh?4Ra_3*f98(k zNI>-4_e1Q(d81PqKgy5-5Q56pj2BE29_2aQ#zl!lvl*8Sf2FaEXyQSnyWiiquLC(l zM0w?6+BB4mpO*hT(r@j@waTg16`2Q2BuGh4q`{y1nSL2Pb#<+smN~%`qIRf^x7gOB zP*_Ro>|yP2%*vMhRRLJi{G|aQEt|CWrDQl;`lbi+*YQ^4o)hICyPie)mc4QvptL5# zb~{UDFMc0;^J4)Ru5)UriML)F>-6|_HToiq+St;N~-NvhUX%cwXjF~F0%4o06!H}0}V*j_l!lQyVr zGH?#?NtOO6BO^QU%Ctu?rJdXwl#W?*aZKrAdut2AM{7rA{_7hiR;PP(IY-XL%bT&+ zquT<21wZENoixrVq?7<(wk>)hQ8EbWgdBLhu;B%(`5WN?baVpqWWGg zDQYzTQg0uLwjp|FduAaS|_6t&n$@zb@0boQHCp5kSJ@ zw)V+T;|@(DxHMN`mgwm z^71DOkIW}nwh9_;A;>J&E*b94zw)h+zj&F}{*_EcOLTr~AVkzUl)1i>#woxS&RSF< z>)m-~&x5ui!TpRPfT1s*t&t@^+W=hPjb~I(*1TSqgtEMiL-6T>xwycZX*bGSwCrS; zf{+gv#TQ?un?#Od84U79ONZ3u6&9SMa;FZ$3NMs>|VENJ`fC0 zipG&8<5X8-)%>U-klY5Mt~7TT=TfAI!#Mx`CbP0|i8h>@V9E+-1@mvS@Y=Oj34#Hb zC=m~&ENNe+#M3;7|9&|9Ui7k*7ra#~=bDJVy|9kc2^)78|8@`k`R$NKW%f__Z6&LL zr?{Xrq6}GQ;x8{|62^K~K38M)vPIUeu%v%7_?W-=El+)?am&%d=-vw623^N20~kS$ zR6Uu}`myj|d7dlFwZC(+p06EPa1H9H>l=d1gbkKNgL^Z8tcMr3ADHsgw0u(R0n=6E z>I(D}2Xnl9R`BGxN+(N{yb`FaAg?&n%>1(1CGzIktK~k?C&3mbzZny5>lu>=T6?ET zS|9$snMei2q5c1}S^Coa9Hr83}sz8wCc%D-!ZwLqw(c-j=d)|I8 zfn#1(3Ej`!+wRQg6xCCQs=;qGeLZ~rZ>2D91HDka4a_Ggl`BZ8G&1W;tkEf?zn@Ak zlLu0o*e5Ljv{nOX9e34w=FOvAHSW#GzK@bUVtGG+-lDQ5V@(mGtJi|vbJ(Og)aTs{ z1!S2uvcg@1_QgK?THxlhv={PTG-MW^Xe+qnEy+yr%#9)m1w8}u!fc&3k$uU(!stwA z4~}z$?kw{h^~P3CkHlwJ;Xo#;UGoD-Z4gCw=TpLj4O3Ju3>_QKb3>i^ih*$F{i@QV z$yG5(yu~LN(ZZMHASdoD7(m$JWnoS6$`OP=1{H)~PZ5Kzks^_7#$dOHS?xsN>u?{;!EDD;`Z!sq>_dTinrMKnvv$x`2b=3tp7qK%}pkr8xf0 z6`$jnaL{1?O}fy)Y0kXU`Ru(Znf&iT`h6b`js!p&b+-F5nZfr5l8$Izky-bTxIf2{ z=~nk(I8Uvz;~9i?{txK{WO0b9wwHsEf_?5U5#{>Ze#Zv^aKD!pS$2g(8UwDs zf=U(4-7)8QWh8P-K+)kz{&$ELM7dSzD^8RB*p)s%pY8;gYDzPvCZ{ z&+6BmMrqA^OKWkq6X0*>!AcvHScc%goi|`V6E(PIz0E>TXR{Ty8IDJ7LrZOpF&Dzz zzN}w_y&=&&FzY(n6vI94+zqg=l3VO*dQaTX2^%N+Bz29=D|^beHUG38jkDcM`=gM& z-th_EE0KsR@uC%Wr5P%;;y`tG;`A6HEZ;{ObC0H50vOl$k1 zRtmuNlYj)te;Q(2)~Mi`^~HJ_gT=jIQ7Asi{*q=Yzr!Z2i9O|ZfG8$bzHptk)%8Va zyJcdp2GUXgDVzQ+Fhb3+UemV;x&z zWA-;QiTiu0totphw6%)uiNDUbSzxh3atrYOwuecSMTUeYlfTm1b&e$T5zh3WC zd=6vryA@b$p+d)ZrB(9I?cHZPLE9`#D9deS4e z2W{6%>qli?EcDmVYz5JsYCku1`*gT$kXJ52LTSpt!DO92$}(y(gI7KjZy z=P0;!7rt<+(-^r#;*L*6=}OPiAMyHd{lr3R(z?YxR&^)Z3=M zIMl2xn(ZQQ`$%MExT!0E3NAWyIu`J*2BWvnCYyBV63G!&Lp81_^DXaq_twW0`iilT zi{TY`#qyQrq1E?wao7XGaj73>w_t@DVm%R-aS%ZS-`$U@3r2P`w8-Ypn6;nE93AY? z`)|x##C1DDb(|+5%=8DKM~!;?hoU$lb+bC0qBxz%fZ_qI0P8({HgZtj(6rDK>DlOeVc3o?S|$z9$OjitkB^Sqdz$8U;aiscE?nuVdQ zbfW}ZowZ|A%(9oC0zq@ZBU8iU#o$uQDo^Hipwin_g*RL5^|w;EgIek0Kd2Zx#u_5s zW1D@#Jmt%X(+eHSuWP<8Jrh}x?3i$h39Y==+I0%nSS}Xg>@D9epc&=+gEJN7=E^sLK9r$wmf+{Wx@^|;#+o^hLo1n z)jv5Jh2a%00-v~o(gZSKZIAI}m#F+DldA1oZK^Q?ydeF>(WpfM@tnH)&;MTi{OK2C zjYxlS$kF7gi!&7@$7V259`N;Ccg|=>f`V$f^~x_tp2_T>f>?m{vEQ!8@@d-8x=p%0 zrJJG{I}ayfzxU3ebUc~PdaK`1jLlgp|57ueay?ocmAtv=oTQOI+v_L2Zh zL~=sOFX*FNEJ8iSAtsg9Ijb<~1lGRWpFM_K9Z6k6*eKMyPTXO*xUDRwoQoJDJaSva zIXKS0u}a|6Uk>n5+H0v^#g`sqw)g2PZ|yCj*)%s;ljdt<@rsAU-eT*^NS{_eHP)Yp zeZ64L$&k^(Hc?l3NPOqM!}jX_L{MT`t{b?VTV!;qx{Uc7TJpuT0HM`a(AhlH z56|X+9SAuWV%jXS1-cEyFd66Gkou(STwH+KV2%9vpQWQ~WZh?Kmk-#ti8ZB3_HrP^ z1hjUW>u`QQ+xtY`q|KZ(T#+$bwdkYQQ}4NGZ*h>YWy)dkuJ#fg_BzP3XR&XUpCT)R z`_yr(La*JcWOhP=EIX0KOPrs**>Xqe$9BBcO1p1jt_6tj&v2_{=-KjH+Xg5(ST`Ko z#dRRFW%`}#mJef7Q4 zW$Oz@mhhJB5l`_$dw*6#a{3Anl#q2qCpgbvt2kLM-BI1AR8{zr$NJ^wowCUK~E|gf?=G~o3~(Z6`4SaPaYwd zi^(k;buFA+IcTdx8Zt(7J>&3dR`e@Ru6FJH_G*h#Zb8GM9X}E+Z~5{m1%07qn5%GT z@XEPy{X;^lP=-fqCWvRvFQMbSm3kR?*<6vLP6zrEX1LIcspwr5zsf<4hr0tAW2p*` zH#^tL$B1qT;c?_t)Ah_S|4=*(&-AwGU6(iB>u?^|5gO9ITE05AtTcI*{h;C|=ZJg7FjY}P z2q_2Wh#B160;mnycmuK^%&dI zvlQs2j>HF+$QEgwbjF9aj147;?1E93*-0Pe()?e~*z6d2-wVtt;3ntTT#h4C@!xIc z|Lf%>zpNCeMdGdCvJ_87Z{ccT^Qb9i4ST|%>(OClVwfiT=10<#;YQGQu3b@CBd2Ja zm@U83IM!K9&%3v`a9;DviEZeuw zcICK<+}=X9-HW}~$D5OrXjM45%lab5X^^k@K^jl!fx#)2%Kk4mu{T=%(8Gkfox78u zMeKXA#-Co39KJelrP3~xZ|A;Ttdr5hB71F0j58VkmUnxT9RiL=7-~mY(07}ARp}8= zDh^sj0>>%E12i}PVxfgeTcNeKVa9)bbSVKAlb!yOX)sbKZaRRjhhbcw`AaBf*X0>^ zeTl&>iMg6eOllFM4O>1gtd^p?=5y?<+50E?e~9rXGZKQfKXfuUdNzmPp0e+UhBX@6 z<#I)q+uOa25lHJvWupi}}HUq!xzVLEV1k@znn~ zui7XbaNb@1oBapdjY_NFY z-)lO^U4oR_5JfHxp|@JD~C+>^b~j=fNoo#0z$V>wC8ZX6qW()I}%5mJ$T zElaEV$8gI;Ek40o$Rk)BvvYz7;1G#=J+wN8j8AtzP3 zc+l+O%2rZy8Q-&49&IfZ8;&cp_>!*JE+pDdsb;0b0l{i6>k$BIs-srZjQF~*tDKHI z?sbWV#b&1RpMlJX>|c;kAJyiMyhGXsqqcsNAvNY)zsy8+2>!cH7FVzM-}=KN`<$k^ z0A$_v$=en1ip7*w?Pfs2;Y?_YiRSpg+6y&8m2m0U+bmnRnJAWn2B2Ngeb*y#9jpcV zH#23hmMz>h>^?mNh`@#Mt4E)HcRdRq9Ap%Lfq&U=x%bZN;Xu7>h&PGd-U-oh2yb)W zv1a1>QV_{jkoB;^CH<0X+yjT9e7pDVBF#J#SFgUS$&5Ol5GYBBaboo;y4(gDmLVmO zwE7NSM??7`FT#%gTmuIsci@xNpx?!rSd~KS&bO)kA)D9bpA?I!h_vh>nEutQfKVOI z2=x{qR3*z@ycmwNe`HtKg?0CtE88EKBGdnUNqW3@hsq z0)`pCsM~GtPKDMwNhfDIPgm&oma(v15%1&k z*8ilp)Vs96RfVq={ZPHXuaj#;hP+)4|4js41;K7{_kwrou6gMJx^7&6uXy!81%N-M z_#5DaIx0>qUvz$dt_@~wZo>G3UM!>M;<&5UD(rc9c`f)twNCnt@Y=f8p-*Blv7u2e zw-55I3*aP6evZCadgGXeN6yUfCe6_zPPG-S{8hJ7x8~1C1w1ax*f z)&U@zksK?)@Yp6pT~IhYnhe`#Io+gh@96Tr3`pIaS@fUOF*%^D0__QXATAR1XiK}8 zk3Xv>)htZ4H_wQz*E7xJ5}Yu)j&5COb5d`)eh@n33YXauTn$of8#|TWuzT@;dHHwxTX@i&irHp3MVMwOs|B1 zKAZ?m{>k&c;pqcVRY83j!ev0pU(OX)MccK59_C5-OTeG9>_PFubYiy6DI@5X%uXi* z1*y5Z-Vb`cCmU9AVgSC)mvKoyy+3|(@2}jf|4bcWGvp^p1e2({o|s~Q#cNqa6AU1{ zABex<9lf2K^p)-_3lzibA@6VO+^U}(+cz6Owi4B!Z~N0E)vHi zYEZIwm>>4SHf-n82I8eDfN3P;FHEE2QMfiP>Hs@Tf*tkSU)TDHK87YYz&S+O5=(&L zUP43a=i8s+kHvtlM#!pWxXgG}ZMXBiUjOs$>dvla8%aQZqHOPjj9-yE#iJ2`X~tbU z{nobagkK}l*zA{;Y6LVZ3e#=&34HuRFukQlNi3|e-tuM8LqJ|YF56{ZI?pdS#hY;Q=h|r z2Qmm@Vx+68#|Rfoe5~ldL0jJ*_*`L^eWojxhTFn4aS%ELbN2a5OEDkgQ^+m=L5Llx zG6LslTAT=LyW%B_eXOoj;5b5PWf?WvR`NXNJwNX3XII{(y~q&9J!bpnzc$CHe7a11 z>U+wO*CMN$V!thm^s)XK_tzi@m%=o``LkbrAE%mu2c`gPH77wn+#E{J%U-x7PxwgW zzsdPjce6Jm#z_N}l5xvNJa>B3QFOi1R_RmjA=Uccx2q{aK}wn{P45H#>DTwgY3W97 z5zk~IZ}xAi(?9@szOLB<6GyPh;^L7dY_6r(RuER{Tr| zif-6lywaJvA@1EPE_SiECATB{+1NbSeYI{idk&CtZHvw;hl|9>rB z8XNQc3^pQ(44`;WgXX+~YG1L8^{PSnY^&wyJ+v3+XpEtWM`mwW3 z@3g9og?PUNrBDr%U-``*V7;>ga{tFaaAeRkZfNmpzS(o_p~<`g8N?7)UbhOG47MzQ z!~t#YM35nc7?PZ{KGYJ}W_=m+-4Hk*Fh=J8YmCFc#^^3BRq>lWlMBUq|HD6fqsWJ& zen~Fx(n@2UhAciv_N;(*$Q8HIcbtJ&zDB59WH{AZo;f=*3+~~HNALK5e)G+S4pKwZ_vY1{9;kaNs$Te|FtriZ5_XBmv_q zzSQ5Yf<(22FSwHnL3JDby$wjfpH{EWZZ6#Td~=O8I>sp-ZA5BR8BEH7AQV|STes^E zfM)TD9{3Zrv6E%sVr(3OWKP9zi!Shw*!(Yl3@xktFNF~Y9injwiRRe&4vhu774iw~ zCD-ao%1%gJvDt_UQevY7WB~bgmCi5@Arzv;gCL3x9NuN!OISCxFadR7NlJMJV|69hT$Ze{{s)x2p0LZ_7T@k%~7Lf-%4$-~XF>#^Ulngnh`Fen?qO0KTJj zbEBeMU@qYNyu$aWCDdp`0E|kNx@C9s!Nepx1vo0KHb)y>6?g;Z+`yO%Dj9_0-mhD9 zf$NJ0;}t}{Goj9`3b$rYmHdL;gpD!q3V3@3GlV z#YK|k#GC4DCg__zUXx+|{n3=U9A-4adwf;V3RWDd+mhru2B%dy={gMJ&(_Lxyk=skVc0XbK@@~_juL7vN zZ90MbfFYBd*huoR5dsQST}s74rC8IZxil`au5u+_rV=;LJftlR6e0t0exZB&1@_}_pNkeCnmu)1}5W_;U4~<0X(RVae1Nk(_Ais%gX3)2}WiGak1+w-i|7NG4zIeVoWL#kko4&$> zW_p;O=Fv%3{L`hos?nf5OU9Os)<;7IYbr*rz`Y6YoCTiLSV;U3>2U^-6h~ zF~YTZK9D2p$fhqbF+IdE!xEiv{>Z@b_3@7ueyicnoT6lAavLoT4_AFM=Gh6N4;nCO z`KJvc$H&F0K1f!l@%8N&Do4hC!YPt!a}{zB!%K}N7c0(20L6mF@UtbDnRR;GFWGQX zkF7c9IgRt+(w88jY`(GX5@@sxiVr3cVoasM4cCP~fSV}X{J$^Rma}R6#yR)e+c3cT zouwWmsy*Ae42H0$9;$QmmtR_JV!IMCC3qU&`e(N$?B1{%)7qo4vGsBN-9}7s6<_(` zIHKy(MvHqped@MtTi&x+y~A5X@J~nk25p0_M>W#Ir)UP@5S{kDkwzLuo~wweTcA<9 zlW832L<%#8#e1?UOp7ePTU zdG*KLzf|;%o&<=n+81cpQH;t9J0bB0t!?;%m9~1r#47Acp$tO-AK6lms@}Wcd(txu zf`nU&uy=va4!gqg2byy3kzF3y{!}ctJ)CF(w@x3u5a98lyY0K@?nrNqr)6-9Pkwcz z&*+BRpOUasEcTE6WC+g}ZIB-VaTG0A zgA2393ZM_Mg$6UEyW_8d+$PUYZazZh(t?Py=GfhnMBm}($$hE)5`I1o{mMHol5S7= zqtD2iB3G83PjQ51&ZE|$PIuY6cF3*b0-i@G&5~bt$_(j)Ol{f*dRQ_M|8+?O*AQzk z7DMdz=^;k6!02ZeUwJDxyMjh?nJeDKk7cG4hSlqhqw6Gkvb;&<C~T!pu#*Rc5v;jvMP8SKcz3r#m(J^ zBfXV5IkPH$m>9^boA6&++)zRAq|;wQ>u|Ed>;m#SmUWrKi8@+uuE5Vf4Nshw?La$B zx^!0IbUP8R$%5I(eQ7*sb+z`5GX26mF*`Nh`>|pVPVg!vCqE{wUTqNLakA}gVuPFA zo5A9RaM#P#gRkDds7M9pKH_mWfBcl)QNC9G*O6(ebH#71A-ylaMQCP6Mw<{nl?f|_ zm+7V?yTlVZw%;KNA1hJ3>@_%DJU1s|>AO{KDy5-4nqldR`s0DK>~TPhE(Oa}mMi@k zdXshD3mlGrVFFb0Nb<90Wg=D<^x3{a6V1_-OLt*1H9`Ewj$UYc*6goB_kl2rJdETn znAyFu9#=^XNxs4Za<2tF{>T=-wKB7bPhSiO9qWVmN2m<&6ZrJg4;Z0O67;zBuWn(9 zlc!7PPFBN%Jc#wKYFw0dNFN^7%$S&W&j*8}P^PJP0a0<`LaeN+q5HNiDA&7|M9PvC z7Y0xNd5VT0s-jLFz3dHTpXE+Z(6G$$gtw2sFC2gR$w`>iv0%R~x@o0jyLaM8n_44N zyz!hy$04{At8STPM7GkZ%ocDk zck4ZdWZb|V!nZ{iy7F|wSBavn1!;E;X=UC2a8u?h z#*ex-Q2G&DD8lg_P3#Arb)Pybvfb26hR+FAGC_pNd05|;b~}~~tZsNt4PNgCwfhv$ zPgd`K0V|d3bv8UkGk9lF{4Au-K0Y6KJUz!o6LP~&_)h(J*0ZIuYr$08vY!te+#Dti z&112$)2$o`fsxg2uXHfZ0x>KGo$X&Y_FsI3Uu$lKKhV|DLh#In43mOON3Sm&Cg$eQ zW-gkQSgYB#hcKUtW`higC?q9Mx$@7igX^{iv zo#xI`1!K>Cmj+|h>c{VLB~)RV->NVGyk9a$z3on);2R2QzKUU3lC?CFlj&B@{-sz~ zp{a8LPRPgujUUueR%u36xS8I%h&}A-ArED!`*lq)SqJs9rSd?PKqqX?xUw8E=(wI* zvNKiZ=k{sxBs!>SC4-rFsK%Y-d5rdVxutU^#bd$v&6JE}A1NkY5EZ&Ck&7R*`qw)T{1>AK71&hCZ^@}8>m^^?8-h;VZ)WQkA0 zxUa!;0(@AIr7#KZBH|mt60b*deDoWQc`CKUmkvl@vL~r%>0Ue6>$^+FAQawhRUH$^W z$sB4AJd~&F)!A=>OFj06-e*7-&py--aOr95j(vQqlbvUNOyq398gpaW+y0)b#~swn{}4n& zVvaFFzieqW=qr9A?xN~*S+eS3_8)V5;Kq_i2vZZ01C(*0w7UE`qrbm$8Jsd1v>wT8 z>W~q3Ai`t@@}I;7qgC_h{f}EC{JjX&uKNeRM{D6h)rYuj>R%UVak^UEh^I|crS71; z|HF8IHy5yD_5lgpI@LeQZ22S8eQCDABoNMSiOU2B5)WF$5c}g=mH*1AN;9BSFw2to zDmrbg4=B%f(qs3QsG|7Fa}U;I5uf~XZj$@6zj`k|lUOPWQvQkr99e6}mD3el_Ai3O z7C+~Fqk-xe<<2pbSG0Fjafvb$Ilc7Z@1V6S331bo>VC z58CuXMUZyaWq}bcjUGL0Af{SR?#RD>50;qgpeB$0d>hI|22T|*)5)0sOSAk=Um>Pu zBkwP@d8ZXmF-CCrB)uE{nP}}>WJqsV&j>(fA<_x)cMxQM%ME zr;oZB3|uPy+F?XLQ=(^s=RDs%R__g-flQaFrZ`Pjmzr z>K2$Jim@a-_`Re*vLTW%NE=}DX)|u?!*$609`9%#NN-NoQOR2Ogp}geS1)sgjq_ms zL3PXtr-A&r}}@+Ul0MDU=UP&N3QPT^CT5s3Qu!bZy0dF%vUgf;pl4f@K&Xa6!HEyw4px z*8R}6Gqr9k>$yz6I^rP_>VK-#uzj%dC@#FtRGt&!qQqRGS+NWjSClgZg}Vz3iZjO3 z(0O)NNk@Z);;B zMClsR`om8Te~10yK3Pt1n<1{Yla88=r0yc?1|YATRvrwTFV${jM+P`M2bjafbgwTl zc;SQCfM`w?wpKz)0Ucu3+xcdbUQFL;NqY+dlQf0ims}A`oAGjiIQg+dS3~2_T~BuO zjkD}4Jbzvg4#@&M`p`oc5K@$*O&|@G%Jv2Q{Prt_b>2b@AY#s3};;|WPoS08%E;+)t#!V7Rs*+4L| zL$(7*M)6Ll zi%OLJtrX=le{z8kxCGMP|;`x6_#91_D<{G2%#z)r|iqK?R+Gel2H4w8*c{s zf;JDkSMJ}md}7D|X2_6t&VFF6ZJC|r*2u%J#U(3ia3bJ_l+{sSs>p#Nk~Se z#|ZG3l;fEGj%@NWr2UuOxQ_J7L*vcmHRl7+kLpIzjo0pk0gkApRm8j;1C4pmqlj)=HpLFxNA=tWU1}-SI?s*Nn_2vAXS@y6K+JqcM!p<4i4*dZ6 z4G<+!b#!Nz!x}rTb*gEt9S8ZsI%O)N@e_h$LF(!W0MX=JTb>rbr4?Ui8 zXPPCZH}Iu?*b%P4e((%3Ivn5Eq%+A~h^o8C>F^PdOhaQUp z-wb1*)Q@twjTIcS9KP3(t4`_Vvw=;E0n?3yC5mY$hQk<6_hL)dC#GTZ30=wv0kMCv z=e$RoMwj$MiY5yOIhdrU?j^<& z&ud~5PJ{*3Q%vp_6$(ie(|#T)Zj=XrC2MKZSYg)8D!GE48yUbA^X_6E-~J}|45`t( zZOO1VP@<*oEgU+(tN~^e^=R^gbCMH+Oyvxi?aPypCr<%B*zvxNU&wTW?`QA602Y%x#L{Qi>}L=$aZV>of8O8Tk)jhO zxl+CL0aP`v39~+T8g?qa%@Dsn%ey=Eir)6yqntbNkDMl%0OJ?*;E~)tYv>@-s?$Y} zV4{NGRFEIx^LE*I*FQla$*wDZCmkHb#GlvV6OQnFgAd?fh24t7nOmQUa1de=-Hgox zPn!;5?x7(h8iu{wGS}wo;4;gLD5ieb5Mv*I^jpJ3_mju+>9hQ1v)n$LO3@yjw>U=- zZ6aW4Z-8qKvrl31wrI?5OPnI60L&ZGkTeG9kYY&LGT|QQXcKbHt%CLQ|XrV5a*8y2%V!3Wl<)p&l`PiJ$S|>B@4Ph%%Z+0rnskn7V`m3SB@` zvNp?`*XcGH>Q`gH&%+w)v;Y8=yClb>`#8sP@)IU6=xXKacyxQ%nsV^rN4K{Nhp8M+ z$n*pq_1cbwJcMTkQ{fp2MG6ankp&52Cc6AU)`N}lraidct4UsbqtA8>)Q1K<=uFM8 z^}E#HvMd$BFaXS5iS`!gti?T6)TfS?S~BJW9CWET?L{4(8$sb^*xoRW>|Tcs$PZwU z-gvNyb0LaXsPg6GqeJ%PBJ%%q?D1x7)&q zu45iOGRgsoF)_-;=`TDrP~edL9KbHI8y*aZQP;bmf*4tGmnE`abN0`^54W=btJcG* zAXnk~TSG513?ve;%;d@T`%>(J7_Ye0i&FLPO2w95Id$z-q~)0r&8&qhNi>(G&*_@Hw$fJSP8a1@Ugy}) zS)+RQTHqd;yY_jp-{x1Ia9L#B55_xuLi<*c*Kq6MT>L~r6!3Ffpvy;PajVl#ZeB>J zG4Y-Y#(QN6Cr8v%N0GPqo$UicaRZQsoH%a_F54g%q79E4!5Uiz4D4s`^k)@Izu z3!Rs0@mRlpvYmf=)pjqs{mX&-Ied<*mE7Xz7I^MLX_%G7FC;TIJls8|& za%4XyaKEZ6>?cXuxt=pN_9=eU??GC+Z;l!lr#UlaRkidS3uoL03;3Y){vwtXyR%bM zYKK&#^{|E*;=dMf5~$V7?x^=m(%Gu`&>1Kma(0(Si6K~HwXL@r+fQ43FE5{K9M$d| zWVC7DBW>~84l{>+1|C+qq zhp%+`)6m8QSIs>Sw7!;@9%a0fqn0snR(_pQ^#DgqV~O!k+}{$qAy+M1me}EC3N1# z=>Z>ay+^h7u954}cICFpT50FWmc;qjjqoJKlKt6+Xbr^!{yeWF#ODp^WWV_!#K%3# zTV=P5=6}9N4WLT0i)Q38)7Ga{6b}RKl`<2jFWay zsbSvcLTzJKpBVi~WvLZJo$MH=&cTDDRc5{fhf8bb>*a%FWmK=Drr|Ewn4o?Z^lM@N zN{4Bz751er)~ZN>5f~S*W;LMEYK!WlB-$LnUc1yu`Z*v~Ini z51Ld}3h7)wN1rM=LMIdcuX8a7D=X*^Gj||?{QcOYX*tYdpbkXSPP9qap+l*VTd zY)r(Vkye(ah)ag{(t~Yiu9Hj2LI&~?kH5ZL_fdk{JhZ)Ga2xWW6FMeCe*&*V@ivG8N=RVw7J++bW*3zR5Vp4?;vMxG+wLZ#5ikoBOG+UM0 zmRn)fKEa)|NF+iiJMWI|jZZm0f`l8_sMMlgG9*k2e2vZlrsf)Vd+f4aUl?&0&KmKA9zan=ahPW*=`yet@%dxhd3I1&SY-m4#lKD@)L?4 zY^cecZ}xR%!a7VXHgJyR8Ax1WWTgBRTsQBTba0Ix7RVFR(i25R0gnl}1<;KadK24g zW4m?&av;)c?4s^=j84?npwum{1NqR;kFMaFO&i~b|Lw>|(L=2@juU_cyu|S~!7PRr zkPp^cGcf}i^MmDlf$q~_fgfYo7r`2%r9Krd`YFc)>cojl)m~%|Pacf@Kt|qisJ)T9 zW(x62a}^Sb7>fMHtHLmU&>{YjZ5U*!a;Vm!%g(-Gmvq1l9Jk>LxVLm~%}go>>U1K9yC$19W4I$C<0@-od#6k0bb zdVW~}(G)ql|Lvou+kAb_RT?(O=-)A*f&j%up%5|O|Q zX>&R(4tNt4CGPa|Py&E%0cw7~q$!Gbw>K5Sb>TBJ{ zwuO}evjMw)$H626Nk8e6T$M$MCl{_agwAYP**Nj>(F`#1Uy=o(h}=7&s%L!Dr}gv5 z9+7ZfTgsqWzxbLJwD8lUvZ(|VTj~9ab~ZM5h$f-7^3D|B^ed5$m)=58sQ2dn<=un) zPTbXgZ5?W@1vFV_y%@jeF;)#$IY9SWvI@rLy0=T_j5JKX?;5$0-v!=amDe_Q8M*$M zk>K&Isr|bSht&7JmU6!_Xm}<;r99a{&(_Zejr22B8$aZMYru7H|FQ{Ql9qj~wxj?p#2D7Q+D-=k5o~MOtlkPGKV=HUNC)xLBPs`N7QdP$ELDDC#BjEzH8kPscu{4`YwV9s^=xOn+ zh!>C770lNm#=BxwTJr&MoqbkHkiT@bMy{7AGd>9@f^NkY_leIKF=zre=#}|L z_uAX;vlR84N}LP5t(NZNkM}=dnz{r&QPV2tfCsvh)#bd&|CUtxyCw@y8?5!vctPDj@!`o8Zl z?6t_2rv@^5M0p^xL|lYFD^!BGzva2@?5T5iKi4C0fEQnR z+<82bp$682X7rZ#g68?$M(FV!P*IAcCK@sb-Yz+#eBr)&%fV6OWw;f1F!*CQVDAbA zEtJiRg2w-@s(DGubU4XF$wDd2G_vAx@{fmY&Jk+;V7o%mE^J#~zfI^%22_X=6|@vxI-5@AjQE7k~o>P$knMM!%(R&k5HL zu2C`1C&i6K6BDHYRB2t5cba9^q`tdG2)&7G2!=mY(=b`{p$GaxgCUkjLGD3YuY>BW z5#Etxf>~To|D5VbNQ0`P>c_*>nYs3dEZn1bF-zhG3i%8tt^J38|I{&(XF@wiXw!Nu}#2JWku^ zhm2K&5E#3wnT#OJKDDw0ZvJkr<>|Yf35~ac-AfnLaz_9VJc#}6Tc{%jBdfP^#II+y zE93z_P`w8*bsd-=@GJcuas`4MS=1>P5~9vr`CkaMy zxu+VZf`0i!7Ghk&@^YZMY9^lDM~y^456T%rOg{!1g=$J zK?}AUnr2^|oE~3@K46C*nBK+-0XcL zMqsQIxg?Fph%UQvKmqK_-V>v9p~N>z7(b(`VZ-zeH-~gbejKd|qi`e{A4L4uD{}y;fam|hQ^v7onQlQgm7-I?+4W3I z5?@B|I$27N4sDDdg8f=$J_U^FU}R7`obVyAZ9W+fPy#*bIaG@W+_a7rM8?6}7kKV) zOu(57eMkb*3-`1Axhk%@>eg>7Tm&q45U>I}Y@+4~b0o1o*TA~FjwAtqU)7{AO-n4dnZF~~vax`UQiP+0nUS8k0)%Pu;?_p;5!BS3} z>>s4U0!WAT{6<|>yMI}k)%Y_Domk%E3Ssl}`lgL6dNj&06KS>R8cXXhRPNc_v~J0p z7mZ^#Y>L`)BL?Zxk5ywRd2;($*i6e9!Py!vYBmrXB{zEZocUh%&p-8~PlUey9k#SH z5xN|N;O@!#E*q0`eUgDQds(-{7qe}QW}*A)k-=O1viqRkkTa6}TGI+E3nWF%jQ0s> zdLjG0;#0Lw`aC8l7K#ED67Mu8M!zo{0pIC2eEc@f=bRY4&vmw&9zs%#n^rDCV^I$N zzs^hrSP44N;5(eE%Cy*iq*XvJbrMxx3V7OxI zJFJ(GsJZ8o5r@j5qA&?fr4-ZOA5?nr?zYV7f}nw+iDd~}3Z?N+s3(_y@HR)sT_gDe z)I7O~hDBEmslZpspLbLTil-O~R3lC|5OajG-@*0qkLn09d37uOk)5tCSJyB2Ye;rf z{UrQSiisQ{t@-A`(~{XUrO27qA^1C39l!+7HaCzDPa!nw7!D$erel`Un(-?Z)^SO* z%6wiHKN@O$BUuPWsLWl9vi__4YmZN&e=Uyr=JbAFggLfa9V#>sFu5b45^k0vi&dYY z`@8*I>l0&@G03#n>5PM~s>4+6ZUu>+obbMz*}_FHy1RrU^Mg0UFZByiR>hq*zLLA8 z=64l>PUBkrAh;K7HO+6NAfiHenLBWW7JBbZ`1{`; zSy7j6#N^yl#R33H3?Q${{oi+B1}6{H;_PlK zg#6kI^I!&HgR_RUe`HWT(_F)-ljMH1ffRRh><~-9@L>&-fb{j)wMo5 zzd{Glz!w$WOMg$wAP8hi6} z-E@7mJ`b&M45$itFfUH1&ZnW8_QJGX1N4DtoE*8Sm&CzpfSKG|#DCKE@37&MS3jW! zr9Fsee?(b`ul1pF`d5LWjQy=4ePkU#u1=v|=z*{;&a%&>3w}n~x-WGhBl7^M5uwrL zvWA*P+`nwAqoBCoc*{%yzLlR^D!96joB^62 zBI4(Bc2yuEng@+aq-)~e*&ZQ6JYaH!v*N`4%DSqfhtfwGgT!90*`2#42}T5iUF`{}_MU&eP{M@Ii)I`AW<$W99U*XqiyP=;}|5L{u93sTm3S)VU8TwQ6i zLW-5;h`_m%BV_63#fkc@23?G}AOCI|`2U0?iH2oUDRusvE6CJRy~p?TTGNeraej)P zy1oRQ_%(H5R=d$m8dI52W(FV1&%F;GpK1#N^uW_w1ngP?5kJV?wM@4f1i+-zIHuA> zi5*hcu4iZ44ku4hgAsyx=2lE&=#41JsQ57Y&0JT&&Gs%|h$w9KbbPvyqwV`OQLaZj zP-~i!QW>a_1NfST^J%}%fT8>-UA*2*4wVARF&60P15O2mF!xfQAJ?nV2H9q6a`e(qZcRfpW|ze_|7AW#}84av+Qdd-Y>i##g@ySy}R2 zfl=o2&S9e1FKcMJShc1%GW z-Kd*e?6nL|lW7PAg}188An2FTm$bCYbH8kE{FyELF3os~8~BDl`4v@L$^Eg^1N5

AF2yRV68(tD;nv$H%M(8C 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

-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

`55c0%AyxtP1 z!Ut7ofCOR}RPfv||3OR9FW{WEVnSNNCc^~cEaU6ENf`5ZrR4UdMe|3!jV77XcxUvu zpMJ+^zvfX!OdwS)jzs})xkjnPht1(s15|F_?M*S~+N1WZVfwyadJ*rqfulQD3F(0L zSc}No)F^$1YoJU0)OVCiD2?`?t6%L;>u;$=54I-Di3ThXmzp*avDnN%H3g}Q1y$Te zn+AD^oJ9r1?f4@zk9gWow2Iapnj}7Ba72qZZF4Hwli@+TKX!@BS$H_@q*`I2Y|5gJ zSc<>&2fw2`k^zq2@%A_)>Pv4BQItvfvB&-m>r=|N2-HVq?9sptZQ4H|+g^KCqEIW- zu2>M=O*;$U;-CG!TfemQF5i}CfX#PAVLl!6LC<-1_JK) zyUWdsb(d*3srxe2zPZ8s$5HcP6u2B@CKD%t{dJ%0XZwWT>9?oz?{;6)#7M@(7_j*@ z{FVgU?aj(++;LE6-fYi!u`Ay3G2Z=SlAn5M%oB4eT3cU6d{g1mK-`U4YwsU+=~k7) z9o?_kl=*SCJ+x^YZ{F-3YD5-=40$K}tI|;OF_7@lk>VO=FDu1Avp>8bEaE)s@V%I` zhtijaLg6pt?23b$=SXV$Chq9WhK=tL!2d&Kj7i&^5|USk^q8l8Tm#aBfT}MVszQo0 z11_l`S_qsFFXX*1E-cSQ!u`T#@}NS%t{NSYOAZAMlx0P2Bp9G(Xk`AHylIlp%iCHH z2q_oLx91)pQs6AZ{+fwaMO$^$;Z;7-E5)p7|9=!bRELD?_bnq!GBfui?o2v3&(>~9 zYvz26tEN^kdX~NjuW0<3X@oy*TpQ$a?>~EmBGdq|ji$QD6UDMTs_~n{MnmGmrsj&m zOl`D+hv{}1Du}#DYUR_NI`5~;Iyq;v zz@hgY)eST`OacshkmOw(vu9Wb6yewS+V&>~7n!dtgVh&FqZ}uNpWKN7(rDbYSMBVkku~nO z#GN$Ttvlf900pXk;IWb3*PToAT)7LJ-8ZnbvyZ$@3&zT9Tc6$E2k9BRwYrw|W+J19tpl)3!xQ;z`ax)}u+zIEIB;s>*O z-l65xX&L5$O)3nB1eSg4dN=5Bl-0OXVMjCZhz=B6jN*M{RnXIC_SC$>X+A62Fwx+x z7+k|-9h@)s5nn!BHUi_de`nI*KhwV1!ErJIa=P^&V*T()*nxM)L(bE8zKnV|`c>9H zF9C1J|Mq6SMm{1iwa}kRFF1_ov~ROQwbdE)^{nlpt_uydgWe2O|27gCkxMAlW?*~_ zzif(t{4#qu*P<_*zV}w8!Mz3&AA8+hMkCPR-{BJKCb zN;BX$>X!RT_+y0>??j^7fTJZf&|Ic(Y&5booH*Jw z&z*8a8A&k3Zq>z`=v0l?xvz55!U7CtuyFVF>^b=Ba*So-&ZR|2w{Q0&5V(EAfQrB0 zp!c2?oPDM?6u`_HX{EM%cfWyYhL8-d0XsX6cJFq7-xJ!S&C z8VYby5yO48?$CoMkRtqA@`+g zgRwJ<-U3*!IDhGo$M^HQ~1gG`im z#W{{tHTv8|P^pa1|3zt&1;^Z+J*bwO5a6Hm`L19q!-TU9oo>R=LIIev7ApI7M{-%DV>ijck*@o? zf`|Qe5&OW;-iEZGsTNrcZw%agPy)evFFKjxB>U}RBOpT{caNWnX&heezKNuP$n1jt z3dtt=!tN3uXs?h#f|Dxd0A5Ki_+Er<{3RZ!MQh1}KPtp5YyFPiR0%8N7araV@tGCI z`|{D{PBL58*RP=0Oz#ZAH_4QMpEebJ4lFEw;8=s+4_sj{_Mc(vHG!}p5d+5e2X27F z1HA-5z&m>vCwHF>c`ilvjypD-I;uj*!=7X;$*S&xRpTBpl_roLN^IXj(uU33{2!iK zKl0u$p#On6$~+`-tj-L;U}0!g*&fi%y)y)7)%N?Fv6 zV?(tcb?F$II({Lfqve^F7kM8OqBesqyiZLwnTA*uX+bZf?;me7P=J65_gTp}amP%E z{fAog=@FboeT8WRE;Jpjs=}Gt>P#x}TEPCs?sFSQX`nke=ZK0F*#pp>Vp9a8Z&U8~ zM;}R`ACcLp6o|akztJ1^hCr1Ay9ZnYFeX2t&3k6nO7+#*^;MycLb7^#xA2kkM4ilH zuXdHXAPDt=$-&X*bZ2>ToX_l0h9d5OFSv)i{a0#-~unZ|Mruz+rqcMRc3~gUYaey@EQ{9%HF+wdm(i5_UZH$Oujv|xgukG zcRjToSo8GF2RtXq=emKGOHyMh4Bs=W^|hcwHbFyoCd*i*&Yh`QwL`D=hF>kw)}|eu zHMtqJZ?-K}(fF9wjtIP{N~-}~%s%*yZ==tr?if4h>V-K-fB@hHAHPSjV=Ura| zstQ}#A9y32l=&4QGI8{5tW+3mPHLSLuPUosDBl3ESaMD=;ju;USh9LN`6X!gQ8Gw@ z?Y+b(s%ORpLqbpP$5JS<2n8;K$IBg?>z{HZf>LO3s~xm3bZ>8CZTM}C+8er~-f7df zLRl&XiS_i)FsXYNogGV4eyMh4Qr9Q6$yz^uoZavibJwod)+k>UQws;htjWn7|+{FwFm)MfKb zSWnL?J5iSS7kX{Vb*wsXJ(ZoG)xrSWQxohi(SoYVzfz=BGE|;FdNh#QM6>T_!|CNP zYcGJ!;#6bR*7bfKQ$D?5Gld=hx!B7v->nh2q^={S6V_rUlp4Tomo|E_)HLX(p59@p zzmjuo&iTip13(N8ehu(_8Ag_AO+6M@g8=-)EB&W`MODzo1QtN-I3U9z-QJ+ju5OgV z8MRuhV@36=UNeYJt*56+)89gX{4-J)xp%%fg~>`*WKbfgzoIZJPo5!+U|?DpUV->x zi5|x55rP)vE~=|Q@@W}|f{D%&6puZ__i1prB2u?H)b)?~%(p>au7kF!>#r{;q-1k} z{?xoEb_uKQDUtF1Lo=3E8IpzE`73paR+Fl4jC+bZC^5ZUUcdu;y{{b%N&Bs1$od=XVLrh^3Tj}Dv%%Kly^N8m*desAoz1g`5AGmK?)FQh7BeE@ex8a2hROO)xm_;PT6>t>r@cC zHBr8sQykB%l#T0Yp-sF08Zo>fKK;NoQ1^Q#KIx^6pI*w>O2@hHk@kHS!N+uO+AfB^ z+bo(Ny{o<~xGr@EhOd%6e6YyhZS>dCpZ}|HuXAWOuXa%Q4y=1Nn*qf++d(^dGlm~D zmq)kG%0tNshYOPKbK0{7y~;4&=jv@$@aafFv8;O%y6@6O#8JJC>no5`h@ zHObbIwPj}e(|aG*;NfQcUIj5ORCH9MP)Fl2sL+5FnWIu%hOBJ+9GmXEd zv;MtjxxvqUXQSrXvXN0q#(2fan)*9T3IG@}F3OWjzr(L}-8a8D3`gjvCJv z^wj{AN9xv{yBHwZs-VhqUkP4*N5=xk8p&bq4dT+#Tp2=c7t0zqpnOZnZu4dcc~ny^ zHPvx;a4kQzul7i@iOTA+?j4x__+n6GJ$%IycmgJ}o9PWVg zlA@U;!aX)W?q@N*SJV%Q7JHD?iwr2B-;4jnruj|eGNf7kkblvDQ|T|996WG%1=>6@ z@4u9Dkuv*UU=H3&(lS1lh95|?u?lhB<3BY2+Cv%3`U)!P?hVz}kN9%oqRcIDhy36= z3s`0lVSlPNOauUhA#6akq2%+Z)&-N`1{pnTE&bbIl0FswSO*;FN2k$^DG}g&0sFdu z_%5ngkdCz0$-_gESk|=Zgt~VY#J+z;)yKMO1qU;4+nCdp7Jq;$Nks z7g@T?pdhiTcP~Sto7DJ)$qEbQwHH9Eg7lK)@l?TQ_Z2?N5}c0hEvf`%`77XjfEh*- z=rE{!iV|W_iLs}c7P2M_4YfLbu z5_w}jNG?ff)Fpo#Z*4=b3p#nhGYbF)uxOQm2-E9-6;k@3zLF3%}Ja*8v>v{YR%Vwe+T8? zw`61$6PCB%9>y>19jDdw#0Zt1Ull+z5kInaG$G}EbpE4gY+1BaLh7VntN>kLd-Z~f zc8>C3mOL>vyjr2l#tSpUS@VErvfSWdQmN{pS>Zu1`zKXsn(7X?61uR+{zD{k_u7KY zjuWP@;Uq~pQshENtLc$DPqT}NonaOH*OhmIf8ud~Wc%ckp>tQ1?kIwN74Z8?DEztu&G7^5-Gk zlZUs_YtT=NLEj`8S)0B4zzB-Chu|6F;MYnjjB{L5UfQg`{)3kAmjii+TS{l8#Sg&5 zATD(n*{g^p!%AnQ^iNxp+gns;P4Lj50wc`~56U>@bDWvXB{=zzfu}enTbOYKMX*4?(G5t$ajQ8*@f?4HEbw>&DeH;~$l8k2pM;W26 z3!N|GwojIpw@;RNJD7x}h*4TaRLxPej46-s0l9eUYXZ^D-L$ z@x81n#ewT5o*Kf9htYQR4Dwt_$4jC0vc~G}!T*E~9fA9G%xh zN^`k-y!CN|EtqFMhn=?~NU2O!>jAc2=|yjtFKE zyKfZ3!8`bRcLx0SJ%bt~OpO;4bF<$pM#|Aod4_d!U+$5Dp5DNYv*WCc!Aw zSer+6Vs3vrH2$GKs9mi@Rbch4uRCl89t#?|a3o#dnyJTVIh5d;j6X1{N7#MJcpIR$ zgM4lRRgD@)r6m7#8Y?3V=V3Dh?&Z8a()^32;%@gbr)IY7#b zB4_@qSa@NfjXPJ#qo&^-Jw8Vpg2XKCOyW{EP(Rgg%s;ThS(eC|nb6kP^zJ*=7#vL> zNHKnxF!rpVvPZO+$}<1Lbk6v^E@|b-SBNwhQJU#`HU>rpYGxy&%s_a`SJFLoY|*TF zNV0yRl$4BDg%UgmOI{2-mhg>hJrMS~CULWR>kat?YoyV~8Tq}h4G3FS7v-k=K5( z44+!LXvqA#GUG;V0n-Do_h593Y-&F6>)$iX8)L?`^=_w9q2$lT0yuj`Q{C>so*A&@ z{CL51MXIX-sF|?~&o-N4nv&jx$H+plJZR4UqI0PT(VUbXVHUa~>fV=ASoogdp}J1M zubniXxxLl#wtP8q&(~Q(lqO6YMGnyu#y+_6h9RXFPd8H4I>fKRgmyHj(cR@s3*sAF zvE>*EdA+e~$H`E`O?(2I%0?7nnAzT)fD1v@4%;(dWjlB(f5z|=vt+%~z)fZ@n@!aR z-kKjIR^=WwI+&4jxIb84M6NB_`{n!FVzpA`nZy8#9qulA#4x_eK)HL|dig)^exIIv z!rSFg9!<`u1jvH*_olu%!*!YuZPC2VH&D78*~2W`>|r;UuzH(b9!?p%oKeu4OQZS* zz8EqiGn0i3Qc9p4F|Sm(<2{e#tv>SHu068RKAY0AJ%8mSRxdrmz_B9|Ts(JBwaNW< zo(k3>E;+G`FJj)G310G}>G0RJ@^vW$xnvB#7BHEt{BE`p$q@qHb-POffm3VZ_Eo50 z-$s1Oi!<{wfA=qvDBL^DUbsdO*#PdurqtXNPM+Y6{x|(JQ2UR2exzztu`>N6`oxkXXa_|Q=ggYUpUrF*7t}JV}qHRnQpVJyS6^n8C39o+2LUzE4IB9 z%*2zI&wQ-ntjQSEq?5aIJh}I$YE%oc`rQ4qCM4{Cuovy+pBPG>dTteCRJSEBbgTEv z0MPZB;m$I`0pX%-o}7;Snsil1g%Rz@WfSOe-z(hOO>gJE3di4g^amFs$YtMkZ3_!q zwCqwE%c{1eQDIZGT4(WtRp4@oYzn(Fg4JsnrELShlkOJ%gp;_WeQHkWgAsV(XWkxxrvHShr%M;w$sD<(cTGWU53%H zh?f=?zNtR=8h=Z+Wo?3P=FiY=PxLhK>id*c7m;tuuZ$=iNZ`npo+NRp6L7&BGBTR| zc6q?Kv$UeByYS0_WyCML0KT^}>d#2@4g4C}30n40R>|l2Supv?>%pw^@Gqz;iwfma zj$5JRqz5SbD0*D;wdD=W!*at$JRkP410(td1$TkeyRUwW7WQn+%tvDjR^K|%BLNi7xGd?Vbl>rxH=Nde(jVoQ_SaO&j7!13 zPypUE^e-(oMnHPeD(~ScXI1%`E@wn_?O5D5Zo2hCNCqQk^*h_y;|nlE*ruku#}hSu zHX1gI#Kwn*9~K-CYKYsB$xm?@o-37q)tqxIf(VX3y)G|LfwaD|JeA1I5&CjiQ#z8j z>5P4dD_Y7i^`eV_oy+8jz93m+-dOLXuL!p)Cn_=jQzO>7ar}kDU>7t`g%aHjO|XBk zTiG&dNt3%>m4PNZsYS$nTm2rSx%7xbnBXOn*AW(E4ktEtFat4auuYi%eT)CBvqOm$ zWeEM)tju_=ovfV=MFOh|@Q^CWs^{tz5MQ+&sV=>)NrKoayFXKB{LPgA^=O3yy{>cQ zU&yO-@5?4YUJq@^Sks@Yed$usqZg+N< zw1Z8It$O->216wYPMtdl?uC~>l%~WCIW=@G_x zgN5KHgHoy$dOjzfXxUXcw0dQt&7H!Wm(?}X8VI5p-+(`@vE$#FqLcV(VOap5!Xi>E z?ukKuARF0$n-nfMb=^cfg{s_$j5a$+`WOAEwLP|jIS-#~+>`HoUk&`Wcfrs;_1C^g zbBs>GhX^UhsFt*;pX%yOU-g(sGwW=m zUTjG#IXc%(LWWsM&;y-8f^lZ@2aDq6b+4T~M}PVH#w*Q633BB>8nWqCkTl;$ zR+`Hh<>jyK%bdX4B^&=Lf*Sgt-1Y3fU_r}2Dh5!szhc+^r}CA;1to+AL25nXi`GWf zWtF0%mHkrTfclXT@{A7a%yX^Q*19803n%U!jW_M@ypC&kbBiCS#0sffZUrim^&Jn) zcw?OV{I@QO;`pcNVg7uM%QIH1-sqL?6EG6-UQQh{Z||baWT|WI-llM`IfC^wJhrfK zVpFI`>uEt<;4wAQc&dm}Hen+^K7unx*WGw02dG#NpkFO3J)$%(g^H4C2MjWWOIYh6%};;<5Wq|-|S)Kw>`&$oke!<|9NRH@;3gv zQd8m2^tLL_MT}x9J3de&v!td}%Ec%ZTPiTduJEcP!)zm#FIkt_+mz zxp8>m#QneGz#|5N0yk-*x`<|uy(D@Crs~e5*BYE_Y4ik{N*)2UFCwQn)qfzy?W?_0 z1DwRHOD5S-xdCA;ko?CeSztYlzFhO$J)^{vl7)3blC+)iM_PxGe@SFkQxUfCp`h;% zmOl7wPfCRPrT)4-MGL=_2`5!S+*KPsZYt6h^naPd`D;PKC`HzR(VzGxiom*;eUEAN z`+ECaLo=qO#54~Ef}7uC9-cCZH;a@JCS2Pc1XbE@$G6e3cu|0XJS;?1!}jRu)rE0J z629>tZ=esnFr9N4m(GIyXYnBsDSw4m`A>KQwq;zPxk~DlqpwWw38-=qX~-H3IV7WG zL=z9X>FYfzu2u?42NOax(pwgRn@je?$kLYN2O>|(62^Bdf$-CfmrKrnZ-b<1W^cC(-#v}?I_4DG^{O6INO5l>49)GxVXb8+m6`oy z)pjP_@z&-}_bOGNm|e*vLG7>cX!YGEU|t>7-%8;tn!pADE}El*6MdN{##mJVfxYKv z$k=tKs|ewuTB!J8{eAQv?zwWzVW^Durh}0l0zAiU3Hai@>YeIeUcY=i zee#omNu28`-|Vly7cPkzcnhF&|>CL~XP%Uzzt6Rn*Pg3cuz z7z+zObd|^O|M{{g@_Xcc0flUYlxM1vYTG&$mRd_dDb;r_@NsRL9Av*Mm_1W$nUA~s zATX6Z^C)nl8K34afO}qE^vzUIv&QSqIKAdi+d67C_olI{1D#MX_%LMk`RkujV4;Qd$?vOCt5v6tgT8lk5bsd5Hv#_tpZKax59{xVaquIc zP~|Tirx668kxK9#OCM*pIuE_2&B{Wgt9KoD`ZNx{^?ui9v6`0&Ms4@oth zK8&W8Nwkpqghy3OVFMQM+1452zIr>U)MVkL-NuP^cOC+u^hO}2APhlGW`x2)=sbph zbKO(m2}gfe8qMp9m$Ec>AtM?Dv)-cuL)Jva0{Hh4b=BO*8} z8cKhq%k0dDk`Ju!Z+}6(wTy|Bax}jC#2$Hg-6x}JGIyIu!AR=&>_brCUyajdX4oTaFM5(zJ%3XaCTPt3O%3?(J#k~z3KQRxXK2M=05+m? zn=4*7PKJ%r(R@Hh2&uyi#D!Ep`3oW=R>mdRe9bzY`3uf;cQOGT1c@*M&jfd}b>~98 zjP7@t8@cswbQ$x_0*ttB`d*WFzns;)VYC){NpgnN!60kr1>~BRfF`;4_5OhoR6DUZoSP%0Q_Ng8R z86)34jS4@DwK;pV>-Jfqz0Z<(*>uCIH{+Mx>&eN>x)st~4<3%eO-i>*(39`JnqDuz zdHSK9)|HKwpeH}!3(X88bta-8$E{Zq;r>#d$AMruE9g^&f+iG7E}P1hjbc!VyK^nb zhqB8;<;)1E2=qF&#=O`&hm2vnVKn76UYCIMas^lPz4a}Joh9Pm=|c^u(L25BW7VZbW4S$ z2kk&4{oO7r1q&H_0Y{p?^_yKm&jhTVRyyNGQ5D0-Cw_Enxf0>TyyrX5jY}R2h=nq?hk%SwSe7K$fwqVWW#jKTwXeGjUG zV+Wr{f@r|DzMs|6qHjg^Os7`&dU^q;@(JTr~8lXR+Gj>TV;s}HKpgAK!( zB!Z9#l>)$>2{Xm*>>*wHzqauqH>%0X*9TaPjm#7ZhFg!qYzNo($-g|aumFtX$(bUaN{9p5gF;% zp&zx_NiGJQO2M7nY;9knCD0#BVu2^KjBOkokk(w?{k~pFTLLq<3p~hJRaKzyGH4-K zJp8>Gij*IQy5ho+Mh2f7*S8z%m!B}9Uui2QO#Aw*f{$JnT7l4jxxCR7yNLSp&H$|UY zbC3|EZzaI(YU=kI;jQvCy%6;1qnpQE*0ZseEiB-+&skR!26Nomc z(r@W@rZrRht!>OUkqFKiCiJ0ZQmN!$=XTu8DlQx^_?h^~qv$$N5d~xExl8{XCNb75 z#3n0gS#-bM-qdI7UX^h9x}-pf-v1njTzgmOI37VLALWl5@gE%|l3);&s~hZAfriwp zzcnwyL*<%Y)0@G($J#032WWv<6aQTP8n3G#*TfIBmNhE#rxHCpylrW!rBe4hdgufg z)LnP`Y8vAvHx)*U_tx_s>DhQ z35fs^VVG3i+0V{4Dm~KaDYe4Yc3kT+Kin@JPCkiWDEc<}E)A@ld%kudGT`=lFqST# zR93z--GdJ+Jd}c@#BT+Mf%|>3%G2-$VWRFCazPG06E5EKE!mM>Uq9D~uDz_Ff|cSS zTFHsbXD)uk4zo@H>AUY3n0`%m9>3!?FtFkNBJEkValw}R`k%V141G&~oL!iAJ9c8nGS=2Q zUg({lF8n0!I~*}<@Pu~zF%dj-5X~?BGwoCB*@RpkshkQi%5}N2-)*_C;8Sj+ua}!C z=nTgYWXWtl${k^eSh?fiWTrkK-ga8n6mMP@PcFMwI{aus@0y@g%dddzj&`IsSk}B> zxVXOzX}i<7Y#Kb%Ammde(=oHh7nh74n0?0qJ4(Y`*IyTa(+JdU50fL>oG4L>tG;pJ&HIxpp5mW|8(A*0$gh#h%a`2Kxn?(x!yYl0SByM~STO|U zzCE48`avi2d~Q5$WHu67o*~VyVO7r~GWv!*=S(uSx4c$H!9LZuza}z%y~TY`}%^2N1OorDL59b+Y+XPcJFsPLJkD7~aSI<lKg1TsHE|DQmV?Ct$(d5%J{B)IsB7kb~DWkN=-=I%WT?Rn3&3;+0#uk*rU zp#;May1O8P$uC(1_>uuwA!fjbxwuS`DM&_Lfh% z)_=~qOgmpgOWgnShek$*bK7opt(i?+o%rId;lg6k-IPhl1KW)U}9BlsWH5o z6l;vcexcO~uI+2<^w@{9JSKi+CEe1yO|A+#*=hNSvlWILMDQdkGro-Y2nUL!KS(l^ z(O`TX(dXXRN;|0xPA{i0_zS+~cS92z);(k44Q4S|*xqjAhqnb+Sju_4Sj?_l>&IGC z%37MG_%w=i*csks-kW#%q*Q2zL~Q$BAFp#htb1bzbUE?yg@&Yz4B+U{R9=I})z=&X z8+kJ)irSMLWY-d^^a_1F1Z)X*Z#4`bq6O163&LWX4}C~AOK+e zoTo{gtPSYvB(I>l-DAJIzZb`bU3c?ax<#R_P(b?mNi+RA?=x$Hq6JwlSliFp+GUlz z#LN64&kQ=iC{ElL*DM%*!cS+Fu&i~oI9Y0NXS9QRkE|)|cTIVKY{b#&J0=FKcV)Ye z?qf)@-?%Y~E|*JMVp%e#+%14L5BUk^R9vP9V60lAhP&D6nNFEXYe zX0RxhC3M8Bz(KL|(10Wy4hbyZ9QC?txGXZ5CUuGKL*?HLfy6$Od;pHUbx2H#AZ#qC zmvB;PY335$HRZRnN|5#X$MW(c)E!yzKc2lBGV~!c6fIW$`MkF9fZIrKstvrZIWrBk zF&>+Z$KwohCgwk!nki57PeiO8>i3U^Usz^{fxB(JYlw0Cye-1a0gYI0OIpu7KQ>tP z5}2C0lRdjRI@b5J1?)EBa`f4prS!$E)z@+t?t^uaeM6rvJATwWml};H1TGMkQ|*>a zn*I8`MCQ-7N#?QH$kd!FMSg}+ROLqO`OIEtLXEtwn3E(LwC{{JG)c7TzJtAU4-XZK6U&~qRui;q@oE{5NU16h={pS1K z{U-J+RZzEn{e4?%T*17#`8hS-^$y;B`}w)VAv&R9*pub^?hVZ)psrDIBo-^c=fZ=hpq((Lii!4^s~{WnJ+Tl_uII-IqT2Xw$?1L z-g|-2V6?m(Br_VU4kF7OtZDIZp5Fx3I1cZIYn8JrS%>AQ>$sJI)ph}*@&%J%ZVwU5 zXC7zSddfmmp&2rY$ufrCB~G=F?YhStJ#_tpUaBg}5X<@0rFpvCWL3u13_Uee)T!wE z%K$)~63P5T)BCMT{1@T}|)8aVNC1xoaMC z_S~ZQ?4M89=IA8uoRi087QjhS{N-Fv^+vz=T4a(ff4j2H?{I$k&s1fHSSL;v zYl{(lz{j&w(2w5n7L0C|68IDzRrAy+<#!({&dsV|SrYL2;ZK)Ma|k>wPzFwZ&o7bx z>dbL$EjY(?75(xS-}D+;A- znD$r~BR3o(2X0qye|!mjppqh7gq82Uu+9*`z>7h_bk(g;&(~;yL6_-BufF3>`8;ZN zgz5N%W7%5l(_5TRR4|m0;GMUDpo-NT!nn2$zZZNdpEzWdXd;k{o!CWY=v=~xB}tV0`TC5C5e)xs^F{xc`^!|vE~zc?kj zu11u2@a(-udikkXWJGGd&b2yunaKTl0vS}8@u!8+*{c!1LgTk!LQMDn=7lTQA%i%) zc8uamNB@gHr>Ir3>lxs2KGfOS z*)eMBX8<^G@uM-yPsAUKil#oA*jmjP48OpPKdSo$bNV*C3s*71of?0dANpRPNG+o$ zsjt}=&EfB~@1iXA@gIq4+hs{d1|=AGw`dBg{PQ+Cw%H%I?(oH9em2j!AY?j&!f(3o z{mJkUfzeEaKmTDD?es&9SF|fK!aNIn8>>vr{_?-{Qo-7uTz1??LXRF@>-=k%cT1Ld zP&v&rP}ieya@|UlDOZMer1PJuD0tAVq2z&e-<>lPhjJ0I$BAToT<*$0+G!nWP`V6n z305Q@*!D@&JuE8d{+l0FJ~3z2 z8QlC*-{&AjFjm=-0JGm>G*e=03?go}1xTwg&VOm|x~C{FZws;rPb(m7-o^0*`bs0V zY+2%z2Rb!dQa%x_ca;FS8(Y1xdf-PJ*SSJ=H32F-;gxV>eU3U$FrntDI4MYsyLQ4# z_9WQcOBq~hsh?sC-MXtv$7EoR7-1C%w6o!lU}=u~b+&ss)N5V>3#Zbgw!0(R<|^qE z2Xe%&dcN^P1Vv?TqobCeOLAmR{a(OL)Tl@6ybstYfR`6{ zOuTF8XAkloZN0|aIseDltxpPi%Pn0=A&x%xl0e+4J@zu7$>SEs`p;3Dx+&He_K4wV zc{RN|wJaPI+QWd#yiGW7?l{5_a;C!n=K*BWjjHC-W>mSL?jS|&Z|7;W ztnv_u0BLi`Z=U_nfGGW2cK#2HG71Bc&;)@Nahig-kMWaFyWeSd>kfkivm*QE@WO5f zW#93L_RKq_hMvSfFGb_uWOc&<|HyDpBu!%jAy= zwvZbq7eGodE&L9xgB2{e(1YcGH+|S8(eA_oMYm2rZza{Nfu$-qIx3P22~M9J;kS?0 z!-d4-KnKrB1R$=&(Wzl@iZ~HPM!(oi2dDc^))}M(lWLrh5O}XsJy(xbOy}3=ORAsd znQ!$!9Ok}zjjf@w^HX>Md+5j6YET_?SG4f^rh7W7k<$UT z7)QjxD@edqIHhQ|(xFm#120Qx1EAQ#Oqt>qo8JXepaLnc$X ztGG7ier0a%2tUup^HZ?Bwh|Z-_w&jBqw1^Unr^$eZxd8%fQU#)NJvYMQWzoK0ulmJ zju08mz#v9T2q+~nkZzDxiK$48R${`G(G!W$yw|v&=Xu}vZ$J3EcCK^2=X=g|qO2oU zN{cNF1^Sk6gO|@A&E5p#VE_I6J$dZpkVS;OER0=ydD}hl_XCQdip27GBaHwp%4gkA z!iUUPVlQq6PLCv7-W5DYJX7Wa+OoUx4T!zCUuxTe(iMT) zpPwav*~OSoH84nOuDi}VR~i?nC; z6&{UW>9Tvnz2h72R8D?e>t~+U^IdzdY$ zK()t;@d`J>P{h{GnP2~?DSfE=OpYB(eM-a=jXHbkv0YL|7^za0mWFpVb^Ks|CRTf^ znT;w?@f%a`h+&d^n@=R&gRD})51DeJ=&+>IS^^6t0CKjH9WD^@wkJ_d?1@j@%bsoW zecZn;ee*mL(6~{&*UWo%mV_K#s#FoHs3Rjwk@mFFmU`i^m&M#5CItlNr|@B#`LPl? z9?SuCupme$ZV;!t`=+hK=#2cb8e&Z@1{gk&W#L>#7-5>|DsPp=++W}bzBFsSB&&bH z>mWcfBVY179!r;{Qxrd{1?`vr-;GHdX!Q{IjZSW?{80zX{27q<*r7ARxS|Pu2qIGG zgE?^i!BVNW%uvSx9Q~O=-`g6jM+xgQm8ZhyLEv?<<|plsaEJ zY7d`Jo=ANQgHb0JpJ@%}=-G=ghXRid%@Jq%k4N`!eIZH=JtxrUC6{kfvTGEp?tk1# z>$Nc^{4h&zNz=2-_et4?^=%Zux$E|YCwOteDaP?Idnl%W@$;>?M~K+^a%MirF&v)> z0&A##<0Q}!T{Z{7teI7SiZh-2e?B#pY6?W%m+1lY>dx1VAUNLOAo$TAm&J+$e}hhy zrGKvQopn}*U;}_PcqU1O{n5u0j-z7sFvXp8*j*4;^hlD^Rpel|6HDoZ1o^5Tr$;jv zsn2g^E^h4?<69YqIaI$()%?D*#4n24M;z+u6>0E~-vB_aRXkE{c^BiguJpn33ZY0- zT5pv8=Bu#Sfq0OMxMmVGR>l0F$p(WIDu`FT|2ElmWi1v<^sx=pl}bLEAN)xqNc&hd z+k>4QqmTv$69uCuDeds9ChjXU&EW$bJGXq& zTrW{_4la|#Sre8Ami#BfCjdRV<-+(8Eu(02mN7YI zcIfv<`wr#RNmN^JC9nd=9)a;ud zfs|gM4jW!2jLrubL=2E)r9szTTJ@3aSVx=`%}30+w!Xxu3K;@xS$$j`I;H230;kb| zJ8_A{=rFp4f1P4?6Bk;CZP93VhrKMKaZq_jssKJe9b`NzQ8i`9bC_Mb{wijw>e@@`nimnv_WH><76Ax4q8X7tt3!A~>rkd&m#R*%rt^}f2W z^;{+1W~<41tqUI;!5(1+sLxaHso1T2^W)twgtvQGxqi2LYo@;2GA*r7ft zrAB0#HMV}xYb`qY)Kpc(8?bM>+2k;U7GyI@eO^N^*2glQ#v4A%vO5Lo=+N$Utg}Fz6&^FkuinrZ>O@*E6X5%xnVv%%-7~O*sSXn zwIB(%76N&MEIkTZcBL|9RdN_0Y}`lAbA)883iur0FX!+%hMslRMldCl3B!LKFVN2y zcR09w-lYzCtpyU7>rJ)R-9$X!_wAr6_Lf1d`MuaA`p)2|Tg_)1#h|&bKEmrD%dd>O-orQxl;dGN?yjQby<+r8{KjL%1Z>xO6%^v2%!bPf4N47E!^_$ z=z3H8d!fYo}De>!BVc6?{A8&MPq_Q^%k1urpQ;W~>u&y|;ky)b!nYmB3NkG495 zFE#jk_-G;bjVs=H4Yzv6h>L~cbT0|#)|CAz(I!Zpf?BEo!?(%HZ}sO2_Dv;)?pvwX?=_&<@5!?09U`hXo3fdztX7^ZIIb5M-k!kdS(F87Wf z-l06zAAo4dI@_rVtHifOii60nM_%5?6n@6qQ%m4iCug*|MPv}Hn@qAq0wZyE&gMY- z;TJd`lz0Dsp6pdYijM{1!Cd;H>~ZOOi{!e^-&;hmD0ZYOc(4;2{A?&4WQ)NQ8{k|r zJ*xZywxP%}&or72S+U2nJLxXTAk5^pGT%}%1zAebA?k*W$?7AXF^-;QZ>%z+zgvyf z>T{IkSCFtoI;{2)B+Bl=ss6HpB+4|H9AdP!A*#-eXr3PNvczm&)NE1rYtMmx4bNO5 zk`r+6vtu>RK`m0DW^nT1q{b~Nig{8}(w^X!=<9BPaqXCCtRdDe>lMa)!z~^!T-*T++xxy-rKP@2|cPH0rI2e zK1iH>-0-wo+K2HGYV2YQ9`g6jvC4Rix%QPmwNW1v*SEy6K+nLX8)M#!eZ2AlwSeA? zSd&L>1yvszmw|-T{Nz+ukgX?Fs~ASUcl+349G3U{#QejW1k%j07`xP@G@3K)w(?0J zyt=jI5Lkbm$E;hJD)U+0@`#s6SzyEHn_I8h?b}4e*)JPtp@HKcHFqul*#=UVMtAuI zaC;%6xWCgNL+_sE8fQO<`Sph%oc4C(FrZnKZ61VAp$-av`nn!?{=RPH_w*e)?C0bi znEM~{3{&NJp6>x4I^O?MyldvSRpvY1AY{w#_JNj(YNtEG?smk1%NgmP*EWClhAwod z$+O&TsS#gs4+SNC!O*UlG>Vs|fuBmp? zIiNt2zZ}hNEtF>J(tG7|LnS&txNg=Dlpyv!iE9=SFBM$aVLoigy*I|flu zkZpD*0tv!WqOXmjj}6# zAm_<>cF}k60yWOH&HSy9wu?gnUg3g!z`0dR9*q1VKZkCy9p+3%AC3F4U3EIAZW*HN z%aCP);&KozflX&h)iY=(YtDERnGN6s!MT+8!O0KhY%j_duJ_p`u5_1bqdClIX{Pd8 z_U_&UKE{;d%IURZt-N8%b-ydEY4PA?lkWk?PBSiM3+HgyXnri2D(53cfHLRjrqH|5 zLXh_c+OJBw-!D zl=zM7OBu-HJ>RJAGIa~aPX4zf=0L~tXFvzG2Gu)V4yP-lx{=_t`gh;(zKda9Ue$wM z%+jw>C+&%wl<5-IlN}=+IC|iD-rm-chex;O6OA4TfzU>IKXKsLx%voRcFee( zqhR)~o#+t2bNA-=Yg~Z|bf3(Vf-@n#lh+Ooar+cQt8eumCZFAMlTNKRgZ3x?)_qvW7xX#M3 zY}>UbT7BeQhC{9xSQFmXKNq)ruL#?8w_L7nCFRMP_1>2y%w>uV3FlIPEP8fdPt9E} zHiE@t*QmmfsNfALy61>Y3S%w1P}#gy){1$lzY59mk`}6!Zd35iR^N(*jlX>dAsh@G z3HlwsazNmW_0$|b>zM6OJ4rsMLE1SRn?Ad^-G%Y(Q#-Xjk(IQHDVr3z&e{U!a6t&` zYeem$CQqluvoP4OV+TIeq70X?)nO0lLrxa=OAOH*QaE0y;YU}ckG_va*9Q&;9d!51RyOMG z<(=^Q#`FVLiD<6%rO7q)aPVJNW;bd1 zI^D=_`v}SEp=w_ELRvl3Opxq&f_Lyln&+|1RNCtWkgiPN(`HCfi&$N|&KADL*=1B+ zCgm@lkz3KbzUM$)xw~6|(I00EetBd9OH&iL0iHcwz;f#8obEkR^$|arkSqJ8)1A)r z9<)qQgAH%`CTt@`Q*)Q0WvPuj*o5PFg#3c)oX&X9+jlp=&3hMEoJXf1N}NSqVhTgf zwH?tn6ASRcHM26Kb;33{k?MEw6vtCX-;~_ar&R|cc30aXqk>G}=lTkP7BEO=2Go{x z9X*aE*u0EaC5i_N-b|G`Z}H~sX9-4&2%c)%z>e9r)HuwQQYQC<{#Tn6Jkjx9=bI{$ zychBCPGLSvgs6Nsyv%0B+BRQa5FQR2XL=`@o$mv<|>d>;BnfVkn5Fmc1 z)6dA{^3pDAfZ-qcH|a`Wup{H2i6Iv*w<0q2r4QPl)0$Th2N7&cwKx0ux!K?~5g`_E z%}SN>pneOpb3 zIFelGLWix#^GI!oq#$CS{`W|rL|JiLp$>;3WiY7Dc++g=vwC&tMF^7CAp-d$%IW?6 z%E1Qe8lf}~3Z!Z`XZCM7rQ?@RkKF_ZRv3Bo1b__f<15vHjP?T!Ddt zdhj~yNXcr-pYt-z8G!Xp>P3bKlL6ji6m`iO4c`%M5c%C=K~|Gb^UVw$FQ70xQ1v zR~qhv$&tX=wX@q=`3(jL{9lv24^$+7Uve4$BzHV)jc zfpHq!)&2FhsKSRGlezFof6u)Rz4D@*M3iRIE0DnPrr|tm4u8uSDT5uM-Zz0$6Wh!q z8r-XGDjy#%Ni6y*z+F>wv-=E2rRv0oycW36x<4+n&0V?gGOmS@du^vgEuCSV$-u_6 zadoIm3-hL~UoIHg@~O8}Zm9<7A{k7zir0hXS+4;U!7Es(I-3gROMww8iH@H)7>nx% z*Q-61NhwE=rx~%5r5;SnliuV7l0B0-8Zjj#F%L=6Iekvs}p@9YJt5>3P1De z*0=cIebk?n4=_XJ{;5ekcYqr$S(a^yL$C&3_cWH=68yDX`Sy8QJlF>)0MLG1M*Ewy zR7njg;cn3zk#W*{iwexX&&p*oEiszES|jf&fFKpCe*}fu}y<1|Dw!`H-7b(pxO*>&DnNyQj>n(A)tCm7eQnBIyhDu57 zGQCp4ty!a&QxJgF<}qL`9oPpN3Rme=UdDT`rx;cBT<%suAJlc_VSmfUN<(p&X? zYPL%GLAxdu--1WdS_$8UIgkRy=6Nq%JOfV@BNO5X+g%$5;BZZj9y9?%*9GbqN@F z-XfGl6Y$5f_z}IYQJ|A*fx;KcV7-mD`6{78&WXJKoP3qRK(noL9jRDySggu?yI?p*{J2E;U z4@9RelezC>@pGbX$WWwbu=fA8jfu)jr<aQTxEm# z^#SjvwYwHxfM_(Uw;w`1DzCEJnbE%SA+Sw-SQ5;o$rRWW>-2kl<(yMYx4*pA@Wu$! zCFb$#a%I2p`PY{spRn=ipQ|LTV7f1SzZ1ogEYEFE$)O;D&#G%7Et;dwcb-_}yP*Cf%9^Er*g< z%^uCtoo?=rBgKgiT56LI=rYmiN!n-vmBTn<)wG*IDjFduGBnsJG$5WakceSl+Clbk z0@uaUje{9mtF|x|%4-(M^|H&d#^YJ>~*L&t<_o=$~t_-#%$8Rh|T%ET{nEcHGIIUS)#}9_he&0}L&&tYq{0bjA zS>|J5-y;7O$ntCckR^9LQ$Tj^XL8fzz+-A)$?XApFKKoaBg%9+{_NItHgDmjuxQX< zO$-7O?V47DZ6eD?KJ_=Pn}J@qSOf=Zfq`n@93IzBR2!rH=uqFv=D8S>B-tHYecRA9 z^W)|nWKw>4MWTCqMBw>-!T1`iQ;X`b?|aLU6BGI6Mxxl9!H>qAqlcedwW6jy^-|4; zza9XR9;ygk?gb;D?ixJ28m+)K059M2R3sU_XWj-xEF@q7GoXPGNHKccZ`U{(Pb%_2 z`CkC9zC0FDYWwXRa3H=h%Vt{G<^@1kZ9-Zq&(S|fOK@%H)4MHIY#IoypbD}adp=~}x;wW}rkD;G05Ya(_ED|6M zAr21L($5(t6B$*n-b?{QobLI&_IuhlrZXf`sCTCC%3kV3S}VU;NAq(dEhx1$Rd`|G zg;kabUs1OC;2h{$qFrj)*tI(M$lcb6%h}$>-fot`$l6a^G3RO|6Up9p6FbCn$CSz3 z6GXB~Z;UREG5@mItB3&pqsV@Tr(=S&v*AO*Q7}xWs59=f5X8rZx2X$(f(opK>IrYr zg|-BWyUH^h=j+A)bGn81MO*JN1G)m?4epQq{31)QjISqNpN@BpMt+U9U%7(CQ2u!P z8hO5LkG|Oxjn5pdvfU=<2JFNu4FPW{xGUEn+}>_IHyR`O%i<rt zAVwEOGt$E`5{;iF9=e`}Q<)stzNGP68emy&Sl>x@j2Vkuf3rX@)d#VjybB&tfQuy9 z3^uXP?60?rpSR3WJPlDijW(GYezM<03=;D6oNK#29sPx6-aVBtB)*`sC9P^~%l(ev z=Rv#C*Tmk~D>deK-=B!)*43JnYqhC(>}I*h4_q6Eur58>rtvT8#sI6jx51(uyhX3P zx583sBV=$zu1p;7{T%U`!MNI2p&|de+^YYDwi(3OL@q0lfLQl znWKl_=YX*K^mP#yDMqsFv@R{at;#-E!2UeVOhtk{5|18J!QR4a- znK0hF<==7h$q64Ir8+M9`?~w?*H*IG7n_eUKXiT0HSiLn5LIuWb+>W;;1ET5^Cq;L8F+}xqSLHCo` zv90L%pBV?US3_Qa(*p<3(q9hd-DKN2TNn$NJG^uh_^P0q%8Rd$PoP+gpxi4h?>wGF z05jE_@6!qBZ+U}SaIGd-z5``%%c1pEijzYy1h3Yqp7i&)pv0|~iq5~==amnz3F!Oc za?*ES77BoaF$SJ))%5}t`ThRIue~cI0RyiEFzK=`tJB^l|1&u~CYE_hrqqX3=F~=W z(g{NrB}ZzvR%jwM?yCxf^HhHxW>m|LgIhYhojd*{GjL%jj_%gxPfuFKBgFK_aG7zK z{zqSL3L=mmQR*8Xx(-3bmG`BVUj!e3)DO} zCCQ^3(M9Cyy~P~Vkf=ZKwD)G+Z|#SZZ9r_=|;F-%_EmrvzTHluFE#ZsibFH-R zt#NTA=W5Z+FJK~$Pp5@cCO#4mQ3^|Ls|0&S?Gv2^qQUYvUa|G+*@wX`Ul+|O!X(5;OoY*k+9Z^|Ecpqj_VRp&nd;JX!+G4j~Q$Io_+&9`a_{1WHcLMhE&> zF#U?^f$~BZV5KE+5V0XN7G>umu8xoc^)j&>(|0BGTF{g#JDN)A`(ZmId!=hZ08}JR zq1nbh3LPYjlS1d3ga6p$W($Xx=nK&bs^oa%catBji1eQr)5viQ`wEkyRA=x6u>r5} z`bfdx%1dCp*~pc15vuviKzyLxS$rrb1I3Q5!n9N{ShTpal-<*|vJGXbe2x(O)qORy zP{1uolP{O=YsOj3oG%BA!Rc1{v3avh`$)K zgn~vrY*4s42qOoKSmXQrl>B5jA|;f1ll&^LRzzYJLn1@^C6DYV9D(YZHEEW7h* zoxCaW5*IqN&cGn(w+HZ{Y#CL?M3!8=^Rx*>Y+|8=+}q*=s8vd z2oeqN-Ei``Oe#ol?m*&Lh=aCSYWG(BzE^nEzJ8X==Tg!sI^X|`3zc$NV0PnW9eaD9MFL|i>>$& z0u$?rYh$u2q;ydxvZAS^=+g64qu8^IT$a)XktfM3orq}URksFt;PAWi)c3xTemOO2 z;7I;ka~H>07G)8fN6JAy_~`~O$5RLWR4|p)q>1W{^5YPx*G(En^eD4|vLC6_oUPLUP{GajILBlm9U`qTidSxDK&$qT zR7GC9wqCtbP4WuXNA%lM4nb)081=a!Sk6uO%#>UtGv1R}`|a^<25U-(hyD9iPUF54 zZjTm)WiRw9MCu(g!HiK*RlogHAFb|c$jRZ|mV%}#Z%R%o+Q$wh!d8be+XV$>3Fv$> zzsL6Z#5daFxNL>MDoEv)l_FAau}N0Kj`{YxJ+XE^sPl}Rq%Job{(3Y;5^CZ4UcCpa zLzp&gJWc{c9NI7tITsmm!Gnkfuh5%JC}S-XfECuvby+TaA8uVcmY zO2+w1q%uk56HL^#)~hGb^Y`!j`eri^jUfZeE1x(slJkeuSM{$ff=Hazt#h)Hlpw zd-q|6@ha^)>aaJYcWGror@~~{4}@n z{S{>D>(>gmLDxuxx2U7F=|c0`6M|l>`7b%0)VqASF$IHd0Thj`i8N1YBEJ91R5cuX zH%_gB8cOU!v~?pb;wph9Awo<_j=u*SR5$!Fgi>P>%@t}mz({HG>XYI@N7r$}^pBnjBPvWq}v4~2Tq{f(ckHS7W4PMX7lrAn-#4qIMr*#gKa&@_A!026QiHkzQvIbRHu>+yK*Xv+KWl^| zsf9Z=rp1G2dYI@#)h=4cguF`zLv|?M!lBT;_T@nmvN^l+Li)eAH6gP(!yWc#a(^~A z(NVowpNrl;_A24SCSyrSSbZDNMRU;dt+a>Y3rs!gyFYPY2JI1|+IZ68>D5?L^;6tbT3dTpfE1N@Td` z>RZ^D#~W(j7Pgcm3)`=Q#J_ui?_b8NNJeYrw;cWx`bt~lb@(imJi#DEYRTsXT^^#~ z3wRPO88erW@9Kr;fcx1Fab*peG5;g3m*zGuN%>J5Bl~nu1ANT^d~Loh^v_!`ZAgH| zF;816^Vp6?vux6jZOliw?Obwi4OL9{X_O)G3ZBoKRDh8i>MPUEyQJH_(5>x88s;{d zL5F^U_e4{$LYp^EqF(~&hnzw2+BSRWJ7HE19AdVt9<{zn``joe8iisnN(hi3u!bCG z8o07JzfN3BM1@`DmY@J#gE%}Mq5EQN=$C}u9W6xk-m>R|jY_n`w`eVbTo0;b=55)D zlDrw2*l)h`dXJVVh#(A|ib;?Xnpp`{EXv{{!t8V0SZb2tq77B3CuowL7mRxx+79FN|dMF7~&N;=B zadF~9hY)Pk%XErP)<-0H$v*Yw!!K6COrL9Xpy#onj5-n9+bx@cH`p9~Bbw$jHU0$= zN+8F2j|Q;Q++_g9 zh5#-2cPGd21MoO+qp_T^r7{9K=aQPbU@X(ZGK0HAe%#j33T~?>d_hlepc;tqxmZ`_>;dU zlB!kz=uAji-~=5=JY;1yWnKjDF=x5*z7LAFfufL^$N{Bm=c@tS%Wy$CbLKzAX!LuV zsRJzDw+XytW1Z^w-csl(GXQip&D@qyq(?1SC}?Gfj9&=*=cEbuYm3Yjh6*2GFp6Q(wrBM;;ynYNC0hW_I-Fx) z2kW94eJ6QGeOs08yV8hmSUpULvf+C4Vy%>x^1BN3Ygt^a2X4;8)DGu6NyGo!ep(0hx z-2+E@S4uBSXi5p}-8g6sDyaQkd!spn7WHUv_pzP{^teBO(J?M?8VH@umEQWzx}VxB zn{osr(DRs|+<%N6*E{5CZ?Huyz`B_+Z_c3olcG>GXxqOI1Xh)ugIO`ESs{rbBm{e5 z$Pzu2TzL(Y#WJB5x2!-$OD+41xRwTIAX5e|uOonu&0#xbZ?oC8!ThpRARGkjdCNfu z%{Qxw&=Z_=CW>B*v}NIAd$I6P06kbQ{KHq-Ca1=D01Ul)wCNqn>=5RC^pVix;!=*@ z2Wf*>j_MDmON4%AC3_tE6a)moD82i!5b9oqH^I|=PI1#Ad^Ovp+KR%Jl>@ah&HRS02pJ-z28~Fm75f&(%v}=rqNZdPywGnh zm3hAxyy-^zSC+MTMz5?tVE*Gsj}(b)0GPzt(Tw^M;QeBOa5VTMk~Z9ql8ls5D7^_W zzPhpG%J22U(#!RT{Yv|Z0fhmy109>%XC{}9y{GTuzz4;@eVA?sUA4K5deHt-?|yvy zyTO(1e}CO`t$J?=M=$&2W=X*rNR}*`vAIHZvL3%xOy(qc#<@8g+{8okd;bKg{HiBhWbn0~2=~I;6u=G3Tp|3HP3! z30mAv5bT@#{p9ubh$bH=^k&eZ^yv7Icz?9fMY1}E&p;PtEBhm#?vKFRTnor_vd>Is ztEj#c*FZxibFnLa@@I)?2L&wwDJIYbqprLKmTJk8{yY<-vIQATWtild&ay#Ep#H$P zTRbxFIdiY#fj4FTG;|jgf3xs-c)BlWr_>7i)#B=WjyJp7>-pUJAuk(iN{Cw9oiRA1&xV5Nz2((b0z>P`U78;NJ|iDoo;Sik5`K zj{xzqCfw?v1V8v(TW!7W51j&n)pTFcMli?p< zUMG))VJ|Y8UR69Yu#ipcuc zGEP2sr1*aD!qZS@( z2_!Zd-n(2@KeWoxT@~7^0196=_l8;*JZ3tDXEgcbDt zReEBz0l(*+W^FzDsQM+i_NaH%AlRUs2i)ZQ)gC*b9`)*zWMIawYy&3LN_%2%dg?k` zw(yt^k1PaZo<$7jgGos;D+kgCtXyz!P!vkG1OGGScCm?TFHlY{OWy%0#`#Q?!57DD zMf&iL*$EQq3r0JotkbI$uwqUs_l$qE*TRlp{@$nC{jTBUUnV)naRJY4Zfg*M)qzfSn~tPB-iZTTfnuxiuX#5 z@S^{}!duw}UJaBrp9s(1q$KasPHtTlnGU^aW9DwIcoo0Sk2blv2)gAr@@RLHyxBR! zM301fZ!NN;TnfR{t~xNb>SlfKzPpXbTs_P}soLb|36{K!YkhHlMhhdW?JC3_hRU1}&dJq98U zT9~9mkB+jc^s-cQMYxex^C2M$67!p$w-V&S^6mW21xbuAOq)*4YuCx{R8|OiWlv_5QWOtQQkfW0MXVyHexKZ9kvUz3YAqRm&>FELt_QY{N0?!#j)c6}+sJyc3=~XmdC$Eu-0HU{g@;E>pgXVhV6qKLjO;zVsTLbS$g1ma5no`+k^W69e1N#=Ih3Q44VtR zX&kGQJPyA{DBhoM0$D*XkARq?z7_+dLgAA5BsOgI)G9A;+{Mii&AjQLm$B z7RP;0shv9a>vvyQ!>4KYyA76H%TGdPHEtVS4oJGCKO~V%JB{e?%lP2j!G9ygs2C)} zA?D3#{=_Pqj*OrwPSE!v1gbKx|G0$TZA>>yD|TRQEAbcvyY87|(qlhn)TmDqjmY6- zAcSi~KdU=u`NCL{o+=`^)$cKAWnAY6(-naIQ)nn5hMB#I=ijE-<8S0SR|hLYCPpq7 zy6UuT@(Gv;YLeSzeq6HAq)Mx_t2JHX*QhMHR%e|9?cpk`_rEtbk^MO^3blYh8H_Ic zLCV=b4r%AjBS=wkgEdcV_)CO{rf<8FEwp%)VN=>Cy@e0lKK^RD`5$GfUj> zBXUzSNdYyN%FIehG1v268()p+9sgrg6#rzir1{R|R9?zUBjQZ6nVrou4{F_w$->*~<0Y)C zO4%vOqDJgc@vrEZiy-~0$3eW?iq|1n_9W7DIQ(< ziEIsZWRk#0BFp8GyQu9Uf8RK-E!`z%zTE!`FmuEF-nEnr-a5M+Q0fA~CU*(1h+cca zaX%TH&5$8?uOeJ()|!FKCo{5kEkKDY56Pn}<5GUfk$9LicGJg$3wldSfRd9btG47T zMbPxjg@GdTa;8u{7zKChwa(vy69)=DNy!GI)ITcp*&HDKK_(f(Uk#Kp8Gt3c32itZ zI<50lM7{3mivTQa=^wH#gm?^sx@cwGAvy(=;`ZypH0F_>i81}(-J}=xK?C4O?=jc< z)yt)(pe;41Pdje&g#h{wM~L1Ze{Gqn$T{IeP0W$9jW2P^o}qarR zf)=GXsQyN>?JkCs*oPmk9ak~tK3w_+LloGDLR5sH&K6(*n|9kKCY)fDnboJkwMT!t zb5~f$D-rtnE~>4?)pDdy+9#!3(mk?q`C<35N(3F3j}sTvsJeq64U|Ddo2q4chSacQ^*8UIR(-bcg$Mq{ zVpi=D!vRbD;8$V)_p7$$TZIL|X6zG9f8F81d*A>EJyy`W{gyi;ob6A+{|n-{7u?Ei zVm%-B2O1A19@d)`Z_r~CjUP2BG3;B8`?yTHFF7g;ZT?mmP^BF!PNrjHExiP=Vm4fd z?Ke+X`wvOsC8vS?C5a{9Gczfdd%hHqk@GBM2{SeqDsx`RhdGboR~tq$t{CvjFelDA z4q$XQ|Kg)Sw`=;oGQS%CYp5uMO%DBQ$}{zrF85ONMd#kW-O;ey)t2F%?9Mzt9E`o9 z)(?1nVv`|3ro(mbGTfK=V;23+%#>+U;Zw-M$`XStP5=B8`KW6l7-$OLm!O1IUoc%E zKa7sty2i${yWYhtA#=FTkN)l!wa|T6K()AgJ_hM|xaKa~JfhukZ>6pK(JK(^-?=90 zAy!^tgps{k?J1=j)BL?Kz9!u+^G`$BJU6i5A=tZeGBV{|(ny5TL008_FL31*y}+2%tm7J4`|=nhpb5$;+$GpMU~&)Q(>F=G31D~t{Om=5vV&pX_!(Jewo!N+ zR(Dpw@ttF!-imu?Ri~42k+R2xmc6jz#!RjblX^#~^FHAssN)Y=?l#BjdxUl`S2IVQV$x6utOiA6QC!55kvi=_XJC`u)K1E&gTRy4v9d=N|J`>w7Lg)(#~!*?=|0 z>rLGcSrR%j(XA?~Zlhmqb7jH$vCVYk?z`bOAdpo)_trD{+5IP7KNaFb@7;h>iL@s4e;*NNzi}4K z;{y??>n+;Q+k(;-T$Y(BPece)TpLmuES(-7cDv8Dl8Vzp0lr`VTWEA^Kkjy`EuoKv?p0fMGyHsJqYKk_*pQ&QQd#xrhyz!Bu6t(8=P)?L8!2U* z6aBs@E;qvU`GTK!P(o0a8A||@U`B!^od5Fn$3M?@5IY^9GhRtbE`g)u0&o;XwK4Ro z%A98b$9(-QxP4$-5j=mk57ADWX!WbXQl1-K>`7OfkKPzD4G%p|zyUR5D+jgS6elPL zD)>FG_dRVb1>Rghg%V+{oP)En?He!pg@5D_)HoK-Qhf~*prCZ=#*Lcy6c1S}Qrnat zox9qDKirX9qXOwbf$ifCH>wafYCSlKCy&4tmJVue+p|L!3XPyXN?cGoEwG#MXItoc zQ>&kOCGL})%)o0ab8j=oms)5&6~xr1eI={b=aSr;6KFkeBm2tL<`AWhruH8RGZ}va zf@OOYL5c1?WvY$zl+#)_AHG)4cFdK$Ri0aa5&w5>U$o;sJ;d;6PCdlj<+*FD6iJFHy>?I#hx%ArPQkf|7EBDrPhCB zP)k)y9Czi5p8{aenk&Qd%j-zFT=r>e9ADlcUe#w66uwhdcX*bj*jJLlL*lUMs4RE3U(bb3mg*9QzyALfvPtdQ~bVq1xaSM_!MC4FU69!AXK)tKK1t>w= zG7(l+)QXXfFE$Q7<;wv4%uvoX6R=$SHS`+9a6!#}O{2d_ZNBs?c=Pt=&{3xZ{Cby? zIQ;uM^p4HV6%kwfH;Z@0`fP+>s6kSMT~~9NSCBXLU^<7Z6fykP0q=UtR2&MGdL@X6lV&)omMYGt!(Mp;!iqoqoc2+`m7!>o zj#l296?=nyKT(Qbm}@^<0pO@0dIk7^zSuWgH^a;LpTag6vY;6e|>)n4Qxbj zrB=CtDRhQeR@y4>#m_d4+V9^qK#U_xJ3(-R!S;2JpIny?25tllxAQA7@%H>X)3Ko7 z6>p7ms4WJ^dgWAY7iW>J3eR#1;d&ELES?=2Q~mzwlJsZ4Yc4Xt+4^$XE3-#HmTP)e z`=nA*in+7G5{^6YA@H)SQjUlK9W6)*MYz!LXTsO{e50i`QWP%qdlsmJk?aa-W@im~ zr>@hF+j8dm5!&B00wE(l7%ptQXiLM7zK+((ia{;Jr`WG)kNvok12!I%SmBkAmpg`q z%qSU4O=VG%Ap9FBrrKV*yjLsuF64z!s>Dyhy}$Mxtp7cc$pi&I8zGqgh4@OcHAhH} z81E;~yjLpOiw0L~cHeb+qUYP>Lwd*tj(A{CoMK5JeucQpMvpuLBpplwDHK0JeFgAeA+8Py0Kp=}w2$A{b;H5lnXPeOBkPV_Aq0CaT!ucSM4x+K>bCio+D30Zz{52ryd3{rnyO~%sE;4s_A zHe7*8J0(k_a>3Oq@|z1kE|ykzYrSuB#%@FpAl^`oImS(9z#m!`#l!R&Nq@yh=tA_d z#CgBF7cZ1wt`SnrUTm84EK9jaIy-l*J1Y?tZ@S{8yu}n+!e@Sb^ae$f;KMX5TS#t~ z6V(h=NHkIrcuhW4TZ&OS@5bDQKhZFC`7t7toGPg&FQ>zY|DXhc&zBR+ni?{+|qV`;~E3^rBypb6szadZ9*7=d) z$^f_JPx|Nl(}$Qvd->FdU;8)oAE;cv(8}}d%0T9&AT*rCBv+?5;8D!7uHZQb$tMmk z!}Do2?g)NSe1&STS$&!lDAkM(cadl2vW%kxgZzSUzC5IGFacF?a6KV~Uh7MP11DE= zG9A~io9E!GJ($-6+Og-)u(Go&_SJ?fSTU-xvi>=`+ryKm`&Ynrb%o>O+M1p0RXf== zJKVhq!>3g6EJ37{_`PwT7apEZlkuv|<&!i~*{JuXe*L)@9c{+bAEeHQQw5b=SRP=G z6S|x{A8B+eD}m&F2r-124Z6v!LOJq3q0Jjv()Z@m?z;_7m^l4bsPAsG7Kjr1mi8^(KvIX_vN!{&JTu^P z7q-mg-HRETD+-D03GFupc(xsR94)}YX_kF*A zVDCK>*IYAa&W!k?s5CWLUAtf&f>I-##;eNE{>gZVcmU;38>RPz=YEyIFGXI~C}%nS zKfE{F_Q@=g=(raUb@s1ERxx`U=iE~(8L92W7Y*;|#NT`IG)I)(TrZ87qi{g#t^h~O zhQaMi*BA7rvTJ2RtgZ@1h1&%AZrSt{syBx$&Bv?eZcJC7it70S*zOSUR9P^AdZ0Wb z25RKs79LM$Sq>;Zm78QrMAYYb_ri124m&Mi%<9W$fh$`KI_6su+1e-51gBV{Xj%j0r;QJpJ!l@nJ1J?1x0?`?MWil;xqpIuAwf$zML znMPD9Ln)|m9aA2MmL;76zvu_tKtlXfCZ>#Mwh;^(u5Yat7X>=JZ(B4O3Bqjwi1_|* zcYQK3!mbg7M7gEC5y=xO$gwg{tkvZb zF;mB$(cJIfzA^NrbN#Mov}N#;`Q|LTibe$tedHdHLkdz-d0%C@m=*JF)ZT?*UD^W$ zy2%FPZ_r-^Z0JtqfF(=DsxGY}7adnOo7V~~-O`M~HpqyLrOh4f_7(x{8FTdg_b*lV zu{1txdVHY&!rcX2rK|egiLtJ=iq?`3@}4?%#|xRRR?)wwwvUowP;^yVkjQjYVpZGC z4Ao60%&Y)|ls~1N60W-Huehoi!JXe2wfueCGo+y3!hgkrq|I*G^aI@`|CqPCH+-2` zCw&xuT-nF2YxG&{dH4GzsJ<>_lz1TTkL#h`4Z}mH*y@g0+(M;<&*|q4GlgjhWlt$0 z=a{bldF@sG!u^Eqh&Re>*JX8w)bTHTbnnwFMl0jE@6tcB_+U*&qnzw%&Ga4@vSdIt zhCfl^Jr;jevle1p(;`5t zdvyC_KvQYUBFNb}7pha#2s`@Je#kxXT5|muWa#qZZRE$>vVyi#yiE#=3>-tx4pOFd ze^i!A$3E<;iE6i{!zp_RjNoZ?{<~*$t(^P`&OM~%OH?K%I)XGk;@uSx zlhoyX!rbj)4ip`Id|*F}45`PDT$*J6iUC0uiq7uINL&JCcLS5rI^(F1kLPGzQeAV? zu{!eoTf;SJN9ItvkPUU)N-=(n`}MvnTwo|{=TZ_=xkmM0$MuudT;Mw=Cfpj?1Scr!=oeK;3Q=S)ei35RAKZmtzDorP1x)BBHkC)v+yU zEp5r>g#4F4zW?;6&OR3h9Bfij|q`3+A;SYn~JVQD*-JEln^xnHR%0FFE zzLV2vlh|?ZVeT9=)lQx)nm^l+q3vf)REO=HaqLdTYd$87h<<@^tf0hBO!3{$ENQUo zWG!T|!->+-_S^W{)OM}nQI7X@&sWXG2T4`3QrHXAghd?S5%1t(0`KJTAN-A?kLH)3 ziFLYDHoGU@o6+a=;LHEuds3jAeh=1@2}Kh$A9+>~{d`Ddaf>xWXQ}GKO;!({Y})0z z={+$p#Yc50YjaeY=$CtHKTaM{@rV2aqlehGRZ)Mm}mFG$Uj z^mgLc?+}Fb(P)XRb02SH^`sYyM>g@KOli|xU5f|VDtJWVEXTi_T_fAEBPI)Yn0mrM zx@wM3c~6#%bJ1X>HDC7ewcU2~Smp$!nG_vzMQB1wyaguCQ#g9OxX8Qg*Suh%~ ztVTcbT0Dc&7ZQ)rI*+a}HW^u{929RteBnDCUNd!^lcIv=$IksTZNozARNicc<89b{ z8_96bU~^FYgb$u+Qtxji2E8PPnWZ!rZ=0Sz2E$C1S-6Rxw{6l4bW`I##83w*DJ`w6 znhHZ^j=n^p_8D?(@5BA4ASJev8XlCJ^J&fVbH*QKmj86?f5}f$Jc{(bwH94EH4N_I zD+oJ0Bm&*8PYM+cxlUSf)sCCpHM?eKifC+7>O8u47>3{2Zi19lj`G4UBx*#Jb`Fi! zCSg}xJ-u=?)GN2pXsJ&0YGpOE$<$F@sFAcyoyd8Q`y*z55d zt1pmq$hYEeznZVZ$$Xeb?1JQ=>bKTF%AG+Wz>@SB=+HPo z82|6DL_4emzMq~OKMFP(=9sd2Fsyt3ct@<1n>#Kk23EAUeK48IZW1EYBB7 z#>NI&RsBIvXV+f@c4AYUe~ZtF^wss(1#?$PR)00HRM?+lGK-p(WL{pw-8DwvKpdfP zDB&=Jb;s@y19Z7PV2eFnfGw_T1bICVCr7i!Y^0W;J*8mYvbggD79FlT$euZ03LD|$ z{anz^6`g=v%$x*B;zN{%x z_%By*_l)z~Qu)lT$o}ccN}8*!8H3xJp_V$POIp1hf4PtfwtGUC?vAG5843(K7v+0K z`R3e?-J}g^mSv7f;v_8TY&-b-jGVhIkHh9+*mrS=eQosGQ|V5+=I(~#C-^y3=!Tkz zkh77BN05-0-&RvRUGV6g;yk(ejkHF3XKb1aTP$sZajvS+AidP5S8cgbEy1o;m zb%ww#no5bj|NLL^y=H|d0_qW8P}|I2kd35 zWGI3eaaV~_TFp?h{M!P+YQcPzZix}A$8lmEIlkBqxVeBN6;+Y)Um;}0q!a03?}>$e z|AJN$Nn_)8Yh53Ke^PFF`E1E1+L30Ux(nh5gs{TQl!0EIYgSTN3A=15NzKTs@YFzw zgH1nT?+>D}&^e54N)=g{j23^d=f<0@cYN)`3&&yo>`X0cwcat zCclEB#|pYt7Ce94gp#zF!h^gh1AZ2$D!^maEbVWjb}r#RUxqt!b@Y)pn3T5lzXMP8 z?p~r9umEj-x^#5$%*ouws7JBkvk^V+S(UVA5VM z_1zsdbS-T$hiS6NHIJEY^2JdOs-x~LY;0SxIc&G|tAXu+zYzCg9;Z zquJ-MHz7;qHHpU}g`3zcYe`yGn@3YkmP5A}Mh?Roy^yaQtw4b}&|dN!2wK)f8e`iJ z;8yY{Z9dGFizVmQb+IZ$FWs5Q=dPfssl2=Yd~h~4GW;SX1ua2#$imqeeqSzeqb2Sz zgrakT*4lh(*G-r+>q^Hs*Bf*@1!FPon=e#tulmZJ=Jhs+a5beOZ7bd1yB!5XTX+eT zE8FIWyB$Y#h}TB2>eQdL2v@9O-Q86CmAUKK966nPx9u}sx$bnRLc?75x@%gR1IgC< zEt3-UZAFi`MjS9rN@VjR*ZzU5)G_uB9?C4swUJMqlXlcqbY z2c1_XCHL0w>w-zW{p)UjVqj>14X~DA)Zq{_O{r3()?icFb*3O+$8R* zQ_0xcSQA7;Rit+2GWq_LAdMK60P{pe)k-`Aa*ER068BAW|Kphcld*46lQiUs1EkwvyqJSJp5fnfPnG8NqhmtvVx@AhTr1%qyjIjf_=+kfz)Ew;Mb? zL&9)FRSGN_vcZxW6y|!8heB0*=7Z1ey=^#IL%q7Fk*WgL04!9_PF@EwJ6$~WBMX1%Ff&O08+LCqudc3}S;FX|Hz7y%bf{Tc&dXv*O)gs8Rd6Mq zy|K2+&ex}oBo7F-ubn;*uY}_r{Z0}@<3*0coT1QxR}$c6U;dSY+xWsbVErU#tREX= ze))8I>*#cKB^k(^8un*bGx3!2H@k6q=NlYwU`qgMgN6CgZO7Mdg8QbKI52{BX)@`O z@w2yRPQM*vC8?4@_lP?H=D_dh=rifY1$B8mwVe|IKT)A?NYe|qg$;p3V#5tsEfa6 z<|8R4)egpB54;YxuMS#!9vE#nQ>gKO-&XkVZ&%R5Y6m^M;`I+bho2it?wLzc4Ve6q zIo!2Va^z%*?+6Ya{mVt_tU*_uqRxoz+Oy}v3@>E(OY4!~@)T=NF?Qor%Xly$1a*6% zI=&!MUG1Ci>km%ok&&y#2kdGjA?5OawVWz)`;w0rj`9D5{=TN5Hw7LP(!r0p?AO)8 zi>$>^4Hy+xLZaZO`3XyWFUU`_PxBKin(&{`i^w{Piqu&yT9n@gLUn^lM*TkLu9@Wn zR0EbRfCs!1;w{tDOo4vqWwt$PmJyEn50kGF2fR>YJJ8o6YS>>BY4UVEl{dPfCTye+ zvzyS?3>Wdp_A{t*4r0p)+L&$=N4h~^)G7e6Z2yXz28?tq`zvm{qfwB&?-DPT82fHF z%KOLvk$U=8q!Y|gbY!u#Hhb;l76_;|>4CS`ikqX(s2K09KH^jF&%EVvEsOGv^FF<- zKkLOYGEIZIWm~C@yox>d@h_6q-+Tu8K0kt*w0TD56eGzoOa$@*_5TLM94jDo1sxq* z?2u=aadlFp$>WYUWjtaeS zcas)Y<`s57?^iO?5qP$3*D-i%Xd!SS|C4R64|q}(3DJ@tYrk`%^k*vQ5MfrEE5k0JLN(okgez@}c8n1?~ZL z#h9q7wpz{`)Kmlce?Of#O8m@1AWheHN!8zH0T3%O85y$Xqqa3_f@i64<(iJ_BW2(N z#p4q#9rNswkx>JUb*(|Ol+4}4ivg|HTxZ7~CceINd@rtKQ-P~g4XVyoEXv&V#c9v{ z#ir@ta|>^qMde!=uKCzIF?Fi~Yqu`m1y|e>fAcruPKaFkY^WKWixjq&nvS}0NZr+QkOY9tcG2PZ6>rPMhtP^^XBtigbqn`YQ&H~OMw8lR zpOUZ~>n|~NCvyU+Kg)uQ9z(YX+LMtJ$hN+<({#U1S9i}Yo1knsPA|X-aK3 z)lqQw5M1_Zy>6nho7}#W^eoDxQ}s@CXB%1q)K%?SS2jVG<|U)PZCBY_3T%t>@0UUA z`LkG4nY5CrF_5q{@C-~K{dSMn!UFCa)6U+U^tl8|jvNb}@w+=ayQSszVPG$+adnsp z+{}xIJDHByGW}O*?MLIBFx->Fy#)fT*O4@K`iAD&+j|0)Z)EKS3KMl-Avm3BceDoi#NWB5{Dz54~L8rwlUF6y3py2T7)J44=`?seX8~vZ=gSxVDMUAs| zAEr951Ce>T?F_~WCg4DX z3Ze&?i!4c-LC3vDTS@4XB)Zp(x!hRmhYNFCV}))Fb6}_nodJweSSV%aoZbU$KMG|V zAm97htpraNyf3`!qlHD$kVy3XH&n}hn0(Za5 zt2Y;56FwK;xqR{RgSYf$^^1qWS#@Ph-X3+>TLWy7tDq9*kfcSOy2uh4J=O$(0<*~y zn(>x$Zrs^uECBP(J|x)2-1km)KYBv0eyGJuqT`Kls}E#Wj_0+62IL}j6LnQIbz_-x zuKMiqJjv@Wv=~*9ai!3&%aBg`>P7d)k%d_)T{70PY%b#O5Tu~-Ln2Lbp(a z2RlO{Uxrp+2r-#SBs`Z@5eUC@`Q4o${}TVzcqqTi+SYBuMz8acT2+~pcAxY2!<@oD z5mYaVuPM=6n=ZQ-6GJQbVoifHxNc@wFoIlhTHx%{23av1QWTC1&7<4EnIuwXhG$f2 zEmJ)sweo!^AZBm9$gbd z^)(**1j$aloEalu6Pvi;!n|FsH{mH7Y`iMc2%WdVqY>cT{$^KLmciX#bIO^-Rg1Cr zZRtQS%^$Fd_qh~(OM`C12E)AAHmJMBEqX9rw(J92&PSvrlhjJ9fBesh$5&yF^K{f2I<&bZlf&fYWkOTqD1m$GjBKp>N;zB~aza)i@K2vqm7x`P z&aArX(d}70)125l!G+JoMm>wc8APb!-IYrD@3;n!Fx>{wUVhX{L69u%%Y-tfh#nxq zO^|wqk+$i*p#16-BV7zs?DBqPr@qE#o|OR2ANQts6WXjeGW}7shQ?+p)l%=*!lo3} zKwSZSH!UzO6PBA74L%23U1dO?2NCBTMr^+SN7+ht36=cKNVcAwCoc7kmQjzdjN#6i zz48S`qN0AQN=jk+rS-KJQuL>QcPeWWu*;hzT*) z9T^P~6(bVaX=T7wycJL6WSyi97>!3*R+%w8CKBZaK~b#g0?2hp(7PJ6mnug2y;WV; zKwY%saa@}C0@tN6S36%G){IqCQgHiSrB6gpwsqhguEfT(;Jm^sL~0fy_oa(vmfKX4 z*Dn39#Gy0zdBnhYq(a5Vd^a^>zh++736yx}qw~(fhy@O?0BKuSleWqXPyvIvadL2p z0v7w6nRXil_euA9xKdERzJl_8d&N6U-3R4~WAM1oAa{8wzZ{uDo>+7Z_{Qce%Qc+% z|0+DLs@=Xh46Dn>x^Z-H?;*4##|Be)j;Wnq79kWKP0%qQm6RAP`iZh%KaQ9ru~jL)<_KZfgy_;&OWAkWj0S{+1{ zB%^SmDmc2z12&#E%6~Qga4*zbrNp5c-LcJ0N40m%Zwp>p#N>Os?vG0a3)}NLg};cH zl1jF`OEbVxAi)DB7dR5IjMff}iUXE!;rI$X+tk08x+sUuU^vi4T$R76&qu{~%}Ufj z9Sz?tpgC1OsQ(sObftdQ${1VEMA@5Zy8YSPpzIcC{~rs$3|`LjF_3H|FE*(S{$e;r zHs+EM_q4Kzk2ygz!_o62rbUbGF2&+RJG4T&XF$(H{+sK+Qb2*WH#}1YSD@g6E&@?T zirFN}MI?Jmab|;Q5Z@mgszad#nyyva#Em}8MQ%56ziB~=HQ*G|s2KSlh=FH|=pLm? zfX1o%LvjLi$!^Hfn9izxjM*pJQ;+8#{6P#n-aW($nPsgX<;tPg1X4=OnHfaJXl+Q* zJ^FOKT-ymzd64OW-}8Xy5rQ^oZyjb`=_co8S_u@N1-R%73JS(RJi{2;^qvE^d$^}O z9{Jez>j9bTByWT7HuYrD!V_C5Dru9EoRMguMp&effEOt%#x{uaO08+lcc)q?dKc@=I961`$(pe}6Wi#uyk!mc zNUOljRJy3xZv$uk=jfp*?@v0mZ*ozscwPQSu}&9>2fmioiEpv)+t)hBkBLD4-Ni9i zK{4mcDaI5-n~?IK7c~=2WqSnw6VbkI#U?oQu2mSkIay|}FzEG23r;Pu`C)GVI(Mb- zNW<*oRRJX&n1&cKTDR8h%HH+j+WS?Nf6x}&2PAHE6M>^keL{PwGm~n%@eh-K%r+Rg zTG8Z%h9@{L_9G`+fSm(l(~LEh6^3*Y_}%}k(5l<&rtLuzF1YkRAJ!3hkwLbmNMF4m zZee{2H&wSXqPY;x@vY;LoAUDCQh=@hJo9+el~Y>}&G-rrQ|UDOn(iad$)s8+zn;O<=416=G41PCpmw+Gzao#t8#ad=`|4b<2xviNcdoie zTI+uiO9U0lfk)T)7Pwry_`h=(mon3nn!WoMXN&aMHeMg0!mO$j1%MqXR6Nb^>?ZcZ zYrX@XsF{)8+vZ-yLPhmFva`-DgEE5&2$TNIz>``X8ET3j#LgoaXyk8(vh^(9O%{h0 zPXi+(d!eGUU?rSH^!^<1ZV=bP_8Bz)=fgXPq5|`~O+(l(L-wO3Axr7`vo8A&89M3j z0lrqW(=i~(%1RI}7@YaT4QyKV2s?{tq5+fyr?5t#s43+vg%DEdWaEP8AwV-2*-I7F z?5Y}J?^6(u6|LvmpqNo9xWM3#9&kcN zs)3=upF5>!JO7a_>;K8N7S4%r^d|Q|7hcL32U-WCZ%Z1+7)`Ia^jnDnaE%Xtur1m} zvJ!OpA6Eh>qEeE17>T(h7rVG2jc}u9wavfGO)8*90(@!8z$RbNi^4l#QL2l3)+o&@OA1!k6xkxaoboZr&!ynE;{(hK) zAooH*v5=JqalYYQupZN@Q5&sV6TZ(l5JJ5G=vkznVx;2nMm7JdAh4iTpc6v7U>a1+ z%`(3B??>|(;P0?DS=Kvm`XGM3$7=?MsOCdmqW51;4SDs+cKw~Pcc_+g0I~pT3~kmJ z(opwgkfKkv`N-{29ox=Ehj4UrkWa3r(Zyn7?Cnr9TE+9XfrmmJ!nu?R$;jm+kYNm_ zPlr=(y&?p`;l4ak)}!}tY774pFSP%`qHfJ$ygbp=AvS97pqqaq>SPB!5eeoi zImlIBBkfC;>$jRKS8r;MC}{%4O2t&$DH+IIZavN6qHjZBbG`8WnL7Y=1f{bL>oKrf~J-Wq|(vAidL)#&Vpgw1$V5E+#45(d2o`td;X9mJzgPW>D9wtQZHfJf*y!Or? zBTx3yG(vSALo4h+Y0WvJ`M4%XUG^Y>Z~LK1`rf$>h+#KFIm7ZJlp! zazduhjbJbGtzeZb+3$?+LXlu0(JLhu{g8av0~|YO?Swh<_poHW$8d4M-)Sw+a+!2H z8EnTEdK56sS>Yihp}|W5gTjgo@V`v+uf39;CKYu|S6SGb@C%oVjq3xOPlC{G@vUx9 z@E8QFqDF03JD}RqWE$VCAOB&CHNANI*2{?_xQXt}0>Zb=iwe_H>0I;1jW7--DK@k- z^XR-8zAfc>C&a(IW}4bgLNl`MSuhYYAwJq%8mHYB@>UG|)rEyr0!A}FX*9@-jut8a?}Ir^W;Q54(@?n*;7NzGKG<8rRZ9M7bI z)s(OS>@G6`ObK4d^JwBCo~p;6OY_=dZ#p_iqYCWyFjn3l+|7%9kKfJJ;{!|61v|rt za_j62C+%ikhWvD=Lkj{JH5taxn+0BJP;5@&ttrOdO<$iHKfM52zZ8-z( z(h9?Zu*KkqAX-#lRW(SAoTksf(@fzQb0YsSL&3sYB zDuwTRZM3stG1@woZ9^LA7;OA_gcqjdd^n50K-yL~?K^Tq$~^?!quIusNGAtl>f+i5 zA_~YGVC$4=-UoKl=(UP|8J)kspDF3O!lIM41g#l(Eb_sCUR zx7b+v_^TXr{bem@ZQEzxD}_)}rMx;rG$fShJOcN{63-^!IlkT5d) z-Ix39&^v%$t!P8 zMe-2)-Fid?f8?FIkKD*BE(*j-yzUyXx=2L8T=bL%Rff;kY+Q2z3*_~;9nrfpgiJBo zACzUbeRSevYS~#mZnSm~NFeOsZ&)@(ubndY&NIq~1YJSyOrLJ$?PkZ+9N|=__U4=q zlYCE@U%}Zx-yWs>Fml2rvc%!=t-9#s~ARU;qd}QP~kLNEGMT$UaG{<9q5+(^Dzt1uIyt$xB z+pH}sBeCedXz?skxc3_=o0QjgLA4E7AVds)65?1NI_VyWF7% znNrhM7dN_{^KD~3ZErUVM6Dx~lEL)|m&?TMh3vZi!2kBPk64L*@R$VW(ac5cwX>;I z<1&AT&#>X*lQkNukKXdZ9z7N$UPp`TXU;Z_B6M}o#W~znN}S)rs_%X?>f>APEAGS{ z$?hzB)km=PQt$QtxOB57TAyb^dqUXAO=q_!IX}qHd)XH6b_iKJKE}hR}~sc8}0H(gqQ3lJ^_ea>P&e9kkPQ*`iCMKelM_g?;?U z5Ev~eDjNDxb6et*4--=#OSJ2Aq?=IT)_Rk>3TB?+5XVhLCOSegrsh;2y89`X2pFJI+-Wmkx4K3UuSptTI(OZbDf?2bN@=)E+v%@%rc z3N@-gO()b_Q%D^qJGA3YY%FYp|3o4zs@O!n;5Wx&ND!)AG<2KA%fp?PIo!gO-O)X< zK~k=aLaI4pN<%b3uaC#I1m$(T8m6YX%jQyMm**=<#QN%$6nwc$?V!ov;McA*J=*gq zR%KZ%l(oh_KK$BC!N!9>^)_Fp*Tu+_!y{BU{J?=9JO~0O{?x>L1B@%F6BPC52L-BW2MKmaP`;C+%t>n#X!onH-kj|r&EYo+ zjM0KYSu@_T_@77En(gkNzs4-niAy=kk|q4<`f(b|5or3|)j-dyB4E<;?%vqR&h0>R z{|7~p%8el-u|c>Hs?(#IT_=%JosJNT98g(svw5Kcqs_QC*&FBRxk&3OtL&k;=%ciq zev_!Qq9Pz-8+0?dZS6|@+*8_cFm5`bbmWOHZ&BjT^ZpWfI8n_w^02w2j|f@yTvAl% zI$>LzczF0P0SVD?EVFUP$sWpKXq|H4?MFfV-kdcsA!IA{Ssh3@wk6??l!}6LVu7X* zG5%khREqFug#RXScX*<-a+_cz zKTP%z>F|2{Kty=ib=cOG!EjjPRfPb|os?N^;dv5)*0LH3`BLazZ){u>wQJ@-8qCa6 za#@3EpKKn9#>Q1|zBGf~v}xUg`_rG8zZfY8TQ4P;BkID!aAkFgJIKvVD#N20A(_Pe zo4?17WR<`!fsqSRCE1dlH}Z@vT>gBy$x5%W&@;87iefp{mnr0TaK^@brB-Qhfv)WL zt$FUZF?E0_Y_qeF`kRIy(JAfyDcKb`8M%<0a_y#B!p^*Ldf6zJPc0Jhu~%$wX7Va2 z1x4MAu$DAI` z%d^VMOR>8q-8r=Cjf$EU8E!blX;_A@R}WPt;8&uz?oyGF>);KrST5t_T75=1tKPq&6LRh|biZsDAiZD;$#`1y+->ddOQB~dkPRJ#vXK7BT1;hF z+^m*Gx9IxT2etXp0BZMf3ahxhVpV-1Ioa?#&dab?C}1ZA!4B) zy7j)PJc0d6&02U?D=cyzUgiR4QGRrL^VbFgENyYN%IwfA$<06ioke*-03JJzk{&%; zl1|qup6x6tHnZ^%GU8^XC$&Svmj~H~^G7ORZZ|&vtXeJZc>o>m?n$VfNUBqyq#`3= zxtPKAK88Bb^owypizCC--X0BV0Q~p&%SHKc@Ye-_&<~GFV5QBlZ~@XGrsSzLYqSiy zL-A6_i>oxznUEVd05S!or-LCLtR~Ky#rI4(5s9vaTeZIzALT%zF=oG$sek9#_+T~| zNIWl9uucrfpVS@NspV9aGRcFg^d;A)g z@b_VvDKRN{tMPf`TLVA4biC6wxMurSuO_Elo#6E05HVSG`%pYlBAXUKnJk;(le;`^ zSEJ`q^R{XoW{#$n|L*t-1+vbA$p8F%R{s#ONKnTzg?xS51-X8sZJR=NkTC*?{p<9; z>Pg}3Z0nuly>$~)+|Roe`qSN>e)pv<86MLTv&SflsHjA~c=Lv<(Gn@@)YcZPLZ~8QnYj!h zfunL7n~}@*UWY6>Ih=zcw=#~iJ+jAa<~ILOPuewed*)gbk5?5*UZ&DSm%4zInO;~P z@;aGR3gLGu{Mmt{`n?f&IUq~Q9^kR7u{q>{#GTLdqhnR2WfkwdjtPWfe{ajVxx^@C z4z#bIEYj`mVX(iSMfX6Q+QeT5m2K#&uG}*mZlun6-~>?(G*7HEgRxh}c{NA4QL@JM zP^p`Hm}rk&*7T3aB$4uPJkS5>ccq$yM30%NDdW78-3)#Sso^~K%Hz#z-%HFsE?2AU zu#r$G;{skLBg+!T-9}l*2Ed-(*}{G&XN?jH^?N{c{`Nbr(C3iL`n??QZ+_==PRrf} z1p&!?bz%^>lJpEFTGNg(wuL-)Uo>H+Ur#>a{nUEjE$)LR2PMdZ_(Y~4I|KgpiO35d zd(*FzyeYayfPP$jp~~Fp*jRxhXsdmk%SquGO4I88*E^&cL}B%oZz@cnlCeuK&GYMI z$7S16B)Pwi81B4--S0KcHf*cJ>b{;|&aQ}})byp6|MJEsGNSToyJMkbpY5~Q1k%Sa zFnqnq>>r@Cq69!m+wnoGRe&@`Sy9EL&YzpvP{BzPyui*VzUhCzVBXZuoW}PUVen>a zMlgTGWAfg}m-Vmv8jH#-CeYfc@9n?1oN8Bg*ODUr#+l@Al2sU}UTlg>R^ljp`C6tq zGjewJoR0L1=3oxW)`P^d|DA>xGLoS2ZTog-qo1Fj+_miyN z9Oxknk5JDV3l6^gnexFPv$vFQRg@CN=(pWNN>fPon9fPo*pnxjYEgcEPlj#C4rkFm zVK?p-v*Th7PvE65;yGBIFY-!;jhD3X>wN5%fZSjVG(&=T#QpVdO+qrlk*8(#K}uGY zE~TR0lyqB{=9Tor1$|CC2Tt$pS(-hcq@yiHnn&e2iz92e3x_)6bC?Z1MUDmYAn9$?;l0q)=ntaKnk_jm7 zMAHM9-5xM z!i^5|kN9!@ed7F=5&uQ^t*LA&9mPRJgCh*~>m{n!Nmh+ISqr%g-*f}FMc5v;k%e0defPo$tQQ9(hYd7>eL`Z_kKn@N(CA37XS3*i3Uf8d_e|KTzE{+any z+FYGTXYmqtR)7h!W<+W<@k9mqoi9I@ap1cKBfHgE_F4T|wdF|ws zntJca6SHqTxXIWDhfj1W&W* zVDO&xVsA?0n$|_{MB5=LGw@|pRNE4#Ud(zBXlDR20#gWUq#2KNO;nVnY)2)QS*}a( z6n$W=0^wP?kAC6kPO(^h6xRQ>_9xkWqI5}PlPAt-n|(b)ulHJcq3EMylJKagEbJyi zzRf@By25B*tNlp7RaO5V?{LyZfke`7VOQBM&-8^3yUI^@pK&yRQ_^rfb*$5m5IgSf@dZCXs0DeT=d}lEK7MhncB-GdF*ex4px-{%wdla^-tr*0 z|CUDlLwTsqgY-oBQU;f@EWYTP{?EOwa+9_So>SH^9lGq;<(?i~j| zol}7DuRpQObC0Fw`kc@8>oJ7sr|GL#d!N_YP2`@(2e0xlbYE;0l|lq9;+L7y1Kj0hfzOqBvG$+n{_|#_S`zob9WGxPG+DRCR9<6Y7_3&ZK7+t z|6D>Kg=gj0lX3gZghC@pqUXftx%ZQNjM^O1u!FzE7~q49K_2mwkN^Gm9~h5|JWw4d z$%1jT>?-nL<*Fua=E$FoeFquUgWw`ba;ioJ^?PYwKFDIbWD11xQimc=`C7_9F2H&a zNl5@QH!8MBR_!ixufyLAPPNHvR#2$yY2v~aSMa9hTVV5{Bh!tjv{qYp{`HT>He|r> zCZ17&ZUSKaKVBy5HgQH%eTTlHV8M)2Y63d?Uc z%{8)2&&#|EQ~PH0HFtaXXCmL{{2G`8nUd0_oe91#qhE|+j{ARTi;bE;ZPB8@Y(68R zHcBivH`i7Ey0S51FedYPOd)?=)Xpu{OVfdxjBKi zi`4_lfiZ$S-O8iJOFmh!J8GQ|?TIj%Y;~C$6k4mr%N{kAuHlP{)tJh{|7MKDkk`ED^2I;d_ksN5N=>^2qzj~)Q%Ge|L{;WH2oFxnV$67aD#KWczeo6;cllUT zA3TI#S=FWNmUiPjPI0QSJTxp!`DEB6O#?gdu&;GC{Ro=iCTPJ?w`Ageg{zKb>jn#<&=^WhM)+dWK zpY7x3BmmTs_=$p;H9q2yVf?dhAG3*mg(Fu$Q35J$bv8 z1M^O)z6ted^c_e7tsXzc0OQe8F685%TYAnM_#DrXvG(O)XnKvsEw$-B?Sn^XAs3|# z*srZE0u%3jBBa63$p?;gqa{P(Z%Gmqr97^*WoCX;c_$`bPH#^Vpmp88{Bx>lGJt}Xnt|f{;JtZT;dyrpAB~rZsdZ#w%4~4@tp@*YgBN-r?H|M1*5gbP-(u< z){30^s|KW0nu|oIC90*MXR((+;RkYgxsrYjoe(r;lbse4>=KqiwtZ= zmc7P#9Nr5UHE!6*h8C#oqWgS%PRh7?plG_ zh{0)U2)LEQl{4YNuLquomky1Ig>HcA7x8{MsMLJq%O^}pP0cjSFJ&fsi@^{y9sU7| zX1Wx}6rdr(=u)VQC@}=SWZ2>V_V7U8NfzW>C z9m#>};VOP@`aKW)#r?XddoeANd9`km-!p^MH}*E~LVp^s3_A?q(?_@FGQulA^P)6^ zmn=0Z4SuA}{>12jgdmHXQmmom9w`bs0Q%2 z{NIJ)sEPMkJ^SBENcCXWeSQ5G5m7g@4_mxv0;zM~1z5eLr+M<^hnQ%q0JK&gu2>s- z(;eMArUb@DW1vLKCn5eX>&d<*>%Fzm$F7N z1zb9|M41nF%^II}!PV+Et=O?x~mrtp*y_VC_^p}8?_az!k z=I?F&#&@_E*Le|RM`9%_?y^Mv_JmWo3(7?Y$L^P^Q&TgR1D1wGHSh(7#j~ShVb;8k z_1pZFqo0+@y2EaqDv*KI;{waYNOFpAwa0p}n6WZD60pecRGI>RrP&R}^TB~les2kr zF68BxTP9b8UT6^@O-`lNC=nUlg@#U&%xjV1s$)yb%E-_ZJ}$n(?;%R5_a*NIIorBVYd8%_xPKWkxLW)VVJxo;i1OvYo*<9uh|eGsjsbwWuiI z-EOSQJR{D=D@?4U3MkF5-H^cZXo_!T4H5gN6rpl!@Dji9Gso+ ze(7gFg}dhwG&3&w6lya(7EVfCgKVYdN!R%rw-n{(e)VASc`n)Px|*D7JX65W%#y}` z{2ZlmqJcFm8ZIrX`IuS+9X29Wn3?HdN?m^iGdFQ#xFJsjyvL{R1Yz7*Q|*|%NZ<>z zfVrLDPz#M=(5&Q|d}IW7G?I*1P3Dm1%vC+%KGIpV_SjV1CE?Zl#QwN~>&dnCTMws7 z#}e+AJ57mInSWvxIJbYa6@HHA9m>J7**)k3+gq(TO8J9$j2I=@HyNm3`Tj;6KMT16 zju4qmB_GKZEm>r71JPvcccF{^kGBPhma^&Z0v)eEo5^dRx22DYKRyJbVS>Zh;^UK{ zf*S+mY_DQrnhq6zoF}tEBR1$nHzfRhZOGZAcy*?=l|J7zao3GA-q6SZ**X6hH$IU! zpZ0Up=>&J_)vH%S<(ygYcFo}08)N1*-KmX+AbDis4 z=bZQZta9V)U?j7QpO5Eq-3A8;_?y{+0^p+)mDe}pg+-);e(6+z_!9QxzUQhtBdYDtK`YudgH;A#OnOzmd(kS*QSB0YGIYnlEAlN#c7Mhx5B-$ zLsD&0ZPjCEH#)icStB^JA5BLjwav2E__hu>Y_1ryHKg-sOg0fLOl1V)7l&xbv|E^MIXH zQAkScqc-?a*)V$fK;X{FOJ1uvlXsHJRIS1rB}%EQD5XLxBmK!IG6^d~3*uPf+8@$l zlj<;oB4vM%t|FAv7p;6b_8eWL*$0`7Zg42aM6O>H)*G1qArMFfjl5@F`wtWZ4p9Ks z7fDrAioYG*Kz`%O{;VxU7+X@uT?GW05@~nAA%JO#>j?nr|Iluk|#1jM2IQ- zp26j6uV0%}(^zCjt7O#~wrb=C4>idpSy68Yl?sLB7^l?ku$q10A+IFVVz%gK@#-;_P< z2#E3#Aj%gV$vD}n^Q#yXBC=wWyJN6N*sar;68^joRlMQa(7YFbbFDk>)c4!^ZOFiU zKXcfDBeW*P9vO`nsqVKEgZXZ9#d1~{_Z-^MG-dk(lIEWuEEB~#(mw`H;NsE)EQg^D z{`%5Ocy}DPMf~NdkBq+iUN|^}k`9L7ygQK_Ew>~|5zE;+Zot@W&1A8l;FCcucoxB` zeQEy*-kG9pwC|r#R;9w*Sz~qztB7=Lz^a>9Ah!Aw14|D+h?zy3SJq$*JP+{>+hLcc3Hvj1 z-4Zq)#V-Eq$FOWYemQ3b=rfE|_}m=!(1ox}{;vupJJ3{gvLmA{A~bt@QY($Gf`Myj zW&m;q0Q&_6shxKhx-hr>d$3=Yo%@BAB{ijwtDzKKdy(3tORm=pQ)(F)_|08@{LG(G zOol$Vbjtnv=R;`&S^&Cx4S+{MlIX69yzMo!9V z3g;ge+=v2zIp6We#b<}Kcir=XfaVmA0$8CaEqV%3+|Y3bekHuUl)snVu&W#}0^7ey z8k@$FGyGAM+Qz2Od472qr|77(mspMf4!Rj}PB>R6dbL`RYAxOS{ujRBGjLau<`p;D z0qv_|u-NjCY0Su|{W!d2RVL5SiVw00i{W++|Et3Z~F-}bN1a|ZSKvSPpA6-zl_V`Y9+ zp!Wmfzj)6|+Z=9tB?CAg$L&-KqvpN0wJh`F!@hcYZ%IRYlPs3wY6WC9AFY(*Z?F~P zmVD#S7Semn8tfGltxt5kSU-4ga>beWZjixu&jf{KWw)B@AF6sp9yc^-qWJc2LDR9S z^{-mF&yTr>aOJ0NC>M{-8(^PrTu_iy@u!W;fY)#b<^~tz%x$-Y0T5YfOaad6<;~sN zA0VBVEH@^VGXK}3$of?wHRaC8aP||vgf!NI7kajNN79x&k?OOHi&udsr07i&@k$0i z(ae?mq>N?FD+J**07-^N?y52!t>Z+fr<62Eip_j#he=_?ajc$^ks`_Xww};#yD@ze zB^9kIh&1;Uf^|Bp44f?{kq1$n5{N=liv)qQv$Tu_3H&*AuJ#;v*`GzV>{qyF!55cT ze>^d&XNpr1Ur#7_3hLJpy9I5Bp&jS}Lzp891b_IO&v;?G<1ZZ?ofg|bV9Q1|_n#Bs zbb$vG0zu3$9B$(1C{9Y&XYb)m<3Ww{u=&SUpWtA_rUG3J^B*r-oN|L%AOrj|d(wtJ zkY@!Bn)Fit3~D8B76HoWci_SJ5gw_bVU`b-i_1%LNN5Bi*E z2`}Y!n0iybb^i&xM*|2ATz()a<@}hO>-X;%C1KkRI2AA?q9#<_v z51?oQ;?UfoUjmf1t z)KFqfjz*21loHO9fZbbegYS6x|$>D5n>txzO7gjF5v zI&hEi7b&7$O$RdE(sG2F@F$0A+#KC|4#0r`KdT3?Fe6kDf|DhBq%Pi8JQXd;&S7e; zZ%07j7Ba&$n+BNFnabRZho4jQq{-CdeWSIrvKm+mW>a; zy69x%`Bj-(u{y#g6Y&2gcBfy4-5W1xdXf1-C;#%${g?6kJhw?1Sos5l4+i$1D!&(s z+=V0_44u8s;tSO=Lezy4a4(+`N2Oz|^W-bUy<9fNAr21f&#lj{ippE7yJD_j1sJf# z8KRm;$I=?}E6;m<57zmBwsHheju3DK`()G!oBf>M(?bI!rJ=U$P>h<}JbmyfVVtkP zag7?)L+6u<`P4;!j%RMHf_*K= zxqzei)`j+BzV&VNXW}GBCntZmhV71yj*jUxvg(Grf#e@O=K=FjEaIzi2Faps>Tdp+ zU6T_d62Bq#WsqL_1b;AgacEkbo+Ny?QW%3(F>pZm5|;boa=-Y z6%=&L_cx$)r?Vi7T=-I2TWHE?k|vde;6g@c?8wU4Rk_b`H3?;{vm0BTJP0-aUhD)` z7Y&afZ{D4RoXd64ek*y8yP+0A_K!%jQ_-aYTI3eRWUtD3gC0moaH-n|`oL8Xu_DJBNo((~z}HO$^G4>3bl+G^axLX=E=s{XFMQ>DKM6_Y9SPjhDkQ!KaJ_1hfXdN> zCLE2bk9ZBbt>NKRP?IMrA9GRZU}f!zT&njry(8P(N)jbUN6DM&K|}|Oa=m%jgVy35 z*v=yD_0VhUuk7DEoOrIXQASN-MhnjM=r2=qM#4hvqjX`2BGTbZ+^1>p9ZN=C)a29b z{sD}K!%U4wIP7hc(sTZ-=gjZeXlH9oOuHfqrYJ*C5;l${@<=r5T`xBhi1M>t$#E%-U7s?_=Rhe^;{pGUmhc2jnKmES7GorsZ= z&1+}|SxvyiJ?BZ7CAn5rj7f59lEm!O&#n0S+}b_uCf1*wFrIFD;a{7ZKVieERVMF> z+lf8nb=0H;D=B{F{B-U>QDj|aQyMBv0tNm1h`cZT KY1sE)_17cC#qu$`1 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 WNk7n9Y=J+ajL(|=Rcd(c@Bafu96{9p diff --git a/images/avatars/gallery/Civils_H/Civil_H_56.png b/images/avatars/gallery/Civils_H/Civil_H_56.png deleted file mode 100644 index 21c6183494cd091edf7ea7a74457b1a9ca9811b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27529 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_57.png b/images/avatars/gallery/Civils_H/Civil_H_57.png deleted file mode 100644 index 2172de181527ae7b16673a6f4b678d33bd87cb29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25147 zcma%AV{oQTuzkagZQHhO+qP}nwvA1)8{4*%4K~ReV`CdPU){R@@2_X-si~Rn(`UNp z^h7HuNW#P5zyJUMcxfpy6#xL_dk8`S1^NAnk5rHc08Buo#e~(oK+e+*qx3AXN4Kx$ zvRN%>ryIK{9OSFTs8_VeQ`BgmD`ggB?gxF8qhrKsA;fEpcBk%`d_}8BRD;0Rx z%Ny0d*isN8P%1k-(<~E>0e)Z1-97LD0EQXn$-8SZKcr9HH&^1r`oADj^clPO*VfOn z&(7Ibw~_{keGsd=o;v~;h~aVwutoWJVNc}1x=QOSGi5YQ+aI8$&*;yd&scmV_)&TU z7(!j`(4RbEd(^fUnUbLc^E#wdfD664;r`s+)N5!jHD06+F1nzjCPEMmpbIU$Eu zgK&g@yA76 zstf!(F`w_Q_R9B6eJ#KYNn~MUU{GK9SW)0hCNcQGO8$x0f3s&8jhI0A!eGR~nr1L} zd<-F0F2Ggr*)_7)^Pj-_`0yv7Y=OB78cDdvo=@3z?6=qd`SG)+9^m#u^v?ZG`_7|> z{Uiy&0o0})@*^_w*k*)60Kyf9DfXBC4eo@5HTs0x{e7Ky&3Ucb*ac-8Jw>p}&(P=T zkeu=LM-NePsB#B0YYO~nhG}(KG)P+CQU*NeqovQV@x`^~_1rZFSB@JKgI`7k%gGZt-Q`3e^W(t&HJl%ySDJU8WDqoq-gn3P zIk_>^`2{uaHI!~c`?JIs;+my_sSi95ar-B}#exyYbVgx6n0e&hpzg658&*_9#njZ7 zOl=TlvnU-7UC_ES3Q);|ilJ-3oo!qRR6_*n@7w~J0KDS@LW5L2z+&k4bplOj0{~Ln zFokUQHu1RY+U5c&78KU#6)zZ36FUxe`>Haf+@IlVL_6fkHc|^s3$SDk|M_duNbi~K zCdD!v?U^|90Me_=BT767f=Qns*pY!3EpwZjvXl?gR4gV0f(hiQ|H&%SikB|vpED>> z>pyE6G$LMv@M?*jUMR`Jw<8UBrE-lyJPp(|i#9`J2zet65&r22eo}bD#z;r^ z>hp-=7yzXjlk&*i*2GSz>}x`R*zq(-&AwLt517_|P%25iPupsQE3}|CDv+t~$d2t2 ze;e?P7`I_);V<_erXC7`p|si5*nU#HVz@>ia-)F`DAL*RAhWcw`?;VR+?kVoN9+ zd|-g7EU)O2wt}zp@0>V@q@8=u6)7k?0J#7eUC?SjXgi;*_TN;cyOYP+{p~eUI=~{{ zJJnn>D_j1Ddxl`a=Zek^@S>Z-=6Z-Q^bf*3=;I1@!Zy!U9v9X3RHkm`zsNXqy*xuV z%TK`Afgku5arcr9}i*^r6`E<9|HmkWD z$ZiNQOF!_!;zk^Mnt$gPPtZ{U>9uXk&Orzi1CM`sp$QEv^+DH%kL@%CDDsM?t~a$j zEZQimJzwrDBNC54K61qLXEGqMxaWBUQS8kXyj6NcP&73LUbt)RDfuvINc68b+BwKD z-u#^t7AsgqV1oS|Gsqs1%Gk30i0v9n!A^ct(Y4T2Z|mA{=#<}JZ58%129LPuCo)J% z@-p%oLX0|04yGg<&K((w3j>G3D$T&!Eg#G1CrFGe-U{8a?|M4D{8c?W>mNNG)y{c2 z`y|LoO3O;y$kN18?T|*>yI9rky$^K#JRbgf@;^?$*}XXIwmq?o*Xv;m%~IRfyUQ~D7_aDoQ@X}xLkMfcCMzPL%yN`vUg(Lk zR0#{KpBYEv>j`U-O&TeTSZ?X$WfKhEO#?f_`rD~K8#3~u9tkx#O}PGOdaE1>M69fS zp_hqzdfIPr)msU{rLxvQ?d!-~N1Wq`V3eEf;hqVp6tOFe|J$^hT>3*u3>7K_YPR3+ z$E0>dmF+j`b+6n@I-oi2j~Y0ZaV1d3SObl6WYRfL20wh{%**&4uMDw!YHa_SWbL64 z^dpxyX9&Udv)uuY_e*lUG3OImx;=RR+uL5A)=%u2k^d(|+S8=e9q_cS+b=;g0jQ_F zHQrUbX})|G|4kFv_ymovt$=*D0D;oxRhoXb>0mHEJbD*DDon5w#HsPFpn!#ymD$gS z>3gr^Tg%!?VtLgH_bWM~UB8Ipnq&%Tpzc?CruAvvqaFy$ozhpX~;O&T68?Tyi+ z6$H5{zn^EvrJyBL8Ki<#vHPxgePcHh-L%uXU|{3->It05IZG)`LD!6iJsOzsz;(WyG}-;HTJFQ4h4s5WPOA5}vBtWf$L? z5Z?i>dWe0fZ;FM-UL6~lptdqUk^=M3?xcXL>(7ht$N6UgD-2c;%Mmndn}0_@<&8dX z;i`ws!Ht(w*}cTVbW|f_+IvE3T$`|PXo#T(Yv;~#Amc@u$-bbM!}1g;nk@@m=9pNVpy{eqSBqCiaUFXj z3wzwb1pV(IIodpx@o7xUc*1PT<77Ibm<=>#$l;nGJ2cCM|9I&)+jAwr4>>2b1GAr~ z=Ox)PxH>Dn^`;IbPe|e6f-ZbEF+;jXDHKs~0JD|==3vH#V%ipCh!h~0D0fqPZJA@a zo=DdPEvim?OC05q1zMai*2PfinRZI$=379{?Tf^cI4{(^RmU}#Wa%G?sk?bQ@9TF! zSN9c)U*J&7(W<#4oYHqgnf4QjA?Wa|oqSoW>1Xji{j*I9{;T_iXgP zdf+n(+>u3$*<5?(R&s!3Yo787e{=KuAZz~pSK%tPxZFVh-gfm4_}UHhBiwJmo$m=zBE{cB^#J`fL~bz;nzKU_d8|X-rqy*^f+%R6lcHY7)AX; z&41fB9Lyju4!bKcB$AJGMX}QQIoWDM=uKYZ?o%C#*XIVWz{KnFIe#2Rm*=zGN|w2_ zFOtiD;PKAWPIQ9H@ej$(-LNOV7Y{lqWtIWzz@&qxzriwJObN!i77n^Mp-4^prCB(* z!breiQ8}R?PUv>B9%HFROr!>&%fi5cRQg=xQ%`M{QKw}IbL2E_1gWc!FktR!!HwTs z=5|xKAAjS3mpb4pcUxl7YQTb@a-_4HP+X5zL4hR}XKZ9MAW2}pAD~dIa9T*>mCzey zV~@4{v7mT;$_O0c5|&Z4G6)tGLKiYIprqsr)RDfR2j%cI#vvU_Un(QDjZ(&?VGXab z`r!#@L};LyeK%3>M%WxV`(dvn7)y(HUcL(;6_npmoc3YKcGnv(Bb{Fr< zs%`CS65=oP-68S!v#@^eQ3?j)GWuU72A|IJ7iU}zPuD+PQU^3m@pJD;s!0GL_+U~9 zCUb7?ug34x2b-F^BOH6*MLD`4^5fTM0Ay9*1(3v58M1zLjfF`9#mS1^nnlWmDf87$ zu+_VVw^V2_i~LID7v=$l*1pCrA%-I5r_xSPI~mqAsB8A@&>F(OY1zkpDvX6J$={y zMu4DzMX*J!Nr02jk0dmgwaxAKP{;kz3v#_IEMD-w{&klPm}!}YC`yLeopsyHn|D=3 zCS+PIEj`gGTh#6hneFlOi+TdT5sgXDDyT zPIDX>7g@N0={RBRKL$92VeA#u(mk#A^LjB@wOlqA3xAPTJHz@OMhwSh%GJ9+FC(8{ zx?sJoR!HV(2W;6Q0>28skiL!#1N1N0&GID=7sbpFW7&Wn8)NU~*zOun^Lo7(nRSqm zLKs&Mgu)R_6u?ED`#)i;NxsB`P3E3DEVDf zmBYn($%316a0TUC3QyufKY+mXgL~`;o@SRn^$clrW2f>M9j-G2^bP;_N=EYbF!BhAEDu90Q>(?nZU7tavPvj$DI%`XZxteaEMR`3s7 z6gs~-j?GIj?IC*4l{ts++nJ6%^a+XOE2W!~Ul+mNFa_hd15qT|uu+*Ey^`B2KxUee zDj=TAde;%=uSw0R<^o+1bO{-E^Kl7{%XE~V=wvnBC)X#}C%h+^;`v$IJs<+#rV59? ze9t0eKGP_)cf8A_kG4$!jfU#FIUn>#?b4}P*?6VS5n~^Ecix;v1vprM9p`uAF~P1g zTn?3mhU?D@aymzc{mJkuy4TAYK^sx@_kk(FVcG3BRJ}Z$vD8e)otMgj{yRlO^F_nG zCvpzk5RVehxoLb*yhVO>h&i`w)uUgp<<>66B2q+|e|;PeR0rh0nO zU{WG`H^6f=R_yeUH+_zZ zy$N1ht3F+uNLd6#V*l3jwLea7DlQ))8Abi1ijCiN6r`PmCpMYPxUtoBrBYP zN7-o192()Gs4`i5&Ur2~Y#XKrCT;5>!m7TPuY7DPhf7Im+$5~TRlG+0r;Y`=9i9}l zxVkopjjLvJbO|RYkt4_lTT$LtMu6;2oFMB{nry-Lo;aEEpF(nqMTU!k*7m4@D zjZx=KaKZ-M>Q*F_a0$mCa{lTpjeWgt*SQG5qpw^ytpF*W+7q1Oj%La|T((%>o#!Wx1%VOopo*?$g05Wq^iYC7d?WN^S^l5_vZXxrVoexhbsa`v=?a zqJToul>54)tsrk}BY@{U3j$UU+t!%eZKB4C@eNMpAYoLNNWw(fA+J16B$YI|Ic!vk z*ua5nvmPNYyk>TgDh2qQKqkeJNmERzpKJ*FIJd& zA8;qJ1PrzY9n|_CFb(_9FH^7eFl%68wLYAJ&zRuXuNUt@i;HdRtpS!hhR6r4{@{7C zKt^s18S>a9T&UArt$=-ZI7PW?<`JC>73BCW$oSEL)YZBn^NZfA{i;df| zv;GTTk|*jPu@g(27n7T!ipiE^_7k~$Bi0jCdRorYE49hn`%{_j5=YBrl zyvH)2T@T|5+vmcnR;zDr1`nO^IlMJrlk@8Pqf&M3BT$+>k%tuIfr?;Kp)XGEnHx=a zErFNv2`XA~zYIBV=ObtTO?(S_P<2Q>8Pz+^wp|DN(w5dZ9QhqqO|7RHtPT21NUg!x zzDEcx36B7cJ=1`)C|cB^cC*%o*GER=)*Pu2p$5GjpvbJQQHWxF00_`N^7I|_QnVJA z-mv`r-VA=8}Y)E$D8U>5U;ASdZd!|4q5aH1O_{`s-Md8$d)1?rYqHCKnEgM z*cUZyh(v%jnnB3{t84G9a&j$j3u}rKs#1%dWut5iyw4~5>~>8S zq0;_L(uX|q?9Cx)vbkMY#S_Q`N-(af*u5Py}P9s=cN`PqhDX)s@U zE2d>n(M37js5r{NJu9wM(1~3 z5eNC@>UR6OD=uQS;-`+NY-lWlht>quOh^bzq0Uj7OmY0$I;vt>pNUNH7|8ErMCWktR|i7<0pqCY+}QA2-<{>;1*_g_+n{CfkT+-YqmciS&oTX!3tqN{!8)qcR`$`cnTMLRpQ%E(1Id%OLY8Y2u~ zG06l}e2g2J!`jChnEaOskD{0`3<_>nt&ZJlEL?Oey06a;fxrpx4 zg`l#MD545$7mE{Km99PQ_KVgWQC^dImrIpUEW7FL+VKbTD`Z=~lD6xtZ)xUPGaw8} zTEn3>y1WJj?CSWLL&Fat0BV^FX_TD-dQXO`^pBoe+(_oIB!ruo2pS}L7$*DH1j+>N zmo#=9Xgn!7v}p_RvJJZ0BzaZ_#N5LpZVzglN=R>JD_14NIGRf4w0bEB+OXOqir!`H z4OCKv_0JF3eHX)NT8odKq+kDh2w=}vLlo3Hubqo zYAloA`4P+#Y9N!N8%JfaC;97`Xf2y~*mG!>F@#8s9oOM z{Rp?O%ogs#2cQ4|qZQ;Lnv%XgQfyNn!QTpp2-dDc~*_eVZZSZ=Csnbvxq}Q6lepWzdLCg1> z!;B$LgO`yp2Wi0-&2JG65>3PH(cz9OyJ!ewl^pt5)@qmcnGSKlyE8~OPb^IO27VL; zgSf4}F5uD_uS-q{I8zw_&X9|*e zSmsd$f;brDL&cq&Hn!=euilimr9DC_;rNH}Rw7KZ}kQaN)=xH1H^& zW)f#5GSD143=~PnncTwiJe{rakyV>;nFfP4Ijzvzaie;Z^L}FqE!`oBE%*;?Gb2y2 znH_KS8cg{X{_k2Gl1?YH1P>`vTt9kQ;+xItkkFn-(l8w8O?@lNar$zF%ik&IPT7J! zM-1aMLRTGzp8U2@t^)Qw?`kUxn+F#5>Jfly z*DU<7$I*_xbkuaJc|XLUormVt_&FWxih4JOmCDPA6uZdzuCODD;Yj2YAolIpoy?Ld zz%SohOBz}|koq6~R?ohv3)2!oqnd-}aE!N?o-#2mc5dN8$tOH67jwRVsXFGIiBeSGy3Q^grc#V?@cIV_C zKM|!Kb2c{)-U;vrNGnV8aGzdpySAUVy3b~0k;hoZrt@{JArVs<_#?rjOwS-L^ls|l z!caH6TSDS5@YNz&pHoe3Qgv0jjIoYc>J&cm*G zUohV{nBd=6(<-@8ioRw#_--M|2}jG$W+FmexqFrS(}flyL#2*ugQ-(?&IFV z_3G+c@+O*^>YDPU&dJxWKF@9ct1Z`A1!H;!+zW;G>9Iibwx{}~XYhSPdVgegPppo- z74N|_`B^B=g#!_xd}bbw_^ND(!}kt7n1VC==EfY`lUz&ya-vE{$cPDcl^M#qTuRHy zywqARkdHwhUou8yc_TIS%sW>n6sTytz`^eM4Wk{2uLX)w9mycb64v~^lnc#ZOZqsqSK2R+^wNoJAjS?G-7;8EOZ_GG* zqf)P4!~5_?_%&D6b*)dB6QBo@aw3B37YYDS|KK=opIMu-$X;;uSY?lUE{35nFk-Xvb;FELaBFG5AYXmZjr{{n zk>_&{vJJJw8nl#6>T|}W7_s(L?5 zR(83-Jr^Y*7)!;Jq?R+ke=u`Czpi&N)9%{3LpP>Nr_DqCMZ<*)17%yK?oE-Sv0uZ< zED);;wMF!yVpjv88!=GUZ*Nko3Rt@HfAn~Rr-`>u?#^~gQEX@h7b5jGTN|0$ z|EXqMJ&=g^H?kL)=duzWPJ$6*e%KE>VV(2~BbuS?4%>KN`}UZBp^s8y@>$8SB5GU+Datkl4@mU-ss_7AFTAFe&r;Y^GJYF{`$YEZe? zL0zEZ*y=gSUb)O+^?tjkNR|h&S@Z_SV%0&;WfuxYG&{d;|H)dj4*|~j{!Xy);Viw4 zocvtFKmEf+mR=1{CRt-C3Oh3u=&a6xn_e8+FigVIbFp|Oa67EuG}&^nE&f{~r0HZV@z_8s-xOKwNyVVUV& zmi#Ef32FmRPoTtwH9>cL1t8yUsZ^z4V$D}t0jVz$PY(n8oD&_F%o9MV9)0AX^yk_)U@YUu%a})3oWeCdSG?;SOGq>n1w!3;I%vGfJOy$q zXva>Pc~tnh#Z`!F6?me%0&_1v7Mm!Or74tM^~Gz;%?#-+NeGg^b}1REdE`_vU5Y7F zD|X7#ey(Lir%EEY{DO!aTrT;widNzO=JQ=6 zG6vmx-&VK$H}6)S&OM-EIO74$^C%&VpX-j79@J;M)m#-xu1yLp1aP85=jSAohd6ef z-U68trT^+_k(16vvbqePLGKS;vkbM$z;J&qUBJSU^LS#H%b+I;IAb&R?4#MCtXjwP z>mc1`PNMtm-^fzA)FufON>lGq?mO3FQ&|eOI|?D|L-nxaDhi)m%@nIuHzu(B&W`l3 zM;S}RQ*z}CFoadnl?D72mo;OT|590HEQ|Ge(FJyFkkg5tpWl#n=?~>Rzg7lXw#jP2 zO3ECbn!2r~tpo$iRHzRZcX{IJ2T9t!yg_5h90~D1){>3I?^~dV>*$x1hTmroZGW!V zNRjQm1JY{Pr)L>WOe_dKUg!)wj_qyWSIbSuNE)fHBYS0U7MRZH5r&}Q#ipd@|)7G;{ zu0F_6q~qS&z2u%>R|PA{B9HvXSYX|jA$Qa$5YZ(&EvGM8RyQM>8)p8`g0y<< zv~**{zT{(SeGW=`dXl?X`)NX{UJw4b0Ns#ZQedwQ?p3$_rtjCAM^{*@(YXgm{tmFM z$M8eonvyddiBCA7z{ay4NnEP6K<~uPWA%oKzpDs`M;vp`0_8fi1)>yUg4Q8VYK_ao zO0b}lr(*nEnd>BOe12puk1MQd9h9QtI9aw*$x~l^JjfkFxCmUR;BFmmWKyHdlV1|K zkuq~Y$gp60QATOS^|L(bL0oDwJqLvYnd{~4?;0CIBAmYGySeW!FL6L=>V^@*(lX)s z-iHIsG4Qoui=mkGoEpSx7x+d>>~%61;L17Wwfyiw80F3++;Ps6KrNPEpj#BXiayck zrtPe>`mkXjnkSelv(suyszs-+RKq=u8D7*!8A-Bj=xd<^jj)apt#YSXje3l(a*OUG z+ zx%D?zo4VV-1HKMX3I9%*OOCkzbr-eXOM>4fDmL{waFH!uLa(gENT-$QvRs5FOXch| z?YcJquAJ65CoS}Uy%8X7GwSI=`IZav`~Ala#2o!ndippc{RDo@x$km@&=Y1Hzl@tN zjhCfRWmIo6;^&4mW=u`3PiDJ2^_u3?>H}Sh?e{J@`%Eh{{%UNZfX)xv2EKxwKHU|* zk1NnUkx6^RUvQ(?x`vQsG07?TOB>QYQQjQG#=7ZR`%pECfv@Q#|Hcb$rzz;~!hu!g1-p@zzHBP`j6b5`m+Y+lO zi4>E|An4)T)v*q0;~ptrxA0DqDB;Vh-H>z{LpX48^Gj5d|DDy^z{u|YICi1W$$hL!NwO7W18>WkeRYLb8gh%0m zqK1kozJLy0PMRxEww$fX1{Logvw@knx|G}}z|pfUy+e0qhQF)XaGv<4|K)|0@6t{N zT2Q*z%tx}%*BxQt&y6a=O4**qt%1d#dw!E4>ba8f1S#SP`?vN7qx@vi(#H={!+-9m z#zL*JktfIrqfzFS`9D`;+|_7N*wrT8J9|QHI$~TpD#p9Nb^worSYnQb7&_gF6I_L7 zb2BOTOR!nl3`PZkZ^D3BTe1}A7}1o0Z8gvdwY+2@65}BzwqdxKh}z;^pX(l>i(>J= zqbTN9Jy%yV#u=dd4Zu;FNo3mucyYQ7Bu!+cxu@Q(nb;n6{6KOO%S6KU3mgwLeT?8j z}-f(d(^Q+{2=>m`35bJ*`|{{mL8#$3~4*@ zM;rZQeW|OIC>lIP`GtRFIRvDV>@o79J(xEq|7P}f#*?aTT}&`w!%KaE?h>=8Mi85%=AD(=Yw9$5zm*y336fJ8oU#s7Mt23YN|BSygC~y2~&&M~flNAHI zasTz|RHeF+#rF!A!lZ4a+Mz72$>tjPG3>nAafE~G|Gf*v)muO_xzUXmms~UG^=b3|7LHto`W7WaX8rh5C>yf8hDdHntf$R4P)fardJAG1T?C__xwg9?r zBhDZ^9KDHybBM?S!cIB^OqZ4>lIARGIa{g0DYVCtM))Gbx?DbC2)Dn3?mAX>z1`GIe&?`TANQujh`-p>H3{c0RrRkcC>U z{m0l%vfSTQbV-+v0?FVTPPahrQa_6LIltW+&8x2+$NlBq4|_ws-$!mOg^x4^P2cW; z8T!hxyRcwid0oE5Dt=wY&gGqaWpny7+9Wi^&7Tq5@f@i{l~$-gm#I3FLyDY4FHld< zES6Wo#zCOif;7GBl1A^5$(ME*32CC=wi4CBlah2PieJCz4~vsZj~t4#l`v6}NQm*Q ziuPQlBoTZ)rb|()v@VY7teetkn*M96XdiJyC;^PPgH;+jfrq~NCeK+Ksg5_Ur~UOT zEtWKqL{4#JURl<1c2bG$PR%eqFik$maM?g|N0HI{v+Ee|eL8b3^{i7~3$8RwGQbD6j<*Pn3%#Lnm64(f zMcwj8ACqEah-Jon8*DDJ>K~WeD*&MYh&aQN-TrS64ZZLf&8hbQc|m4)$GcTu>_w7=NxdIUzEc}MwcjuCg1 z=nm{QwD&sz_HD3hrq9-+j?DynWakH)ptW*xLvm~O^u&ejSg;NVxS8| ztl@YlBp3!;qTQ6y1H2InzAk_pJ3NqRtR$pKmsO`r4F+vpC`L2PLGFUNzS10>{gu$_ zvE&EPENR%6QhzKH`siM=_s(tR7hQ07e$C`&d>4xp>4G;j20s1-HIm-@C0eY&(BlP+ zxGe@F#NCHDL4#M3B{uO4Sj|x>C{2FY=oQhat?=;(qdY09)}$gns}@}{hO-N>@1DT4el;&R}$g+h&j@nq7D!}4JPMPkORNvzQS_7XM< z-lnogmZbICc@k*%Rk@hf+EkhYqHc8KJl*%99L)I`0T;UtqhC5ND(ofZdxIz7GJkOH zIlzn98Ldn=BfO>D1f!s`3COVDQlTaZDhdh)PL}D|hB?U6rtOcrmUA2Sumt82YbX(T zF(WH%p``r!F72%eCqM8LeW8n5hygZ=1(6+tB|L%Lcj}KX3ZrEEL%ISdx>$3t{i9qX z&vZiu7p3h1Th9KSnFMXWwYsFst#R=?KXt6a&_X&9^TV2bRj3pdOUz!GaB>>$#rG`C zW2j_n>{J0|29h<#?b~8DM2K}Np;vEPRfX&^Z?eDFgaBqzEXJl02X!l_CleLvPFbVX zzuyh9OydNvWQyB}3NV8nn1`Q#NL=}ZrZ{hS>N94@4L`ItHco(X*lP*{Pa+bc8>pw{ zFq0HUNE)R&^zD^}mZ`4oxeR13wR8bSsQK`7B<2U<`tZA5&3KX48 zaG_}E)ypaK;#e%ZA?%5psQLSYB{VR6hUw>M{LlH*2bY$ZM{!fr zs3JJTN8(gzmHGEt!kBZ$bU7ol?RlAoO|-Cige^n7ZhVk>IWSjP@ozOc*epjb@-J+w zVvT*)DgMXHSVt}4G{NW{s1vEc?DMV%5z89I0A|0aKtIPk3>#0r=<2-Q-LAG__^>f;P0bJGpk zD)+k=RxhW&Szcq#uszQau;sjvF?ME$+31YVWoxcX#eB-%GK`yAUeFWnZeoe<3C5=X%oaSO$8&M#dZ$49!B2_5*A&M$WH>V=O zj3l_%4`V3w<69GBjUf^a7k`LionDE5cY(n1|By_$i>j90QbCoghFzx%xgPo{65xlBCZ!R7UcbFTFA>s=K3P`GqX=l#Xr%74c`DrUcV@@m;okR`6E`WYQlJ!UmqbR%d z0Nlrf6*-2yak~4rZ+Br0Ly6SfYbgM?3J_lmn$$lvN13P(+UPs`Dvnn0F)a;UFhu!G z{cat-dsAxo1yj3{c$?@@5$?p$sr@`zd;6cwN5OP~=kf{1DF7(ck(=!?E_!()@cN6W zcU)vQ_VGM{&Whr*)#I_|ESuViD(^M4&~L7-W&Cl=g%=Al4f7Jl5?Z~N|Fax&^`F}O zzT(G{{L~|kW)MSefeAZzTaZX~qBl9^LmgU4qiT&B4^=540&OWUZG)XaR+1{KNPjs{ zIOvH|>`)mfucWM3s;0R;n{loEgP&J&_f*IgGWk-OG*_lnqBQ*bFV_~Ua64t*qbmqsDCEXqlzo)aDgV8}BGobBeNl*Gi!D>mPkh2q5S*LGaB@)PZ9;1=KV>hE(Ol#HoA>L8o~f7i+E|>q8YQh^Rn5@`soU737_P~J$rc_2Laf2qIUrX4Ge(uyC?G~7NPO|)Ktb<)Lq;D zr0oD@_TmJ1ik*=2MR`(Mg>nClUYz1ggQC9LQO&n#^zUrgzAA z+AZys%puH#p=O`vD1~zMvT3XoE;^g)*B8^Ms6@MV$mQ7-B(8rZB@y- zL~n6d=bB{N=FAtpM)cc;n5b+05WEyPwjaz?ocIG(Tbkhp8h@FW)I*9veP-Vv?E|+2 z#vFDuP=eU@F_DnJJh6vl1sODb?WYiI8=x&=$mOQ#i1MQt=i0*BSsZLUK$>F7u{tF* zYkpc}RwORCyEzNfVImSo9ecNx0mcK&hstfz_q2qgmA_vdxc}HNFzEY3)}B>ax)a28 z?yEH0=lR}TNRgpBoxHnnkfcbhja#xVZ0Ck;=FfID&^2vQKQVoiE9ho&OJM2ujs{W? z+P)_Ce%!VNo*sA6i2O#YQDZ}^OhB->Cu4fe^VHWJgdAqfco|B~QMyF>5l)~*hP85Nh?{{(^|ecrqnNg<-N6doO|8+G1HkaN%s1J6v)Q3Ojo2M-=Y&Sarj z!KKj&KKn2X{rcHC6hd9saSxq8*OP@y=WhvPBjovT?9fmj%q@z#%$44dwZpLOJg;Uv z$oOaMQ6bpN0+3<+GGl`AD~#;gLmNunqstAuvbZ!%nr?J;dJwV6>WjFGJ2o&R!?^FI^eM>|6n< zgcZ3ig>+_q5tpw`sxvZMin4UR6=pt_q~b5v=wP;v!8!nRfO zii^MS)Dh)iN@G^6B_behUuRS2a~VbS7CZ`pd=qif*n9?wqW;z*f^@6y-GCyh6$#_F zpS*~zUym!5*0liuHhKmXJJ zjX(M8e?&H$Tz00Lg$S+)KoErL3Oh`Bh;bjHzP!x1y4&Z!5%!V*9B2Fz<1ZNBgAIr; zkmfT@1Ga5;wGe3%X%O%~Xxg6P%Ed2^PU7^D0~n$Z z)LlPqM&dzm6oWm5~e6C{ZAm<$y`kUAxoO8MiUo zzJ-YVnj*hk-gY=>5ONJ@*Q>HE3x#3{&#w=iEM`5%KxVLNnS5E}2qse8C` zZIXMhz#{oY5aoVE>-JN)2^7~VLF#agMzUgd+L^R8iocV9>)Y7{>u+PhBWtdX#XH$B)aTV$X~5F zuy|JD{I2Vv?zlKOJcO6u^#U9`I1HcfJkP&@bOs3-8|cL!{?T9KzyHlYa?SvcG8*GI zL;xDspSyub1T=Mra^_nU0f7j?n-TT)IOD<&UeBty83aI1^#>Tg&-f_gr3`yBiR6-m z^zpcmU)vU@C5ZLOQ z&w1H&5>-0kg)7&XTSH%Oj_W=v5;qIvs4dH&%j>vs@hToZe*rz&G!E1GW4x2u`9%uZ zl-jF|6V$jb-87Wzzxa;RNTd?*_--|_$vcxm@|FMhWqk0r{uFuU7Qv0=SOg$M*ku7| z-I4T^?}yj#zYEyM_;Eyi{|w_h+juqWVmAd~KjRk|pJMzQ#?h@LYcK(xh9CHNu z0O;rqk~XHTI>w}{l`A!jPR`)AqX*HOO~NIqH-d75gpPbXx@hMEs z6j-|k!!(t+$-d5@JbeBVh6j4o_!cyN z^BW-o=It^;mkGPn5^m2LgNz?#{1_r3czjznv5NxG%Xk~(6O8vV&R|VH>>R2|NCa^g zam?+8&&Jjo8XHerbBt}7n4B$Op;X14Cy&5lZ5~~GqfJY5=_HGgM?|1pt*dv5gpC}@ zl1(M(fOTBGHi_xE1=Q(=A;(%29h;#ugb>oG-GtO2WS80ugX`!FEvB4ta(WJ5`R3y& zm8&>z1?mUB&Cy!D@LwJ0LbqFPEX+2qd{P+F> zfAtTa!-1i`RcjLgptSIOw?_b^M5#sYrLl%sbpZp2gy4+~xj>IG-~4-f_I397k?qQD zG2XzqkMVj&VmlU*%djkihD3GA|T|RTP#rk7E!9y6v1-oBn2XkzTPayWRRv%#7J0K z%ct-tcWh&C5z!;EFKu!WnIH_{aPLCo3WcdysgU$F%oP?DL5`99J-IXr#R{&BO>&%z z1ZxxF^L!s8`-gDnnGbAge2w+EuWGl32k?*o@BrTZYrltlE`vDptvojoyn5iH z9=h8m0Ijo;v#)bsQo{CVzzvvSe2wur#>0$nFe*2*0Nl>FpYayP@OGYzxV>TMh{r{1 zuW+($b^X-$zXq?k^At)XPRpGe%_f&vuXgz+1d_e> z<#QB*Je@So+#VK+WfHK2s^diDWh4_e1tE=II%h9QlTIaJk~nIeAW$yWa`c$i?BZrO zhy3o6O#?4HeH_P* zj>x6K<@}9!+Th*V19^;H9>ZJT@gWLbRqZ8Q<(!1{UL!y?aJP~E5kwqClpWq{Y=;zJ z1tuAfFuub0JmXu8xy>f)mH_lJegu)*-?I~^Ak8NikYKaR?@qYCtRqD9JvOIqv^_^$ zx-Xx>&%WtEdx4Lw$J+^yZW(lq+?*ZW+aLRgDoA z2+3s))6_}Oq;k)`d=|NEnyzdsf(nUU{?-)1>!>zK?znFB&E;Mx2;mZu(sdn{X~MP) zh=s0cTvJ2can$;^9UH;f+m1n}V7MIH?&TU37p*6U zkACzM_`|>YEJlV0upZAu0C*y(_|A^?fuODgExZ{-U@7P>c#QE4#zTli;bJ!h;C4i$ ze+%QlZtPH+%VHBsgYFdhTd1?qwMGnTij<<6)sxL1D3sYOSt>NCbjuxK4wj;vh@+e&LxDIB;+uLarA%WqbRSVI~Rx zng97uc;B!80eZPN+p^ZZXAyu<34qK0H?R|Q6w*sgwOS;0H<<{m#1o7!GahDqfpMPU zcOn48j2~vam2vlO?nDk-HKuLtDEZ}jLxvE*jFAkCP6R;uLtN6Q+y3C|UV(dGa)#uL zh`E_FP+}l8alS`~kMlhGd$K$iQ#rAG3^+z7Gn>Pe5JYohtRqkY665z|+)@rNq?bk( z0f;e2$XZ)xT(7$*koe;GuIs6JA`G%Gnd4Gagy=^{hH=N~6G)^I@ahpc+TIrh#2)Iy zG&@!GQWt0X{z z0(9r;<2Z8UfGCX;iB9)mXVdT<7x%yC!}!Mei#RaYw;}nLihu}!zk>qMIy(_|C5n4T z02Fw#uUn1OFJk;8<1LJRyIth74HCJiIKN!?PP%^!;)rr;;(nVYYAPAW0-f~lANV?Y zGARrX=9Q>yWk1q*1|8gJ)wuHDmOvcKZ!90vSSe+V$Wc{pwbvLlu3?$awu`Lk`#$O< z>@bOX*X^f}?ad*mIq=gb#du8_{ z$$6FWr{1sX?wOwNkNupP-Ps+ly=H9%DH4AGH{2sG`46}Tq+AhD8f>>0Yi{Tl!VxlZ4xUXfY-Y-UEjqyZ*|S~?#`@d`s;mbTu-UCyV{B@Sd+jRa0oxe%v=Uf+evPu|Z>;{{3V~(rZkU^D^u_3Uu z(8c>d{Tbf+r|;s|fAv=g3L)Y&9si~ydU89@O1$+cZn%4JgU*`}N+LNN4B;@w4Y$|v z#-INkzVXJlah1OFJ=)>eacpGq#HUe+UFf=y&F1LT3OED#L@w@ao zAwD@g!du_@H*Bo*aj<(CgE&Q;rcU2=RP5t4%We3#Hdb-(&OSD2W0z@$B#Op|GQFSS zxf+dEUVRPU{lRW}vjAjz$@mEWPy&~+iFDGasU zmM#OqgUpH?MNR__1O%N^dq1sl|G^|e*d zgI(-h*+hpnx#*Rq*2e-hKL9a$U%%xM{p~!Z36^&PR%p z%+}QrdM5X0kK}n_!yY9mmKS@ty>}HaKevawH?LuRrEj+`Z{#$~XJ#tyc0|wU7=weG z*Xi7W&=M(|dD44R{o!&S=!E#z>u=$eulxlv`fZJV0yug{xeDon_f4>3%B>Mzk8LyBajeaCRIuIRs<}$xr%q+`98kz`+tIWzV~BXqHC?x zRAz^8v;hn zU4iJ~AhOrnYb&_3e+@4`cLTR}E@6q_Fd(B1;uLvtwgB+|QEmMk*Di13-kp8B^|P3^ zDE&6^)}k4jnk&vFTeAkND${4geM!9%ivdy2+{??dg7i= zL0$rYi;_~JL)(I`;7R`Nz#`-`r>0lRk_pjsn z);eugX+e<^xK68-&B%Y>U+CfP?Hjmp{jw!OLie4@EU9m5YYl_{`50gP^4IZ=zx_un z^?O+EFIdpeLc#(dMU$4@9g2Z-K$tzUPMNl{4k0}LKhG`68mj`=L%jt zxPjhM9~r@bO?nA@$e|3 zK1%Fd-oU-vySRI6$A0gU`3CeJyx~_@`nY#+6N^{3fjkEY67)w;-jIF^p8mZS|INuw z1En0_{N~@|m9M;xqd|mAn`>2tGj1Gj{kX_*lqWPNe?m6uC+>fmW=@xh%@{p@t+)7z z7XV-~YOTBqKZ}RN8#JPU$v_YQlZ4$K~T-jw~_ITxNi)`C@QEo?tSG90Ne~I0}8+PHvEs*3ojg19v3qL zCsd*14a~t+^qq|+1NyB?dofrK|Xr;WdT5d z)%`U_!MGdw9Qs8Y*1ml(+C8ttfXee6X_`3?Kg)?5*pOkU?bay@KL<6cdZTcqVusc# zp9(u~Z&1iZ6?zK0JSFV5zVh+E|E$V=tWFO)?pxU$rht72^k1I)1WLZub@Tai30iZT|9saT* zhAvO}KF#}gw4zg2A#cMzv4SZ>dK%lGgP*3ESK()gd5(p{FNA1J_-8E+I&b~%F#Oz? zwlkB7x4usR;P4kkfjCZW27J@p0KkLc+z0;k;7lrq$FzpXVdpz>_{-sSt0}1Vm53?fW?hS(;Py0*oird^WHHAN{Tl8QxtbnQ2GNO2teY^UlbgEKk9i> za|Hl5p@x934SANPmD7T5q?JHNt2X>IP#u4lo#iE$Bq{RTZ?Df40F^2TWSQTMnUy&3 z{N7#K{;o}WF~$9bQv~pQdC8?|=Do+~4uHBJ41p#zXxd^+_Kb!S0!6$1r!MX&hu@X0 z*v~~#*zMm0%^d)&I`naz+D3T|fsu@s6K)g^ypa;2Qf>HWs9*>IH@+^duS=S**S;P~ zxq5KjoYaysfT68emWAtnJg#!`&>!E53?b;9yP=uV9a}w1^NwDfbq;?~6paW!OSpWv z?NK0*rl~!J@VjXo+;M@xf7Q_nl3u!OxBmrHKpxJJWqD)5&r+@nsCpG3Nm6@ljJ5>5 zNGd4sMk<6_+wZMrt)L3woLbG#;^4D~n-qSQa{$!h#yx_7A_({vlwhpw&)Z(myLAa{ zt>&kB#gOx!=Q-jyb^Xd?Nw_XxR5b*+nf$$JG(Aa-jIJ?|BCs%Mb zNws&3M)PdZ>O5kP8k)05Rz0)413)cqYLeuLp zr39V2akKUo0Jb<0AWbs@L1G~=ZxEEn|FE6v-%5O16$P2VD20&DqG5(;HJ*y1gw~Qg zD;fm>uK`d)AW3q>acZxfK;RtWz{^0Or}f-6P%A&g-V8%+zc+;e-UFb9K$>QVqQqX$ z8v>)M2K(&ica63+H)#{Jnp`|@DFw7vW2_E0Y6Jjk2xM7qA;67x34znZ+rOg}jFR?y ztIwX;o5m>et7yamXbb>GArQx@ljiah%Tvg1=}$xN7}F5;UtIBSaJ3*RTLuIH?d6hs zQjG$@CDT$&eT({zxY8(Jq6SXZ(QxL)r57+V@0NgBY zTDARKwK{`_94_Hc(5lP_76Sa~3j@3d05^-bKg&Hi1CK1#>QvE?0y>0e^J4!>DWR0~ zz{{1q20&RB6n?)N_LPFkWQDKweMUuNvB36G#wZ98c;RVp0l>`>LfU4*6OOZ;N_+Tf ztyaE^eH{>;jM1)3vGNuGtg1;&N_RE1VQ)2UF$A<0bSnGZrMv_{QIt0PQVMqsB1+q5 zpW*SPJz7xsq-u0-!}V$PF#v+Vp~vAN0Js@S`9a5L1-_OIeOcAr$`_RoG#Eh;ho=x= zy9899G0JHjUICzL3hef8)oNT-kq=y#amHmQ?dfWPcm)6+oz@ys3U4=RIRsS`4A!a% zD(%7xX!E)7yf*;gmzPo!02GSC&+vab6k4@9pV&7XeujVxc>w?pzsn|^H|~6#jDc1@ zD6s#QjTs61UnyzNc`rXN0KhUvL5RRMqgAU(#10Dhprz6zH)*Zso&o0o7^Pp6!{6M> zFRB991)NLleGb1ddaloP3IKj-rnJ@yJ`RjSeG-$(6XM=vc(w9FE|#HF0I-;NLI_U- zRJObQg6sd=E2FK}aTto`I27LQ|9|J@InwypZ7DNAVMrv))y^_2r4N=WX=_Bd5V;sF zX2MMX9=6+43;z}ayn{;qOF(~f7Pt_(7%gxS0OuVj&2+OM8m`x-rxesa^N!-@ST08w z0dQ1aUY?riqHX_6fo`K_k7>kplMD?7a5Uxu;P9MI>$0xL+s#gANfHxN0dU|;K^4Hs zJMUkB58jewf3{5yzr#!bec5Aqem*S#!fyXQ^!je=^M5MZa!e_V!=)xM(M9C=;LQZU zgifb*S=Tk}@F%e-rPO8P9mW5H!>=mK(JRG7033LrQ~^9$T(@J~pQ-HfH)wY~2vMtp zYAwzTC2+LBOa#DE0D9j1b8i1Rvr4?+@LOOa09uT*-vtoW%kOz#o@(s&Op{*X%v1un zpt&X!LnLU!aZ!qh$z5gw(4fWmZ2QlX&AhC|bieHafHo_AUU2w*roYfk5?F3?LH}q~ zv}A5Xx&UC%N-2OO84L=*3I_qqAOUSplI#s3;h)0NVEFobcTOvtNk$Ffls7D7WN+iP~Z!YPu-R71@)E zTArIcyaPz4#B%tFlK^Hw+jEoHM7d4CWyb_63HxW;#Pm*60WiUtXJqEwBGUTJJBV)r z;5;AN-mNed0GVS;B8Po&Sf7GYkKHi+77_cVG8e!S#>vSHaQvfm90g##Ak76}o!}Al zouci*jn-z!Z8joRL{-f1G#5amvS|1W5(4i4?!||`{dugTH5UMrALcMzWd^zF~%g^K`Y9i6MxM(wx`{ZIA0*7K*HzgCxeTW=q5ZM3u5+B@?C%I!Ca6KEyEu)Bu6;y4GK`PY8{O^a;} Tjy)~w00000NkvXXu0mjf5Hsja diff --git a/images/avatars/gallery/Civils_H/Civil_H_58.png b/images/avatars/gallery/Civils_H/Civil_H_58.png deleted file mode 100644 index cde1758da22420b8cc358efb232f0406c4d427de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22843 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 VSf_K`#Ml4;002ovPDHLkV1hr}*wO$1 diff --git a/images/avatars/gallery/Civils_H/Civil_H_59.png b/images/avatars/gallery/Civils_H/Civil_H_59.png deleted file mode 100644 index 4379604eb1be2907201e6b54f9371a8afd95e755..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31578 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

RX;{?ag`qV!yTN6wn-dreim-Ombtv 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

Z9Gf*qpJ_rOZ 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_7.png b/images/avatars/gallery/Civils_H/Civil_H_7.png deleted file mode 100644 index 44f7490ab418b5b9d4ace01e6e4aaf2d4b741884..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26069 zcmd3MV|ON9v~6s4Y}>Z&^b_086Wg{s>e#l^vC~O9wr$(V&3n%{|KWV98a39~wf3BI zVI%UVq7)(=E*uC52%?O%xbpXN4Fm)f1P1E+jTaFd8wA8GOGaEo)dTcAWi1}>VPzzD z%ijF_W~F20jxtk06jfA)S|orLCjWOtXie)&%6LQHSf@h#{#wT z)e38o3T=|IvU%A9I6LhJ3@?L3U}wi>QrB6d#o>n_n;ZHsg@)0~$>p=7#+Sj;n`f@Q zmuEn2*R>vM2pvE+@yN5N`H|?Zde}MUto_pj*UZR#aLV7=(g~nn@fI@_*)&kz^N$k;e8F2a@e^KdVcD{(K%;{RJZZ?@%6Y z#H(WurmEiDft~>#xLq_-VdFC;598Q=7H&u-7k=3IpC~z}fB9j)V7Eg2gTG>5L7;v_ zRtrh@eGnk4pkPY5!c6{To~eNzdGYjs>PG&8*$Vs$)1QatqLv1B$>2^ZqbyupBf*Jg z1|*>my3<`h`6Brt`9XYv`9pq%leg?({hhQNx7q?MAv%K?Y_Q7&=kVz>r|hW_U1^rYPe-bFr-Z z?RkC{?H%I+a_hRn2Hl*mUorwQf&HA2N!v~xQ;xd$YDkAWMsU0B(0)*g?vDd+>;>G| z;*#1nP6SJjfBB5DU$yw(T&JAunKp_zl9C`pE!H=6seDbN}+Zx&3$(i~!&}v9(L@V@lwx8p z=Y2rl58!&7fED(z0n5qeFy+;N_Wa0ntu&A;Y-$GW8uIjRT7Hgr>A|wT?Ocg1$NIOn zhhQ55^H7;`wMwyi>FzBY1u!$rDc$77=TVa~+iSgL@5=CQ%V_S&knMEugeyjhhzIWh z*9)f`jwracw-CT|s6He6qXey5gZAD(_umYaGh_t`t*xazkFOP9=*4q=|NR|`S>sC4 ztyie}k}SS?_on4$>;z#0{hc6CW8?$gLn)K&;HgEMA!^9@(|5<(v_TKA8?Fb!9|BpT z>$grIlNY#1vkub41k?2TkY~jL-lsEE$vVf@h(9k(n3xlO+M?`PT@}h)ACOXjjX&9! zJ9oS*w`tGbFcUf9!g_vW?MxcDbO`zkemXGSjs}-KeQG_LYs#O^O?JndsAppkV+7G! zt)3YrM_19-$(ky^taQ-0!W4sWv^8O>Y@Z;>4iI zA`Slo<9&f3)3>ZKdo}ihuhmWqr@6@ord4aXm`9_U>e|E~%;$QZ71-WuG0$X39R%aA z5(nKdP<492uQ@z;PeXx_aq=b^o;h;SLm0e58hN*p6cGq>^rG}|lST-Og@Q`oLrc2A zePa7@{(oZxg&E0WS!b-H^0p??xHCzDmEwcGq-*YX=F_2j++aey@JHHC_=++tX8~^3 zmKor5e?Kb*W|V66f(%|%%qC3rI7(+Oc}pes{xWx6+71t#U!pf^D2q9EhOT^V@qwCu zMs@1q=p8@nL{3zd9OfppKU8*gcVxUpEn8XrjriU)VLoAwr8eEHtV*$R;hz@?TFkWa z73-HI`SN2wqIRQePsQ}j2(Y7d=U+aK3x1Ik`c$7;5@6O!;&4?b`juvAxoowlyN=wiW~p^9$cnK z^o83qFTb1sHtxtE7NbFL@of9kXlRhOKEn=1tur9J(Nw5v8|mv#Np(HW2#kUzNfAJr zn5SJWDJMs#TE6&>*wphVca|CQ)Z5Cn#x*iFVv+$>tSs{tZdR+rVV+>jhvW}O6vTTv z1cYMLtepXRg}xNf(xa;tu8@LbnPPuuI1Matk!61uz52zlFE7fJJY7yP z8yhoieZ6AZf;%b$loP4LtKL|Vv5_ya*s$QY47vMBYTQK_0bF1+IO^*B;Z@+1E4D| zr5c%V8+V*C$kJ$|UamiNynC-xAE7%yE?Z$l@b+&DgtAlkSc)2>i1 z-^`RL^^5mdS_h4*lDpCmSUW;_5VIuU1_9qY-~QLMWZjzG-%kpaRlnEgDz?^Y|NBu% z;U~R$;#pf-&*U2SabRJe?^KoLg8s#ZXd>$k26> z&7HT8psruLGeh>k#P@>fhD=`OjBc9L4sn7T6bWWpYV`N5xam@%wrDWgd&HW{*;8@n z=%<>^+|P#yEueq8@ii$#45(Zi!F6Xsw&6aK7ML;(al-c?_dr#DD@G3`Se6oPEN&>P z`IfhtK+2}r&PxbCgCKtH-zUu~R~FUO1NR{{vMqK_Fcn|?7ZzuM?oZA0(B)^UF9aV@ zK~NI_lV#~PY?=%eMv1bwYjqV0vDccm!+O#lZ?Y_<_UyW*cXd{0I&tcksE+4=|S0upHnuuMysneCqDnj$mtC zuT-91Fu&fEyt79>|0$6jpiKxMLkMNb4d(iY<2JU#z-~gZMP)}Zb>iB<*|T5cx~psb+GO{>FamZs4o#U zH?e&o=gs<-Zxj@3FuZgkhm;}Qtj$1saCd*30zXFnD=fY_DVjvNJ&Eyi^Q8cW1m=qw z#eW!swD}ng22d7yKf7R2u3S0u^=u$iAlWEWb2j^LhKyaAc1H`0hH7>*tm_mfYU{4B ziK>AJmvVVoL}WE-*)0g9{|OwIh-RjeiC+#xArkfHu0Lv4>^Q1YuOvzc2v?ra+pAnt zXM^n56_LM~igc3?qZA?WlVeVC6X=mFQrYO!K7RGbA%t4{WNDF#3(Q)+n=-k`ofYn| zKgOsEBL=z0u8j0*C^n4H^^MiEd-nq_L2gb#86sBjzup_Nm)7u?CT8gF@O*nO2HC%M zJGv-g+0H4}dY_BzvC86cNw#ngrS~Ou{@)IZcXYcLH#Pv2`k!mN9MYY%G%`GU%*P`K ziFHy%nDqWEgGMZh#*{-OgN7Q-gVOfe&j?$|O<>wG>kV5_+N&MO{R1`C`kDd8t<_P$fPWq2n$$=Q5^H0F*E*B^yHb5&udE8OmQl_9*%2R0*i$0yPtkAXjGUUM}sFhX#Is=sgNSoC^ zBL0qoi^^p(LE&+8Ru`j3^a=S`@CFn;pP!pNnxYA#k4I!TV&oh5``mh69*QyOPNcov zh{9U)CrwK{(ggjIES6dN#iBWr*@AIXS?n|08TX(V;Ly8mB#@S>2gZTJlCq@6udfywroaa;~H`)-0M4N1(N9?sS zCf<=mD_d#O;H5sXQrd>a_?czr8%?5u9vY`akZ&SIB{QcA*Y9yGHtj}r81uxk!tA4= zJHiTz_u?mP{Z;LQ?@D{&iX=M#wI)0WHNz1br=&DH|HChrm>VBvz<_~d5kmGP2ssZH zA~T+i@?ophsmz(0urlS*=}qmc>*!>vwH6CoLiBeSVHU3-0YP?F?~fnuM`9N;2zZ~a zMHLlw3~Z{ehgF4a=v3>|Hp_;4&nM9czsYDZ;i}0@4kGlxo@e#vre*J!h4ki{V)mBV zxmV)~zacmy{)V8spu)Q=eF7A|?6?zCu(_;*g6K4IsDo|AXx@zfu~U~)d-CCm$+u|_tEnVvSj^=fCq1VcSj@I@oTf3=DQOVA zepQBjKp2zu-uSTm22K_J6$fNgGOPx$o{8LS5m+=)K3oSotEx8MhBQ}l-)GsbCF-%SXYb6L|nEH>8Y zSh8#^%v)N=pkD`utS-bCLRF8-!yuFyQ9!sq6nxzxIBc$#0C8>qW#VCu0b^jA;kTH8 zxGnSQU(~PRPue)!OkQ^3WxqIW8Sk$DJgv;9_5K6sc1gCvj;g4T{dbZ73J5Vp(>X7+ zO^+%m4>q&&J{`ASq3g{*k*sNB?$5x z#i{lx-KEC2DctE1y4cg8GCBo>Wgm&fM>H8-jF&U|4*sK-BfZ>!Qt{M>U7lZv*Z(rH z%lI^-Z#U1OAYo-3uE`hTXmNvS*BtMIzgG1pu9^;xrfIOh$XgBNBk>I z#UnXaJ*bPG2BMgXdr+(+AB3F^%{vh%byQ230;E}s8B`H9fXI8amDO@-PXCUWJ*KYS zFR1;2oQv52hV!zmi2&#Wbs`m3Lj=|u+eQHU!`3_23cEAy!=;9a+OA4}^^71S45LM; zz%LTc%|F_3Is`Pqa?KPi+0_T0&l7D}Fs{ zLl+x`#y;rGUs(Jy;r$qIPcWb3f`k zU+|umTGcuw;F>SD?R_Yz+O%?Eht*TqfQ1?Dnc_q1=_K~>Wrl1?OSo98;KnEv?Py<~ z%9hS<#(fUXDJ}M&?LIit=$P``$H)0@cjXb*u>^3}n(9dzU5m%tv?PYVvYaZezOhPw zr>i{V(6ZcoK}mt0Og#C^L1twXiOk7*9Q@w>{}nwJYbY1luJ2-|yQ)VvU*@;3=D^_f~InL>cLJoPlV>yt8@Md@s+9 zZ;3!H(B;BX5R&*DcJQ2$RY#J*-P?fx>j%ne}AmkqR5?Ub>La#@BoCgXQL)iqWwS36)`FPGsiZ=d*aR;UdqVU?;j z-;FITRUVi!25g^+&hc%F)h_S1UQJIw z*6;bLC(dreyO*i?$PB3OVkNP3pCfr_a@^Zykc3hv_91_iqyWr3D~q*@&W3m1(8wakHlD~@|1r46S! zGoYXq3tFv0?KQl0GiAEV;if7Ce%oadubt%Tpq}%QmxQ!i-vP~}%)Q(l&{N92gOq%~ za3H(td@O}@%2ygsAmB$tGsu)>@Ge=;!;_An$XSoWPH;HZ-ThFu2s3OSV+d(nA+e3Rid9q-{UVDyCMh+&q)#MPRjX`}ZkPbv~~Ak>8U(OnYF} zZ45WZ03M|$G{hpnpu=u`MMyEPY3T?peIHNySJ`dE@c0zqu=F@(@u=KL1 zlz2m|6wf%e0PX88vi?W4>ff37z2eQfooY5<76@KaY#=pQ6WA|vBgfG1PLJsLPUlHl z#M%k>fvlM>pK~%i8m%t!!`_QfVq8>T=dVR#M239%vNwyN>@OEx=C-hxdVitUbEt1w zOOYsx%hbeujT+F_%%L|sf9VfK;(>i43;u~SpU<=Jy5&!~^(4APFFJM59%MeCy&S=^) z8)un%$S2Nj(^vTGI@A4RX3uP8VnrM;MR@k$P$1HNgI#Jr-fWm=q{Zx~#FCi!5T7u!<(J_kw7M(3sLE6yn|!B0dsAjSOC4J!iylLs!-=Nw*Z`J&}?$x`GUl(KE% z^Uzv}43YmQWYq8we!Lj%b1ydl$SkleRF-f5lfoY6(D25BY5-WVH|ape66 znO+*3?&9o%AW*}yD}mpoB}=~oZk#2&qU(5T|GaS+omAZvZ@0 zib9_Vi2))gGWs8NT~L2VyiCD+iE@=P0z*m>O#*B@vxwmi1glkT?(bSR`?OE**S~=w z3Qwi2JbM(dB3&28ABj`9iOs3H(YGKt$`<9kgHCLzd;|=@Wk$aW(vApCV;J!!{nsAj zxnF`}i)d2??lLngbeTYW=JMUV_mh5{91@_)B7kPb#h$K0O5w)|E}%_2{h;$?X=D}3{)37#Q(2{hw;yTOQ!`8k z7d7r^a*Bw6W}4+3e8AjD$s-4Vw+T`33|o+tXEOp*2YKryhy@{|4Etw9jt-;U_bMNV zxlWGVZP0ZmRl&v2>-%1oHBurOxaGrt#5=~%V5<$@Qz-bo-a{F=7v4CQu zY1H_W3ZU&25X*uT92=W_-1i<7B2%FNNhL`I%KPNNOS8|5>8?Izv3EaauIm}2fO>}m zJ`9W7G!a7P5hj^CRXu$%g3%B}xspN5l_WBTSsqcp{4V%!fTqBT70An+sm+JGsV(v&b7-^f8r^-j-n{9G)q34jfb4M42~cZRohWJ=dk(~bjJ{eAZ(Sf zfaaE?QJzr9nlU)BhHQB`W1?(oLhSWasFY}}#_Mfel0AEtTWmtq=1C)fy=%eSBEhDD zR*MDy=ZZt%s%Otie-&yC8IcZ%F@FVM%0m!D0fF$#AEBf={#-9~#UhJ^DE;Lkud}WY z9ZE0YeTj~7t2GA7tjMvFzUP0-m)W8Nc4!!H6((Wt=N0aEGpeBdJGbzU&}WY5R3VTt zT$N^yO+!ELB;Ca2;ocFK3B62PFAfbNE}GdZ8w>c&4Dg+&IsNS z%+YHiC#&RJuq*T)-RtO!INfJb{Ln6R!kF8uYtHZuBm_8kfhV?BpD<71M&g1X$%ZX7 zJ4$wvX;T){^HDAzj{+5{Hf@3h9nNh-$5fWtO7F3OS?Lxj z3tHqGebUJvP;tNhF9sw-bssv`1H-7y$h_pf_b&>7N{-~Bv%SU--w7AsSfZ$Y_i@oc zLthJ<7kVgb{+Nl>=-=ey;mjpVKgYz*KYZw%XUF%vYN=S|%H=;PR7&Ep@Yuay`F$_e zG1|TF(6sg2ruGM#98YiWmV2d!$C4!q4V}YhBn#~ra@eS}Nw~=Tq1XNi*^#nX0*a=a zp`-6NV>|9U48DGKrcea1QYN+hq@O$gF)t5^hI{sQ;<5xxsu0G zRad_$Qk~~C3d(8oBiq%>nE(0tF7q#|CM1*UoN78Q-q2_-Y-8bS$zM##a?P9qAIIcV z24oXj(_Rk-MP46T1k@apqg&P;U2+YYToQsqTBV!>Js-0j(12*(-kW!i&F= zj(+}ly`1en_jAbLmjZ*f55JVrbpNX=Pn^6^ax{6T$0NFOjrdZH|Bq5#bnq?~E!(wy z7qrTS_SubV?B4Q77T7uz(A+nhd1Qb;R_*1sMcnXwCr#E8Fc4eWxhlDMhRr~&LjJU7C)Jc4qY)}g0z@zQMcPI6|-H=|Ro@^bp6 zR#34DIijzUs#;k#RO`6xSx`V(Y-L;&JwhntgGMuzh~1E#sMTD0Se^$biW(Cb$5}V0 zWV$#2rACQvw{Ycdcjt(BV;yKrc#G)@l!RZjlO;OX9VcS;FlC7YVs{55&yjY@0Ocu= z>rtb|2z4}Bq<_)c_14#bvo&`2jC%v!jG?Zdx~Pz>P*oE5)kdK< z!)IQo;1l1B9C`)hTWP0*$I{nBT|D`_53H8J9J^KH!e|0eQx#_}i$+`!Dg>W^qCggj z%`;Dhu~b=hw^#mZL0XU|fD;^TJYblAb~!` ziD(uyAjA(tkgWL7cSL!qP zdFKI#Q;2IOH1bc%Vb?8;V)E!lPSoa~0ACEYNr=h=2zWi&tpJ77px6o1<94t2<07Z4 zox*8kFhsZ;Cl0@n>@#i|ZsZVB1ACvKIr9rpATDQ32_AE$9GtTFfeADJz}tm}e#rMnP9D?c z7L`C!X=LM+a#w?RY9_@{1It!K$;hy18b*~a z^^}vM6Us>|7h|s|#vDP3@f5Z8o;qQL9>~3=Vu1g(##W)dZWn3b_R-A)P&`aN+>wD# zE_M~JIU(lug*qJ=5Ek7NjifvO!gwbfsW34uq^Sw9t{|$CuRflJeF*B?!Yx~3MaIAO z(S*nmZv*no#>U3p(@?OLL6KX};$xep$F(UWE8?mCA zkpx!f;&5KlV9+~5c%jns`V;Q_?7hEWc90)u(kj61VV5U;+t?YO)qzNP{U>rr7|)7k zWtlrbqXXHg-Ha`cQ-Ft%KLm$EuW>OK%QPJ-HVy8U3%qYgk3S^vgE+a4Csm@xmQ;@& zF32n+w@0CJ{BGYIKA9nAw^5p^wDbh}>$dh}HTF!ke4z~1Ly<^8_9$-Zr;RlY$lS(i_;TSM(Ff zk|XO5o`x*?-%&ez9I5b-uS@=(+lMoKlP zkn3JFbImeXS0wnXaeVCL5pa~FarMFWUL!M?oxv$8IMRFPq=s4I0$rQD7+iCZP%NvA z!mFda;2*94)=mjYuuKN&=~+JoI~@7ux5JiuFD9df2tX+GH0M;4DHR44v|RA34XdO@ z6GY%vo1y;A7mV$SRj3gT40^IMq`9nno6nQD{sYw{38x!uo{_QaRLi?PrI(&Erf_r#T-YVHA#6w@+|qo0)=pEo7HeJv{!#=M(Wcju=}2Qf@8+!$9YWwz>}BV|5Z1`ibJi|Cp5GxN>NEt z{9ecQ0zOHVweoIU21qM-gMp(+jYD@SI#3ZZr8OzD)Yed7b6Ihs$56R_F|N?BFRakd zpslw8fY$Jo<86Z!Anqw%KI?+(oq z9J6eXhJ|ll7pLev<3xFd=?)rETP`K%C`zvEsr_o9WuZY^cu##*&GumZ5_vbfLqpE& zGHFp|{QFgZW#gFtBiVRXImh9a2pXQ+I>SZ~2U+G`Xk^Q4Z;kIXgQ^S+XN#|IQ(|ITLv2ITa)jCO}`l?APFWCnhGMlt-Z6 z36_!X^r3hROb$~8{J9g{5i?cZ-2@H?IvS&m_1_c?wrhKrSZ+<#X&=9TNau5NK;%^4 zgRl(VBm~;XQQ|Acq~5CjHFJYtOsA`j9ogMVH8Z?4e>N#>m{$|Booaj&3MloKhp`M zW+5sGa#1h1VtjCRKGG3@;K^uWZ`PzICmO%cjF{B980IqIt|*W$DSd5<^-P!&NQb$v zOV^yizhEU#0K$VRbD5Su5*w8ne5P4s)M;6&I_QBoMP}!N_w?J|%)=93`zegq3+(}# zH;kD*?g{g5f6lsjL$zy5*H^-Qh{l(7%o(VI{pfhyIX0%1MT2@*D8Jl zh3fjRNtWfaiOCI@AXf8{QKtEnDxh82jOs>nU09cVLbh4;{~_O9t#{Zq?5r@Nx~UBG+K2JmL1bcFg)f3mO6}EyRtHn| zIyj!PdEB(!=q8110y^V*OC{$DC%E%pLT<9Kw+Z)rw#K+DQqfAPLI{cb=aJ1i>l7 zBe|gR6T_QuTHQH;nZ2J5#CPtKc^v!_ROPwi@8@2P6rk#BR?7@q$i{g$orE1XoTs=1 zhUHdDh5_yI+U8RSY>W%I3g5R8i>xc;Nuv9dcjG2Dx;C#D(_MrpT0mlpX=yn?KF6#v zpgz9NU9Dn(C!UMmkIoepl@)0nQ#m)wY;jNZNrn=S$YSV$nzrHOK>>-uS<)gR#z|=O z{X|(17KzyjhNKA6FtDJz&=5QH5cW9U!_F3$|GK*0F4nx=T`w#QJT|YgDr#zKDr&m* z7S^se-(0c}__m(>uAca>f^~~-;zEYZal#zV^=C}N9c+mvN+QdP61T=tDxzK;Od=W% z6L+`0_fy((I8O!tLVGGkFwdyQw&6Th13*6^EES%}Q%J*NAno zhxZE$8=l=@7{HvM2xFkUq}{9#+?N& z-&(p8dJoO?^*_D~&#PY2(Q>i7tujZE>uEqQypuS%oa753-%hJ9{muZI)Ky4bZBE!Us z4kj@Ch6styf|Sn^QwFS*8DW-PqHXx{V{|^u#BS+SPeh*1!w#$9(Z@eN368`#9(1s* zlD51;)K{_-(#OVnG&_&m#&`{6eNthQRf5Xw<_46?xAfnWZJV4BpcF@5aIyd_pNE(# z8f+yo#6as8GWj2D<3@SCbCyE^b8p!vnn(fr{tbSnV>mC|zOxmFX6%B~CHBY6-Un26 zjL17xj~>3G-cWzYHb+xvhZx7j!4}!{=Iv~9}`SkBu9HwgM8(o-@^so-cjecfS<3iAy;nLh0J;7NO6D&fPfVTOR;11o6o_rf4 z8+ijszcLB(lS+y3aQ60}KjU~|NFyAfZ6SXX@Z8^35ukIOjatZwabXV8E(6abD;Y9i z`K+2}3Zm~C(~lG=m5*e_KX$thXFQRYl3oZ5&MdujpZ*1!Y*TFa&BOWi?^Z=lK>1;L zpn9YdF?)sv6lq4tm*EzhMGX9-)ZlN5k}z>OkRFj@pA-qO(OE;$mCsz`$e^3(JxD=XK_<}cAdV2f2rDHQJ?vYT_j>$i{6>o+U%gF5 zzrUww*xyJ0%G6u>jdsB$URFatBk5Iv$6~gLwX-{vR&mXq0u{Q}$r$|!Oh_O;5*ce? zHgx|EV|FIl9P?nI`C5r}7fr?ldF6!%A*92Uh^v_5vNq~1MXk-T*HxRu_7~WWD!gCN z_q<|*k>inXECRM5PIs+D6|_>fKxVk!-gwb^CEXu)9Of`}G_XIw(j5jJYO~B{`hfuU z4B{9|g3IBavVr^~ECsliwHm6dh8{cRb`2gFF-Y%Zbcr7|8IT<-{@|%48Yf9u-;`yy zLHl4ndv5oPN4-A{P`_68$_4MEhmr6QBX#s^MUbzJguZCeVmdjnyJVY3(>4zet|N+) zVktyHDWpXK;0iT&;*2e6%Te%inr|NEdTT)@_G;z;q2!}Qgzl&+NYKx4?U(+RE!hsX zm8|fni%%{_lu+%?Ypzz5_K}mhSwCjd!$hV8Ua&*V=iCZq7}kCu)li48k)yy z)GWr5N8U)q?fquQ%&e#~o-i26+=8?o(aW@gUMg0}yr_<4W8#d%#*1q`L*%SRSy~IG z6Wf0g^dvT(WG`Xl#AGJ|=l$4O+7+9CATA8P1-;91aAZ&XO%KCppYCE;6CwbG?b-Gq zz6p?T*^6|A;wkoE9Iw?0`$SFkChUQPd58D7$xX-;TG%DD*`_y@$r9^oQAmm9xB3{?6p5pU$rEGk&v%4mOSZxfB&=#mY5ZBMEc$B&?SsBEx~roV zK|4s;)muy)@%M(`X`7$z1%Dzf`nL|M3B!!^u2_3U$cwMjOxC_pO={F_{7zLa_)QIV zM(W6N+KnUsO+ilbHrwFJ<{v+T3F-p%M#Y7()G{nC4cAqI_p;!pMy+ZUh+9|7ZAj3+ z)Q_XaYuJ>slpTmcsQ_vTKuH?e&%n6`VFW!gy}9o@U)&Xpiv&;dn*4%U9wr@7Mlbup z?~LLo!+#Cb%T)iWkl05CA2!cgA^UHN0&D075nFNn(8cAj*QVK<6$dyx$H;y(ADH`I zEh1Lf+5-yJ6>{?xyZDu{G}L9(n+S2UF1HDoVZB~f=X}HrA?pHlzgpLeePQMvz-jmA z%enEU%KIh|@-|y&VvKj3vOFePPj=s{9QXvQ0DaJ-n)+J>;WnA1?%ftQhYavNyn4J` zQal4Fu@=gGHV~GQw(JyEA(bT7y}p~Q(On}KiuU*COHcfLExaMFZxc%r4E#&^)Nqar zDpxst`86AV6pQ7Q5(;nv6gxD%qD&x=IRiNnQSh*0B1iY9f}iK$FvHAn=j#YW1O@SH zcxyWV)iWBWbg8{}AF&7&dN5#-t)ik$6(Eziq-@hkJ{ z;D|$52AsE-a@Jj8i$?h z?0{fwuji%FbAMOhbQfFMOQ_!t_ykCp+j)byni|6*&8t~C;#h}c{X1@pO0&p6;6fJN z_`TY?X>J)N_CuDRGe*+jJV`jab6h^<8QnPSAcEW7mF8I^w!H*3H-39C#FMtwu&j61 z*NeNkvfUk-R!wf=SzFYtRqgG9rZ5T6=rYRe?rrWh^_Qpu!Gq!P0k{l889P}AH?x969*=J2q z(YDUZa*PzMIBSmO$y24sB`Ey1lk+qd#||a@e{z)89w`5GGffuEI3)zP4xIdZ5%)v+ z5#9KEDzYAMXn0`kXDxabviDqoGx`>7>-pb5*|{{R9c(QNd0T=J;hUc%VQLnLVIv9? zWF2^9c%6f6<^;(NNm)*Cc*fD=*iH;-$Q?)p1u+z2LkGy+1YqP9kvU=t1h!m60kh6K z>&p4{g(=&D>ycDUO-%zM{h@q{e57E8KOCrX{{9dL8`yDMUeyL&9A3H7%zqR*mOq_u z9kRc9HzB7P(?ZRLo|i)0#ti|;+oD7daZaEVm|*pT9x()4E2u@pI3Ejbf9@%=K4s8h zSaq`}!5Z_%4Lf`L3CE@JUJ3R+_;N4wEBJ-))-F{5d@u6bVuKCSD3S2UF!tvwn;hRV zesaOOj-%;3V+RkZuh^qp&AIWz_5bAFXbRR-T;d?PjEj(T-y+CoNRG~89vXECS%j?_ z`pr0Htdrq2Ly57j>l?mqo?=b+L=DFu<-_FMHX6$N>Pm{#+}uoi$v%L}Xn`&(>Ql;2 z`d{R(*NM>A5sOo~3(Ug3lwYM;NYNGgOct515%Q#NL_bW4W(F5NMA>`6Qlj@cj>K@* zacqQ8qOGg?c1SE7sG80pxUL6QPhg0^NT`*&oX9jp-K~J;%Fd|KP>9>j6H_+ty|5=u zi9pS5(eNb|pPBaW03&o$4+2e0wFRf}7M2M6oz9Z!rjl})awOAC&J63b*X*Yl2Qdo@Z7M`% z_|4qK2rwk_v&;Z%H;*WMaV8|ap-z#qY%hh5O;t#pis(|JF0rIzVZ=dH?USSnM7SwVGJKv>|3*^=P)WBL`A zQ@Zq`TxJcTn;>&=r>|AH<`RWYbI(iJyRk|H$}JpppsceM9Yc*qd6CN~5x31Qd_4XB zwR{6Uc2srWOIgK44|aY4zzRP*a7 z936@T@)>d3Rtqhx2DX0Rg1BWCVM0{6@y?7DA^WtMa-jmzdR}K9*c2kHH-aHL-*}~2 zl}6MdtiG43ajb=}u6Sa`BB+TH49 zv-+}eFD5dgy733*`r|BtV`i>^)DV1p5_=g66`37~PH)P`IyF=}!4w%<$k82cTBE!m zWl%}w{vW{&pF2jq4zHvZ&dL)$nPG34UUroUXDah0o4$)hjaFt!(v9hmpDPn!5hYw) zkam?c84jD2;>%^tmabOWcAbuyjJnzZ$Bc8u<44rUrSocP|A_i&Mq-hK1ga)n6CO$E zAMwNi4T`h-nN{Q$2dG@H2YgF2^6y=HGv}?Gion{A*W`a# z;7K#xnj|sun%g6|0F55H!$@^l zTfIwv5Op9^#G3fKZP`oiV4e=$3kfHbbRw(6Y2EuGz9Sj#^6iNzBVzJ0_}*Od@dFnr zI%wl$xOvUx;#*pFEurI$&!i|)W+TCK_gn>W$G-t2FzBMv=K=hJ!|rv65dciap{bP> zZcT`DKV5f>Db3%45VLOh73!x=&1%J53FD#g@b~j`8pmU3Smpd0=x5;qc0AOi``hrW zS8MD8)Nxx7+VNi0k;_7-wyl;QkImV`VO@N&w5MnnV`A(S0F7debgR3>C*B>$Vf3L? z$?YZ@2U|eu`#H}{J}=}30db^J)PNE%WTqVu)Ez`nz-(UFEfa;@!krD#*VK-6*s1kn z^TFHY;oz*Pz6FwMuI%Suu`;OiHcsa7@)Ki5kqE+YlaZ6QSm^pD;#A7*H^GBz+s%eD zkbMP}h)Oc`PYjg)BuIFzHqiC)q1Lz~FhUMmM6be`66hz54!Y(HK{3`>y4LILfd%E6$fn+P9G%bc^h4IN}F zPpfQ3ef_)<#%!vdlSDH^r3|{{@Oef>0%+gOogyLlL!a@G zKW0PzxTa3&i!y-wx1h=FkOdQ5T9YlMGwGr64kftx9`KzQ)uhNbHWqCAF|VnpW?XuI zpjmXQ&!?eHzvDsMT^GS<&tCh11(RQa#kbxyXf!1-G!?U%%Av#Mg5pL{Bd7Ea-BiR` z|2rf}@BLdO{1w!6iSJ-)78#C|u=Ae9c~BZ5pVAcn6T}4i-M*NQ+)`S3HvsEO zvq=U!zDmWvj_nkr$7q%cy6g`%gCCE*9aLIQx3n2I&J-J8{1)}*K}qoZA*7%L{ofkH zFwVvH0&8T4dYcCFxU%lgpX^weKW!gCn_IXfBTj&kRcKOFEiA#vz2$0_0OK0r7 zC?K}6?V_|Kr};(v*;W)qG_!%WPuv>|_jNc8aqGMe5){bDc}!30L)81@2`{dm|DbE4 zW2v=R5a8sz(e7WkX6U)uc&NQM7>Sk{kuy+MvyL_R(=};zVIrG_+eeM-c%5y^r0Ttl zt{S{G;0fgRb1-`Jkw0VfXz+uWYuh3yOKZ@9Wn=nywh=4z@40p+X`4K{xF}2m=~coN z%KOIy&T9h4%1^gSD3ft{z{& z%tXa}siKT}nL&tsGk3c28LS|&;2}3cS$BKe5lHrM3-QGHL1~%C4vQnh-plX4>POsb zEKuhx#s3$psI|$h7gx#>U8C~%M^Ga`EWe9<&oER$+JB?3&fZ>h=t%f z0vr`WC;&Ss^IF0;GQ_N^DjAkRX2B$@m?I0n8pO^HD})F~=D9=cLEgt<_)UPkc&s#{ zCbFU=+e>$nwOg;fTha92LH++3lKLY)Hv0e3jT0}n-q_n26SC{u;@7uZwDsVo5a8wK z-;b`Yg9Iw6nvvSzjv)$?_S}94@M%o3ahLb}fb^V7(HPFqT?noyBYz{uPGeB%oJ4UH zQ|O06Y%WCSwcPXC)ZQW7w6LjjJ(?|w}XwXkrJ<{y7nbaN5l6pPR(6f*$`d$^6uI#AqqEg*(y9M7Xd z&N^_esT=YCq&uOS2_`?A7mvaKP6F|HZI67{-%E0QDnm$yrK6Fcndk~Bsv_p<&JS@! zaHGyL>|iV$7XsU^H>laRg;>QH%ta%5h8F}vjLHD9$#7A-UWrz3z8VLfttzVCdG&q3 z=Ybc1-vDk+nFgmKPQBO$MI1-sx4F3@&<&7=g*N}hbEz2TFTfS@t4S2Sj&B~LR8OM= zq+?eIK~xn^74PG2vMh}xvv`+e4unt@nY4mMIUpIGhWLi}kwjTD>1hfQ{}mUK5LLa^ zrh2nYKAf2yR>F7e(v%oOn;3t`V+Iw4#p>DZck3aw*kKj`~e@$ z1djLA#+ek`&;WtFc7vAR_%?15Dqnh%G^^kj&tJY~73Y2=3VdZ8Ck@c;eLo=8GKElv zjbj(|{M2pZc(f=-1q&)l4*tDxVtmI=)^^;~*&(z}K7J4iL36H2-~9ZH8%hvHBxT?9 zzT@Hb%{6LO)@2A!65<}*9{wEgH1ONNSAcDLi^f|^Y$8AlIc>tV)kP_A?YFnKF2D1! z@Bffw6v_m_?MvV&O2~12%9+N{aWd%F#+c1&txL|)7B@WLU3qtuPFS=I_D1S*W`{LbPm$-95T|Yui!9)2UqYhc9_^wA4_SP;_rt({l0I}?XW$xxwt(kC%n;n5cPvyt40@jNwk5J14{#}O8j`Ll(#0pf zPkQW`=P*7R$9&>8^NIc30L;Ro@OAC=LK*zn{-X1oMqt4L{?C@XW#V!X={Cj8r2GE znm*3*j{~0v-Ua+i;KoEw_k_n=No?;1J_Y^XYw-7nJX z-~1z?;+Vz~yqTTH^T59V{x{%F>FiHLycNX8ZuXafzYF}CQ3EAOW^sfwh87nKd96~d zcAc+3nDnk6fRrH!tL-sCAwGO&g3K(Yj;Q#Tg{5S|;;E&KoN+cu91l@iubPwH&Nq|K ziQkP%4Gn+=ClCFcb5mr6W^$Go$4=S5H$Mo(IDXHfYuS$YwG2ZzFuNOzjhjgr1@zQ& zFVOPChxG8)n^edd6k-o!NRE^IFz{QzmwsZ=VWYkNu4b_Q~WA4VXb2f?w}dP7J6L@h!9#avF1Q#hN{RZ3T!2}l_av$0{3 z?Dn{htIp&tA)KvhLx^BdlgLsd%QA#;`n!b44s&>LGX9+1x!HDb9|-5QOgJH4aMO@j z(5OKS)QlQ zAJYH1zCy1oR>;tlah$FH%zhI1x4@4A#)L|9V&bfcO#z+;eiir<@FI=t-XIQl>Y384 ztf;CK#}P=SNZ^pvc3eTqL4tDOYymp^Fazp}Dw%$x<|WunN)X(9xhN9oUzhJp-Jl#? zZBS0U#|Y2;FrYRI&G&_96j{P|dUh>~CbH{$Jab%!wwez8k5`vyt>$99a?maCS$z=r zGVt@j?9_{PgmIR{26oXWfd5RXn;qz&m^c!|Rh&DgL2PoT+GGR%n=-36Km>iEud2$%h(GUx+RLnyMJML=0 zoeGvY(AC(nVhFWTt5e%?(*0l@Keyn7yk8b53r~jA(ZD$*@$MV9H|RU}E2PS4ogN`_ zz)w)>a(@NTj=QdhjnghR3;0{WzXtvu9nj5sBaS07tUSTl#JzAj78J;$pgYgN4cIXn zEgM911?f`35xJg6Q5bby;3R~|AHVaZ87j{dgf945F`pw%RriQZRTSae_m|gbb+eKh zRmauz%+<0vbzHLpCPRd-!TFkKK>zF760Ox;A-F@t2Z3J${sFLX+;u%noK~^%>9L!A z0r))dLx-9T3}Nz=%Cls^#aL9GRRpQBZeGac#5H&QCPWuPU^2RXfM3@SPLkF{a6{ny z7Rn{jEDYX*W$h9g3rdAJY}cjRi_5gUz9n3|vv2<1G;~q$By%|yQ!-F$oq7@(s!WTO zHr-fl2)8?AZJq!=3w#lHUv~bdE>5G^bl}H;ab8OE-;G(`~& zXq2&0W<4?-ZK-Ng!wIm~#J2N(N;&XPfs4mo+k?c(W5(bp0Urnc9q`k@>_le=5!!IJ zS8p%Uw_dqM30korR7M!Nhk#7Te9jclJ0f&kk2b3{THUNr6vf?dPf{eAGjS*oOoYbp zU}cT&F0GIshQjeWLhFPH7iTByx)|Q;nkL5WqqVNPZ8lx1w!Ln>CKTs^e+>LO@ZxdT zcHB65tk@gx0e%ViGNpx`=&3Qk6#Ut2`LtPU(bvEIDs9896qVgAA&I*^{&o1q#ACwc zOf&tM|Kr#5d|F=LqQ%v9@_mq3nTY95G&oNc`*J;x?mS$f#kEa}u^*++jd_nONCRT) z6%W@T72A00DG*rG^=YN%2;ogQIJqAKejE4%U>;jx$BdIKwi)1WP+H8Nqtx9d9-VH! z3PMC6)79_Yr8jThBO~kdiX>;`>h0wTS*Agzu2DyY?0D>I>~8nq7LMzlD8Y%nAjf*6 zNjL8=(Z+U7^1x33{}K2UFhBJIfN(X(qm70`Iuj{Q z=nwz&Ra)KH7NnCh0rm4MC7(k1oVn{gUo*Mu%{GX=B!tI~B2SNKBZJrGTo+f@>CVFy z^86s(*8q3wY|((wI^XpMyBZ7bAi*_Vt=qKKbV-w^N;d=eH1LabLIro^V&fy0Wo6K- z%fK%KUj*I?OzpOV`{5-@8-GF;#Aaxk5L9olxFS5e4_9Hrv-mWSoe9X~?Lto7 zQ0av-1U+MV=aD*~^q$8yTQ=Q<*w-sHF~7W@*zp}V5B|2-)%cp{)-`pY%kLL{7}Mf* zi{gWR_=rb}5_|?p{sOL_N5V(aw8u;Am?GJo!`}uz37AKj1C!MY6I!mdAc_d*l9Eg{ zP5Q>w>-74~d-VQyJx8M&GV_N?oX?pQMiJ(TcQq1TgU75_s^qvHJ$dCKl?(Y@#7iJZ zcAegclXzg!c0`41tlL?O*I~=*nDAD$PWP5p#hTne_C1fx)rw`we3758Q zI9v$Vlu@T?i%vqK$!DT4cyAnr{}VNO8T-4B7mI*B<;91_v51XHV&n=GxHh2}9|S|# z`pZY1hX#Ufw>?^`J0RLl*XIttxmBS*e(5T`_}=I7P9@I|hR!1diZS_|Ma{O|b%Gtk zV4|wjv>m$rV3}r%1<`C+Z#;}0F@T$j@9>X>7()DmETrRrJWhq1%9-F;DEzBnK0l0T z6Jqm&U_7B^zoxO*)p{F>HpW~7>x?W_T-ehZp-y)x$4l93x(+mt*484c8iiYxo8zZ@u!~oVDO%lM;wnJ_Zk}B_rjf2T` z(m2c zggXpx3c{gd@%^Bs!ziZ3?G}9~nkQLG-Fxc6MZhw?%lg9E6lbvqC7&embGT)E1gHV% zesl+T1^5Q=U7*5gXP8JFrPvIh0F;1tCQ#UM-sf-zODw?aogUb1!e()bc_qm@38L5r~a;oHl^qY+PD1vp6FK z+Y&or>z~i?Ebvj_Gr&6V9pI(x_dd`BT8DAHX^M?2zL0I?aRBx}FJkxai{t3B(`x8( z6v|Scqa0Oe5Ld$qXt`#KPTNmae#YJW8!um@oA;LJiOc69HhbTBlZ?DM2(Hz3#JzMp z#ywW>KG}^G8Ez8~<`Fxds_st}b~YL?hm?_iz3!la`81o?$q(a4Y!8nTlKAi2ZP7e( z#W|7`2rk~!I*bfu;BCMs0Y3EWz@KKg32bEW4wA*B#m3@dVLb)B6L>f9Jn%G-=NrYqm$54F|3^_}Eodp_NLN{^UEa(_jDdA0-6`6z@HtJ;8J{4V^+b zq3wA`NUDPcyP63X(lt#qg<+wfF=?oUu+RbH#J8xYHbRilGBsTvf^+Gqg@SO&qw%&* zfO$y5cWl8yO9)OLB)D$M8A`wpW(a{L;2Q8<;5ABJ?*Xv6Uj~O28w4bT^bSfz#R7Xa zdp5UcyV+(vyG47w07V9Nk96L4^gp@!@a+6<{dZ7 zn&An`T%}q z+(+@z%8i3L=(%li{#LO}GWM2?(Lj6j@>GVu0MvoIz#ZUq;3}mqcn=63RcxK=X}}Y} zdnt9TcV+h%feT#Ip%X|lMS)LltA<01#r+uZ|H>=V-?+}}{(tYj3>VWv9IuTVJ8k8} zjhDEo?Z#-)0&USCK~Mw;P@u00nt!*2(>NOl3SaWWl6TI-4b1E zv1M7J9m`rsnWQ*F&T{AO_x{d#?hG}eNNQ$yhcm+O5D#a&_dd^ap7S}M-XxrgA&L`R zF4YjxTC`OR%LTzUo4hcEPiQ>(&CT#{Qkc!)YuKK{mW6Uu6BZdH;8OZC$ZDFdu4t>) z>vT9(oqH3K0 z*BWfSM;qe@G_EuT!*`0tab)%@ajMic;NssHo-t%leT&8u$SgM2n8<9mxKkwXoGJkq zQg`VeXlQg<$B!|ySQmA+nq~PnjS6z1R>!fEXYu$$57NCdff~0p4+F-9TChx1T{oL+ z0C;0SxcDu@px4!nm3=EgryK|q#n%@k-)EURDwQgJw)J(KpP9o@!CnJgV76RG#SKv~ zsl4JoB|yqfJoH>~$kxd1kO?>N~Q{|@f_(pcNDad1JJ zriqa5@%*5x^z|aR31~F1mR)G=++0+$`%0I|^u4C(7=L{q4jw%&;9bk!GVOiA2{2Q3 zarc-dGSLsWiD2N^w!Vk7Qi45tI}}9|XPr|tS-O|T<21g{*?yq$1>1|w#c~v%ki7?|c%06s>B5mFDC6W4lFU zhA@i6{Qb0=v}83&*mtc^6&V^qwbFhq%fQ)-)A-dZZ=yntWN65~X_NE92p5YrJo1&X z%$7;ta1+7x7zHls>oAAu@*TS!CpG%D;KgVI~PY0xgchzJu1%)DT25 zd^-4cf-O+3IyiFb4F2f%9}(R?PTMaME>yMy16Qrpslbyp4bbZ_bWK?8W;@_5s;Wvu zzTsL`Rj6^q`0rQu;KNTpC-BUh&a2R#J$mT$LLF|9z|aQ6@{*(wa2^3ygf&8jqvo0> zxdSJx^)z|_8f`&TwO_B1s$BwYKoX0rh#Wr_UA3*6XIQ8>KR98b{KSw~_3OQi~)+d7V!t3?==(e{26s*8oX zhuNwp&SEgCqFEaf8O}w$Qli&D0GMawk8h((BykL{x`>os+tbI!1b5Sf@NpP6dX?H- z8(*gz8pih@!;9nZP{Aq$joJ}3e66C8S#*8Fn-9;;1~Lt!tv!pi%8J-$x-1V0J!AXs zgLr4+Bnkx^ooHUA{d4Xw&pR2!gHsx!PT6P?Ny04`$#8zIhRYqc>>yM4PMNwxzKhMv zY|Mun#KLf$^Z}KO;CLRMec@I7>Xlt$uWYJLg6CEgMc8p8?Zz{iWK_0NJM;1tDuLE& zL4GaR7JmKNB|Nu%Cjv^KO3&*g7_cZ#Fty;&YkGq<2O$J-VF0JRK)?mL)o}hKQ1Sw= z4!`cSZHuVJxVqrx*gTEj-d#=%xo z$*AqaAwj2mTFqkp04l8g%}x%V3$+gBVjKXJE~?Tp;zzf&fpFmHxxV zDGS^hLf08cqqP=MK(M(%M4!^GpTmM+;B-^R?jy(XkH6ST#W>p@a18)DGfnqlbZ9lc zPN7D^Ks90I#_-Y``*7@|N$6Jl7GEj&Sy7zeGQk$bDF(M%S_~JG;mRdMzAHX=6S=@9 z=#N5SwUqt_*=oG9kPh05GPA8KsCHEdq8s@3Y8e`6p!1)-e~R-@;ey4F<#u?RA|V2k(vyK_I@IQSlPdRAV|luIQD zV_ckfkRFw`=4HP zvFHT&@~A;TC%Hbqm%&DhqYOA3W6(@1tNArzU9fTTxp-8~fTEeu?ScR;rY;!Khy!0N zC|iU;Gk2SG20}KsLuQMUw5L75F4&l_)bP_S|ASiH#Sj1N8CYZ**AH9fO`#ENoRhSX z%e;VRt1&!Dn}FDsA=Ys0gL8O!*8xm?cox3z!=}c;4IwY1wFa+mq2{4j^Ks7@6)O@9 zMq6$#*k}pKWeGULS~E{-9+PGh2#rBeR55hZMv^1~JOLkDk2-jg#@9-JgTWJKqgOYG zXl*GSc5mnBg0K4le)+;UYL1J)`Qe|FIT*NLX+bLIiw-S{<6P!sxO9Sp=WYiNhTSG> zUAi)dZ3NlQ{Szovs#G{SEZY{>^a8ZzdH7L`sZt#e-E$k6E_ZqME@+|r$K8SJ+gX^0 zJ-P{+Wv{x4TwuF?0oQ`bXW9kv$&ly*5sk139$B!N^oIDF|9Y1r8V(gZn@v;Yp3cQ# zP|*go*DbHTMTYb6;~#xjSfuXxB40997@H#x*!Yau-VB;dxnBzsMNwer8XU6jn+Ff! zrJeh6{?asLRTVbtsrDPeYvqc$RI0%bV`@4QqCugpbsdc+-TcRrkYq(PNr{>z=S-&0 z66F-VHrq|3%1xug@`Es!*>p`Mi1ZafE^8SL116yy7jVXm|Y%QjIU(9(Wbh4wpN^H8L5*QnX^>BJtJ`;;1f zr8US5jGP&ZVNxhh43{ug<2zn!c0N+$84Z=NRNBbhhQhYocw&7F9(4;IsYwS;osF%> z&_x7aOz%^+o=8&GZMr8#f-hi8GRtk~mf1R*XdJuVeIMmo9e?{*-^b<$euGS;!gW1( zWSefc#(OcyYCOmCc~!QVX`o!K;hm$$u>GyW`1Hb*sF|VR!jkd(5ejYC4I)gH>ezhO zZQ^s1%UaTaOwgoXfKMf;c9CXw5GDfOiY|Uhq-?%;ZMKw1peg7N3m&a1d1oa z_rs2hjh`#ieln{`*MU>8Oi?%!ADqKWJNM!J)03!&AziBr2>S(DGkCoLoySzkK}ct# z(B~vh*H=$8B!WtALZqrUfW@y2m9W)n2F$q~_aC+!y3w^x%|*gG=V4d{BxF6`sfy7p zEFm4NAI8{t)LKkKghW*j4<7ple)HZt#Wj8y(SFcP z&BmGIy{S}S76EnX${b$aeGt28jv|>&*EInk`e?J($gB#?lwDNZ5Mu>xU7#tt4&5vW zxCCr8aD%DRYyZ=0t-jYWV6a^u%ZouIkiZil@^4)L7sN3<>g;_GTT4sH8i{3O_MVzA zVe8KQ*!SLt`1ZrUjX(Uo-^Ew&yITMhQFDk1y4ApFKFgpY6WyE!Lsxfw>?FXp5onVa zr^u)ptcK+VEqF=uH4nv_zb@E>(IncxJtSV!^jh9}VX97JpkZ4coG_8lF7N02>RyZ> zN(QFrnxOE$<`>I&ZST7{dg?5`_4Tje8G`P&zH*PSU=&5P?ik7P{nKYn(_oUt*jNnb z@iU)d`-a*sN=yeGbowux}i1>14Mxj)i4Lb+^um- z!M2{@1LVT4`VpBTh1~B2tq7eaz$un1*g;l0c6t(z{>}q<=81=~`K$L~*tQUn<@_Mb zdbF@RFg7|wpjo&uJ&SRI^>w=4lrVGOuw~vk>rTx76)?vJ|=Mc_bm=c|(FkBGN8g$S&nvL&^#X729h!IOejBeMR zA|$gJ1RZ3#OGWl37`CJ_Zk3QyaS&2RiIlR^L&Xc=g%J!@rrQS(xYke*eP z3`4qmYy_q*rx}2^MsVT9af~nKuHw}_2huB7X0-e7y-VLWanhZhn@=~2mpYHZUt!xZEvX44E=bT z3H|Ybcwwg6?vumg$z%Q5(-2s2!NzFj^ePI0=k#h%`w*7oumQE9tPvIkWr6p0G7tkk zUILnI8!ZMQ9EgP>KNuSBEz#1(-X1?%&??m0v+%&Vu%YAgbLbV8xI&5O4Q)6_jcJ&!^;n4qL{og@T&c z%%Mv%?zuky9z858-G5mm8FzYI0^Ye{>Ug^IVG@>n9 zOv_S2t>~=;&jdgYr7CY!DNUXOx|{<43Q1xrs6~K;cE`$%UvYTiA1FOM zZF+|Ri9UBk1MB~LV`vQwzue^zUa8#=XcZmOZ2AOF)8SFP)sDGMNkduU zVg=W0kxTxSue0jk-bxiG*}s*Go%xVWd61qFt?KN=J^bM9(X8=8%l4w66WfX?IC&Im z5cD3u1+`2kq9d>Vr&u$KFLOm$I&DD!54&OkUK+ol2dSK?=Kkg`@5}A!k&N~drgXyd zX+BTs3f=0B(&got$@LB*raCW{bmdX5ediy)a%oX11nL~gQ7nJgs4s}p`##5jDivFD zn24Xi`Nv_DTOQAD|Jj~+pzHKS)LL`(U>G~HY<0x@Lb5a0C)1_82U?+V_kwM;*4DY` zEG;8NRwt-;ZcSMo5*;ZA5MGMFv6;t*6VL94L4L%t>>}ui!!8kT87+=st5>c1_6Xa-tjp)WaEiuJ1*bhH}w}~gHW)ICGOV0 zC=SFtT*j+&^yPML($a5hyR_uT%av=-;`zMC0naSux8dnu`yiJAu)&>*h|nGAD&1I6tK&L721b6?T(Lg}Yv@F7~e1nF%(V5oau`wcZarsO~V9 zAZv(X*3KgFV~@t&ZlO+|!?xAV(wr(ib0mH?|bDQS{xS-784cwFM{6*lRm$@*}NB6wo5aspw;roDV zm|ze8$~pA!TDWR5U4u8t6nwF`aB`~opDr~kJFt%2B|TpfUxtR^B*Z5;nwR$8IDG;q zS~m9lns}#OasoA&?rd>n2NIn92$Pf-n-@tnJODh@l9R$QkoS%G_jfTHyZc(;*|7AF zz2Q`84e2U?5vJ;`AD%}icbV*ZlTHJA6X=m11Qba-crumhS6gUKO1qH*t*1Rpz#;ut znepDs61yd-DVFHBMYqWK7r|0}8PPFf_atpFbTk1zT*=njIwN_TMp|S>-Xyn#LDT{4 zkA~ZTucLnE&e3CJ(vW^9J@vbLO(6La1`pBv(p;aBhml7qS&t4Ukecy&x6%$-lcOq? ze_h1j@S$oYzLG9?tn*AY3J)Ows~~H#b0IWBN;uzL_&tGJYsp3d z#vVB$AH`3#mmWXJq652+iZvyB((R#IsjNFCV(5U(!1nw7|N^|i#rL|AnY(g&f5#X&_*Ja(zj;ZCe3g36Qv(TYa|fkDloy*s)hB1AYB+hxF9T6Z$;Puc9go zrvF)C)h&^iye!u2G3EN6DaKGhb@RK3#nBuVxTBUPsFb}Ish!>Ts`$t2K6hO9x~wQm z8oyoC0v(}I{@U{}>MPnhS|@m$MpP~7Pa+{m7wi{aMGWAE4>|7!_8fOQjYkFfq%6!N zKq>kzZt1~6mx#o{2Heto6U3}tI8z_k8j$L**?!XR^z=gyLim(-S%afhq;YY< z#^h@O$R?c8Us+zUOFO@SsP{WD(;S5fG^c#t1Ne8N`f2OD*V)~B>1^8{#ee+D)VEj6$y*jcdM2&0`)qfdq?BRi;ZcN`Z_Go-$t$&NR+qUXFh)a zz5lB$Z3(T>n!o_#aJ!&bgW>8*_RzFrkI84Ln2CivGPt=EqY!b%dMiKFTc5xxIN>!T ztcqiNI-({kar=PSfVBeq7c$+^Ft?`LxcX9iVHD<$3>};O3twKp(JEVjjCDdX5PGr7 z$6-FX*Bs~frKF@wsX1RoqH_4j1HMDV+Uj~ck~aHJ{9wp~M&k||aH);UMzpGKwP9iG zA6?)3KVryBzj3L4%ouE&!3WkL)rUCcz8n2x{zkHuow$m2dv`2v2zCs1<-oFBU5?Y~ z`cIKXS^h+rZ&_x>V&NxV{E(J^WR;AL4i0lmrtk3kKC0#fnOx55e-ZwMe|C0N-C;v!n zTc)qZ&FI1kVLTJACUZD%0`DKhizXjbm2etScK4m1y|hB3;73ByjzBTeEZGMAuf+Vr z(u1Hk1)TW6)Xs!*TC(9pAZKAA{4h4ruQLi@l=!ZIBv%egX($EY8^1nH(cT8X$W~jD3mLJRa%vw_CMz)7g^Y2|7zyQZSos z?0v&?baK`TerMuWYvIXAH{~!ukjqdZRyp(hl$8<@(k{h39sYaS^`deVDTA(lMW0Mv zHj)b%tCJmoAM)Z^xgD9+YoBS*6LEWLpVwRW*`7$9A~)Tjo#_gMcGsLbsEQ%BvS=km zd2iaj-GG|_odMC`kaR{+me`&*H@#@MzM(FK1-a(AiO0$ScwSmU`Ol??FM-qNLY?*K z?As?EL0exs1pzCuHI@u8nP)aXz8DKi>g*-#GI504Y7mG5KVcN$$2|CF&~DJ!*s$hY zugTxw#D6(Jjfi`U*WwH}8!-=M z0*Y~zsF>|!sa7T^R@w$QVh0c@n5t;5!iXO|>|9_60`nAk@%TuSY{Tt&i4smteC7C! zrl_L#I*$nypJqN=1F_qF=Goj4`W*_wx%JmPkvno}y5Ub1_seo{a#-nS!b&^fw(5@F zi+T%wM-Pct<4@jT*Pi%2uv7J?a%=_&nU{LJ;lP^gF@?S!d%%DBbN*`~%;buG_zn+m z&i6j>w=U7gtjQ-K9)$;e7b_i`9s12c3YpOGUn*q`DRiv%tt9#td;B^snl1t^HK!0M zrowB^&-y^8T6763)4J@*3K3(#6@IKAirt zgq4gihfeoZqY9tBfVhYAL~Vha2~SCiKDq2C3C0ip|EhA1d6wYj%UkU_4K(VGzIe6G zZ?|!Q_7xS@J96qpq7w2EeVHQ7FM$fzZr%$UlLtl&tMy;GFJO#l7M;A5PN=8>!SY~aoM z5gPRdus=4jM9B!75IqRZK5T<|pmNZu`N73bm9bC!B=B{cbqmA0B*xwT5${hIZ=%_e z3K9g-2}1HAU1Tz=CtIye-ZT4(+1e_&vwR+x{mu&+1pHD<)xsJT+lu0SPDxfcg?*?v zS5Y{ld83_{Lu0G;GptCg$5}5D7#=<3iYa$-QrEpu)9ftjC|?Su4(xng75T>`B-jv# zsntt(?E8eBRhFu_^yxa{^nAG#0V>?@K7z2J_N@5OD;?G)cuS$4L*pwGjG zHe1F-yTj>9KXoObj4M%2$%Ml;wnV*JlWMJ*<0A}#D9#Rt$_^q5EiNhJWw(tEkWth2 z;)fwIkh6H@_iwz}Qu7su+E{+0Np(H~8b;q*)UFFabmtS|f{9X} z1mXcm#FQ+%_Y&a8p82;6etPE)|2^@l-nvM$*7pkxTuUGga}1FA%blS-70fSabvPE- z;PU(7H5K3Y%2NJGvcQ!A{+mp@6rjGp_%MSeHW3h$k3_+VQ@{so*xA`U>-kgH2*{xm zx7X@`X|m_3S*!`JmQVpKI`UL+ogj-#j{#dOBg{4Dyv6GfE|0rqiS9Q5Mww|9l3kK% zXuZ+>m$QTUO!$ZZ75;fQ~iv@p6Pcl?VwCe%>o- zoz;jU>!?rbXyOPjQ47n^ih9NiCDX&Zo(Q@%FX9OFH=yq1Kd#}$$0$&4!&r&sgLxJO zGL%8;IyKB7m31;b3D^EOwMS>-9bHGb-7?d9s_D>9d4|Je($U#L1HM#LGJc=d zLUKAByz&VkT2)b1NsS%u;^<)bOMCAah5Sc0D#C+#Ic(Ox`<}I~VW1z$Q>ydaY_4*2 zG-4xly5VQTaJw&^Ich-?>U}qpHRYGw(UUS#ri?gX70b`w{5ftF0Bw;tIjTbIe0W&L zwj!xLOi{)vS1`2nV|~N{?+5z$v4;@OwHFRbW`4%UPtmLYkaTzB^HMLaFoGQz3H)7* zU-FaQ-y|Sq#=k1z5oh~f?wicAGF7@Hq1f~)G^-`CwH9^@^5=H5TmkIzUr-0M3mcq@Ga9( z!@2}DN~Z&rXx21jTV``Q$9sgKC6Bns$@PHm9QW*wFp{Q#sBWg{2z%uDPBH@W}^$)WAk6d|5(# z`HHktmfHPS7Wn3r^iPm{ZXE&t>Q)KxRh=mxZ*Zj(PYGK)80DXsPX z_6rV2v?0GUjy%d)p}O{6m&V-h74ET#^M@~vLiecc^N1s6QzctpwL+AL zK>lkk;1;cP=8P&XPB;V>4Wi5P1^wSpRbO+4MG!!Ng+nM&ksdnR_#-!Oay-Urd(A00 zVcgsO*_NheY1T0${6+&?mD-al)5SRYnWQQUW%YuLFbqS9EutzPF&*rh}*qc?Ugg=v7aRjTbUd1wr6RXXnTcw>{MsnT?5+7H< zG(r(f-mx(97SWh1VWURWh)>$yc=LY8yzpYm?>>46Fg4r5*3#Dg6)4ZtU_|O=NA8hl zEVy14>(t2z3`Ljo`}kyJdcZGd)Bg;g|23J$y0HDE2p&D*g9@;JNP53Y`UtuIj7Z+< z?p}HP*?#&#O&+v42m{80<>MsSp;&yyp+LE_^pe{hFHHCF!58C?uD#eKq$PdY<|Am? ziQ8x?tkYZ~wwE|JTlQc3b%;3uWUtBe@!joqqftyL?&f9=gNBy*rB8=X4iSKfe2?-n z<}qXQaP3dj8F1Wg_=DdoW>W?meooPv;XC`_ouW2N1|!Be&r^nWcwIm7 ztm@{MYuktOr%g#y)bfFD_&&Skwsy7lvHYWsS%RSDOKIugN0&pp_v2i#LOj-U5n;Ad zyFr&{Wog}?6SN;6qD6j~^*t|rG72OF%lu8|l8;7Lp5XoEMdVzb?JI6$deWy_K9fr4 zpgVnE;w8YMo+kRA`_pgXNGj&Q5E`;2NoxVdNh`N>#mW>$MVp(?`~)j(1h&$b5DVcq z9cfqCu?a@@1#_TY`2in65*RimDSKrX?wZvfA-ijGOd!s#tqUz1pX}9oJTF@oR#uHR zgYpd7FoS72o;62}PRyX-SGsHGWcG`PcNY={9!@j=DpXQ(!~-;Vp|y&pV*AvS?&0Zz zk1<_4J98*(jle#M5yEgzZG{P?hS&-%y6=@nWa{Mr-3IXpO~P59E76c?c;y;+xxL{o zjVlrZbBOkOVo1i0Zxds2h-wEj-nxZ)d6r@zTDYTd&DRVUH<4`Yo>~eMqzi{K=t5#(lvU|0dSfkk*ZRF`!3l~h zVBmZI6lNkp8hH#EiM*!vI#u&zSuT1xm;R&`S2{D!XXF%788M+{wE*IFLQj%IOK4~# zxHyGg$2Yi|P)82+U4^p#mMufS_J@PKq6nm)0?HQ885L_#gDb0L5FH)qIQN$8KIfj{c`Iy&WiCNFRScS@#Z zC^oZ2sgWJ%wx`N5nc>G_#qBtCxmsVWG;!llr!eQNuHkBwRW-VdDp-VYU?RQ|H63-c z#cDyzN4H+Bs3fBzkEC1evQVRA4-vp{f{dZCdUQVdJHF;(g{i@%5yD${Smui&Ntz0# z6IU=?g88~j z{(_1tgj+z^ZZg0=w%yKUwhNs#Nb5K-=!C}zxu7DK5>0pwN)eO0zuyI;vpAGujv;i8 z!f>RFLN1>u^xesggw6}RUf8A4oD@T(idCOIg$J@$`uQa2cb#^as=7^z?)G%QP+ey72^Z!^Old;Rq;4pzx1|R(kS53(ytu z{AfYMAp%8s+vajLBgL73Ob|0ok527I1zQj9>J@*?iGuuj5|o&k3(3<~@<7-tF=Q#_ z!0THROhx;&r8WtYcW!t@7@G^vg*dF3|GUsFRZI7e=#lYa=V@9mPf}peuCfIlwHqhr z7OJ>n`ETe33r5!}oX!0>+R435Pe8iU;39>EKBfg(0zlG+V_D^AK|L`w(x%eP&-%xL zHMbVS`oVkyP~EC)Mhy=QpcaP3lf{#h-Sg*st63+(bpWXD4BjD!Oky+PRRr=O@h;NR zw*a%D-BgdEpCYqgf!3KqyAldQ!Jo}9Z4`Nv@x5s?O)&fG-_Z2(BfSf-3^x2@&+*!i+nODm3p+aMq#faE-B&wSu=Q!5cFdR^xm;4n~e^ zz!_$-52SkST3|+KM=?;kcBQWO?zmc$)FO7>0fiJr1fjO$Tkvi=taeUA8k`>LLMX~n z`o#At)GF7fUO9EX+S`^G==|9l_BlS zc$2#z>G9o*cH>f%Q(Gv+#*-Po@uJ&;trss+ArVSx@R=tuiovyOV0A*(`PkUn{OdN+ zLtgK9lh>UGI~OMtM1 z2kvO5P5YG_2YivCzYzx#Y|>3IF$shj`2r*+Rs0} ztcXeo%eTZDR8g5#ClVKa8~u>8tNYVpzAckCN|j=bgq|)Tm@e64(WMO6sVSIN>|YK2 zok;`!;Z&W-jHnwR6$a_o1B;GXnq!QP>vGO98SMp+QP40NMZqP!_iV7WZ7ZHC4_5=Q z>9>}kj4)L9eG0PV2u9dw&CF+x2`q2CELbf>Qk1x?{2NQi$9b#ue#Mn=b%eY0IC7!o zyWeFd|KcAyzlVchq{Io$@36MINf=EhkqI@t&JVm{znshp=i38ve*d)6lO3*xpsrUV z7A?22jMEt}L1nNRg5_c}918zdBHz!wUA(P3&D1QS z%d%dxVxNK{caw}N3Edlvo!x256`^y#=W!XglLNpK!UNoG>miGBu%@{(2(QFTl`H2c zKCw)zrXOBfrNpkFPOD}rXyN+qWSIVrtK2ME+7eP*l*N9jNR1p$t~42pamNZDG8 znQ_8hX0d`7KnW3XJx##Qp^uyt61{@9*`DpBhDb`6Z9Cg&IC1f^vn)vMWYb0w@p7acr z7}C!SQqH<%_) zZ)2J$kia?pxmxF`JdOHO^P^00^jFGvU7T#?LEA$j0Z@%3olJ&gL85YooqdUTgmx^Q zl7Jw$KD0WXeue5$x>Ra$N_amsyQ`oWe8xuRftm%5La(Kl4fsOLC7!JFg&@HE-CXeQ zFQM;ITgTCKD}ME+y%t9Bi2?VA;ja_XFyRpYCt0EH6*D1{0|m$%7$JF_5!zXW!%PSl zHN8e$x@wz6awi(dBsHS?2U;9eixj=>7ijc>v=g_(Wj=Dps;HAaa;p8T7{wK_2#|Jw zVG980owSfhB{-u3tXDvcgQ>G+5mG8@ICkAeMN|dMqa-S7c#H?jR>bhu+g41gEm9h% z!Kf@rLq!Pr=LF0caKE~1GooOb^yJ5|oTN7H*2AX9$Mw`R z8L`AzS2+;XD=O@LM}NcdxxXeUde}}po~w2q&XRa1?w&B;yXrbUNKV?OAk)^lvjm>G zMDr#ca64i*-9=5#qQX4mKR6Aj1z72J>ZtH*x3x=7ErRO}K+N#97#&#RNEr&$0gRH1 z!tofG-C!stQF)4yIWVV+q7dHxZ(dwC5Q8{38fPY8$*Njh&W35%tKl`#G1cxkIAxR+ zgb(?T2lYQP0;j<5gRHjwV-2T~nOy`&HIdK@TOcFP6V*lxAnlHY7rBr$ed6@*i{Z0^ zpd*|;sDqi)JppQ%%&r$YvHDyMCTcs+H75mX+HV{Q9UN>K+ihevINh z6`=G5s`$5}T|-cf|0I+;;h=UIBR~gUy|q(J*tjCzF$IlYsodeWW0)1 z6JK$z?I4D0M`pTaBOwf6{q@bS1Y>=m`WMh!Q;nS$Q%jzrbbt0`s?>f>_c5==V}TsZ z5-t7`d~i);-5fGWY;g^zRdCIk6UyQ8;^TGzKl13CLJLtsoJ~S)dkx}u#i5WEQ1!|L z7O6yLi#{NuvU-AQ|2KO1js@X39fG*a{y(wvFmsD0_$;-a&Goj0%?`6=cT!avn0PY> z%l&{3^>CIEL_8s586D`;W(oSF+23bTbhdWo3Kt_sn*%Mx_DHD;yB!p`jXp++t=|RW+GOBr(dS1Fo?9S_11eIha7gbkNETH|`2Z zbJTZ#*l<(*wVLzY z9%&ew#V_s2{h+(~DDw9Oj6&fF)e1Uw+F;t*3E7rpp6J4%>!zWA;6*6y1X(HmFK83$ zI+h)~TLdf^>a=ePs9#YT9!3M)E<^*}l+(_$st4;?TA(zE60HaYH~f~)+{fqje|+D& z4@TDY97uOW!oPtbpCN3>_gjCkB~ey6b-4WPlLUo+2a+{p{1m@vkqnu9v~tL4fEaM% zrNGlcFk4~XC2#RYEGTSK@UyWC5bwCxfb4-=!Dh_ln;Z`O2>b)C&_!?Gw|sZ6D!+dH zdOd7TfM{@{H(U>d2_6OU>}WEBDh0Q(J}V++WWaR+j!#73q20(Q5M2(WWL)uydVjAGV#6l-;DIW12X{_w&feSX0}a%Fr&(e zJ8A9PP7J*zK=`4>Rp}HuavSW(It-tT^Dtt;YmAgFnZTwDj1DwnXA5BXiZ;{T9~-f^ z><`~-$b^u)ik66j5j37N8~q4vkwxXOhmW1Y;3B{Q)u?g}w_$kevg3D_x+5>&`*29^ zmB`456WFbJ+p`8QWb8r~&iXh9BueIV+w0?x2aS@r^ksr9ZBDRtm9ne*1@$#CZwLe-J!&5wNw34VFuu9n&Ib zZigf0HEeNwDKKJtuz6Syco<;AL+LVUOqxDLl(T3eD6?-3g6d2L$S;~` z(3AO0m+nYC5`StqP62hr8meA5xjiUz%wS{Xh1SU^TvMWhu&L5G<#2+1VVu^^QjiD) zG<3g=P6fICAj^#Tp@0dT2--Ohop4LxaMoA;>LDx48%twkk`CW2nv&|D@l!@ZH$HM0SvDu|`dwnus(cA=**V4v8EUQ2Qsoymwz_5TiY>>Uzqh3mMvP#PagA=AGom&(GK3jRCgxz`jp<4h6rv!27i;6DbROnR8+m5t_nsO0{XG|) zL^U8~*_|uMCpJ(nF?SNiKlgE-FCwIGGj87o_An-?V^6JRlp4iV*I6X>sB4Bv)5bxf z;)*cCqI4@`G5j@4iuzaE6z@BfEta~5I>l?SYTpyv+bIuxeVC}VeQ|P={1dxN8(5~q z&uOH3?BsxXq!LC_YLHNXI?RrGg;npT;Occokd0ZC9FYk*cL7F^Q_ljfxW^0IVlFFA ze|vDN4^&l2i9J*4JJk`~Fzb*&-&>sr> z=*)-=K$QdyUY=t>6TF@_a`4rB!RQRz{ePV+#20xXgV0dmuWUpyN#O(nFFWGDsDHcj zlSGeW_28J|>fo9Em;NfO&o&n$lvpA!KQhaU5?QusJKwk|B$x1oSmtMG$N`cUp12F$ zr}t`HwR}{DBLu!uQ3Np26w7n9eA<828_{ZBAZXTmcKO*G>HOSGL?H>QwL|tXq4?{G z0_!|&2_8?`B0GTbn39tJO~SNBQlsNrTKGWxgC<-G(JS`rPu(IoLDc8SdjmPDUvk!agTF1@cl|^4*)>{=-B{m+dhTe(ZtHg2X3c z&uq5!xPxCsRf_Iq!p^ktr@k}Z^}O@k)C4OcFXzGCeWHDLn=iW$BMaC+W%xR0q@N7e zxM*PD<~)S5a$5|?`00Y!bXC{sKd6Fz<=qQf3ssMKwZOZunhONocnc#qG>p7tg3<^GAWPb}r6aoj4TlFa=mU;NP0pe*M-eFK93klT?95Q?EJ6Damp zFA{SP=#`sn;W`Zg6+wb33+;OM)Q1@wwtS(C?XR#k5T>2~2tTftnKU(UcMkIe|COB7 zfM}fte%orcE*AF-0Z-2F{rQbx^FaK!_~FDb<2FNn6E9*cveZLr!9Ku?oPPGz6@#Xo zSJ)>N$jzRAlkxJud%yA}bW!s=wjlC)0R+ug5;!+ynA* zUn^|8HA@`EFdN1~FC*L>HJg1nigUqGzZ20aHL5qxkgDLMHDN>3z2P=h%t;V3-Y17s zvtW{nB@eqR9JV=f5gsac42g!ce+gYuCtvo&drUFVtgDW`F7I?jBO)LupH}t$gLs+1 ze6aQJKPgdm1=m3>XMXd*iKF|wT<+PU)Y#`?(7BniqJSJ=r(&*XcF@EM6EH<-q+x(T z9ORr88Q*1AR>e=E?pI6sIc-6{hJ%c{i1ps(C6tUzm$B>+z#xiBxACZ#vufc-O%6qE zoZs38+7U+8El@ucmZdw!Jox`%`3pi_Y~{LfkvtY7;L!U#SvST(F1}4W>HAGsevhV2A?~iyW!v*V&zE6>$26 z0>D4P>AL;d3!R<>M{feJvJx+$FYFMX_M9&3G z-?crp0!4$HB~!uz2%jt=8TFn`q|16Drw*qWlYtk5&)d{rtY!EOsX*}Y%pGt;v{OTKRR}?CMIa3Zh&$827I$|~Me!wvw(7N$6w5VTd?w+X?x6^V zs;GIc)Ix8PH7>iaExnXgF9da0bk~010oiw)uHLUw9l&E=`k|SzGW-WWzP||M=?P4B zMLDgusWp>P)d|`vqIL~`NM4=tHY}qc@3cr%I^6bm@Y)wo?mN5sf^PqGt#a{T3$S(> zzcX`la!T063yEkI*?VOBZlEhPgVVN~_03k4b6i(Y^W?~&3xCC!?}iS7Foe}Q?-<I6|%&=?eu?^K)@ZNMY*ocg?W#A7{cjQ57B zbMb5$ka!QLI&=cNcAyxNc1a^(@^+>bk2b;0PmD$>Q%7j@q8{#5|wB>#xj1|CShft zp8s@&(WhG+ruuM@6yU4VS?_x311c;@nHq?mb#{K9n~5*V#;xWz=$Q_mo!*9n?43qJ zG4>>}&lI$2tZsM8ZfL%t_r0oJ%uO}+$$i`o$Nj0(oscfxc44@z;^tJr5V>D-Un`cn zorqFRhImvj8Wj(cBW{AztiN$#yuzT@R8fskQM@Ob4#xnLn`~}i3_p<}cq}tytogOB+HHrT z!Nmc?UevqzK(fOulP$qieSB<8JUqAyWGZc z&2Xff_&kbE{K<=Gj>Q0n99v?BVvMBBrrPqRL?HQ-7mk3wS0%zSn**tpvm0` zdkvNlo90tQYoT8~L=7%#FCM37ryS&a14X7(&`XNf=bugGc%kTk&s)*o-|@m_0?XgG*Sc_hHS*v4x+d=nAZf z9F?wkDf&cm%(v+GIs7f63aKcko;c)vyKes-)Wyt3@o>Sh5KGB$vQ9glHK%ST*)u92nw$%a1zQl(>I*4rb-x}OujcYdN1ei( zsXWH(IuHKJjQcCh7>o_9s!`?L*1=b~7DRI|bvOeJgR@nnN8`;Z_Vz8_o(`pvS zYSQ8smfHv@)TjsIUj?rnS7pGdpRB7ua=}bo5r4e=O7>vMfhdk8>EF*g&yug7g=~h8 z6|tjg(?Vd-!`gOraA{qEy*5xcJ1^9Z?mETVf->#a>aCvH1_?~o*SIbDEMxOWGnP?D z7@{|@A~)+vw#9T>w1&{?lwC02E0}4YhtraRje_g-L*+j_V`en5AGU6|hN zA0Vno4FiPNHc~!U5tBx4Xu1b;s2qjP+OIZE^qjy$Eh_ywts#I~;Hku~g;L#3|0t`) zq9aTCpUY&kBN&JC2%^eKBJR$xocBoYkypY*MOifJ2qS$4J&nSZ36k*%{SH$l$BI(^ zjTT8Zm6O8?2+Q=d4{1l|vbV`LDW=kaa6Se1fEJo|6k@f@AgZAFSC(sRuqF5v?bc_H zvZh-admnm#O2)3m==Qt42Vs+V(rcfwTDAo&Fq z&Fwh}h9QstZvRvk7FD~(%$W2l!-)SqyQ_}seVAE0!Vbo4En*}2b>>mMqm8Esl8NQ{xpAu&!%B+aS#4__1!)i{a8 zp$yus{I7-zVIoI-dq^AQXanZhCGvb!2=F`Hqi+EI;9}L9L9whyqB5~1RHocT4y-tc z!<|Bj(x;yJHtPe<`NV?pe}t5tOJQzM>B^JEtLra+j<_RWUi7|W zaFmdygMU6?j|x{mnke!*@%Ktk-9;`}-l6B?2u%Gcg$@&#QBI#|t}iZ?QQG2M&H*o_ zn3f~{ct{yKX9PW%Vf%$aj19!!S+DgWE)Z&*t_=~FRljBe&txMy6~bW3r+#iB{Vx@h zGP4}q1vRPBdPZ1Hp#)Vbp&P1NxRkMEKdZpKj+90g!y~P`E7lz5?U`LXOB;-o#2Fofj_4)$r9S0-#B4rE4kMxb3LUqJXy55 zUlL29liQ%tqlQ-%%UIHg>d{Gl8G2M;dMU=X{Agcx?l%WEqFw1A3s9N`*=j5$fe@p6 z&qa*vIe^fPk+HIr5cr%{F^L10jj??C{Fa_QK}@hL&#WTQQraR9t~qG;zbe`j}X|rh`m#@ zY1<}~@!bi)51$}2p4e_Y$It6(D-h`jXuf%V(nTow=M(4B&gmQ(M;f;@YYD#;oDe3V zh0}RvwioFAs7Z;k%(N8lna5gIRTPBr#CO743iGaT#GGUHy&QRa|27czA*wa z624qdhKTo)e#t9#rr_L}lK@CkN>JP@LTuhyMa)|`Ym9ft5!UB);6E@nj=&~1_$9@Q zYC1vmAM&|GQ(@34rSIvxU)82VTo~DV;)u2mA-Y9)fERF09|HdaZBse|f#y`cUKN9i z>`XfLJC;sJN~N9}(NkwRmNsH}r?HA>9~~%nh$ET8aYNzrh`ut88sc-$ z7Yw%5S;j(Z;xmdyjd-8}0xo;IjDG|gz(7lJv0(O+G3NaDVSSk&dlANYP-l_U7iHch0y#aXV^M=8d!I1z#99V(W|;iV#Q$l|aQQLJpE5 z;c&_!WsIF71_y*~Y|A>V-PNwN_s-cfec#`m=ly?Q&-Tpr%=Fx|vfkCJ?&{vLo$Z7ek4Bn!o#V~E;I^>{vm1}i4t0VsAJymOU&oE6X z8V*x`Pl{CRt?9(PsYEpV#Ya!y`Rfzu%q27ht5mJ;^v!N+$UD7(^#+RML14zmo_xIa zi643wRU5{fcY5R4i9L=-6e(Iy5c{p&q*Gt@v&L+Ag7w{*3;2rccPkkSL5#2d~FYiS8hEzo%1Fls@ zXLMbc3grq_{4U9`NzEej9JXWQQ-%wMwr&5sF7J`|0XJR{v>$%rd*~zYeT+Wzu182!*{K%9`d;KdNrq#{iYRck-hi{YwBTrgFk6GW zKNmKnXwZH>=d@G&`RoxG@|lEP&r=u&{aeHJsTCpmrQje2<1hTP{|V*^LXVw3Nk{kZq2mX}=-SL2 z<%;EnI^K?SQPAlEK1RFHxV`=c!sP}hY$-wjOg+-GSEx=_Y4Vqa{iB1Fj73)x z3l~jPf$JEJpv!AIT*DP}u-kRP5o6JC&^-NW3nAcpv0N2yDFE4w%awhXyf%}jbC<8t zjoEnsVAAMNKOGz!5#4{Yh0p6nLLrE`t(P>pK1+5%zrzDk{le_ z={+nPe8KmhI82Y+dxC!PV?QXwxk~Iuz8x9kKe&r>(KSt_?qot_G9L9%a8Ed%>q(+3 zBP9H@T?SjCXgEyG-`5-bK8tW_E=xB6n+g+b=gh%UZqWJAX^o?5;j0UhH25;9=Mx+>r+2U?|tNfPA{_``6M#g{6R+- zjYT39LXmh5E<6O`vG6S0z6qP;i_}IZjzEl>x*&#ig$9A=N@cn>m4@g58eDFqznAs~ zpl!CJEf;(O9gfcH*Xo9FI30JvF7Iv78TcHgWz$@)fKN;O-3;8Thx^4fo7~3~DQE!E zNQnBnQvgJ1u0N0bedMd1tjRzR_xI3~kG+ZdG0#wMH(i{VK_js`X~sJmyAC!M<~>Ib z(9eA6z4YOCKMH~N2#4!14CJvO#mzSnZ3>H_l4XUvu7qwcHGgY%PIe%MJr-HNyQ%23 z>?D^Vf;u`d3yaUej>cVhyFhCVZZ;nNRcZ}xGQ!=|4Kx(Lae0&}6sc0L3(%y+&n45e zBtWPvbTo`l#-ai?DQE*S8TqxA5p<1{|pk0#bnFJ8E^?f1Ht*mbSI zfe`l%573Xi=P?=`SQBU*v&df|zj!(R!Mj;h3hM2l&{<7WuR;Qi#ZPe|__126Q>9v8 z7i=;dgoQ9MJC8YPuu+1zk`RRNX#8xefvqPqcRiO(%N7o^#^4vYz5N#QQ^+&Orn)U;8uR}d3iM&aw0;MJOKm$g`9iX= z2YC%*{3(zASwgQG_s-2G7p|VF9lH&LnYfg%ZRs0GE8|TK4V&I9{W_ zyNjZ5?P9s=k6l+ok*Qp(31Ip4Tjt=uJ86?aEaeI%h+n5jNb9(<@mehIOrcC3_P$(` z0NfhRt~LMmf-~!y?(fNUC-Kv7BEPu+wL6j>sibX;c3y0gfQfsj2*p08x%uxfNGHA=XAI5qRH-kBw z$w9a!@q0*9sjnwRw(WF$Kz2nI|BdN6tPdlBv+|q_QZf;zv7vsPAuOQg;PXb{wB4x$ zr89ZT7K$|7*9(Xw@oeQYN@O_>&Ep;6`pda7dJCX0;l8=)4Ix!NucXR=LT%RNpCkVg zX>L}r-Jr2it9S0Ac)i2MF%zWd`jvWvG{4}`3smj27dDIEc5KQQD-`B#EZ=m9c4Ijv zX6FEMnbc)O$YSNF*6Nhb=4n1(B-6A=1~4x6aeXFDQNSGug;s^T3Ap39;=Mwp0>I@! zXbM?4S|(SZUO<(IMF3j>IPc`ehjAwEZ}V_6nuizUEP`qtXc-_I~Ytrx5W=jXH!P!{sEpC!? zJ$FW0y-N!>V>jwbxB*bUXjro*gvi2{q~%4(?|AsfB9F%+VqXjz?~yw_fBHJ~glia> zZvsvk*|$eP#EvNit1=kXdV{V_r^Vde$poozBNgMilW_`%xTF##)QE6M-n(i0_pp*H zNtl-#0q=!j_F6pE!EgTEbzFu5a;gby7{ELB?sc5)iq{=%4RrCQz_?T2>~!9(9i3#y z@f>gUb|?wKIS_rTd3k}DB)P?&XfdSxJPE*fa5NmIqx;6l0-)@O0ycIxJY-Egh|&l;bd-$i|Cq4Js8UlEx>I< zP4gFiZ>c}?*?H|X&}L$d%A&bDbHvwm>^j(*65+Z^YiOlSaThC9Au4`XSyW)D-FSmF zkFUx~^YS)Wgf<{y;kIs;#p|^QyEXWoH~>h-Vgd#Z6|`z_B5}50OYAm0Ll|J?0Gt>2 z3PZ(?+8npwesG?UuC?42(Z#D1G&7f>(`5ke{_(5#zcNaRCO8YXV41;ADVV%(+5|YDR;ikqAWZ3aD0U zEF9cW3dIuLm`)2g)AKpH_rwu8Fg}WPRWu&kcUZVD?}gztO!JnxyZyboXtJp7G8 z^E}^yTW#IqhJt5G=dii$?2GqMt2b!Dsy8_rvO(W->KGjvAEE#Dg|E={nK=ONZpm8f zi5-WHiFMa%n=-B=}qVfA~u{A|$iD@KPKe^gKRt|UOTf`{h)_t05=XWpYKDozG%UNx;J{ z$xd|U!es&8{dXRvqX+j=NMm=kDTe(d;cmrBWf5$CgKz_9yLl>hSU&d}`(74Vrezw$ zRt0Z;2n~C^e?Ggtx>twKoj0_J*^l!1{-%)3!>mo`>ChiL-!s# zD1^cS+{Tze8l4Q}GO@F{0Edg_t%@eW)nafimE6D)S!gOC<2kNQ%+L$3yhb;s(*i~v zF!1w+VbIjoncoNLsng><&5hKoWp3&*2woUse{|9k)B6C?+6Si8eQY zCl!wix8R|gstS16iC%v7GM&G4ooYryIF6*;T${x|lg`pme;@Vrq=dV*3l;OF;b^n- zIRV$w;2C)je73W%U8Nbg+`Y$-(DB3jC>f7Z!!#+K$&2$e&+hTRB`(ahvK?1|w}x;Q zI?fJ7vq|y2KX~^YXzVt9^`-Ol%H;_v!RdAaxNV1xp$h9dee8XY)BE4{peUvbLGYz) zcR*T(hs8U?ToR&V@%rLkUQ42xL_!or%92c4NTF)2POn|PLEpJ>ndY+v%pr?=xYe;_ z;ck;~qwW;Dn=J09HTX9huEb*)Ms~~PLc!QbNT))nOn>{$7lq5+ck&Jz8t4^{n8WW% zi}3h-UJI}e&dlqtL7IG>MWnsO`X`%OOmXPMoPY8akJ1{3dKTfcG2b;xof5pF##JF`r@@o zdila7nt;&x?~tx7+gbT%3HLFT&QMQRibjX}+ji{POpYdJGh%&qOnH?%3;}H0cEn!N zc=zsOhw0GxC?%p1sx^!NEf27H!5RF`Sa`>6IbR3CgWc__V8@%nxwwry_3lS#Vs@VX z_)E`>7_U)HxVk%9C_U)lCnu73o%S z9b249UZy!L1KW8d4{}9oU;%UCxJc3}Mecq)_BT&mO>RKt9lrof4!6h^aRcRaXvgi7TafXmS2bQ(@K zPx)e5yrU|L?~?dm>$?1n_rhnnK0QnGg(96gaRe@!1mrf}br?H=nxF>t^BYUYuyJuS zJ5^BsyeMq7LD@ou{_7W>r81gJu~HX@S7k+<(e+%6lecwmTM8S4#$A5za6hGD5z!?p zwH)hFy$SpBAV_<`>2`OByMb$GixtWg%Je_K z{4JWC%aLjO4#uwDJU4ECNA|d7u<@ZDzV{B=3lTm2y^o6eDd@JlEg*cycKm{@77PY= zdIm+3TL22^<1<%lbvk=viYn-)8iUsIKEKCnv1{mfHVA?5+cQl2;bMdR-FRQ2A|N_@ z<|56_W~m#_cHqz$C6Y1Hu$~k+VR|M@7hk(ZC5S2<2~!{5-7`K!eSO_D)Za_T5AUa3 zp+wVjS(*ZPGxJ$=_nKJ06}V;-r~^25GY$>SLY912<70U%b(Z$QN;bB$h8h}B8Sa1n z>NGv~$`$(7xhtZ%G@X36#FoLvhdc}sJ^h|X(ZP3ZcVvxKu|KynQAt94{7*<9ujp_c zb~B41f=KHPgK9_(j^0{m$8p7_^mL_Y&tN|w8xn37k44GFv+R7HCMISnJC`TJFa=a~ z2&i1D(tZHfKiEU)3N&$Tnr>X5A6>1AY&pGbZRvae7Rhu^XD$n z>~spiIv7_Hmc#3C2*Kf>jeDM&oTW@ANBsb8WNeVSx|0+FkTLA>P4^t93cK#bD-_m4 z3wvX*8fXrNX;Lg25shOL>a^vhW}yD|`SWxh&F7_8Z;*keqbkZ)FT0`GGT1m+jDP+& z|3EKYxI$07`5t=TV{h6>$J~nG?aboSS+Am4wEb|BY`%no+aycE^O{cuAS~!N-E)E- zxcit81Ut#Kt5Y;HJr8&aWHc=Cj)G?b0(MXTb%4A)AU>h5bD8vk`OApX-_JF{mEk94Fun1 zeX|SIY}VYw&tILUFMjnqltzOplxyOSb~|VsTM8SC%!B~XUAaM5r_J#7isCyH@Bjkwx41{&y_%Bacf{X##TC#s@7ssYbsZ|yOez;@G&4CzBYOsD6yWvt zr0DU7?xVl>%Gam_$7Hu*YgFrL%|ErqLX*%Y@Toe z0Yu9LtoPooB+bF4D%F}eG&>rzar(|X=+yBeG&Px~>u|H|e1Xh{DM0Z6D#M|vDk+*@ z3WnE{0)T>k#M^TNt5X06CqtsBH@~y+#BXpW7jrN?HN&97T#<^ok^p>c?=bD#KS~eZ zcNcy6tIv^TJ3_1u?!OB0`tb4I-9=~IiQx6wWwXT!WeR2b+}}J$*JrY1<6ikD_}sT! zY&mSr;LEd7+|T^k7bz8w(kDLf9wD;*BmK00v|j)xE^-IBV`;lsdo_Xa-kP1ZHQ1%u z-THgFD3dP;N8_`cI&p-K?Hi}(zj2mkr{>870E(=Tf+nLwrm7!y30< z0RQIyE(xflzyba5Qrmqe;~tr|E!?yL=*sgYdU>uuQ`cu{|DiFu^T+{u;rvChcV4;P zFob{^{tX5I_q`?By0eVhO^O$u>Zl{F1m6<6T&@ua4$V{>Lk7P$`!hC zZ5nW?lmJ{IMWraf425)G+=4PsfEG-%L{8qV@@kI9r*OPBfbu*HaR_b|2ha&4LJc@% zxm=@H&R(L!NB2?nfI;UkT@y{vc5L4jH{R_GWO_X>va9m)fBnsKbR(UmzkA_=fd6)M zv39W|u<-?|D69$rp1(Rp=Ppl*3%xXvrURn`^aF2uU^}-{BFWC;b95tP1!!T4 zzH{*gHB1W{QRwv)I|5s4$hc%BXk6bsdzsE$nxL1F3jxuj;t~4TlaGkY_fuY{1lvXx za-VN+A)SW@b=z>{{bR#)0GW(OsgN(x(Gv%#8;+;LVR(ULZ-T1D8Wqz;DnsyA!xF&B zo7lZQ7mkO$$f``q{v`E`_EMrZE}Scxh)@jonV!i~EF7Un?!TK%2>T!!gagnP8Qa=# z!$zLxJ6&lIySZiCRIWAXkN)y&WLTE?Z6;Ho0-RS>mDe3;96JtMYiPJ+6K=q6*BadQ zE>ET*29F-U|2RE*`l$Hcos5x!BC*h2Z{4goNTz%B2_#=A(lVg)J{U3{V;CkyV-boc zqT+YUvKNGw?1@vNJ4W?#Hx&R~DN`b|Zu-vw9*^j(%3%?#L09T}8TJ)LEei;tu(((PH^w#^1i{jmTbRQ+) zDE!@CBC_QIejvuLx(76Ydc&kbxk5dur2nS3zVq;Vj_t1*iiT)#{~+~@^imlvSIJex zxqK1&Yw%b8WN^Hey)wM)T#23pB>@`G#nBG3rO+=IGJ^&P=krBsz=`BG&2O2=Ausau zGC=31$&Kly*KW{6I!B-XyB8L%``rRrGj1E$mJ2TEg=^Dv?#d)kl<4sXPEc1eMuXi+ zdhEVqi(p`=oLdFR&X%$9GI!gR1R(i?DOW0!uBnuWM)9}1xQ(wNnq6J;e7EtSX*Ct5 zNLXGZ%GNzIXdb&~V0}DFhI43WFr-1;>_n2ha1L*c-GJ}Yv~8Nt6{u3HcMJrU@!(+R zF+Rt4^Xl~(df~z~@%~qydxgrihH$v==D6))p|Kb)ye&E@xx z_V>K0Hx-A&xU0g$uEZh*sO=r6WiKqZhG|i;%IlV?SgukXz%?DG`MP&2PYX0ji_u+h z4JmL*ey=$X1H~@I;8h!S;hGN4B(>Z{Gx%?I)VXXyG%5bOLqikmV*N(n(EeH|(SPb| z&%baV;uG5b`u zP*F}C9QC4MU3Oh>Re%iB6s{4{v|AYoASeK=T(OML3e_NfJ8({^MTt%4V>gNbUO#o= zOtAZOVkntEkIU`tK7jDQv@h9IZ&&kbz&tbxe8N5oZ4iH_@Aewi; zjyRXgi|0IkEh2Q#Es{OM#oobjZU6Y5uDgyNK0Gl!`>xqc=9Ho+bu_v>hE=z*#4E-d zux;xO7R4a)qp~FZIz;}?u&#w~q_a|`-f-?bv$*yss*Keq28vb=Mp_TvrMwsi+0n2HCGzli)fkKr>Zx;22 z0hg}RaDTtl(?24)o`Oxg!a)c6dZg1QPk3kcS|dzpV}O|9=0@P*K&g0~VsK4S2f%4N z4wY(k@oY8m@naWIvQw9R2RVfBMIN)O+}Wd(?(u zN~#``YUP4t!r>G}UH(k?7Y0ZyZsADnfWuNcI~PRn7rE(5TX)Y*ptuPzbTKpp-eWVk z4(vqbN^JqscHx^DoY{6D(mJw1@koRYjSrKqhsaUmnCvEO9F}ckEls-T&f}Df#+(<< zp7#K06nAh4kKclP2pK}&KpKl)-okhTwyj^b8~G9BzeRF)jkP|s9h+?1aXwXHe9N@ zaF%xG6n?mBr~9vd9+UOxXS6-s3Z z4i~|!2QcK(pdL(W7ReiNxAHFDfNcxUhkO(HZuT?CVWhltKef8yKJoB_&QCw{VMS9^ z*)&ZdL>t{XJ3ouUl;8k1wkngh;7m8e#T>e-P&^tHE_b^GpRs|nR^V0~OV7oByJ$G< zWN;;N&{Vjwj1KnE$Uv`nCal?kF)6yAi_Y)AkN-(Wj~tW_kB@n;Ub*JZq~|47RV77| z*xB|X-$B09alJ~&;#T#hH(=YErFxN1A%6q;1Tu8%5D7x7((ywF-Cy{rAE%+gKBZo- ziy{ceLb)rY9Mu3D3ytApm^6UJ;I$k|xJEq6XOg$|J~tA4#(JYcwT2r(@*@Y}q>^zuuxD7DQ@A(}hIq-fe0O7)TfzyCb8vSD_l`-&4jrJYH>TWcQ`3^7 zDw3ioJT<>GMm}_>kTLRs%Wn3W-+*oNmw6cZ%g9e6_q7|)6j~|~r(gc$$K`wPJTBKN zRUx{j;!qZ9lrvN+6&DI)K{Srz1Gfk)JdZ~sq$*s@ZN1WUg%o5JcThLXh4VF=jKPjq zt&`lz&x8xiMp9Cy*#1#F%}q($)etqq6gqOm@2LW;xv(ux;M-gUBC8{wn!y7HKz#*RyO#T>4Kw{loO+6OU1? z-tas1!XTL>t4!76JQW3mwBUFwKo*Vyk*I*Kd9E0oO;feS^X$@S3XPr1Fs+5Nv3pf< z7qz+}0AtXa=h-vVPlLT(a%`o+ES74$PTvp6KK_vpl7u}u z0B9jZr$$FN3RJ6AsZg#i5-5MV5T$9^;=2|IB@zlz2;KiSU@dSkkII0J&%uqu0tn>* zzSi@yi}j=uv~Ofc)Xr^tKuNfIIs+cm2*qMCaYsvd6v4oyk_qYby?3z(dN00mf!B~! zRb4u%Mm}f{Am4`UMouFuT*mdB`wiGOHsuicZuT4Gcfrug>l2l$Rl5JK6ZG>x`3&`@ zl4Kah;z1JjWtK>`t5h>g$`{Lv#MdfT7AlKRRTP{_r${)oENt6b+Qncs_uJYq_-}SL zcIgJr$)MS2I&v_cgMkU_Ivp4rp=dZPoNuKl86Jh=J-7?4y#oeeW6cQe>(pH*r6}e< zbKy0HP*U1BBKgn_l3(9`z0yrj-#m$o&gCu5c+slJu)f)yC;ePdoiQnY5MPwj3ArhTQXQTARvTj2;B+p4Lzk72!h6vT+bO{ptwbg|^-Ly5@o0p4 zl5yb>UW?#uIA95aPT+YI?#JMH%UR$i1%rcCC|9gdu~Ma>-fnRg{*BMo!1=R<64l{q z-0_zl&vslI?CqifyvHuJ(sucb2FB}QHl5DS#qT({w>VsI&+s6ztMNJ=I1W4Aok9K} z^3Rc9M81qPw)9dr5Vsp_e93PnA2Nomz`rl|t=a8yX+W()HTVn3ElgVUqb$G@8RtR5;vTdmjW>eMVXpgjJYgMnf(CSp;t(8*`BIRO9* zjfKD2!Fy)s%;XDjwX*oGL&&NkFF-Xtm!)j6B$~w1TM+xg-pAoKu}FAT(D)41S_2ml zqF5{@-tRPctb*pYZ)_BfA70bDOX4o__3>Yjzm0r|{N}uC;&yly^*0fG|E zX7X@D(-*w7<|DNY294bzoy}9BTv>1(b_?OafQSK{p3jnmGc8@0kI8Tj^>zyfb~+G0 zAF*!Q9hcgJ3p_f!coHjP73B^7o3IY zi{+|#SKc6S3@rnm&K9Utt>LVGdHGX=v+?sP;Wv0JLGR74{mg? z49nQ?5b1iTv+jv54V4OTSg2g5PMfX(4#H07ax{^i$D4kQWy}{1hZic&5SkGET)sdV zz-c?Kc&`cg>g)Jx@jUzyxTWFZIiGdUP#=ZE zT1T$N!Q*U{Ox5&t)yDN)O2%U})Ylu_^M>55HMnr&$WI|ZgS=<6CSFhMM%eZs|1t6p zkx$b`+$;z#o~EiaIy3-yl+}yL&t;7~NfBaZAw5)X-c*u2x3hDyTQ}I&ln_Ouk#*IFn~bjOw0CqEXZE4rg5c); zv$(QeX@?9>-H}z>2P@$1$e%(!j*M;A#J1y5G8U(D zLe+*L#L$`ZNMh^_xQPab9O&y7qK}3`n9Eu;j-v)(Ov@22q-hH27^~wuyAZ?0|M)Dn z?ZOc)vfzpq#+#NUe&@AXLGs}wiiC73ma8;1msxPbrNQphl}ym^K(A;jZildWSl6`B z%)+t2N!RX54(3o}Q5qi`5zSDXqmA=!LVN&CX`7kbEwBwCKaTuSP-q$&L7r-Nottz(aMT5vNJYwB<(4ijf#ak8Vex-5?qpyAUCo;4k!jt0TbX#mQ0 zuEwD0sz&2*{t(vT{dN+(Cf{cT&eqc#57u3KeVY62@9hx{F_SNBYW-Vw97PlPv}u|> zSoJIT;T&=f>H0xP84D`Af*RAtPI{hz$V`^mbDpipk)07M^f6NrtNk0sErR zb)8ZWYz45e@H=rh29$+%j}XoxRC3y zv+<`7Su=UxIkzl;Y6qHdA`BWG?1Rvw0NL&MUis)euc}Ak#M-*`%6I7CeujE_Xt1xB z=5l%3nh?!xI1-NhoMART;<(O?EXgn9!3)T5ATN_>bHpNXH+%IRf=v`<9Ey4x^?C;1 z4{haYEa?88ZqihxbJ#rGwG08ts(`Jv3#*tX8IK8Y8ipZGvl?_PbRK(kYDTz}6wF0| zdr1LcJdN+9zMJ~<;=AlSEW;rn0$2|AC;$r_tmzP56WV5A4tbgVF)Ty%} zBnAIzBrCq~Zx+l4I1!5o*Q(YV9f^bAVQ+Dq_AYfxJ8JnNHAxge(W3oOiyJnf?Id^~ zkx+>Cjtq)B>SSMw+z6mHESHk0ZqZC!*I9FYn!ybtr0X;`G$78mmBI5z!chQjQLSEu z{?ILmV#q<{!{oy?O}^tj7ko}3=aISfuDjK+bsYi))Wkz+;pME0&l_8hIzTL`%qc?5YBc^C2k`LK=g1p+b%G`dBXcx$kT;#jY@ zC$#`c$H7HcbRjCwbIGs6&F}?5q9e0wR%&%JEvsXob}l?}ah{>R9vbNF65rR}_dK%E zTogS@nx<{Y)fVm&pF{l&f0zv1qb#qnIj(U%1x+{>18`13IO_^E>kaY&Bp>t|`JkO6 zAHK8X!#Kavn(Kv4YI&cn_a5Zkr z`04vyt-EB)aWXrZ*`XGwqTmZa@dqD~k3>;a!GCN4I~$Tr97nP(+mdzbZgHNsCC8ab zY)figcrx$Umb%~DbAIP+T;g1%FhDgbF?m*8Qv_f*Y`XQEfO+tUI-O}6T*t?7G{$H= z*|IZlR&o!a@8N{0CMF??ymIl}39nPPTm?mLM(dZ{)oeOLvszKW{psyHSZ2{#@MVd~ zINZM^-0kq@xvz=ie!m!h&(TMoa_^8sC-D8-;_tf$QMwXr=3;~#e?ShGK=wDt;gab1 zc4Tom+i~G?tYM>Tl{9cVOPFe9)S5LqShCXl${=(Tj_c6{>3)v@Byfr7M8pPv3Ur4E zoSeZh40M_e8lQ_aN!PkpU7Mpnn4r{TvY9$&v(3$OGM%E;sNv+Og+KoM2Hp1BX!CaGf93dhj{o4eehfBQRlo{3zC#Yz-*WsNM+Z4r zHl6{j5+V=byFPzvs^PmRSyx8AQid1!$W|4WY?I&^mP3K*IXq9SC*O;R4MWG^ZlqG= zV1VQPGVZ6{tfNsWAQ2wVv_w^u3*3NT3F#9NFC$L|HUR~)Cv zN&IV$zd#Px%i<1Vs;CyZ&DZnNwJM{yEX%}kyG7wsY-=W}X4op(IK%VTp66@FVSvGC zgz;pmPQI^{Q+GijzdUX!BS_M8{mFO)&9LCOA^{{jxa@1u_L(FJn$-##wF=&T z_^6U|S9c_Rkx)pIDa~On zC+!v{)9Fs{NtvUjBk&`b5)K9TNnpF%($*<59X^|)>&DIn#>FYJ6mcm;trDyKtg{0F z)-+ADI=_P-)sRuR>m-~Ehb~LDoN49aQF(oyF2INwhC^Xg7 zez`x#b8ytGbAD}8Us$=MFQ#eJ9K*%>#ce>})}}K$p6j@?R^~L{gLdRxuIs^f{X*y63T(MMnDG4&`StC-L|BHdGu6s)RFZ7gv@}g%(KuQs zKOl%(YW{WRRChzrY}?xU9mrZ@HqBb)K3zAMjsFQ~HgvZFO*gQO*jeuL`_mUp7f&Vg z?khi+?+380;(*^;vUy%WQCVAe?{8H~7(~?VMqNRdZ4_;JWoZh_w9r0zjZ*!DpJ>!y zy7D}-6N`J(wCx#@oLA?$TeUI;W2pOBzXUWwV0u(w6S^JT3vyd~uT^5iQHU8$ZXYGO z)oCbU5UHO<=(up$#PP)qJjdH=L!PRXVAzg@S1&pWI{CYp^AR}9MC<4ks;yVh43iM9 zE(p^!6b#$)BBBA$b>K4{vP~A5FF>;*Xar3Y;0kj3Z(AbT&AEVHD#A8+b7S3auKK7(m4~OTg824b?^m_2bvjO-H5PD)%I5 zYZ|(OVp|sw1s;>w;NI4RL!jc_&7Csf)u|SfpA}O_*A3u$ zn}x3IqOHyc3K2%6Ti*HX5BDVc6bk2}co2x^2U=Fxkkfu>(JaPG|so}MEkrn&4`CMYBb<5S<)4ZY#Zq&UL7#qEXzi=!5tI^ zTkh5-Jf@n&{=Q+8)vM(g^=f%r*`dyuWeLia8d@hm!uCoF;GValWtfCQFZ`~=TwKRS z=zHtUEua}T;J2VTrOyQKsFc8Yhd+FG3ZG|~CHsTzp|%4*;!k7keifQ*p6e<4_g#6j zG&E~fgh8O3a+_-jU|}gn`}8MxQH_6R&uWNa=nA%?E8}@ffuE;Bwu%$abI?p5bH54A z^7wc9Z1X6p^;>~^lNBT zD{5b>32wa<&C-;q?xX$UNBD7*f=^Y09(PL}rb@PA_aYF-QNTM`EzM*jb1Pz^HK7|$ z{@K2Y2dR`}G^^#@EVX^(mY3)Ha2EI@!-1d1hhd{$?=6%}t8Qy}u`zP9~5F|cQIjl%I7(3~t_2-5IxHV{& zmjnNZctl+KV!wBzG0wU@bg!;>Rs%1XK#f{OIe(gF8z+&>;aECec8-;KB}od~-Z&cy zDG3#a0TU!M4DJTces68q=8J!x>nqX^CDo*8?x@5i)Ji3aoUj$>xX%YJQ{pVw+A7@y zxO6swZhQ%xZfMH6XGu~>qPvbw*Y%!&cL9}2lk^ChVJ#s0Eg*7+_8BrW0ymzF)p?&Pa}yV} zEnC4h-}lLXwJ#A)vtC1`9McgK>>jnxdyzydRq9l&j^5eNNT!2D!fEQ>C}WreP>EUn zy}^2PnaKAPaNq2SGDWUs$Ix6Rk?iFwM!8He@u}G?Q7{Q$7yWCD#uL7$sl<7B)(=cN z`Mz1J61oOTVW<**ourfXNgT>yfNCX1@4#Rajp^)Z5JX7WxtC zR|)%&N)9ajJZjdJh$j@xzDp%smLLdAFi(D9!o9)Zx~t$25egh4;&cOJ5L0n!E~Ow) zE%|b){DZk}0d5trf;>SNpyi)|2~C&v6KtZ+1_ zchJ2aK6ly9Q5&XhV>F%=zJ|;%fIRGb#)Z>IM5Ih0P2jLGt&`VOrGdfKM}Cn|fCSE9 z;v}2xEATydj->?fC1^}E(^sHrrn?|9e@1#KYo|$yPfR08v0lHA*(_OzTUUv-YKeL1 ze19|^i0t{X-MSzs8`Cln-}1Q^1il&Y~lX5bo`saP`Px(G;t}4DD;(%1-kj-uJGWe z+8@6&nGkIP*RvelUY-%cDN{wy_q$kYm0F%r&TTNwvuwHEBGIfU2hFh5-*O$gmP0n4 zObJ4tko9nRb4$UbO3*qV+Em!f`;z^M>HX>5dwlF&;;30ihv3PbNqT+W@0XRP8O_1O z>5F5y7L9XSym1y$bDEjKeTG4V{>_!r;MX)~uG&<~v>2PgZ$xw`B|@*n5#oqWLw8;W zGzFJ>O}hteJelB*E`51@gS*ifR}|)SHj{_d_nzaZHRXQl)iNx@R7qnl#Q*TF=Hk$N zuh~9D7*#O1?&7B3BfxhGMiIHV<#Q|J+%}tCBJ8poY5o%2xf4TkDvJR`1iSk=xn23m zcZQ=8K3!aKT;iIhk?|dqV940ioF0R2cz1{Ye)ASRt}RK|s8!(5e6ocx{#sLW-bXEt zQKNajJv%FOUq#lOJ(d6p{g8dU`RX$(C!6p26p)oS^Z;u{XKprXY+^Ns;Te^4ML{S* zidg3=vBs0JO0Pb_x?z$H3E7NuiX1G8TLipJ6#=n-d&|!>ygxrzbCseHB5e_s>)5a< zDu-^al0)9*zo=A35XFcpEqLJv^txvl4Vf_MjL#U)OBZg)_gn&R=VF!KXogBN-6^TP za9d2R1lI)moPc#NuPFQx;nQGp9YfnJ#a4w*%u4R7(kr3UYNAe<k+-l&@?|-?!??Wr;rTiyBG)rdG!yWJZ%R4n!iAsm$x~`XZ_h4&|7C{SrACu|y z(I-X7;^Y$hGRAyfrPlQ|26qC_4W@)w05cYVSQNw(NU3Gx#`)zLaSMfcM$=zTiFaBxjP9)~U$A2_$C=1bEA znQlS%>ae^LV=trWOjRPEUtHj#f1~b2ot=Bxhi>J(lK8Us3*L=DSB(i>lhDb%NYX8! zOL(3r3>0jKUP~hgm~LWha_6#gH7 zeuKdCI9!#IE$&&Iy&T7Q`ReyL?!3ay^#wk>e}k*bu7XbXu6-qek>EeoK8(_w?mi@>&hfuN?IlF+>yX+IX0ila=+^8!vvIu0B%@vrhPLA_b zl=t?%@kdHDU>GKXAVP9;^+gg3Y|e8ga2*e}{iWy*t@4BFIPJ8RYmX|IG?O$^E_=aJ~gO+Krnclw7@Qg#!IcytkI-|a5i2PqrIqPZU1)2y`?y#=w{O?%B6@#=b}NUfBjPn zpU&RmrhjqonDR3U12|C~S5ph`-u*AS7Z;c?wdD>(#9vFpL#!M+sHFSYy-?6KYgPQ= y$M4asR#6H9Ws>sT|A+ECAJb%t$z&o@yZb)}#SpWDhvgvv0000}} z`}IB#cBHbR6fy!H0vH$=vW&F2>i2aW3=A9$4(5BrhYX1e2IgHRBQB!u0e+rh6GH*g z8~$qD()-9h$puZHdl0WakZUkV$!d-5i|x@ws$hv_!y&GIf?O zLuW-pgCM=>Ck8W1B*2F?F3J}l>yIN0BD^~HHg_wr=;(aab7el#csQTPI-m5Yur4{u zeQ?s$)ZBdQb^q-3UMaomicL=DB7?yXQ=E99`q<8(W8EZKV6kl8O|;9za#Vb=4a>Y> za_#&{_YZLU5zz57k0S^DC@89(p?VR2*Oh07DIwJjTvoPI0)dONIHbr>O;uL<|7|F_ z27N9XJNRY<6J04l@87z+fjvC~;|KZaw3bz$Rb(iqi1IFXy?H%_71*S|0?;AOK1(E! z3igK*g7C*Vv~rlXPY7bvA0J6g=qBzlx#mSYv%-N&K3#Fy(!Q zlaP57@rY@GHN^pWK)zFSp?T?Gh3%m6hhX9W2N@G*m@$r6 z6|`&D`yL-rk#YC-9sGR8y(pI(MIV7UkV9Xkf9#o>)%mJoQV`=j(!1F+ zxs`m4+!)yO#yiHZGX-JlD}87%pqCKbz!O)NJ^0Z-lbFguY!T$Khysmux3YwZnZw4H zw+8#i5w}+Ar^^G5M|*0Sen}4SZPaa)Ga03ta8vl#lMHCDi$x!}0Qt5`8S_b(yo4|HI%|ovh8tEd_yRoqJ8lKPff9q(do#T%FHjX#OE4&m5$mnT`n~O>7?& z^c}dwsBBFU^dG5h>R+i8Z42!!Eve(wD>P>rP4wr5T?JkgQG+-M6{ZF`ygw#=(kWE_ z7LyAGNQoi0T%gU%{d4jBYtCkxNu_1H%kGB;xYdUv%AVkPV{E*gm92Kto3i3&t9BPm;N|Ofc3=@)_ZX zNt7*r_Rg%iKz`p5+3;h%k+3tlkX!*iCtV-yisI$JfR_^I@hDJZr$rQl;lUmUO<=Lp zWVuQRX2F_z{#`*~2e$ttlW*T?z|vLXv&LJXD;}tATHE|tt@uQ`;Rka`+0kc5_c5jb zD%KO5e`R^c6-c@t3abf)ClSfY5(*z#6dh&EFl6gyQmi*Fpr9HVT@^RWmW-01N{R{e z$!No9QkePinP((mGQu_W^!SlK!SRT9^apb%p}!eP&Y2;aZ&TlcFqfxOxRY^pOAOr- z_IIvU5EbUd(thdj^8m)lb4|TRr+g457kd>xU%N_Bq$tx2!8$kwX#hjWH6xgtL>nt$ z+4T`(Ps&>VPPuT~i@;q8&FUy|!){HXZWBoey!YoxB(h#<&lUOHbVz<^BsRIFv*pM? z0vK&+H17Q;`?Y99p$j-;;Ce zrMZ2}3B>oueK>YGIcLaI$hK~mYR2W2Bt^@SnqsuH6HZHJp=-04- zoJ{{I*A3IUagLYQnG@2wcU%2;bq@5d^h4{qT+s+Pqw&Q2h%PGK1Y0+HroXOs^wIN! z{;vaO*2n8*MTXC}Mz%w~DP1IKs-Fe&d{=Kj278wF=$F;MwJv@m}s0J(P}EMCs}oCJ-dw@sFQ ziSI?wqFN&>wc?kKmR5da^u*$|4ux`%S%xX30KEV2+3}=4j;Wxm`mL#UT$^Top&>@4 z{+7F6VM3^1=JWX(VR7PTkWH9icAQYL^&Wh(D3#PqFbSgj#6clz zQ(V6^D}b+)+B#Y~1&Xb~Pr$#X*>(EZL{RfL1Jt`CemrqzJ&?5izMboD=$DMcf;U_V ziEiMmw5VT9@BGOgf2{sB^WXoyS>PZJDj7z=!%Nk z=F}+ZQEavkOT0$zE4Qnb{KPcj(D<*|hYKHqW>8VIpEthPz9@48vs9JN52-npfuVLI za(&b!!xrBP*C@&675TZbF6G})iIH;QlH{M9BA3dCbP*G))w6%Je6FVq2Y1?dupav+W);a&v`6M+4U=d{L{LM+%P>lCjcAiCQ@(L_ z7lVY*>nKU*MF!ztXiQYR^`YXHBy;+LZe$S1JHx>l@{KIrL)O)_*f^S6t?Q7M_^6Iu z6emeJN)KK+r_Fd%IXp7O#({sq?2Wrb4^$&JV#KIWP_|KNz&vy*;j;xu8|0~EL{U0F@$w1IQO8DBg5(nPM!4_7^`K$xS-c42hwByBL()%SXs3r z)Xr|)B&jp}D-RmVA|NhIG|pvp;kdLw0Uknz|SedkZLvbD3fSNb;I+V}Q5Q=Th_ zRK%t^(UMwhR$eULPEcWC0LB0S__1_=w@+cpV!Ine0d)SQvgX?9JK0Py;C{a1M28jC zWMQ36HS*W!Rl7tcd!lJS3li03_qxtnzj6K&XtLgV@y95*8u_j6$CEgzC74a|T+x^3 zKGagT#(DmWL0Kq{|SdJrbXOpG7ECC$NQDPLZ; zN;VOO_!SDuhM))_9s^6=U@2gYJ?R)h+9Xl1fS4L3TsM9JC|1U#!acnpem#&mES~aN zm880%%Lb`uO( zW1Mw?eiew(+JkUe5jHz4a|wnMuFUdHziMS*gb|m)ZhcSRKI$SV#Q8E+L9XVwFk1@; z?(pab4cgraGw7Ky{HcWh8vpb4vR3UiH_rr$;j|dtR%OkZs>;X3CmLz5^>$zTe*WYB z9Qo>xX3hYMs}{*A8Nkp2&OU2>&EK*yGBPf(5{OdvacPw2e5DTn zqZqKNrMCZeCs&@-1(hHwwUY<-yS;DZkDmcE?C^GPVoVVM+=I^AnrRBD^>+5V`sK=o zm?l3=W)`6oJ*7y{B?QkJ{vOlB#{8lPfMYWbD`5qbq{739GB$BEAN!I63OSv@#`wNH z-Ad*8(DA%(_}BU6ov94iqOy+5jz#C&*D4_*9$DTH^krogk~yEP4Z>Q@4B?^_?KC8t zE}{m_&&%3j1y7cC$MJC5);$;!O^iv?E0WQ~qy|4J$~TnXM78_7F`Mae%U6ps$rY0G zOi_=F*V+BcoMjX?J?W6=hOdN@)}7EJ3LIi#A{t&15w3Q7lU)c?dSqEv01?mkK8}6# z@Akg)e`S4LH|?HdIgg zDmVS(wEWqJUmkSBi|TJ%j|?Pm)k|L~d#1n1yipC zqyNB`D8#tOI0|jngY2T6YapqvV*;GZF?!5#vXYe9vO zjo!xvLLJ;lIsPx8qp?w6Y~%(-38OPlBF=R}Jm~j+LtUjHqyY5L@fBu)nKceRQm3g48;VdEK>QQ0aHL9_IIZQR@$73?*2K= zPblQ&xN&hJv!yzPI#(YmRH@<^$(q zg50G@bFHms9j&v`kV+9GJ1MIN$_QyeSQ}2pJ1wE626H1uhU~oqWB}j zx~ahyq(^qHksWwj?UqC{xfa<5S=AKlv5KnfE04pwp5~cuZSF>U#T4y~Uz+;G#V&V9 z-nHFNPr7++dh4qLECen;{nPgiHm*3gDvr5VkV<;+A=`8D3HjY9cz9Uty>i`k1F4Fe zI6EAmSEjJzl!*E|{jRH@2hw`ONFum4$rTpRp9QgTaL|eHG_TwZO~mNuE)ekS^L)21 zzReA-p68&DLCgYwcAPE3GbW8&#!9-(;QVQpsIGn|4V?qm$~soF5sF@WxOAP3MDrAk zBNB{|^+eOOFt1+{Y?ZfYBE&gSZ)jw|?Z}nW(J-IEX$YTlsAFV5<0l*{j0pRCurroO zJLuX?*t+(s574_Xg~qNb#J2<06;@yxAskXo61}(G<&Y891}@)z>V;&06JR~0J7ze< zC!kLaw{9t6n6=tK&!l-)wuBEdGARIr6NLnBHRUJ}-YUlW1uN*%pIyY~qjNFy`2p$h z@aV{|KL~k~-~?f4vHcgrr1KLi-!WTHg@4op{OHs=H@$gct2kC3X~~g}RHb%=sfEa~ z8UjOz=pb?!*4e$xM0DOr@K&S!r?M;946FIX{V5-=kdK{O8PXI}w;6dH`JWIRtR7c~ zpjq{mA!5dsBFr^yzC0gcHlM2~_wx*5t57x^Am2(w9Sbdpqzz>X0YG@vuJS&Y8CO6* zP_sSPDU4!fs}1a=9oyIg^4;+TyxXO-mf68>ARj}_3>q>8mye58R9MpIC`Q3SGB7fg z`$lwYIc1Vss*9Ec)={RU^jInkC*U#+oz$E>^(pYHxF`tK^J%51YC^738e!QQerL}Qb|+t4m}xlLW+`L?%2zUkO>TO z1gTLgDGO*%IkmuMEo19+{})VE(0XO%-3GsgFm|C(FahH%6an6}D&BC?gz>5fQ0&1> zP$CkFx)p|hcuir%E-TciG-}roW6Co3Rm}-v91VxJW9GI&E!;L-u-6CS9h=VW2-EWT zotG(+TCJlS30Q^T5h@s-g*o(!^@ASVg{3Mu@&1Cl0I3FNP25+_$38;G4MK6AJ z2M#F-w3dNYZdrjXL_Q5$k`rM^FJngy(iAk#tHBo>xN-ZPL}5{$F({~a(;1KGmRWw( zE>p}*e;Q{HJh%yLdEH*!wmNgfd;6(Ktx;RwRM4KKOMdr9VvZVVrz)nc&$|;EEz)jS z7kcUjErXYJ*2JxQ0@H`BQ&7@Gs8RsnPL;bnOtO#?8}6@IJ^W|6st%23EB`16WppkiJ z(>0Uo#ioTgZi?ATYD+_-3_4_;&QBO?x&7dR4GkPnzxZRU{M zT%&nU!>!*QH>_?43)~r(dK%~8+ zybE6hpLuEh`v9y-rOu8E;CB!lp*vDbh8G3~_Fvzo*t{-3{TvwBW80h^oIKy~JY)|X z6@5)=?g>#???dx~k-%0Uz`dhJiOCYF<1O98WpvxKmpbbs?M+GzRVV9jg3GSo)gr8$ z-JBZqV0ih8n${GKUAr_J3fMOE2RXp)ZL-*0ybhhn<4QO5cyzG9B-r3oBZhE+AGc+5 z#Kv;1y8+bc%r5G=g(|x5Z|Mt;q+Tl?s(KS0&#BCha9DlK4tYygePr+?dL@Mh4);4` zZ1Lu&{_8JSqfVHxn1TUcqY*#m68Vm9lgTaZ41owzJF=9RvO|Bh`Noq34k+FS_6DOV9nJHfG3_f0vsIGzJ`^^Eu@ya0^@;g{3~``S1G9Au@NLf9)q3 zwEmIa#^TX#wd;JoL}Z3uvcC9ltD`IB<#O?Ol#6W!spYkykBdVcC7y`)&)fOwreYme z(HUQE_^^&1yu3p+N8VIE;BR5_44J};xN$*Hf!un;K{uDT#JgUT)8%c6Ydm9fv`a~n z48_`Is|s9IoZbG;bHvNr*99mB_Og3DUex~%13qi!Bd?pweZ1wuAG=g7;L+-_u+eiR ztg*cYpD2Tm07*0KH<8Hv^2taAB0p2=88YRVEnRUogON5?$riMhKkzUMyrZ8Ac=eNd za{KMV0Qqae;p6G}yz+>1O4|1Jhr1$Z`sQnU>xy&x^jOLwiPK8glNC;sA}MmGCW+d0 zfz8#aU7z&bGdEsxLc=j7x<1-$o)%hX6uE~uK(BVczV&Ct7s%ji__*)b5e@p%9G`sZ zCTsHKqvk_HN@zgCBuv+H?hZhZoeoEZO2}ciuJ_c9BK0DlnP8Sc;kXBcu;}GkwU^j| zy|zJqfA-!g|5{`I=*$=3*^v^do1=D_^xwGZcp{tpU@}Y-OWq#9Hrk)~EKmAg`6J+Z z3%3u50~tC!0jI*MhqznxaqLcj!d36BRp<_Ld9t~E2X*_aKYz;^N#SgDy>zv%hx9E| zwp5+`47ABv%)cF3aCVm2usn@C==u{WRrYf{X|$>Ovfr;GT_>UCq(Nhyb-VPiwSka( zND-hL;6ecVpBTt*U+AODb9WDTKSce7Z3GwxQKF8y7;`d9hC-rFmGm@CgC)PcK? zpX;D*q`R@j-H)2xlD+u@s|b9nkZCRCTrKsw)h7|O5H+==U1>9(lef>7MVkCGn-Jy! z0Hq>h%e3Rg2a|~YkyIyo)n&b>ShVr_3MF5H5gQU(2*bW} z4r)8d=L7A=RZ%}%CrkNcT4B zLU#*7&D)$C>OKeKrFBhRF$dN^wm&Za+nS?kkVdhgO_5*2_m!JXkfjX%*2Lp5tJAEc)*?XoQze$eMSQfq;iFrNtsxDvVhNLaUHM=o`64w)?C z4OHdf51jz1wm3*S+;))2j(b#(J`}0nzkXQEt1lt{>%vjVi6x!xPl9kK`(=fz5SFXO z;h&F?4#fc+3=9m$wm|hwIrB!3-O2xsZigq%qU21K0>#5o6rq5w!Dk?@bx2Ppmtq%Q z1}27GL?u6Dc9%N@KKMYgv?-Fj3AzN0jZj`5jtB~9{B4|w09(3H*>Z7`-(97J2P>AV zaS$>D6lmO5{E-z3J7;Z2Ff~*&@&kS5!43j%9G~}t#DlAvGlML#7q57~BSUl+gzEzm z|DvHFX)4pA?#w=e$Fz_VV8OK?;SJ$DqeNGU2Zt!ur9&26{ zhq~X~Dc$8LvGfk#KdH)j|2Xu+acm^L9QsnG!Md(-7pQ^K#{Ex`I78rmOX#Z+HPv<$ zJ+1SGpD(oJtbdMNYQTrdBC^vKi;N6C7w&oWDrflZYp?KmPqVis{}_xB?l^Pn)4Tat z{GF^01(_{ZnAg)0f;wJ)cW90_CO$TQ$aU<=ey8tFD+$}b5h9YOv_+7uLXj`tEaUkW zlsl3qbmIibXdmgotRJ*x2h0qgcTEBMnn$a&CZ?{EdTb7Suu_3okz}q2Ku_GY|$QAL8ad{X<(6E93p4zkj=XU(=UJ5;y zYmmtqz3gmp>q0DqP@54___icrY_m`qcUF3C#xN+)GxaicWm`?Nh6+~kpp9y-^UbLYpyDu^8uPs}pt_%ULYNi`2_Y{X&Oix<2$@_Cdq z&`>@~4yf&ni$QZ1Eo8K8U$5T2bmvDEZ_5Gd!CL6^RjL}kl>0w0UtG~rbp`3~AfD{0X0_GDn5Dz80V$o7tso$p`Ua;uE{nRX>HXF&G1ea1 zk-GPHoc6swhtnJnPC4ac)Z2vmV>!eBIu&|&fa}Sl>}C=5aMS%`D_O9t(o?Na0(y#V zoJ7mA_{Y4gPliKAQDsf-<#sAbXquZtp(x~^ghT|}yO zjmJ7uy1w#Zs>G8CzNAy6Ko;*yP5$@>I9H>HhwpaqR3?Pz*{xon))p#U0`c=K@96y` zr_Wvc(ar2hCsv3JA@AOHD1gg~@;9GOTu?oLD2B*)heKY_rPI(pn2uw*rPlX{JDshw zfXU<&tA8XfDfh1@E+m1^$5D-Z%ZX|sKIRz%XJW+Pv+_((oVuYS9phzO{uZIG}dXw&~ zc8vn;9W7I!!d4Px1PedPq3VjZ-rxbf=FNQN(e-0%my^p1%_UWV$7$B~;Zi?8u{VAc zRAu_i!s>5pW+)b!7e-Q-s3O;&ZY&3;IvbcpDB4+F-$=@5Q&&}%Rr}4!8&@iv>^k-{ zp3@*JCuyX(=WKG0a4&PCSDcJA?AMRi>z!_Q3F>%-jFvNN5wr>zYR(W)piLF9N-&E5 zM+?TCd%Do5yqkTLW6|BMX*2Q1t~+`OjmK-&%&}3~$!!cQK9P_c1wjRpHc@DmD>}ud ze#lq3|1-wtGjm=aqJ@D-6icKd<-ZI#g(2mg?!qM4o3W3l-QBm#e&O;E7aV32b2oig zcWA<5GEsyR1c+1se-L(QLc2uW9vWMVFe6D5T>R0najN^;o-X%_yp|HUgYO_YLPc5O z9F0b04CAcir8UkKFZNLyCovyS*v*_#oP~4DZPa-ueq5EzA;y?08}nIm`*K*DAzg~0 zNkfRh3EFNJagPu~TGZ?69nMZiZYFjAkr<@JQXfxh&o)Ho52w-rs!}iR4q;tww9d+a z&;smVPhp;sq?xA$mV0-EwT zdK9XGG&FEQ;FXoY>y9rE7iXj`6{MaB!M9M*2p}A-y$3;P3fI$+=`}94BAmyC-bbLQ z7qm6n8-9nFf@z_p8)#>KesO*3 z^JXr;F~(07sWKI)kL{9u5fRbt7ldDdFv~*@ou=t8U?|VVT!hqs|FX14bI`usn)A>i zBc5f!SGp(zPApj3 z840{>)s{3#akr;aX>M3?VOSBf4IMg(=eO|Y$st*)iCXw#ItUy4M+ingHqK(X#3=@K zrY=B~D@&z@49pFy_EbZY6`s$0eWHa)y}-H2B3uAM@X18ZS-a^ z{JP!$l`iT|%H5$T86-G}#tEm8bjWcE(`AK80=JDU=*O9jIXVqYd z@EOy)^iD5$_63~d2+k%vSNWLu!OFampJ!P=K<}$KDycA}8MpS)|IAT9aM@K7%gchg4!zKB^m~e-3VWRwK7fBDU?D(utNKQP zuFwNB26dbBybfo&URp&g8j$jy%Ce&#!Tb#+aoZ8o`?=C5Ppx~fUiu!#TmxZ=FC^Mt z7+Wdaieb;|sdl!|6T)=1CwQbSyt~jfj5r^4l)8ilIuYXKFrb0>V?Y*2a0-_ z@sTBH%?j&}T#k*)PfgAwOUPwWKj!>cCHcL3U(|vQp7^gfcH-eX=Is7vYp_w1LAbn; z{@t1Ve($RRrLTA9{p&?^hUuBUr=bIgAj2x%%C#rg?v%b$og#cm79CnC2j2;D7B!jb z=C;WWg=AQ{blnPPMkh$4ru2z*mNR~;OVbtG!_tiSaXy~`sz1rnI@n5dLjNH32T~b@6bisH#XOMimgXTAt?HcA&bvbNLvJp`dKz7&-%*9$yJtIZ*0gs zABf&({NC{Lq z(JD|DymELNyLq$vN_6`Q!VOLEPEH_~5-rt+#1ugaHGY3FQD(z6Ip=-RDFz8u z1(?V;tZ%FhPYLLN9iGw-^9zpLZv-fELb4qnx2D{@-ST z9_*Mq2D}{nuhWNiST@Bz);$=ky-V*)YRjuWLr>hJ9(NdnkJ4W1GOAOz*%}ek{DQ*} z%U7!Do@+aRz!Tg2Dj5vjKJEcuqb(i;uqiRrc(6J)jyNNVN{a4Ur$r|#hBDSEKS6VP zwHdVL7k#ENlyh#2QF{~enGxjE%9Ah@m`F-chD2L`f|YNTnT|_5cxR!%vj9gVqN3Lf z3k)iZ;I_)BBP=a_lQ{2tnP>T1n1sNyAiHB@@FJk^`+~$lA6h~mX46-%`#csd7?J1< zuI&y!{L%N5I>EgXwWv?mu)ef%A*7#E8alM>7`9D`2@SP;mbBwL%Ntqi7(xI_fXIeOv)h!UxN$72x$JfeAVzZ^(* z`rY_!+=nb`X?OpG7s@;lmdP7CK9fk)xcJ<#7+RWQjho_0ib}C&^{I9bcjB2_F!clH z%j8X+9B*kFRtfYL`mc|{yDseF_p`plm$ zn3DQ&H+3x(>iJpP?>&cVc-)50z<)RBTG->V_2{W3ZCO zs32lul?n#%ByLGZ?+A2bNlCp)VypN~ZL8Eu7KtSb9!J72M+cuai=D1C?W#Cx89@3> zQJq$Vf`uR0%hhl$m4v5U$Y~Ek2QQz+EHPA)bioM80T3ruawwhZbYxN@GmH#nHC?+h zw*_$ey+#Ib_=M6!b7hQuvS>^TqC1{#@q0Px0%48Y{J}Tc+L^X!yZW_MzyHPK8K`11ms6mbrT6hxJ9!!U| zxutiwA&j9=n+z$m`8-)S6xfDRAnm#%PD2#~XYSzK!Q{%k>ESu(8C%hFN3qh02H zN0o@?^+IWSJ=%{peiyN6YAp#j$KL1o*snN8Lu!Vai0wePtse z$Jt6fVQerT3Q%mzzo70qpl<-S-)%S#U6j!kS4 zySD-78PhipdOybPFiL>e`~pEhz6U(i>T$8ZxB_jVFO-0c95uicGh<_=Ir^~^wOzB0 ztn}t3h|pO{oF!rAj~PE1R+X#&QY5buwE)Pdl*{SgiW5ODUj+${X2M+3I7KZ)X|?dC zwQT`&8Cv)ak7nz7Rkb^#2S(h!EnDxF3sWS)rfq(Lg_vv^9tg5pEqcGLVBaHCnDXrm zv2H{2h0&Yx?I)K&QB98${$a)+)WJnAo^*ank9C)PUk(&>9MKEgR*_b zng{*l5u&zD_AgW^@^v;AEUoHx^!~vw@C|S^s}VWMl%eE#k#ZX`-X~a{6;8oQ2kl31 zmd?IpixBuBQ!qv@v4m-Bu@P(DWK$K32j+xn>mCk34(+6~_Vk#qD|MSvDy2QPtbOqy~!0nGZMg6jlHN}(uaMnjM-{-4{6&FRs~m-F!3j0>d&%e zof=-{_Fg}B6s5-$9)B6?f;^dh(OGzeNPhD4rI+ABw8R|t!^3O`paA*5esl}00&MN1 z0G7_Cst$K<^-WSk{R z=yrkR`O2=}2+r<#Qb%1|2sD=xN_7#C)=fQZTj=h*lm+f~HmeY+2rO{7ocwaF% zBK-mw`zI%i%ua}4N5gLRDr+})ux{PCl0+8V$)eg2V`Itp+R9BK3dMq*K&2$UB^~pG z10-&;GL*Q}NzxR@rnJA}+k$=E&D``OJJ($gd`~`$0g6i2DV8w*hB`c9#`5*Hye1(|R4Tfrb^d`MQ;SD8-kO&XFAPg%;OU=5Cu! z5GbEE-|Tb8>qyu1wUhDpI_WDoS3OHH3U3`-=e?t+aOC>AGdH?JRGma1elx0@T$6;I zro0Z-Z}>)E@}7wNK`vA9e#C)*UUKNt2n{GIdnZ@>#6P;onE}Z=>A|4_Q7;T4HbZf% z$cUrScJ{6c5avjMVPukNBnh20YH3=SfM_8R)3x;z5IQfeU^_65R_(cf2@(n|6Ds*@hn$?0)&&a#Y z0+?z;T9)Ct5Yf$~AY=*b>hTB+*y<%oZ)1!H&-XA+t5Y)@)xu5VYBZU!6R6V3Y)?K_ zya7$y=#HQyJpsum9zj(VSRyx+2F4vzzCx=# z7JfAKMQ8=;!J2K1+ouiZA9BsFvPal~Cz)~1gw;3}k4np3h}#2TR;Pqkj40Bq-P6p;flvzB#sQ^g66Qd9P*yU6&UEDX+FIU_lZix*SXk8= z=va^Dttc=fR~WU#Rv_ULb#X&a*M2I(<~~%MZ&=(3=hWGbCYt)2_So`;?)Lw7-cTil z&FY(C*7#w`zd=O1^%P7Z>+~^7J<8gDNIfNqr=R-vdw1ifVdMJtquw{O_H4_Wx%tCs z$mk9mfRQbZo+~Z;e{>wmxZQ}kX(EOtpc%j=YgBYMx<##Lm(~9?gX%Kw{(70?q&i*h zaga?n67HDVmMe{nl_cRZqK-^OrmV#^F4(c8!>^)1jCLRqr)-4K#7a(Ymi@385RM|EF5B|K?g}MxcejiVOrrv43ytW zSzC@H-8sewLM|~p58&dHieH~JGF_E5l8P@`TO6ul>f~Gb*a8VC2Br`j(dOyNlYB3nZ72Zq6bsmokXuxGFynk z2w-=_8VwOH6Xu!(AiF0FQw=ty%mF)}~1-Z(DN>eZk#&%_$L%CN>soX7IxpWjNNVE6)i zSWE8KhAhTc8IdFk8esYTAmy!B2lO95${3EO>RVz!-X22t6LgPbcV!DeH6OK{Z3N(pgm{}^_K@5Xbe?`QAS17ejo zLbeDfv-Ax>W&2_a6AIAi53dnb9S?EtwM49wfwCpp3ke^QQmFjZf1^2xz+9Y;azwlV4duIf?wxY>U)}4^s zOE9npj+a@e;~LfNcJ`KR;DXS`i;79KONk~K7)a6-$#Y}}$b2%1`11$Ct~`3A0z3as z4Ka3}aUl_wo2mx#{A7>rR}ECOqD6D(FVfHOZr8U^@IzXEG|qTQ(QP^MKQlQ$La!b;gu}Mp~Lk%HS`;H zNbF{mJ9paEtD@C&0cYbFPJ_5?eo5O1A-6O!qR_|HaN1H6EpwJ@+>kmcFKLt14l+*P z?_;;c_%qULtTQQO827LN#V1mDK$7N^SV9if3HRL=_3wS24ZD)_I9u-Wzm9s@Y{F-X zp%=bc#G<&fIbOUfMrfhyrJuAaTWL@KDlelBIj-BN-X>{c7RT4a`3cCYf1}+`HS>SzZab;K489&BI=V(#5*i#iZIBPNQmyDj5TFpa6iw0k0*tFQ@MY`Tzx^DYtM{{F}1XyB4 z(_|){b$Nm&{h}~8isFUHr9sfy-#!!wax5NB*+6U3>Y994JCsU4a(Ah8c=Gt!N43i$ z)Mpw!>cCoV?t1-wc*cwv25%}=fAS!K1Wu*x)3tCUqQnlH#4OQY@+c@2R4jf84nvn0c=ZTOZHsKeSvBUE>&;;IQtrli>`<-q=cm zfN39MBgx$rjgi1C9jv#rzYZg8-^e6p6`Hc${BzfBSJ?QomU@K(s?GmYc-EGe#8Rt< zJAR(mFX@y9l*RacUV!q{G7U?|hGVxmXM{xo>97H}IvHMEkyptxKO$q*Gu?+Oe-WSY zefsO&;CW}1X$N-enP%%YEF6B5^;epiw#Vmi`ppGyts5!CF`&_+DL$p-!n!qp&}h@e><9`SchJ~^rs)vHT!GAshTY^iMPI<3C( z@?dEUDr+T?EqL&G79a%%{4uaNqump_Y%#$c;a%zHcg6IpyK$_9J>38xntOTdDfoGd z=|5^Qv-|0-xJP=pSm5NBq&^!8P8dP9tx!-2gCS}C1!cZ@?A+`|PJW(dfsHLBJ?gFT zs7wIZ&{%I&+j@&|*BXq;3d1?MCP#KFYbsu@zI*KmR^S?b@U2^?GiqubFNmujuQ8v{sKM1FD!*aU&**=VTlj7|$m`b|Ex9Hs;CFpzfq`oSBUQw?zyPXN z4w@f0`g3%{3R95R)XU4YYe~C* zHxTf6f09ji-P7s&90)K0KEGCN?nv6F&$`~)b!!_Pz+m1`&`2cEHb{c_rDd@sR67|u z8CF#&hFchTQyK`VKbe2Y@XGx9Ed)qOrdK5J&olGQyVqX)E3rovgeZ+hB4SKvSU27C zaPR!|_VeiCvLA_Mq4B}c+>-d(NNKz0sr%^X)k{t(e#Tstb7M&uRZNWev3{Zmz-EqIsLj%sDXyhmv(5=8JOV3<(!Sln;lFpO}-W9q)dfL%eM-)S5J1|P{PrE!Sk(|Qwp)bXvqP~G8>4x zf)k(_4mJPu{^Ba)^HRUqO1mq$eeVI)`C1D+ZO|19^XdXXQCD`?qsMD2Jt)~S3U^w6vq$p)$$MGXJ;UB`}gyNbqQBQq=gz{cPxoMVUa%?1&IiDSbHhwSW6f zegq^OO(cv>)MYsV%%=2)O0M4O8d9*@dvj~tPN+d|=;fAQ%%L*^ZW1Ud`*yE{C`*e1 zv$v-Nrn=L8ck^jm?5Z!oxl;f(pl?~U&%W0TC)eYi)ONECyxSMDZDTXK=ackdRfr>| zAW`MfeQX9v-}g?h%jKTOzTFBx*Y6zM7O;*IF8r6MSz9aG+2)YezT($$Vn!7Wq**#s z50E^_p#=RH-h&lIxcb=g4qgo#*%eW-D+LPC7G-aXrD=Bb_WHRZWc2Wa*k1&XKC4w_ z^u#8k#QHWPO#OcX>^c+0O&UFu&7rZO4t3O_cizL_{_tn$8yG@7ZgG8`m5-Fm#0gt{ zE#aaAwy$i(>J_b6w|W&;tXhG$4j;jP{>#5Y=cUV7zos4c-FXK-ao~R3ykjdG_>8#4 z+Es1Xvuis+^^hfyBW&W=-+m7-z5X^vnS+4p1wIbGa}*c5x(VEa*thoE3s?aCj9)x*YLr~4)uGQ&t2~7#b5vZGq`ZM3!i%UUNqFzpkO;{o#~4dDOU^W z$dw$CzXg=H97lDa$C0-h5oob7(5e;Y#IMDL#X9As5(#&Z=g#8tFg~i-Nv|ra!S&5G zO4w>sDR5FN7nweahR$c@zCt0dn%%Ta_?{1gxk+lixK1Rlqw$)7TX${4 z#euzcu|^G znk(-(s7uq4W(b=!tu(vu7x2A*_yx{%UPLm%iCM65|J{4>=}$h0bSzGnaFt|Pfly}$ z8-|GjLG9}uM16fN>gv;M1m3_keSuJcWFpTYaIy0W&Y!!C))mdzxqCBGsU+X&BcSsH z0wtABC-E7+Z};}ic;d@maHY2&pL_ga+`ac^wf0mFCj&uX^SEZQ zKPs{ma&`raeW=p~cgsW#x|o5y*-V3>o2h**jIEe68T$pZ0i4rF2g3;6JO;ZjbF%5G zp*|vR=NY=*CqSrqR%$qDzK{);&E=6!BoqwMG{DI-I-Mp*7=HT8S8??CDFvEM=h(h^ z0~`M#Bu$Ip71aH*oUCinrDW}{OT9RH_&6?K>_J^!8trRVV9olKXj|FBdkhTrkKh6! zyKw#r2KtBLxjxRFxr9sSyRiG#?O3;A6=E@K3_6#?LL6_?`Zf60Z+#B0zw;iRd--(* znZPNZKY#HcZr-s)Ij!6~d1KOPqYxq2ROD5#Gu9xZ>-z9wAL?|V1#JJE*#uWl-jH{i zGrduW&oVK`OQ1X7gU*gqICJti40FayEZJa_YmN1_`lI*n!>Sdn3XF0{U&(iewwFrA zr!_Z1tL}gC;2|73@&V#(e2)#>)KIS+q*A;N` zyF&*xO#=__zZ07_uEXE`@Mk!7;tXPhT!F;1oMOIm^v@t=-@Q3GF# z6SUNVIoY)_J5tzb@k9z+ZoUhtrd8xzgQ-!|xwgO&&!8mCkkV!)>?Tgh)YRD#yu=+87xg#o)jQ z&Yr%2p6-6t@Ugg6Tnojzdc5~CVUqXC`T~unndL#Da*D@eD(4d)bfD{UAGYq;KsRhg zI-NwiHU*P=G7PRxZQr^cx9-}8V<$V9PozM!9fx_=SF&u?rn0ALtQ|U&Lh5_Ia`CBaRCG4^SMfgPPYq~Vl)Hg_T!DSbhr@}XmKS zykV^ZY|P!bUzZITBM{RaQ98*6k0;Q>XI3>fVqH@!4!(2<-E=O2OQ02)%cUuTsTYS; zByKo<<`!E+ZXRDraWn-PuNr*TAZW6#z%6TO{FLwVK9MYX=2Y?iG(ofBseKjm(55{n zd6%4dC07@?M>1LOwKw1Gs;NmAZgewWlQ3LAL`{7&w(Yq`T?kMdSlS}xWzK6qrN)RQ z(yDRV)@?z{>J7+rcfua&Rlj9N1{Y;xvkf}R5gx-|zj65Jt`}Z;Bi_{5fZCcAJT>t( zHPr<+q%_sIQ-*fc*wu4Eh!gLh5nDi{6~Pb(D&26kmg1uP9=BphCz43UVhV8EbK%i> zl=xlVEr2BBao!Ur)Knr4(=cJXE^>AOdB;(IyL_e$rl6`oWa^G>25dU3 z+^=bR#To@=r=KLm@m;R>)8}8&R<*CtzWUo=ta$%IhQP$*!n^14a9J|H1leMTS)FB~ z;xv|KGA%T&*$Pm;>tOisuaO(-9vgCMf-lX8Qpxx;o7S&+>~zQZCtiO2Z9M+aei&>< zHPQJ`8ottGAMXP4uk46kKu07DnqG2{l1u4qZj-JijVkce(h-w%L~&1j%;}2nRnE%K zAPo4sg#@9rEJFcOMpnRUtf_&|CYO61&qJPIIlilaDiA_>v&S_?JzM3-Aydqe_fKVR zTFEICJlE`BzFHg}vagq3JA^CUz2+C6daPNGLX+<5-{?b>J>-2Ig+O{S1}1T%QN3maCq|DT?|!Q0zICAN%f=C+=ls0v3 zWVZsFyiFgMhfx|9uN^vqgVYy3{Rnn#-MA*x+uy>UyKm(ANjK#~6PN7-@`27gZ{*vj zj|GKI#-7dz+_-MX*d-%b2j8)g8y&`}_YW=h{;vx*_fK1!8z0T(^Iv`Sjd#qp=0>bv zw;Dm-Ru1Khvlx|!L^2syP$?kz{kFSr#_F~kV+?z^&LF>##@RYaa-5*U{m^()~2a7gJ5D7G6)2; zV<*qx7cahsUE8O2<#53v8jN%dVKWFuqoT|ZY>llseCF8}ea-u|609z2B4G}IxTO2PAeDnQ(_DyCU> z3Hc1TC(AO>*ir{8ZV9g7@Lad}P;qaGcnlXVb>pWmyeh*b`uwLJ*2J|71v^cbZkf{k zs~9T(NJE#CQm!_QK`(0D5ZJ~?!~>TzkjcJo+sDwpVVk-xQ~2D`*WedM)g)cycyIgW z_5bfsX7rEGbY6@fJahz)aAM2kcRddp8wwQ~sq99w3vo9AH1K@Y1q~}2P}@|C;l5!E zTpU1lD694^4x^w`|7o-CnDRRXU^8Z__cX6*Ms0JgTB{6`)ZcYo^?CIbntK0K?=0^_ zT)j+NjGzq;kKpIOdKG>BgZSzfJ`L6kuH(x6tsivTyShgFU&Rb{OB3SpINVTM zvXGVIhQl@%(u}$eD^XLvfNi%wfOx(OdgN2VqNT>34_(i{JTx*IynE~&twPDw` zE%1X7Vdag1Qynq7pX|?O^SQ34t|`Z1!|H~Pmenn&Z>`5r_Yg9@8MwBq6nFtwi0FnU z48xdg`D_1Be<@(OZf#2~8do)>-fZ+eFI)`GyM7L8CB5VBC8 zP>-b=iwE0STrHArCE(R>gc-Ro{82XMA{9{6LM!yP+xntDdSHBCe9`{g&@!QuChV`Xa#o;Yx?)=*o6e8E+OU9OMFn>r#y+37eYW7#qAdIud;Ox5FU%m^9XHx9rr;bY4VPPalq-K8uxYEm+sS5^>95 z0|wKwCN40V%@ti^s(aZm%Kah&6w~m-pFfWu{^A9=zN@ZZJGpaqVT=i7M11}SKYI?( zzWi(KCTtJvy90OKb}KfmTZ352QqW1R0_s$)nakx>j_RK4fGg%_(AD0ho4ra`a|qY& z9b2MD@4H(K3(pJGnU$W5Vut3J8e&0&f640~^4bejSj~fqmJeqtmMCn1Wm#%+I*wDZ zQ5PVdqCTTXk?DILS{fU0`z^boXJ0y~dA^T>Zy&*q%^R@)uG`?}a@Rc^vIF9liTc`< zau8`;rAb~Sjcu7GbVG;uik?d0*RQ>S|Ngh%XY=}~O{FJk{7Kd+y*F>$c;nrpICS)V ztZHk;$M4vKd+)p*dvD%F_lp%_n%vkFJYh6>odqV7d7eId0l)h7TgVaKhPoO&ao}F9 zwWUdcI(|*!s-P({5~4w^3iGR%#r= z(wv;kxM}-l?ZlaL5Qi%i96a;f%h{()iK zvU5AvOTu--tB#;egjHO8vQn#c<8ki&5}teMAcjXq)%E-C-W%Pvd%I@a&ZMW8ur$Ne z)eMlhi~3{gPpHCt4oGT}OeRrVTRY?WER|TYu$4n+6G%~SfV;)1-=rQYccT2?qr0Wq zsCV4DE4tF%tGWDs;c^##@Y7%7pZ&&Dh|@6~$5l-!j^_IweoPpT9zUhrzz=+cL8zMf z+I@+m{p6P~;YZK@lHZFiJ~%SM_oe2w5#JB!m==ELi=V~seeEk~tg9W%QEI8+=M>Sb z;y$Hi^K`2qnAp7XO#trcA7qX%p{H*^J-=ebm>WY9f9la2F3#ns>{l_1g9= z8`zK`Vub3@(GT#_>+i6s4CQ79yUR38Jpam@c?$vvAiRrIn|i4m^HShxKDzh ze)7S4v97%x$4{R@@4x^dF)<%6&*pMSCgS+kZ+!{>_PhTAE8ALN6SQ(@%r%U{iNlL2 z35*eQ9M4UH`Q~jK-~aLR93H2k^T%{D89nvr{b*}$)Ew8H1T^Bs^$gyej_YbOB_vv@ zKce=|=a2-jQy(l@1>w4I_aXtRspMDolJ^C{yv>7OPjS#GifpTljrCn&e!dW65&zyJZ?Gw~lzhp1+L0{`((cl-Ck;<8tV_M#vnT?C4bYu35PP&5iYJW;QSP zW804Ue(SEC=o=iu@iS-njIK1(kh)}Zd9JYofA-zq$0PTBoZ!03t;!(EFc5g2dG;l| z{KjGBQss99VSqFnc*o`qsH>^rK!~f~e(~Z#{OGwCd9SV@-MoHH^yQ~Nsnw=a@O*#D zd<+(BI3I-P20Sf@B9>sn@Yq5PQSZpBXLC>nUAd*D1@Uq9T~4tqU@M1T;eh86cTj&p zHIH3kbHu|u%+Q(O0D@g}V}o|7yEhsf8qws?`v!;6-P?ylM?XXtKNFKQf;5RZVdupw zIDPg4MhQkLkw6n66KDm-ruur^ap!HwjAZcMhbI-J1{+?@Z#BiQb-PG`q zefT$j^n3Uip>+xc<&xzgB{>Oj|3J|GKT6;d*vInY--E*$96Q;8-hm;4Y2kxY9r)fe zVf?TL5{UwZOU?WV1pRK8P%u3o8yor7-Jm-BT)zs{#+xZOm(OP!s~K}j8JI1H9+ zEF0LQS!9A=cXacMdg?z>cVVoXHN{sdu7r#jB7em4yrSGxP?a@mr5 zOdjGC(k%T$BlwVweDuRpAhdj&j>h_0Hot+|R0_B6xdp=n?&yanl$!*6rwkcCm?)3G zL-%Ov9GKJ8`_xeI!|+tU8#!KN7}wZZDe9=z)XUV! zOb$x+Bd#`nNG!KlHknJKrqgLSoT@U-s}RxzU!xwl&NiZwCJC1fxNY-#?WS#;aO8uN zNG9USoo3oF;th zUdpZPTqbK?upMk%yE=OO;r*H=@38HP1COjly;(oZIe~8K6({3;)OV;qr*bpv0lgaM zzG$&*U@M0}CzD>9VxF;=`a0Dx{-UhPexct46I^ZVcTRP2usd(N85b^hM?)hcS|T2w z)r+NBEjGPnCOJ5Kyh~`0ojilpE81}L&aJp>?=ASoSAPQr_bCvS;Zf;C#T*S@6F6kj z%kYtP#yhL5KR~AvM|8ajCwLY z-4BLU`E^#Q{%=$NccmMvaMnvAmK|);TmqYD9#N0tLGPOE$4cW^j@{+E+gG;X{(XC+ z=U#qYoIn#O=C&ULwS>+m#234|aq&tw4!(T^H*MRDjq6s^(Lx05+yvcIIcTZxLjEDw z<-L~0V;pP9h)u5}ol4^McizLRZ@sI27k8X#(+W_w<0^Q+_~fJ7$8Oq+e8EQ1ORF3TX*l! zT+ff5fBALIBY@J-bBVH3rIHB+L?)Xfa7XdR;rGYx(b>GJ*{6Ehnr$6yvwEvEeX^!ivJy)uUxSG7Vd(?*)L`KY*5o{8>seeU%hw7co z)so2+YHMpsbzi=*EMbdr;#!>Owr$V2iN-|>ilDVk`m1zJ=oeKXf*@j(N7|ixc5ANd zMlZkq4zF>dv$5wI#jR+{QDk3N_olItqjBzaHGDtdFW2W9xsifQK%7mDWIfSi_wS27 z@!&mLP;%DkLTBAFb`bVveQ`K#7TcCd@ig@w^%qjwYvC_Lx7=e{!d9N-@+s49mIrYs z_2g7P%Ha|k_?+gkxIS5bk1^?cK1|ER$M4(&pY*-_`rCqpX3hh+@p+URZF;Y*PK4ZS z!Etc+o|_}Onr5=T;%YMqF|yul5a!*`u#8#fnxMW;9j2a@3v#BZR1%Gijk6vYOEvVx zPGCNfOeT>?BxdtSEA_inQ>B}vReV1r$kQCK0Ou=L(e~eUn|{}Awc(g5FV|4manX+C+Va+FZV%X*x{Pyk_Vu-&oeLNytGM zGjkHz>wfB!74IS}x*3BT=>*A}(LoDvhN0uYeRpejd~8=lXN-J5SnSfwD)P3A_O@31 z=4T(r+V)kj3EoVDfT2I+=Ic&gP#}N%`_oaI^8T>|xXO;`E!r!PHUTLg^r< z4z8n{@HG>j=goMkdY%uH(BJ>@JG7g3ZiPqK0)o5LLw0A=!D`bfaWp#HdgKdv%(Tq~ zG%tw4u8hz9MtT)Y=LsRSN<@E&dVjxBuN;}BTdz`1l~A><2B9Kc@2C&Q548&QpKaW%>&9QO zZU^{x9c3(bxvCK#3D_j0q2uwm0&kM|0=0J*i$OOn_+b&A*$!-RhlaXZJbvI_Y+k<> zw&P%_@fHRl^K!BO&Rg-+V-KkM`5Y{>34?GI{3zJGoME}4E`_v{XOa% z)K)5u>bU2k#771;37M>hVO$GbJN0F%VW#Uu(m95SNVkwL6y}tR?uzX4H%rv{;fZWg`qj1@de|9ImywiO%sL z)~sq%-S%_NStnxK8+!To4! zX@c$8i&qyEL2GQN$Csb_1h#Bkhr%2{E7y3~4ltMt7OaVU-&ZbtO{A#<)W4_xC-q;c zZ&16j#NF;A3tKD}Gx_I}Jgf)ivW6V8L1zmiy)^mfMw_f-J1*9(S%t?B+^d|fP_R`a z`F;RjCODl_DVSX1tg_C0<+vW}V&Mx<9Kfx+wla?b*N)}{t*qCV4Pg5rj4IojR+?-w z=*EAaBn@%9FH`>!SHb%XmZ;mAi=9A~LxxA3+D1LeL;4y&lXF^$&7>1H7^Z@)wl-3S zKFOq=5pb^O(n;3hk^A@I#n%ogw={H}Fh>fysn(Tu3T&QVY`jYExONS7t<;qQmAvn% zM<2j_ci*PK6Ts)>*nEbJVblrdID%#tGLU5Nx<0KZ)KPa(d#R_W)K zraGhesK6#b$uyIKKg|Z+&t`7rL8Y`gbrTe9nr@P{7@aB4#tdMY=A2-YkY;xr4_h~` zLn4vD;NY-oe!*c3wn8onc6hvUkHUW?FZla#cxpQ{SOpqJBWVP4!at!ev}JmNRUUy8yP8IzT;6 zZKskvAYGhezM;|8#NFIN1}+;}V4F{!3YLIs$1>8b9TN$=_hPYjt+FR1ssb5nsQio84Fu!oS zxEjj^HYwOPYCnpQ31Hhx*T;e$p$*Qylk~=w$xyg(@3G{Vvm+2f45Oqr3c3!PSrvV*^I*w*zz`P$3cRS%#$_sxU3@% zR~;9=rig6n7@cz=LQ?ezS%JT1=THSVBV*`bYM$Ut<*i#)1^&|t0iZ%i065nwgHOAH~&!8)pQta zjwr_lvmMmehN{WtGh}75$1GDdoy(k!DmIcdra{;eTzmfQaec@%v;%=HWZp9aetQhwnLp+h-P)Hz7NiF2M+%H4396=xs8kAgd!9)6O1GSzyK>Y!VZucYV zJt{-Fb6tEfVH2m4X|j`gq@?W>tpl^GtV~ZHh$k*lCD4k&?l5#{R!SYVW4naIrz^!& z6U=8>UDwn)`Fy_0Wi76q;@Z(d&?dDeY_31Ovnf{#e2k0?%QqMVO@@K%IIN|O>}W>a zqto%sm_@fU(bU|E`i4dYoctCBfpW%}WzB2A&32bm4Rs5(3q`kkjd~76_%2X`vt4vC zU~8gwQ+H4gQu|8R<`o_xPzN;4eY#gV zU46Z}NA?m@^BQdP4?|L-K1n@Bou*!)UZ9Rp=O}L`3*9K#Bw?8lcT@LJAE!29whlH) z6sKnZpCG92s?f9sC+BEp1a_f-=9U)K00PXEq1I!PRstFuM+-dUas_qxEzON|k2pfi z4LEs3fUqcm*r+0GvZlBM7Qopg%bZI9!phE8ge7FXht=800H_pl7M2x*P3Xk!)9G4X zmD)yXklsL7tC%LWy`(QuhpD%yUr}#U1C<_LNZ8~k+E9e6>|k4{`f9#J9R?3G5?8Bm z`qF&4To$KKok$`-O=I>s%^;-2wiklt2CD);s!oMGMn^LuO4k zG4n=1zQb@KndkfQhTWuDzTtjEV)`( z!PN|cX4^JFJAvWBA@yDEb=U-FPM;u%1{xZh)PYVmH5J5kH9f|y6f$E?CX+klGkyI- z2>bwzjrGt4xLHhI(tb#-;{{p*}x0j+5UG%GRAl8S%I z;R`T>!x{K&h-Lz3n6q;ffjv$qa$INL^^jb2Lq{wYQ_x3MuD6uVBWwjvhFj%(^K>V> zP?*~ND!fF7Savjn+PeDUPzwdPfcvsAi&?gqAq+H9ccN%K-=uyu7uclhZl?BApDZm{ zf1`IJ&+4b9uf0!z%Vx7Ueewi$+;kIaYHHP*6N9JA$!x}x z>iH;=_ZbuNkR~6=j1ss2Elmx@reI#v^@W0i&6G^UnMbbZqVsS!X+)E-B@?j)X-aXk zAdD1n+7u9J0tai9$&4sK48xf9d!z=rT$bnOu$FPPPH_-wrD?ZpLJ}6n)=*!W4Q#d4 z-PB_!y4bGLLN|T~JPc{0Dh4_z(-u3t6p^4i&4UNuHbb0bm&NSbaYO&^cPlq34CKWihnHc!K_kmPz% z6={=|%+hv;@}UB*(%BSp1>`uy<~lg!Imfn<&*fN~gsP$E`BmN1B1B;(uryH*QlF*n zqBdb(EiwO)l9!8r?Sbk#o7VTx(QyjhSFTh94W)xM2;5+QKhEf<6mZ39>QA%`-9)@~ z12ij+LSH8$zC$yvmQSri*|vk;-T^c>H=rh+;xCnflRcOOEgp-(bG<1YW5!UJmRhe` zA=y|4hZ_Mq*XQEwfUDl4Pm-ppGxw7j8Rq%8b8@xvIw6NvZZw1XhDM&LRyvPm4cnB? zB-b0MPg7r{_E4>h4H?R==KBbI_j=F_UAa!jnUmjhsr_kL2zc5M$4b>du*AmeB2Zj`|jSY3vHc29GDd58} zm{)z|Jz5n`i*t+lYPc}up`+hL#tvW-vZ-oXe6Nm?ks-RfJyy^8?89|kjp|QW zXSVez*bW@m<6737))?<*X9?NGVV9+4e#X=}mG{-#+lBt#o>>pNsrC|bP-RCmsBdgi z=Nkm#tT8Ot5ZDB;$EiO&Thz?UeOv5Mw(%E?y7tWto*XJ`;%g>+h?1Vx0 zTDxw&x;_y&{>Oti5;aBOde6cg>E%UE_i^to=Qx}hML@@DX=*?$W~nKC&0CdIOH)VU z5OdC5C#()evw76lrZFkk6+)bg8Q@CB$LT&7LwODry?DJ+tsKWeUr!f?2K&`s=Id(X z%7Q{650_3EPbA<6^K<>h4uS1|P#YFIk?CSGS1TT>hD#SZl^Y2Kx;V@{L)Hy=u;vcD`YLtb&=!R3N|%p zqpGccqeCjQYO#};NlbLLA`l{htn=Jiu^t6RwL;bsxX*T+L2plw`aW3$M|3O!JlVPt z$rYPaPEqJzcb{C(=WX=#4j`M)D@QJ`C+*`Al4>-Pte7hlxE}MG0dPjixq3!@9KK|u zgO2705zGpp$zCM)!GV5UI^U^4Gt{-}fmQ}uhL@}#a!|>jUCywHvpH0Ju@k8jWml8w zufCTKTR=NU7~}w|30gS}!&H;CaHrgSrLT#sO#8+37Q zz=caUGn6|`KZN>vyD`w$%iOCwXFC=Qv~tM7Iy~qzr%qyIXh?mZtYG4};&QRNHl*6O!%Ws73jCsNjSF!F znb3WGLl_zw;m@4j{3p(aYB(E7aU7Sx6{b8`oj{434dw$JzHH-UudSdHH=7DHSy$>@ zDCBYJLMQrrd(`!Xto_w`xya>46=))Do&#yIqPo7n03n5y0?Ra&!V73U1nunU(+GKe zp$}WaAYj>SRsomer+lA0hz)bH(oF^Z7K64lu z&0g1(^35V-;-qH>JiK$UfbNW^9L}iF36ifkOlD*l7tfzVW_U$+oy-bK*PoIVB5_n^-MG+9?5o@rQ?rJC*3$rEb2n-zcy12%A?Mmb!p zeg!WD%K65JG>o*&@JI%I{euWNOr)Xb8^v`sjArw!k*}aAyO}|a*dgA#V&j7@8@3-J zR>94R&l#%0`+K{UquGT*aoF6zhL^h7c^mm$PUUj#@LDdhq+yfB5l52(o0f_GzCN5i zb6UYSTSqIy<$0cZUcL)3;Vc}*AaKJ&gE&p#9NVb?obbg)w-QLL+JZ#$S_ME92G{LR z{Kj#L`BbZY4cgRbu7Esq)cH3V<3524!*sJt1zh5%rbWu-Dpa5An5>n9uFDtEbLBGY z=g+$C)d;Cmz}n?TGdw@PSgU2|ZsuYqP$|MF`v2Q254JY4EDe8^gCf{CfCI@u_w4`w z6Z7oO&a*w!#^8W4Ae5yl#Y%h5kz~^*NWyMQp03Znk5H+?t$WXVURhk;;99jxMmxlC zaCebU!W+VaVTuVdzK3bsa2yA@d>+N(3S8F}OY*&ExhHS$Xf74JJwC+l-hmkJHbXL8 zimJnYv;|c+(XV`@`2=$8I&|MNiZm3j(?v0tK|r7#mistq1hS^OHnM7RM{%>!e7`M_ zbvnKnl8-GaJl~G*q1)}y-W3)$k8jD+!X{QD3vsx(-;hoEz21#bFjS*Y?%)v>c?^xt zGffMbYzEnE4tWABUns&R*eu(UuFc@6s*3;d{ywuUd0u?&WvL`{+1}lgB8Yu> z1X!!jpfGUd_lSc2HQ>JQ+JQ_EqwRH|Jb8#qFZ=@9oi^jCsI$217aHP}HcgwJl%`sSPu7bej zI3u_i)Fg=o0EQ~LsSVPxn4Yz{y^Ut0j`OomFy-3mnZR{=@|Mq|IX<;qPqzD;)hGAlNZy)V;3ta+xV$f;fV&v;jKD>u!7+BwU2IY!vuZMvPp;{BDa5E@xax%D0R zS*=zB<%=@{jvJfyhvzOT+_;h}>pA*6K*#rh$B!31y}7e=u<_>CYc;$(KB59q@p5xh z;3^i$2pN~avIq|2bCE=GL?Z8pd#359}f%{|^s_7u<)CdQ92QKn)(@>Pr^_nt*NTug!`UnDT43;tmQ^1h_ zV;j-mIvw*P0~bA=&Wdi7=Vb1+$|b6mvdo*C+9EQ6DxtOKhRKbF=fZn!S{60d42>++ zKn4#UJpAdb##t)ZxM-qrH+w~<$>s87E=Nqmzj0~tW-tujbFn9zyz%@w>h&s4KYpa5 zRmOIi9w}O~>ANEaPRH8XBbnbc;1ss?+9tH(LuA4_ZAK`-@rzF282Jq|n}(k`InxUb z!b~M#lN;we7z|LpJV&!$=L-esAC(DQlXc?xFjy9W<+v_f8kua4Y9I&OwqemQ3{%!2 z9@oInmZgGiQk*NRt56v(F0d;b@@Iyh!JECayN70@0pIrp@>!$NxkD=6w?}WF6GW?I z%5bXTVxcNBvgpw@E&*r6gVB4Bk(pdQPjRsoyP*z0)CjfYT0>*|`M!tCi!*dPJ{?oV zsNX*f)R%XS$AGb!8El4#P31T)vIJE=PtDbK$NJ%rE?62Lpe69HD|TeWME=s8f>ggCJQ&4AzS4~ z#v;fZ$AM{@a_$7iQG<>D(18CFvXrnbD!i?1xbQ0J#-dBz%YVHIZFq4~^j8-}YB8t@|>s`91a*Ww4sfIxb7+==XY3_|r^1fhvw8Br$3_`3vc!*6h+~M#4mZFt{oFfysPEStAIy#=ccqvA?tAHa#7vRh!ntFe>+91}^ z>;vWMIqH=XhQpzliUG38QVbZ|%VntKxC4zWtB&6#BHQx76zitBe^S_{WCFzI);5~; zIxa5GVay2|hl`p`dGh`}*~P%q^$jWRn}8dcN=2YrFygL!!!34G#&4H?_pw$_oJPz$wkJcy_m5Ms79Mrc z6ZlyY1_4%9A7E#9PjqsVk!A@SCKwKJbod&zT2%mKD6S_#r09qhprY`go0 zuWz?o1l((MyPfO65j&A$Ay%$~Xb|+3W)Gh#ZDcd9T${uxY|ES!wtIvDd$PWPXD?oe z?Y_k*8bQ;j*YNh}2!p}k55Osi5kW_w*aY5}XK19gD2l~u{b2~#bzm3<;v`=5(xkZ~ zDQx!$1Evxr+dHqYva(8$^yS!nq7XP50amS)@$T&rf*^#dUfC7}2viG+^5vMSDJV6& zC^b5Ct^&(;#%4=lTjr#&-7{ejAd|^p|Ce9z@Zp*OG8_&GmVm4i&IO+UNAQ-;&++c~ zjhON?a3r))F%c`8e9;K5AdK*#)W#r)=(`Hrvg96VmOJ{QC-5^TiXyB%dW=G01+7+d zG@1?go`-I?EATNiJSH&Q1_dAI^DfTLpc^{2$eR2;B4{ImEmSPnNdSdlE7f`^x4NJ| z2{uj4mS*{r!uAbe14U5`!!+>d$rBlDyuqN4cDs#slL2hO?|2yW`Uu02pqc=u$mdn~ z7_ON9eL6jbp&NMqVpGf&CS)_!f(rteY<6U%O$y_BnlGAkfKOiChbTfDOq$PDn@K4aR5P%9NSP3D6;7&uoDFN z$O8!Skskv=eiA1Rg4l2j=OY2)z)@l=q6Lbi`I04Cd@f~*79U!^R@6Rbrn~Fr-0Gg; zaNm#Fsh&|E@@&;~S6AJty5}CX>chLJso{C#EnP~gP#_K?Qd$!kgBMJ!6#9&3o^4s7 z?`h&l#`(m|L{S*eqdZbF9^c^wG3JoDsx7{e=dzx(3N1#(^UE`eKb7~4IXS|2e!Q;C z8^?mUu)duKgO#W3II`i+3)QVDqi1qRs0+;*u>{j-M_?Xw~?HMe8b6}IN7s&Q-K{!)tIZ# zFkbn7d=3IRXNfoGlgj5^XIK5w)O7$01$G@kh72`mS)pafkS4UO(3I-{GGwSh%L*++ zhBTpNg~qM}$dI81zUu%o%oqhrMP;-_*TH0%9a`4WS_TYnW>)CkhxSvj>JOl=T!)om zcE}tp%}}(Q3~%Hx`VjgLp?^0sUxxDbAL1 z?)3=VYrTEW5Yg-arxUm1)lk%S2yPHOO`h5ViM@>X$H75x)b+;S&&Y(f&=5cItQGZu zeQ>Hx5XGYq*EVC!2K2jR1l9P}JOHQTm0%wmE4tle-HrF+**^47ftSG%*T?dHLngEZ zg<49A@8t;MBHl(3Z-sMhCN>=na7`cL>P5Q~>+WR3H@LTi6Ee{+QAAHcc;~@G;6A)R0-gpVkX;Ac zD#(O3TPT1zkKQ7r;YK9vV;lsJLR{32i!5Yr2AfxCc(Pks&TB2Rk6H`|*1bUgi^LYi9TmTQ6Fn6p$x5cDkeZ z{UUf6yZ{b@#&xjGhL#nYWIfM+nnjps6$G^bg4#hQdXNo&C=r)x0dY+R4R%6oBDf7W z$0s4UpW)el{C*kjYv9kpt5la`Zhf?@(B^deDse6(7bdu$qv#hYGFu_EO?b8hoKq~3 zVSLK7R;8@wDYYPSw)4(#D44frLWFbSry;ttIFlm?>;T20J4vzVGE9P&71}HvtrOe~ zVQqn1Z38#Mx$Z^VGoKhLLh0#hqnz*0PW{+`h_e)g5UN3L*U6)07EB}a^4toCh;AcA zAkl9ku(vSJ3G@$v2fn<9lIW2H*BgOV%{QxrYQCfo#JtwIv@)GG!9 zfpoUF)2=O>Y3-`zRxq>C3Vg6Cw0hZ^=ykYQqW{=;lx~iUCIX%_I;`k~L?6dwmr$Ti zp}!aXSI~+8ugg)?tx7a0T2^S|ps0YWUWDqq4((1Zm$q|c9)KE_AW^#NmdRt_d5V@V z?xuVDmQffP*Qa2G_3rQp99G-Ruj8ggbZar`TJ(1^8xdGP7W@&~A5tv3VX)}>3|ydP zg{JV2W7p~>!)qY0on)eITrO|LZxNU5-CO7w0yxqL93+Cs#Nk|*bq_)lhvbC~L`2tt z_D;0h(S8|%JA!r}_zI5YBo5*l`lF7IqhV-8p~(fWMn&B~h9D}ljg8p~F2$uw0bda3 znh;niL{bM)pa+tvws5Z<0yF7A-Y%5e+B$8_$K&sYH`uEiqP7?^+==p zI1IN#Tw7ov8zHXcE`w5V4-r`ju9m^V1D8Q`yU+?RL;0sTGU9go!DC=Q7`YC#-e?7( zZK5!ImPu{Lh22eTR^TFC$8-ybMTBM~CI~N8vAM@eoX1KO#m8_qm&l6Dy4?Yah4&UU z+=LefzPZl&>F0|BGP3bwKq%GYjp5 z;P2y779)#^qR@3blYnDKV-s6khUuYEL$%JM_Z0YRuEVJZnpJ4M;8!RXn+1nKY#%8^ zDRHz6Gk{X0a(?C4UEr6%4X(qQFPc$k67y%kPgAW&M2V}Z^x1}WG`OzHENyC_P%6(O zC60Cr+rekRF4y7B2hAunIr!Z)_TX_zTrQ(EuHzdU7M02Y94%dOr4mvkeSd7R%!8i; zcTscZt3|T~eh2tf@V*J(MiFrsxsLHRK>kz;LpU0{4ki77lPM9}c*wo~0l3C>h;v0V z2~BR`^AuM$HQ@-c4D|T!)f+C|@HZ)nu=CfWHfNx{h-$XeOcUq*!QO zQ;rG)>uhO(!oSEEh%KT?Qz!#6(Ich(sYb}lXDBYTO^0R?+TGxn!Hv_7L{f8#Tn&b1 zMOF+#V%Nc>7}m}7wCT7U{0g|nb-c4hGYG96{4Dq@GyXz^X3~<@;%E`XmLBn^4pNP# zcC%ZDN%Szd8|-u)_H2-Lp-Fr@!7qYsGyV#R%~3iM+Y?8N43&a(#FI*BO$wYL^59e8 zCtQa;8>C%mcY=QeuAbFb#vr=`B2I&=!Opf71(216Iy znhI$Vn%wu3;2(qSb)T6HDc{F#wNtS%68+-!K{|is8WnOmTCt>?^1ikLSSWaKFzso& zF*Hp3PMoFhA9{^Wy?vQjx$}6r3tRZ=YwNgRS`D5BPdM7zq)3aa zIfRJK18)qC(3_VBXrvTav30k%SrOJ7zV_gx5gj{s0RnrS_Mhmd!Ql}+*Um&{&mj*t zTbQD^DB%I{hQlq6LmGs(4E#&*aazD4%La)I7g5S{y{!r+*x1W;?P?W>7{tW}2H&Hzmj93HWP_8hxd6^O$VH(U7g zUkvtvFM&5*Z(HC}Xe+@#1s`w7YI3>a6jIrBI$W({=^_RZ$@#0->FujGXmMvdEnC!O z#WS6|$r#z1IOCpUr|A2KU#GVQuG;TJU}(i>SSjL!T!c?`zMx;nDuL=)VrWPKW!? zQL!8(;!D^5WN)gi(8#znxDGrHo_4)`7ebShegyn0a8;vMW`m@K&=is}ZLsd3oUDOvR>2~0CAb&7 z;d1{jgw{u~$aXY-yP`C=V^FI;@ ztK6L(R9gXsEuZYh8U6=+9z5-0@kV-i8~8NER_+v%qg)PbwOt56#x$3wYGFDGQm#px4=#pi~9{+3z$!Kge&c@%kQMZ)&C^p)*T zwEr2)&_{}SjjZRBq5$4Sals#M^x};aS_pm%{3!S-YOI@%gCq)<%j1N`V}w-6t%_LU z^s8|tO2ktmpx7m9e2rrlwa?UTvP=gMm*}1mlBscH5nBWSnnZ}E+E2zL?S!W%6N;1h z+V$=#I0=3iyyjx@MhZ=E1^gQL0Cc> zQ|WLsaj1(N1(KvRa{vK)6OcF{vV$ zq<>30DqTXF4%Mxw@dp*l?>6VFh>>w_@o$JPiicOk7eQdApecY*V*xrnl0D$J!Lq9W zTnMcQ{ww$~@Ru94Xyu}%zUJ_!&G#&|b($z1l( z&SxUgkH+5~sH_bRrjjbkH7=JS9f+?Y7M%~#`C*wnw1b6i3Ot>>nHLQBE$}7Rd#%88 zyuO_Icfl7aKAbs2E~g!K)}D(+mT9XwP$`7@D5S3Ph;_R<+}i>0pTPHA@2>*aLK9pA z{}wzqpGm~cI`c4SRfl?*!3jFT5_JZ}Bq`^7kCIP+51w+ppIW3rXacD~{|J`m^fgLg zyYErn*RJ=GVV>v;MyU;ABRHFd6waAzPR#J%!0&;^^zpHVQ*~zXJ9=QXmPnCZ)Yv!HEK|fZqha0iJdp|3pZW(B!~g z1fK=J3O)vQPGn(hObwYlzus1+s*M^GpqgsDjIjUtR;(4w3_Bv z=LVksgr@$M=f1Y8T|c?&${8|f#in(jeE%SxNrC0e%+z9f}=J z+oTl-lLN0Dx&`B$J@UYrLRAx9-Ih{uUWigmHBsal+m^9xgx0`CBYW}jZ>Gq^zoRg) z&!m;#VHDc2Q6#^ad_Nag<_Vy+PadlEMDXxV+jnEr8+-S({dOV^+jE&@P7$umdwWLT zIv)@7Do>3U8y-k3b{{;kLMlZ=*1vVuHRn4GJlWS|FXIc5^SwYp_#J9jf2XuQhc{-b zLgpIt659W>SLQLYZP!`<&Qz!7>bd*Q^YG^R#m;+n^ej6jv11d0tVH0Di6IEYUr2zE zjD!V5NI^;hL7-S95JE`63XZYmc);}UH;e$#z-e0RP*ch_8J?ykN) z)a~+Jeb+sw&e>=0wf9=T_3e;JCT`JxlLz`OUjH78^`{Bh=vp08C38JBPzi{}L_m0O zojP3CiNFaWfCD}cn!tp7CZNOsDbNJ;a7j&L(BkWMsL0*v$J+Z=poMF{>!_4`B%nbx zuhkz%5OxABjG$NGYe?8hq|#Z~sWdDrsn*l^T?|~fuHuDj?YlvLk^VdMuh6U8eAqi; z_abP@m;|Zb@6ykOo+rTlGW}V)wQ{VKgRZwFg-KR_yv7P7U^VJB)N2*gt0j6F9zhdu zlu9-`W!&Lgiq-~Bt0=YQ#V_l$cka6dV<$|S%9_RovSyL5!$7!hGtuG{sCxk~kxao( zrU_jRNdb@dX2NbNag?KWwbR>HSaFh<>HnSn2lNZQKHJUMJquc!Ezmzl|1SM+(0`GB zpnZTeUe%%5X=8V3ieA4Fcvkjiy=!Eg+Yx;u1(&3)sDF%NxKZ6ja+DeGPmM z)pAk!qCN$~w2&ZViDU+;Ojd!HOl4qNcBGWDv>&cqqelNK{dei#px1kSuA8;J0GgOI zx3}p3ivA+~*XbXoCnX^|v*QvXr%^+#Ql>8|<#J=NT58qowz}Ty{ru>dG{6?@Aw|@I z$GlW4B^2lQPQbI1unAi_lOue2SX4aSu;Ll6)Bh9w59wEWy`8&0hJ8=}WUpiBXe~HI zpYK2=`)Ye#m-^J&@+2neYg!4aT^flak5=?_ z{+q0W-{in=V+|G4Qb}lr(SrJ3H6yqGM6YAm(83^C`KV0)K2P>Lyk?#9+_8FT)>h-> zu<2UU@8!e)k+-%yY0W(Oz6aN7xMqI%KNz9($g~2`D)i!OdI?_5n?!vV8ulCB(kRoULhP!O5l5gFB zJ$i`y&|&6=kQkiUGh4d%LDMyu*<|xTeZnScrnMD~ru)9D@9K$%cTx1=YG7KA@1ikx z)6AvkgdLD;f4`!WtqYG$N!aAt2Jb?iZy`JsDW-R@1$SOG>p z56!ltpN7`4M>of&v|1&()q`$*&TF`Gjj$``?h2Tlw2h8r^?R-3&yIX)omEr8yB$Dk zYfPdUYWkpFMWa@MUn@Z~Ef}dRGH0Gz`@0^SshRf>Ys|csOhV6QsAPI~ho>yE{rq$NjTi6!J=E_FfUgZhb=^q_cU0cS8rc!u!hpI{byVz||E35VW z@*=$A>^5zD`^_{*M|vH@GK-S5nMw&gUDrJ++^{Y4VW(mVn`1Vcdlr7!iB_(uHK%LE zt*$!zgciXhV_0!=ubj_y!{mECa>G#1gD^lC1PZdy_to^FdKTZS?$Ekd5e3bw{BFi5 zb-gOuWl)4`D_Gm}tq4QhCqh4NDB;r4XdCshl4qHQbo&05$hv~EA>pfW2#lqL~XZo74x_HdQbDymxHMv5D@RCY;GL%2=@janT} zqXy4)n;^GA*S76g`Pkq}2#l`=9&WDLrS_ni3p3Nbj$x}7uyej1!kE+G?OS@>EJEf} z;4xTPmTeveQHVP>xb*d}vzP5-uT+276%4Sdru_0Q?Le)2wK_r6JvT*p<) zrt5|%pRY*lGc)_8f20dJ7^VR;VO^w>y~6~a>~&1{ZDaF1AGK=L3xeQc!cKjiu>A>h zSM7CN+ihl+1=F=%c+3=Dw|MqFSb=!w!OBE0rAN&-s7$OCJaR*2j7s z+O}IC$=NcS3`5)r!${)p+dXKc%nt(iet-~RE(pT`IwWV3wSIH6Qg?cNuZ^4oJcbK1%gErkynNH~!Ag_Bw{0usPGv|6;CG z`Q-op%h!%wx-|{{hNj&IuGc1tf$`_i}Z&DYMO;d(Ii`@r?e{2)+g{}Yd%!aw@C7x3uu1AG<=d@f&? zdmZ0Sn(2Fe+ek{xY4wRyhw#~nPvB4f@)i8?H(tio$ysRp6NS5PyJs%zER(eH$>$%# zuYLS^92yybPh}H@qcxh|w`PXDj$r4kh!7=@2`*$)_?4gfaXfN#KYsr!-^F*{zJgM< z4$IJ>Q{jO73b#`x9J!u{iQxi%=_lWZPkrcVqLJ85RG1K2@Zq|eKZ zbWV-(_Wp;ChtA5?_Dk z27Y*L3fCs*aO2K2ip3I~S`{HXuu0Z*y$RlZ>&gP2v4AC(FiqrANj!V@DE{`xp2riX z4j~Kz_(Al(&4{FetlsPRchdS9G_h&ALr=sHJl|LF93INz(?5O|m1j<&SZ!dcRK=yq z1-yM@8kcWP9dXAp#n z2BAtCjb$20S{5dT3OG1AfKvy@@W9~-933CRIG<%RDOiM0jzhlhpkkdAE$sDPchdR^ zv?KIK=x@-kAxhjly+O}*`XFk^QCE)htkZJ|6NS+{&WsP>!;c&#Odxb6yng8#zWkln z@Z#(5qS|ngN+w}hHasujZwHR+sltkZQ~wKq&Gljq)f4&G8mG11_1Y9vY#wrz6A`FV z$pnV7X+o685yB*3ouFzRp?ZxE<&d%yQKR8_flAF0bj^)VpX>F$ciQ>|G*PU-Pybc= zcj%v||6lqodTrCQv1kkym=w$O>^v@9yM;I2y@XfazJPbGT!*_*f}!iM$nUYS1K2-4 zj&wQ$pO97S4$9R!9M4lQx}J|ZukyRXcT&Wnrb<;+Q3g?QHamaV!@h1%g^~#i`BVhe z!O=k+B}~WnkKpjcFb<6jU?iVGf@-E4I>8E~b|PJZXXX0-W&n##Kr7+CqU{O$0R89a z!}O2SpQC@2ezn^@N;fu46Rb59D^;9-?$rYhhU|WaQpzZYE7wJ-SObMzEVAp#aJSUHO^J8)fI&0S_2J^ zEAko=HncQw_e`ohm$Gqe-!Q=%#lGPJCI<8BnQfT}2~!jsqhpf^xW8(>jvJFRsu9@) z^v51Ki+m=fn#(3k22bw#hIiSt+7JG$*D-9>M(Dpq|AiILrFNuKrm+ERI*Ulu(yMLgJ`~EefX7SDGl2ba4T2YKpaFQlJp2q>V%4 zqj=`Q(@5G0yng;NF0rF8R;pAcU%@5?*1kfdR*_1Xod3YsFdjd90v~wt5j=G2C?|{ zU?88tCqMKYe&J&u!r_TA)l~d0_9)Y}F-UI*<{^v^Njnc2BT%*-rA z9hMoB;!UM&96T__VmCW>Rnssqy|9SS{>T4@FMs=G{?-*d0?uGAi&KXWD8L>&eH^2M z1vPJpfJs+>{laCuedQXiPtKrPudDeC0Zv;DwRC;~DotpQAKZthA3lR;=x2`|!uZG_ zmCjOyC`GzK_um$i5M_^sVM<3qkqzn=RqE2UoA|+7=kdmcD+(^ztHdMcB;(h!_PAxQ zat=>DbPAvT#7FS_lMgF3m$O~ZT-Q_ISyn4w^Ynj1|8070#}DQ{XlvTf(*KajNkyP7 zLbcpx;svw=`$s#1rhuUT&o6xgzwvv2j7qIe#j>$~WC)L(I)*3DoWSWL2T;gnlrjkf zVp4D>-Ss?75mG72@4fXduHK%)e5u4@@gs%kP?!>f>-kFk3Iti^fBb=yc#{6Wi6a;p z%u`vkR#)F{=w#3FSrp3^T)8!g^H;9pwR0Eo*2VX5gH0oXOO)PJ`&i2&)eh9zC{+}N z?4lA-wb6b)^EAZ{EgDs)K+lM5zL7s+?RCs(?Thso81a>pWs;d=MV4cwWTQ?bU% zm9VVk>owO5361=5H)b4h_l|D;f%))AL^X66@J@bjqG9qb<(!suW@jg>jAgaw;LEr6PY zPuGp6(!|QWLZ#JnO*I6M@rlC9`X2qoSKq?t{_M+2xg6J3ienIDQ4cLvDVZ=_np@Mzs6sZa&PZJD2dK(p-1FE_0R!2rg4FkY1$3PXwNR=kmA_4x7Z*ync=aY8J9`3t zThO9#b8|(M%hgsxDiKgIflc;IJ3;?-`VZ*WdtG#QV|yL65`9W;R(5_#S}J9$qU5Ezw?SBC?-EA@ zmaB@~aXh$=tM((R`Ywz7zxFI7JPQC3mO44ctl zK8O7yL)b@`dr_-|89^-LqdB=pKFg+)3NTSPqX~G>c7EYXnQfY^mFBlAP4XkTYOpzU zdKW7#?G^gMZWq{g*&F)d=#Ll!9q&uz<0l0bU1C$Yqd9B%o92MBRdBvr>Tb zJSBEfG*LEDwOBz{H?Xx$6D3snSpH3{)GHfTii$WqlvjD>?=m9LD%(>wyKj3Pv^xDZ z-8Br|qOICD@X2ZjFVa`Yww)NtG1X>K(eXL?H?#E?{R^NTOPY zC&u71=1Q%Oxnh~n%`5fu{Ak=p#k^LNkf#F7%jYiO+MQ`U_t=99hhj*d$;r#phXzBCh;Y!f$Vg@?ORXWQl|ouXT}r0ejf?I%olX zlIf|%ph;RxUXuh(y5(9$Aq6VQkIHG2iY9aFR8W4eprD7G!eFPDj$f=+sSJUdS&Dc` zZI;wX6?j`Lc@}?xig9Rsgb>qtA#^b|K zA+I3QnvmUXELke4*Xt3)=t zr)^v7ek3(7$uF0ya9wXrWmvLM{nJbfdUg<2ZUD0jMSSCxm$0x{RNqTsCQKcA;3HvZ z7|3NXF+7C8_uw`f1k&lajue#dFBP%Fctl;yy97|yH%&}QlLEUtZq5pBm};<_o)bUKNV;R2?n7no#!9oV!8uuK6)ZU|;7hf=kMul?W+ zyngW-oO&Iz(|6!B>aY?Cj7=Owg4gj89S=P7Job%_VqsX7oaZdyFP9d8@Mo2iC`hHk3D!6 z`CL{hPw3PTREkt?H^#0bWTt6iXfO}UGTRkuSp$FiR;q=mu3oNAP9V`u2+WEHAlHje)TiE{`sI{}ZptK{ zg>nV+#j?6zOF_j`*&K!^4k0@@gje4_kC)zg3k|C2{M-x{7v|s*s9a$P+58}ELZ28t zi06)+j=tw!g6bl?xjP8zm5#9pJOfmxRLWihvUr?M$ZVw2wz{qu`yT!LmaC-4)(@bG zqAjS-$WCZ5X{He=MmI$&NtR-$v-_7y)y{?KyYLsM5wMHv$qYjJ{_!z9^1xYq>!t4_ znawMZ>eUKTnH+SgpG$=t9LQs2XozvhA27WC2z=MY_49AScN)<2&dMfZMbSiw^yZkg z3zcfCEvcE~xrD5w*4Nj7OyV0DoxsG=Qz(p#DFvM={}2mRHUR$3&CX!v&J8vc6E+)$ zH8f1c_b@vzlRdl zurNHvGtrbP=Z8iWv|}S9Y%FJ>b01ETz*QD_CROP|D&n;O5>?yCWc#u&ZFL?bx3AJG zyH-s*Wc>hIgML%4hH2PRNKwMVt|xFBE*cGIoe^5AbBFBgVXXv*(B%l-b0;UL2%dt~ zSB3AX;%Dh2l}y5$d=DX&Nh(NykXeQ^No1^XER@Rh3c+-j!6vsJi(3?LXfRJ@u#^jE z@=m4;IG0bDMU7;v+&2hkz3w2N$)HrNF^;DCaBYJy1(~Q#s~uqp>i_3b0@h zsIy}^EIf1qS8v|ty5rpEab86&b+y)+V@Giy#a?ssqEdDhgw{Np^{mS@NUWlK%wc=( zX6Uc)UMcOI^#f>{JGjtI=FURcD(%vrp3iF>a_;4 zX@Z=zu~@09)zZ8d!17#6ltVQO&uvXZWE9lT93IBw`wM8tCq6~XG~v(RiJFEMpTkCH zwK0e7YU@*_&2U*s-k_gDA6P$trfP|9NI@EguDW|yA1ZYSsb;Rab_LpsrKJ#8sb{zn z%+(fulcwq=3Ee<8joHN#)gvSnd4iIJY3eOSTHm7gs$mcWfkL42Sh%8Y1KBKWDq^In zVaK?X>d7Hm#+vb}PrE!LolQpo7bV>&ey!EGf|akP>9^4b)(@b`9tP-^`W1Hnq2yl* zIhRWjwg&2T=PqE|nn@ALirI7;DZ(W|>7qK);a3;lx+YCVO~!9UDRb$Rg04GQn@1OJ z&z@{MfqXvG+RM78MX&|Is{MxB6H)I??{xs%w1;f_UP7vqbjPsE9Az^pjE)RaSrT0p zi*Ld0a@{ z#w3a+g{yTp9J;O{mrb?65+M_1*|%?46~0cD+lfL}bBZE!eo@uo;Q}nn+(eTI;d_2x zE1KEs0Jg!Bbi4JdnXJGI;5sf0)9894Nw{rW7#|=DSh9uP_m9kMPRn<53x{HB<9MZ`o_tU^) zv4Tpq)>IH|dOz)FC9w%lhd z%@+X8B5>l_Oj-fv5VSfWkwR@W+?Lv{R0qQ_RA(2k(y9;>%euT2(nf_XlLdZw7jcIw zUXO}iE?41l{{o$W76X;0@(3LDTn43b1e}bEz+O_CxY#9BiC@9Ry+nJm)!E2=Dn z*S?wpjNfWhFacHIN^pO1?BQL+w<=!dNEEF#pC}stn%HLOIr=>Ixb*{QSu_=GrAaXf z43bFG+S*pz3rgm-6PEJ$ofNWwVXz3hDa4Jym$yL}D8;;66IB&&hiv7ZaIinrDMA6)LR8@J@CW~LuXZJN>Vl| zL@8QB-&kQ4w1&3j7&n4ijnks_y4~+~m?)Pt!FcXi(Xbr5?O(VDruRC4Et*X~NzY5t z#8wuBB+hfa9VwLMg%}sgh9e`T&^Ipr1QpY=tX-?MXb+uzN7j?vc;0fD`vR-gw%0)u zB|9Ad=v3wcVBiM`f&fhxdumENl%nzI*Hsz~$z(!}+u?u~t~=p#!Fu-OphJVe#PKI|-e9kfyU@z$?3 z@*{~8(C&o_uhk!+j1FK7=){G)sJTOI)E+O z6#XJ1Ws8#3DNlUnyAf!;E;K3p#lasvBFWy?t^xZ+B@`rLI1b($JR@dD2Q};(=vB8nF?$!*Kiyx5U^6Y zLUj!`{3dDJ(Dg{&?#ARh!_bjQr%)# zVRTm1T?Ji)Uw@e1>j1WBl8wKhe};Z;%~4EO5CjUgT{W)jdLHH$inw)a1`G4W4Iz`l z7eG>}1h&e6e4ojrl*>`c{u^}%^NeF^dJeAZ^+e%C%>=YAAUAeBxE(UH7YDrq_62&9 zwe(qb!jqi_NK&PP?p6nvbFEhEn4MeTwV~GS_N)!VP`({zng&Kk22@KbS89kuD3@!{ zwFQih4yrM`rfgi_BjDmI&qP#Ap7F22pO@+1pjUS%u$?v2ZMeNz`Tw)mrcZL5=e6g_ zJ!|j1(bx!(6vS23LQ>Q&YPD?3z7Frcw&TWiT;I6upb=%uO`Y|?``$m(3)eBU?E?>T#0 z?2+mJ!;kkR{yrw_y6F!3XaL%NHy0V-^8=L{o)_uCwWM{CMrhzG@S3ch= z7Bu=`V!Vuf4tqpgSHvc=+1|ua>`|-VD_6|z?}TnqnFcriUMZSsnIACOEUn~x6h*L7 zYv1M|3DIb_cMV04X50;FYkfS}4mlczfl|4MHXDH?r<5FPwT4Qx@v+jr?M>D|HcqoO zW%T|IUW9z!QO|GZ zdwE9g6Ts??7CIeIJ!6^%Y}pC>Msmz}Y+1RA> zSC{K3_X>o~g=LxR#=QRitb+txQ?uDdtJzrxdynTuvN4j50$!zDM4=#KTB5?zt6OBf zaU3IJ*S8IOSFa<~Xtp}2)my8bS`K3362T}}3UD1q{VmHTAwR#f==cX|`Gl8Y08vLNwe;z8C+g#W9 zcxmrG4d)ug(VmTWx0R{uyYK3EP<7)ZZfw^z(b7(h;Cwy@lj-OQxYY=mT4wsiV5za z5*M~^#f!vzEhbFZ>#4sjns#!cj3N_9l1r|yHK_QjQYpeGoC2s^3Yl&mlcdGOYPLJ- zcgVDnCNMQt#^Kp11uW4~Kq-jQ^;sq3YMQQ~iuhcWNp)$Vs;-Tdix@8zkRwdCZL+IU zgi4Zjoa4(gGDp{SFgrVem0A<+c9*Fe6Y8Ey(8@}a7C3H8vFLD&0wF5qU6cxWl#4k$ z$noaprqs2BDJtubcM6Cz)8i;G>FRvG)A7+DXazo#;~2YzM83(dBWMCy!X${k1chg|x*3FfGN-`m6X7WGy!?xqT9S|s=P97AFs*+1 z=KDBx`aF&h+{aEF!$Zf9sKk?J6!aW#lF3^pgp#;X7^}qFX=N#$D4@6L>9Pa&1ZXX* zLda&&H4BI}1Ll%Bfu>%>Sh$R-V3D0L$)LMCQ%*o@?DtE=IKCe!<4h2;Vkw{P)>_WA ztZywY*YM(N@8H$9KR~0^&C;z8M7fY7Y#b}-^^>nZKL5%2)q#)!ceT2F(_Cx(3NcJCjHp;%h7Xuf@kf`izFns(mAZZpZ@zyH7p`7Y3`kmF4XpBag|JDt zmoeoY+437FFYlD`44QuJ`N0^P-XFLBy|lhe(?E{UAxDRT=_*dXe^vouSvPItNM&0VY|~T;DUd1Pq8MQxyr9!l zh8Jkpeus>?RKa2~?JSE4W)m>mf+2uu8HBqjX%fwL2bUI>aAa^^8WKbvQAjh72B2%FwdJe6_j z-mF_-KYQ^io_hQQ`uVqCRimz8&t|>>!z(=0w?xI8YpcwTfj^D zsb-o3h}N!4Q;8Zf{Y-(3(C^2(r7mBqVx``~%;Xs2cxQn#1f(BQ7xrZVyD0H{%dB9@ zor7=W6c-xzc@z%J?QYQ11fJ%=gM(8^4*8^uBi;p=se}fyl)Hn1jz;V95bnp=V*Iuj zV7|Jn%w|~TF6N0%8~1>fl%2BK>B0+oDmibyTh65DGVwZofV}Hupbc)+vN;bLfg8xMn&U3`0{;xwegRv4EUwBV?krJr7YBuNqeYk@g{>V%}3A zXs%-;pK}#-1s==AJSwGvdTgc9QfjulXm>sMy%1@V;nfQxG};{k>!X~{qnOWOZGH}t zbH^dR{c~;V?f&t$l}3mnCRSj$>hCMLV=BQCO&=-2ZY*;rq&KZ`CHV}q{#E1%TPduo z>vsTfbk7hUtKZSn5jHO&C1T`*GgElW{7AtxNCW9{9hz6h%h?W0Q&%q$xME7?2l)@-9i*cPfaoci!Q&R)KXYb!N^)>Uit z{GNh)jG#*z%9;e&1AI@iK?B*NlFt49eht1|afb+#+4uGsYWCEwz`C)_-A-@8Jq#m_ zFc~bO5VsX@w;8s8s%<&zehRE>*+Z0oWtk=p%}ybgb5tsr%7{>DP^~xBJvqWyR7Q7D zDHI4+g>X*dzJs%vo1IjDOERk0Gbsk1) z>T0ZrkX7pq1?B{SmU+%hj$vwijLDho*LS-_eYo%L*dREhmhD;iMjp$~%)0Y?Rpwqy zG|>!P%N>Ff`#40ml%mG%giX@y9QEvGHwX-3@N@^=S)LKojnm}qjwBdRZ?#cvv}nRu z?TCQT@qLus9FCVKajZCjF)I(tPf)+i;#TXPr`96)N5@lTv$T&S`Dpc2N9u+q6i5=hy*wuWj^vdB5(ptngzLnD$lel zR0{a);}5|txcKPu0+TGrU}Fj<+@E@@gS_LYhH>P;G+f(K3A;0&Z0QHtxVMqPc1ucp z+cqm$ai&#=Yca)QCYmJMe$=i(8D+=k z*N-iURh2>t`T+rJz|VfBS>p2Ei{}?$)98hwt03)me0beJ!K5JCpl7JiCNw#lP~}~e z3wbs7Vm^=ZcmWefCt>AnmBjCzyNH+Hd=GD({z$C{{bXw~wM)f3?mIN28pBR}s43ZAGhDUV0^WW>CbegvNy%hG-Bt@YU;Mb*w?fpytak-w z8Y&oXLCH&`J6@npY&cIb5xc*nnr4g!TFN!Jj*Wvellb>vy@e&3G~-57&`1&p5TAME zL45bw&*AY0k1?G>G^;JN7FzI_c0T|1gPuBuQJAGslBH0j6sz|P;E|)iB+q(Yuy(_t z^Sve$3ObWYHwd8tn}16Rl?ljLsfc3ERexKCq2RL$1n)o@W-j~ubJOFPn;OUGKlupG zUtPdI{NQ=~fz#(~KRwO>0l#&)$#y|o`^(AKaUY8EaR?uTdOnO>Ii z=dB8XJq2y;;vy{@x?xSAX^mqtxTb*9K@*89_P5Sar?3fVQi&LvusNoq02#LAR)b09 z<{Z@8ZJICXcmIUOH1OcjIehC2pTVv5mMFt$u!awM+lj?A?MfQF(8m_-$y_=1O6?~7)&aMKv#+dCD*ZFGwB2l*Rlz_37z+-B#{On zU7NqHl7swo0fuX;rqG{-`rqL*CypP%!}lM>&t5&H*6R5IicG?>N>RbSlTr;R-tyUx z`rmBNN<1hT)i%qke=oXoXqlBheES}r>uO&>yRl@!Rp)?OZZ7Je60Y=PIt%Q5s0HdZ z>bsP^*~gD)c-z_V@^%YSiPWX}<+rZsIK+he@{^C_8_#?S#}3b`^D*IBrITfq9pu!=Xk#WC?KnGWdjMZ{7!cWn#>_$gHYbS`EyG|ze&~h>f?*6n${S6 zBS*Lnt@D_6ivb(dEdgy%ON32#5_E$i|4LB`8z_f$B-)-Qob2Z7)Me`a&2Ey9FD4KZ zjWoCzhmiKd5IM)eZ++n@eDm|4#v>2hr&2|dXtT1JD28PqX!z(geWqKy3d3f}D%VWI zK#9p%F6LKPH~=wArj5W!p&L5vvI}=24>M=31An8^bq$5QbDan+Ya}}@nS0EXR!wK) zp2}{8m$65sr3o7LB(CJ|L!{g4?>nJxDQJT@uR60x`2kw&IxF!sX8o&hVsEcs_YQRq zTYx4XUrb;)#-=9U$T$fLw1(OyNKN?z1>NJB^UzZ3USszQ%AZ@dVU`}bKn3+`l|a5KdS9JX7dfT>GTI-AaA)RMV}y>P4jy+*yY7w_tt zMb*qbqku@W?ik3VZYgMk65up$d{1`~P`*JkBmoY0KT_xQG=`33UF7eeB+X7zU!kmx zZjg^Jsb)L&NCT%#kbvfKEDK4TpxyNqe3DEz{=)EuQgfT#AfO2#nyw8M7Bb(MptU-_ zY6UCJ7B0*$;>7(&)9aw5H%x{JD{~jP zbdyI(%Ay0SXsh$;vD@T1Nq^bjINo$$#0Ksv5vTPh8WQP3FKRpN+X= z&!y{r#_^Czy+N8qQP#*dsSfq(b{$F^EGEq$t2(o|<{sQZb}+1AeIk0R17 z=rndN?w}MlkZ_|%sEgF=)TcIEYsz$zu4`JuZ3XiK2@TZo{0s(q=n_He^&;4|iJfqE zlfShr4Ghx)Tqd5L0VHE5Yz#7Im0*-Khd4^IxonhrJ9xce80wt@h>Y3lbaphPJS)vX z8pkF~oTfh5YR2;I+g2G}qo`aVepqr2;BKos6tt`)!LGT7*u^x0)sM27&(y|ougPwXO;ol3@8XD~mW+%t#sd!J;E;IS@ORwYnm1{UK zHI7+oyi!7?Sb$|3G{1+%l{(+O!bGj&{=;+l`sY5mixj)Q>p91UOLe-Qnn=eB5cWdY zOwnN*iR@*}eUc`&MV+Kto6V!AyDGi9W{E05O9!sl^&)S1-O->)$);-jy1t%+@8-GT zML3C%gWU_N+YPbtzoM>U3(&+6Nt~!uOSf^7B$^il2*Oa@qzqMWb+E8p$K3QJ(cV31 zI@3hp{oZpg;>@M1$h!{H(n5j9iLnw5Z=v37qecnvlCBROKY~v`@*pP1$|{L=zTuim zGhNGeRn{BydPSC zpbbiWc5b+5zkyUK=ulCg3>qYyaHKFKny0u5I#g0#t4~$ zg8*!{y9x|V*Y;$sI>&ka-7~nju%rwxFm?Sv!F6SEIZLhntMon?a_`$8p2xGF{p5~8 zll4fWX?D5Brv-8t%@0x(-p+7|}uQ7`akxY?L#k|GMD zp=aPT&3gU&1yt$wSFcso82W&|9hRh-B;?OezD=Mb^|#10jO#M5{~lZy7+-$teRbUF z95hYGN~4YEUp>Xt?kV8adR3x@YOTXm)QiyJ8sxYUWMQh|V$aSkN2c3JbhL?D7Z!SK zpuX-RpaimesqQ+^HYx$_Z0TXFI5TM2lUUZvxZ1ODHB^ePh1QF_?eb>NOaBy8#8Hfm zLvj7RdB=up+X{Ixb<9M3>-0HXCTxbWyDb%X&R)EVvzO+#oy*#iTi-cz0q3tQ43*5A zCECwle;cp8eR_2ra?bO63cO(wyT|)F&CaHcOGc>0238_-+(3HN)>6GvC}4VG66I2P zxWv2*>z)8jN;2$9?mk>7JctjBLwKc~$E)oEUhNccvYT%#MrL(0n@FdQqO1$|XsT^q z1lzV?TPFJ9suJbhvlsE)FJ6Pk&aV$)$gMy=dwCwMc6aCm84$5lYvAPjXX(`xqlTKn zHC$e(;$NQsl}hVDD#{$ZAW)!fNj~=?@B(yO-K=440-2=Q0vn*8XgTiT;mX*gJ~eX? zrP4U=<+^7;lhWjCrwLrg!R+iDaygd^ObzzdZ(r=$C!%!gkdQ7cM)5kHGV4Yq=N-#} zr9jK>5wM~-#=pLF5^ubJMwxRbsEOG@k$>Joz zkAD6t&PgKPkjfF~()K*8c9t8OlaGYbMJ!CGxjNxJEr<*ek~LS&+wXq=yFT2Ciw`u9Bj57hrgJwfHR zj?TNY?n%(3QW`avE0lD@_-|zEVL#DPi%rS2p;~9p@1fJ|pcnLRLQPDZcWnj6+T^oL z18=-{4&VRTuMoz=gCe)dy@qb!>f$o0wdU%xGJdA(zq9jeuC2+MdaI4)MpHF|Vcsw4 z)#>{9;S0ZFgQ#phQ0I4=;?K`h z|10%9>VK!cMNLyC?vc7@7P6)c>Hzf!jrLs)+Mn~c#crC`LalSyf^L$NVQ7n^SS6br z-JHt=lQx_sPo974{S+BgmMRH;@Zu|Y?8GrV_2>yi?D(6N&P3F*&W@OA;1TMx7q2qa zTI#xtEbox_2{@KvGJOmJsjK9TDRt!Ya+K+{yBrmnA@>wpW5 zV7+|m1HAI~=~d`&sx({MT9TvzNs0+}+NFo}BvY|^oKpmt0 zi25b`X=>x_WCL5_nCP#t>#DOO6vQwMaSmZq1K)X z0AeV@mMi3-)3{=Em1rC|qIuW)OyF6rH}SpaUcj+~vzQt$(@g7=z?8J%u|+5@&M#qp zX$4)+N3+w#$@k76=h#d~6OL^vxa7CMCeO+E14txkl0IYtQNp=O>b&^MDSUKsUcLYR zBXc-BH;qa$uM+qA{gP$|u2om?LpFw5v#s89W68Z!V`V)0z|mC*1+s3ds~{OBHRTRJ zjM60uMYCWGo{**#MLpQIv-Wmrl#|r&AWOElsDGvYt^a%RHu-B;b+>~i-|RkQaDA*vP@lncdAX66tg$HPy5@}?eyb95iLnH>JXOf$vV@D*HF{M7;+r3w!w+6~ z1%L6o&#oq)7+Y$k(Nf9v_J3oh`tS`l z#Pb7u@X;lFc>XdGSKxxUtcE_7e}| z#IeInphPts)p&-4Y!H*n&92t;^M+QsK6zP76oqP>O}>RieWtHJrCz39 zX+A09Oz3L|t{9q>8WOg1r0 zI-p~nuQc>{?+;&m6%XHk1fTolBM1oU)x~AJclIJq(b$)-EvXcfr^V#v4MtxDYnwUU zXi)h}Qg4uaEkg0$S%L0~f^KelLZ#e^V}}qBmVf=lYv>Y8wVoSF(rltq!dIXA1RTpk z$TfN0EZv8NEZd6^*J@29`69G*eFKa+=8z5Vcwh3(-=UtTen6e1Jlx@RH-TnTbJSO; z?@~`uGgNN4$N4c06NzqV^VPaJRw~9*m6FDfJY-wWOd}n>+xBp1Vhj&3CEjCdh*54d zp1^ahTEjp6-0yc(r{u}VRMjh`&ov;#OnjuV3QDic;O0OdgEOM*hiNa zV3`}wBj#G4e*6SZ96!w834Gs2&+m=&e%X~;vx8PQ07_PNBE8-eqBvAQ>$Pys<)L&9RqyCBdcdA8&`@X3=s5>1rncpOJ0$C^f4)rl)iKY)diu$-2XvmilbXT-X z*Q!Rrbv4&EF-odQg;9hf)06nyKlnEOujgLCuiiPWUb2=o0Z*sN-+1pVsw)ke*;Iy- z^J4y6UDIzs(E^*Z&B)K94MRQr~1@)mWcf>xrAQ=g;0O+AAw zy~Lr~P6uV~AkL3Ncb2qTv!z|BuHg8=88zsru!%tr5w^eh_E%IgymjWhN~pDy69e~X zq-Mv%WTm8%?M|pc`bz3<1esc&q}eAvj)#sPK^!IUxCUtyqwKy6U2ii*`D|P|h}3ej zhPUR1gh0oXX<9p7jznRF`YQE#>MZpm>W9=RYX0`_c2;*9XwscNO?`#>GWEo+=E#q# zrE4H!=S=JzKl(H@zk~T|4P(UuJ9m+nMnx^_`g2ob_@l3Xp6SrR#f2p%mvPg5aT2Q( z(Ka#lZ7G=xrESn;BBs#vLLX<)hDLR^?Z$_9r`)~=Fr?`w|w6Y96A zH<7{i9Q6v-+`paOxNZk%>KjuBsAs8fQBPAxsodVaD%~*UQqx8>b^un;M!ng_RVLf9 zxhd6!N9ACURG)q91giBW{@>?+i6H1f*E85;xG>HV?M^G1w{Vsu*V8tR6O5OO_~NG@ zL(y?iTd9vccNuDlDR^Oik!hwQDKgDuKW@(+6p=M?@z@_xzoNcR{gj%QCEtok+)B`l z{-Pz;e~bDK^&nM22HveJe()qehNLjg-nNAKAqr`^u_0N71dD}+4))*P!m4-le4IQ6j8y4aM)6BHDNHey! zG`W>qAWfZYu4Ms6{H;>zD2qX!8B$s7I-1sc-gw=l1D+qnD(bTSm-| zYt-iz91BdgBeRn`9x`G|%ubBqkH7u}EYolo7Zw$43Ew5->$;Aj>ncO0w}Cc+%p(9x z^(MM(E`ub?wj)(3CrS3`{r92M>LOi}cEgO_Y)DfeFg>iZ7ON@ zl5+o*`cvvf>ig6S)LF{ks}~u6^*4XFmlMxZpQ8S_Kl%SoeTO=TEV^%5$%pUteE42> z^P6aVu$)8-yqoa>zM54_kq1s!~RU$#DAO6?ADj0W6AQctKA==2(_GcdM)2 z^{~h!^VK}Gbx9`m#6u6@kH7InjC1b2UN|~rR~J#|Q9Y&UNGdak3fng>*Uc;4#*!&Z z2z;FS2K5Ye6q#phl(*X#>_wui}H%kX|=B1hyw1c@Qj1=(=p%5BX~7v~q2u+r+tmcr0AxWzKs+}D)AY3XfCteuog zJxx7H{TX!F%}%y%L&q2sF{w)&OGkB|5DRb-I;kosrpJ*t}-Xt*-|>TmvTl$T4q9;AMU`k$%)iTVz*1S=wI zaCbzBp@NXerIt@dIVToNd80&29a+rsBtr9>kHENz@3} z3e7HQC!>W-mO;`(B$jPQlFvz6ZOAP|E2%3aqK)5_qPNzze{=B-YVAD__6b8KmvU9 z2!SL~i{08}3fb)R(y2!UZqVV6%ueIc2am!w4J^}?9j2SuPt4g30(txD*mAr{TS2wv zKJ>>Fz=9w|wb4Mc#(VaoU!2

dVyJos?Qzm6)qutD@Oh8R~w4Z7gb_)Vj=P+Jr4q=N&>eHCDpxLup&uAi+>B~2CuD!F6~1s z5^zM4kU=k0^A1Cb=Mq9UfNXH@fvIu)_LrW**PeU=F2@(hM(khcdOgfnSFo_sfX{b1 zOnynSoNKFl7R+g^n3ds-!g&=-W0;tl9SQb3s6y&p>c`YisMlo+h5_ve^(6Hy^*QQM zWYKw7)u^CJ8MN@h@EWY{3Raq3`0U#9>2;1(a2?EyR}^%48cHVsqZ(rXRISyd>IS_z~r33 zBn{%BV~6pF-}oXvb>bM}C_x+#57}VMju+s{;tH0S%zm$@(s8^($aqAWz}FmHvJWEE z%;5&U`$1bKoM8sfVdUw|myRshxl(sa8t5I20}*4g<70 zzA}~=RV-lBGlXrtTvVN00WzXN1U3QVqpOSf@hflQm#02J+w;`<>vPFWxOP1v zz5l)psw`Qx{`EE9T?H@C2661*3_kI(V|eDVkK@SflmaYChMTk2r!3}pjaCO&m+Ndo zZM7#dwm|0CW(GKCQ#B{BXig5l=X|hGEMs!=0EUaeyP_J@2grc?KJ|*Uoj<3(Lp_Bo z%?h`Bmba_KC>`BJQ!irNifN)E3OSds32;4?9xKfjJU>9Q>tmAFD+JGC+Kj?lM57BB z4;(&#xv6n{;=%jy{hz;v4=-I+a2QO>fx*|7g69VC26v?WG!yg$*aK6Oc#PwI^2Bi* zo14K{A+J&`WD*X)AKAEVuJzhVy`N%X21iaHE5c^V%HOhgl432Rpc+;`pNA{eFytwH z&|>cPs!&f;Pf&kGy)22g+`nMl?%C~S?Ih8pLB+(q)W038p#JGWGqe;_DMl}qg%CRk2?B03TQNVSXYK@ME zfB<&=9>z*}ssPuqGvJ0awU`$KcWSJRKl#QN@bK}&c<$wsxUy7RhnbjPl2cb^ybfKC z?{jS%_Z^(U6HKq;2WL@m9F=}CB~4+J<|Gv`wN{#KrdWe(>~eaNqnZM%l+U5Uwd(r% z%!)MwZM_J#pwZIo*P|iYS{>VD zirt*lvR7;o=oooK+RoA}NfWih3`q>xm+rdy4QQK`fYmgLC?y@0Y#Tu#CKV&PG-1$- zm}oxQexQun>UsnwhlvWuAaDkgXxMa%nQn2izw48^ONz>z1+XdslO~ZSX_nYIN3G2y zY3sHDZu!CpADhfXrWqbq2+npt5hX)A@8cSn1-(I z-3+i*$TSC4V*-J0{|2%x>YfEn)gFBJmd-@dJ1E8NZNV0vT_*$1SE=Ts$z0LwHKzI(}=)~76rVzfLDD+H|8>L8301z07QS4pP#lQkW(@dTQKWpfM- zf|hV6b_3assdg{dT?*R&-(I=?IF3|N{8W|gypztWhY>q3_=ey+9}r0V#ry*Zv|6zU z3ABjEuJ!{95@LFm?!-x)mmgK!TTc2hy*-mm$FcF`wA^tL$92p1{O&of*tBa|!5cBO zuf5oZYohnU#$pq*nHx6YJgnCdW|VA~lx%*mK%bJ0fjeu}p_F_#IPZ&JDsBqge1&hvQ%V{FuG2)PS>M2ULl@s&Ynyj()pN5heHTS>GNRwb zn@_w|7gl(IbX{mqW?$@}Ky8ao}@dj}Eioj*H4wx3R*?V+u?X0m~Z z(xD%Z(N2QBOt($ATGhJ-E{tLvqZyK_G>! zdai8NtCXTHl)Onwvj-o%uSmEy#eCJWz#Sg2bdRRw;GRJH0I}IP)h^s2Lg}F!`*2OX zQ@Y*O7PvYcTbWIgZQpF6OH9=jjsSy~+8ZkZA&R zB3rm3$kvo-SpfF2=>*y%v^C&VH4#Y%eM+`g5}*Ya*K#GOnHXaxBQWPlo=q(Rn|LOjTOY zSW+sRXvQ4LG}bb}Of?Wn7lU|=RuVu$7c$+p!(pV(FjgHpSI0}Sk4&WojUmfRD^bCP zGo*xY(M=|BO-(*_ug8+#o`X<8^;Iz58TLq8d# zu2;FkmZq-2Og5;tKEYO@Pt6Ikj8$^bl(n^C59Q$Rt$C-ag-E*S#Xj0e0BOyhPd%}4 zFjgIVM0B1zU?y#i6vasUtW-4aamCfME zAF{MZg3>JQQ<+t2&{!#Cd1u-UY%ETc&~*v6FbsPgQ>Kj@kFnPxsk9)2pW6dH;F?r`f~Le*TM1vKQ0I+#|8W zF!_I0i9v%kmn1V6v4u)0jQufw_t~eIO?(tt_BXhA z{hHt|=3Es8?9riBe$Xg64&vGaimUnR%P;Z8pZ;i5CQGC7pt*ScA6oD4&_>@&&D=%h zNU8F!B6F1Gd6$v7N)H-)x(E|0Sp!^+}v4oWNKt`#tOPVd0 zOZfieI#q7#*^8Ixw9jDlVe4bCT-U=nfhMK8S5p*47>&jV!ze$aQ;m{(!$;Xw`W>=~ zxRH5a#%srMY|~@C4(}P7!E3iWc=_swkOww9gVv5$%%ICR;G!ugzrx+Ko6OTYiv>Sym;{gj7L`oTVE*$ z!zWMd>q7u@P5d3FTBYIHa@&_nfn5 zZ`yNq&zYXxooDr^XXeawzuo=*`V|*%zn7Msv?eMPNDi(h@_iCY;gKd0_@twVgeUQm zAdTljdPHbR^1U|Sn%~jl4!`3%j!DD94@_%>_w9EQJ@M;!+w>LNZ}@wDMtrTzbMkSG zOYT^Bp6wGYKQPz$PRDp58Q+e>-ykNAm&4|{gpqyM^vj(IV*zV!>ubRG952UeZiS6$ zO5bYA(lz2T{p+SR<@dzQbxy`M{fNom>uYEik=Hi1F;Wu4l<&!`vA~{*V$pT>bVbs2 z0J(Cl1m&RR%9Vn0&~oKUK{;r-a;2agv|PDTP!3wITq!6AEmy7-l!KNlR|?8O%atny z`K|-V)s_U=J!403=sKWWttkg>X{eV-50Iv7N$b0De-qk$xPJ=Qhk@TYv{lzZ=9*hM zXjzpIt4OJf0Ms>TcW9+{!q?$`fPd9Qzl`QFKz0DYJ&Py%@XcZTb`q|*4nNma<)CFt z{qToLX#k~mpuJg#(anIXZ}!*qMnLvy{QhY`c1mkCjCQXU^nwub5MDS6N3JK8D+etL zVu-GVKc?gOqdHbMm@20ADwr!74EaRJEo<672m#y>;3RB{0g7F^2SR?RW{PrY# z03L-auyVaf%UL;S-BSr(g9N_<-pSUr=q4ol0IrKjc1u_HAe*iLX0X{e;`%{Acme_J zCJWs@_%u9DIdmOY4qB%KV1P_X6AdAeuhdH2O0n93_M?Dn4Znfs!hn??Tyu%{eSnl6 z0Bl#{`Zp2ND`@v1#vh~o2|NOyaUJM#Q4ZST)dOzSH3>9t5&`$ios z_khhN2^SFSHniJx6n!3XzK(eequomuy4T?MT?e|9m4mhr2_z(et0CRW??JJn`F0}i}f;a9u$fc$nwASRo0elsFD@F00 zT1VI8)c=ryt6B5FrRyL%mT2t|C?VkM(O!>3H9CfOylJ;c~UNCE^9a!|Vi z&G%>=ap>+;RG!jCtl@oF&--vas)cw-2(cH}!|-eHA=phhcc_&F8dt6l!`pQfe;iQV ztYcHfhPnk;vv9Ig4RF=sh$O~H8?rhDlUJ!ka1qw_Uaj?~aD5y@9?^pK;d(c`pKPUz z94tlZTF#(x)dF1lLul^;P&-wnx{YGB3CH<5B!FzZ*(JE92t&lNqH;9^Xs(wgb@7ZZ z!J4yo;QBYP=Eu+;gr9+5fRB@fZdq2lG*wioRFuVg5Yy+-)VbAQjIndM1c7gFC zRJ3Xsn(GxT>;d7h)0@!Vg!X=v}SSs4U*D>SfO7aDR09<{UK@E?K-edOS%rA3+l(F{T?=Nr;b9Wa5YQd zFNzf^T9kt}LmG8X3gLTOu~LuV!9}hk>a>;{Xgr@^f`8lGMG;XPWdk;Z5G#Pj6^$|w zPsSty6gP?O)B4wO`#HGaI;Ku)xq-F?{t~>-z=g!tNbD?#(W(Lb^R*iCDF>|~tqowp z_v=rJFjuvYkzKZBq2&ZxFZ?*Xb;{ESpv7?ps+ur4RSiSZ_{%jZ1DUO6^+%V%e*v#` z9b2cgTtH)r9)RzkGAD+MAwwl`E`%ZxPq`YRvc={)7li6Af?&3T@OJo%u;)6&9JEQ@ z2>&t7aRTbFW=~7U$&Hkv3MyJ0E7zf9L%b(k&HO3Vtgb%z3-Dd8!|a5X189Trqwuw} z{+d)ZjRbcok%Yn(EkZm(EQh6Eq_7}@L8CcOoh|TV@Q~|J7ptYd+Z_J`@cpni=UaSQ zW}vDGj9oz-AwZKWy`=G8c%B7qW;JWpz3^|rf$NYLqooeo&F~}e>I=TbNgYL|vbmH* z7?oPRqB#vE6B2>n%E4EHe;>Zhb-atwQU+}US;%f^>1~{vx>lR-^z5pHkaWIUGoY>L zidL^?p5N+zY=Iwxhg^rgP%Tx^IPPDAA86~VC?ryfT$K|ZHH>0_rf@CD9rEraeBYM% z)^#8JARM@keIZ(^plyTy6fU;>1;eG4h0S4Aivc=UHJyOB;=~h|l0@LQd*Bt|KZ0*@ zJ%xp6DT1~h{&V=sw!g$C>#$})b5YeWWQ=N7sYOY~twiahn#qN%!4Ujs@WrlY(XN&v zXb-`kSy1c@7ZP1Zk)zNBMW|?%FmyD22E=<%uV(F^HN5Bdz<&VyuBWn`LE8yG4EHX$ z2d-xIs^&m3##Ks_Cp{_fvx8YINZ!EE7S}PfqJZqe zvi(K%#G9;?X+;pEI*B?|?~J}jr#={`OV+QUHT}J$xXSTq-^H;d#x7#MQ54g@LvPc; z!$-}SGEL$O?rPIlWj2e2hIhc9vclIZm}Orp+7H zQh%vPQQVosnWyKYg7g*(GY078K--?+{^kCj?Le;$=kIo=)nfd1=+ z7wL&T2LSO06yQ07?cz}33Cf-xtaVoa=T5JNUxbgOKe^VFWzdG;ufSWoI!bcdl1%xO zZ<0hJ`o2eJ&zI??w@1)cXft3N>@88O6}3{_q>xlB_!P#Gsb2r~!##BHt)m94V&I!G zoQT&KRa7Juwo6(CUkX1(wz_3bSp}^CKMvmycXfv}5}AA?0#1CFVhp(IC_we*iIa3> z^fawo)lZw&3>rvcHIp`e!oL-9P(^3W zPm!WHZoJ2k6_C7Kt=>C3LEi^l-~I7^dgIu;raBgU-}O|C1ma-OsQU$#H*hoj8hpt0 zyr(ORpj`?74SZ8t18UA@P6)?UtuBEBAV56l%2j%G zqTxet)3*0g&A=hirSc{9d-|IStx~_r$ z72e@uaLu6g_L&pdl#$M#?_|%CX=;OyC{_r~_QY*~B%YtI`Q{>Kc}2Gy+AQ4)lBE*i zl<3NOwxH+Whv2te3_e|{A2)M|%gD9xR#yR-q^i}33Wc`6)zhgFO%Kf@O#=7AwDly` zB(;L|{46werOjW`ZKN*vz9iKWXG%zlVI@q2q)khvt$*Jb)4VbNf`|Zsp%OcSjCCV? zIedg#Ug7R3E1+@448zaBzv3hUDM`l>k~cz<1XB`3Hv=?NlgQiP=JU*QVC3$ z9zSQO%yXT**GkehNwiyH^!!yxH<>|G32+>>g%7Q?_Xa@2o=iFyvy5j46@FlUcL&<{ z;GbpzGFDbVV~xOHg>Qm4y9j`jU)QQrt6EbfVt{NVnyf|^9(&#RtqCBJ03s4n>bWV9 zzzup@0!Xw4WqZQBlgesazK2K`;PWs_Z}W z<8+uNfz$0AxZOINO?ddz)8eUDBLiMDgppmZ*uJ93R>PQ~_Y_V_eV^r@%dljliW;atyr8A%)Pgn_OY*QgZLs7Hn5 z>)8G-dCf)BQMM?R;jh8pay{?al*Nk1;zj!^ydD0?Vmo8N7_Jg3R!<2UzDlr7ip|GV18d@W#f;Zhrj81u5&4?6^+H^zY5<27Z%zH zL)7aD+R$I1K2)v%unC!0FEwxbB&R4dilNz?FIzc^A4d6)&Tzk;%f&T@rx}ML4ly%TpKZCylSK9fA zH&J50`cciKTnf`%nc{uIF-ZNDb0n%2Qc;X@r|gdgI=T>e$H*SUM_tcjJ}rd|Gget1Yv!;ipEnl3Uf z-*o^j>gQxnt~KzjG}{4z4bV&!HbrC8R1}d6Ji9MKcXlhxK`Um!V{@Q>ot(zz&3b}p z(n{O!MSTi-4j4IReL*m_`F8$^nK9>0b{^@%@6CT;*%x%1Cz~x=$vW|@Vt~cqVGsF{ z###x_Bl1jp3hg)X+Bfj>>$F6)R6t|xf`1qO9r$5*1DPxq4Y-W!ryn+3%Ek%UqU=VS zO}B)a@9O~BXWX?i$z)n(?@fZBRY?pnDyl+7Rk${-xySP`B!Rd*FGz-)nUwrQN)PW` zXnPQ+dB>X*R|~u}?{E_9Io`7G_>IG0b_xYaJ{-i{Al28+jE8sY^Pf*f>tBVsuUI?;D zfTXn5C03C+{o^RKP{d&Z4fh{gcyQV>H2f|@W8aIC-z-czfy;n5Co01> zw-~hMcjicbq_Fh8d5#ynl>j>zXS_z9A0&s3p0(PUcL1y(6sXiUK&9RR3W_Cr7%-qJ zIiO~gN8MEQXDkH&|1SJ3`0D`gO^tQt^;t?KXj<`0`f3JOC%-j7 zZXSE;=kuvvDd+s1p^u`uJ4oWuHQoB^>N)yJ;LvkKpVazft!=d}_LQgxu=NcL8t8g@ z`vG1LHcB*h%N#z*JjKjPS%LS!e-A&K+|LeV#|>WyS` zX;KtL(ONBAl9$2E0C9o@Mm_{^FbO6zm?Q}DVe&co2l6Ff0_5u;K#;&lfFQ;MnF%~r zJceRB_E@%MTeh{6lt{7JTXlD>cg^#jd#k&uS-p^AvBV|6AkE;qHTn7#=mT$})!5R2 z`JFbM%%>shlhrUPW55s}$9)bda&Z*xx}CKPULN^k8M$Hw&D;#SrW>#1il1#mxz4zkb?lfF(0Xq!v;9Nf|0BLzHrg8q*}Cl(f*x4>M$zd6ETzU$>mT_L z=yb~pot%T^c*rk5cio*k^B+m%e`c@u;xM@L1mV-1_%cq4IC7Txm@TViLy( zgJ$v^EpyyUId)j%PT+opGO`0ORL8Q7*8t;I;5iFH%Y0QC56^+z+u{#+o{T%O}+XQN#Nt2k9``eK>R{J_Flhm^{cRL=pu^f({zL{=s01d|g<6 zj=vTR6rnutp(!R0CuoGma&3KSIu_mzR(3xGl-#9BB*y{ecq&isMM%l8 zsZ{^=9gp<=U>>rUpQ?^=k#sKQ6^gKI=g>_~K6!`T*r{8I>mi{AQ|Q~< zLzk=iy9zMr1J&oC$JrA3%(QISj(fcAZEqvK_SR>@iH{SO?V01w;jY3kjXm8Rbs~q@ z!N99T4FZ(h14~ICIN1bRK-p{64-2p5-e4inrfbN(vDca3#y$ArJrLt~56GmqfT6`8 z*6cj-u>+j3~Q~;|K}+iooSsgUP=r3bQrG8KCki${bW4XJcxRqdm$7Tx>U?14&W) z95{WpSGbZM;3{)J)pNd~yhz14v_L+rVW~Jhu*r)g;+bhj`NghH2Zo zU}zW0K-mRn7oZdz?NIu;O0V}jS-&WgJ#_a&-zyMm|HFNjoZLyruB*vx0&EIZ3UAMK z<0yS5@8Uj?lgvRiz}fpq`U=Q|S39YOI{ila_r6boPjV;~i5|M-J2A0Ek_?A&!|*fQsoFngPz1%Bssn(O|3N%nH-+cN=8WpHWG zGDnpzVGy9(Zo%(#c-oVxdO zB*43Fq;@a+9ZCvP&vI3t{pzBl_jy_a7x-O5*Fm?_M$qjb3d77f396Bf=jMvny?p84 zaKC?KWX~ootk%ZHxN{g~Tw`nU_%&z(j^&C=(Xr@M;#M~AEz2fYW-6|pF!?K@cw{5F z1J463ci4LY&St@q{mmCk+5t6q-L8hN+iuhG+WHyyzLU$9);_(5e|Ez%9dFz@j52N| zt!6WdqFJS46e=au7EaN@9R0Fap_6@X_c%U%=>6=2RrcB;bkg$WvVOOI^9Hsy*5%q{ zbH|hczaVfrkA z!T*eL=Qzr+K6hqn+&PRgTJ)^zhBCtHW{CIeG2%EOX34nodgR0J2I#gsu#^g*jB6}> z+vCn@lwn2DM2n7`;hbSaPT5tkOofmp#-GPA)<|F?#OZ}H=E~kXYc1nn-Pnmf9(Puw z3~Qn>OJgBPV7VqBEr`dR&Z8Yt*KNeOyy#&jcLKI;daZ7}{r0WyM4yZ`?gU0023wV9 zYudcZSqjbI5hyL6;b75&;%|{v&*YhO{Ak88)#YcG+#BQ0ZIm(TpcUDwY)TH*v(kgs zC;d3a7Ghlit<8}#NP`RGWg*iN(6 z#+~OVW1_1F(!+CmH*&a&$6Ct+MaRI$I|*(!5(Fg9G}04)9QQY(Y;RAN6;78F96Fio z_r8#VxX5;E-1&|wCf(5lG_U_bLfAqcw8s*2ev0l^Q zO?PA{_1N=;*Y4+%M=nQ^aclrhPm<=N)hj-(;Zgy05ET&Z;Nr~l$> z*fKqQczp%Gy>=V#UHydZriQPvwXMNZ6q#k2`g?&eWo~l86HY=}QV@h1G?RtKvJ6zq zd7L>>!-cbpxP0Lht~_-fKl<+X@cq|+fP$Svc(9A@kICIUOg3olVQ#iRL`Z%Zp)ylN zzEr@pXXEVDY5eXpr>U?QpKP`9aeW6jKH0#BAFtu9x3A)jH-Cd>%ct<9vS*|4U(e|J z*?ZVjB!ws5_aN`uII%R3vkNm=UYf%b=TG4b@0VsPn42oWaBL)A9(H2`Kl#ZU=mybl zF*@cEOl(XtXgh56<8}_i5czx#UwP&8a2y9oqrLl1848OP4~w+|Ui#cQL>(Xh^}l=z zjrV={d4+c3py?-Q`w==pLSSR9nj~||IFnGkuXOMJ_Q5D_A+7gJvn$W;V&Mke#$e9J z{iwfNl--#8+$AHPrP!omML4%u!XN(8*YW%dPovED%H|81hb{*{K+>Yq`yrOjp2n#Y z3wZDSYq0IS&i{yz)f$-Km}Jm+`sf^|qvBtu>*K}ep2ibTU!+)q0r4e5N;lN~cA9nk zuRs4bUihuH4ISoV^!u#}uQuqEe>5 zj{C$Z(4+t!tyV=sQ^=EJ+o-T2UC9(YTOm(X6l|c#=8`yvz$r>4Zf)XkUjIIxIClb- zg?S{+788&6Duo2^%e5Ii{nSOg^X`Yofvk5{tr6>CtTD-;NgS(626Qur)%oR@o=34% zMAGTr(MNeMwmKdB_iug+fA!kybUB07+Cqn9MNvdS#TrBrZISQDix#~=qB6y&dNc@H z3Q`oOE!5TreZ91F8t2X}!>2n&aiqsMPhrngD|FrHV3*?9re&hB-Nb8u{R4b({Ug|x zHMGBewCj=yY?WRa{B?{3M4j^*+R3GpPq(%>R-7pO_(wm3Pv`pMKluZkSeQf79o#Dc z%i(8FU%rU%eE0vN%L3*&&XGsJwlx-oJfN6#(CSF5<$>!IA^SnVDt#JHKJyd|ig|w( zRs?FBg8Jrv`fvF5cV5>5woMZe`<99YEX>uA%Xx@tNd})6@;U90tu{qw+nLZPR=$&K z`L64C*?jmMHwXirL%ZEZjW%+5X%4RIYJg)p#L1Jhxb(s$4N}5qLxXT9w8~o_evEhD z{3+_6uy}~#g}`h*Dd?GfiQ(}Z$9A|L8y44S7?#d&s!~AS%jtF4%>TpdALG3buj+hU z*TEY8sBw#Blria`HE;xI zA|3(frI((=Tx~||ZQ#9t*rwS3@>~B~Lsp%h!rW{Pi}SNuNb|g&o~pp3K($9`0V@s@ zVT8sH}u*(I70+ViBw<*mO$PDCJEKbhPU}n0k)6@>l z=U-$2c=v;=_~oyEi}$Wx*K7OXkAH@jzwkU>{he2sQ)_TjncqyMjLVlU;NADHu~;N} zA0OqIbkNjMmD2YEEH2FA=@+h0aCC)kJlKJizJ7BB-A)Jp^q+hKGvx{enM0Yvw;fxH zs>?A1lwGSJ3nI{&N)b8F!RA&I^_?a--PUIbAJ}*YB+!PG?vdUq0{c5QZ8bV&OWej;_95&QXzTb{MpWL-ub{`5it+hH(5*v6CB34 z6ZkBwPe2lv8U~s;Mo5=fqhkcY@gNg0_L@8qw<54P7fUBy^X`1y#7i<|r108uFRrP9`)FUM1+6r#f_-zJn@U-;(uN&k0J{Y8It$tXIOm?Z?-sd65()v|^? z>CaP~(zD^RbvpjB#*|f;@;REJfmXXa%*f%`rgl1k@SuVqbA?><=K8iSRx;jhU-?za zC{{{2+cK?V6cu%MNBeNaq=P0Fbl?HX(Hj&;&hxY_4QN5`DY90hrQJyS?GF)F7_q8v zH_&W$&<#QaY|>xxouPU@qq5nMIa^3ztOFggKSb!BYZI~x@_7%6Ne<*G?;VG0aM5aY zF(l19H-&jMS{*brWXXWilMIra=U{rOgks*+g(2Esg!*7>HPd1=JyYpls@@`wUrBlu zZNgzXEG8YaCR=#mTb{q!2ipD+5t*#&`&~kA#mTyUfR)uPZ0)qDqC`8QXv(xKh%AFJ z()WH4XjhWCJkC`pmCbw) zEdoge=kZ(YBIQf&eCZiuU^8#w>$7qE2kX+35{f#U!`M7X75 zPB)A2N*m_NFiZmM467A)02T&5Y%hmq7~{j6xA5*qH}U?>6?mm7M5c{vw{9aaY!u5= z=yuw;y|#&KH&(Gu$I{^Mb75Ur_^eRKabNoOP?90AIoHiq%Hc2_2KDxPq7OTEIiwIf1GJ_{yd<7SteF+`P=Jv)qZronS zFW$Y5_Xt`jhR69fHtTQ-MfQCe7hil8UU?c}=7iFEt|2br67tz<85V^sz#DYeo?cXYIO%3UdD7?2f2Li&cwK`yltyesc0sB#cD{1<86#nD5DN* z+zE_07fPgHTJvoXh9< z)#(x)!O`=Iw$)I~(#YjpET!!|MJ^7 zIX^|vW6aLZV!Ad5H&?{$sk6BG!FyP}agA%=(fe^~zN+Dtq9DbpK*zPYCfTF?cFX>z zt(`bI>a3D+i)EBC>7a?4!h>Fl1Vx;?j<&zz^4_*h6bd=`-2kf_TiVS;_4&LsQ%d9M)etRSMOE}mJym%s2l>h(=2>Vz^xj(ziNrwLj<+C;FihOpa#&96}>>v-d;tg-9@+SXU=F4Xj}IausqY&P8Mg5 zv|9s`gT26YY*?0w4hw<+E#T?KB9brJi0U`6xpfPM<)9yKRJ6&Bg#LZ=YT-VlfCsBOh{#vr`aVufWG3lUn zahRj=^c@OZ0MKfc2Sb1ps7%5$Gwta2aTuW4Xln>WoKo5QRWB9aG)y*?lFsinV1%pH z?og~gzY}356s)Pg64#TuAn;0Gfly_+NLukQA@_ps9NWT~Q}djolY$_BDs{E6-9*rC z>}|@1iMetS=f3!??xXWpX;qSyL}7!B^;|J69x`4&=b%z9z#&|{(BCA(F%l3J3x=EX z^z{MT`$)v3gC^=~9`uq&k38K>yHb3x3bc?iF^O;$9YBP$xv{O^iCZN@&2vzIVHgvb zC>6DyOX=^Wd4!`}DWO=(V`F_wgSJ11rlM;xRD!gee@R&oeryX)uPxUQ@B=A8vyD2z>d;YTZe1w&*J`y91c5F#2EU7wSi75s zRRH6)Jky}@nG_0f+jB7OO&Kx(vs02-_yw?aq;Kq;sagIRY4AEfFw*P05QW6L>P{k8<4uKtM_k z$t%fzdttJFiB6d#96MW0Y;UDbmV$2(o(S994V_cZxsxG0Xm{iML1^mV6zgM@Ip*zH z77LMig!|zx4&dPn>uZ1e_r{&W$inaX^`HLq7ptt?i5f~9i@$a>>)4Jq;B5Rxs=GMi z#(JF&(cv3)pp6O!;v9uiUPI=%4gpKuLTg*xPF!SvE-L*txw{ni@{A%_blmA`8Tk@{ zt2eN--K3j^naf}h0yXHulCw06>&)jp4e#+n5|81zF2A+3dmdu;#@(;(;R)*x|Jfgm zJBJa4LaV+tyS247`^Haysa!hG{t#_>1kIsKl#XOojO`2$YNNIqE%W-X3bX}9M3S_JYN4e8p zaE*>_>2Z8N7)ltQce-7_jR_8xnQ+`Wj4YgT>5sqq2?A~q=)lVUtx|M;%mN#;oI#nOh%EtKbS4vUOKQ%(-XjQyk_s9nrcS3PbX z`U`^Q(Yal=X7f&##N`$jX4jUN&#b6Vy}HkCSV?nY3(4=W3jgCPS1uKwd}0|t`{l2Z z&v}DAs3J$4P5}IrBG%&j)F3Dpgd}wzb?5lI&p+)nNeYat-%v-$yVv&~CY78+?PzpS z7NKO{81g=fB7EVCFP!|l-}w3^zJ3D}8WvA>+&PRQ#9F?dbh?+_auF}Q@HxEs)^G1{ zHQTgMprd`J;t*KX{Vw_U!66T`GbtL8IGX1YHYY6<`#^JD7t3dt&gP;1KHBX!Frl_) zj5~o5g@Beb;vNj^KC>UVZf?Ojj!C5-bVVb&$(>@PmM+7L&6FE5_8x6t)Q2 zszAm9VDwe}{;+N9z;_3Y9a7AOyd!TP10Ki$cBIgs0ZWNNoE44YjFf@xWqgpYFF|N z=c>rD(6l>U!nTG+BXhQqtWWK^Sq8nV(PFVkvO*!ymkN2zojwVNc{#d>JO=Hd4P8ws zx-zp3=ioTDUT?e8p__U5(wDw~YIRx{0BMMm4!br+v+?5(YupKpD1;Qn6IPxp2kEBP z5C*6e3pjCN0l#?b9Sxu%m6k#fk%;))?JmrsiTjP3xQ$Q8TwAYeH#IYn$5IS9w`19e z2>LMb`aytOH&-z=Q%1Q`62sEVksL!p*le^kz#YPqzDd6m7Zf+F&d#7TRbrne8m$hx zgl%$W>+(e;X@0t(wr=FuR?2I}=4h~t+lMX}c2Hr#XgoHvNV0XLHf=*UZ_ z7E!BJb&jhmYq031o@48EWzj}j949g+8MIBL6><+WaTW@7p<2ZS!WQw6EgpP7OWJ)X z=r;Qm3b|A?p8_^zDzus%y2rK_zX(m7%&~3E%~c6}j^oD~7RR*-Q;3zdEqt=Fi5%|> z`5f|j2YEWI%X|6$py<%8>I7+ReG4Jym@XGERVffATf5<6&O?o0i>nG0NtC**%$wu* za(~Zm#Lj8We*Z_{Q2Mnym28 zKYIlqet4CK9%^Ul4-t;Iox_UjO4Yr`1Qg+s@z*x$2>C0J^kA#iDkv2^I!Vm&`HXYs zaxPX0#78$)v9r_0mTB<$7P};vrt4gK;*^Fh-g5yRCi{J|vcd1xSs;At7T z4$#iwAyu9~_01hLo9#?siPqHgR2db5BRBF)Pr>&Bwswa&g;C%W35rO!=v2*CM?c$N z6r}IwW`kfg2uiHSlrh9*T6E@+0za`duU$0ZddsCEovx(ci$U%*xG!{E&6v8&#i}$v z*;ASK@Xrr@S;*Q%#w0u1CVHSr(d1u9k%<6B4F=uj-03BFo`WcghYlc>H%YtSbqD}E zJ56kCZtDc(KB6F}%0<+w6)iapS-%G9DB^&&ZKC6+4lLi9ybr?|8}%L3W=h(@w5a7H z{%aE^KMG;F7HqngX_DLaJ+Zrb0LZ!rRvHZZc1CODO>t3>SdFnO5n$B#k2P`T^EAwsf@@ z$B8J!LLrA*Z3;>ti1*FOc^uD$NmrBaE0x0Dy!?s62&)`V##%aA%UpzW5ReTznMuHA zs-+Z6L$6lnusAo3vu74LK&0pB3Er|Sos0iTpj} zf(Q6R;DHx-fZ$<>V1{w@44(0V>2}+_Sdy)+wX4>wT<^~L{_f3Gsw%50t5jK83*YXe z%DeuSdp_SY``VyZ)URP{A62@=8jJ-4{P#34u% z5>&u5nM7A#dzpZ4Vx!gOv&QJU>FDS&eQw=-h;?3*WR~|!n#nuQE!OfTlB#Qd5Wr(v zf9Xq?ncB`M&BoK(E4Wx-vORserp^hN%bfSpg{De598v-aShi)N#f2A!rK8c{lbB3*u$5;JCA)242=^4<-m%tpJb(nrQJ35-DIiQ(g&lOl~0 zl*>iDcJ(4Y`uIAcC{nPA=hb6rW==`5Y*v~A*`#8QV;GtmFJk(YO9j01)~jeXYJ6`z zF*`KgTdkDf6V{DZN5R$Z^iU+o^?EgHM~A?gfF|px*DH`^L_^S$QyXC0>NJBUC5bkm zN~(j?=oij66g*nqP~}fF$%x2OMg(KJ!8C%^>kqK9)*884#%VOFD3!b^5`xz`my0hg zVx2JEy!{X%lgMHk$g^TtO(R(P^CnjF1wIzAtmNXsM8MG6Xc-DhZVzC?XvpfDx-L= z%MLDP)`sMbN>j}|GsE775XeG8va+(Fl1Pq|BtfHAL9JHK$J_foDW5U<>^twghJ}SH zZr;3)b*7EHE6ITx!%`i`gehQ32+UW%bQxD)dl{}}DQMF@<}Tyej-`_C;o}v)D?t#3 zSY@-YFIXxq(?d$0Y%9|<1=z4oJ7~j1%St|Q{*l$cgljusSq)E%xpORc9)&lHc{VmS z(e3rsJH?#kQUMDzu+9_`Lr+_Buf=ySjdWQ9 ze=jmM1oN(Fhvzz@-GcSq-J%RsYPV~QF`jN_`|AX4Fz~U-l$TvuTib-|Iw*K9 zZ%GdM(`+m048g1inOB`@(8NrV20Nvi*e{vVwCNDXJl({gu5HT;UT6U+6HGv8EL8F4 zZ(YJ>tE1*TtT>9Zu?PbQ8TJd=7;HMBZ8qx&_#U5)L;kL=wqRYb6x0WP_uj=t;&bZJ ztOl5Oo!Y3*>j8Ch*9{;T!r7!05Id)mXjAzsH-DNz=Q3sZ^8KgFq~aVPsmO^2L8ufF zF!h%p+K!#g^+m_xI410EY(hBop#W=)PJPbce+7i z7au_~p_F&`Vc;}P*!@j-Od0JE13=&{mkVet)?wKuVghC`WzL;%V4+#Vp<%$a7D@#a z3$9wWEFl)qXIoFHpUrxZd6qfv2^>NFIrUTOd)P))sv7lf%{oc5M4Psu%e}T`!nQ4m z!^2rYKDZ=TW6@T?bvivbJTCILmIE=GweUm#}mW=5J=a}rCctEW3%-I6)E;a#SgZW#G<2Q1D>V`2^AN%I-X zkyG^Gcy2bO{JO@mvh|F;gGrRe2ZP;XqDiv|f)JKzs-a#apbcGzrcc~M`96P!47gKU zX8|;E+W(?{M15z{4Z4;Ycv1;0A^~zYaKuQaNi+E=JlD)K%tA5cHUDX+5tn$#-wACRS*JAOevzW!VcJYQmrWDj7{Bvpo9 zSg5LZIgUMj0tj3>;i8#Snz~1zHdb3$U*6!~4YXTb_`Z)QjA2>^9HwP$p@J%b8}xmw zuWX>#>mwM1YMx?f0mJ4T78dJhE;Z0Nw}4W)2%YD)!KOW9C5_@?gsXXZ1rK2uF`e~Y z7Lzri-PXz;6mw2J4prWApQPB|vO_RN$ z;k(Mk0$kgMMYE^lhL)7#7+OqUCHb3poXUBg>veiqAuwxC*Rc9z6&=DA(BNr)uNYmY z@x}B$f!b_!pxt?-#uO$rUeopLo`|r7Ou}AofY$mZ?%jTXVyS?}`3BBkTtvN5RUpc{ zgCHPxvImkh3Ce^~8iq<8p7*3-REp}|yQO(DTB|m(QE?w1bC3Tm58tHz1@*El3mIr1 zP|>^%GV3}kph-QT{tNYOsx*FKmq5!BEuJEq)GaCOp;5^lB5HFbvhTQOcV7bGfK9`3xhQlRB;CW8`DUx#2C_Qujnrq<{?x+{PNAyLBI4 z(NjPQp;4TuzcJyI1pK?d_cd5dO2k=8nFO-L=CRkZ1=bv>ZP(=-b$c-I|EFo{|CvYs zm8bt1^-uE0e}W9SQ(b2XGyx(e-Px(XqW+Tl{_un{wMw)dXiGCAO}XhRX&J2GQuQW zo*vVN@~;rc%2>HkJuq@K+Ds~>|pYoL8W{dekps+ynkY1jPq;H2?P? zl`>_PE?>YaOs>yAzK(9Y$FmtI0+S?(!Q^mkTS4XW*mG?ZTvz?JElU}B;QMHId+2og z{M$#L;8+BD zIh^nQ)+x}YX)+4fN&Cmu{*npZm3u=btZiEXPycxAmQ!D64K%6$LH%RuZ&M#pKg^r> zpHP>#-YnM=!XhToX_pFG919sc6^o0N0P6| z^pd2Nxkd5La7crYR1?57U4z90^J+y{1&8^qtMy3g4pVTyl_grbBZRtP++uP*8K+C; zEKTCHmzJ;h=4JurXB%a_S?#Eknl`yJox=K={3FKhbZGJ@dO`!=-RWjAQpDsjt%LU^ zW#;gCLn`A}J?NeVZLp)T(0~z5OCxl7_zBgc3R~|Rn)`)ot0U!@AHpEOUb6zbT!2sDf+29)&cICvw~Uwa zy&k+q2^Ldz2;Sk8mVvg*`z+JAVcX{F)}`zE$!_Vx*~bJcOtjJOPuDB#r`b6_))i=S z)s*%3V?)7oeY1#PQx+k6yVi!mJ6t1%Yi1@()04e9<0T2z>GsA?{hWGCU7dJ8K}+KV zI=gVXQwu*xrNh|a$8by-i&Z#G9f3`tOTtJc!$Fvqxw=d-w_a4hX5bxeB?8(`o6cM}+ zS8M8l^RABzdCE!J>00)h!}Qubs@oed(Vknxb?g9|7+n%gV6$o7S=BIs4BJFuv4X_b zvHWNa4!?`7>7y>XQ^~huJ3y2&sd@84vj(qTp*ND5K$hln&Kl3w*`@S~e&00BFD9WF zGXo(g5;SO#xs4=ipW-`#pN4vb47T^EZ8XW|iZN_^*DX7o8UkmU2#gd10UQSZ+X_~?4YW-Bmj>2MLw&

C{f6Ad?71#}}5t;pf`IM{yf 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 diff --git a/images/avatars/gallery/Flics/Flic_100.png b/images/avatars/gallery/Flics/Flic_100.png deleted file mode 100644 index 650c32d7e4686ac04fad98e578d66455c6df846d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28343 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 TIVD!~00000NkvXXu0mjfQM=!z diff --git a/images/avatars/gallery/Flics/Flic_102.png b/images/avatars/gallery/Flics/Flic_102.png deleted file mode 100644 index 0b46809d3139794e4900ccdd8d9d1c7f2b9fbe9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26654 zcmV)(K#RYLP)*a#p%ku61*Ap-{Dw*(P_ zB*;So2=I#�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 diff --git a/images/avatars/gallery/Flics/Flic_103.png b/images/avatars/gallery/Flics/Flic_103.png deleted file mode 100644 index 1df04c68a32fcdc325a2bb1d218927cb06951ee5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25241 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 diff --git a/images/avatars/gallery/Flics/Flic_104.png b/images/avatars/gallery/Flics/Flic_104.png deleted file mode 100644 index ee47e53317920bbf17fd31445deb6a05359ef7c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26302 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 FV1kLLylVge diff --git a/images/avatars/gallery/Flics/Flic_105.png b/images/avatars/gallery/Flics/Flic_105.png deleted file mode 100644 index b3b653824ca82b36de6e2d4925d8c67268401ae7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28477 zcma%CQ*uuZ<$oY=PQOf=z4G|9x8*tTuk))(70zSy>H-TCiY_x(QgdFWp2obFv! zyK3(a`=ua-1dj&~1_p*C{X<;o-*puX3>*v=`rm3{+LQ_m%mz|gTvWvs{5(lBmT=H( z=u0rg;jt@TB*OYf9X2`Q5HzWXYfwvIX*eB(s`MafuS%KcJ{B!yRQf8#j9m8d1jz=LqoiJeR$xZa;Arn8Ljj)5z}_Jl6W>rAB_NW>(A@b z7iV^Of>aN{mKMfy*Kg0Br!<&7;mfCw{Vdn$UkIARWw`+mHMhecfD@6^A zr5Tg38P>sTI+G**LwiyED3tE)(V)wk`PZCmm*w z(qT>uxw0Xv6BLeefb}Vx<1u4hIbGufFrszA?-Q1CSCiT7>@KWFD=KtxYVcMr%3}K~ zOg*D!lB>?(NC^;=qqH!*piFoQ{dV8rQNP3e!~gyyHI)_uwre+-r6#L&kvcfvtDMCHlbL&ffDLigQ-6x(&so|y z2u5N%HaA;*Pki4tUD-zbQ774SEk;?74km~io%l9v>h7qctfBfXsohRMcd*6qwzT@H zPG}MxjE3Rh$$Zez7u|bq)o)@*y{&;8^OjE0tMi`vW?T$Gz;*4=1;Z0P|#PO~}C2L+VX*Mhx= z-{K7W2}@M3bySxGVP&R)v?VEHOei>9vQrzQ;T>DX0^6NB& zXA_0p@#7liI`HCqN&0J}4XU z*FSHsup7dm6=HY`Mo+3Hp(A<^;@Ts1SvoQ)vqa4mr~=~K$⪙^tC8SK2-pFgsZX7?e?B_@+}-DaUv3wfeRxb-%k7BG34p0oO&LRfzE~F;}I7 z@3|M@c(dIH62X(9(Xj!20%PiLc++)7%4cI&?({sA_G_SNEHIHnwqJ)H9ILw%sFejy>b>{arYMU3f3jrD(`LvnO1H0s23pL;Yc`uGNI8+j0Vr=dR& zZI>?$j{F%%;y}6dU5fkd(uZ;;^X_Zhl4vaov(KkX#T$+Rs&lAVbNiGY!zc7c=tSPr z#`(elb;fW$3uksiqV$lr{O&d3QY+rkP{`c~ZCDN3s`xo<&%ON$Kea~VHyw>?1`mfm z>RLRL;v%dqi>M7JvJqlO{Z8Nsd(=JjjI{_43S;Mqw!~hAWyA)#H$?i#B_vVXtsA$e z$_3N=a{h^;`5i7$TPK~-$Z$@?FhvyU!IBMadS&pAlKI8&IqDquuxJkk3?x3m4d1;w zH7}A+9BVpDBOfY9AB0u&J$!2#r!D6K)J65(HSIla@;$BCea%5aXcWiyTU-|oCr{C$YM*PWvtezE&M(!6s} z3J<)0H#}>>DH|%4s?C?7kX~jkafSD{@M_DBmw(_|`^%&{3BAgAjc{FT;T-`UvHRV3 zs8l+|R1LlxsU$5`c+%Jc`yFxJtbMUn$DSvfWr&22(b@e6_mh z*KW`b$KK7V0eX)AQ>u1_^a4Zf4ZsKHlSxYhM7YfAWYpaXg-4qlPgnb)0Z$(7Y$Ixx zY)1Gl_H4XX#Qb{_u*$tH9KgNcs74ScnXra=g<7lhqtW%%a}Xhd1R!#_Fz@Yk?O@w} zaf@AG3!!Uk{jsr&= z>m~~TLVh8?2VS(!=jZzmIeEpzLm{QyQ=I1x$P*1OQj!1a2OU%5<&^*0UeUCl#@N4m zvkIc?=0-f7al+pw?$K@LNJu|$u|96p?)O}U`$Fm{%0~I7Z~B*Q;`R8MA}Z=9=wTzP zp&ZEhWUJp(v26MJ(^HZfIz+DL4m!3X)>x-35xv>S%AfxF(~+Se9Cp?Hxq3&cG~0vO z1Fw%W>CDW<47DHCC-wjUbJ zZ5bMq$hu!dJ5MiQmK{oYUc>|?IT!rmA;LoPsv<+aM@-D}^{;?U)TOtacb!4nU{zZGbmVF)JQ!j!2uEGs#{XSQ_kUvT=PQT2+rtUtH2Cqlg3`YUdTMqg~%-TS2mZ zMW#`XNDowcaDI)Gg~#{vfTgfeJ4@v|c{wHMUtr~W3AxAV2;P!@OlyXmQ1~t)@|3g^ z4zcKi=~Q{7%m2hbq!NPnF*OU8hrlxk_68HqAmWxZ!-xRsl>bFHyNl7uF7#s$;P?|} zdQr}FYH5|Hp}3b8*!2@5iLTS(9rNQ|Pq>rwnsthP|1JAv{Zy;AHjL#5y;UgR_QSP~ z>+-GRk*cDIM_@dM<{GG(Max${mv+Xl>Bw^5&A;4EE+?~HB!Jv-eq&Q+$;Al=6&u|; z)8M^vFF@>mmtX4mpnv$7A-f;d<9VX3C0c2;P=kC6VB>4}{NTut7!I~-{Cu@T*xE7a zSp7o@NMb<4af*l6E=~NvpxyR-tBRCRSuvh@_d-|sSo7&9Z= z%`4OG`UZ;>9hsN)B2>*n%f$$Gm?Yy?xMFGL$K3n2GxCUz3EoiME9}>N^l5CZ9;AZM z-;tr$dot8zd&5R3%r1_OFZR=gS~WlQk(ggpc+DpiIfqX^E|F>j9!8xDMTE+KeU<@3 zijVuj% z4DzbvcYpE*@xjD~JVZXn+tEH9o@qS$9+he=De#yDAs$^4!Aztw0lY=&Q^i?bCCSZh z*(7C{S%gGIy>SsVe=;yDG_{M1SI=JAZrZ{@i$c}|HG|heE#~#8$x%t$TTkc$&`;`F zo#AojtYJ!KGiAx56o;Ae1rmVi2R-)qbRnz=_n%(++a`3r#eq`jhlY%YDmKv)z_>sY zb-8-EXT_7|Z69A|%?h$4AY%#fr^&O;PTj({(3%yya&0l`dP;Qn;tP|2eq3@#`%C#4 zM3uw+&68p)%TOluj&37cyCgVUL?W>J2}Ef!RaNNh)D@*FE-18Ipyw8qQKj9p?#|us ziXVRw8l;~~u9==$J?5~fW?&y%c<<%N{>D!D7M9G7`X&Mr!IJ&O>p!o3tYtPg>RCH= zFh?SBIOeAnqQ5cq!7ot|vucfwB2fjCs;sj>z$ zaqlN2AjlwSr7M=TWVU4`M~4yhaCWs6Bb^dYUPIsg@O{7H;Ny)MGIDFZrKRfxQBv?f z>I%bPZO!QPj~HKwk|1ILF}?9~>!^6flI%U9D-<*9)e{}Ltx4y&2F6_mpKgEQQU^%B zj)d9#YV%7^p;T_f%KI|?5lMX{IK1Piwtf6imUYHg>X7i5;Y&1#J#EN!VkxnotTm26fz#F<##mRs_<3|Su(Y3X#Gpi7w(FZ#u8PeX z2@kkWZr8EL*~w%pkoxepkAHJ-#p%N@2podlQp@e#``gj}OFsV8dl`t5&2;7qrSpkb z2p$M+70%HiS~dM+upH^u*HcJJ{3q(Bl!FL5fGPYZt*7w2;Ii&1#LE%=9xbkxA9Fn6 zGOf#B0(*ZbT1P9zAcL)vaeaDu=mYo8^6%2bokkv0cV^O>V_)@Z#)`>VOWI#KFH=v8 z0`~$x<)Uvl31$z7kHBw1CYDQ{$!t62!q+{bS z5iF89on(Q(e=clrZk6-r#C?5E@v1flYc2qp9)RWdmzz#gg8eR!PhMYJpI3Se>|cU+ z1z9)@Hs&~Ee`t&umy$I@|S%l9ttw=n6?aKY1fiHvuJr`}ujJeW#Z?wBX=0YPP zR3T$4(2inK1BwL=MMB})-|848aq^G3lEwwMx#Zcu81E9irz_OXu|O1sjUPV`bG#l& zVQ~rNw9e7=JjgS9lxuKvy!yW%`j~v0bsyEKo>PG+tl7RW?oL0tXx5C(e_0oswOeV# zAQhPTy^-))=8X&ckja@Aa$KW`z1JC`)v!Lm$IzqfaE`uA>A5lBX1*7(C}LH*rnmH`|P)%2cX18u?ii)KMtykfA{R0V!?eC7ihl zVS`Wn!w{54&@@gv8VB6TudmD(=sWH-Y!Gl0lckSxSOsU*#9wYLP@eIn`%|)TA6vRa z^{Ze&aBmO(-hN-$PdI#cOQ~L=_ud?`tyo!Xs2H%+Aa0v+TQzuPra4h9Rq*3VLU3rq zUeIGB!D%PcFtp$;*lJR`F8kWcf7sn|gW9p$wCRD^?J4Gu*f$RfXL?g~?zFG;7kGnZ z@1zK!bf!-_y$b!~&Y(F$nU-}PN?0fW`Y&`A*igscP>9uo!>FR$6>q0FjvtSEhVZ{V zy}mX0N|nj@#@g5vd$yL)r{>G!iNfztIm{@78j$*udFfKN_5*HP^wm#4O5ZXRZ?p9u z1Np0*99obz0<%W@8Y~~W1oE}a@sAzN5;X-;C6wc?zKFPYT{y-)Z8W!C{+t_wC<2R9 zXjY$EMuc~7a(+EbU#E9|iZY&V`0btD2%>eZndQw{=Wmqe&6zp-#rsn$;0_MoH^WlO z5inY>g=OduE-dndHr1-ZT)R&@W?Z6r4Pk#<7QC|BGksq=+dKrsVCFU@NKj=+ap`{N zQv0>-1i@_4=I!*`#Z*j!>5lTyXPet+UPojtgL}O@`S!>(&mKHEPU4Y$dPV~ z4|59Ty6vI0#)UVo+O|oU+5{9CH;x#=8iyAdpF$mB3OQ_^N4I`I;sjnl6d1k5dXw{YO{BmkWp?0Fx$1)cQT_&u`S#$I!Y>7?=pal= zt8PHO%XdybI~Fbpd2YSAjk*`IOi$d+9zPn#Tkb}hS7Og&e$RKjUFdc^NTq4xU5Axv z!MYMjyIb*Yi)En}Rz=jx?p3`myzd_4F^KfHd@$zhYIhH(nWwpm6w?mujXY0d!RJrv zD=21O>uP4fz*qFur~}Xhwk}tFkWZdOuMaY(A(KCm)wP1#7TXhnsc|=gYb-3;Byrt3 zam;GgxW@LPusZBlT(wzrmlW2Q;=r~<8=M#df5K&!aAgDD7DAX>?(nP@mrQD{B%EfU zef3Z_1fv9v4YX^=yvWS8BHOzgbKkjCGmypH<$4KFZ@O33~2-u^$ro}o_N0L-9mLbuL8nkIo931lm zKh2kF3J-?RY-QVh*pL@jG3%!;NSeW2qtMnYFna0%TwoWQyb)~@*ub`l zX#c+6{7E4hMYFTRJS)EDz*i#Y0w8*AeH>SY=-iE1w*ufsdoe;NJ!7ou%|13f|5<9Dk9Ln~~2J(<@w5i(yIJpQv$NL&e)*wU}z zbFsq*H^FuYQ8f_0HrO4Xu&>teI)P_fFd(f~6*TIWG7djK>V`AGf{?0@TJ@*j(b7-z zjEYv{!bvf)3gx$N!c$B7`Kx}Ihg$d}x#>(*xPlu+hEzh&<{i!A7VvbbRiXrPX$ z-UPKa+GkHd#LfbjfgaWqR48Tx2yKGmDATMwThtte=Kf%)g?H0%jww3!_7uy~(D0h) ztY%96-5c#w&1W9k^R(^EXRFEBVlCxIJ6-8%617Je6@TedYGgPfnjDKHc+Ga+$MUA# zqX3yPsNM@(|1BY-O+mvvVGszLB$~oTh~IS4GiC&v3=x1_>`-u!)^KKX=z3=8^0cms z5O#S{o9!^C#Di|nZ8e_WiKXrrM|4WNSTltRzYc+iNbIshwAmV6adMm*>> zOl4i^kVQDEg^ZRp_2lIWIZf%x)O&aAoP9=nHDR}P%f&5!u}%(hwh-v`l*zPg(9_kp??6P6`2`gX{!kEYo(Nc@KOJ010nRoI^UgIn};DLG-z#-Jnl8}S{Xq=e# zm+7(n@V}>46%X&&P*$oU%XapCgUJ6j4Gbb~R`Y*UT`5{(tur+5_1!@nznk5}G>xsp z8c40F)h>y8#J@Pcl1J`Nnb|HupQCbdgCgSPJu%y9$d2?@fmPVu482faRXg6C|@*3Ot`~x!5^JBP>V*$6Q7_&`A9?gkym9 zrhTLkvUvp{BGEd;tnXZz>_8(k5&x*VQFN3@+%MhR6HoIHAMrOuGD62ae~nNqB(0EwZ<4BgBO?^V zh%5L4O#f;)XcV`2>#FU4w<3RtR6N|UxRpp){{VXwK^ST4um${UTVU36N1j^TrK;wI z$&Z;$oSQhkE5|z^?L{O(uOx3O@((eJKMXrYD_LQJCC#L z_#7pC|EwV12{?0M9UJ==E2Nj_54U+hWa^App0l)XaQ})B2o75l@Zn@ube4bPb z#|+01CsOOFW5ExiUv5S>;a_6a&s_0dIG)3RE_aFea&yUITdQE0VSi05yMDf-3AlNp zyOblXYn1NYUbtzsaR%VK9I*(t`)UA#K@PNqs2Yi>gkQ%#^4c*BXlXzEib8kUYQFWd zAt5H+;t(_JEDx{{33G+n2-(5I1jC>P?u;Shcp|Ua2h;x74s4t(qvWclao5&82>RPT zccC=TDgBgz!Rl2ZzzD$jrj?4*Go39Ao1^VkwK??gf>$NaygfT<=4o$%H|G$cUdmLk zaoIy%iUvi|F<8|syd%3rBi9qpn_e7kz!kA$@28h!_qt6pMTk3W2jJpWkt9tC(zlg= zj;>VhxZkj-XEbw31$s|={r7?o*{fOcC;FUGLdyFkEe0^5E4o)4SQW>%^(Z4uenu)X znEbNwfbaMTx7o;F|7>KA)m(hUq6^H^u*ltWGj;1Sf1!2Nn7wG9PWX}@SaMN@RRPD3 zYKhH^Q2tAZ01+f0Ne@MUN7!>BX2>JN>t9e1kcvY`YPiONB*v?a6Ntaaj-X(5A}@QaQYdzRDfvoZRO@4G46nqe&m-f zUp-ttx*&!jXqmAr1tJ_u6)_$jw$On7Z-`h9BgU3|$y1z&s$=a$N9`Za&Z7ph(+#~?Hc%) z@E|M1QuzXZ^`PSj5@}YAp8+yMj5DSi`QiKAD+=lckJ3H6H_r#I*ompk#e=GhcAlSE z6o?51^$$754c z{W%6%QO9o5D@e3p!Qw0LN^^#TC+wSQg9& zbt8AC>F)j#=WT#bg+R&S21b+i;ls3r5U!UHoHwY3wTTm}oP2jryM{LsIdNuM|48=^ zYEbN^2M#^aPZK<7@Pk_m+AR96w`+2ltPG!y>HXhpAyaVtX^2fH)^#Bf8`_NT3>&uC zL*C%P{*K=J)Zf)1M&q7Klo7A@DFGe91D1X-&SPT%BG7-@cz( zc>EMM+lxaTZm$k)%DU0+>q4zFld#lD(?Z@$2zeDeAPoBeqz?>Fa5aI+@9(%lM&Y*- z8UvEnPPRLnb^0&xbMggv0(WZRR9qP_$43rtS>zGYt7sKz?9LM|+v{{JId;436Jrm_ zY~5xnT`@!82Pdy;^>K>J(wB@$ErwaIZX29;Ck#jIyh0?0t|z#=I++)pg#Da@R`Sjx zZkjB`r8@@hItnqKB;`pgxbR%}lD@`0(H>UOB@9RtM#*$(a@jcidv_EOV6uV0tf_CN0c13P2*7!hUh^*fT53g*eva;&sO!-Y( zs#k)a_v}25`;ZnW%|Knr!}q0IrGBf+p@$=x~keb%hQ$K^}||aXI178I+sPwd!7z zr>3k(8Wihx>6ryqVGnFIT7}^$lKv^pazvWz@B{GuTc`s^G95d?m+1Z{tF@ihrd|JF z>r&*O-M@Ux9l8p{o9E~gLft17GsBO-m-6Lf`7W^11I=68d=Du5RDk)vEAka9@)WDf z-h?s|D|0%?ueP$<{7kana5KHm^UHI9xo;pwae}j&256kX!k6n=XF%&t3`2_`C3bF)GjZw(Ym`KJu>-v)W7@?Vz42~&b z(OxGu_+4+NyJLPbbyFLD=ce&?_Lyeq;k*Tj6U4y?-tWLL;Vs}DR*biJfAGmc#X<|B z)%6rd?_!N{a`2p=+G}s4KkujiUBe;3?H^?JA^iItUqBB#<*Mw2ibb)(u>_g)29xFC zfU<3t%^XrD*Bn%9(XnVb|4pvzihP@Y%q)&CsRo$SKo;b}1K#k69&2i39-Kh+Mq4L47kyNEdC{#1IQLkv%A;XFeJ z-S?q%#{_A7n_QhW@Ca;l9|yJMf^E)rT;o*^&PX9Qm&k8Bh*4pOQGCvr*b<%j@r)KDk?0rAcW;v zvS(6zbg*&4@9|4J%0 zOMx0-KrFJyrbPd^6xXUd5lk@s$X`o_#f%m{&VZ#VCIcoHKv!Cc2X0`51%`Odas)gt zOh6EWOlzcn{fb@fx@mzJ={S0LY0zLSK>5i0k3@|fx$^f#OL(EyDyP;E|F|j18gEB8 zw7eU5@0*uuvJCq2n6}9=76wpnR(@{nTYalx|Mh0bL#P?SW~o%! z@3%{eni_rl)t!h1UK!R+m0G|lOL5$e`%U={A1@+mG51t}-Bgg}Z(IA-y#+0wF!Z1|Estt~H^$KEGczc#KoW-QgLJ?Qy9+=pUQB zf!=X{E6{8a><$#bb{gr7^5>2)gvpVRGRL?C_7&w3|rh%5b9OVXVDT9hcUIFAW zyOF9Xxo9oWb*>*5F1F_b(ujyrrP19&j@oJpH@j=ZdyD5}`WCb)NVF=Gbm#!=Ki%;3 zx3D$f{SA8d+H%yxE|cmU+2w-(9ltpZ(1 zA;*${oORRu+d2ADCqT#J4yPP5Lxo$mkU+4>w8AcsSm(R5DVWsH?4YTKN39g=;(yxH zZd>^H4g4BW6-~khOl^(`e!|O0wp+H;5sTgD?h+{0+UJhW5qwm)r;I!SNAL+p=k1uQ zs(!DDp9nF_yN}_3K;SFL5Qp{%qb3$d^jyTu5nqfcV-Ql}e0jVSU2Ex1O)r7fX>yya z+R-eV*Hcx~E;W?I{{#k2D9vV9p)m?HqPN)0(yXqQ3q&cC-}ZP)pzXNbROL*Uyng02 z;zV(4_{E{UUvCMU1^^$w8{tiB@>f`|x1eH`BVa#UcDw+{ybv(Vox4l=Mr^pZuJoQO zL9kD>9zbK^TOC{yEonA0OgLnHE{$K6n`mmSMH=q34oB}{XS*RrU+&m5h3uIyZ4ZoM zSSrXfFfruyL;D$Z%J-Gb?7S>+`RH6WmpaouVwe`l$%>dSS(6@%eWf9C_`{A~A&FE0O@Txa_KH5GsM+Gi5Su4NOs!48RvO2*)3& z{O*1Wi1BVfn^B7@hSgX?;LsW!<1no{E^8!8(EFZVzS5P@4NNBg^J=_M@}+uiiL)9S zR2mhCyNs>|c*eNmV})?fKjlN7H=^F&WG3%CSRIb$(Nx%|}pBgp{c}N3jndxQLcoEuk-ikSDFecK8t;>b~ z1r1dD+({Ggv-k@?k8`thtEfRpob@d88L)=8?0W!u^vXiDhI*BNqByXbSIW7V{KG1H z=4YiReN~B#zl@!Eeg|0FS`~+nLO7Y8<+?CHG#{m~%Io957juO6i@8N6)&C%l(&i2) zbcmoLZ6qSV7mZUOXTmLZdZbf|J!tL88CQoK>6@7WSFuMnKCzWwv_ea+hZ(xQ(-n%D z3mL{N7kcV*CJ=DGk;Ng(_;prv_g-@3v*5 zM@cG1fF!A7cJB>!d*@4ta|L)x31qo6+K%#WL@{aNajn@F(iMNn`{&S^DcD0T9C4_UV;h2|Nodug;qi;)gFGCE2 z#AFLy^GuhZyo?EE?gfH7?QKT!Iet+dT4vgCXTPWY>HLX$ue=kxvH~s)B&bJRz zkkrqZlJ0OXyeakHjOxE{*a%03?Z9VfBUT4m@#AFir1}y7=gE=E)kpF+P79-{s@Hcf zTD=i0N({Pvxdtjn!T?d)oJJN)w5BhN`9hBG1h+u~V@bV9Df>D&LoNKFj~m?Di<`243E<@iM`{rEx!9f6(DhXEJlebAkSV@v}u#D zfXHyL2iIJOK`Xp-45Rs9RV!O&&P8HDu>V(NqnpUM2FT`+Ajl09Mh+410}CkMQ_uII z+K^#R%&gKA0u=M<59vYj_;_1!Hetv8zDEF!20mL6H69LLzdI8J{X}bxyt{^5-1+i5 z_40+8(-!(m`dFs{33T--BD~(XFnvTdcpRETSK$GHoeW*;?bCS%>nW8JBjo=&O+8Yv zr~5>Nm&z^K=-X(HbUA&nqC7MJSGZOgV0?6Y7TDdhkkO2RJ+r&tO@e596Gm#E7hU zDgH}4`ZXTPg%9oylMn!3U*kVb=wHRX@aMeLLx$|CDQ+73pB^W2B&H@b0 z8>$$88H4j^Q^NbBQGk@slXRZ&f98#Sw$`$ucJCw)25aF(^j$xKNg{p*8^*PK5iV6Wc=kE%T_9eG4y9WEmo5 zB2T^APW4J7=rj;S8@vg%OC8iXQznc&khKz^&nal`EtbM6(x24yZ1s*hZgRO+^;LB|S`C8qN)?s$e{sW2hExv$kBY}1 zOnM>T3FQ5#G7foIEuq3WHxGZn%@ndUZ@38Q%`H#}$Hcx;IKiu!$79AxhhzK*$5(~N zl}J2-!pCc$=+ze+a}ls&rKp4u_J3Rx=3WMev}$(7aE4jY9t3}O({-_{9OM%gvIT?H^)DgXX*Ud>z@uU zu(bsu2#vJw7~NsJoKUm#u!g(R$rzfWrgEKI20Ju2g_na;+9l)v#`c>vCrp&Q64&mOjnQVD2nDoMjdE$-S|J(JI@ft6Bf6Rg!+x>9Q& z|1l53kFAL!kIkwq4~ztM;9DViNBAR%5`;LZk4~;OL&x!*vo}zrg2xe<)?zpk)L*l@>r= zTC*mr9Q!meV8x9f3~THA;Prt(eG+Uli!0di+FQcoWQ%ze9ZgTYNzgQ}Xjn2(&)q`ZVZ0?7pqDvBV_ zS*dLJnfBlvVfJt6?MJ13-9B-YHuai8hB$qv=T5~iEQ8vO!&UBrYZqm2Pod?1&O*B74kB*Sjc zwXeN;gmr80!%Oxs=Z_4<40+K_Z1pAi3%>dp8`gia1~tgYL|4zdPoVp=7@eNGY3{P8 z;Wzj%=G!)XQ^#NoRL8EL%L6MyEzU5+TbYUmu^_`ix)(UlHZ=Z3SQWn^4=#yh|3iwc zI80D^V=-Ry#p_s9-$0|$G6R%%vi0vV-m$Rw@;@oH4~1p3T0=w4*?dtJ%||R!uFTrq z5nFE&ORQQ&3OMr|Rgn*% zzGEEn7GChcp>^4FhWAfD*U+3_qS~c)d^Iv>s#JfjR1njUhHbBgiR@0{N91oRG=PfA z?m2EE8=)!#bo3$#71yzN`1pD%E78ipQibYO1NB1-_QYJ1qjq6@9+>zrzxdUP=ikg6 zKp43PYqOY{191m5U^47zAn|u5{aa7n59IcBhEx0cdjakCda2=?`Lup>qyXEj3|7xY z3e*yeyT6_~^+3+Inx2kUXVoXEb8Zmcgs|}^l|#c@@N+EBuVv(&I`(Q8PB^q!*vpmS zn7!*~5{>gVGA^{NUvrion0eKiif!#YF`?x%_6zNRA}wri=nm>93D(=lymcn$WP70i zKvqTS_$}Xd(<%w~9zwRkDy=+&RFC+BNY4VPz|6YACPBbdf zvH%bF13oJU?Xr1MgKOvf*L^0bg&}U4?A+){q&->mOXKiQy+S3u4}8)DiRtcIGYpsYgxmoc~Tj!NjU-@Oiq&&S0oj;;0Wk2~}E z>26uX;E{9+N|Ga-c4$+mthgi?WB;$%KY`k(EI(4;GqSV?W|auRq428C_V^H3n(R2x zI){ya9pJe2y;V#L`u$T&deEhkSNR-`{1kj`YX6K7@MV{zhiWB28=&1H;`>dAPB}ya z4=vD(D-D4yhKo(AAGiGD4+(CmnHeHj0UfnMcFZ}P1CtDYm_KdmX~Xc(Dv)e~|6DZt z3dI}~n||eVa=qEJw@2;zBtDozWEoE~!mw|Z;4)rVYbw3s(@qVTHxx8n4>41rU^P|K3L;kil z7y`Drlj$|J()~f8U8%TL;++%zumy`Ct{k#v%!+K!8CHeRODrV4{4R#*v^T?Qw2O$) zeRV=;O{r#yrQ5ivLUK7JmW{a$bI{z*s;(7cwN|Q9K4PqtI#m=KD)o(`llCu;8K(C# z>ig!C2vBvsT=SZ(WX4YEh3Tp9$s^&>9pcIAqfRL z>%V#mYRLwpLatRU&(*LXi3=r7P?$Y1&}!Zc5IM`x1&bG+oA-EkbUXFW+q@M;<<1N}Si-*BBB_6+(xumJscsL>grMXNc(O z0VH4J5?z<<$mds9CSXuYLoi&>zEIoN6x6tjg%`CL4UNjD*aD+%a@Lly)k<{EfA&cl zRk>n%>AQIMPIS*!!V%Ktty+AJ!5>Q=S@Nxc>Ot&O^vVBpW0%amx}=_jaM`N;$bJ}C z$r2D}h72QrdD2#!V)yucF;=>SMNlwWj%swP%|7zN9*MpJf9#~NCdLBD=2E{Hc;qgK zpTyZtc-)4(N@d!0C9SiY!8sm|l{ToCfRCwv^^CJdp#PMP$esFRX*hCkc;46Q~ zA@8ugK8wTPbVWiA9Xd>wT3jC$V{(#Qj5lhhWod0)(4zA_gUMmu;v0;`Vg`KEXDg(m zT?3QjOlgo2+oG4GWwW@ORL2E1`cHOK*?B^``v4LK%Sn)X2y+foM9qdJ{c$wEzsQ;K zlj(JGnFt(FKdsZg11>;KgaJ$S4D*R*Zeww=31r$3Jzu8zfR)))@4-7Z>AA^`2(cmu z&prpWpK6k-3pylEBHy^iK)fr&;OVn1iz%f`ibJr^RSIk`STOIcK@`uAGn7@ZH{;SQ zRk0Ae(wv}Wm>ISJl&KIjUCfTIX0eKnq^lRr{qQqkm%fyO-O&%?0RFyHjQtC5*CtLD zZpjs;LWaBn`j(m%oAT)cnlknLXM=)BA0PpFPD@2-Z?YgQSjF%`lC3${)V9ixTx9n@ zhV+tgpu|SlpG~n;nn>n`tHblBMHcAT(B-;2*d%WAAln<_rXKE8u2`>`6Nmh9OlQLS zIfPnUspIW6BfgB8Gv>M~+AaoE#%{xg%!*%-67>Fdbs}v^-J}DDu8h1(@SM56}cM;%9Q7S9n&cGqY zPaPH|N#TSunr(nCVwy@T>`yOl#jmkuP;!Z}KKjX(?F>prBigjUgfm3C?r{lNjB>6( zVmBbei$JCirbf2Q_=m0}bFX9e_?-SeMm4;^p4B&Ae`Pw=XUnW>*G`Z4uJ>q3^70mh z7ew?MnxNgKmbk#@vqkdL>SUAoZ-_UDkcATvU@ew+VA4CZhE*sjFUJue zMPPM`F?OlLf+*G-{O|7|2~c_ScIzfuF=ox12c)$L03hF8F|r|36pSZ&yqU0;*LM|V zj9@V+pV(9}wm>9=EkjVRVdW?(HoWmqs;LVV|L#jT{Eshtz7LThTea7$JrdC)>!q$g z?HoM%zHXvfzlIIZA*ZWM^Q%;J*UN+uV=-kFj`sD>;H00PDq^*I26q?DojDQ{3sG); zlgrYQ(frn+J^+XpAdf#guqUjj&@5f}j@rIQ<0OKaI_@~_yrvikF9*GpGi}1kt}Q}` zt2P~4!5i33e6J{GZ_Sl)t?hHn&Q^8)5_?lr(JAj`%fau>*C%iS8BJ=fxHg~q9^0RM z8BWScIcVB!sfsh>dJj80lbDe@A({zXF*mGN8G@!{Re&uXMu3NfYt?12{zt^LA0fUk znKpfM+yzw~<*8KBnaGr&|DZ;%VNmYXs^W|-9c0Cg=(}=YwBv^288)};lyB3e$PlqW^P>X8Bka#tbm6m=`96WE3+i{%ejG!E#M3=t>LUx@k;$ z$BUC}cYH||eP|c`Qp8zV`K?yFibg8VEIItFRNHiS<<240*4i#pvS5<`q6-ZG6*jOs zgtfKOGqlK+HBL1^r4+_r=`ko|K<<%4m5;b-KTVdDjVryly1GfHEK0r#`=Q_0>M=tdDgKMCIMH zO%TrqI)*&1)!)ZHkVzr+W`RS8YB=5q_~R}$wl;pg4Y~NmZMsMG4@zhYw_G|M-bi7t zT7Fws(0n^)&1=u^mjc$)TLt)>+aAa}b}uKi!x^pD48?~`yR++-ivU_TSQCNmd;XTwcD4!HPkGF5A?&Kd5q-?ibR9Y& zbL9MSD76AOUZ?u#Q1=N^y;jBb8*d_> z%qW07*TLIjSRy;p^(MK<~D(|5syblay5Bogy&o?Xr9kGwQ>!qObVuD22ZxTXD_};ps`3j zB^GC3n8tf_8k5-*+negXE;NYxSdQ`(rcyd$ ztiNJCK+_Erglqr{7VZ(S_pv5omk8bx z?$KG}1S~^`o0z+ZNotG$#uI6zQYkc>O?Y%VLx0!|_S~QSw`hf0>;7WP4)h+lLRXS<0IE`FVY#bM_(KrGVTWX@3~=)K>om1$(uIl$KJ?cGg4dRScU*Af?1T)&eYgSrq-0GA;8VbAZEo zbJT+t-p55`QOCJp12N4(MDx@DL7yv}mC*EoIlI(Hgu$j8#Rn~G6i1UH+gN#kTkpQj zPThdcBHp|19v0{$bZDV7$(ZSE9+zKz1Ie*TRhT;p+#kn^Ud7U_cX-bW3%vtlIJUpD zC-x-aq1v)M3;3-hQ~%P7p8$Lz%`a9w|Y8y+4~H20|bBd_@ZowbH!Ciz$m z>7=8}jeOdAl#0O*G<@bwkfCrrKJSWTf6ZY7$pa;%u*I%3r&o~Gn~KaazcRx9o{8{T zXrJhYzUFz}C2as{s%Tjd8r#vp1+z$f&%+vv({48vWP_p$mFjsM$}lZDk;&%`cJv6W zXk2|7W&~y=iU@yaC(a=|eWB+7p4WL--my%Ked(*nWD;1re+QNAO}KVjotkBFY^nzy z^A{LZ#|^@<)_Qz)4OH*HYdpV*32$4w{cHUY_nXjN!445VWEDBCwsM=mJ); zax5Sn8rQHL$)U{O+Q5AZ!yLsHm;4MC{VdGD!=!H@jV21HDt9~Mz^xmmam%rtOM`B9 z3rQ8#piN|PHtID6+9U3S?z`M%f?*P(cq)fjGK)w&qu|obC=1&n6O?8k&`iFi!*c_a zDn9D=I^wY?Av6h}g-9%-#%$JFaBLS=>RCh!3Fyu;Jb!}}*@&len3$bKGL;VBi*Q`u zQGiM~?G}G~a2y+}4{l>?ZJA>Vh#{C7-Nm(SlsDE0w?nrvhQbs!kUjUeNUfgqAs<%g zfsb+|kA|7TW@Hkc7VfFm2jH+UN132IkPy6VOd$@NZr8-DwvCL|I?J%t2+_L)=643( z-DhC};Ku3#wl`Lln~5CV zhw*&A?<*IQ&~=UD>dL`lgiL^S`E0vo!zO4lhH3*^l*!CMGYDwYM19diG}<8C;+O)t zPEZXxCJV!ltMQaFbiQro(^!GQGu1estU>axY^|f+s3VciVwh&-qCr zpt-d47#5Px60kTlu3I2GXqb;PdDr0@frXE}S;RF5*R4%;&4R~4y$*2NN$=Bs3-OJ> z_}nmz1%h^Ew_B-h9qhdk^+pqwCIOI zQV!;6CiljF?6J)!OAK)6Wlmt=m-ehmY#JpLP(@m6vvc!6PdRKX&UM2y?rFAmW%uG# zadLC_EGXrIa=%mJT7XnKf!TB8n3~On^za$q@z5$Y(WbX++Xdn289larNxjp15GE5jvFC_tHK`w-0DlYVnwk z@lc{+q)<20Sc}go=L$NGb{JtER+3$yR*+M=pqG$B8{>LS-4O_bli0m|f~8g@Xdi2u z_U+w;BMzZ>*uyDyGDo230*+%V7xKMs2jshSu2>-fBW9wt)qqpCRbhAM)H*Qr=g|8W z9B}6ph=CeYkJ9yG79y#Lg3E{)>blJ1c>&!}L)&hnR;}#FW29;J&TEUhbI8Ya=+Ujp zQe+&<@r&>~UspuvTlI)|%quiw#iz2drVroYgX zqY;*1#1fg*$AOkyKQ{<~AI7EeCGPqr{_A1a_d;tKF=17#!QS_Ef)L3VKsu`6 z@?C+=BXk6g&^^&wOdV!2qFhY3^qw0Jg^25FHtJ}%S_hg(+?b7NF9%$rHgHO#Wh79H z&7#TAwh>d%9c3IDXx-2|RoBpBXh0N4N^9Y=w#LbKE-pCgWQGKb; z&niwyh+FX#)#qa38Q6MMNtS%nkVzalXx-2{2i}B*W?-qqx@eSoW)bt-3d-OlyiUWq zVHof7^ADInyuS#2&xg;0(6K*gvL@GY;W+kQoqlKR;y~PPH;loq-(8?3KSf8d%drl^ zDqpYHDzFLKsJ1P0$vQFIBx#S@ofGVxYU+UJ7H9^1D~=6o9Gg}_)uE@EJ8JSc;@Cjz zM)xS!{S-F*r1~y^op+ZJ58BAk?M?(X;C)@!iv;Upf3gCZ@A@O}l;^ovxOW#up;Oj%KZjMs=IdMRDQU%X}t!Ah2alao_TGi4DRV3ACoXc_A>UobqN)w32;+UAb1S>XqprVp_7wNwD zZhxxQw|gyvLUQw54}QlrcAg>dV5Nxr%WEEoZXHvD?73JxKZUW&FVo2`A~rSw-*rv} zWD=(aGzkTp7C}=h^nTYOam1Y}3bp%cGciKfeasM=--%deji0%PIcdGZGFa?8^VN_{ zWt21YhZOAE>LPye(;wnnzxPK3AvUluyCJnuT)a!otFiRHHTs0yCrnb{?arL?T|PBk zQ}DTTrAlc7*}~Mw9wKYm+E~Zi|Md6RD6a7Lh^5eR_}vr9noH#>KD)m}SMwdNp?p*a zwL3IThm|d0?knFRY}4FpFNEwA#i;^KLhAt5jhc}{!%SgiV+)nr@4~a&2*e>q=)MO( zFm3g@i|6cf)8neccM}TyfCcZfsLhAhJNL4=yehK(>*5sB6h8a-1I%4`2CuyFR(Ned zcNMV88>?8n{V{=d9)VW5D5dS%quo(lxI@q;ksg!W{e26w)oRjp{}K1^e5M?8)WeZ| zkjA5qsFR3J;9G4QpUy9!Qmsp)kh|WYA5dS&8VxH3BND^(o4Ok8as(huQO&;O!~`fvVlCHha_~X=r)(t5_(d--Fg737k^7HSbvT&Di}hd=0F@*4)ujB6#o|aLQz*4ssOdZk=lbGkd9J6v_pAV1W2EI7V+^}6rTU`qxqiV zI5VL2haQPx`i*ZRnwvy}?p9m53thU}Avl~A&dT~0KAm60jcd=qGL5jn2%776zx53mh7lI36zI}Dtlht@#v9dD_V#07Yjr_E z_v}k=Ai=!)p%Cy_7VqPyKlmQ1m9olZP{`^cu^87HeWZSsvj^dHl5?xw#^?8!P+^0T z^#=hRCy~+2!mM!^=b?sR5;A3aY#bBU-&AKU^PHtPlc34Q8_@(NU;cHpN<}m`U%=+g zpTjP1hOPYxLW)NY_5SiIQpp&uUYHBrhXrf5ZJ3t%h@+*%J%${-6rXLk=xRU4SYZNl z=P%OPQmAcjDmRmRx^5iGwsdpfTwNqomU6bJxG0@dpsJQjc>ACJ0c&(wV~CTGCy<8r(xH&vG(Cl)%C{&So2zSXe=(91@#$SEtQC4 zZnB^{yJI`>ShP}zT~{;MT?I6KNa1#$+1}c~_x|dCVtjHM6I0XBJsVE5f@m~)sJqfF zcyUVsc{1~@C{U~(LAq`0yN?~FWSD$}bIhxzIm(pltOnG0Y);72C z`Msr{YswzHbo~ml7iaV9#o!yv>vtP!7R!tR6t=YmSw;v!8iz1g!sUmaQj&g?(^{}urEM$YOBn7Sw zDPXx?tCmr%ZsY#lTS!Dq%uExy$*Du%5}8ZV`26PkxOMw;eD#~Zjg8_e-uuNra}6$Z zW3Yot{<^N=(v{~hHG7Ut#qEtJ>uxvO>KSpvrfuWX`32OuN1CR?=k=?X<_OxeSh9@- z;C_v-=BU!+tU;PnG#W!LKM{_9h9Q$U`=E70fa8Z1Pa>8cgX=h|8xJe|0g>RtU(*aT zt;~wANkMIvEBNHjeSGQptB6G-s;ft05e1t9i_c6>&nZ_cZU`&lA6cod*@~*@TD8iArX(F-SBt~&+ygfsJ9Q2w`E0Onilf;NtNpX&hJ!*e$ojX zcE~|ZO`TJnFqO)%xQ$T@`5F)PhGs@~?1>cC(%L3IyT7Ok&GYDLw$r;WL(j}zz}4q( z^ju-D=$4H@Cb=F}8A%$p6XsbiZK6^xDbV+eOINOAdiDZ*uCp6<%T^7h+bmYsw=lo3 z%KZqGa+x$-o?lBBcQJSL~+V3_7p1KCpvnuHX4oX%Dl zpN46eVe#)P{F?z_A}>vc^O*jTc^dT{VDi!|+@WtwyUiPNm*ZO{dXrt8I(X-Cud}3eHVW zDCi_QD@svsQu$HOEEZ275{d2Gtj=OQm7sM)4lFxXpnI76J(}UuU!{GGaShL0 zc@DGZFA*58m#07`(00eXv#^5V=C-0M_AH*ed|`*1JN)c?eV)3!-`pk}&iLdk z8`Tu7NaWD><21xm4Vr{>$*JjcJj6+;>KGhXsT-<8Cz6<%D!|$WfzCp!vFL8zT|lW) zQ?PZ16L*sWd4aB0n4Ipp-OymmH%$wMZXC&)1qzRi!5I-WS!a~4{M<{g(osS;lQHbJ ztt8*Ycvsf9aG$Oo?n{7YF3jTP7cO%x295sVUfF(cYh+(v-aA)a?M0GqDxXiIn@K$N zph;MfC>5iNM4{{Ypu>EHx)w;+=KWkYjfwFbpVf9eBn7uoD&y1nMO3Qw9YA@Wi^-We zJb&Xg7R=tR#Yg^6iQ&72GK;j%r~L%Z2h_r=Zc(#byh zY#vR5Cyz``6!69?*OmMG{;oAV{F$V_O67OYX&5G_C78jTGZ7Jtoz|TIsh5O5Ep*wOp(MSZZzH|-eW+n%&kFUb-=g**Pmh%bbr4T^Lohpnxm&T6@VuozVM>^&?`=z))PDxqLokV13) zUR_A>wrmF<-nxreJcdgbW)O{91kG12^4yEB;PX#D!2Io716@s`QmdohXkvpa{(74Wd=f+WC}D^+Zl%c$1ta9nSsG7bn(HebNR^b8C-d9_x<{JkaIy7K_* zgiV@U(T%<$Qh;@kFZgZg8SCaGddl1udD% zNR{SGn`__Xp~t(|eT_v$A&|DLp^(e6h}&3Q-`erMbpA47`ROk|z`dmvT)%n|vr`i= z`D!Yi!7FdRg_XqzurxH-bF%(8ci|Fq&f?yKC46x64pxhsXxsJWTnKTsoiTEh6V|M;IyI)~#9X)bx{8!V##+^E;S>-%0jEKE)LS=Ot;fTxN} z>MS0MvWRW8+B>0<@8TR=+f^(s7YR*GJ)5Mpf3EYkYQft%#+SRRvj_4lCnmTKN1Z!FAJ#>Bv`aV7+4F7w>}Zm=1oRf8D39>C$P`D%cg6aJQ9Ua4dH_t3>W^6kUv9TsY0vYFZb7kxiJ74Guu!G>Mj{sGrpH;#ZMvJiqmcE^cX5-O zpWnyAQW4Kyn8owgp23T+eHjb)?x0pFLpO|}iS>^st0pHOBrCsDHX)!Awu$_G%UFr5atzQ%>C<0$C~<$CqDw5tD`7P{{iC%X<`~ zl<#@}mB4+Q-~WR87iyVukK^D^LwpfHD^M>|-=h9C^%514ifFYO{P1@asX*q_75aOw zI7KQM!^~tsf#k9vcNezSDfoJ$iT7{b#=^=vF3c2An7K&MKIqJ&@0)CQTyd!4#wHzR z>yc+9A9UR9z`;D^T_cu)m7Rr|nn2SQCk%Q`qqi5F$FeNE_R@2>FgL~D{zy}31J=}T zH^)8C{bR#0e}|X;nfhz$N7QXu?h~K#DUYWaw9C|25CZm1>Js{Dz;zwit>&Y}%HQ4) zAo62bwAwb-id(7(2Nk+pqeY^$T}HW5g%P9?pLhmNZ3BM04n^<*fIH~DJwsr(Vz3C8 zm6?VfNj`MAT_MhCStf2ge;LnRxzKZ~{Qy&rHh@R9-*y{`gq32W_-$VLI`u2+@2P+6 ze6K&=!cKoYZJ^0|UZH-M`c3L(YJB%YVTWz;@ZCoSkXrI!3~&*^Fm&Z=^1ZlOg758g z!~W29T{(}dS%~B>(mBTAROp5RoYU+euN}{>sHUL9NETp?(Z%99CTN82Ht_KP5kmI- zwP*0k3s=;40dJJ>_?XRScdyLzJhYn)#N%DK5u@Is-lYD7`YH7{2wkpxJR5U-@ic%Y z_K-z*VBe*_fzZ7Y!(Na=YPTBvd=wNZCx3|J$a|(~Vs3hzAZb`zFR20=2HV5y8uVxi z(Ly2wuDS-dx`Dv6j}W+^XH+^}ERrQ)nMr77G`zkiWEL)8n!}Cj&mbO)5;FfFvkve_ z*$c3_HMw6d_s~-Fbi$&Zr>;}qp?*gFHA0swQtlCK&auZ?22DER6hi0vBkB!=?zQKd zr1%}jhD}Es42U++(Yhf8Vi*Qyr^aC#CYIMWlrs*4ZAa0ItHd)f2%VRjq{FSkt#1-I z=OJrBm%CBn3;N#azOQjA6Pgi$5z8nSGotD6nP9jx$=YJE2rizR!3%V=bSiOR$coJX zEiVLX_rAKW1IM-%XahGMn4|u%bEY3te@Xp6)B~!CGaP3Tv>bIAVfXt3>IM}-=xif} zK;}wu4~RfO(~Ldemx9!F9aG~uLZ@SCWgWKT>;qdr6dH`g7$Hc(ZH&|1itwC<0xn?3 zS8fyZdxN%Cq(gNP^$v(8a;jdV;}L(>G)?5ySbpDO|pI4uxFi zK!;*5jiq{k54U{S1Wg~X6#{LGt`>_Y_Zmvx9HZVs*gXH7`YY=HQn#ow&S0D+(9Tm| zroP?Lvp4`;4Us=KD(<%wc!NSZZd$0@G;gDt0 zNzBcRE2o|uA5)Da*u(w$Lm=B|1$b{WK*b&mS$EG|I-1Y57;Fyvj4z|GOW-By1?o?! z?^AzEy+^I!48>^&OAito{ikn(J4Q54MrrkoALg7$FO zI-k=0#n~3=Y>h^11ZR5`INgdWScKky*8+Bbl19+lgw9sbkw!um4FNL=m%-yBSeoiL zK?kgmoM0cg`XfJ<#?16M3S$`sS~Lbwp0%5~E^ynURx1;YB0@k*X zVIn>z+)bFl-bF63B@;2iHid;{zFVn{G|zE{@M{IqL5RLJc^rj z*CT-4q?@sKVU(Vtp5ge?=ngTYexzouQ~#d&d+IN!cc@LuKgR7H8YcysZ22_xD)rmc z?^BmL`5b9o2EMN}T9RSW32gFRU^5hKdplb!7R80RDHtr=&FzZ1_C)S>XpjXkO%pSd z1xyk&Nl9{@p2*YHOzz8wZpQZ(Y5_jn^kI`3edMKSY7YN!9Bp@4)OqSZP~WBgk@`Q> z&!~CoNG2UMjvF+Y?|JGi>bIzWMNJ-O0?N&T(F&>?K0U2uWEEt2uQU>D(P#wc1UA#a z`sOx^D;TNkA5}( zY}*d-{$_x!_Q4_RY-Z;Sj>YBE)NfF~PJKxI1NC>pE78n{eIZg-zN)JRZfl znMsUgQwl2I_xU}I$#Jfw1KqysXUYva*oTB{x&HX>tj>V*%bc<&N9b(*AvO0Ugbn@= zseh*an))%dg^^p$c#9IbS9tGLVr3aXz0M^Y6jNLJiCaG zj8`2AHgUA+i2_W+!1C%kY{xwo*ktZxGL8$gQ%I*0>bEE!k16;qI_^l2Q7*UaDR;I2}aso$l3Mg1@8`_ww+9M!~!1)4yVqh6rCOZ^@~_ln}l z&g5`|MJ0#)BoV@9qG%S>_cURX1qOR8Q;J!*nkbAZ=oXiYXtixM+GxCKy$|gGkY&*W{$(-nPmx^PKOId zSayCa1D%tvZK=A9($ zxlC##$hx52qlR_2<;zQ2#)^Pi-C6M2`!aB=;)y zo7A_d*Qm_N?bm1_#dTPnv>!Hy4wv`JFavia*v7JHq*4hM8}sQKETZPD;DfI*D@2G#FR-SZ%gMub@EA)S-^LY)Ss~vOvf9;j) zZyZ7c;RDo1# z)m$L7X)a1hTWSaI-FumxnR9r)GhWBZ&vu;rc6K+Jeb$e6JaatfoSEU z)UQ8MBF}^ryXd$QZ6twB!9>%_!e_FT{Th~3|FN)zaNucQ+uqzpG>1vB9?06i|L9ww zu9iz!PA{GqvW^E_C1m&e}S(gyto{cZXe^dIQo(zoa#p5W~r1)99MEd2_7o<2vv zNH0%&=T9qnB9dltbW&sQdGDG_@R%4C!j=toC%3m_;1L+h#XR!4%!yjLu-hC)kbTzG z&t5l;N2~O==&#W~M+DrP^mV#}69D%pXemS#f1Umz{W@JaVe-wiq+o&&G`*h$aRBEU z4z`>!Jf>SdXu%@b(<)clYhiT-l~N(x^RYng{gMQ`yrZ$*i;^s+NA;{KO@E0#OaF}i zBmEoteR`WdvWt%ZTB5&6qyPFC>?Lv%e_55*86r5Lqb>d8%Swy z;;_knmzUF6Un{}3tz#h*pcF5Ex~rLF8VxssY_20E+?=9+N&lGsEB!nA5`Bvf4*Q35 z^lN*5m3F4Ri#Q~8rj&{fVs6utYywup%E4!{mHax=YA`X_1S-d|v0g4By|D0D$O1l= z+ii{Ob&Xwb4%rhbPoJk>N0e-ma&OVsXm>P7K>HPa8c{QTPQ}vK0fNAv_{?oH1JAZm z4(iAR-Pq?7rcBesTB(5CO6IYUx$M0+ni?NA6_J&=|}W3EhcyOM5wa}irc8720$T+oII6<@j;8msvnN`*Xw+c*+50jlc(|Ew$A zVVe1B4%wKrK!25f6;aatjeb)=^Y$)2*E0AqO=~JWMPM5m4z}zfzipI)1}rA*xM5R- zD!aUdYPkU0wvL6Y=>k`43impC|J+<-l|!GRe?q@zPkS|!5lfntWLnnLRv@rx!$i$q zg-6)RejN*XI5yY>ss+bEwNgZSap6$NMl)^ofGax+|LyDWA%cKJ}qB(W4vf6~>sx}%wBdY)pFlS&R~(z#iT z22(}Kdb&%|=$cFL9UCRWmJ2#j;ypEN8ijlg)x&Y+{ zzy}S5kD59>om3yx#8i@s*c0@ygk= zxJJl6?M8r_)81@?l_=1{L^Efr+zdu-qtV3GE0@t~H34q`OW@+Sp%sE4AVi+fNVq&G zrk23ebGDH>EhcMxP$OKISNxtEHufuX#6Mzjs0U&uJfaf(G|e4ZQQ)~Iez{73phvE*4C;a zuyajMv(?^XR8+Gj%o#~EfyZ@SY;E1gjSv5Y;m~ChFkxF3L9vi>Y%HW4Ebu!ef76Z? z*|yAZtT==)`oSK1q2wO-KE8{$E?hvP-hgGzPJ>CJW~1sRA{};r0nM25N(2ti^U!Ft z@X5bF#@2s63(t*`YfQ6*_q%!H1HAp0Kcn02&S9IP5(FA0ph>Y!ku+h+_k$3!M!ku< zcWz-Y=#3e&2S6)E`L(N;ap~_D;SPs0ljuoP;-0!`N>`sAX_|%KY_`zp?DD&Y?d{Kb zF3$a$1lz;A?_9$B@4X8@2x5VHuH%(3&6#|z^rQpzUOPWi+ z*Te0bH&L(Gqgb75qDmBKQeT!u(D;cnMGl|aK)2gNt=2%mR1wg!D|u8Z)z}k8D}{x{ zMU*(#Zl{M%yEEC%&y_6DM%_K`!hTdT-(WBxWOaC+AO0<%3H0lmr{FlL@b9>!c<(~7 zgzEZ62>H%VjnMZe`V002H*A{LMCOt7Xf~VZbhhL^oDzGI%oW(dbPL0hY?qfjV8A4s!DpGmvjLA~A#p`XJRkIbaOCUqnQ z9VcYHUY{vZhwq;(C1gxxt%_`RB`o%FNFYn47Vw2LFNYxOW9F8zlDv&ZYpkHpwJ+1= zuU&dPZ}*vyLC~zd0vkVMp67*-x$f}9=^(|O$!1Y1SI}xT$Fdf==W4Nta;5rMcx0VQ m=`evE$0qQZ@jjTjdjA6&xAoqi_RY)y0000epReeQ(u0_lPAMw$L2~V@Py#knHIt@;oy5M;erZL^ekVGFp@1=W&eZxR%*m zg}EN)Vh*n*ht1`6Fh@v9MyX`Pvvg5B;&o)YKIVG3R(j|@zmD}dMt+~?S=QE1*Wz_! zW$*FaWFG#f@A2ApKF61(oxWR(m%oMY8+@PVm~q-4 zl6|!A@cnEbMY31+ogf&>BfVFf%fGXG>6Y=I+BtBZyguiSbwo$Wbu~2&(scj@3fv7S zgjS$H8&C+XK!G-(5L$r(Z9pNk0tMQDLTCjFv;l?C3KVDq3ZWG!&<6Of11L~8I>FW8 zW9jeh;1O`pbzlW1Mq}W43zJWV%IB^n>Zh%$SSrizFLTLE` zp9KqPB?R>-TDn2qIaUI#=WC8?yrA3ZvAs7~eC3_Tig*alI4V1D*zz z>y5aZPzbH{5GfbKUDlgeKLLR~ZnRzrK`aJ?7Jl0U;f`iGWVHoRoHIrp7lL*nq-}V% z13U$qlm%LZLTIgl1VfbWT#Oqqe$+(qMmWq06#YEhE44o);~|b^`2I2|Y9k!(bGUf| z)Q$>In7h+t9 z@xvHDZ-h7s(fyc&c@4k!fM>z$REVxAD1_D!1al7D;yws#Ed;g6sOWK{^g}4%Fq_~y z%1OXAFxxfo8{m3Zab;K}mO?4X#1K zJ!z`ZQxMh~(t0s|_fB_VrCF8vP^J)qBv>apkT>te8eDI|%V&)-2XVa{{9j7k?lP!z zlVFZe2yG-vD8DY0$pfgBkD`-5X(GJ_0$Ydzo7L#zQVLo$w}(PM2itB8T^$&t>$e82 z;HHR9y#EsznLi6vJ&*ASxDEGT2j9V>SMhtW5M6>CoVaszpeW{{JAVKL@&p`flTqGNxLbt==c4=IRQIFe*OSqY<9a=5Gap6cwd$iRu4=5P z1V@W;?FuY1DI|4;L9>_U1q0i#l-h*rFI&+Gu><#Z;`h7Yaqzmc-ZKxW>Nu@i7p%!P&N%mlGH#70AYsmW`?(G@IesI9`PP7Ae zy3n}8t^n6j9B+net%JB$;oz6HOI#TQ#Kn#_SgpF=6IbZPo^Qa&yhhg9#6HMz2d=kM z;&wM&2iYpzsX|)t#%ugC)&S31v z#<1Ytq(pSLK;=5nX2EZFXKw@Ug~0w;m&?zhV|Eak+%yv_v?_$=I*@#!2Q}D(aSa;c z7Si+*u6JXT{u|@Jfo0bLHUqgS!X}{vK1XrSb`X>u?I8 zjl>G@x6_eGL1;?3j%f_aQA{y}R$yWX-^U-@h&EBuIA^(zsZrc1LJPrP1%C!itO9Ok z;)pL?$2J00b~L5aAPbCvL`nKy_NxSb7W|m&unM6i_<8U-N)BcSF zklJ`)HxqKi-rNhm06yS4wnlI#2<<`e*TLmuo}i#j6uXYE27!N7h+pMQ{JBBR&BipL zr@_yIvt5UHw+d|*_(gE@gfrp@f-|n;Okt>8i7B>@<~o-AL3kcGZb|y!m%xvVr^1!o$z?HJ$9GAsdK0hhZDbvl^ILR&-0#xI*} zqKP0hlLJ>n4QaU9t!mYEB)LQ4X5M7eHi6HBq3d|3ikT|3+2D)dhPr0M)eM{@56}>N zH7Bv;3ce4uP3rO`@C)EGuEU)wW}?uz?foLS74++RgWZf>EeB9=w82W1CM~JE2~v`< zLaS@`3h-rcmFuwYbfG;2z5>pz`wc!oxQKzX)zLLu3U;)J<0w#r$lT1-{mN$Wi{5jX*--$x=z|Vr80)uI- zpdwg`cAA9NhN_WDR9Aq6=UK5$1FOLoz?H6Zs0TAiXpexuLW!$Q4@!|yvC|~1qeT&P zRwzwaHwzkB;u-J@V3+G$Cc{h-+G6l4;7>QSiZMheayvSL!M_NC*A8RI4cN`RhDxwR zN%P$d=DKsu1fhlCFM*$?MmJLkx2}fov%ap}7@(WwGWnjn?H7oJ=`aAo1~g-(W#Dgu zOWY+hIlS(rt6j%186E}yh?=#LsB|Gv;6c##M6$BJGH{D-4wmVj-X7}i?6CLSx5 zPf9Ao+21+-9vwONzWv?yy@1F>7$$;id|Q`-5x5O>)J1QPybEnH_=n&V)To5nT1;h0ApI%2n#=?4xga5fg1 z@S5Ui4DOn%z<%&x+mopSc@`RP-izRuz_977LuA7Dog|hNwxA2wZqTvw7f2~hi{|!F z2VAxlV&l*Go}_EH25I|&BlOK(d+D8Hr>PpnBxU~jO`|xr4+V(xvckCn$Rw8@fnZUC60v~MMu>x~bZU?V8O?DXaD724*zXL98=~uYm zjK&W5&Rs1N2s=@h{owC|>)Y|Mr1Wt3zVABk5rSh$ox5_4j-9_i z0b;wSx0_0E0zHA)SVW#DtvG+M|1f=f*Is(}^f^18kz^>-!!__iy8M1h;4Ghwev+vW5a@mTlr>g@Z94R&*0xQD>`;MNX zZ$V%?4jiTHx61au$b*XwgDjO0aNC663oZfQ0Z}!{$Hkn(91=GRQEgtkKg->7Id}*>=raF2v~hN@-vHM;`8pS-(qvGm zA`D&c#RMS=E4WKH2Iw2R_R^7a7bsSW4xBzuk&3PJ$@V%${oqFCLtwtMQdyHb5Ks)L(^k2fv42I4)A<6w!(!7Y+_RUj()-tL*qeN>*%6ystkn40 z9A6kNnnz+_xYNs z6X9T#_FHCpajWKS0Y|6djEIN~3!2Fh4{JQba~1W*j5QsLjL`*d1Q&nxOx%4uY8&kBu&VoTDRqN#~Trq@_fi2OR-K8EQsH605<$vg0!-YD+`Ad~j&Fkh4o0qmaJ~yEPJ&+r*Mjrg z{c$b|E)5UWWz{rYDrlM<^;lBy~Ge_ZiyS(nDt6j%192Y4$!Y9Fw zW-ZFiR$$o>KG_M^>c&NP$){N%LB1xK~f74{=F*%qH9U zTx|c{i){N@bR|{As7a#%R=l7Y%l{AfACw3#7m%(4m;i5quY$Lxy8s_#fPM3>pVsy&qCu}=FaqLdR^yRn2JLRg`vR9b9x2FgTPS-RTxtl zVk=k3RI6m77-y<$GsXee$6Mf^fbY7_VLbS*1DFKdnf?-71#SUL6V8OdjMnIc+Kw^^ zC?94fMm1wGtTv_wlQoh%9FjA&=ZFy+;|(;RkZ7Eq2g>9++1PX7zkvTpITaZr??Pi7 z0$&231D~fvbhXkose@UO@wFwNfyfSG3J}?U8eZIDqPgjer1s5_;A^pI(prHSRcvF_ zh?V1#Trgu+HzcKJIrggtuSvY;PuxImldl+^*x08NZVBDCWtmC*$u!;^(sSkgqd3ll zr-bkC5Ml7=`28AYU8fvlCJ2pj0{m0(ElNc9G&X*o$ppp+FbrH4o=lwNc4sVVg(<8k zn4}Y-@Lv`#3nLlhR5;1^5&nTOdu662#4h~5}qF<-<g!?3Rm8-_oDKY%a%1q{f(GGIW4Zv+{VMN=|46g4ExMWp!WY&|nQ z(@XVId+w33|DW?lMpjl!^qRcBXrovc%_z46AoJiqfi!L=`7U|>>5O2HEE^ne!cqIlR|OGms6$Dyew z8zZmhFhF^cRRF9T7Fn5`NW-*A(@lV_?tm931#R#=_l(O${sj4-k>A5N8pp60#}X$A zv@|xNAoyeK&d+iFuaJL)TuLAE_V5-aTa-X0!3x-+1X#WYpjy;+kgYn70Ic1@eLvao zIB~QcK}$(redMypcDu(>12rt3)prgSA)J2bGpsciuzGb|7zh60U?FZ*mtLsRPz&94K}do4u}r~xZ2V9zf%rq@P*8$JUkO3IQ ze#BDhX$}tWApZ;UuPM1caUspW`FrCY!=WQ|UEw@Ev5frZ$bXAGFH@wLu|t6iu&}Y7 z+omA!D2}3}YD%fwogy`kh||6693@$Xev@mPY(q^cyD=FWXAxLPh%!iM?_X-%o)PJY}&J-#&<{b)~FIZ1T}7U$gm$iYOS-f>$? zS4q|_q)A#~M(E(A)Xx(Mno=$csJNObnarN&l4e+>$VNQQjfjUUJU&Dp0-E>`?+gTO z_nq#V3|O0iqaDv0O8wt;?tjP(l44~^pI#E6nafv5%@%MPB?b67jS~f$l*y88StQxE z08K>y;zC7mI!%(Kr=MFY@OZc-Jn7yZ=Dql-4Np4ox2658Q0luQ?d|Moi<=~&h$`}4 z($et_AOA##pcEb(B(y5c(~J?%T+cr?Ua5cvoQr6(Ax1Wl@%aUf{oW`)AW zHbsg`4$jAAzx#!%&M%C64EqPemBvAoFLhuW^o)fPCr{F@4h7SI#&M72y5}h@QV$}s zL^3-rDz}!Jz7M8|vNo6p$_`JJ1M-1TZqme3X!ioLqPAaeD@ej{-bC@ARDrTS{Q+1qJRM zbpVTSp1>A~bHO3NysyglwQ9C=8Ryh&m7D2k-{VY}5Ua0WyLRGO}nW*9hf>bR%(z$5LrS&v%|v)eco zz7X+YZJ7=PWcN$)ppQ#E(D#Kh8rYrrB@QQvV+Z11cspQ6aR)vDWz@YF1|j)wn>?iN zdAJU`^XOtEy4V3vRn;a*`a5ADJ$jxU>ad{(t@gObaO44b-Hp8P10285dq3S|b|h8R z1x$u%lA3}A_v$*+Ad#moFzyK+D0TphpR#>t)tERgVzhg8hH%?my9BrZpn0B4ZrdTh z-KN0zDGU?m6gUB@5TIUJJoCYHDgPgT^XckcFG!wGLa423W!z&pj%Wmdx7}M2RaGIw zwn;awu45^RD!`I@+Ql81PNP41ip^nO1DLADsfqQ^#zo<5>~J2Sa~*&O0Qp`RMKn{g zy=&*ntBcc_IEp4`A5;i(++#S72ms4%Symp0QCOBJ((QbaO4D-!ERJ57PQg0H=mV3B z8W%ZEE1MEHZhtx+ELxK3klFiW22k=ynNdqt+M=27}HsFaiCXy5tz^>L5k$RkGWSe(uxa}-2z z>AjVD;q&$8B<Bjjp3Q1H9g2^%f^{s1*;~vAY1Xsie|0GE| zSFklxRb=w8d6G2lk)1{wyhjT~lU}<~rs&pc?Q!wb)cdB%M%js_XX&irqur5QB>Bd4%>_gU6g|oc~@gjh>P6=!(!^TW47A-1X z*Whe5`rtu>8eTvW_FEX-DRf63T+A4@aCnZ_@92`rdwaT ztJa$hQS?Sc4H=Dl>_-`s4jS)fg9dC`y3fl~7A=--^0RaF(N;vaS5~P~sZguYBHwjM zjza;R4CrKbyHm#-8thyQPz0w6qezq}+cfCwZ(N~&|DA8di_`h`pZ>*)iRY@KjO?mK zr=Xp<;OZC-dl*6#3Ltv>d=|u()#VW!-cC7%ZDl%mNRyl9e@|iL%&rQ*lvuEg=Z(gOP*^<1yUCRT; z7jnT~1kgN6oNZ`Cok~2PH)*M8(U+H}$O~VhhUe2(y-klR4S=^rw;yiMormipH@7O} z0=ysy1gH$&ivS(36NAO>rKySlYhk897v`r$US66NfXx)MRLt3A>6%#nz(=i(v(B zUE8LQ?yb?M_a4#xM;r8DeVbYUFBM?|9gft2uLGgf{ntHopFb~{3Z-KXVqM~7eRw@o zfK>)OXJ<-uZhnfcF3%y)(86?q%7rZ1rcN4Mjob1&_@gk|Sq~Y-$S@4~07IxDqj9gp zQO1h^S}^J%3m^bpuIqIL!9wG6J_$PomN_xtTxQm!>8wT97pLeSy>XGeAfzpT_i&?1 zx9+dfM|U34LqOLAkS-k2^#hTPo16;)Mu~%_ncPbRDI&%gr12GY0TqBTbwfDQJV3ex zr@C=|o-QuV&|JAd`J4r)6tqpqjC%{#kfEcLh}h@z3|R9Nw38Rxw2z~u)q9^N5K~7{ zwA0prAQz|esPYAR>-w^Av{u`rW;+3`4Y=Cg4rndhZ#G@=oU_()@!Y3It1aH+b06?> zdoBRa8aG2zXFSI?fI%W$jZ*%BP9NVa7N06C&)r#OU%=$jc+RrQ(A>3N730kjq! zV|8Qz8LnQzWlWv2HiU^9j(^mt<$UOres-@!uuZ*&uhe7H>np(~1VpiUKthUJh} z_uhyEHE{x8xQ~(mATuZ<6VQs6m*a4%X?XHflfK49hjHIB15 zjw4W09?IZNr!%vTchj!z4*gTr1I`v}0cJ4v4+tjC+;c zdmTQBfDa$ZSf!ow?ik|E{bVl5@Y3<4VtKx})(u14I1F&?X!`z+#)Yv$r=XpE}T1*yYc#IntISZo2YmZKyxUmki2=)uttfW#uokAU;dSV_pLA9BtzG*exqUIIdefdK%6?-2@D_E8r6WM#3Er44hj~?y_JXb z=imDQt*)&L;R~_G2h)QPG|W%NKYoMX6Hp`SzE8D!gF^IIt<=fZEjqWbD8?cKG8I58 z08T@ya6Z0f2pK^BypQ)8EYAa6UV!wwg8%JDx9I-EhZJ?jnZP88enoT~D-;06$vFFL zQrZPxa-GaOrb@L&fBAoZNUrD6+h6^XfG8Z{Y`l)_+Pr=vf(K{znCC>qivSwCS)Gzi z8)OIKLFzDrB7$&#{_Fpb9<8pCA}1m(uv6t2WcPSTGUBigADssh+z^u^D)Pj<94`1w|)LbpEujC{D9c&{^c zhCx#`0S$xC{aA2N9s|2HCv(K}G;}?2Qe5kBELBlOyC4W?ZF3X3K{YtqU;pr3u?BB{ z%R`r7A=gMgawY#0xy~12__# ziQQ=x0>1a?Azi)j5$Xsm}FbF7`vex z0yKsupUY4wpQEg8lG-UWQb+v4`+CoNzQJq6F1E3~O%GOA>F$FS`kSBp9L`ByXB*`9 z{JM<-!p|M2J<8E?o#VuW`Y*oohvOc@@dft!ouB+PzI%VA0+9?Pf(5}FKQmPp)x5VF zv#|L3@8A1?s`WZuSUO8LuU(_XxjEq)hmCTvKuZwV#&%6O0mH{*jQNLggi#3KJZd;T z)mx4Lpf?hoOC!I*ZMLd)I9W^=&s~IDnF6fTHFcclGByCq0zxyHhm@LfyvyZBIW$AN zys$t^Sc_M$UKMWt=;0du_Ptwl^R??;=kG6Rwt$@r+K6q7;{tNBK+9({;~v8?hD3kx zt#5{Z@~3~+-mcYzL-YrOl*#32x?Jj3>@;ME28k2o4l)rd%4D}yz;eBnHuUs|LP{jpOkroN|NZm*%JWdORgu{p5MFbpL? zTqqZdG8cwP2{nGgMLro3TbibRZFy;NVe`ET$pc)7#W^=KL&bc)E1Vu>kke|@%`4Yv zs#Fr7J}F?mV&i_;QEY(p`O0Hzz`atS_&I02*@U|l$TU5H9u zVRl-4v-cbQ>(C3&Vdo^~1$fJ)0vU!r5MFM>PG_6eo&u7tYc`Xin=juu`{vEp4D4Mq zo)CemlQNMZaTD|VPZ!UhyZYJPdvd+e5MoFp72#}os_P`Z5#bt@m1191T5&xp4&y%D zlcuP`X&QjJzaPi*1TdyipkCGP9-~C*C;1%)c4NCL+VqY^MS)=#6ZiQ20V0p0SbRl+ zi^xcBb{K7NQ(2M8%9!FigWeVWOM^jUz|O%Due@}D=FZH%iN{xiAozdu#D4pHg*xs5 z9CLgdB6@XU?u_yJ%Qxt!zx)-2QMjvmTZT!6Og5?h13J(RO$aXt_UKc@j$mT638?M) z)NEqnPZ7b2JI5^caR1P_4<`dw7RiD zw{Cxis=6b@tYuTiG=%7eQ$=6wb~U(U1c6If6Mj!X7pI`X;Q^Nk$6>xKxM0RIg&SrpON@1x%kg(@xEU9M z;Z7Kf!eHu#SOdQmi1!q%yRF+4`j`*KhWB|RzK#5^$WO;Dq@##Q2JLIem-&Q+#1;C= zxeN68@fy`y4Q#M1HaVBcpmOU8XtWzN77RnGL*P!!?cSF<5NuXz)MzeRI4N@D&-3W@j(qBfA#Hekz3oMt?f;! z)|&XXM5TO=7G|e}1NVPN019v{+Z1av9JHh@?*#)L$1Ty`#I=ICRV#JUEfs}LeB&IN z{~k>UX!5uRa7;0U{N2t`gzpEW%Q~H(KPxI~46qo0VlF3+QP+j~0z%MD4GxfqnjNVQ zSGf0Rjn=j*Db z=36v({<09e2S6PFH&B4kH2{*^CMrO}}K_wUdq zoa)z~uhQS$eoUJVoK7?7(S!T+`DeGOJikn5uf0k$OXr2~2UUN*rvtE=QW21aREMkZ zy#e|@RFvnI=o}zZ44XDL*2wWA`fR;U?|;5R-+kv@`q8^TrnN^aboK z=Zb=A9_AK`#mee#*o5n2E$xhnqcpf^^vz90VY5tA6fy2+{>%*AK2HIPVRgGsp&zEr zUq^oZ*~{nXV-i8LDcPJ0JGWwLJ1+S_Kr+O=G`m0x({q%uEXvuL#1+`l209BWu%?j) z;j`;i08z8mPK1xXX3t)LAYZ2t&wl%>pHZV$qwSVQn+=!lJ$Oj}`~Q5Ge)iLMX$!*s z%`bmS^~x3i*J$p-6}aGH#{u?!xRlS4ZJWX^n+=CtjDKJy=n?R4m)rfUI5S6!a8v{H z-P&BERVe2wpMrFR?;?;1nLXy`hb7*iOAqK`!1}_$=gOj0wbGyrz*RL>LZ4s4t!v0%jayhx6O#y;q^!i(0 zqfbA2pQ6VrbZwzTi=_-@4UJS84mCYXU;2l?gZBUf93&1rGRdQ}^Ji#VK_PHGY9j-H zQZD2LG`+%2h9wPjKX%%M`6$(3ixl0u3a+t_hU2>YvF{}!#U zJ|NvefnZU~iU8dJ9H%B3P@Y+KAh(^Q%TY+D;uYSvqnFXgx?|0|ALR8Jd|2wD~SVegH$LaZ!^ zY~H4+nIidcIp6h#YIvhZaFzrf+LpN^Du^)LdVp1g(`1S?S1!_Puf9s}M;@BW0u}|; zo2&gRuf0LDrcA-=ZHfRI0R&DP-Pp6!!sR>&*@t^shS5ceKczs(Dj-V6KX_;=Ty}1L z8lttRvQ-oPNa@ zVhku6NdXX@l5HEJ0395%#9{fr1xMrWP8ExyXt6_zc>p%vn`Q%R8%9_^IT~19PFPGL zXb$otWCNL%Ad-|F76e!9so4^5AhiJ>2e*i^(Y)CV#;9!_C@Q~AVdXJNib`+YxJ<8J zSQ6S$(U*+mBa4aZ8x*DQbRbB36JVmsbN1fnGwwqHX!{1b%oQ^bt3nkxn}Y%)I!YIS z;idp?O2U;cFE8z?Ea}{$A?}_6Cg6un^SBNhyv{r(+q6W^Oik@sUm1JD#c+~h5<%m* zi(Ex!6S#C#UJ0p)YH3*p*zmCF9XUf!5vped@Dy#Zct#fO6q+a?0~Oga3cG~M$9RZc zrfnD`K99n9Pcs%C7lwVKGe$dObzrMgz19@{cHNC9+c^z8E^_#YML}XWJB-=zdWW6j zW}u*yiv=o|iUW(6G+?bxa!e{{50RfBFN#UB_%kLMhEBOcQYm@EdpDTRLq8*R&Oo~BC284nsf1|9uQ%@#>FG^$k_6ku+NQ{lVv zQ;HaU$N+)ij}OY3C}tQ#kig9@f8p#|%AzQ|2r;Rkv73FGUdRwMI~fDVm6Ad5U4PdL z5`JM22r(v=dUs^=ws@~mZwW}BwBoWbS)g{-q72f6+cIR8?Hc)hFv#@8a~@NCU{xou zF`$J~PB@(B`Q*XHT_m3e5PaI-L8p>_o(qJIar3$!d_dB!;-+Fw(}fa>8^)m}E`EsV zow%4(&|1h_$R;ww5E+)qmSdVu1J3-NKv`d-j9K+3SPXxVw3R$B<;Fd}8Z z*jaOh3|W@ZaY>0>*Q0u+DMZ*0Fkh>xOi#jfDr((ONkcN&Q5XTTP<+$vfX9II{oZ%@ zyJ9@-(v*x#*HyCMzIN6m!!(jbJA@5J9niQhS&{+1OOI;nl*w6?FJ{T?tjQz-H>sd; z+(xb=GvX@UJTTODTp_kypmjtR`nazTUKSPzi`76iuh*JXuQma#zmL;Ma3naGodDJ= zrX(Y(RT{!&2DzjVrJR8Fqyp@HPsW@LxCzf8E?~YWECIV67a!qt0R>nCb{}?k3Ewsh zO%xc*Hb~R8E`)~~LzJv-?;N=chP<*>r$)^Y02fMG0kiZZmE}2(Ne1mM@-gy!?@iut zx9w9HhPcvpzk!X9AhbBvhi)_rj2)&}$_qi%DsZ=Eo1y{2<33o>xqJpfH3cy24rx<< z?!sAH4QHRJ9IfbjAz_zQF%Q$;dB#PElVRiM44SMcV(jAYu*75dQJ8?+zdq?Y^L|vf z8{(VuOFD{^a-?$}cT75HoL@?&)gU*8eL5CKLNLfcPV{G46NvW(%T6Au?D-{$Y= za177$#|qmh@Q$KCcBG%R%g(z;E{Z%bG1#M#D6XbS!0ojx5`V@uH(26R>i7>bgJtK!P zOq~=}d8!H@MG=aK|4hbvmXBu=Y_L?HVUD7w?`fpZyy7@%SclG%@L*ar_F|<`WN)1)b{3 zo64XKBPojDeomVrIK^?pCPQqdY0xn0W#s_d)OoelXw$~(ws7uo!4`S}x%HMf4qLm3 zOI=U>;B%g*Wg9q3DQs)VA0nNxOymgTMF8ysq|5sjVB^DZ2ec5Njq(a^@3*~!7|K(I zM4GOWrYaa$PdUfA0`cj(Mx$s?+m)vBl*w7tY&w8#i+n$L=CFnMX1ner1#QHq#WdrN zi{T&7f96by%F_js<*qD0MgI7iPT-j0MF7o3it=e^Eh?095M?50cCC>R;hEp^gm{iS zSZE4B+k0Ol-O%=ZpMlC3v$Sw_mgW|wgL@JHv5&no0E)4mZnI5c5boQY*PnmP zVm4>f{L-{26soGGO?cnlMc#il6FA;b$31{&5Z$_J7&^_)Pm`T#($+?mqO`1zc#~mt zTP|5Sg(Ug-+`)%?27Ll$cnnh$Zq@5_qe9gbQB1P=3^nU5s%|%^SkBRL8yj~Y0`4d{ z7}#70R1}u%RJH?HQv7=6xrO{5jV^^JCSC;4x*;kk6p=4x$h357)>_!{{r53+eF_Yp zG*ds8aWTxbYLfyur<4+bVaWi@vP?>3JbIi`4@oRmMU?@mP8)YuiR(iFupOYAr<_Q9 zpn||{*uiH@S+X(~$rxbYdwlU8@;Apg+GiT_*uMP#vsY$MmZaxde{#>WFSS?o^t5K= zk!G}6vJti{85v79+Po?Vu?7*ogy26Qxa5W_M-agszJmZ683`L~BpG2WV*)v((Z~vq zkY?1~Gu5@9J@-tW_sestPgU1)s_L9td8?n!Jh^<|o8R~T-scKK_S9w(maD}B1$taa zk4_G`&9p+M_xe5ty}?0Pkb@=;bsAt&q+u8#BB%oGcqB=Jovjvnojzu1YSP4H?rZ{* zC11DbpjauW?>_?0i28l1J;RhQHSU6=9a&!)yRRm#exfd)<#f&^>|DVfF`E` zx9^3p9s5|w#0A@}9tHy+hOWaPoC2tATZGh9&j^6qn=RfmP%IZFa-B0rmOJxAj;ZBM z1lh5R|2FkCS)Q3J`W3`o0L`QNN8Qjgedq{jUfIV*mV-I%P!NP60zW#^SyRs0>kd#N z9ENEe07N+<;o95nC`TOK(~vh08LwO^s{SD7fgfUfV-JfgaJOL3q;F)&WP_@8XH$Td z9S7z&sE5I5z!-lD!rrH5}w0V>cY7(^BF42m-hBP3~_+9;o=0(?JEuw`lP zcydjgqqWz?=966vdeTR@k-Q-q`L{eHE@xTB{@C(cU<1n~fYQ2(Y!&LaWn56vcTHVDav5 zx3EE|1UTQLGi|o8yVa%}MhdRn4V8_l0?x1LNRt#rx?!>8s=4I39>EmY;y5|dMb8x+ zCd*Q#(>crY(2fV~yVPIch{kx6!@TMQE+K@DZ&Ux3`g;d&)EH5^(wluFG?{)ghy>uggPp;{FPMk~N?9;8J z;7bJuwQ`A0W~qCA5Mh3?&hrc&pOJaHZO&mBm|tp~lJqaG>I1VMd~wDegCS44mZ8av$Yf7mRgj`mL6+NCn14WpwVp;>jdS^hwBLF zP_|_vBMcov(R=u|0_6Vcq5?vSIgL^U3mH>mJX+tv>u)?JP@&4xb!^NvYM7_0^$Hp# zM>*QUaub{DJ9NZA&EMYZ!f`Fsn^iT=g}*1w8_}tuj8|(>vXYfUcQ>hTQoZS{^7VO^SDT-&=%$G{N#NKPY|0{V zgMo*B-$#osSFe_!YpO~|31MrujmH~1up9!@sKRya;kyHV1d5B~;J`X7AlAM@7>!>bIW7}9>Xu#z45dfu10gG9au$FA3s@gD?&X zwbFkyOyhgJD(k;VB~xGEYZCfZCveHJN4-e}9t%u@1>NFd_tZDDypU%R;zWz{HLNT) zP$|2xti1o_;5?m^h+)WC{yP(g%k}|N`4P}swTLENY6RjoG-G<5*Z(nnM&N z@PYt+0?;4$JP(m1sRBu$8;5-anZRS2CJL@iPzwaD#NS6dlw1>+Y%Ww0_yM9YR<2ek zxzKcNGFQ4-Y%+%*$%)_dVDh_l?e_Qky9XL;DfB{QEMDXde+1g8k&WBQlp|*%qnjD9 z?IJ34oH!QfLU>+)%}ou1u8+ic>S8(pE4mKKgiD?;7991yeAr3uEB6XT7gf66&Q=?J z7JMy;;PU-hG?GK{7WHN5Y^9(NA3h>#^wJc3N3Lp_@0-7KAbemO+>xn-Gz z&P0_E>AYqR?}@v`NrDm!bZu<`1p=aJ`3L2Ioeqnx>!>v<@aUQYx~I6BLr0u(MAQ$d zozVpWEoDP7Z3}kMnf(G^QJB5m?p5b-sUc2wsN0h|)n$FkJ;`!Ta*0_%Cmlh+l47(8 zUJg{Ai{scZO#_-v2TQXvkL|b?7M7dX-q=I0GeEUghGoyR_x7p3I(#vroASe8W%eXJ z;zouk8~FbNPmp)nwc{Vra<}21HfD#H5g{EoU@;y9T|*Sc2zlM68=NO(xFX$h<(`Sw zP6xgh%o?-~_3Gh^(mdiYLXSDz)-bhU3&}3Ic&=G&Q@c0`G%k<0Mwaqazr4g`cLb)0 zg?QMJk|g215Lvl!A=ebR=9U_WXWw*XogW_ep$8ku?FxOvT0+aHLr01cbaybs&2~?F zNI(-CkPdulA;rgk7G29QjD0wCU590f`-szCd4tohf3PLi|*D!-fd3|Dex?%rNNkaLc+2Xzo=3xp-^-XMX_?WBuSME2^f|o0P5=b zR2=sL)XmsYV(R-;F!RN`hGB}6MVf^za{)c03?~h+7QO{L3-6M{b*ObH?>N582R4KsbGvao-&hdDZPs*e> z$T6EaOeci^_Udqr?@WkkiOkUj0nXQ4_=XG5EufHkcrJXT?wMJv?%!gklOhn%q+*?u zmQA_F8EQoUl1S-?LEp!q=b_u~qqWyVx7AbEq9{@C8Kwb~&Skr{ zaIJ{S>mQb!0>3}YZB^PeNR@WUKT^>!#RFKjG38Lh}LLiBwyv`k` zFG&lzqupxIM&^{jK%yCV+ge56C_M#j{2_6;$guEz_hq#yOVI|ZNk_pa&)ibr1hgJb z0!d3xusyE}&W~!L1dbTRK{uE*9n+c*par3hJ|) z9vcvW&rZhh2h_$4_wPz$#Lhr3s$#301|-u&@8Ui-@*!J`8`e7u38ZA0&8=|k>sIk89A3sN>q1DQei2ix$TM93shLbAElLb+7H(&F6NOo#7h zaYkp3bDKWe8D+p%DSzs_cEyoX!2Q%K@O4)?m^j(tFee=_g^tJeJ=j@@X1uFltE63Z z{g%XA$U!?XG6lxSFHVm_!9k@`Bv2__x=FK9#l2b+*b2qV)`ZUL7Y7sf+A|vP^n$u}RG4QOSjdeuOF3NIsG*n+upB*6@ZEygp<1UsBtS^f zYKE3~@ME8Y0^r{2BAuehqVAwvE}~j3!_;+z+XK|LS>!Bk1#fOoXG-|#EBSlbQIM#y z387=csyVP51!#_eg?n=tcmX<{KEf!%e6yzVI|uJbqBw69$EV+>zAuknc$cn8#G0u% z5V(4JSpjw&WD@3iCXoSU0+HC|gWye=S$yI|Hz2yyI!>}H-bq=wDc#AWdz@C2*^sze zt*j)jqj2C2d%g(0Xd&*0hzAi8j|!8ghN6uRa`G(CKBDEX^FOm-!LGZo37PI#(DeMC zZqnVV7FEKCk!;vV&Jxljk|aI}?s5huc(m&2Z(j?7Y$TTJzbOaj?6|oe&RdFaA zSweUTnE)3Nyu^)~?3{}x zO-I&4J9&@4hrE&9sF3=V+Kn^|U8ABLOq@)-Yn*{e!kk7zGI`smp=P{dIE-OA_Hn*9c?=6(ATj7XX2FEhEGU>qd#Lf4rN?wk zu5Aw35V&DNBa}uib#96#h$M;?Y^SWnt5kn>Sxh%_@5+>k_?nBy_B|w;v0uO1ITmy( zpp9Zgy2L~KzB)>Bm86UN;X}BYzn|0C5MfO&cWJ-v)Ab3vVJ zQ&`EVf_7Z;V!My*=TJz!eTQ3!xAvd8M$k#Mevx`V^-qsnAEqjhiL2SBF~fCZWpa+4 z%{?S>vhP+WM}}g_MPt53*tC&h&Tg>?w>a7fkV(8vJ)CVO7YnITF^MPEvN{foB074N zXX#WRlbAVZqYvpARV9JSM6BQ&#cKQ{hwwm|U0L+0e@(rgmHLUJmN{bu$1E@_wUvX+ zYSsLKk4~#Mu{DV&CP|7)tqj|-X6tGEY=JCIawk0@-lVo>m&nCK022q3niSBaUInsg z#-)HJG3pGX?$I*p`}YFP!D{z)7+Ey540g#hxk})EkfzyhTbB7s!L?QoJA=j!o)=jH z!!T!3&jPd85AyjYg_(Iobiu$6VY}8$Ig>gRSC>4slO63l)aDE`IddeMq3Td-aMN5w zsN3L9&IGVgTpDPHW89K`-Nl=gSMqBbJIeMO&~_gI;ef?5n-4!NSU+!6O77#e#pWu3 zQw231X__JmA{f^6mrx2fjuZHPaOU^K(R?pJxmujr+Nk`Zh@eF$K_(0KN7V07{h1{* zL7fRi0+WO^`5)WQE7(%j+6XXhrd{a@K|36&K9V>X#A&5mnQ2*T)f z)6o9~fBxmv6PPH;RDl%OHFS+CHm${dn6k0GoHbyhxHh022n7|F;NJU?*)BA%4Q=l& z<#v|^9A^nwF#X+D53X&aS}EogG!|0KNtD2HXH(Fl*e_@;2mC2gS>A+(_eRYin{n|Z zbX#%r9qH_*W6cV7m~W2G>MdjW4cHeUVv7fr_c1Dzx^6C!iO2U2t!)7C&e@H1H#tE>QWO1i+nV#+>4`F z6}oOtucpKu4MWE~=aZgdnx^`#>$;j#2$W}(1TabfOX3_fc~-jk)SZp@? z$hreO+1^9QHPN+8b`Sa9(j3yImyprPG|N`dU6;82psC0daG6^MsH9MX=Cxry`nK#m zSYZb?eM;eH^iVmGnvo(ZxHje+l>-k+XOH|4PPs7E$pxx%wfM|Bj6<#ydKjY*x1N1& z27M?FBL(z9$ny1B-xA28ycx_qvi$o@8=1vMeE&o02&<4c;Mq3eGsg`9Z5X4)<6_F9 z#xH*YNqYmq<{L<7u&{O#W`($~HZ^5;+}Z2Gb!?Q2u5y!6gnk6mvAE~ff$P(7w$qp6 z@(L1r%M!@8l%Ibp<6 zjD*^Uj1tJ!w_9p$_95fC#CFN;TNQiSImp-s_t~9)4tjm{QX9=h;>K5o)Ow*~Hu5<3rSkWqiexmUr*oz{kdR8_V-`SOiYp<9`C0MOQOy^QP?m;$l2clN6yB!ZnR)fqs30 z1sxKqIE-?_xCqj4)^}R)!-G!NXjJgv!3s7LcLn|Ur?@QNm{uCPZlGLkz%Zo2-5khN z?pK|_G(r|#RHUI3w9ZS=Zrq-k>2jj^bYQx6ip=DH4Qi%n?TZM5lRPwOwk zt~i^nVXjtTmu1i5dFTZ&Y!kY1D|#40KU9#3V+&|r7-Dm`4KE1yi(Y4ATUnjQ+PwwX zmNmZKFA>E1eC)gDnLEo;HqI&<%|$hb=q5rYaXYGEEM)Ty!$7s#z{=Y53cNFJPLujo z$`sII)|YLWSf#Vg)hh=&svLLPJ?s&my_ zlZ8=?Ekf2Ec(Szo)=atmgLkZAZEZm{w|x+ve)av!oz?ovO%>IMX1mHtOC6D{Q_|#qxXuww-rxfhkTB1zT4+S*9Go z>kL$}j#u4{2&Nm+$-Fip3u1LCiV0auAoKIJAY|oo0WZ9`ilwDf*Y_u>V6m8)np z7g2A_-@LUuA#Ocr(tVrr%fpR3HQqygj56eh)XsSMWW%j*R7+S}Y@oo7F3$*TQjD9@ z@x4GjBTmrU?ZKzhNnzfUnhCuSgI1qSBFevmO=Oczq}}%vOc|R`y-~r7@4Sa*vo^eT zViS9Xx-Vf}XD==ejs` znkpyjuvz4bKu2Gw;rZuR2!w+)JrS@`2xJ1=pUH9_-3)c^Q4!VpoLbYA^WL_&^^PVX z9aliGZ3mWZ!?Nt7KwGB%CRLOl+R(w0V`@q2u1J{HmYS$nO8eIXI+?)chmmqq86+44 z=Qf;7IsbgdPA;K^i2kxWPdk({th@+h_ zo?}~BU8ut{bnLWys!#>8^_>)U5@VnDELD2V= z+EIv%lQLW+1skLo3m*5suUmLCH6)wnZ z<4%D#3W2LsuEHW{gMLS@$Zr24wKD!3eGqZ>jPv0zY^G^oalXzDZD5-&5VL5#AjHOQ z8w>RcD#e1DGh@*PJs%07b1MbdbVQ9E{8C+R=(3R?!0&p>&E&V_k!C46gl@Ofg&#zD zBXJ!(_uL|um*?_tIA5+0s8^^r_!$)-8_#?}*gL-owj#K1#=_Ty+^@uwQniP%BE>36Dy+QXQSr)xK0zqN~ zRy<*CNe!~LP_LF?8akd3HqQ?c#xb^99YUR<$$L5<5~s`vxj0G^#ITAEbXKM0BhDg) zuQZ;|*m=%O_RMc_Oa%jvY4-G7u1iyqqqu1l3|&m%;p;um$4;w@0bN+~lpGt)3hq6( zger4Zqn{D}x(n1CU}LbqoIl6!E6~jX$0^(?$RzG8XbhWLpgzNj`>o;c1ECxZc`<4e z3^*#qN~s8g&h}(y4?Q|ZLPy(fcagBz=W1nwXzUkmMAs8(LuV0((TC?6ffe|4BNv9S zWgJg|BQVK%mcyi=8UiB#4cG^93`kn&SvJBKKB`hyDQEOI}vz`aC(exn!_o4%rn`|1ttsBOdIqnzv z`!#9@cO>o-XbtKE)Gt$?rQV&Undy6dI*xSnXRA{=T6U<&Ck!c4hcKRg^YB{ywoVR94~>v=vQ>tYZ@$~~*40_GZ3%+1%} zmJ843bB=h@OYv4u+39FJEe!noX_o#IP18Tm3;&ImzeIhDdUT}i-lDh*psi9LK@Qk2 zAa^r{h9nN*`GaF$l){X;{VC7%bJT&L4??4XMr>UQ&mJb(%Psn0! zzIK8oq?vZ1ofmElL&tox0?Rb8vC~2j#_)rX#|UPB0N1imDmaABrVCmp<}-~#8Qt9ht|p+3E;p&q zQ6HziM}3X@GWBgLym%(pCvF>P4)spzSE$cYuTb@)9!%2&p4V4}c~W63N0Z_^f9H$?e?qLDTXJJcsJqa>h%g~N>w5Vk}xln@Hu!yUrqJpW@8(^=~ zXC4u&NL(mWPA8Cb`yMoXaVH!Ij`}ldlZvO8>E*^v2W^S^5cQkL z0b88pn`DFiK@Uk1p9q@V2{H|DdMr{afvsJ@P1^U;Pp6)=-{CO z?S!zXW#s$%N#xEZ4ku3cP_|_{Szlhd6p+LAv((?AzE1ri^-ZchwU3!m+yu}Z7OYLy)y37?v5v>SiI&9G_4- z&L5v1hGUtw0f*q4_UyKLv!CH{C&kb>Px;0nXl!&kT{k;F^fJ>ss0Y+9Qs1He6ZM~| zx2b4mAAF9uZlFoaT|y4l-=;o7HIRchwMd2?^{mlNbOl?*43*2xs&$U1c66Sn&n$pi z;*cc=8eMS~Aw3{SfFIJ$`s`iCga(x)$wdG=3b;k;6V%U9zeRnC`aSALRDUKPf5x~j zpcSZ}pgvChI&vqIYufau($2Nfl8Ct2dSGJNNw7d?n_jIz`)n^fwkLQXiz=NBv#uE7X6XUZb{Vwh$ACQ8Qm;NXA0VQJV*T_>eJMpBM0uQ)DJEz0g1~5 zO{Z3nyVvKapQi5NT;+b=(2#P2Ws@`hY3G<)ipozl{MfV5v{KkwcIB?7vFe?YL(m*` zei@MULUA(z=4@^z`K4((bhJxdxkco4_c7`pA_wlv)c2`y*2!E3Xb$x}^;zmSsh6q7 zCCvLws2UVUBWM?)+u+Mvk)fRJz8hb~r|gGr8gNT4Ovk#^dEaPd*!42Cre_Vc2T9E1 zrKUWJI`uQu2dFO~cenpQeTV8%=`1FlC1^G3oyfb00QM8ep}W$^GIn8hQ`zH-z!r0W zH+>89c7l?@!nuN?F>MP@*@a;lmtqdGUgBQc1niA=s=ir2=OQL_H33b#$R=DY3dozj z)aB=q1NXbspHo|s;xs3l1!zmuhp5j`pGNLx`s~*0Y$0wYuw69dgIbY}*ZVeJDn*1X zy;Rst+k{&!K-cxlflSLm+vsO_bu&df$j%L!B%CNmOF6EgeqUh-11r?uM_#jkLVbn$ zQ|kXx@pS|30rfHJQ`FB>YnQlK6NhrMY&sh&qx{%6;iVehRSGd@ib?dT=s z&h^XG2dVklugU*wuk4=VII1Xqrh8^~rPYTm+p=WIarkh_RN)FCMU@kvNTotS@sJ8o z6g={0@izc3yZ`}065xRt3T*7yu`Sz3w!xOPJNx}LGu_}GSWSREvUrf}Pia=9gj4M!LY76%|j)88W7Wp0W*U4jP@ARPJMhU4oLjsL^G_J;3pY~DDHn3fwWSe$FGk#b!ETX_J zII*3Pq#}EC58bXP+$<}!eVyeLd!G1IMi7P1YvfPKzajsYe1+_7|H4k7jgntM6p`O1 zzdD%o|6W>iqNzmI;;XOHm$*i-ohR7li-BombqLyQ$A)xdY)RJaYg}Jbxa%qSDjLhR zr}*Z(IPee2A0dM7FXYGT4{Zi*ocvAlyX4mqrCEH}X9{A-R2U|<9ye+u5cs6&q8(cJ z{AhrJrEw6{Es9{f=$iLo${M8oN?YUFN{Ih7wMqOOvIFT01AmWvnfz<=d*o#XZHoLh z`A6h8$fwEiT$?FN6KI@jNs1e`uPxkZ6KqQ0LaC3Ecrn;Cb-wM|Ceel|!z@9yRM)ur zB!t)1W^BkTXHhfccMt{FPszXHU+!m!K$|3sv@48LLI`T2toWB41?CUKtF0=4BCR3|lH|58hXL z61~vE0>L&@2p|zbxT}an;Yc`?Xbc>u+hN5(HTw}@i=INLqOn}@i9rhyU96w^qvl4n zQUYyV+|ad9;9pG_ZA!P7ivb*=q4e&A+60-f<)I;??VBHYwXJb&RpDV>ZH(uNRoYIw zg2Z-;2s9~V>W#&ycL}mvEe9P+w=a(R7-iUYdR7WJ1t%ip5S;OznbReLiy^CYbe>`f zDl?#QmkCQiq?~B$;wl1d;eN+Kn_#<8@^Q>oTVP|Zgl$8T4+9wk)ekjpR}^lR6j@zTEqF9!4PL5Rm67AV=y79-fC=T2$?NkvUZq5 zY<C3L`;u~+ig-fr$VL;XE z6Xr@>nF5U^q%_Ta6vTD3+Z`+~E#uDZTL=Q*q!_0WHs>vow;2%wWBBZR+cE0)die8) zAD}ogf>*!#nwc+$EgfYJG|7#81VG~&dIUnbT*3W&cTul-kaP)PD`NZkxVvbt&1M6C z`rv&`j8EYF!UDn|NPFvI5P2{I3Bt84i8y+tUcVp)sfEw8QN z{olWbhs#TwV9u4KvIiRd6IOc7#*l?!Xdr8Mx_I<(37%J`@QE*F1zj!=A1o7Wzr*Uv zN)B5J$`oi?uP0hM+h)i(xje6idc9!^;+ocLi*sED`QF_{+`MrE{l0I;awVrsfky32 z4JOPDpGKQ$qKN^kR;%X!teM#}D3!(%S$k}J0@8L(ng&6T!C!Xb#~cin6rf&UFJaS5Yv9a?8;L=SXKt9LEte|@f?!`w%Rq2F)6=IhI$A=rSszM$Jn!t> zSxih!LhX^NTxX}#p}Nad$0^vh9qUDuF}42(mh-<&T@y!600000NkvXXu0mjf=op2N diff --git a/images/avatars/gallery/Flics/Flic_107.png b/images/avatars/gallery/Flics/Flic_107.png deleted file mode 100644 index f14c07ae8670d91539307956163a8a32a3289986..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26659 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

xT&mzkG(S%!|+R%)o1 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 B8(IJW diff --git a/images/avatars/gallery/Flics/Flic_109.png b/images/avatars/gallery/Flics/Flic_109.png deleted file mode 100644 index 08f74afa898aa33ec166ee3d5658f2a0ae473aeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24912 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 diff --git a/images/avatars/gallery/Flics/Flic_13.png b/images/avatars/gallery/Flics/Flic_13.png deleted file mode 100644 index 2f6213acc063bc17bd58ab535aefa5ff90e7dd84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27912 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 diff --git a/images/avatars/gallery/Flics/Flic_14.png b/images/avatars/gallery/Flics/Flic_14.png deleted file mode 100644 index 9879aab32bbf93b1f0a98682ecc3de8a5ba01115..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29262 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�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

wEfoSnB-MhA4?i8sY}&q^8x!Wjm+myO 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

>Iv$IX22FC`gnIY;zo`Ecb=cZbhwru_g)UB3 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 SZpo|w0000WmgLWd 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 t!#~ diff --git a/images/avatars/gallery/Flics/Flic_16.png b/images/avatars/gallery/Flics/Flic_16.png deleted file mode 100644 index 6490a3e3cbbab5322e761df0548ad68fcbed302b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27242 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

R@LG15&SS^K$=@ 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 diff --git a/images/avatars/gallery/Flics/Flic_19.png b/images/avatars/gallery/Flics/Flic_19.png deleted file mode 100644 index ee62835fc0937a82e6be4374c7b1d04903ae05c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27603 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

KBp!LI`5LPa& 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 XJB(6miK~A*00000NkvXXu0mjfjzkUv diff --git a/images/avatars/gallery/Flics/Flic_32.png b/images/avatars/gallery/Flics/Flic_32.png deleted file mode 100644 index dec4f910ad761a332feffbe1dde943ee2231a25e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31051 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

`c#$ZR|d@4g|O0lE4k116Md=kEI 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 diff --git a/images/avatars/gallery/Flics/Flic_35.png b/images/avatars/gallery/Flics/Flic_35.png deleted file mode 100644 index b800d2f254cecb88705585f95a313d718e0c6fb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29280 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 KMNUMnLSTY;yZkHw diff --git a/images/avatars/gallery/Flics/Flic_38.png b/images/avatars/gallery/Flics/Flic_38.png deleted file mode 100644 index 38b1dce071ed2bc0d6a0554202f14257dba921be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25143 zcmcFp<6kD;)6TZ-&9=?0J7dG0ZP#Yow%umCHr%z@cALA?rcJ;7KL5k>>dcFS`OM5U zbDcRST2)yN6^RH50s;b6L0($@-?#w*0SSQs_fJ}$wWfuDF!@lBmeBNuyiC`PBLVr3 zeQIrUwX8Cu$5x_g(BLv9ORft_>gj2eC^5-i8U#51!O(BSB2c4(MGT=4528?!H4KG8 z2oZ*z&>*|RAV4w}7e|q6uPPUJRmf?lSMMFMLr-A>^DF|jUOu!$dK7)UtUSFc>^$2= z&&XdyI;&-Jk5_k!m?;SYnixxxu3Y^&0 z`PFY{H`KM?R5IRgcGHgm&TZFx1$>BhZ76A5IRGvTU0Ak-9a!3D>}$U6cElM}dIq-M zdwOhmsm20Hg?9h!xLo>Lf`xi{8TFxmbPNe!J->l|;GHveefLNzyM_u0SqX)*mXHvj z55mJq`+pW6f#RyeSlk^PwrkI<^i?jfa~npOTj({S@a9)vE>7gnbmElJ5B%W43|OW(pwb)6ATJnD>aLTx|XT7^4uvu^?bBebBKH)($ES zM5Yf}(iNYc7-ZC6VsE}Nx58kfk(XEqFsmQpu3-4ZA%6i(0r}5NmwJB{cM+zbW4SzK z{XMHV^~fY?_#|U_);@nNLUSd;04%FZC*!PIS?cXLQB(+cmqhGq65&H%$dz0u>+exb zoSt=)?3K$V8UQpRGlJTf|UTb#Qw$-AHYx*ETIlG`jPL*)y{rytcD^FCJsi zir%R8r6I%vea<^Z`FZ2~U&1`6pdQyBQl`Snb1V?(HkJJmdv7>5?<7wGX9V4p&v?S9 zmHqhji#XzT@w`Lm&^46`xopJgXi4)z^GA6GKiwR#z)i>8TDF5p-q2dW!3W>YSsOkW zgob?|oDuGGhYeR^(*|I-S3?jxU?&vvfn_ec0QN?oTS)9DV{<78nodKjt zz;Kn4$5MVWP+#oL7w?~5Lv~t_t;=?7Z`|c)nerF!@=ZpPp^i7eB}Ps0_nsfo0m%Jm zM(om+F2Zo!Dtq2!WDmeoJ#`3&mzX{HJ?ONWQ2Ai!vS~+ep_Cyn2M>#>J{}~>^S(yt zPw?RFckxGt3h(eR(ZmZ4?-zuRu|3pb#JX_Un=%MJGseL_>w3D0(}pa~0hmG2$ct%b zlXWAh7N#}srHlvi6v>pd60jSJ7Ky^mL4gcxS(;-Wn$-LA2_nu1OueB*$gV_)+W{&O ztc3({_g4K^eOnMBjtK%%5R`-MN>%ho)%4wdn0 z-#b@wer*H)w4D@`M7GEY^Iazi(Bu@l@jIFxHo!RH#6>usQVhb1&Shq`aIl7l%bu;y zYR(&6C`0WxPtOxn_0l_kt~2NVTN~|{Qu)_K_wtzH7Fi?zlGdKT?4U|#KO~UTfj8pE znl)G01!W$2DBEyqKe9vm3bu7`wA>B!4L%@+49fU5ex>Ke%xSu1T?2Kl29W~0e|01h z>Bi8mZXoWEK>GvxQryZV07n#xJhIXse?zGbe~uTj%pc;yLj5m$LgK#MjyzayRtqXQ zgAsNv$$IHlL0hHw)}f8}7`bd|H9pO3E#L$3=_6YZp?wB^I&1qGa-hTF~4Q}hI=Z9rgs)TRI7W!xpwHl9v)XQ}h zk@lj3WVHGY|6w@>L7u}#7&r3zR!G{O)6l?SPrYT8h6K}a!!UG<7ytail2OPMHs1@% zph`NNcfk4W0Me5}NeO@dCph$md`RUlD_c-|qhUxOdcyH8H-kFBZnw?l3!(KdFG>e$ z%u$-7kgM_B-(LIi{dNZNf|#v+H@Qci!@i@{V~@-*L|Q4#^BWW#s`+MIuO_u)Ssz zl?0p-)1@#UiW&|Q_v!V*H4wKPIa_u$8{DzPuph)XwQm`-DLN&}kaaMD_&Y{V3f%1q zSOe7&GsWGCvy1A*?3}0;%6<-{Lw#bgGmguWFAxyX(7E?h<2Y zpR#T9Xrk4*fps&>N0DB+^*ijty)u-BVEx45Kv<`Ht;erRh(%XanU;mX8AaaZBuCMa zx_m}Jx@`>B+tMB|t0OAe(si9>oXrpR1CQjTV9W=yj`)Mu&wAadW=X%sC8(Tt9!sw> zOJMNe=ht0uq*0{Nok;ux)JE)$*EnQ{{krD;(m9Fw;xZ#cU0>X_mhg*wx3qp&0AT=j zz{rz3(Yzkqm5D2IpWUdDcnu*=BdS#DMQ6E) zddi2|sTTtz?Ezfp@k@#EKWh9n|I-f8$~H@B;-8Ri5)j)KzGdyg??);8+ixMJ>x;h4)E8pjcfgEfHylYB}_yu|}(Asq8to`xvy`jnP zbsnuCsMPO|vf!bdh8c4V{<~LqLm_-%VykG&68wnp)^URj_-uBtgq}k}6Gq1($P^Lf z0h~CYEapcuY%~`u{Vs6S-*o-bat(y(bRri~5EFi&{AZrFr}D_7b|~ZK7aLw9^t+|~ zr#(WkRD;c;+lKqd?0;MOuq-#ezJ6`fBg}JDs5$*L&Qi8XpWf5M?973+%AMrMlSFID z_y?Tr_GecvVX>=rIL$WxOaZyD;{}ovvx8>ZvJ(9|f^D#}7vK(AhdWmg`H8l((~Q|n z+g|kDeoU`>->6$eK!zOHqp&Ou*&cAtf}1(jPC!wEbX%eWOyIGY8_6Jw47>sUGNv zaR1BP=kFfHx<%5~c*iG94M&I-4n=apv!~pNFo3M`S|C!p zEfKqSJs60BuO~{x$JU*aTLK(88&d@ih$!PbC9F$tb{8uFM@#z1 zlci=W=3xL1hD<}+`8{r>M?$yRPNv;fX_8?>zM$4f?ZkppoPSnc7 z=a|{4`|0rX=yzHPIFqjp1ynR{0)JZh;i_u%gtS9~?|B7@7DBY?OMFK;vBukq711|y z+Phe!%Us-z1%w)(36VFL<)3V#$#6aH#vVJYFZJCtbc*6@Pd+)<>>t1eYN-9+DK>n; z0`O+Mc_Tke8(1D$-<+J!TM)E+LLLKe0*3;jync%cdR3{Ls}E{3a(LA%w9qskyTMr+ z66ppps}dTw>{*;pDOOyN zB&Y_CZbjKbe4!U-R$+BNFsR|Tz^SRN&K&JtVDQs0bimg=&015b1bWk~Ry!s*`d>w^ zSJG&_If@v>AtM6F7B$pEIn6+YgMS z^JminT%izktbQhKX7AYg*I6TRt0I>EM^ML7sMI$7WfZ$jM5@~5q~&|~>!7;N{pUt? z7kC_korXV=KBu0xPVBU%Uq3I~Y@E$kzwdl*z3&({qFb`Rew{{9Kz$k|i`kG|P`01Q zPGMLHKtVwZIXAoczVq|C{VQMnhSTa=z)K4>4qxzClL7&XE z71?6e$nA68^IrJ0<+ulB%}o?q4vDgpjlb=G-F4D`l6UeXN{q3PY`!?dd2KWqZRWyC z)*#{4JdtWg1fvvbb85eq(_J`%W@3kXUtCK!cP3~HQ*UjBQ9agv?w#_2!*%}PvuJYk zM0VkUIvMU>g>+C-qjjF25+9qk)2?u00^yEabEHR|xeZ>_6O zfn##^z@3X_mbicMenH}jWMmQmS$nCzpf=hE2ZSCbM1EJw3_A01?Q~;p$0o*g!S1wI z)#!?$r=A~2_vx$fY{C^!rDqod`33N#S_`klRZ}VoaZQi(d9H1c6fds32H-lb$+P~L zT0bHP9Die8ynfJY=d{KWGx^|fJFp~E-cky+%2o}!!f3CS%$tsqJhHVojTbzifGFwQ zEcH))Da^+A?Mo;(WeTRfl{sF`nxAIomcr+nCdJ?EEta6OuflA#MOAC75j}(hFz!8A z&o}90@0xy~-RH^|ZKjz#b_d~(;oNgg`DR!4_|sSTC$n{CpaC{rTBb>aX$vqv$0<3? zf@8sW_a%9x?(Ira3!PPGe+%yp0#8mmc)856^ijE^$vHle?{~T61QYDZG;w6-Pz1<{ zC)Db%v*{&T%~RhB{hhXIYG1lCuD9&JQWH&&jXjL1WnLJMO(5Ew5wo2BWS1^_X9<2S z{kA$#FXSmR)G=Yk6hce)7=C=>#Bn_o!evAH%l@vzk{~w1gV=3vYACfA{(gWycw|XZ zyi-a#*_``T#M~;OB&e{Th&o3Xd96%zn0*Lsp!#q3kVprYF26Ed#qT8ezI7*acm^}eYfZ5TkwKNsBV9#>|Qn}LtdY>=3dzLA=rvujme zhO}^N-nlaeg&{I8q+1mytNg^m$f5s(`5XY1B96yHnR;T*+@h6w*Zf^lADJ^{)TU1~ zo!2A_k9jlv%4gjC{w9lesKwsu!?44^uwcIf*3LxkCwlg0@=M25wk~6bytUbr$jSwg zHZftr0yWH~7lY-?r9O8EU6uzR?vK@)R-5hzo`ej6-#~(1TijP0xOhD+fuxYw>b$Q4 znngu+IaU{EIIAu-VjZD`q}RKC_EbVr-Ln(;fUA!B#or|837Nr}l-^x1!i&wh36&;- zoN82#)15PKRQCg%M)^QQJ2`;_?Bl{1e%tR#0XIjed!MUF2k)7xav6 ze5l;XG^M{u3aXVF%Cs3smK*F@sl6+cFgqfLudEQYdB9X{t{JfOZwEvT>oCb2qadZO zV%=<^7_cGprE1-T?@*|)QRiQROJOa)kS`AuD9xhD5^!Y+fkI9#I%^l4r%XcU>y_V{ypl)#(s#{$P**@fn!Gh7~a%UJc(2DAniu-c)GGA2a`fT9q= zqx`k!Id1=zKa#t0{>Nia2em8Lw+C9olS5PJQV$FKV2^4((oNJ>?X>K`A-{wdwd2az z#luRw#Z2rJtZq&C?b{#IxH%?N%z*8xjEb)uLkkY*va}6g3$(ltuz5R;^Cm7gZjJ?T z&i!!U*1W&r`%d7X`Aw8WB1bC!9?q*{@Mp9 zWYX@3OZJQ^#3-`u;gg;k3wO;-k#=VV>w2W}&^WriPv$0B5znl23(A8Amxr~ot&M#O zQJs<<*{)vKXbfmXk;#kNgYy%pN1QVMAj-mvEfDpBQNQL~Vx0{e7FDY1UpH`j0C%}| zZl)hZ8)VatHr%FOnUfMzA+?I?p(4HVFjSde@te7c_p{#<``o_9|IoJ)N3mmWWhMfT z55d84H)n8y%tmhua>fJflS|RgYAwv%cV>*yu+Ro8sZv3nJh5_O4+~t(qZOG@1_mX$!@MCgnc@0`+~?(kXuT@Q`uPYR7yH8N>5R9 z6py%4$cgymoB(;d$|e<&+a4l^13BgEu;!jTlF~%mA36}LTf7NbYaJRp`p1#J z(rHO2;up3r7_@hI{Mg2a#{r0qYIneoaFaVS7D8gI(-mZ#EtmUzK&QU>uQhj4*TD9z z&Ih3aXtuspmS?yKHF3mks8MrPRgyZ|B1 zR`H{4xvjH}%hp&q2D;^wl@^k%v$ok>gIqUrNM;Ia4=B1ho^zfLw6xS1g_N0%BO9EWGT9#h*+y&8!2z^1fc5T0se(i`$l8p`ZHjpRei)uDhh66S$J})HK z_h(mN9wW=t_d#X|M({%jANv9CGz@Z195*v)YVfuhP>Fo%jtZM+)WBs|rB!Qt_!#$R zmxFh!klLH8&u~*OLcs0ar@?M5DyoEnUyiRwxe9F(Hh7vHA;SWbF~p+hR~JmPKw}C9 zN3^)-!7()?XRykn!NMexxA=F<97nHgFS9TccQzoH0%QdCn6@LdtYcrlAmU~G6?P%} z1Cv{lS`{@eZlO&W%4%*N1-3AZobUSF^ykqASk8>)Z;&J5yCZESMQpD7Rb$(&#FJ#HVdPlg%Maw$CKSVf zFsoaE07vqUwA>^X&ImN(hgP9pEf65_~) z3X&zv4diBy$aXe{^S~bdcDTo{k!DI=fH6$RMXM*VT&N=5Hc5pmS04b zbi!tbjrtkgyXlARTtM;iC*0Gk5O%}OE~KXJL>Gh`m*?yqBv`Run}W|g;_Yxdu&hJU zNp=ul&NtxVNauX;LNe-Y8Z$-1pr?F&fG2vRbub$U_mmaXpga!5och{?Zfs&=Oup?U zp34g_j-;jx!BCR>eZ$pm?SF-#J@KW;FF6!fZgcTuu+4oL=;f{d8P#=bf-~F#AR+nF znEUEvttd!DOa-npmdEN2tjX^Ck5BBQT7CnOBfW24;e~%Y##7|s zjw=5Egk2gR7^rM{L47_RCLR}lc9;_d_SHy zY%pUv(1rw{T^y;W{lo*pg$*o0&w zb#cR{o}kx$HOm%!O#HKd1BMh1*mZfkgT9swT#;!5*Y<%qNsbXM6LilX1a+`Gpsbt6 ze3MC5QYfihNRcDy<02ieLGK;pKfPv+Knst!yUKZ_z6D;QHn)%r`61}d7he+i-4^Imu;?RE27rLyKbvj6Rb2SJJZq53Y zuU;4ewvdW+<;A%KQDY7fLIo1@*Te~A*3#QOEyUJ`>t&2rgM0J^{nT}K9!p6Y3WVKi%fD%mWnET2jVs<5Gc6dBWLBG;0&s9eiU&lK;+*=A>0dlJFAam)L&$<8&Aq)`dMkLbQ({&pvMe=zaPup4to zd1zk@fKk&JR-#w?gf9-Jm4)=559sDcC7P~HtJrG0ZzZFnPOA!agL80hz`db;@2p@k z&N%isH3yhZwIBO;nut2IF#S-h+w^->5_zmz>DHqROddvvUHkA=FDBS`^j~hQAM;&O zv*-&-_up?H!)^ z%&Xz~rU1juNY}0eyHuGe&GV|ob)^}$SuI;sSdY-8WrSR3o@JOO*>4uT5DbN!W9Y-{ zb}Zd+&1m+Md9WO$5%tv96aJ-F{<v5>%KFM8#=Rlu_gkdCqx-_Sp6Xn4sv=Xt z1VEqcc0+-dT)b!54WRH@I&>W*^|OJKr=e5AZl=q&r)u_IbFNc8*~|KT>{cGnH1`hyq<;H(W}8PlzrsD=T_&w>ad8 zWGKpFrW$OPog!$j53}X2UZFC+@I^OFfhSC6Czn5`oX<|bNLw^)^2f!(G9u0|o@aXq ztq>!J=PK+w^|t!0i6{Su9YKkP7Q%568w|>xkhn}e^6o?WfZvxrF2=J-&0F4R6JcO_IB7~gf!(%R0cc`9oW|42M4GMo+ z6~2iY@_Pkmwyn1*BCWaPEiqpkpykpHJW(0?ymJOTh*&v4PI2&J;$yCEp9$DNHM2oo z-#KOBgR*+EPa0*+dO{yrk8fNIwCAA2A3mPBM1$r8AO+l2!Kt| zJh`0NuZKK-SjZS-R3LV*-=DA*t=yPoM|=%6j`mKq|NLQ);j7R-Mms|b{^A@{3hYuF zG!l7-ib>Z)+Q~((u2ro$nC*WdDfoERNqss~h`(XxKfIm_C7bDKlIynQbwVL7ntuw=02H?Wofyfzf*p{`?K}h?>%BT!zxW!z9yD6~r`G zORL@m%S3Is8+!e58+tutco^$KkvB4;KYoxzN8o~|)GXojxu*>A8xttu-8yrFsqh5+ zK)gcj?vUaJm!qq!rrnxq;EV*kZz)ttXImL2^uh3IODni|AvA8|={{`0J91MnU$v7i^QFLeudr<`QSm`xy(s=I?_VMgTLmO*jyHxwjQwd<=|S6 zGr+2H9*4`g;M4E&RklO?*}NddtPLK5YLF=^^mmo6Vxm%yZP^5l*Q~>}kbmY$4JFif zOd@G_AS9TwN;4KDOsYTYbTvZ~^S{E9MA~gkxr)^@zJ19%F?MH9+(e5z;ODyNs#32y zK(Q$~%04rN4L41nl|^EGVOyPCh8sd!?p$R{I2>PV^l|@!MgbAU6fO}4uS}}0+=~-; zcMxZX9fV>4k{tILnLfA2;Q9H*V~0MCokwHn;f$&tFtvAngi;@ekCWEy#0i?+>6PTS za<-mj-*6~9_^OhVGg+Zs&7+wQ9CJA~Tu!U9%2=-gIap=H(zEK0>rs+CFG zUC0oVrEuiiLUHs0t{pyrOq*Qun6G1{q4WS z(db4lF$1XMB;Ss<6AjWhWR$|mkA0aA*vB-}RGdv~xAeF~JQK@+MAZF_vGwRsYpm|WXHI57yZPgZD z;PKgA$@nOp&-OaohtB4DA5FRR(~Xd0w?|9r_FaVESDZ82TJ?7E&gu#c|Q0?P(0Wv4e%% zb)q%9-@lfWw~#<$jngq`7djS~Z-n}x4u9(^7|eLEXRcJ~GOAfp)p4_l1rtU@_>IXJ z?Sxv?f4i|o`^(}!^L{Eqr+N6YwOXJy^U6v3c`hx{)y;o@aFvk!Wz8SRi#oL%v)Kf_ zQ4xdHGB+(gZz3jSKh~aslb7c#9^89#F7#D8!)EUi2)exmkqyrKQzNV|A1-T7Mz$1` zhB3{|SwG)HBsZY;ml{+r^02J5w5mmY z=DZoi^d;$F#z=A&*qnNk?r%frfsYv>mr~aPp}T)?sF9kD+mgzuq&kQQ$A>&F+Z*{p zg1~qlc~XN6tLN6wL&A`X@q!aXr<3&Xzf&5K#w?}IU6`@Sj|<+;*SY*6BTfQ7Xc?Cy zplnRW$$IQEVCTFf!~#UmUZSiHzCKUp#Yr z)vn7;zz?7*LCNaY zA-+haYQ^942&2NJRm3}&N`zfdda%U8A~}jfR$Qlgg*b~xpi*)X9R>sx$=G~7Nz-*`nzDE{H76A%2g{MW5O&kKJj=7#0i&aN!F zV8jz1Ah?I0H83XJbyE=)mshM=$57eG370{|P=+8RqqvE>E7zqbSG4Z^d)meCg~@36 zx7{I5WkM>QGJQ~i|E<<(*s0Omy~_Sb{d*Q`9P}uZt1f<5oDjO+u)I)6L=XimPD>O& z=>i3_B!e*myUhwp$UZ~TgN!qbM3`$Gni#Jt3P3G@kOnoNm>f5>4oBtz@G=>%d z>EHdTAGB>nZBdO7Nhf`@d*;%R(-^fh{ZM@z@$aZ#ivT0fXD=PjhhzM*aiRcIKvc;(bQfwz1;@kj?K{T`I$=GVFMP zKj}_cK&c#1Vf-6ElYCRdseT0q?@Q6S*t}W1%@=-rK?*1AtPeeuORVai9r)nt^=yk$ z@w>xz<{~?PKzgc;^R~qLKCAA=cEk{qu_M=Y(zsIGuf&)8igFLSpp1);(}!#o#L{{7 zI8OG2W^9Agi1@7|+=cK%ufe3^02&OzS^8>X^~&Hw+~ajUG(OIbw5Wk&MQZeMzM8IR z(C>o_N+=vWJ*|S;oIs@z>Lf0|a9RXjAmI(s9Fx0Lwb~$%#LGs-wR{^F%%9wEX~u(P zBu~TP!!}+tww?CKw1spvi%cfoh?l&j`{hp@59cX_HnZg-q|5_+j+_;ZeCquq-`|f6 zglyA`U!}sS?+uRr`Q?&mif8EBah3`#O%NV2XJu=ccZ}X8{l(*W>hGkv|L~vC#(%94 z@sShyE-^m9;ck%ydUe$+q=^khg5%h9XLLkxuqeE2J$j?5vD55(Bd3mQhC`eduyb2}$0 znup)6+2ynkr*D_!B2kj6C&G&a;91E`f$lA?VeTct+*(^NW-K<2ffmQ+wLy0Bz6_|ehIZ;+J%Qd5TVfTH%wen2!03hEOLu!$OsHn3g2nt zs63oZI5I2-E23&)WDBq}7x5DgiD3P*c>hLv4h1DPYX97a_H}vQgN#cw(z(vgDHt0W zq1pcRvmhBbzHYD6W*sh5Y#X zZDZYVwGnJW5b@o=!v1}~@O^r>&&TC0%jVScZ$G*8zvrnSC|-cw=sl=KI~hS1*|s%~ zNEqpTIB_SOj!dvlnypN?0&&*kxhKK<9CeK$9@Pp!A;jaDMf(n(P%vd+)VZI{?^rMwXDMaa2prc8NGjdr;iD^ohkLTLoW~|3ApHTt5H11iF-pX#b}ci--GIO zecr$V1!7a0CSrKfH()nhUB^BXyN8wkxtg1|pDa>@Z&`)m%~sBvrm(*^;9n*ndKfEt zf|scI&;rL#F}z+XzAK{l{QBE(uWRZ287=iZa`;rrc2U2^!>92telxHo!<20^o}$;wjhIYZm82kfcr+;OKQ8-B%atn^Ip#8h=iMiic^V=cEtGXtM*g-v z#?u~e^xxKpmYxK@4qGMP+Y5F8_=kBKEU3+dLfbQ6e5cSkaRsPm{Coc1Hlgpt{?ZAI zT4mc-4bdp6D4l;;>kGAzKn{t5(8L8MIMm!$RPzlj9v2l=btl`}^+u`MGOwPy7x_Rb zZ0$%Zb*HpLG`oA(*9GOWYT^E%Bu2%L%2t=@qsw(MZgMOYNR;fI^vSI0%T0>VdGaT4 zSfOz{?e;u;r1t%|z7F^!GMbm!xu)&eto@IwM`VA-yr^V*{*6F*IbCB9I1GK-3-mt} zFzDo+sLjD@i=s%HIdd=AYDa;xG^zO}Tl`HeDLbM%?CPe#kI0hBR0P$KF|F)SpcCd! z(1cCPwyGr~X|*jaX|b3G^7^R6b(6@~u8?n=_^s#du}kL; zEfYX@xIS5kr1;RK<3hq?0wB@MV6@v6+Db$hxdTh}ME(sB`}gnOt^(pw;doJGVX?-n zCxjN>E%`O6fxnHS+lBo!deW> zH_VuZJn^FB1h!oZa8{Abbl2kbT#h4_mx11v``pY!`B0iOX?I4p#vtyg^@1vQxrvQ% zldHx=%u>x@Dy_sSO*N;dp+;1S0&Jt-jMP{gVr{!U%boo;y5($<)&O@ViG=^bkOsfM zcj9PY6CSfe-1oGX?Sy;_Y>+4H73aOx6lil>GbJgtjGwIgojoR+g~92%GNF^=nzMw4{{bgkvTLVu0+{2y2JD+EjCkUVdf1pN2<{FjZoO zY7hW?rW%1NAAT)l!50=|h0>}8e@i>%>`IxAi&Dj7&U#nyNPb2`@z6Ue?9Eb6IqSDe>~rlXjUdx zYarR}fdK>T3J;5OwTB)K75HtRZYvedIz6ktyC{i`kI4~h$BeJu5Rr?koX38rQ-((5pjOfWv~uX>y(k)4lS$OD&pAHQ)@)Uk?7OE$;_fWTZe+D&)B3a&62;e%U74sT zdnB(;F*%4|RV#i-e72r1(ox7g-s*|<1#T}NadLDIQorN!%b2DI9lOV;BZO^S5{CLO z?c-V2%(tO(me}U#RPA~Hbh`|>y*&~#e3E!dh z*?r(QK4%Sc-{n&bPqt6uMW|NwdTLhJz4THN385H~O^R3S_jpuEip;QTC}XF4LB z+%E#fIavn7%qQ@}V4*`~Vrk4-KBVQ#I;Wf?NM_uh+;vt9Ua@@rX1`N&GBGi=FxGOm zXcwF>W)t3mukVFs-$EsPqx|e{ii_>k=g6a+CDWS(({)(J2_+ z4ko^NGw+nUlCfeI2hwj-1^G4)s)OW70a8N9^&=&1O2EfMsyWPlcT_NSL>(Kn<|@v* zn1GPg`-5xQ;-H#VXAiHi)v^6L8#9Mn)8gz2>=5PC;WgUhN4U}VRMFdmZkV?)V>x|U z(Gn(tRl-*PBlM(!gtU>H-#N}nd1mV6>tnwoTY)xnhIIYsvu-;JER>K{_r{(_ek(_ z@AXh|dL1qZquSZI3nlCVw$r#@OzRh8*cxz_Zn{ZD#73p@QeC((Z1qy)#ELpBzM+>E zy0OcBX__DALy5oG;E#bSv61);(dE?Tr5X+?p~i4Pp}iJO6qTDIh}XuUDXOFtWp)z( z-nK&bbBkB3v=dy^7rRw~(#j1Z&Q+cZBjGc2mvZJjdfdQjFdcMH&>c`Qv3Q#zRZ_|^ zlVpCqE;EWSL-3W<5%j$vX_~5pUbNYYRWjW+vcPe*N=IjHf~3y+dJr?G(`Y}WaI|W>u8ez z8SU*x32ic`jfGT(y6jyq_2;}~fsMR#<4P93aw=fV{~3jdg|Ch^G*aph*+SuU%?UOi zWGj%UCM2dL33@IKF@21cDqH|0(>&N+uhNqq;a;Dt7;3$qK7;i`9iUa6)=?Gu-IG0$ zJj^YU#d1zrjlf#~awaEsNcGFn*C*<~0@j(l3G&gk_Cp-yH?#{7dis?>33KxGTo`r29;ll6tHF4K`QK7mXc%@%3$t9&&z=3+V(-X zN2Ms8O!)s)Oy2)SdzSOHuX&<7-_3=bSQ2x|zNb~k!5ENZuuAW8heXKf*=tk9`kVCE z(EKJavHj^HXeM{EpGJwEf?6VW(MziS%XWjNv$aDP_Zyh{XvP4~2hBxFLa{8%t=(lF zIXMVk0>-OaonXxTr^^V3!}`k`McKp;?^c0Y2;br?YM{=<1N25UciHeXbqWnxpLR0X z%G<$@ZMKdj*@2+5T$}-NMIx$CZ0`G1DBD1<;KELUegv(!zYN*Pdgg85VPT2 zgfR#>AB2hlTj*Iv*-s|TRO}Ik>W{u@2>h-Zl)fCCU??)sXI}Uv2^lN8a6#G3wFz5b zv?V`xG)Bn|;=QddgVo9VB>MLJFW~auyA7awvP<&(zSLh22lqygWnT3K^=pI)ck;`ai)4buLjH1i>lz98kb1Y02_?sK9=Wq>&zBj3 zdvUIM`+*i~_($kyTaQj9+VLuPJPN-a=a6J4`M+1fZi7!}@`xyznZ3qW4@jaO+#Y`X z%)BkWo=Vx#JOJ5Fixg+?TSDyI5(skPC;!jh`DmHA)du?pAF8;FRcZiKzj5Mz|I1DGsry~CUh_KpGl^EnAlq~U3+u+ z>73Qy6#d-6a^v}Ky#?7I03;v|`?9Va3s-g7s}|LO6L3VY!3KBFx%T>s$}ooDcmNf% zUmb4nu(yyJ%IiJlI7-3M+J`V4B`kIsn@))ZT{-xQJYNYZr-}O|oG~{X*Z_;bV&rr zJ{s2>Z{Ee<)=T6CsG$|ph*q#U*Cu+2IYJas{Y|TN-*y+<;oOjc;2qX#WqFY&mNy#9 zZ%qC9&C1jd(UOX0PuNP3w8w^Ol_uZOn6whLKrDtD@!ciqVWn4{b#6nwsUukJmZLcU zZI!d56S2sF>J#CG9CXz|N3W&EP!u(GYGRoz{->^8QIt^>nPf~-29!a;A$-Zr{OrI_ z20bBunj=e_H^z&qr#lXcE;Rs}JM}4mssOj5~M zXo)-VKcu1zIoa!!+tm%Vx%)+!xR2MZS?65U!)U0f;~zJDTf^Mp(<438L&o5I*u~23 zmW2hSDO+U2L9k7Tik$4PFDbNLs(_qCt1)K~oC54gU8l5vQ$N7AY@L z;{Hus&~1Z3U?KDMw|#5|#Gl|*QW6XyhJgkiy(6D~gV~YIVLj*{0#QG)9e`1-Ritk9 zD#-(pmr8**_~gH2*!J?wpkL(1r`6bW>2qqxJlLWr6Ar5Btkih+dH=zvXAUWd2#+|B z4VT1Rxt=bfF9FLe?8GHc)T*-^s1icCd0-?Ar%dLCc;AejK$N+AVjl{Fgf>hj6Ak0K zfDlqNP=6?CynAVD28A2(0rT=+jsBi80)UP`Bp!F7OiZFC1!yF?Mxc~hGwK|2tQVh8 zCxm^sXp(+JXu4Oy+soIF{SP!5crneS4e^_g8**xJ#wohL#Y@utKp`iWfT6>T7y&)z zlSEw`$%4sxr!u2B_93Pv->cI&D=>BLA29GSP>)uVK4HFJ z-_(Y2%Y2cc$C!qU6tUVjm!FBz598476ab}!s0;Eis6w{#X~OAUn_+B(oK zl4c{xnRj4d-{rImSXbFGtA?U9xZXCs-3PhKU7%%chEo>uX(6SW!|3#~eb~ z^Q_Sf3#pI?$GM&b??k#S{}Es)R`wl<57uVhH_64NWKyc23?%^u%#AVZ{9q_z?Jt8RIs%@_yW$_Bch{#x z5s#%u7L4k-;Mi$Vd(-o7e+yIe7oqV1$pFHahT<@Iq_m(gZ*=6y(W%)r8D$pJR!~)% z8*^0Lt4iP)v$ireEAKam=T~OOB#>gHa987>m^qrElc1)qThadoc_D`0@|(#2f&BlF z+cQ}9r3`H^DN~IKw3{rXhkz@3MR`Of3O)menwB-aw)inkKSF+p{5JC6z%jlE*2<{n zV$i)9GOpU121h#OX>e;zQz)Oa&ulfk6d~_n*kO_kh;&>ShHT7*p$E#Dz)nsF<)rO! zwjF%_Io9;MlmfOx*F13bsM5fzMNal8p&!Jr%5MvzLC=Y2nbRd`;U2;*nV`~Lq39t0 z64d=YKEDO0`0XH|=LQ?FSR=r8RySgoG?1t1E#b;U?0Nxh@3rXTXB9FHjczR$s9bc& zv2+PB4;-Qp_(4RqW|tm5*@uIg^wRxh0B*{$7`}PLq@eNaQJnl~r|bR))6gHGs7Z&v zjxorJHtJzW>BiaR*zq_N;P{ewLOR|uU^&r|;PraPR~$Nq2PcpOVc5ivZvu*c0rfmL zERrya&SgEUTLzO|wAJzG*>;0I0ytYcb?O2*0oyWkm5MowmKSmoI6nww+g95LXdP;I z15(lM@kWJSePNaEuP;#EF^E~4s90bTLd+ISR!I~^A9ljJ zLdat5<1n)JM!$J$e;Ugx;1H2Y@rbpmT7M zeu3yf&>zB4k|>J%k9mJAW==&@Wc8YLu#0uN9=-q3wsf#cy+ctL9|CO9^;EgI^k!65 zqH$zQevW<6qo?~4-j|zF~L*21S>Gw)JY zD?#@vHIjAtl%J#g$(CpKYLQLA!BA}^EAnZL3S^T@&nJ(`%p75UwSR8G3w{V!*op|J zmN_*4AHxOM3A7P{o;Db!O07-befKFn-q@!A;*-v#o?NuV1Vw~_Yjr&O;d>jjwcDUi zyn37NuP?yG73rYo6b!$~w^Pa*enpweM z$f78wpFY~9@BjEIHQKIx);pn8_sPM0$zl7FUk|lUMz1aF*J}^n$nyev_k&H^-fPk? zzHx^h++Kj|sq==dhOEwWg84-v_3f%f+Q|O{3WQ0CP$gt1#mqq)4AEbjpbh1&6i^{) z(W0njK&J05WeBmaM$rdyi35vd4Kf%kM(IRTgo6GI?fV~Y(ck>wWAgkELRb2*@aTYD zI$N4TewvypUC9eV^23+{jKRNoJPn}e7(+)JTi4_u+%7=72o*Pq6S@9)0LZP~27T|H z5N;jP-Ss6h4Sim)@u1I;mGim8*+lAA3|Ij!R-`@adGeK9ww=jhuAmLa6LFVR5z$?- zE%lp^YRD?SDd&B5lSBY9zORs|0jq^WFG3b>G@T#;Mc4CbV{4z@``IQbiJ--TLk1u* z0EwoWke_5&Gb>pCKTO zsqOjzFov_S*(7v#ZJ7*XF472*+sMwj-QtwN+N@X)WUX!Mi`3Fra97c(Amcb!&={^5 z3xAZ{k-se}({qte`M7Z@oehrlP$q-T26bbrLOXj6TFg20 z(sGU*OYgguB0mLAWnlc?*X)iNrjl(*%Z=mI(faEVsr<LojgqA#HGh2;;P0HwdWi zcQI!|m0F8z)1ce87HJNi=1~gTl?c}4j`K2A&HI#y^gvU{P9NtAS}zpf#^J$!ADgd{ znRxU<{1KVt(t(;TMSL7a;U>)Bt-*(U=AIwGVFI!s%Ckfa2XWzO<)TAxzPJRNOvr8f z6#7x$CHW&cM90t|1HT!vBm-#hT{5a)77Vfu*IWeTcdSKv{A@=S0LwJfO(ru(t&05K ztOuQK@Hq;&*nMgmx5!iT@&Lt@XK^8*4Q|O5w#=W3SLiwST|npd-(Lck+e5*Blu7l_ zVi=UJ>j5?mPN1B6U{zJ9kh3YDv#3~hBp`OlB(D=tx9L&fhLpsUU+!sT!1L*bO1TA_ zaz%?2tY@*4BR`0!TyjpmA3l#0g00}&$nVf4inKhT&MB7ETURU7j{P!4LZcWdX5{M^ z3fkaC+aeEldxP#qkNWTIs1B=+Q`^3naFv*Tiq8%*ci7bgs(&b5DQ8=!x(*gO!@06t zf}^N?7t$bn&CtjxnB)VrPQ#VZ;Rt4C^gI>U1uJJ#VaXxG*5yN9!^%=w!Y$qL6cs!I zWIoP<`-t&(^%VI#$kuFjGF`ClLSbZ%MYQd_M!sUpbH)iA(&jAU!a*C{cw5QSPn5U% z&sL)kY1w}S+m2IryBOf!K~`u8v|jXFP1m$jT?_BTHuS@NlFY{y0T2w*ZH-h-p;pbM zI7+78K7+t8=gSs3>|z+327ofLo?g4tL=c1&!U>OoEJS_{`Q0;^?@U8b3_Srd#iSkQ z6{;DxXA0D~xHO=RiXH0(3WO;S#|f)c^tV&s&gE$O@g3yXk^c^948P=R-gSLabLw$I z8yU%ot|z4HC@Ns9bR}$kXG;!7IBp!#b0_q(^Clp($#nFC=RSGMO2ah z8M%i1Eu=c!!1I054UH_rnC;BW2g9~#QwX59wrbLVbVVgqQAmYy6r2$YT=bwC=pLi7 z8~9ZBTv7~$UcOTRYzD<~awe!oMHofW(T;(vjr=O|XR|$=NrTrFQ^QzCu2Dx@ph(fv zv&HlCic1b!&+185Am4ECgl*rV+wC8bl0-5EMRZW==Mo#p-=-9{&knz2S99TNhNepw znrUF~JZ2{eXrtYLtHlyB1;SSGToWp3_$^cLXZkyW!?b*l8i7Yai1YE_XuBr8Y~3Oi z4mm5(d_R!;KPJ9~{8MB&+k-jgz!0&}pc9ieoi|aa73jy3zXdyQa(;mI;?je55J}(W zyIP4J6+eY1?)T&U8{aHsGo> z+T@3+bHs6!zQjjDe!s}@{|q1}ObZ#y6JxVs7kjc@p}cL&}6T{!qLZuSuQ2gvHo4rAa{z99y~L}4g6mK=B5wS{3wAslTCWFGR5k$+7y z4uK--sRgQ-_atmheKmvZayZwxxIUn9Fl;L?P|$9YA8n?!odq=m;7}!3bzl3fL{SAn z{QLC|>8eV%mI{Z452F~BKA@aBy{qxK9oMI7vm-$f6KE;rhxdHo={>LW%8;ybUakh7$#O>-O!EsyU9!KgY%UYG>if%9h%!P!S?#QLqsCxewTEYdZHx;V|i!Ub{~P#|F3xome#z0YGC3m&^<_hJzhVQBrrC zW=&j3qUf;D`FI)ZXS*%+ky3o4W9fN3uAO-vq#_hjHJyAdPp+EFwth7nY&fnZXuV+3 zTb4s%;7=tk#B1pN8BJ4^yls*fbs^pqDldp=bFU#`Vc z(=u&ZUAx_TKvy}Gi(bIIqf}m!?ly(MSWdrzTxCHO9E(bMJ9UOk#I3GRoBItw7fR8k zZU;dEa50^eo*9l_zZe3n7^&~e7BviwYZS6N{ztO=1ImZ(6OGxLe^YEQHxguSc zxb~oNEG(`9xW%(}=aTw)q$71I6u@RvDF@j4Y9p$*T-vEL`y%X#GK%Ai-u_I2_Y_63 z+*1!&-hGVy?NnN{TWw32vtV8QGV+sWnTw0#((*dx3#E(R_RQkigT@ut$rY$nTB1U6 z;Vf1CGsstg4#haGC=mdRs0h%Ca5s?&jz`_EcWAHHrX&-b4~Gjfm%Hl0#}|Cygy(9+?&4p!qzbT!L zOO2sx^x~aW%G)N|Nx=B*-kfv}KCjZkGUx^I4lGW z)p!BU=2%7_wpPbS#c%c7QEts_kiRdwN{rlcI$Fqyq_3Q6!SK{cy|?$pm@c@ zrz4Bir^mUP5Q;2(POf+@0qez$1ub7FQNCC{PW*3CDv*8v6{K=RF)R>GQ)r=>ld$#l zQimwFD@{0BD%7heBnGLQxmm02(dJ%*+zc|_kD+Vy{Ox5bqtLLkjfevBi^!$n7d*zo z;z|Zu{-U=!*SN8urEq9e#ziZNG7MafQa8JExYu|`Vuo}c53t#$-k)Q?-l6?kTZ%P~ z8cWaT>mrHW5$CQ!JAwMyAfPCJHqLO7hY2PbY zgiaGT7PK@3<#R<^zw`rabqX5~ci?p^>q;VBzjHpcH7c49HAeSrND9AXpi(bGb2$qq7Tyt`TPrGjW zD`Bg#G7J;{V$ix|QAEv&e2ujvVJkXRskbQ%BihGjtNVlsjwK;nEafO~TYyoOBc6u< zdtj$~BDpRv2&vumsEK0G!e^`PQnTyIR_T&b$kvuhbZ>15Kq@2G%1`__-TTq{AzpKG z#s6g4xv#}>^nE<2W?im5bvG3>6=@-FAwPxu97OPTl0^67C@MiD+9;D@&}x*YGC(U* zNB*89Y}2Gg7(k`bf|JG6^#ba;0qxaVWNc{?ItFg3n4_FylCG(J2&Umq9R5#69LMAb z0Lu>~R80WY0#NO)Pd;2WieiehNx2sTrKu{JhEB`n9Nh$;s#P~BI?IDSHL6dFkqbAek${$u37NB%$LH;{jWe2T1HH}am<0{{pe4%3^{0}yVt38!n4rRxy4 zEuD_xWATp)E)HQF9g-z~4Z}#z)9!iz%#$z&c*gCA>j;Ca3c#f)5_Z$nqC|{wG+ryi9!sc)hO>~bX89H5`^fJg{~Gx{I?pw{w;k`1PD>c zg)|A&4Upg;A$AhSjxW3Gwby%@Ilt$7&aCY?zU8z^zp>A>p5r6`F_rGM|tEZ zj9ACw>yKfC>%u!K6pvxs1r>drff%bChg2PXYIqO#XT;w6IvU{WeVMUxh6%5|Ll5@u6GtRuwl=HSvpA;a;O z8baQxaIm^Q&D$x{x2Aa|RixR|Dc?v}YiQ{t)xt2+kz}{``1L`Q{##2+mGXTf7sYXy zW<~~+UYkXd`}u4N;g-X$KifS8s$`Hj%DY zZ|I~^n`Ga0ezZk|3YeH8n32m`|68?1_KmCt21K$EO6ImES+f>vHmZ@e>*N&QAqw~9 zh4ku!G0&2}kXUeuJnN31vVZQ3} zy0d2{K^0TFf!6iiwq)<+z^BCkYJKvQtq#;G1G{s5z9-A~mmFXt3-L4EJqZ}fp zqR90Gj8wlMkHg4jCq22{N>Xe|!DNmdIjd{y%CbL#Ayhk?!%BcgO@eNB&LD!$=o(W8l3i zNzr6%kxLTm7>r<#kq41ba!HG-HuqmrZH?2NSA$4fRXE&7)g{@mn?P#)M|;m(muvuj zo0665HYN%It}xB&k-67OMPaDN(W%?L%99f@Z<24wS@JPCMdo`cT`xuBF|1FVaq=8_ zDZV~ThT_i>Eft9*`#EVX6p_UU(ip%>(y!504a7;-u4GG98|N2OxL$GB@3m4gM94%_ zDuQjhttaon>S&A{>XLLK-TUMNa*@cUHM%*0Zi^;z$;l!q^(1*Yep!(#gM^Z6r&61K zwo{U7HNMIMHOnyHT!dXswNAXJ%x*A8$%gXqT9m9AKr@u-M zr&Y;nk%h^Uhl|AkD~uoFbo)FUS>AImjTL5=~Br zXUOX?l8J1GLa@yxvXziVT^+>{tE7`HKpjyZ$RluK*LT*uM(_9~IAP_yyHQVLTmE+S>_9cXgl{B80QxgUpIu+1gOCMi}#7ON`2 z2-9sG1;&0Y{uBOiwD*xx{m71k03e z+*;xhxy(CZSA*WoNyoJZ8* zx9?d6Fu@|6An(GY+k50wGEE9FNw;3Dh$bREN`6KD0Fz*Obb9UY(rW6o%Ke#A=JmlS1ITS~^LvR>DJEY_L5hmwikW0<1Qyj-}XbYr;9% zj??)E_r84c0Qo(6gG`c>heF>jGC$!T(ioZn6~`Gcon7?JJ7uD@ew_=^v zco5!DN2nRo4MhxDWhxl8ESt&_x`H2bbew4EwTj>Y_ieAyIDmNg(xkvGZj$YVGpg7vyYIBD-??#CKZSXLQ~ zSp{mh7JqtYsb-UMr_xNVd?uwO^F0@~wxYH4l5bkEL^Y%?>dYrCF z)|>+;VB2@KXq#)4JSU$1NzSG}EnsQEM3|QTC;^j&0+&c z5+os~$DY$V8h)fnuk>4F&bvp2x@m)%0BZ#k=Yz~k7^hsn# z?n6C{__s=@meU78V%v^>7Zr!_VJJ803G_|LrgQUcCz+F0#IDzB_}|0?roX!aPlVcZ z>NlG*l>amo>WH+6&CeF%m)PjtIea@`!Sg3hU~Fs*QPdw@E$5errc(|5F{fVC;mYq_ ziz&u`k}AC}kxZnyeEBjief1T>D7qt2nr(1vb_Qooeu`Uj zb8s9dk(A!9l33%U>+rqt9;Hv)9`>U&zc4*Dh5vr>Icl|P#~M)*@#f8&I7QiJZroTO zE6I{M$r>NFx+mJEk|wmR-Y$uZIX5?p3+MiW)s>ZwHlaLQl1viqG-bPf?OMXJsr5M} zEqt%*o@kp&i^e8UsyE|Fa+Qijocru778VvdmSo$FBhUZr^l4n1p4N$-M5F6<718e{ z+P$*6)a-YTW1+fM#f_`8C@d7w?Y=j%&ExE6XE1a9CfM$Y$R^`DJzC>_D*K*nx0f`e zZFjc;rNJAu25wBxVr994;h{0MU-!2`-mS1$#MS@1hWWV#CQOf_d&@y)JBKdOY?nXE zBuaWF{Zh6i4KJc~rwJuQl!|a`b^(iX1^yox92~~{;tXnyYS&Z7_k2X5!nLb2dM+bl kBRv&PWbb->_g}64KO-rzBUv6qcmMzZ07*qoM6N<$g2T@XjQ{`u diff --git a/images/avatars/gallery/Flics/Flic_39.png b/images/avatars/gallery/Flics/Flic_39.png deleted file mode 100644 index d8c488a315ffd7b7857b212c0b2a69129421f18c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26041 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 diff --git a/images/avatars/gallery/Flics/Flic_40.png b/images/avatars/gallery/Flics/Flic_40.png deleted file mode 100644 index 3412bdfc373a486ede791576f132eea82228db88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23879 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 Q>;M1&07*qoM6N<$g6G18EdT%j diff --git a/images/avatars/gallery/Flics/Flic_41.png b/images/avatars/gallery/Flics/Flic_41.png deleted file mode 100644 index 77b73648d8cfe7f71a49bcba2dd08467a1c5c4e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22533 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 XFOsv>x}Tj$00000NkvXXu0mjfz3LWT diff --git a/images/avatars/gallery/Flics/Flic_43.png b/images/avatars/gallery/Flics/Flic_43.png deleted file mode 100644 index d3064ee63282293477dfe6b3841de162abf69883..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25130 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 Y9|gJ+GZ!%pLI3~&07*qoM6N<$f_b%}9{>OV diff --git a/images/avatars/gallery/Flics/Flic_45.png b/images/avatars/gallery/Flics/Flic_45.png deleted file mode 100644 index eac009cc884c097e6dad08b0887c62d834dc74a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24581 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
+g=vEXbM&J_hzljprb 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�wZEhfnUX;h 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 AX#fBK diff --git a/images/avatars/gallery/Flics/Flic_46.png b/images/avatars/gallery/Flics/Flic_46.png deleted file mode 100644 index e039b5c4abb6c75f55717abf8edbc070b6af0137..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27626 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 X*M^~cbNu2_00000NkvXXu0mjfNn0E~ diff --git a/images/avatars/gallery/Flics/Flic_47.png b/images/avatars/gallery/Flics/Flic_47.png deleted file mode 100644 index 9497726c54fcbd39fb7fb9ae7136c9f6ca4f9b57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25355 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

ul+%wK4iF?cV&Px4tH>1?jNeGnPSZ0>nn( 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 Brl$Y^ diff --git a/images/avatars/gallery/Flics/Flic_48.png b/images/avatars/gallery/Flics/Flic_48.png deleted file mode 100644 index ce7e0f9f1fdb7d4ac5c2a3c72ebea12e53fe98f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27662 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 diff --git a/images/avatars/gallery/Flics/Flic_49.png b/images/avatars/gallery/Flics/Flic_49.png deleted file mode 100644 index ff7f4f7173b04b1ed4126ba9b898d456388862bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26357 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 IM6N<$f|ssO00000 diff --git a/images/avatars/gallery/Flics/Flic_5.png b/images/avatars/gallery/Flics/Flic_5.png deleted file mode 100644 index ae5cad5d4ec8d475080c5ff30b0ac8e9943ea336..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24127 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 diff --git a/images/avatars/gallery/Flics/Flic_50.png b/images/avatars/gallery/Flics/Flic_50.png deleted file mode 100644 index 45bc993a2717b24b9bb9dbcb954bc564c52b4fd7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26392 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 z 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 JPDHLkV1jwp5<&m~ diff --git a/images/avatars/gallery/Flics/Flic_52.png b/images/avatars/gallery/Flics/Flic_52.png deleted file mode 100644 index 1a427af311a0be33e3cfeba7ddf1d6ae23d2f4bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25772 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 diff --git a/images/avatars/gallery/Flics/Flic_53.png b/images/avatars/gallery/Flics/Flic_53.png deleted file mode 100644 index 901a1c14c2eeb8948d333385eaeeefe055bd9f5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25652 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


|N^y}v69;>i`VH#i)OBRN`%sa@bTcW$0~CO` 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 Eg0wU%>i_@% diff --git a/images/avatars/gallery/Flics/Flic_54.png b/images/avatars/gallery/Flics/Flic_54.png deleted file mode 100644 index 2b7ff304e2fa3b13515f09a8c2ef882f1edf56e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27193 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 M07*qoM6N<$f{ba-(*OVf diff --git a/images/avatars/gallery/Flics/Flic_55.png b/images/avatars/gallery/Flics/Flic_55.png deleted file mode 100644 index ea47c9b0d4b2128ac0c52ed7fc710736588b9aac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29978 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 diff --git a/images/avatars/gallery/Flics/Flic_56.png b/images/avatars/gallery/Flics/Flic_56.png deleted file mode 100644 index 2e7abe719838d004d2540029c3d0afb0018da720..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29812 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 qbkqd0&A!5qZwCmH44!>BH`DnjH2_V{<5*iO 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 diff --git a/images/avatars/gallery/Flics/Flic_58.png b/images/avatars/gallery/Flics/Flic_58.png deleted file mode 100644 index 14a2b66db7664dcc1642809e2c8fbd7952868433..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27565 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 diff --git a/images/avatars/gallery/Flics/Flic_59.png b/images/avatars/gallery/Flics/Flic_59.png deleted file mode 100644 index 9afb2938ee76ed7b4f00e26c348545e87b6cd101..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26791 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 a)cP-bCv-9(Bd@Rk0000h#N& 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 diff --git a/images/avatars/gallery/Flics/Flic_60.png b/images/avatars/gallery/Flics/Flic_60.png deleted file mode 100644 index 46f7c34a7433b4342502c6af627d431c810bfb56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28278 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

-*y0`UDrCDn5@kU7bySijjDm+4 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 Z{~x5ESRf-~_mltt002ovPDHLkV1i#w`NaSL diff --git a/images/avatars/gallery/Flics/Flic_64.png b/images/avatars/gallery/Flics/Flic_64.png deleted file mode 100644 index 60b8c95889b218bd036afc33fc164dfaeed43d4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28815 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තY&dwq`+X9ctt^WQM< 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 JPDHLkV1o8r0bT$A diff --git a/images/avatars/gallery/Flics/Flic_69.png b/images/avatars/gallery/Flics/Flic_69.png deleted file mode 100644 index d441301f11b109392ae5bb2cd57d33ade2a22195..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26686 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 TA(q!l00000NkvXXu0mjf@!Usp diff --git a/images/avatars/gallery/Flics/Flic_72.png b/images/avatars/gallery/Flics/Flic_72.png deleted file mode 100644 index ceb8b71f193ee622d64071c972cc876fa199c6bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30051 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 Ef~^mtSpWb4 diff --git a/images/avatars/gallery/Flics/Flic_73.png b/images/avatars/gallery/Flics/Flic_73.png deleted file mode 100644 index bb7a4e14095e7086fa074fe00c92dc6552e555ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29596 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

yM$Taza9Mz8m>+2|M0hOq_ERR2`YRzbvXARCXM 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

%R`oy4K3 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 X5CC0JWMw))00000NkvXXu0mjfWecH5 diff --git a/images/avatars/gallery/Flics/Flic_74.png b/images/avatars/gallery/Flics/Flic_74.png deleted file mode 100644 index 3dc070988f021b8f5419b54b4bc3ba80e72ea58f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30076 zcmb4qWm_CP*DX-o9f}oqcc)l^;%Mw-EpWws8k!Tk?gZhL4f%EqXl~O5;5=>HZ3^Z!0?-7gzTAIZz zQVERGQMk<~l9fcorLjxz3&mK0yo2cQ#CLimSGFO( z*#hpqqAwc)meZRVJCm>7J9NvNu3uQ>Jjgtmv=gs=UqIYHxhb#Zgh=m4{p23 z@n9VsvAJ_k8RW(PzH;=O%zc;X_d5KVy7NrD$7y4ot6jX`iq{hFKX79rhFIz(MVTXc zmwuo9L{cuwH)4yh{)QsN*OO&=J}_wCQgx9#e|2Q};O+;?izkip7+mx@A>@*&kSYXZ z;zQH|Ac6rfaMK955=<)OpZC-d&2(kf6IYNIa5KIjF+%_4hra9F4#gevBUcAF!y~+N)JQQ z^%Y3G-4hdzg^g@lv<033cYrBW+PA+3W~d^vd}+m`T(72)!jsmQ9aAj67py5@r8tjh z3Isb^{`HEu^6Grc#Wxj`d#24b8cNqzl)uL(?AX=_WWbeh`2>xGmfr=vS-F2eh6qtF zUet@I;-+Ec*byf4b8n-VgY@oWZkxQu4gGO(bQnimWI*BnO3`%QYiR(-7R-Jbh~jI= z)P=RD7kYnX!@vBxmx)H!O60=jFdNk!(56)60K174`-aOR^yRVsI{ECAK%NR>O-F$B zAZDTu+Mp`}!<$XJR!2s$9yEsrIjriJrDxy?OtlmAx;!w^R?-{(><#+@#VSwo1^J1B zAD$M3VO>##sprm)Xjod(4jl*lt>ql8W&J4xztD(q1v^K3g&7<=9;Sy8%x8MRw*N+8 zC7+yR$mRU+bt)xt0T4MzM{4D(%8Df5chK+MXTgZ7AlTBFA)d5j*g-9c z4mq1Hq>JEVf%1|~lwjZ3nB!xXUt13Iz+QQ{(Ao8o6xq!zV73oFx*H0t8`@8v!F5jd zJ!jUsHZaxlLxiV@#JgSR7wO5XLSNF0Xe%RVnOwEruu>ju-OEamiwKj+2s&Upo+9E8xU z=8%ZDjba|^F1(S`G4xE$9j|a$0+bE$2I6iN;Iw^4Z^1Vu&O8E;I%c~3Qu4NF_@6^E~yO?|Y6 zmpre*kV5W;F_MJSM}fX8Y155#%5klvlK!F(1BjC7!1N*MZ%+l2gcMH)j}pQ-WoJ~Y zGN-5))VGeC{6e03sNhBqN90JbRC6YMf`ExuOn}JpidGaJ{@>N*TuD?78|1)7u)AE( zQ#9w12Srey>w1Io+aQf#v-~T;CJ8IZp58T5UF{ssh

(1}F@(c#&H*+CV0e@(Wx9 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 diff --git a/images/avatars/gallery/Flics/Flic_75.png b/images/avatars/gallery/Flics/Flic_75.png deleted file mode 100644 index 64b161934e872623ad461e792e5e4862c2840784..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30144 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 diff --git a/images/avatars/gallery/Flics/Flic_76.png b/images/avatars/gallery/Flics/Flic_76.png deleted file mode 100644 index 4287ddeb7c98ba19438cf7b2aebe465ebbb95dc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29251 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

x}iG2f2BBhI2g(}7`eP4+(H#&vo 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 diff --git a/images/avatars/gallery/Flics/Flic_77.png b/images/avatars/gallery/Flics/Flic_77.png deleted file mode 100644 index 0003b960de301966a0d5663243f7297dbc8aae2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30882 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 diff --git a/images/avatars/gallery/Flics/Flic_79.png b/images/avatars/gallery/Flics/Flic_79.png deleted file mode 100644 index 6351c2884c53c6ec36a46d23dbdb1fda6d7f609a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27808 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

HU|FKJ0*|C* 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≤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 diff --git a/images/avatars/gallery/Flics/Flic_80.png b/images/avatars/gallery/Flics/Flic_80.png deleted file mode 100644 index 72b198473cad2e9dc9cf6b5d93e5dea3abde8e67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31215 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≥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 diff --git a/images/avatars/gallery/Flics/Flic_82.png b/images/avatars/gallery/Flics/Flic_82.png deleted file mode 100644 index 78fad6de34440d84f562fc735fef1f57b0033f9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25395 zcmcF}V{;{3uyt%Z6K7&)V%xS(GI369+qP|cV%xTHVmlK~@;>*i`xow~-Cw$DRrl&$ zy}CP6Sy2iZ;Rga37#OmQw7BYj?;~NCvX#tI z`{r~s<=B4pJw|>p6PG`X^)evqUAM>*L=U&=_xqITR5!POLg@)#w@&_GdBt3Sq&oFK8Y}1x5I`>U&NXztW4}7zkzq@O%T)PdO(F0cIF=qX1r1M$U*Li9M_N!B zWo}jp|0%#$Lej#ey?_;lm7W|^$MOdsvkj;W4EWPx3MhJ0~t#{V81?o&eyx??Upx6I@K-pnuz`B^vwpDo|1K$w;^d zTPNnR->%44gm|aXZtj)DRm}i2KZXd~a@dBfAcmkoB`>{!07$c^2C(DSY0Bmu-kyVY zdax$89IqW;F+S<)@`a=A_g{(m5tK6WK4&Npv+!-hh3buY;An`|9et?5F0(tj2>W$q z&S0Q6N#?1%kb2`TEgYU*bNZql-5q>ziP?HcFZFSnKbxVypt1gmU`xJ0*6{7;me7z{ zwHPug5G;KAZi=gML$El;Njn}81uG5wY+&!vzEr?zo}CEoQXcl+7sDErN-*@6p786} zkhw3)H2J!K0k)agun>t?8Gv7DIb35ChCBR&29Si7gYY!Va9tRuf>tFXp|Xjw=nYl- zq#J$2VL*`5bu+S+b(zb*V72H|S$4r~i~e!@sfAw9je2AB;dd5u_d+W5bNq>Hv(cH~ zBqQ?zpQ{Zxw<}yG!RPp1Kog~vG}tviz!a5uA%5uLFE7Ir^oV&UmlEL4 zv8Bg*AGjLC0DO#ID~aa!J>9glbIQb#ULfRs7>L>m{D;0ZXqr3|J+MIpN36$^{$@h zWbZ}3bm0o%3)<6iC~y%d#EaaBm}Rkm>dr#KwWiV6W-gZO2E>zld*l6!9u-t zc^7>r^Q!-f;lo&7d0Lf?&Hi=Q1{&H69e&5Cx(-Nk67thZX6);6n8Bu&t0g{zn1h=_ ztkFC?XSY;vT7=(=5{fTclcEj0B#H?h-~-POk^&*Zq?guqW(prB5%=edV2_}x67C_l z--tWeDpYkp2JGNP7D!^L{EU&Wk4!t{KI$Ochri>g=?BX3?)^d2w0K6Cm^J|$=txys=`u?Wt$Nl!8% z6b}lI9y~=HX8f09l*EIW8sURbN5Vm>O#KejFTrgSFChJb7ql()XV;zGSK(j)7{JKT znI(=!vIv}AL5DR=gM}8OSCK8}V*OP2AIB>}nN%xAt<-$ge;Jc{X8ux^M#T;*8{_z? z$R2qB5>Li}Hj~L_gpn)H6moao2KxrjW}WVv!6H03t3RB?z>=-GJT zdFhxAtV()Fvq??A%-n?dlkD1f#Y`=DL0+rfvE9w;XnAVIkgFnP(@1(byvf6YODr+~ z0b@)EoktyI=|^GQGd}ezZ3ofu1AD9j)Bo|P4$I&(_;L3*3Sm*59?Y6Q#0#=OV)2X{ zYjwz3;G$CfspB3ngclP1$7SbjkwK05Q{a_sX-L0n6%!bIhv`syjOm!t4pw3oi6g5M zv492EsIHAXXP;_5vxzDM??3qzkzVu+v03{cwsJke0TL96+CS>_0ant@+-VZ~y?6(= zLF|}$UCUg(DBrvQPJyS9W@6z(9v@gic{$n*n&o~*qp_>@3nOu4;`o)AkXul6RHJ^_;c||3=$2_Ika< zZ}xj_1NBUK(ZhiOY+UxcEyKZVs}{h%p}`a~Z+<7Q#V3=e844DZC?ILAm^+%oni8V zvyXX5X|M;zys==F9N2yBOYpT>rH7DUB}o^}zVFCT3BE6vXA$MDzn%jmUK}2mJ(HHm zGD6-YwF|L6WW`j|k+w!}{-D`t>C{|_Qfxu1#KD(qahfPryZs%)tgKa85-p%*v}?8} zRZHLb_kLNv^N7ge$FKh0N%pB`Y(IqE{1H}?B?i>z@ua-~zC^gmjZv(&BJQBg;%WYRDDr6s?R3`}C z5B7ewklz89Z;C*_T8{Z%M1Rz})>;YLdl`NV#aYXwNr^y(Wh-_cznD4&1-0)qg=SZ= zctw1ex?H2F*G^!A>R;L@6R+bQm3PpiQ0Za06pbdvT}#V)ItytGTqIq>iLGpte7BW* zzXd4yP0`A)mU8|k^c(KWW=r>o?gTZaxF42_QV}=OvD^J#jMv*Tr;{EVtPTCMD?p*O zHviA*Ij7W^zv8#o6~}wqVg1sv^;%_=sQXqnjT~mZcZYltTfigi4q_kD?`eOhrWQ@% z%iwRYFJ0;%S{t)gMeC}Lh2CIxJ_jbe9K4ch&oI~Pt*M-DT8VQi>fm^G>oXVdFu@8$V~<==vD zoC>QK>I0((WHKoeZ{#w3-6!3_J}|u~eWngo))38npuQkj-c7{Y1{%R%8CIFxJA|P5 zk?OVcp=EC?!FA>BO@v>-uJ(9d)O6w zRuHZ`&8ih^&_BNxnl#j0^J6DF>n+i8Q2mg_i5E`Lc1kS8A+2RHJBvAyMp)S!f92>0Qt8CYN&PQuO$0fSswHW(11r~h=1 zpKwy!RdeUCd>RE1gg^=F&-BiL)P)%OG|L3*bQp+|cyMZrk(K<(?y|w!SPZfbQ!!hQ z!s23`(`7N0)^EyLsJ{C>)WXll_yhR!&iRh5!P*83pe@ZYPSs6n3D5M@KCchs8n z*%|%@--R{K5iy;pFKlL#^^;2T0P-+fF1(iYHX#l#4roJKK_W$pQ!JsVHdi&)B#&fZSZdZL z7rw3#YuR)^Wly*vZCYg6;#$t}{7(UHqn1gBaRi*G>^xV3Ab8i7&Z$)mB?!v4M2GJ7 zhSvDjB&@N~*;k$K(m~XQZA-a36_laSD(d${RqukSURNKM!ApsR5#Y6f%CLfv+taWx*&|UDw*V zo~OnN?h>AE)HQAvEVZm0N`s$;kr-ITnX*g+6&Q`XPBMr z8FyxLRB+2q3oV)w@oMJXtQ=<1u&}j)53!&{qqWvP+Y~0aYR+43$Kz>Yq4AP%#veEo z+Le6$?KnVr3ntWND_!~;@ zW`xz<#TI$24YW#+Gl_>xA@e`|Co}V%x}{>`GrrT#-MtO;h}a{QGQY!g{_zKoyO}B2 zkrK&wnu|B21YbY29E-M6Q0ejX#dT|G&7f6o35cg;erI_WZ#^b@{1C>R`u=(1@4pOg zddP62vZ`3tb!ng{loCCW=gEQBLRVBK^&6oACNa1bqucu}+v3ZcqH_Zy+t#fs0C|+* zQHZr~od1yq@`!;b&eAScV=opt3?^1V<QF|-#+ZHggd_z0uyv1jT$@lnbaRz3S>oduA5^|*`oO{td#fGnT6w=bv za&8IQx9p@PylN4$r`$@3Bv~?|Tf>Wy6wV>}aGG}Dx_ArZOOJP6ZbNdZ2~%YUUz;20 zy8Y3z9Ew~55dA58f9E?by?M?C?4zDJ2u|11p4aNE{5!;X{rd5EIUTggz?&hw z+F_(SrGs?c8%$;B%AF9Tsf`RTS-|T6p;Xe3t}Pn0=$YcH`7$^xGeq-`h(futO7}o^ z&RrFlg);O94nUj<0N?P5=WWx+O*^Kcz}(mMP8Y5id-;KXsCHt{`VH&srO>t|de0t2 zrDE{~%>^RIeYr)e^OqimpR|c=1Z9MQP534crbW|)g!h@O%6AO1fciA8u_!-c8J=ko^ zlv=nd`|o(O3~|l$E90#`!+-Vq&4xWsb3Q5JQ0K&-0%))H+Bcc|CUJ6hG3FwG-otx( zB5R@HfQA=u$U(rdOh>5>uT^XixL1SuM|hwKBMn8F*KqY1aH{%a#~`7W%IoMt$l+&00z}yf#FFA{vMO z?cXam!1()^3)34l+66CB{6_-Mo%{@s$Ai>%ia##w?#uClw}JUm$~+;g?&$Sj^_$4@ ztp!cV_#(aURQC-vDqo1_y|BVpC?olVBm%Pg@?9UPdC_jc2 z4$1;wI`uE@wy90yk+#6ezvH<0SjiMr*cev`Vtq(z^2m;TE_6!vZB@Qne*!Vc9x-p0 z`(h5y#T!-~mW%nc8F|A)dhvCa#7pGg)o58;? zJWNNHP#2<`r94hSKV_|Nw6SmO5j(k`RPsA(wr4JOAnCWKmTDz7S8;d6Lh7I={G2ge zX2hm9EF0i+PB_{1d`Zs3-^8)m8&{9Cf+?_3nAnAVCS0?$)8e}-J&P!`%6Ln&*2Q>u zHXJ`b=lL$1PrhtAMI|?-Dmv#Mcq(~gk=eIf?}IE^;tJt8R^-F0q=46i4WF zwE!-R4l1D)IA>s>NWo>+ zkRR-YxsY7z;y!IlPGPcxh0BHI!=s9n!Atv96$It`hTi{67hcQAkI)C3=rEeMS|9yG z@6VZ2Ow^baZ^i<%_M@I-oJM|>e2r)EiQ5X-UKq;CA*Q}eh$_E&D`V}j`j&c#{N*IO z>@Npx`<{I}!5+76^mLUTE=jfPoNi24?p2swEv80@f;6;djY{U=MVL|33wUvaJhO%r zXIj|eup|8*%HAXI+&x)Al5$b~bJa~w!O$@W<|m0Z=9F0>7ahc;kY)pmA

t4i0V_Ppy?__p}~b)W;GDumYKDI(AO*niYGY0r3RAQHAN{@ z$(WKiJ$Etu@P<)ssO}|shY-{jR(ZHITgjbWoprAjFTZ29l&I~(6$7y6C)&&uhFAjD zfJGY>kLv+@HdWRa9m^7Wv2xq0OR;6i6aNA)&Hcw%Y8Ow}L|+D%@1J-#VSbi0*Gn{> zI14E_IVd&vtCFKjLorN|Yopk34Y?R?K*cmf5>S#sShpQ>Vl%!Z+U;Gh<7Lz`H5^R- z3>PNvZvhxs^I)#cDqCNWYhB3@&c0yV*xvC6ox)ysDhyS$+ug+TjE>#oXwS`Io(vvc z|3{h(vFLW0TL}^Nfyc&Gjq?IlE^mAWJ@A#FsRNaAlSnq&#$n6woAo=}y&_^V-2?_P zVrH(wziJa%d?9n7tkWn7XahVbs5vpS%8-kLqL@O*o>(A3O|wpJ_Vs`96=G*_S{m)p zH_3tv*w&64QDCZbU>It~(tZd?3U#XRfCh9m;-gc?GX0~BmCwo=m_B+4VG{K;GT>;X zL20qm>cTh5YF)biktYlkJh*Gc@dUE-XS4?H3JlRap-?D~z^h{<^6o)j%8Wj|TTiZZ zOZFUxP|-H)dOxyjc;}CiIvtl5rvVOhkR*e0` zH20`dzfv^+a_bPkd!HSf@7h%}1NS&ppLgkotVAxVuyn#Wg*2DLYxz0w;ujKGNh{iV z3DBb)UKwr+gYj~_82{=RdF$~1yUHi@mZ!zc?AFyf1J`u!xl;#{87VsbSTQEEz9sn4 z|C-xn!%o8sIJ znYa_SDI>hWU&!4)e<`Y-dF^)df`}~}6sotLuiF!-)}DL_35f^S4EW+r!v79ELJp20 zgTpk$3UB@A$x82Z0854vk95c<^n&ekUfMLyTX#{lsPBGwA1>*0rc0+J;Ec8RHJZ)s zcNP$&xGz>Tr7z_jRovs)dt00_2db{m8!G(geLw3>0=jsmkQWO#x$WFKjPY91BDkMK zELSg{vS71uQK+$UUc_rtINg#dm>5mf6B_R3A1u4%m5e7G20?l|K8`AUg7kz&cHSsE zbC8#oH+&^9w#pjaD2O9I>H%-MjY%+V^_F^nFO#A701T7dER0R*oRBfh%s$qM5O@#X@khHa{uhjlvD0 zv94*Z$_OXBY;@-dc@usgrTe4va781g+f&_IzOes+g9oa#oi^(;$)9|TY^hA_^~!o0lH??(6#`xF~Q zgN~bw-bCPXFO4!`-lL&okZuRg5+U&j1Y%62P(jP9LhhcCjg_{6k(rtP}6S|JkJWJO+cIH|D2pw$AMtBr$nF8_9OvAJOYF|6qfc&&w5_@kt|rRAO%o@miRWD%06 zpjU6R@TQ-PZS0w+0mKIOBy_H*a)^}jyS>rXhi&k?jDQ}&z{rWNc0RWFQY#K3F8r?N znY5_qwDPi->tXJt+dO$rq5trbHQhHb zx44id-Tw#FlDdqPXh=M8EXcYs85J}P@_k*jwt%;ZFz*TMsMG;ad0;}#7dOzY@X{@A z;76Ate3A)6YJb;r$fIN7Uj zx6(pmtgCfg59pjz?up{AAAA+SGXa;E6Nk%@#oV5saHDat4tXE@rfd#p@|^+0Cnfzw zOV#NI95}ZiQOWj3#LXoFn?`NGZ5favX7%>3wcwm0N%TAg1TWZ#1v*6ZixZa3_qtI` z-Vco+4Py#%*1g2^74L512QSjYJKfUNg6MaIeo9gNd)-)4P59avGG%l4sItqK1d9E3 zsM3rnCO)}vr(^d~SLK3_ZO9`2*?Z{0pzi$LlwezYmPekmG~}IfMD+IzWD(6rznj;6 z?Q~Jg2(JHN{Y6|b6CdEB_2W?zzcWN1aUlkmnrpX8_^~s2ikD_NNb2%m?JAIj)lrfp z7MoF>V);UdTQ|T-Jm1IJPl@zYm#^u)96ZmE$`ZNPM%+06);sO(7jG~=Ziv59wPvq! zU2}(r2QHlWSXvJ&LMXU#w(rfP{E3Cm$Hq09Do23?d_5u50op^TpwBV*r#OwaI2nSD zJDKFa+z4UQOomdL8Hh6>N@m%S@WK>PmYn0NbLPA=M(b)(MYq42{C*ayS?TghB6>M0 zbuf)-C{EOgrlXM9?JO3$`tG<>WjH&LGxh2lQwLH->5DJYKCf_Th*@yOAH>?$!KspV zxSBxRem_Cf8Fa=`@%5!eDOy`*Qj^og)};{Y^(8mM=PH~rh+1OuX9wtf`tF~><$2m6 zWs2ftr6asQLXp{ZSy~S=(&?>15$Ztly7u2jUV1pij*-Hlg*iQ`)N`m~;uCKmCM!^$ zbTQb9xFWpE~JV9CGuzVKMizue-o_L*c-MTG(msvTiZ3Aql} z*LFWIrsN=P5dQg`80|P!htcMmY=x(tty#Y>tE{_~wB&6`M?j{^nsq<_onz@!)_+Glp_Q!1iMXI!^5%_Dx|$G=1>%`1h;Re=XEiAwCSh z-NlxD57*cwvGaVD+bEPsNh)I(sJ@#_mp0UaHxb$W0K?ZIKMC2I$wY6kvVtZ>~XHB zK7%?E0??qS!HNJiQ)tbRDre0;gys$VQG`hy_ZhWt*Q+r8qx=3lqi?oG&~wGcE+Z_D z;eiun;kp9Z=jHCJ5LbSOE+BB4O=zbmk9 z`dcHKV5j)dF1C#POf5x*!T^kQ?!3~vk;;X$`4Mn6yk#Fx+v_)=6;o_jc|dk<-bnrz zDBj`xP|oB2xQY9h8=Rb<$;AJ7=&(pX_61l$B*gnE$AH^ ztBf6{efSWGl`plQDE_uj<9@tDWGOiG8JXYklPg&l7Z{5Zj0p8BJ6hqLN+1SJf_5J> zQE;>|a2VJRhp$h3BxK~)d_86i3u!{7xMy?BR9&JLFMaUnWfh+&CGa!PiU)76ppDW?39&u#KwI=GoJ!3?1WC6Dc&j5ldBrf0u&v_m9E)3E}E z8}%IA!n%K=c)mR#$HXh$_qLbB-Cwpjoc`7Kd9$tu9dpe#We>mfPUqu~iRA4W9Oazd zk9ToKeJ)?kI3f|^8Rg=8+J`88^JA=k+994l4l9D$ro73K6EKu23C*8?Q9`Ktv=a5u~_|bBgOm1!I0KGb#utF!WaM8ANLY=kH)1?6`g%oR!ybmh|e6_F0&(jlJ z7Ww~fwYiF5Bdj}xA-kVtT;>N#`XNRocBhJbmA1OJ1sDW3U3~U|&OUBal zs;xt$gZFB{7xrK@@of->Fz2!xgxHK*TTzZ5& zlLmn+9lgu1a^H8AmGXEZnGzm`t0ZeZW=2h+e{ZVK01OnZ6JxQXWJa6yjH%AtB5N&8U`%EldWLHn_ z_#kb_sn+OEJYw)qM(m=2Y@)Yr;PE`-QMbP=Np$rZAkw+BN~wMSW9LUig)TF#iqlY& zKo5&80joq_Da~y6E1{QHv~2gUGzo6&XBfdUYe1iC_Mk6}z29Z}y#E>ZZVzu{e(cTCpNhWxptjWg z6?62o&`{{*No>v-*ca(ct=Kxeg_#zYFJdB3qsACsg8sX}V1z$;y9UrtrP*!hmb?(X z-jAyk(DtBM=AOuf##5FSZHYpEw7ERNVBFtdM~C#cIco zIw?45H)?9noHIpwc^3mTlzUr=W`_-w^6(D z&yrO8(|LIYc}RWF(=SCKZ-`h)$b5s&s05TY|Nj=fUf0MuKKF!^3M3?ePo%c9r~?#F z1jmX#C0{8+wF2dF=O$!?=)X zb1aULW@hZrfEsJ1z(Mo&S3pF{nF#T%2GJ59(i=tv?@VnrO)~b4nC+}Jfb-|H9qt{J zahhi$xqu?;*`ITCuB9Rx07B6Pbd~E5tVV_TB+0ChQELQoN31A;G z&XO}C@NRSB^ml)g#q40Aa=E8(5V`Am?X7Y*N#6@wyB*ATQ$4CwKE6bY!H~t8y|J4m z{J)VRi1#x#>IMrSi5;LbA~MnuqPqlYSBt?=$)EY=fe)OoXIW_KKKuoB$T3&*rH@Oy zYY$i?a+*YSfO!EOcaHh_^K%t1w^Fz*t;`6B}#SQ*o$=B{jHYmdnZ{u!D+ zTPV(5US`pb!rC8U24e3-HrMY2E(nSReL<2=f~g>dtrmL5hDiBT$vD< z=eZ^3&A;Jb9q+hsIp+pCYgqWL+uqw~UO~-EtNH{IeVrmg{`0al0#}HdJ1R4`fmEUN z9RG!!@h%&TJ5PZtXQobvoe^RinEP*an4%6qB2~IE?1ymGar%209w8m8K*kXl!Sm@E z%i-TD(aO15Oz9#-@5|WU*qax2+F_9h_`68SZX{eZw{6^@&~xY`-W9#^=euhVKWZ?t z2q_%x-Nu^)luw;%T|*hhU-K96%RtGO+J%{{Pero)asHIYQnr>D={&zC-QKmpGGhlz>hzd~|}*@h@L)R<9HVI@K100#8nO$HV;IN1WX* z2bC4it9dw>bNNM6`KCbLfr$(J)uum+_`%r$ob+xm!2XY` z;lgakncV>qc{OpH2N!m+H(Vtn=cQ6i<`113u*5jxhG3`Dk z)%gK2JONi-0s6IL0qX35#$edHH4?v|FM(ig*S`!nxF@V$4-`&VUF}l@%>LkFE>$e9 zmE$k_=%WoPBCE@e2d_rZLGASse3zT-8e%KtfYhV*hmQ|bF1oFf$U2K>IBWIp$qzf=R=AFiT9nj?P}k72X#y`8Mx5zZZF zvBOsK6eOP_K<5a!qv#$TPNrIWd=Hkpw2G|T$i~8u^?5=5Z5$dm*FUo=)sh@&*#}At zFCGoHW>0VejCZg9e_$YhMT7A)-T1?s(n|h9lZerGRT`!=0Fh|(#Gq9&C^s*Cu9Sj5 zSQiV$;VKL`4cu)3H714Wr!ad9E|||7d@RlaEay1$XGwk$_P)o+)65!o)b@SR|D@uK zzZXnoKU1xU=JI`D?7N*5|JkLTt3D$%MP)RMgvcJYNlbTg)A>t5Nd`nOF_E5@j$l-^ z{II5b80;y4H|_E5Y2Yqh{DklkEi8{?ERYP8s;HiqN91ji3BPS5`n+ZqjE`sf9sY8~ znqrMS&5+{o6}t3_aQS>@Os2LQdnTH=re4`Jx->^PROlPr&c-pbNmrp>WkaXq5etL! z`mcYAEPZOQXs9|8t|o-fKDzkY9+~XMe(|t1A{Q)cnBnnfl>M+1(G&9Zz;f&l zm`D7pYkEVU&XfRi3Q?Quc46}$Fl4ggzqr{82$;FR0XqY$7QP@79Ftl(ZHqdYSz0|$NQlc~;P8EGQ@5vvOj z3dUN^eTk>a1aX=jLMUK@N5^H+gA({)0z)rZed#m)3Y>talSiowRh4O%MnaN7^iun42Jh>RcvesSem`PN^ z5RH7Ej9}SlTAMLMTqz!a>9o5!dnEypw?3Y)Jg*s zgXP>C^>Lq_ppRAI15fGE;n^SL(Zny~6FUPxlW)z>VR#0QXs8!9?Jl^oE-ZtC)DKS9 zAvyzo)KeaC1SE{3!NfW+!Q14m5z{;7mK5Mh`@AU^bk+03q=ewV?tLQmbb%lf9bj?{xr8hbW zNKm%+zpT_&P#z#l93Zq_(yUoVYw#e!)u#tkm(JgH8f`=p*s(9_=Eg(^{`*kRec+QN z2x8BSP$XDzG~t=F=TSN(yP;UqMIJ8Pn#_SVa9mq`h7C=*;xZFN|K(yg#J=Wa7JqJ! zJ5KT6>{D)<;QIHU1*oCsb5ksRJnAA0pgQiUXEIur3rccPZ+(O+`lSovn0)$^5$T!3 z#O!T_+w2Vq6e#Lc-fzfwr(LT66(!ETK@r`fYjoC8HC*ExdKl{+Y7&b*Z%eV0>5m;K z7~Hz6IA-YW)rL6ju;Tf*Mg8Quk-r~w&A2qFf4y_%f(;u}qU2^t%hg+Bl0EtZJPanoppr4Rx+GkjIakB=)rryyJkK)?AJhu+9p9qwttQ* z$)b2|zhsGOQ)?v5nniH+c-p;~4>JC|{^AO>i%pGR+UEQZsdbwby0UOvR7qkK8<5uJ z#i6Y6F$}0l7ja;w<*7=BLhq^?du>1Ud&;fddGn<66cdg~kcc->{iHY}F70%_vG;M> zsqJ!Snx#v>9}~&3nGzb+-Q)c)1^=8>owA{MsssA&M-q4bEyqHQCI}}=X3SrdEdK#s zHwQ1Elk_>FSRj^+p8Cc|DR>@ZA4+tH{Rp88@zZXtE3+|~kkOd4V=7UxF-#<2@rog^ zEA~P)G-t=3HY=4*G|C|4OI(!K50C6FIOP|JAxs9Av$h$cYwjO1u@DfcEOmYiS2!RAg7=f(B+gRJn6kb@(yTCC}@W-&_Oy3!c?6o}_ z68;x0*!raltx4O|+G_cnFy9(FSs{R7JMrg$6%N?ehzi6gn;-SfOU+aQ;AYiPOFDVD zbDjIj0Bycw80n)FVSbb#94qM$O_4}_dj3EjxIsm`O+hB;TYrsUz$6#BuRNEjFInUh zNl&pK;~7lk7f@oPRnpC9?NPHQd<TyA_Mn&`t)$5G*?vqg5InE}QA1fD#(CT#DppqClol`H3_ z*rkm5^MwP2VtfX$z0MhHn$JXIW#|>eE z7Wqr785n)<1026!-d=9O5H>nkIu@8yV94mi=SukZmJNuk0TNwKcYvXZ4CNQULq!dVx!n>&#Ef(Kb|{}iV*qgx>y`p zlzFFU%p;<`%N$e@f1L0z|H6VcHENTx%pu%Oc_l0>KZkNGmV6kZ$g@fxiA8Dkq2tG58_!W8B!^$c+boIV_aH8WjE-;=1pMYN@ z2O=`i^R1PsySx(+3`zL!e)E)?i2x`h@|ExF?ohWaBQVznE2PvgMPURaQel7yFpj}9 zp(~X%anfKKrXd?n<~{}bPK99~61cLP9&)e(Q@sTI=kWaAa$J%({tN%A$d~nz-iLj* zN$_A@#p01T7*g%n0<6 z%`s8t^7fSxGsxIOSKIQ{0jo=p7!c+jU(82n#;(Rd72L|c$5sG zaR%F=PQ+iBAb-2quTAP$cB6A+z>#5ESBE<;njjvODyt4{L-0b9K=S&!Lz>Lk&yV-V zPnwk!lf76CA35q$rK~a5mg@ps8QKqP?cT@e}2Ni!`#W*x*GdJa?xo;Q{4_ z2$J1o01Y-5C~GJfb(p~^*emzXARa<^-|MEZ!K$=2qgE}aU*K))fFXzaODE`tuZR z-G4!+jO?8V?!^DlfcsXs|H|V47Whvw-D{`LHIqPTmum0vTART@@tk`VgvUP8&=_F> zo%I{D;|||S5d~J5Yi$iUf2mg9!d7zp%4fN8DlqSi{Ik>p)BB}zz#SL=SKQPU5H8VF zM&7Yc$ffu@>eG6>{B%A8dT1K{$6Ps^M9&V&n}{%1zF(AMDe!0OPQ2QX8P={N7(x2l zhTTTTr)(%b<8Y7tyyzKp3|d3j*5)ubkS3)R-VCf&ok^`ywTwaTwC-PnzM<5S=L!7S z%dP{UZO(dfk=>roI8M?j?!YOSDy$^t!1gG6yqwtkS0*04I=v?S4gLs>>Y!bG63rh) z&AJtuA4tFi(`C!sq+40xcDb%voK)};MCLvl(6-lW1f4_Qrf#y&-k#Pmn!H;dh0Hij zsC9qno=#NXYwj@X3dnp#kE;@f`uG&UhxobP4)V@(u6dUCBzlxdEDG#~ZbOlJE;jhV zdm9N7(sQg7F(Lbt9ScqJ?l1a9Yig;Pm}$bD6}a_8_5>ro*ZxPbAOM1Ui;Y=OisbW1 z%6D_5T{-bIND8WG-pAjX`c#2MD1*Z%1%R*kyq z;3{m(+P1zkEERgFaM9%xr|o!8Oi)}u}mcuN8(oU-hW=_32t;sH?Y?p(Jo7xowcedh>K9JWBAP^#&qQR6MmR11g9ID8-9h$Ek0lN?ZQ-juRI$0&c{(Nbkm{@M*fOq zwL%+6S^;Ptr*Z6V8sp=)(K_N^>xI^*9vY5s68|UaOct( z^4KAXWb?4(yBwj0{Nx&eK)qoIr;ieR(upB2BW(Vi`wU6H$P-FO#!0p#25px@zUO*A zq9rI5=W=$K?W3M^#f!7g|b$XGdw>ri^;y~3Oi0p=g*ILVGZ@i_~(txB}!M0Ud%xXWVY zM+95^JIDxGp89saaS)K6d!nNR&aioKvgcoVj$F9VUBDK{37o*8LBCJCfC{!~=jIyN zA*+o#NkGPqY26NEtgo-rORv5}l}d?B`nax70@=7j>p8}OQ-9!j{+&h4eO|)-C~ndX z*RvPvZcH_qkp9f!ep=*f(_hU=V@II{3x@^l0-$G~dxjd#20gs@fVQ_<)JxLb8S=O6 z+_`(DBp7&;gSUQVjb3@}bJVEU4ux!Sbt=2|SyTfb=VtL1TBzzhwaWw&<(>Tg`lff*8y9d+FLvH{yXo|=EfFfnIb&0 zb2C`J?^9#FNwsQ~ngFxD)}V5^OeR|%WE>iGa1BCCL5<&$atHbQS(e31E$WPg%m0&w zLi*Z6`V8L~bnDq?sDAw#xp>bhgl&{s-Y)S{@lRpxcFj{j<6S{RxQ7?t)cSJi z${oMRx5-df`Sio^8a165?$)y#DpE{)j_kZ&Wo>jtxYV2oaVRS>kwQmf}DZe6!7 zrvOr^#@VAv-&7(*7CX>L}8bexZ*6z^RYAq~Tw^dK{mwzD$rWF>q3 zwBMzwlTuBlmt~KBTI4IUyv&Z4w;{2-iXdjK7&c|+^E}rkLvHT_I!_huaw;KmC)cyN zrVwI)C44VUlm00ccqW1k%ANL-E`;-O(jZ3|dfwlqt8NHMiHi>07R>`1#Lg}vmdKeE zHs&yegJ`|qMU65A?57uY-Fmh;g_Jv4#jvn$|WQ+`^zix8D zEjhGOlcu*0m)CGQr11<|tHQ~r;*&a#^L^CcS$bhB3f_-I3Hqq(VNW2SR8T(?brxS_Z)FGI#@ zUp1$91}bAKpYCW<$WXe@cTUG^PbbD#%-itewhOoAn@w^gpu)FW8_J@XlHH!ILjpSKxe&JtD3L-I>=rI)n}Q_|pd7D3 z2#lkZ+H=>VLt~BqH;LlbvJUDrf_E%Oi=lGqgKmk2J7*p2h;J7H+QDM(B{evjp(p&l zEo=y#K7S53K)#2Jkfmu0=gvJ7YOHq$ThHzTv8p7cH0)6Zpj5YSp-Q^A?uV522b6^o zAj|9=43Jl?lD}4`()yZpu(;i&c&ANCuWxtQ3H(vIn*y-d=*zDH_~zPfPGIC$F`s(VS@ zmRFT2)dAW~cR*#Coi}%TAGu3MfX3^!km)HaWA|crhdASY*TR&vb}8NlB!DZ6A~Jk> zCU+iVG_Do<0bI|uZIfLti&_+JZPRYyR95VEd|bojRH{gX34X&R^-exDLyeI5D;cx^ z3Fl)7%Qvo4`Q|n90V02IW^_2~Xy)iO^KbVGV94W<9?q8o7Vp32ZTSqJ!3W4skUw*jQ}M~< zf}Q{w{zl!71!A{jDv?P9=|YD?4Q{$a&n|~HvTR6H`1#H6kKhP-zZy(qzg)%;0JMP5C`L4!@#Q?tDJd1t2bf@)#8UTinBM>A~JGm&856bpS9^ zj5n;KvbJWMLK;Wpmn(;gjG@(-Q{(%iL};DUkw1ca-e2_r(geT+Ty_^={kRuUtiNamP`gxj5?Xg6D@3!LH3c&BiCU8;;M_fts@z7J>QC*@0vqg zz&aNT9s+hN0l9FTQ9I@T>3p2wySdYu{FeP`tchC3V&{T`F;Mx#gOe3wi~+W<4tyU} zD%O3exPB~bNhV*5n0!XoQHkJY<_v+BtBOnOrH*y4&Df(zjZSSTaV9|HV28V()~JL7 zZaF1;@3!BgK&Vxh#_=KYE|)av1v3=tf#YK55JShCHVeO_4tYzA{QyM6e~&4nfX|kZ z9dq9bpd}pg$k*Uz4BHfO_VCIN;C%hZiC;}{Q@{WZ5lravVv0!T4l`~?!(S`h4@|9;n(TOc z@jmwBomHM3SEmafdk~dqH}j~k95ji%ba_g;I#ZyH1Y3w`pk14M^|aq5PiPC{3WCq- z{~`Y>O#p2a=7jYX!W9$lo8cTokt4+zfcv;yWL*c{n;XjXS3eX&e6+BM=Lk{MnP@@n z)T4WVOc_b4cqW%^VF%*Ofi@n)z1Yc0)JER)`t+pVL(#1Jyi1)Dc6>hXATwkzsaV5~ zh7^;;KEsMxz(y-%J{FIpanG{E&kENZu_q<|llWaE6eMt+D@o)m(qdJ`HL#noew= z>*a4Dcjn(me(~_fA_wER&LMKh2JJRwNt{!}P}#-lJtsT#)56(usw{B!z6DT_bQ}sQ zRdRj5fcN;p;~B-xV8S?gp&k7BxA^hz%mSVCu#owZDFsZe)VIGklYlzPT^Uq|#km2E zgE#IGV9R?KQCVbk#f|Lmo8AE6Wy^HA7V;k;{}J-_L*2Jq>{f zG&$J$hI8wEP!9R8dfo`&lY}-pciBUn4v;IqT>2I+|2}e)mK37cv-@45ej==UZKlEg z^Eg9su0Z3+H;{26ii|_|)0(~0(;j&cSjkcJY-up|#lo;t$Zw;9E(G-tkzYmbJ5Qd; zn8yV;3uPK2O~Qe73U;95?94t6$1gB;8imLb`IXAaT#ajGhee99Ie1LzNGjK=$}0sw z!L98@Z2G~oH^twLzM=bVLv5IUoblStnS*OQ&K+puAx7Rt)K$K{lFCp=1s26CYKyA6 zPr@)G3q$S=4D_%3!2f)?96V(!VBw1V@9_6Lt^t`)1~<#%c#3NsmyNu(c+e*|2y(YP z4r~k=+%^s4!o9=@GRJkPT(6Sn`+SYVFbiD>50;^a4N{_a;geBjD8z4x2U0AonJz8P zHE828bUNPhp30XMnd>BJoz?~)lcQsDb-F0ncAbF}Yh9;mwK5Vii&rI>qdXsMTs6Cy zQfhCkF-Q*mW`?oFn6vRXDL_sJ0}5*O`P)u0PK@spj3bKmaT#vlQKeq9u(8u2lErNE za1CUkdh1g|eT=0v9?A#~Ac zcWj5Rp_31V$FAW7J_Y5U&Hqvn*T8|trPYWLeJU*T=dc=x0d(TX! zNM$MNQhN?N24~#wkyi>xV*GhsH%5(d80`byF9%erRmnl!1!Vlc)?%C(U}r>K82z0c zL+vO(wR6PRC@v&uhehI4s8xQNs_71uvkti`25|D&;|-ms+wEJS*SVtu5O$@g)4^|- zT;Csx@5oRpv*LICz=Fk~F>n^%aYvf~#=g6FM`KO~O#?WUBD2iSVbByZTu0p=Ro2#K zUn^=!qL?DM*$^r%zgahhK*&4Z# zlxtNq2Y>%O3yM2CMB4*HI}u?&F9u{BmkhK#L@p8Pd+U_CRcd!SwApImP^X`&#@9Fe z%zwF>xDH;|1#J9j9L3azh?{Fo3tKW6Sa&Ja8&gDSa*JF>6myObFQl9b2(O79EP`8S zaAdF;Cm2ikEG+0U#?K$HLH&qAY-?S z`U9*dw%2|suujH}<0!}s-rXH!Dp90eyj$!U{bUQ{Wi)MXZD|(?uwh(!&{$B-dY!U( zK;6y`N$&PXgfjFc2;nc_r*jxL5)ZRfQF~{Xn$0=|5NO!zl7Q%3Kfr`~)k{7yhK(j3 zL^k=lR4G$Xt>ge66q z&9$ol#X0KL>&Rb2K6}(l44Z;Gw%Z*V3_{XrN>R51$3#mPXTM#?QA}aK4@Lx4>Q(Dx zlIu1zIkFQ);h#<7_&4zOt7pZ;R~?^$X2VdWQlqu?Yvec+L1Xv-hRlF}ri&5eg6@DM&w{2TcD z`Qwbq`>w0|qk05^y=^bZG7P1tQ!Z4!t&Mx)ZZOY;p zF0%UV=i0Q^6!ivx%%SR9BZusSU4Yld<96EHPMRcNhGYH~Zhv9b>s?i>{-n=fcmVCz z?PuwU+s{zFxwekx{I{XJCr&ypi#m#8YHhV>cYB+3maZ5!VO=W@Ly~aWN~2~S?Zl83 ze|fApj;OQS;z3`>`oD?Wudi^yD~r!Sn;0xMQA1b$TSn`zn+5F^i!Vu1+TPfr_Qoc< zzFHw{hTt~V$x79VZ3HKRj0wZ{3OR&Lz{$J4Hud`*iQj(=w|*1(waccxOSRZ}0-~#? zY4SJ2e(%?zo;r(gQNggKSwCs7u1msk_9x!sc_$?u%sJhap^})#F9r7d zlR6oPQGhqqG~6#c4_tG%y-i6P^V+|F+y4ytl`-?X@ZqkyfHM|+@K7Dyf|LE_Zm0c? zC>k^u3E40hHl;LeK72%(QdDWwts8JS3?1g=cN_+8Z2pn^F`WFHpP8caY0jwi=qE$P z<2tT08gCJy099tkKH%bUL><6(_1Y6W@6TfXZ{pE6kpBajEqsH|SbPRr9v*TX`LoDh zh7!IS$Ki|pUc1Z>mjN0F3y|Gx8_w3+*c{y-xrkmwp;~ztRN4F(!hD(sBi~m zfzxA7wEsnO_;oR6ff;UV@`5t5wA|gqgeVsdZ3^7?uanoY3s>_|hY#p+{URRyQ_6Mt zACTd43tU}XM$nj?&msR1@=qdv3HicsFIW(RLC6f%nbtTl*caeV) z`Trq*2l-v(`%5qQl;R?T#%Il>yomfd^2^AdLq0ue-4f!C)0pBooaiDsSc0}vhi(DJ zvNWWYK^j8CeOS282{s_8)yOYbjs@zx!RFoxQ|oFp0X6H?s6{DtutiDaOGSPK`4RGW zk>5hTiR>?_r=3b%M9_TX8uE4IuOPpOd=goo`Xxl5Apq{k6NQ3sgrR;WX*+i4>2kKD zWuO*zH0w%YZczAr={OWrD#IH~s z?;(F1`FqH1WW3bHEFmrmXncNGD0i!`7x{;gtg^Wb!9r%HPsXmc$*xw)>;!rVi_#Dy z=kWrdxh@ImEFUr{?E2sNX^ZY{_sDf7H>sR7ZXkN!Zcd1R@-yW|`8DK^kpB_+-;p0s z4&Awk^A1`W`8?%NeFgbT$fuB!j8h`e?#m|#1@O%=M`lNZ-Jq~# z_-(NdfUFy)^wyni>L(fbt~2$UA!x_!Av^(}|6f7=Im$s}=>8}2Eo5tHi##AVrcY@`V&%QhduF zlRt%`QX~)xs3h2y4UP$3gjdP(f|t>5Ei*mc_rB-pZW-a%lBY*K)3U7NI-W&6x1W3a z`8@}((2vm%7I}jtL2TS|3TUR2&~7;Q=J5wW;$ zhsSVkWEvi!YgOq$TXta^kPg}x=y#Ap_YqR)hUNG=v-A8~$)KsMzAdzX^(Orc{bRbX z16`AXCJmrk14h~^=H)e}+D6|dpNoF7&gNfH_Mo+fA!r?=Ok@-;T)v8pNa3raWaw5RXj0QUdMEul{aboF(&?o;b<^~DJH$-1yuTX@ zHKr>X8@w2{;8e4=4N%y@il8auEk83B+c(o|x*p-{!BNbG5h}jPJq*%BEB3so&6%I1 z-=+7^?`N-9=thT*WJ#?g&;+Ed^m9nl>qYvGZq}GS`+Th_6S-~`Mni-3o=vB9Vf8qI zX4_g(GtHFh&|KoCV{Y`w&?qjB&mhPNnaH}B`{Q{j)0rB93VkpAHqw3?p#MhylRiV& zI(6e4scg`s69g`qJ})DU{m1Bzo&Hji#+F1=Ifm@~r6UAwOC>^&;TlDe#>Fjb6805~ za;**lUYmkeAoUBE_Y}@wx{9Oc#$mL|ok{N6e_fIESRegt=J)8`^vCo8dXR2*x`?ts zTTeetzd}Dx|BSw?q*@k;O)Uu`O^_3|S&sOzrpA3b;%8MzA0;i!so&1z*TzfZ))m{) z%F~#b4sqaQ4Pj&vc6C})*XWn%r|2Ck zAXTqPp1ZX!7i1z1bu^tqE%dM@h~cyMqJnxz>Jj#}ZhaGKKG6ye4#kZ&SfTnA$^RVlX91PlTLvqAl*m5O20)vjTAV))2G(1Bn9T1 zI(MWYO*Luq;W;0n)!5z}qM{v>O)aag1b&x;*euah!JsL^J3bxa(BLQh>L1t#VHc9hQmWOT%4Fi;OS+rDYZGf?4anB zq?e_4|3tq{AEf_Ie@>r53SBN00oq+iC%`VGa6Lo!m3>m}NFIEeXzhz(0#7-NHx0g> zt}xk}xI2iG#RgP*@c9XxxG)8e?^OY7%kZ!{2S^E$iPD3# zx1Xm^(_he^();N_v^bjE1){{$&;MV|VKkSiE8kr9CTdamwc&T2f|7otx) zG;{Qr3;+@HjqSPk59KdfYl61CN0V&dXheJ&7#hXN?*q05x*v^;_pT7{D{KIUSD2YZ^ychM5CNkdu!&`MAl z&&!?2^C>nmUB|$gu_VQsO^d)Y9UQSP18vpLaM{>8`bGMe0@`2Y4gDz6^t$aNjVaIE z+88-|v@Inm#@FFFA9X^vo$1!21-2VsF9V>}>8}MeNwgM+hNM`?wTGBuhnZqmm}15# z1itRr{*%4%pmj1iR%NPPuSh`qGj3DBekhr+olmrRNsCzmce&xA9&7CA3$f9QlVo!@ zXv|hXlNq5~iM@2XKzSOIGa(KQjpF$E2}H4^n9iMu?MNw2pbc7_AGf*^&>C0+Eoo%i z<)<#0;RxG!q;YgQz{5!Xg5zHNwFqh&t06t!BaKV zrsiO@g70-M#r|Kd1WoJPCeh&CHaoqElGKRjySaOkyZMBz9xEItY;!#d_g5n(o@2VD z*Vy?)b4!rMua(Z4caedi2$SPAld}yR85+Z}3lj*V7=ggqg%tb#teNP%pV2L*?<$a2 zb^$9vDrquFG+SB?9!rSXfJ3uB8ia29Is%|AL9j`Etd6hl8bise`X1KgBU3_PyWt+0 zRw0w|?8QkO9vsD`iCGu|7I@_}yX;BpZY5~>S_3VUq(&UarPjc}VI9D^x`)UM@c5Q0 zHn|XudL2HY=&e?g>s$g}QglL`wKlQGzblWA)P6rOB*hpV7@uii;0#mj`~(_JLQL>f z7gOwd8RIQF6jr0wK+B}$Ux|%3FX2L}sLd(-uVyiGaTxWf3G`F~Y~Hj1J`<>~uZoHv zpz0fV#_+v?VeK3JDm;Rx13!UF7K$T>p$lX9=5!6U$$GNBTwk^%%~ryBcS~!aQI5@N zq+u&ngpGRX4WNyJN1*=G{}uN4_Y)2o0s^7brP!p394YiM!Ggd`UIoBA)~`peK$v{* zV;$eGzhg7ddpG79P3}=;Ym_UgKx@N2ttHxRB>_zye5KNZX*D6=AZ>^4OCS%JR;Ny$ z#McMD1gwSjJXYioTd9k$u|vprv-L2kJ^7m7TV8AV!SPijK=$>uyf~5{w_{j zwxnEbywV3+H?;=ZH94k0g-PNgiXxQN13{&N%NH+U|Gs`S!;m!v*-beBr%E0lANv7WwIK|I_qw04YW-1z_m6^lw4+f4LhGCkhvLZW?BJ5r(A-!rOpjFB)V&zDo zQt3%1em5trX5&lK9X@mj$B!LLQYiVZKnb`>vhCiD6UUDg3UWSWi6*d@R6z-dK`WjvhLKIF1N=wIiSlTwxfZf6rd@RD1Biwryzg ob2la1l5^EshFMo{U8ZLL4@;zw*<(7R;HS&hEOQ^7Z-9;kRc4Y%Hal?{?(q9UP@lZCTtZ6h zXE9f2S}-MR6cp$_`04&aFhC(M01J$U6E+-T4|Kez0+usJM1&BCnH3@q{{Of5<=f&5 zUfYZ8t)Vj%5d><;XrEod#94jR9%zLa%@}`6PM1{V?T}AaSX|dZT)04eo04o~UO4Dg zYu;+!0LrTG_thS;BQgzV=V{1LOX9-YkAia9O7xl~!$(LJF_qZorkyB{-ne8IV?T@! z)fi&%U6C(AXM`@3HxZQSeUPRAr57xeOTN;wxHCfpgE!bLWI;uA71^KHUW@tdAP?9L zD>p2I(azC+3f+rCJYiHrFd7Har9yC;rUO=}>ku}a27f7Df=7DLV)PBG@jME%{qWw5riLD``SdiSswhvmMaFaNPi zFO=c#p7|Z3WY(k~{(Vm{7ybrMlQ;A)5nz2@{24E2E-U0`1L}VWUnOzL=x}zZUOX5o zmO2b+l=YdkWdKD&!|*t@Et{Hx4TT?6uV`apx`(_0;k%_}W%Mrn=cRnixG5%0@xiOA z_RLAQ%mu$7{F2$h4addja$oSe!DyQJpscLnWt%bm5aiii%H0Pq!IXY3Fv5h}z*N+85bwq`!2CFPqi0m}1FI7Cr z8EzKk1mh{p|msbYXs2%>{sb1tS0Ic?rp7o-&8rwElX#9@WJlxR<{a8`zeX{fFlz zQi`s15ajcxRn@o=++lv&HubQQUIEQY}7o5w`w&{86hafE+{JELY z3l@isn`TfAUFZP$3)JMJEzEF&y;hP zy&fH7TviXH^e^GlUKqnBVso1LDzU-vQrNk;Q(BUs`T!9Iu9%a8Pbu(&EQ?Z3K}^-( zSl(Xs#@5>)Fx+}rriUMnW(d0ngr~hwN^2;!KTib<;Wxlm|3zhG27sFqg2w(uV`*^I z*V3bd(#rmO4G=m2lTpvB8Auln{lvdT?aOQOpY;H9fWe~5D+72({$Ad^vo|ou=hXPE zacGUw2xf;H5Xkr_clt#x6)@l-lPgvS@4)lIF0>&PW%fYUDP|2<%#Nvpoi$?ck|%w{ zTJKL7D=#V#Of1ClVz3vT;y;)t&H|5Y6cd2`&MAD#NhXJ}$z~C_Ruy4EEmv&-SS31x zr-uz-n!XCQD@cKpn~6LA@gl#+x4GX;*iG4#5A_Q?Wn?&onpoN(K~=vET2fXn)fO~& zY1lqMNoTH@ItIaurIVWi4jDau0-$=^Bkd z?l}cr*oSX0KL*d`f&W5z%vQ9;$&#yq8H>Z|*I~G{9=K24#Ni`S*h2xa*aRVr?cQ7U z&FaOqIA~vqZ6XJtcXgjt1Dh#bxlC9FW9E`TWjfYrOo|lqOoRgFP>J3<5PTeKNIg&i z3m$D(eYQBdq%VvwLj!g2ZMsnXbaqEMp38DSsiI_nlC5asOy!}kjZit;SY3Ta_WPZr z@9b^UnqyZ3w%7!t(-3bMw77oB!q!|KN$Ahx}CJQ4+ z)2iTiX~>RDDfVvO7xzwTG{(72nh_irUf2OmYoyj~k(Cu`eFs^!QYn-ZS#tuHgp5Mt z{6Ki9W~-|Mac$HdI3aVI)4#@C2sPhc3;j7Y+8abTw3Ypv$Q0PhB_>Y9ZBn!3oETDt z_)ABu7xkSTV9)TLYRZLh)wt(sY$MxyfJ&^HtNvBFzBbo^;CA{HShSl_yWq*9lz>{83enp(owx~(AqYoF1?U`qB9D*n#1Wl~ z<3EAU1IuS&{nsLbvK0`2g@+T8yQkG3uGNGf)C9z!?7j^VL+w)f!>-_4nK3`te*lt4Zj^g`(V4mB>hgsUabqh<#c-hc+khMq{0!Dt z?)H6<&%r1C9Jy-+xu=$eK+P^VA=s8xAHe?FatX0k71<+IDcW!-!|LhQQPq+W^E|O0 zH@>tSZx2;q?r&7n4tDq4PxnW_$7E~#V(B;?LgMMvK#*&HM{G8H6Y&6_GwusLK7_c>)1N~~NCzSg!olbU9vSuC^W@Ok< z*fs9+@3JbNPXJPFMFo=QLzG8@4qA{h`DNQ!ct6Gq0-hfKCDUAum>KW`{Y7TfLj=NB z$y^DhEl3e=2%~TNfU>kPy>`x5Yqwkx^1{aJp&(O>j{)JKzn88*akN%xLAVD9`n(#W z%ldapotm)KbHs7?fdH@v_nb@xCBI;JCD~#(P0q!N9kM*weOHzAWFhOWgtlk%`t|YP zHuJA9zFd+{d;RlThwMsH_^K4@)ZUXrL63$r+A^m+pYYG?W>r4Hfc2Pgw7mLLQ=>X&!{DA1|AG&gj`Tp^r~jow~?eo>l4;d|V!pwfsG+6C4WENEo+5?(O}MA7^#3ce;9$-E%dE&U(bL?=v)(Qx;E0C63=3Y8TMQe_mTAf)KSTC4xgO zPnc(arb*XrtaV{`lw#et?x22BW7GY~s;W$(jf;>wigU7B(Dm!uilT;I`;TsDR|}z% zfaY=J%$0fvERL)+JyOOhokkbOIhX1eBK-N5ds{ArZ1-GNjiglGk01!+d1daSOM18H zIhg+4(y4!l;j*=GVu%9@Uh)!ys`u*H5A=RJPfZZ+Qficz8h&|p*u=djCJxg#b^%h! zQ$B;$9w8t_FY{@x_#Pgvu2<9zn(8;ws2@Ui}%&?%S`_?5( zM2H~2FuEMg9zy4s#NNQ(#lKmU=YFTFDXpYWPu22v1c%CM=)p8DS~PvW86I2YWh=Rn zd>@xWdU7H^?{F}8Cq}fPb;rJvJMI$KN?s#JW3;W@ACrj0&~lgXLvHK^I1Cr6&`vW? zh1k29-ody-n3vVPdD9j>f(}XRcYNu7Vc4$}c25R3*F!d-f~b0_h>w()4B4TQJI{mx zoZ7gXn%%HH`Z6PpZ(-ijgKD;(W|t2zTzANisYh3|Liqy6FmF8%_@4rZzD_)ob=gfW z5vc;fCHp@yPLv(qbhGJRh)>0GZf&}6YcWvo1TT~?3h0EE&^gc&>H~@?r3Fc~N$TX7 zsn(Q*742xtIdGMWtYK18=iVRC+(s$J2ptiUqe;7w$3>j>MFoFh;#xO+m*$~4?#L#Z0(r&0g>ME!$G)bQx5UOp zs?kJqO6>A&LBw;_uw5YkjlHVFN1VqJ467p$acib}Dn0YL+q1{FRuwc=$3|)raJt>2 zu%~L@%E{P~9?GdKFdF7CESB(=*b}M>P-_AS*NE6V0sj{m5p&5`V_Xda1E zR{>lxyij(%Z|w}HEthlmW9rx7yRYTk1%5SGjv;P+*bDwcFZ&miottr^FrUN-&_qX5 zd0WB#ht}1X^+mY>!@m)GuGhBv@eC@paWNCv3dYLExa} z9ADHEm~QAR_OWjUXUqV z5Y z4irPicHdDq3kZ45&v0TLG*rH_1!ZkL_ZzM{ACV0#ZBSWvwl{obX$cJw+3v=9?Yc55 zq~2fF#+iuiC82@C=`Y_i+NSC(Rk>PoUBK`O#!JKIc#rD9Md}`J)Myj&t^dXod1XSL zX(29w>WTpvl4zRXEnliYS=^jRy<4HYlRPXWt;!BgSZFzF^Eg-YNMAs;PM;iiPc8l$ z_6vTMJcgWV+A6UU)ky zDAr7Lqm4GUY3=M;Q}kYZ-q5dpK5w;uq#f0;5X}TYqfF+kG>~(!^i9psPP4 zyRCXUgthFD*Vy84vL49s6;B2^<~%#@MOI_@LuPTdo34bG-g1;yulm)f54L>TfEgyE zwC|Ww$vhTK+Rf+X{UX+657`m3krcHP#a-$M9jP?JZ+p*tsBeU(-INNL4MAJgb82uD z#Wc_^kpr;_>=h-r8$Yz_m-{Nt4)D9g8K8?^`~#aOPRG2!P+2;UKf`7|YhJCWbwk-s zPc_{ChuwA&<+=!=w4sFklL2)eE}N@?SAEAz==%2s;|jJl-@44E``!jZso%&u&YoDU ze?km}H5}urRvI?#X%+iu=)m>H=_$MZY4boKzw1v#s7?YhI~Kz_Zr*M;+lN_3BZ=0X z!-qA#IuK;g*!=>&l`&gI(s9wVl zHB$syt<~s8OY%})9&j)S(PIjtRgExIdNTN}9+`0L)abD-2-$tBhe%z9lM!_uV4irt z?80!561cK`box5-qfU)J%#oKi-A^}MC8(F0s#cgKdT>4E;k&c`CNp5k_DGoJYfyTc z>hfp8gklto9a*EBY|-2x=&ne%BaUCRvlrmQUlU^XVpUC*n;AC2CJeF7=V1Cwvou*p zAMJOnKeU?_W7NVGyF3g$TtjzJ`@$HU)c;F|S&uP6dDw7?W{k?4O zPuIuJGZb6dop)t&|C1`NwXb3wOXI&m+msr2`FVnY_U^e$cVs)n?O;Q_#lxLSF(w2l z^Kf?_$OENG=LR(i)uwk5gaNgsPz$QPvG#K?3bgTdUS_a~sCbXJ_7+IW6LQIbIwqOi zwu1AvDns+UtMMOUe>jw56I47LAM}q+d;0AP@vF>e;jCq>HziJ4N$h%N#j#+Bo1p$# z_xpB=o@fVcbAk!(8ms>~wnTYA9&@&)9^sYx!xn)9@Xrq|-iYo(F|9$4_vPOciC@#~ z8Yj=VM(MPtEQ;&wg_{mO>~JQc38E50poEY|QpQz)s?yVEld#Rq+SGc4@G`}nC*C_I zE}8`IAd+CxMMrk(ue(<5ptz$t=2Dh5H7)zie4=|AgZRr+f4Q$@+NpP4tWou(0lasa z9i?W|)h1*$pj&gJT#gGQ}Br;B%;^uYho+XaH#NZ>I$KIMl+7Lv26Oblo z^iH5;!N!Z418SOUmT>hPq5@K;RXhDvs!8+hQlN-s6G;@28`+i072 zeiX(WxM@kD>r!42vl!|o25Hb8hf`?BMF97%d6{SGrT>%9@4r%Z<@;=-!<vfE=0U zd?VK?L>uhXg|ra`PjRJ!sN9eliMFj2tH66T8;G+HI#OhS*j)3O@oFkb6m*f*b?2f`@h3W z)n}SD*c__xP=>ZO`&qq~fH-joqDAbE|g${rlou`deDqsa5Su9R_b#I44 zSKs1juQJBCQXwnHL1<%1!DR+i5SO~u$#)&k#}~A3P0E@cIug%P9Bs6*u8Oo{ljlwj z0tGuXye1obu!7ZV<|)m|!VvHU^(S)vFjn306qAa|vxS#NA1^Xruk95I2?dI~BDe-k zBcu2j>?#sMWDfh|Pj9Swyy1<=uhU-fN_)NHSYNO%OsVq1Qy|xHs&OYg5CxZ^IX%~$ zN;>naIFoO2=ZQ_oQY3uLZ=AautWx{~CgC4@y@lJ?w&`s|8DsMKM>pn$4GSiC;DXS} zAqi40WqYlJgQ?@VSNuioLSt(7om=j>ccTnJk8KgY=-Z&}T2fI=X~L_XADidsoU^8| z!_%$fJYo{#f8+-n)whnE%1)){q%ul}afz{={xsYhYI!Axwq=xJm9djivx9s2EM5gI zUO?2ktWCv67}Q|?soc_waV@4GVc}+SZPKWly!wJ`f2mzqOF(8#O47*pY|WEd zOPL0=UDpFP)wF{_ua2B`#9GqkY98V^X$hNmL(}R!DC$3m@{qgP^3rtDrS+1E5{@Ed z(`+vvvk2YR5WxEQ&2oN@^;#gT;WK=CDx)ZOJDCw9+@w5Uoqq((Bu=-KOnu5Vh z(8zLK*fgB$$p{A;n}X~^;WE?F2#t-TdxNMS@bxA|fUT@Ztck9-()llF%%LQo$KzJF zD|Z~X*~q5_kufz1F810GxfOCXv>DmV!K@P9XAd&<0!)U-bqp9`MJk8eA7CTO9C)4K{g9Z(5Ku zvhe!R>bmcy8ebNB0m0PU(+yXXJ%(xZtFB!n^G*fhBg=IX5_usi==5-XeEy*E0>39B8l#~Q z)bySp%^Oc1tHu`2-=bjpRtDVaG()`J;tQ=I97!N1D0pam9Wy1M=kl=Mj2e#w5(&6q zIZ`ivc{GQe^2}LgD6>7+Skxc)_M4*X%!d4hd{MxrH6N4B+lx^^GJXrgDDrI$n#Qm3 z!5n3t+TY8xAu7Efru33l${AiqOn3f!5Oekd!)dc%Ytx%{aX;;dcBCILUi#PlA*}YK zsHLWQPM6s?AF^mUrS`BnLTBC*Wf0Qao``T@W*T$N_s#NhLvE~0N|lJVudp~;Sx3}5 zhdHTP{Jt8STv&Y|?;G+=hlD$drb+Y$X_|e4UPq@ck6@x`DG^_Z*dYk`J>NPiC=!HC zmhf2yCU_BixslCg9WYhq9bXhX4BNxZ78?OBjs&BpKH>5CBR0V_bMUM#_NoyO;?47% zrZ@!`HEG^;zyv5PV4QdVWUJZ65SK>ymgJ`*?SG$gWPJz##E2VP&O8T-;aA*0HVP=H z#<2YxiuI1WfVfTSFgD$(!2>~#yeCBUg_PjZYLDaO7W=KvXQlU-lU|ABhev_d)s9o| zM?!0iI*xoZp`Hy9^kI?0K>G;__5I&0aZm!-0}bu=X^?dZ15o_$Lus-C#ySPRRjO9l zCaYJ@r8c;t8fDkS#MF7#fz@CdRZB<_5W7@)h^N?mR-tB+UCg4i*skwoq0E0V zSSd>MamBk>94l~nv%T}KlUd9QOL}VG_+Ag&x!H5RjLE_k55@8J=jF@M#}!v9+nEcO znpc+7N6?|xx*QO>opJ_(T7QM6+@~#hG)f8wd&Ir|YCy2I+|3*gBHvO+5ItZ`N2JLX z&E32Fb*2%lA|8|wMOZ?6+;l;fE6cWsM>sY}LK0IL!4xXZAfyFPCl=dgjYe>?q$*=D zTL0FCi|2V*>?b>+2~#p0N9|hgy-fvbi#hDyG9s(~&v5feJK0k4Same?;GOXkg)o-O zDUh?Cto9<0c=K+hf3S?K;%^sjn0{03&dP4v_heYkm}R%hgk(TnEZam)g^5{XUIh|& zNJ-$ulM2S&2;GUlzmw)kCdd5;hy!PmZ)0~0QsA?Q#+;fBJmak&Hq^Eee(`>m2aA-&vU0Q;|%AIKYXG^9u$$Pcaji~(jc;faH zrc-Vq)}iNZ6MowJ-QOt%5FQ>LtDCmk9#ye+5K+J^dH&d_JWE z;FeTO$1p)~<~aHjL@pPI#;Q=&VxJW`TzoLkJ*(~3l5#>W|MCZO>mN>sNg!!$Ydfk_Jbg6mfcoMCOYb91JvvIZU&o&dO$-neaIBuNdF!8qPUa!5E~}wWIVM>@m(Ductn}m%q>X zeXegtL9@*mXs0|Xsz|9*k0rvC4HDw z$o;5(hhcKV%(PPF7_jQ&PC)z77B)eS=&!%4Mm&9=D^5MQwO3@;O=%33nCQ9AUD`ti zo|i*<;qe(aE=D-0uG+~-BXc)p$6fgbzw^boA5J5az5a!M?9$;NkWQ8?#-9(_bche7 z&04Uj(Bkzo>13!QI1vfNuzVe@-g1W~mA^>KQFRz2cz4Xt?SaXK7J*kM%$n3|v!X@e zS)Jh=;Bj??0>na;$Q&0ukj8OB4XGp`a+k=1Thy!dfk{pQU$XY=E!c!oVfzonFcY+4 z@?ysIuL=zJcORthc*=9YqpUu%S~|2Lr=Q0|l3ahh^wB^g(@~%> zdi@uas2VBS0GT@kbI4EulJ*KX2~h^T=A`v;acWv za$-FY^C%9na$qvn{ES*(xN=_Knd`~$ZHy!IF=n~a;c~iRi2n(3h3f5r*S#TA6Pv{Q z!C12t@vP7nMt^+*mB2QcJM??mlFpbFe52V=o{~3Fw&=t|g6zyucG5vfruqil*VZHF z&VgV zPceEN3i8L1)7SBv())F|aG&Ij>zp~oKRN)R)mz&1Pks`Aua^_yfb+HVuSuhvvI1#= zSp$fT+c~rakQA&z0Xk8%nUTMVaGuXU{6inok65EoU(zm8x+pa$7Ici?tO)4%xJgS9 zge{WO+Vx@`(RM$(YG2b>&fehO=lllSs-p-8uQyxv&puf8S#tsZJ-IYT@jLCtMJA%_ zcW~PMFmNmiVA$iq=2nV1)EbQ|yxJP+*Cy>o_*q=M)_CZl5F3xr`qRw-Xb5BlVtX6f zYVUC;y$cEn#PDlx+Ly)@(=_c8l%-Ty4~cT8Bi_>-6z%F4GU*A74KTz5|>64){RONB;R$nVSd zI`VV8Tv+IJx%Y#gLI_=xA1Xu5CgE>?tv<77ZFIIl_0sLt&DS^3+kY0mQx)*K**<>t zDPG5?xk;*CCCtdoq)-T8)aN%;J`|E_0!4j6;T+mRF^RW5U{$o~M#t82stna__r{|n z_7|FsCYmX}U2oV)Y!%SfOkS!+F*hZ%zF)SV%s=WujdRR!ajR4IwVIr?)Zo$LC$8v`;l2?jSQ{9U9a`Ta_xkR+r!Lu-xK6{e@aeG zO&`R6?meuDL=+#tZ#0P`UPAq=<@Y=cSN_%_{1X3Zrc#IeXI>Wf zy>STcjs05)bw(~4@{@V%*Iczd@JAJnu*&lVXX*WI0Y+hm%+b}vCkwgVvDO=_8&2z5XX3ycE1&RLgpnPh zmhP`Tb!dE40d-{K3N~C_0RQ!r&3 z6%2qddRd~WH+!HKn`1qk{ut638fMmS6PdFt@N#f=L(2BN>fbk`x%;^Jbb`Xl0Tcsa z`DEj`-Vc=nppps8ov%+#as(c^XL5K$8XDOCYs61EE9hC0Q@JTmevLFfIc*NO8 zp7$t9xbf6}E`Ht)@ASNsh*lKMQQf-@Nf@Xt)KCK={=FQ6eEYk98F>is{6wNprKhGINt`{2#pD`V<_(w(qqE;`1Lvq#)szfJ zyts&?Ck(6ZU9xrUCh?jTTw@n18_*nuZe=4KV47P|^qT6-(0Q0#lQGXJxdOw;Dw=w|PyLFzyRg`*1Q#vG>|HMoZng9T(fW8|1>#hiUYY z|8n%%x<42CyBVS7W+Sw7w-MEe6cG3m*KX~(zmtu<9llbZMB3;Vz7_oD?HH>7ivwSG z7l-7iEIQydEuvAarZ8a^7$c9T1|tP-^ds?(dJ|H$=~84b9yo?k-3kFICdoaW~FE&r$sK0Lk#*GQQuVYyRlSw&&qk)f@2r z3KHP*AFY(MG@F2c{V{byH2-)M4!p5Ys-d?uoKOKY}k7X5QJEEYsQK0n{V#}?X|xb5poJa=5%sQSZd9byPn30)V zT4haZh$~{Zj1UyV+Wz!Srd&~BMyV5u76m_|t!|g%e+3iea>n>gX<8*r@U6Md8ggDJ z3f$H7jv~(XMm+zz{a6FueBkA6fClS&B3xhRsQ}yJ`MzQKbk;l<{$?hW z$rhxPYCPs#p;2m_acF!(o<8~qukT`FD&7@IepRUEmeDtM^NQFO7Wd4?4FjXvWWJtb z!sAVMWUOWP-c+(TZB@3i&cbrRo6~_nbmUVMU57j4OauHFe%fGoQ!QmM1h|u+*X0Yk zx64vW<1)QMNwj9p7Y#FpauWnsXrfc>Bcj_XTnGeq zN)_9TM92R3pu-(pv*zOXKP`e|Gow~w`N8`-w-JnVfMQ1ny;`=o77|iN9tpixXm`ov)8U8Q_ zpk;A29FrxtjR|bp-RVz$6IH+C`DGaBEid%)Tt#urK#vF!dxTa_{Q>U|tudg37Q;e& z6lh4EAFj$3j&7|*g%etf0KZHR8+h;^ojJSBe~pp~i#GJQ6Y5z5gYg1^iQ~YyR4c4u zToe029EzS07C}Vpe=s|?HJN=W5h}y(XRN^bAvh>%Ub&C6rqO@*WukL`krW1VjL41( z{LbOtgG{{I!6igN+rFNMJ^s%Ju*#o903dg=c;>*@k#fG+%w*$Vq!x!=DGNXZTuT!P zPwGfou02vEmQwczACV0VUu_MtX1ji&ywy6R8lp(DPD+)=OMr1e^yI%k#|Hi}-bvn- zs|W3A-%5e1jaM2z`_&{eBXT{(&ji&;BWDANq{$<+6bJ=nBhDh+HCj80NGb0Xa}R5z z_IbMCGje;b2JdQ+@aMtFo#*a5NgNS>q?qGWm$Jl>H;K^a-L6<=hWOKgHuGB<>IC5s$~Ur4dULZX z@hm2C_caA2Jtcb2%uJcM*_%gJg~}!;T)6Bcgay9v)J?+V$o#E#`d^|?`-FN2@%CJT zb*RV1ac~Pj$qzNj3^@d0ohgBba&vHOqDO)-PG36t{BdI2qwDQyJj4ulIW&fbZu~)k zhD9%?CkVx8B%SX=1tE(pUyu+8>_{cW(l9WuR*~Wv&vsb%_!JvuHelQWtC_I=p$Rvr zSco#{r!WR%WmU}=ssG4l+FkZJ&pB}SasZ&sD1=}4EJBg%?eynFMpZm)S~dIRqU}z* z{?6|NWvIEv;+diX*0C;yqfG>Ivgzyy5Q2Awct5~zi5 za-{!jaAXPHaopBr?Nu|=fkh1ex#AHsqc=IPbJLrm0n@|e${^DxkDzZ7TqObI2-K8V zE(`?dfV9%;hJa&?L!7VHI32+8a7-n@HmWi^Sz?<&?{&St(u!Tof}wa? zXkNuolWv?hB}S}UB|u)>V`NUL{*|giVPp6%6)lePtj78+fTB0aM;KiBALH^EaqEb2 zYYycpma_o>B0u4^{30Wyj0wpTTnuY8r*Ez!pmTC)q=n(;?+0HI;q4Eg(i*!6Poe&} z@r4#9nmj0A8M3<5n08%)6wRFNV`5NDEInofaG4;>mI|~(wkpvhUN7#D)bE)UTQ$IcWySQUDv2$`& zvo0*g*(Q}(+PFnSR6y*Dq{twJxD;)yPl%&=jjl-gs|i>01dl{usA-TGG3ShW9)qW` zDt(x9^EU!cNw8$MnVOjbI+8&MpSC?5i8|Cx2_)D>wqRN|>LC63YtOxy`O`BZ89(M# z*xa>h`P{&05dT=`(fg6Y8Ur@7yfPzJ^#I4gDgl|)owaVF2EYIB_-H|Qk;bf+G z-M)r?t64&?1mfP<25i`rt%sRhkxztht$C?3`3}-81zc>i$ZqMk`{B^EB?o%1?iy6> z5B1fMs||-uZg*59oat9NWU_=ZvOY}X%q-FoiF%xVYD&ZCV-#jy6>ey#+l-SbmMx^z7eu-Bm!kZgLjaHcd$3eiD!jSocEgBWqx1 zA)bdg__EI32OX?cj;TeD%}J<8;nj^3uCG3Lu&d^36VV(UeOAi6QkgreL9g*58t68` z@lf>#ob#-&)?r*;nO*!l3>?-@Y@|jm;lG)V&F0qruD*+*tMTQIu$pA|up;lG?$t+6 zzJVAd(|^Kaq!IJyy|*x?0wS||YfaJEGa0uR$cVPdEwWeVv$Ff-(8Y1HZjN1aAf-ea zMn$9zUPj`Czq;36DTJyzrN;4sup$vp?s;98<`+ily}FA_f|_btkKW*3gk~Ey<8Tb7 zr+d+hjYPA}dPeNoe_lnC!v%>GO;h7(b##(*qhG!Z0VIj~imKqbV5sbNJQ*2a5F$I7 zPMlq);rKdQ2$G#-CY}Xm^;Up~Z`-{rH_lq>o!2hr-f`gs#49voDtTRdc#gaq9dSIF z<(Yb$xDt5Goz5HbqLDH?L3R;+0<)!-TU7BEwYA+v=NRh-c72)<*V__=bImKv$TUcP z!5Z;|N-o_;tudSTvF@L|UL1g|((%+IiN}r}Y_oe{AmZwTFdsu!p<28&3PJ{Q9Mf_ zOy00&We?Fhjc;U^>CvGsAN7BKf(`*={!9-U=p`kcI4(MXH0WJaWB$L$(Aj~Sb*rj% z!-|Hs^5u&%Rtr4pxppY>g`#7>o3l*DZ-<1*_7Ouw{vLwUU`;(qA=bb);78+J~)Bx4oxmFX`JE4O8PM<8(amH>f#MJyKOUK+*1B+)z-oe9>kuXCR(i2>Yvg{3JH(q?@qOu;wRbm& zJi!I+Lvwd_aHeIG{UdIIL4Vj3#_F_TxK*XFE(Bx&hLIsQOnD~FIb=$^pDrwA#|Y#f z&=%7YUZF)Ji}o;NRb@kI+$hge_fNXvPVLwWW>5_;RJ4)cf z)x=Csv_X4FhT2u5R0TPk0_S90(9Fq0|0;HAYz zb^3hR_IK*CYIXVuD$}+k*`LN5kbpSXo%QpMuz7ou@);!kyK%v7_TJ~ieC9`jt9UYRWX;z6xk&$VIwaR%c54Dp^K`}I0 zvyW*^pf`YLepVU9tYx_FVmr>n`%#te|Dt73tk9gyxds!kQj*>Ay@mAiqYzobb z6Ho^D0T^>oc(UO67f}-SJEQ~+j${9JrP?5bMJm_?pepdF zNf|)X>h%?ts?1g9DNj{anHUg-F*L03fp_K*vJ=M~NZ6zoD;ZUvm}D~vqPbQTolvQr#8M1H3j|z0l?NQ!p6-P zw$g$F9itnqiz>SCn?CU#RHw4nfrNbLMKo^>)uI6@zYy(Q*dxK@ry20`t-!lV0fhzb z`R6{D4Q;3x`1JI&wduh4Cls?Pb*`wiRk-e?ejl|o-8dK9v^lc@&)mwwy_BcbXyEfr zfdLm4Gl2v#=WAbjE(_MOJZ^j>8PZ|~<{T8%+2x=(MLk6eM8)p|N%5fDbp^5@f$V9D zWPFRHRBXm1M~I*jRZmY`UA?Tmw-ZRR!xOmEvrmrq-1@ux%gKUF{)`+Z5aXfMQunw- zFe(_G7)>P40GGRmXI^r3qbhrz%-$?VDzslsnk~Vq-5K7?@TBj~&ch0SYGdx>H@l621!Ie%`13aHQ{OcG+y*d4=QH6Y2F(A zUNM4KOY)o?9s2t+!Jq7XrQfOtsm-9bT!{k|o7?K=8+;avi$5qb?I77Jzuk%qT1*j_ zJPLNxIBSZ#ASa0Iqi~LxzAkyH72?j46iU~!Y@tXyzgC0!Y5x>OMT;YkhbPC;jnvGn z$boKguib!`yc#~v#@O*wtpP=cVyFu~QUW83IP{(I?E5epj@HQpN{&9dMu3qLJSd41 zz06Kto+B(=THU1uO`vi;xMo5fIaz~LxiRegq`6cQ)f0J za*b3XwZ`S;iv(HSgAxgDx020GeqYW8ppfr5QpulTW-Rm4yIVzo1`#wv@uunVuQ>JU;uyZ}0aZ zOt;E%z6NI6BpwNY>Y(vICV`HEP%4mWosWN`KFf~R?>$8>s4)^6Iz)hB)u2|D z*|u3wMoo#Y3_?<9{MR23;&Cr^(XF;P`kQDpO`XHJz4~CqtOQCU{~dW~r5Uj#g&E{# z4;2P))KQ!bv}}hB4YK z-i8|<>Vq@ii&ict(^JEDwy*9@=Qh>p&0q{<lEKcU7{D@12qr~Yu4~?cP(%^>RI%?S>cJS^&jBe@lBCcA zC`y!vojD|c)Uk5jam7Dh5+gM2nXL9atLlPk3i^k;UUT9@yPz*o22S80&_Ee0apYnl zpd$g1uXuY7cCHX;+EAf3f0SYB6+-PqW;{KucplL1QJAy~9TR(@RSaT9))(UkaK=z{ zmpga0#uwmgx0>?uZR#d4VX>ujRUga)q@{&K~$#r5zYb4{8>9z zQLqXlwhs6Okp_Mq!I}oE&B^>8Yj3nahi7Kv3&p@`lb3+Vg27CPlft1mi9rA=H z<|eY^s`C?zorh8{{E+D)>`9SV;9)Ln6YaSDpydYq44zM*s;UL=y7S;zmZSKG2)XGD`1;>;zDQ<`$^4g6l=cKMqVZ2O}|j>;#}4kh_E z=Rr<5XOFXs%kQ2i>EtW8>ad8P>J44~dQ1mR zJ8L9)wymuVk!Yl5vg-JAJj@U*zJMy{arv85sbJ*PX$92b6TLWbvJd?OLm12D)JqbO zxmdL>kL&Fl9Ky*n18N-AAgZC=Wij$RYG#*2l&J+S%QBg4HdEF>b1H=g@A?#Oxoszs zRzv|&-;nH4=4oOY#s#*qEOJa$X)JmE72sku-~>vUCrmg=;6ODSX;O(~f{me|8d(VC zIgPtO9a(5I%xUr6MB^!}-F6$c-}M+`$tGBl7)*I-$(DB9u=`PL+4X6>@yz!y+;@3bCscB;q=|f1 z#v+7rpBOtygSED|Ds$Dr6yu7)71$iR$ouodBj_VoN0?Ygdr#t2{{Tit$J96imdWQO zrPveIx*AKp1p#%UeQQ+*yAGdxcN`Cuipy(N3=F4n?BpqYbm#~^_t5=Vva|=hLG7ph zyvSqo+(3(6~NgiFZnOXtm!Bt7Aaol>6 zYGI1;y~rH$SV+=e(4*qxAW z>V76yN2iU1BwRK}$V%!rNjaITF$G&%nh}k~km24uo@tcN9yoLu{Y+u2c8;tO>d-

bVGi7b8l^GZm(aOLJPBvz4Y@wQLExyE>R4C1kQ$WOI3p<#H$! z1~It+ChJQj5@=~op`)!0(Ws4q!4V7$4I@`5D4;9?Cu16V2&cSu%QDymVobI^{LMf7 zGd@0a6puc5FP1FnhR?JLcn+u~sjN+&OC;lnM58Dci^w$q7bT!g&CM#!2(wYX=OWeGiR*5;Pc_8#H{OBvC9B}O&ZPHG9aDtO z<3l~Gufx4x{(Yp+oWz^Yejnvx77E5IuZq-Q{fj^%CVuASJ?NxSn^Vbg5X2nmOa@(@ zo%~Mt8ah*BH>*x^T_7v-CH&->U*hTKUZOcmOa@!cmt=B<=~zXD&`5eo5_WfXU+tVi`-jJJH_SqF`&HkxiO=tX#oRW)#PJ z`*5tc7yV36fxO7{ltyBiY#x@W;EBhg1l+~XU)qBcgzgc-cJubFFxUWm=d4*|t-fDX z=aAwV#rRw<=Bc2XSOyKB&FAs`AN~|Cz4j*0M^{EWJD0~a z@)5CYbak|0&8ijHLa;V4QJV-(oRA0k0>(09$c~Jl%tjz%L=*8)@faepI5e8xVfqva zUXf{6ronygBbG{`xxE$1)>il`fl3$}9LAB}lQ?wjIQj_Qa5}?1at(xD;P?H2Nm)UH zW8c5~c6{c6d(kR;CY+O{`NVfF=OWEX&TU{|5FX*Ja4moPFF(SEhmRr=izyIUdFmU~ zKgnYYZHAea>{IrB^8;VP%IkJ8y;eduOa<6$C@>(kRZqgP3ezik>RtW!^0>tfy#wq z2sY1Et4~lfxyf#-Gre4<&N*um0JvsoRai`vcvBOhYeP#%2P}dU@S2Q$qVF_b-unjL z|KOkkz&681;1U#B>&CUK@P*Glgd48E4km{afG2A*vX=UF*=J7DmQV{=ufM+^|M1k) z>Nh#VS`AYVP`_GeBTTodJYU(PVOfZ$TCi#7-MHz#U*nz#STH@nE*Ug=p;b;IMikgi zANvTtbh8tma8ZE*PUFEZ!V(1})k%XJ zQyPvZkE8u(@K68x6!v}eF`|)(nvKVS)ytP+^ZGT|xMnq$_jGZ*D5@0)`AmjjjiAD0 zs?-umh8NRn1WC?U&a*lpMdZ2!f+QUpARO*Lu>s}x~t>txgDY-i$lc#F;8 znV0uqkZZ7+u=V{FnPe@gBp$kFH}1V_H(C=huFboE9W-@Lg9Afw2)~T+H~;)Y?EmP??1`!o^Ae6OcNWuSF!5WW(ygu19|hI-Am^2FlDqn*g00bTK!Icc1%# zda2(Adq*O=zb< z<;IDynM}je?Bsv>ci+Xk2R=jxQ_3WGrE&##+`I!%Jo;(Gc@FuJ5salXC>9EAOnz;g zs(NuIU!cIH3p@%?&MTDG{)&;+HD!PxTyPCC0ZGBBYqh_+I(MxGo;)Y>d7i7T>s(uu z;3X0X^fTf19{dFR4Sy1-MDPDg{THgV&?cCwWPiTvpkvu;^sL^DZFfA3w(b>S!<%I9Gb!^j zSEd#aOE%-KFMN|P*}%y|zrva0ALGEDpAo=}>b#36;fAQcpf*x>*Ds14#AN#p9>Vio zZ{V}{->nQJrWUW{a(P4uUn-S4@4y8_llR_m-3EBRhf}8qkW%_f9dtB~Yt))pg8}OE*5Q#KwOXS)+w|nJ#_?1RHilizL~doNw+s zp#I8vHcn3+qP&GRz*MDtoM^&U!qu~S6IN{8uAq}-n~l1>M4O~kwDJY?9o`SuDPyqr zFy4FVDb=l2H^$|4hFPiyslTRHHD2`C`E4fDZ+`Ak?A&@iitOxCvTlplyL);Np+Uoa zoZHnIV;CGsH6uK;DNFsN zO=@;21=aHmkJzGJF;SIULZJQp(9+?7Ph?@@n7 zHJv?ppj57)r?Ug!`0}q|S$7vo?9NiYA0UxTpsT9`2KROzY&5HBm~i;g3Z*iV1XKCH z!K9MxvR}DYra^PV1TLLHrC3zg)LG2tc__mK&rv`qgsHaRC8;g7@us_R zNH=xsTJ{5GgfWhiLJXH!m{;SG2DNgHw6kr zF{EsC9!pO8Ak|Loq{b%~h%#eY!cxL@Yu6$|(|Fv6_{MWxCbNcEEH>$WC9$OYM+LH= zdcHxc;We?K6^S6x+JdHzb_BYClH-W8)ji`Dy%gwbbE>&b6M7;6ySZ6GmTXGVR6z(> z?h2_H!(qt)><(`MS-xPFbWm;}sfYJw#R#%mR(tfbbI>#jW?OoVWX zk{*yrkE-Squwnjk?;ALLq8B#j*3NGbPgBoQl{tK$7p%bd(6MX{mae@X4?OvYSik*K z^rKnZYjsW`lQI`-<5C-LyaO9|+^GP2@5LX(t&}i)`UH9pz8k{E7iJi9xOf>W+wWN1VsgU&fk zf+q3_hfe^jOoxfEDLYI8gM5=T)wnK`iL28@T0??L(qu+547m`tOI`QbG%KT6D8b@* z$NNs>gF{EuJd*g6SoQ!_n9CPASqWUK`Eaj2t2g1EFaJI|maZ9Z=<`_%3Yt2Est=7X z?v@9?42@<>pXtS^Pi|J%JlDb7zx)>kAZ;{Rr<{#?nfi0;PpOW&X>F#~ST2u$d+`-? zwzW|$3O+GenShLD#?ao;uGUnYMglaJJR`;*NvAnhna#vd;MB*F?>b?r9n#EpBZ(%D z(OivBs&y0SG-2!P>QLWjy6$?C$#XfLO_fRJ2Rhz4@Bz}JV~9rV$sik{j!^y_yt^q& z*A3iEPetP?HWeQ|t2Uv1$?64xOlmALho^w%_9bZDy!+W)~XkK{KL2L z!D~O~)v!Zh_Mqd$_wwqE9}Jc&b%dVxbajVl6t*CYE#}DJv3# z9gX4MC%&y9%MAA8XW#uxWxD+65Xyxtl#4FCPBIey$TZDm5!>EkurrDY<*)0yc;@9- zv9zlb*R5NPVyU8%$fMcPBN=pdcf#QJ>6ljTk&fHcoI<%=R)A`=m(J6gpLX2_vZLb=F1EUYKs&$0bn=4NY`+uhcHD(!S{gn6;3dN*7Or^AP$t!Ld*6Uh zkOU^FSTuseCr;uQdtS#EKYc$eLg?^5SwnVg47P0{nM}?g)pRs9rBEtLs`=x4sXs5j z*P)s?W)M`*S#zxoopUY|fvnHj-qtqlb)I`R8a&ryV<@P-52Z7BbKilBf!|9V#4MDY zkvboO)!g2V-H(3_tFPZ#YZg@n-(s#S8nk*z2a|K|uO`sylwjbJJDToRjhi37^A2k$ zJ&O0)v13dgv62|dGz`4<-mkE{yBl}jyn}Q4Y9`+gkm3EdZ7WSDDFUuJ7LC#Labz;1 z;rKMLX_<&{j7TJ+zROra4GOIWjDODfRW-kGCa^J);V^CMYiIA@kj)+uU)`YYg;5)cd>Z$;( zUcP4Fu)P6ra`5v*n4y=%$cZkqvLTg->yO=c7rS;EeFH;?(^%@TOarBI1<$^+2TM9T zux{mYlqwZvLNWI!f$8A&dOBUOIU;X@JNW@}rTvtJp&lgk@ zNpegy&txTr7r;8ZI=N20W}>sdoo~je$Eq9NFm%KdaViGS^HFAFaJjx@GO6ac6v*Vc zd_J$niE@7*96F4?GlQ@V^StEY7KZupe@6&e>0+ran=&mMsn*W%>$@NSU9@$tfX?yb zsh073eb1elAr?_xRiH^ROO!cGD~d=oPIEXkmmlWU1&SW-XwrkPnOe}{(~MQu!_KXn zae8Qo3APt<&7k4f!+-vpcyx4(sT4sh79CHvivcHNO4rtE zur-1+zPjq!*lqkeSt8UwOEM;tiSZPh31nI=t*Sv4c_vwgX>D@6(QFRyeRxpKp%dzQ z1)dxDzIU7-|D5^`E&`cUThB^ZY>I8&%W>xyzCQkrOw&?lA=?Pw-IZTg9cWTwf>bi4 zG;q2Xm5M{t=ofs(t?Exk^k5f3<2Q|I;K9^w+`sEK3=F67&Vdh@W>IAYgDEM=@zPuG zVCB*!xOv<4C^0#t^Gk{h4Gt-TOS0Iut*#R{W!lMNN;3@@Og7D@sRS^sM$>prXcF2a z*W`)%V+wF40QVi#$DBc_^>SUMQW?2y7KMCK4QzA&A09q}V}1SSKvt=gk!o%$tlf6o zpTv?)f5$n4i!~P+@A_LGKvPFg?Odu;Hjb;Iu1e4vE7jDBh!ba59=*`ZyN#do%D^8S_()x|Z7WEs9D~VbA zs_vC}B1}^G9MHINeqXYr8-`EdxSr{h%q`_`-#I2%K3`A`N9K-3Y!u67y!XLD?%P2; z8d3L_N=2S=Gj6=^ackSI&)l0xHNWCIQua!&s~)sOvI!B-C1_)q z*fncqv*mwL*Q&Qgm}WXn<=1cHXMt&XPd6UF|6Y9OM?XQCCbS8e+#<#v7#_h-Uw8#y zeE0!$wzev>IyAORgNjM>gsoU8s(U5jV)2;ztkb9h+{cHH;+5Cl!0T_li=mOUnp1^Z z7GK2uD<`1Jkv;Ng4kg2nj)?qe$J3rIRsTGCk7 zo6F@0n;Qbgbw(^(CGuPQKg5yVlWa0!!;r?ZVo49a@P#j;(7Gu)k{EAp7rY~Ce0v|9!05Gh&?OW(~zgX(3Pc$hpyJ=bq5c%9t3F1Q*J|U2=@%eope}W8Quq`W0xO3Na`NeTPuKC#)U&e`3eR%TMzla;R zY=%L|1$2!`X=plp!j#MAkfmIH9?KWh9%U~lsG)S4(B@P+M{HX)7J+#gQ~ulE{2grH zx*21m1&$S{X|tmvS|l2~KN^iSvqAi4UfR3R?|(6r_UzvM3%!PUDc7lBbaVus>(DfA z{qk<=U#U)ktlKDIOT3^=U!7zONvgr&5&Z2BevIRN{fHB`i6yBcru6*)mT97^y$$PD zt-u;Wck=WZy!*jN$c$ylfk|1IWxUQSX)Xn(R9j06p7`7&xbL1jk&4GqW+J7TVEu$p z*3~~ah*M_kg+IwPDt7>S| zE7(fVY=f?-PM(Z0rjMl2-~afh$QBBSvdd387bV85I3d&mo#)etT!TP1zxxJCWd{aR z?7lm8Vf&WraO_wwK0b03gG{V^p@>q&VUzF`T#~W|0c$)0hx;g%%edkC>+sFrei9qj ztcK6;(vm8E6|eM`abnD6vW54zwsoSpr5)8EIKXlK2QNKCRp)i%i>QpRe*N1Ey@q+L zD$Qms0tm43=$o@xB{)ae(^xT7_+XTk9gINGz@~ zyfzjJxj*FB=K6Ip4D*IkSyaoU^UL#n#-EN)-E^aZ_N6!9M*qN&GO_?SRWU&qbl(Dn ztWoy^xUQ#wiZG1@68Y`CeG;&8rGl2GX574e8+PAz3$|_9jJBpE++tA%Ji9j@m8k#= zDbkqQp66n0bcCQqxOZb)wHo}N{3%BLBjqpXVJtvhOQ1!lZW`ovr&9id!1r#S2$N6H zDzre;1x`hbDP3L??e1H4V$+({c>c9F@z(wWDjmeU3k}s&C2Yvr8rRndS-{U8A#@2z zb1H?~Z@vll@7{$Cn>QiJMAPKAigONRQaaBhVrV?Q>Ue_^*h-}W^0_fIx3tNX^_=UE z`9ZqTcPVe7&tpF8Y6neTYA3akdXNTt+;yA{`Rr(<8dT|pv!JoB!)Mf$s|G(`xZ$eI z3j&lK2VL!L`1Q{|gsmIb;}?5g!;#*T>JFRfAy8fkB`NKDzS>i3OEUr6fxC9yiuK%6 zgehGmTz;v1!Sj$rQ~Ry4CZA=z>{uGnXbh2PoP7GL`RkuiN$RgDccJ$_Uv;&DmZH{D zcTo3JyZPcf*irRDAq&T;h!f6vK)!kWzZe+Po&N#VLC5g(v4eoY{zZ4+=Pv*S3!gb!L;>wgsK@96!~M7vFpv`wo7LVyVK8 z9#Pj9OG$#2m{1X}ckRj*xc!!!v2*8ktYxFnOafLasWh5SNs{&DJ-l$NgpwDi?~NsA zE^2GX+2dsJ+xtgn4*X*5YipGb>52od}cbQwZVeyxtKcq=scJ>~Z@7Sfzq^EQTAmZpN-#cH*WR zZ@|*7PL(!3(<_)pf}Kr8Ld(A=Mm^-+0Jd@dd4&xwU~?NoBH0XsDPM!Fi+YlJnA%6Z zO8uOAhbk`ULCry3iJ-~bw5jFPz0@Prjnq;qGM$GnR8`*5??%vRyNDW?ajHoY6qy#L zY2dc)+puoc3cULEd)V{N`^e_=h(v4!-CR}Z;l@R4@H`I{$3Y?}AnuexN{)kv0;C~zK z99A*aysCD|3zj)8(^M&U_(U(BePu5`I&xHXbh%dR?Bk1;MZ}nTWip2(S!efhM4~ZN z3HJp`e#}xIQ_oO8p$=2IiG*HBbtNQPE47BYlX{f81tDCLC;3FF9w=< zs?|#j=Frdr+=kVwu(YcaZ|vKTxA%Vt*Y#8))ZvzUOhTy|LZkU>Urj?tG!nUB>d1WY zSd@yX&yrFt&CR&=rtR3YejV&+6hWl|zgWDi7oyeHduYhP@lh9+KE1OLz%>55$Z^VO zE!1t)&D1xj=MVz-F4a#}aD~-kO*DaM6Sa-Hm%5Kyd+Bf~XDEY=W`;2~Ix?Pcla;bV zHNfUb4ojmRLDOcXm7478I)ND-%fa;oz|f&p&Slv)+B-X-n+6Se?rieS;|&on2$+D@G%F*EJ81}c;q{k46>K`K?eYK9ZUpU? zN0YM~S1)X)>6Ghn)Idi|Q>tO^Dveh~GL=MocUK7X6eLxr14_fQM(r8DRGO6|3_;dV z@~U{}bOkvlVB%l=Tx73u-ob@B#KkK~-Cxro>Q(B++TWwIw!t~7g$7ODk~n`Wbr1C* zwS`)N%So@Pim+(4WV_famnJx3Zy5StxJ*V5(6W4bf1bz^n$|5Y) z8>ml)9h@9v1Jb9zPz4&3Oq-p(ZK&xn>LB$T^)$7Qa%bUH&3Y{qXcpB%-GT71B*B(q zw$keYHQlBvspj(kGfcHk%ZI7Y&D&GpQ;|sIZ0lL1C27{5_iWJxRSu{fK&*${>VpQPg~bCdnmmt)(8O9-_8WvH4nu_(C`I@WV8SGk9CZw=pEC z7WEKRXP<(g8X#&%VOiGMbX$ZaXHj$m>_1aRt`fjDXLc6#M4O{dA|8^26K_3^Fxh@W z{gmpZvJ0JZ^I`BfwUWA(dVso*>ZS}VK>yY?LnX*`Os!H)3sbGj_Sn${j9Fd~2efSq zrfJZK!F(Ubv`PgR)9lcogWjyC(*06iTzKYl>UZ%}lG=sPZ@)+VoO+IWi#kd9^Lcjl znoH0GE=jDrsJm;Q?SSJ%b9)|jI+L+hXX^7 zIz3arw8csznWxm&YTjN$eT(`nYA-_QUZeISOu2ch*#=G0Ya(1r=W|0BDtW~^6KW>K z?1RT_>tm{QSnTG;?4_ER&M*un8vD=u7;wfVDPD2|ynniayc57SF0~_QVVmPNHAdt- z0avdC^&oW*b(nesA#|@IOu0F)%LPqNPvTl&60jbjb|6f%*nDhYri+yXnQ43&^;B~! zSZ>T-s)^Yw%T!v7oN4O7fRC7Dr?MU_<1+TmM+4vIJ_7~X0+mH=u1UQ55%mJ~Q|bU! zLD-LHz0AvaE=g^p9z)nI1g=)h)W!2$m$EoXwJKBXbS>2)22-wj`P&q@ET);H+B|po zX_Zc}`o=u$A9SD-j?3AxR%QmHbYk!*& zc8V*bq?;pp;c9?9WMD;A1f=^e8P6g)}iU7vquP;{9R-wgh|Nql>qObsi5pt zVH=mSOM71sSY0O4l zs%<2{OqygUh`}iuSQjavGZG-+wP1$65yP35N!ZLVTo+O41nc;yi;ssLbyl+zK#JbQ z2-u`YK&_^}MLj{ihcMw@q~50rGab;JWCBSm0qb6BJGE|_$v2Pn|F>6m&2b#n8-J#| zXJ%I`Sx$^86I=urWhisO6{+GS#N1H@T)`bzd;&fOpN0!=C`c7mU?@8_D0XbgcKj;Y zvShtWmRI{Sv(wFUdUj)pIN_gUXJ(!GKU-&Kcckq;r|106^Z6A>*L;D_$zcQbU4&ab zg){a5ryB!ku9|JOwXppj*YUH*dc1LSZWue!qVOCE24Kq)_1KQC|cGZQ!@&fso; z20h!sH=BJ#Y|?@I-;4TY|l7}Q|A$@mT9SByEv9~c)H%Z$CzKMH7r;SXvcPHDch z(qmm!{L2uwJs0C9o$Xuk0Zzr4cZ8S27SPRNI*6+JKoAnBloM!iC&i8RKDG&45s--- z55w84>XM6)G*pXmp7A#0KI3nUcNy0ii)J`zY9sc(kFl@oVFS7@#O?kJy0(Ki8wm_q z8n_o5IySZ9y(kKqhk~`Xl5-fj*t4F+{Ca|WJH{IPIME7FvhU$%AM{4Q^2?V zzQw`@U2Hpdv548@q&utq74c)sAgop{ww1dw`R11~IlcilMcJ zv*my$)vBS3E$ycGV6BhMP6oq!#k<&{Jh-3MwQ9MM2KB0%jUTx3TqIy)8}{*mi*U22 zaE7p*jt7`(L>@v{LN4NB0@)s2>^5EO!>t5~E!V|foJYW1bjiC;hUx{HGH@e^azG|C!g=gJ#emSRwzXLEs{}H;m~fA#BZH z_8aG*o6~em>)mj&B#x$-*Tf}Ois}g(r>Z<}=c?IXTFrzZ79TvowYfQ%z@gb{4)bvs zUVMTXquuReztf`=I9PtqulA$wn#D*1fA`!L&Yyn=t?6kbNmBJOAFY{ZE(0zvtbVE| zXv4``6=>pQn;RRreCZO}?Ka{#_V@E)A9xTCz0v(%{5E*W2PZ&Ui^cnQ5gLV`od2m` zQ(&722Vs7ahbCxMoq5$#RVPq|f+1*CD5R5hyIss(xq_{&O+T~$BO*xn;|DQCC_-evZ7o?-Rz1`j+$8U5yA z$_OI`xw1$uOisw%nj?VUAujxT2?NTHQHGK>_ThFj~=P{CAQaWr*!w)y%%oRV|CQ`Koji^EKsTbMi z(pUo1^3qf6Ztr{OWM318IDYJP|Jk{sUClw$Ng8p34z94bvyX>&mIzyam`_=vqjA67 z(dtQBO+k|f9~9;&-Z8oK)8!4UuWk{#d@nZ~=d-h~BQ_0WSypJ3mit9vJZy4!Cllx& zKUl$FFeu5{oF6($>AEuJRZGyM-&K%1OcBy_kInUMtS+zn?}vf5)*+6YI5zWIVf&Bv zw1W)I#uP%jsI}JL6S%fEck$@K6AaRr7fLLGy+CDXTtmnQ_S&gT38- zEHAFYX4XS@Sk76$@A26aFxt>{Y$5gKbp?o`*f;t}0-Nl=xwcJbdy+ewF0u_=4mcfc z%t!r7NlrMfI*GF7_)>iEhn;2|l7?+RKft5=PmuIdPVtvFu)sFen#NRf2F?}*n)T2( z8ZH0%u%vE*Z^Og3LfEoT%ykThojaN;);T9!vEkb;W2)**N|ii(PIZhCG;xU}N$F%O zIC$QH3C$<|uO(bYhnPKf0_}rm-hIXmy*Op08)(E$zu(964G6iz=F@Es2#wQczUFfn lx5K;PUb4ry*M5c6`46Noq8y!J4&eX*002ovPDHLkV1f>Tl{o+a diff --git a/images/avatars/gallery/Flics/Flic_84.png b/images/avatars/gallery/Flics/Flic_84.png deleted file mode 100644 index 0a3fc7b408ac34e3fcdc36101b8184c2056b53c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26143 zcmV*BKyJT@P)X#BuB-_BJt!nl`axCnU84fhcLA6a^~U6bXqm5-FlY(4Yzl zRK#z7^an!lw}MthDgvaIg2GCEl8&r z<9pc{A+qZ<&Bg&{4&QH#S2}y9c@CY;i#Z7I5uWitGahr)*W`J*pU3kYB+-UE25aIK zGe+ex^0<6W?&rApG0&lOHs0)s*Tg#_46|{3&jWSVm_EKXF^aKk6Ep9Vht}ig;d~}$ z|Go){IEHa!#=l$NkJ)PwWHFog@xI8;kFU)b6S|kZYxeJDTh7-btS7LR#--QMkk|poMTkb8sjCPG}Ae1;7c-!Jz;+p*c7d04FpDhXUY)=HO5OoX{K`3V;)u zgF^vuLUV8^08VHQrGc;=Knvl7=1>}F+X1u?PH0O9tHC=!-*zCaLOVNJU^@VZ8Ns6J zLaE+DM-G2~u(&`j3Mnprkf21Kvctip>eFdI~4KLYVQsik}b4%Ut90HPXS z=(&%12d;N(slJKlM{wPbK6bhR@Dg|pOl)t=A%hc|Rfts(*A|H7GbH7sTB$vx)g7dC zNOf&Z(AX4lvipS)*bcPYb((%1?T2`0KiY$ `FA+Aq@qqcXuoZ*C4JowDFK^)sD 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'S_FORM_TOKEN_LOGIN', ''); } - $current_hour = date('H'); - $day_state = $current_hour >= 6 && $current_hour <= 18 ? 'jour' : 'nuit'; - // The following assigns all _common_ variables that may be used at any point in a template. $template->assign_vars(array( 'SITENAME' => $config['sitename'], @@ -4246,8 +4243,8 @@ function page_header($page_title = '', $display_online_list = false, $item_id = 'T_ICONS_PATH' => "{$web_path}{$config['icons_path']}/", 'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/", 'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/", - 'T_STYLESHEET_LINK' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/stylesheet_' . $day_state . '.css?assets_version=' . $config['assets_version'], - 'T_STYLESHEET_LANG_LINK'=> "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/' . $user->lang_name . '/stylesheet_' . $day_state . '.css?assets_version=' . $config['assets_version'], + '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_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-3.4.1.min.js?assets_version=" . $config['assets_version'], 'S_ALLOW_CDN' => !empty($config['allow_cdn']), @@ -4353,7 +4350,7 @@ function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \php $totaltime = microtime(true) - $GLOBALS['starttime']; $debug_info[] = sprintf('Time: %.3fs', $db->get_sql_time(), ($totaltime - $db->get_sql_time()), $totaltime); } - } + } if ($phpbb_container->getParameter('debug.memory')) { @@ -4363,7 +4360,7 @@ function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \php $memory_usage = get_formatted_filesize($memory_usage); $debug_info[] = 'Peak Memory Usage: ' . $memory_usage; - } + } $debug_info[] = 'GZIP: ' . (($config['gzip_compress'] && @extension_loaded('zlib')) ? 'On' : 'Off'); diff --git a/install/update/index.php b/install/update/index.php deleted file mode 100644 index 250c0ab..0000000 --- a/install/update/index.php +++ /dev/null @@ -1,395 +0,0 @@ - array('from' => '3.2.7', 'to' => '3.3.0'), - 'files' => array( - '.htaccess', - 'adm/images/phpbb_logo.svg', - 'adm/index.php', - 'adm/style/acp_attachments.html', - 'adm/style/acp_avatar_options_upload.html', - 'adm/style/acp_ban.html', - 'adm/style/acp_contact.html', - 'adm/style/acp_database.html', - 'adm/style/acp_ext_actions.html', - 'adm/style/acp_ext_list.html', - 'adm/style/acp_forums.html', - 'adm/style/acp_groups.html', - 'adm/style/acp_help_phpbb.html', - 'adm/style/acp_icons.html', - 'adm/style/acp_language.html', - 'adm/style/acp_main.html', - 'adm/style/acp_modules.html', - 'adm/style/acp_permission_roles.html', - 'adm/style/acp_posting_buttons.html', - 'adm/style/acp_ranks.html', - 'adm/style/acp_search.html', - 'adm/style/acp_styles.html', - 'adm/style/acp_users_overview.html', - 'adm/style/acp_users_prefs.html', - 'adm/style/acp_users_signature.html', - 'adm/style/admin.css', - 'adm/style/admin.js', - 'adm/style/ajax.js', - 'adm/style/captcha_recaptcha.html', - 'adm/style/installer_footer.html', - 'adm/style/overall_footer.html', - 'adm/style/overall_header.html', - 'adm/style/permission_forum_copy.html', - 'adm/style/permission_mask.html', - 'adm/style/permissions.js', - 'adm/style/progress_bar.html', - 'adm/style/simple_footer.html', - 'adm/style/simple_header.html', - 'assets/cookieconsent/cookieconsent.min.css', - 'assets/cookieconsent/cookieconsent.min.js', - 'assets/javascript/core.js', - 'assets/javascript/editor.js', - 'assets/javascript/jquery-3.4.1.min.js', - 'assets/javascript/plupload.js', - 'common.php', - 'composer.json', - 'composer.lock', - 'config/default/container/parameters.yml', - 'config/default/container/services.yml', - 'config/default/container/services_auth.yml', - 'config/default/container/services_console.yml', - 'config/default/container/services_cron.yml', - 'config/default/container/services_password.yml', - 'config/default/container/services_routing.yml', - 'config/default/container/services_text_formatter.yml', - 'config/default/container/services_twig.yml', - 'config/default/container/services_ucp.yml', - 'config/default/routing/cron.yml', - 'config/default/routing/routing.yml', - 'config/default/routing/ucp.yml', - 'cron.php', - 'download/file.php', - 'ext/phpbb/viglink/acp/viglink_helper.php', - 'ext/phpbb/viglink/composer.json', - 'ext/phpbb/viglink/composer.lock', - 'ext/phpbb/viglink/styles/all/theme/viglink.css', - 'feed.php', - 'includes/acp/acp_attachments.php', - 'includes/acp/acp_bbcodes.php', - 'includes/acp/acp_board.php', - 'includes/acp/acp_database.php', - 'includes/acp/acp_extensions.php', - 'includes/acp/acp_forums.php', - 'includes/acp/acp_help_phpbb.php', - 'includes/acp/acp_main.php', - 'includes/acp/acp_permissions.php', - 'includes/acp/acp_prune.php', - 'includes/acp/acp_reasons.php', - 'includes/acp/acp_styles.php', - 'includes/acp/acp_update.php', - 'includes/acp/acp_users.php', - 'includes/acp/auth.php', - 'includes/bbcode.php', - 'includes/compatibility_globals.php', - 'includes/constants.php', - 'includes/diff/engine.php', - 'includes/functions.php', - 'includes/functions_acp.php', - 'includes/functions_admin.php', - 'includes/functions_compatibility.php', - 'includes/functions_compress.php', - 'includes/functions_content.php', - 'includes/functions_convert.php', - 'includes/functions_display.php', - 'includes/functions_download.php', - 'includes/functions_messenger.php', - 'includes/functions_module.php', - 'includes/functions_posting.php', - 'includes/functions_privmsgs.php', - 'includes/functions_transfer.php', - 'includes/functions_user.php', - 'includes/mcp/mcp_ban.php', - 'includes/mcp/mcp_logs.php', - 'includes/mcp/mcp_main.php', - 'includes/mcp/mcp_notes.php', - 'includes/mcp/mcp_topic.php', - 'includes/mcp/mcp_warn.php', - 'includes/message_parser.php', - 'includes/questionnaire/questionnaire.php', - 'includes/startup.php', - 'includes/ucp/ucp_attachments.php', - 'includes/ucp/ucp_groups.php', - 'includes/ucp/ucp_pm.php', - 'includes/ucp/ucp_pm_compose.php', - 'includes/ucp/ucp_pm_viewfolder.php', - 'includes/ucp/ucp_profile.php', - 'includes/ucp/ucp_register.php', - 'includes/ucp/ucp_resend.php', - 'includes/utf/utf_tools.php', - 'index.php', - 'language/en/acp/attachments.php', - 'language/en/acp/board.php', - 'language/en/acp/common.php', - 'language/en/acp/forums.php', - 'language/en/acp/permissions.php', - 'language/en/acp/permissions_phpbb.php', - 'language/en/acp/posting.php', - 'language/en/acp/profile.php', - 'language/en/acp/styles.php', - 'language/en/captcha_recaptcha.php', - 'language/en/cli.php', - 'language/en/common.php', - 'language/en/email/admin_activate.txt', - 'language/en/email/user_forgot_password.txt', - 'language/en/install.php', - 'language/en/migrator.php', - 'language/en/posting.php', - 'language/en/ucp.php', - 'mcp.php', - 'memberlist.php', - 'phpbb/auth/provider/apache.php', - 'phpbb/auth/provider/base.php', - 'phpbb/auth/provider/db.php', - 'phpbb/auth/provider/ldap.php', - 'phpbb/auth/provider/oauth/oauth.php', - 'phpbb/auth/provider/oauth/service/base.php', - 'phpbb/auth/provider/oauth/service/bitly.php', - 'phpbb/auth/provider/oauth/service/facebook.php', - 'phpbb/auth/provider/oauth/service/google.php', - 'phpbb/auth/provider/oauth/service/service_interface.php', - 'phpbb/auth/provider/oauth/service/twitter.php', - 'phpbb/auth/provider/oauth/token_storage.php', - 'phpbb/auth/provider/provider_interface.php', - 'phpbb/avatar/driver/remote.php', - 'phpbb/avatar/driver/upload.php', - 'phpbb/cache/driver/memcached.php', - 'phpbb/cache/driver/memory.php', - 'phpbb/captcha/non_gd.php', - 'phpbb/captcha/plugins/qa.php', - 'phpbb/class_loader.php', - 'phpbb/config/config.php', - 'phpbb/config_php_file.php', - 'phpbb/console/command/cron/run.php', - 'phpbb/console/command/extension/enable.php', - 'phpbb/console/command/update/check.php', - 'phpbb/console/command/user/add.php', - 'phpbb/content_visibility.php', - 'phpbb/controller/helper.php', - 'phpbb/cron/controller/cron.php', - 'phpbb/cron/event/cron_runner_listener.php', - 'phpbb/cron/manager.php', - 'phpbb/cron/task/core/update_hashes.php', - 'phpbb/cron/task/wrapper.php', - 'phpbb/db/driver/driver.php', - 'phpbb/db/driver/driver_interface.php', - 'phpbb/db/driver/factory.php', - 'phpbb/db/driver/mssql_odbc.php', - 'phpbb/db/driver/mssqlnative.php', - 'phpbb/db/driver/mysqli.php', - 'phpbb/db/driver/oracle.php', - 'phpbb/db/driver/postgres.php', - 'phpbb/db/driver/sqlite3.php', - 'phpbb/db/extractor/mysql_extractor.php', - 'phpbb/db/migration/data/v30x/release_3_0_4_rc1.php', - 'phpbb/db/migration/data/v310/softdelete_p1.php', - 'phpbb/db/migration/data/v32x/timezone_p3.php', - 'phpbb/db/migration/data/v32x/user_emoji_permission.php', - 'phpbb/db/migration/data/v32x/v328.php', - 'phpbb/db/migration/data/v32x/v328rc1.php', - 'phpbb/db/migration/data/v32x/v329.php', - 'phpbb/db/migration/data/v32x/v329rc1.php', - 'phpbb/db/migration/data/v330/add_display_unapproved_posts_config.php', - 'phpbb/db/migration/data/v330/dev.php', - 'phpbb/db/migration/data/v330/forums_legend_limit.php', - 'phpbb/db/migration/data/v330/jquery_update.php', - 'phpbb/db/migration/data/v330/remove_attachment_flash.php', - 'phpbb/db/migration/data/v330/remove_email_hash.php', - 'phpbb/db/migration/data/v330/remove_max_pass_chars.php', - 'phpbb/db/migration/data/v330/reset_password.php', - 'phpbb/db/migration/data/v330/v330.php', - 'phpbb/db/migration/data/v330/v330b1.php', - 'phpbb/db/migration/data/v330/v330b2.php', - 'phpbb/db/migration/data/v330/v330rc1.php', - 'phpbb/db/migration/tool/module.php', - 'phpbb/db/migrator.php', - 'phpbb/db/tools/mssql.php', - 'phpbb/db/tools/postgres.php', - 'phpbb/db/tools/tools.php', - 'phpbb/di/container_builder.php', - 'phpbb/di/extension/container_configuration.php', - 'phpbb/di/extension/core.php', - 'phpbb/di/extension/tables.php', - 'phpbb/di/service_collection.php', - 'phpbb/event/md_exporter.php', - 'phpbb/extension/extension_interface.php', - 'phpbb/extension/manager.php', - 'phpbb/feed/controller/feed.php', - 'phpbb/feed/topics_active.php', - 'phpbb/files/filespec.php', - 'phpbb/filesystem/filesystem.php', - 'phpbb/filesystem/filesystem_interface.php', - 'phpbb/filesystem.php', - 'phpbb/finder.php', - 'phpbb/group/helper.php', - 'phpbb/help/controller/bbcode.php', - 'phpbb/help/controller/faq.php', - 'phpbb/install/controller/helper.php', - 'phpbb/install/helper/container_factory.php', - 'phpbb/install/helper/database.php', - 'phpbb/install/helper/iohandler/iohandler_interface.php', - 'phpbb/install/installer_configuration.php', - 'phpbb/install/module/install_database/task/add_config_settings.php', - 'phpbb/install/module/install_database/task/create_schema.php', - 'phpbb/install/module/install_database/task/set_up_database.php', - 'phpbb/install/module/install_filesystem/task/create_config_file.php', - 'phpbb/install/module/requirements/task/check_server_environment.php', - 'phpbb/install/module_base.php', - 'phpbb/language/language_file_loader.php', - 'phpbb/lock/db.php', - 'phpbb/lock/flock.php', - 'phpbb/message/form.php', - 'phpbb/mimetype/guesser.php', - 'phpbb/notification/type/approve_post.php', - 'phpbb/notification/type/approve_topic.php', - 'phpbb/notification/type/base.php', - 'phpbb/notification/type/post.php', - 'phpbb/notification/type/topic.php', - 'phpbb/notification/type/type_interface.php', - 'phpbb/passwords/driver/argon2i.php', - 'phpbb/passwords/driver/argon2id.php', - 'phpbb/passwords/driver/base_native.php', - 'phpbb/passwords/manager.php', - 'phpbb/permissions.php', - 'phpbb/plupload/plupload.php', - 'phpbb/report/report_handler.php', - 'phpbb/request/request.php', - 'phpbb/request/request_interface.php', - 'phpbb/request/type_cast_helper.php', - 'phpbb/search/fulltext_mysql.php', - 'phpbb/search/fulltext_native.php', - 'phpbb/search/fulltext_postgres.php', - 'phpbb/search/fulltext_sphinx.php', - 'phpbb/session.php', - 'phpbb/template/asset.php', - 'phpbb/template/context.php', - 'phpbb/template/template.php', - 'phpbb/template/twig/extension/avatar.php', - 'phpbb/template/twig/extension/config.php', - 'phpbb/template/twig/extension/username.php', - 'phpbb/template/twig/extension.php', - 'phpbb/template/twig/lexer.php', - 'phpbb/template/twig/loader.php', - 'phpbb/template/twig/node/definenode.php', - 'phpbb/template/twig/node/includeasset.php', - 'phpbb/template/twig/node/includephp.php', - 'phpbb/template/twig/tokenparser/defineparser.php', - 'phpbb/template/twig/tokenparser/event.php', - 'phpbb/template/twig/tokenparser/includecss.php', - 'phpbb/template/twig/tokenparser/includejs.php', - 'phpbb/template/twig/tokenparser/includeparser.php', - 'phpbb/template/twig/tokenparser/includephp.php', - 'phpbb/template/twig/tokenparser/php.php', - 'phpbb/textformatter/acp_utils_interface.php', - 'phpbb/textformatter/s9e/acp_utils.php', - 'phpbb/textformatter/s9e/bbcode_merger.php', - 'phpbb/textformatter/s9e/factory.php', - 'phpbb/textformatter/s9e/link_helper.php', - 'phpbb/textformatter/s9e/parser.php', - 'phpbb/textformatter/s9e/quote_helper.php', - 'phpbb/ucp/controller/reset_password.php', - 'phpbb/user.php', - 'phpbb/user_loader.php', - 'posting.php', - 'report.php', - 'search.php', - 'styles/prosilver/style.cfg', - 'styles/prosilver/template/attachment.html', - 'styles/prosilver/template/bbcode.html', - 'styles/prosilver/template/captcha_recaptcha.html', - 'styles/prosilver/template/forum_fn.js', - 'styles/prosilver/template/forumlist_body.html', - 'styles/prosilver/template/mcp_forum.html', - 'styles/prosilver/template/mcp_move.html', - 'styles/prosilver/template/mcp_topic.html', - 'styles/prosilver/template/memberlist_body.html', - 'styles/prosilver/template/memberlist_search.html', - 'styles/prosilver/template/navbar_header.html', - 'styles/prosilver/template/overall_footer.html', - 'styles/prosilver/template/overall_header.html', - 'styles/prosilver/template/plupload.html', - 'styles/prosilver/template/posting_attach_body.html', - 'styles/prosilver/template/posting_buttons.html', - 'styles/prosilver/template/posting_layout.html', - 'styles/prosilver/template/posting_poll_body.html', - 'styles/prosilver/template/posting_review.html', - 'styles/prosilver/template/posting_topic_review.html', - 'styles/prosilver/template/search_results.html', - 'styles/prosilver/template/simple_footer.html', - 'styles/prosilver/template/ucp_agreement.html', - 'styles/prosilver/template/ucp_attachments.html', - 'styles/prosilver/template/ucp_avatar_options_upload.html', - 'styles/prosilver/template/ucp_groups_manage.html', - 'styles/prosilver/template/ucp_pm_history.html', - 'styles/prosilver/template/ucp_pm_viewmessage_print.html', - 'styles/prosilver/template/ucp_profile_profile_info.html', - 'styles/prosilver/template/ucp_register.html', - 'styles/prosilver/template/ucp_reset_password.html', - 'styles/prosilver/template/viewforum_body.html', - 'styles/prosilver/template/viewtopic_body.html', - 'styles/prosilver/template/viewtopic_print.html', - 'styles/prosilver/theme/colours.css', - 'styles/prosilver/theme/common.css', - 'styles/prosilver/theme/forms.css', - 'styles/prosilver/theme/icons.css', - 'styles/prosilver/theme/images/site_logo.svg', - 'styles/prosilver/theme/plupload.css', - 'styles/prosilver/theme/print.css', - 'styles/prosilver/theme/stylesheet.css', - 'ucp.php', - 'viewforum.php', - 'viewonline.php', - 'viewtopic.php', - ), - 'binary' => array( - 'images/upload_icons/flash.gif', - 'styles/prosilver/theme/images/bg_header.gif', - 'styles/prosilver/theme/images/bg_list.gif', - 'styles/prosilver/theme/images/icon_download.gif', - 'styles/prosilver/theme/images/icon_offline.gif', - 'styles/prosilver/theme/images/icon_online.gif', - 'styles/prosilver/theme/images/icon_rate_bad.gif', - 'styles/prosilver/theme/images/icon_rate_good.gif', - 'styles/prosilver/theme/images/quote.gif', - 'styles/prosilver/theme/images/quote_rtl.gif', - 'styles/prosilver/theme/images/site_logo.gif', - ), - 'deleted' => array( - 'adm/style/acp_ext_delete_data.html', - 'adm/style/acp_ext_disable.html', - 'adm/style/acp_ext_enable.html', - 'assets/javascript/jquery.min.js', - 'images/upload_icons/flash.gif', - 'includes/ucp/ucp_remind.php', - 'language/en/email/user_activate_passwd.txt', - 'phpbb/cache/driver/apc.php', - 'phpbb/cache/driver/eaccelerator.php', - 'phpbb/cache/driver/memcache.php', - 'phpbb/cache/driver/xcache.php', - 'phpbb/console/command/fixup/recalculate_email_hash.php', - 'phpbb/db/driver/mysql.php', - 'phpbb/db/tools.php', - 'styles/prosilver/template/ucp_remind.html', - 'styles/prosilver/theme/images/bg_header.gif', - 'styles/prosilver/theme/images/bg_list.gif', - 'styles/prosilver/theme/images/icon_download.gif', - 'styles/prosilver/theme/images/icon_offline.gif', - 'styles/prosilver/theme/images/icon_online.gif', - 'styles/prosilver/theme/images/icon_rate_bad.gif', - 'styles/prosilver/theme/images/icon_rate_good.gif', - 'styles/prosilver/theme/images/quote.gif', - 'styles/prosilver/theme/images/quote_rtl.gif', - 'styles/prosilver/theme/images/site_logo.gif', - ), -); diff --git a/install/update/new/.htaccess b/install/update/new/.htaccess deleted file mode 100644 index 0be28ab..0000000 --- a/install/update/new/.htaccess +++ /dev/null @@ -1,92 +0,0 @@ - -RewriteEngine on - -# -# Uncomment the statement below if URL rewriting doesn't -# work properly. If you installed phpBB in a subdirectory -# of your site, properly set the argument for the statement. -# e.g.: if your domain is test.com and you installed phpBB -# in http://www.test.com/phpBB/index.php you have to set -# the statement RewriteBase /phpBB/ -# -#RewriteBase / - -# -# Uncomment the statement below if you want to make use of -# HTTP authentication and it does not already work. -# This could be required if you are for example using PHP via Apache CGI. -# -#RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] - -# -# The following 3 lines will rewrite URLs passed through the front controller -# to not require app.php in the actual URL. In other words, a controller is -# by default accessed at /app.php/my/controller, but can also be accessed at -# /my/controller -# -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule ^(.*)$ app.php [QSA,L] - -# -# If symbolic links are not already being followed, -# uncomment the line below. -# http://anothersysadmin.wordpress.com/2008/06/10/mod_rewrite-forbidden-403-with-apache-228/ -# -#Options +FollowSymLinks - - -# Apache content negotation tries to interpret non-existent paths as files if -# MultiViews is enabled. This will however cause issues with paths containg -# dots, e.g. for the cron tasks - - Options -MultiViews - - -# 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. - - - - Order Allow,Deny - Deny from All - - - Order Allow,Deny - Deny from All - - - = 2.4> - - Require all denied - - - Require all denied - - - - - - - Order Allow,Deny - Deny from All - - - Order Allow,Deny - Deny from All - - - - - Require all denied - - - Require all denied - - - diff --git a/install/update/new/adm/images/alert_close.png b/install/update/new/adm/images/alert_close.png deleted file mode 100644 index 79750a013c5db627a14bf3d57edc8f8e3a477046..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2097 zcmaJ?YgAKL7LJ0*E65`_OVRcktP$(m;m=}RWa0BUlnFI$KFgT?|u4kiA3~!|za!^XLV766|9vif#KejaL{7)!6A}_|31pm15rZevXf%TciR7k7xWS211XQ|7 zVaFu}76kJZVmTs~Ndbc*7%e-9FtPed|G0ug{y|m>zi*SiVR$7d#}jb`!`M;+DD?ERrEISR|7J zeqkN}7vzhjhWH(x%cXOqFak>X5QoLY>J@Nev4GC@B#`|*{mC94R5FpsCi<{wRDTMY z!ydg(~-9>ey7ZS}zi<3m!t+ZB3SKgt9WQ7Gdw4$Ft9d~}4j zFW?e{Nv?m9pHdj_97b)G@1|0l9`^7s(F1|DU%OVV^zp?&GlP5Zhxvso<-*BtV`j90+^+Kq+rZ^rVgVBNYDp_VD1tDjYM!MYi*vF#7t(PL0l z)DyZYi6cAnqoAfJ+sj$iJv7vitlLk2akMevXSk}Y?AyJOkta(^u++rfgKD3$rw7cKB`MuM-owP8{DYdB?iOn(y5+F}JX2vgz#XG`}8n#b{t^MpOj~ zg+kWF*_X97H56K5&}Lh+f9sl>d^#RHFta*$?i_(mKY8nxM|XGkwh+v4o5;OgTKnnc z(t&~Y_IBgXf1jGN&Iw?#NDM}n-5HHWV`FJ@v3LC2uj}dxI1;{9<)g_%Ez!i`;!Br| znM`Ij^a@jO_Uv(;ZhyqJ-C%Rg;?5DqCY$?$XqHO_x$=jU7ObcxOv{#IgZ&VT-z={VJW37mK0GC+~Yb-~OSGgC|l zZr!!dj?z>Fuz&h~MEzxs&zgQg<3&zW3AgzLh1+4IKqzYtm@Vp3jR!(7oD}PFIVLjH zzWr@oYYbJz;Z3@9K1=N#x1V{!$2%>0ev*Z*jE<<-YCWq=PgvMqn?3dB6pvt;H{Up{ zd7_DioBR6uGJWm)QpUF(*kVuz0!+ph1Beywao>^UFx1wac`1|_6gs6iqg>D5F;_n_sqUFU+rFJp-wFwhQkVD7JgIw13D@SeKaZ>)ZJd4< z+yAO-gF4Z=JHFzfN8W7Hfby#=Ocj}k59M^l>lQ38kK?L8?&YOrwf8gR`5pnzrJk07 z9h>HqX7}&L$Wx~68AZB`wWs)RGd{E4H?(8tzjDos27za(tedB`w-v2!Ti0L7i8%Kg z{pab)fVr32!GH^D*`%P6vmxhA_uiJxkAp>NlObLf(dO&-mrdKxoIaINP)J#o)3)m4 zP&-o_>eMz2#Z3YgxgTUO}hquind8 z6ZFON6Q7E3^pnjtJ7$l0Z`TYmj0WTG-oDUjK}#HF0P-Ihb32c&Kw&oWB|A*ZcNl)+ N9Ci?^(l_eZe*jUwWY7Qr diff --git a/install/update/new/adm/images/arrow_down.gif b/install/update/new/adm/images/arrow_down.gif deleted file mode 100644 index b7fbf7e2764e1f1c58ed0a166ec0d02eec927970..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51 zcmZ?wbhEHbWMg1sXkcJ4Ha2EpU{L(Y!pOkD$e;sc1I5`G7?`+v_!DNXzIefUIRk?= E0LkGAF8}}l diff --git a/install/update/new/adm/images/arrow_left.gif b/install/update/new/adm/images/arrow_left.gif deleted file mode 100644 index ac92cb49719f40ae82a284f16e3b9bca63feeded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49 zcmZ?wbhEHbWMN=qXkcJ4Ha2EpU{L(Y!pOkD$e;scGk|0mm^geG+E!#f4`5`l1^}?* B2Z8_q diff --git a/install/update/new/adm/images/arrow_right.gif b/install/update/new/adm/images/arrow_right.gif deleted file mode 100644 index 3a080ffdfe21b646239778d71fa09e843351a63f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49 zcmZ?wbhEHbWMN=qXkcJ4Ha2EpU{L(Y!pOkD$e;scGk|0mm^fI3+E!#f4`5`l1^}+L B2TT9} diff --git a/install/update/new/adm/images/arrow_up.gif b/install/update/new/adm/images/arrow_up.gif deleted file mode 100644 index 0ff587218205e6ad32bde7ba0e65d7d4eeff98b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51 zcmZ?wbhEHbWMg1sXkcJ4Ha2EpU{L(Y!pOkD$e;sc1I5`G7?`+v@)=g_Tqsquf`P#r E0LJYIr~m)} diff --git a/install/update/new/adm/images/bg_button.gif b/install/update/new/adm/images/bg_button.gif deleted file mode 100644 index 03172ff5c674ae95000d265bff3e5068cab73af0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 182 zcmV;n07?HxNk%w1VFUme0K@ln-?Cj_0=;r6<;o#x!?(XE| z<gwv++S>pB|L^bbA^8LV00000EC2ui00aOS000FupeK4-sVxFUNfH2ba934PwB4Iy kAy$z63IYUzDIOk-hJnN66fV%gBr*9|uh^`1%MAelJFawYMF0Q* diff --git a/install/update/new/adm/images/bg_hash1.gif b/install/update/new/adm/images/bg_hash1.gif deleted file mode 100644 index 61163679a80e2c6074658193458280c8713489a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48 zcmZ?wbhEHbWMyDwXkcV;IBLtlz@Ye(g^_`QkwFK@28y#XFfg(AFi+pMLY#}i8UVn0 B2ekkI diff --git a/install/update/new/adm/images/bg_hash2.gif b/install/update/new/adm/images/bg_hash2.gif deleted file mode 100644 index d31840361c1e83c8e4828c1641d1b7d629c2068d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48 zcmZ?wbhEHbWMyDwXkcV0*zksdfkE*n3nK#qBZCf*4HRc(U|?eJVV=Hig*X?3H2~Vr B2!8+o diff --git a/install/update/new/adm/images/bg_hash3.gif b/install/update/new/adm/images/bg_hash3.gif deleted file mode 100644 index 40bc7e1b5c67192a6299730460b88e46ce9b4c1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48 zcmZ?wbhEHbWMyDwXkcV`Q`pGBz@Ye(g^_`QkwFK@28y#XFfg(AFi+pMLY#}i8UWRr B2vGn4 diff --git a/install/update/new/adm/images/bg_hash4.gif b/install/update/new/adm/images/bg_hash4.gif deleted file mode 100644 index 54e7f0019f7bca1fef37bee315e6b44380505ae0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48 zcmZ?wbhEHbWMyDwXkcVWOG{&5U{L(Y!pOkD$e;sc1I1Yx7?{|5n5S=BAAMU((ec}GodoSPI zdiMJ6%QqJvJUe~&(VZ7>9=?A6;PtyZ&tG4D`0W16x0fG1KYi!XxqD9@zJ7P+?&JHf z-adNs{`T|NR~|jT^zhl^H}B8ifAZw*2L@7r;!hT^avcx}@)HBw-UE{gJao$X+}nyy zx>(M?up-H8t<<_3Yf^TbR_=fBA=^i9_SqRFvkv6#=Kio_j`Q;E?|$rwJMujEU%g6G zlTK?}dxv0G7ejAfzwpF~98;!F=^sWQ>T^Bp4Gf?@zQ19tJkh8+`OrN=kC4x@(&;K rKY60{{Kd;xdT-vodoT9!Bh#0!-wb~I{Pp|K-+%uZm|t--F<1it4*>Fk diff --git a/install/update/new/adm/images/bg_header.jpg b/install/update/new/adm/images/bg_header.jpg deleted file mode 100644 index 5ecec5360b11992492807a8fa1353ad25392d55f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 385 zcmex=uI=H%w(=K}(Mey}1a#RK7?>VxzCA7BvVV6b6eVrCR%U=n0x7G(T?gdvlGk&zMT zNCaTz;A8|TLWlraj7&gR3INrz0wobZn9(qiIZf~)lhLGLkq|KrK}H5f7G{Jz1B1{9 zM!`TP71jT@7G0w2`|tAh z!qVN!)7{6=+uY{v&DP)P^ZfVw{_XVpfq|}%G~S!|Npwo z+1>5?A^8LV00000EC2ui0A2xU000L6z+P`-Voi?7q;kn@I-k&}bV{vSuh^`1%k6rz zJsfB?qL|O41ejE#(BSV%Upt9x5m@{kM%(=7Y&!9t#9!C>oFt6t4|HHrYRW6PdRySDAy zxO3~?&AYen-@t~;D7`cXyAbeCaBNG7S|l1w(~WRp4|Amx-)R%zvxSZ1l^mRxq}<(FWFDdw1D zmTBghXr_tg3=6dB=9_TFDd(JY)@kRRc;>0+o_zM{=bwNED(Iku4*G!sh$gD&qKr1` z=%bKED(R$@R%+>`m}aW!rkr-_>8GB4aKNafmTKy$sHUpws;su^>Z`EED(kGY)@tjm zxaO*Bt{Cv(>#x8DE9|hu7HjOW$R?}ovdlK??6c5DEA6z@R!eOL)@G~iw%m5>?YH2D zD=x9vj%)6@=%%ax?z-$!yF!3Za; z@WTHx?C`@7Lws<=6jyAqy%S%o@x~m7n{me=hb*$QACGME$td$6#L6tU?DESn$1L;A zG}mnN%{b?*^Ugf??DNk+2QBmv7jWRi(MTt)^wLZ>?ex=7M=kZ#R99{F)mUe(_10W> z?X}iD82$CwWS4FB*=VP&_S$SOeL>rB$1V5Vbk}XS*D&0z_uhQ>?f2h+2QK*Fgcol3 z;fN=$_~MK=?)c-7M=tr~lvi%~<(Ox#`R1H=?)m4Shc5c)q?c~`>8Pi!`s%E=?)vMn z$1eNqwAXI``|Y^ruKVu1_wM`ezy~k<@WdBy{PD;qul(}NH}CxO&_^%*^wd{x{q@*q zul@Gickli8;D;~%_~e&w_|WL5um1Y%x9|S@@WU@c2pTM8|NZ#qumAr1_wWDz_UJ+V z07$?B8t{M!OrQc05`qOf@PQDFpaduAj}}nyf*8!81~TiOrsjt$i_Ch@r`hdqa5c* W$2!^#@s4=RqaOFj$3EUL2mm{Rf3^$& diff --git a/install/update/new/adm/images/bg_tabs_alt2.gif b/install/update/new/adm/images/bg_tabs_alt2.gif deleted file mode 100644 index a2142d5432be00a2e6395bed8b503a0eb053de5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 420 zcmV;V0bBk@Nk%w1VFv(d0M!5h-R=9j%-PD^>;M1%;p_6)>G#^|_}1t3)8z8r?)=T( z?a<=z%--$P<@43%^v>Vz%iZkH;qcq+`O@R@&fxFM-Rt1+{o(Qc#?RT|@B7^5?%(eF z$I#ot(%s+b@Y>|;@ACHY`Tyeb|LODm%G2Gz$<_D!{?gv&)7s+H-sjQVBe^A^8LV00000EC2ui00#hR000KTz)}f=0u2VC5byV*4MZZCP8OS8uGd`8!sRA7 ziLe+0D4Q{ow3=gRyGez(oOGz$Z;rfv)#&?i2!Vnu6NQE<3yF$85si*16p@lU50#cR z3YnTU44s}I5TT+P6{V&c0;#Gws;VBXsjsjuumS|Nx3IabyQ;mZzqYtX#769z?d||0@&Ft4`1$(#{Qds_ O00RmfNU$KlAOJh7n-8b} diff --git a/install/update/new/adm/images/cellpic3.gif b/install/update/new/adm/images/cellpic3.gif deleted file mode 100644 index be46fc6fcc29f3b2e58196de077fd154c541ed06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 826 zcmZ?wbhEHbWMq(J_|CwUjYc5;%JdWJ?TzLz5@)z+IF6J*Cz2jpx}USQym mXV8t{P)J~CWMbn}@YvAc$jr{K;4;BrAyX?m7Xu3mgEas{NhJ&b diff --git a/install/update/new/adm/images/file_conflict.gif b/install/update/new/adm/images/file_conflict.gif deleted file mode 100644 index 4458c4ff230b69b2c5d0cb5e15527c07c67ea968..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 zcmZ?wbhEHb6krfwxT?bNyrbipug~9)AD=kbJ+iWR5+3@zr{~qVvrl58KD>PK`pT83 z-d-OjO?;Z2^?B`@XSFrYT3cRaroX;%Vn|&9BNzzMnYpV%4e_ z(UCu|U3+Y2{Ukp2Nud8@7sp4YCjbBce`I6;BpIj;6o0ZXGBBtx=zt6c`H6w8)M3(u zk_Hj2g-i~HIYAtYS4=U;RI|CXX3InYyDfqfRk;K7on3oP(i!qOu5kOQ4vNbd;iyia<~sQ#qRxC-0;{311cAfGAn1 S)lOV&917eVY;&C*8LR<45pCE2 diff --git a/install/update/new/adm/images/file_modified.gif b/install/update/new/adm/images/file_modified.gif deleted file mode 100644 index 17e8f976c3745c971ca0d8bb4c36b6d1569471cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 358 zcmZ?wbhEHb6krfwxN5-g>3ra;m$&{rU;6C+o?nNVex8v2c}n5=-Ax}ahX4Qj?elr( zKS$XAyxIO^FT=OJoWG9?e!d*{J4@oVNM%Y|)=%tltkx z{5;0>_w%KnR}=nzJo)RC*uS68f1dOBeo*wsS=T?WHvTwc|L5ua@26DWUT^q*MDg$2 zy+1F8{Jm=RYcIq9|Np=329XS;0L7myj0_A03_2i9AU`p%H9O1@D4QT6wU#NtAjgSg z{fa3DnQVTS)?5)1(AuK(mfImG#aXQ|`@_^eA*PQ%6m?Z&XE|6Eg>!G(Q{1YG+3VYXA(QmgfKf diff --git a/install/update/new/adm/images/file_new.gif b/install/update/new/adm/images/file_new.gif deleted file mode 100644 index d0ec75876d8889d1ec98c16d430c3c7546c3c9d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 229 zcmZ?wbhEHb6krfwI3msP>3rbFi{a1i@A-L3;pYkIUx%4qy}b4O?xsIS*njM0_7IE0OUeru>b%7 diff --git a/install/update/new/adm/images/file_new_conflict.gif b/install/update/new/adm/images/file_new_conflict.gif deleted file mode 100644 index 84efde4faa94e7b0c95a2793e4f355a6a5c2a56e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357 zcmZ?wbhEHb6krfwxT?%BZ{D0WYgXO4b7$+;EkAzzxPJZmix)2zFJ8EG>Ei9%x6PV0 z)J{3qZ&;Tg@WMO1rP-f5pnGNz216$L9 zi3K4UG79q#Cm800i7Z+XVwfpqc4^I*M1i<12^SkUI+-jY+rDi6;l`@yB_a~!&Mv5V zAZU5>CU*JAYDLBRNTH_45=Gf4A&G89CKeXPNDk(pIwi)b(*s3WyF}XO$}t4WGb!^X iMsYf^@vje*@>LcNh~ksn;l$0!!6(SUxyIR%!5RR?SbJyy diff --git a/install/update/new/adm/images/file_not_modified.gif b/install/update/new/adm/images/file_not_modified.gif deleted file mode 100644 index 8f9b3d383916ce09c6bf67a1f8788c6c96ffa794..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 570 zcmZ?wbhEHb6krfwc;?D*;Q&>CNV|uNEGB zI(f&#N!uT;IQIO;(=WXnuIK0HXJuutJodb0`Pr&j`$~J3Cg#@{mz1cgswycfRaI5b z-T%bG!ot$VVban)MMXuHmX_%m8U1rsR8?1-Svy+U*hfS}I66Az7ZhY?=U7|Y^)J~| zQdU;kI(h%qx8)TT;Smvbwsy9*c6D?1wywGq79JiD7&vvw*5s_BiK~vMq@+xpI?deN zqI1Ko+RkY;J@ez@;yTt|TXW(?-_{4+oA3Ys|DRz<0mYvzj0_B}3_2iJgW`mNeR_jy zlPiN0E4wqR6LWJfr?bn%NzNR-jM9^4PU2#0;+?g?#i@mTqNA9Cx{avqWajx3jm70G zl@x_%IcQ2 zNYlYo%|LY~C&R^s6P@{7pM9Rh*2Kv5(?v*1)KNiSh*_M8mDfO_fsv7s?F}y%3xhQP D5Zj>E diff --git a/install/update/new/adm/images/file_up_to_date.gif b/install/update/new/adm/images/file_up_to_date.gif deleted file mode 100644 index c37234264629d4f5a4378c07f0b5be38a5b34f66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357 zcmZ?wbhEHb6krfwxN5{O?|DbuBa6$g&Xzt2t$Y&o^23XT&wFmZzLNaJuK!I*$`kvX zryjXaz0Q3*bm#SrDbH%|{k)d<%sc9l(S{cbmOY;|>sia&KQG&!W)(d1EqWHv{W?G4 zvGwae&r6;M{r&&9^L6gNFYCYl{ruq9joKG+DUTfsp7w^@rJh1xpy(BAGXPu&@8Hh_!g;B96)+ zPC-Ln0|D+J4%I-eb_L}Qu1FS!AbE8;CB@cA5vC?X2{8lhD1AO7(MUuasVh8^NkePx>nFP$W%Nzf-YH-5I`n?DLqf7ejYMy2O3{H7xq1E_Az3TJWFyuj U>|R>2x1(T&qnhx!=K>7Y0JXDBD*ylh diff --git a/install/update/new/adm/images/icon_delete.gif b/install/update/new/adm/images/icon_delete.gif deleted file mode 100644 index 57962d51728640b66636143a9f4fc91ca9afc1fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmVHCpIecJdn*Ws<-1jU*u44=Z&EK@$}?BVfohG z?t_~D|Nr7KR_yHTA^8LW0018VEC2ui01yBW000Gi;3s|*fFuQ?9AoP&UMw$A`w((2 z505Cwfm|@AASGgqj3K7kFk*$nFV^WOn^l=&=;2f|n<__!DCE4=&RC`~vmf6j`@#;V zl`@G!X6K+YG7c1OVQXF+Pz@gdOc6N|8Zj6m4+AXky F06RBtaaI5T diff --git a/install/update/new/adm/images/icon_delete_disabled.gif b/install/update/new/adm/images/icon_delete_disabled.gif deleted file mode 100644 index da55bbbe445dfc0e71a24ca92c901ba292bbb6d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 249 zcmZ?wbhEHb6krfwI3mPw^XAPfmo8nudiBYZCs(grxp(j0{rmTC-@JL}&Yc_AuRnV9 z=-IPp*RNl{a^=e7$B*yazWws$%S#t8{{R1-9ER$0FlKT^%7{*#G>%ZZ7 zY_8Lxjc)437J@)Vr7jC;UULk zPKV?r0ujVSED}2-htUW~afk*0WkYO;IvtJ4pb%XOrU%v-Nl})?@(5tWE=+{(=Nra~ s4p0ODY_g7gXeJ0FLxD#kH68#MZyr2KKqCSbE+!}+9WyGGFe)JcJIK{-EdT%j diff --git a/install/update/new/adm/images/icon_edit_disabled.gif b/install/update/new/adm/images/icon_edit_disabled.gif deleted file mode 100644 index ac96b0e6dca874183e3165c98062c1f8008dabfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 239 zcmZ?wbhEHb6krfwI3msP^5x49A3i*I@Zj|6(}xcqzJLGz?c29MefsqATOVxbgn|`%|Y*ojrT@s%|-I1Y`h$lb@bFUq$Q2DCK+fcGFSrudTw>% diff --git a/install/update/new/adm/images/icon_folder.gif b/install/update/new/adm/images/icon_folder.gif deleted file mode 100644 index 845618c1a266a23aa575c2f12db1d75830e2c1f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 662 zcmV;H0%`q6Nk%w1VH*G&0M!5h>hboKy4$_d@kWTj>Fe%RlgH%d z>NI`4$<*Isn#!cY-TM0b_V)Pn_4hl0zWDk1#M$et#oM60*yri&^7Hj=p2^(g?EC!u zEO@$5jl;0Y;qdYE`TF`Pce%^n?RBTp;pFJ#>+!eE;IYl+CUm&=`1!Wb<{@&o;Ns`s z;pTO9b>ZXa;OFj%u+*o(*FS~8@9^^D<>}_=>-6>Z?CtRG@A2yF@A2~V0001)nVDv0 zX4~H5A^8LW002J#EC2ui02=@s000L6z@Kn9tYkV1&Z3hc5TDRrAv7BWR1{U9G2;}X zPsSoa0SwOQ0YH#gFu+od$~@TE@0&B=g!)1YGa_{l4i z6CjHyZ$k?w8xIo@5Ij6Cs4k?d6NM)WLj?%{533M9J-NBIs}BGPekc^RH^s)s$i)y3 z0vtaU2LKZ{7}Xf2KH1tl))+Sv00%M|BNGuj=;`X~>JTXn88Z$k7&P|wJlgs__x2bm z0S?H4up@`Tg9sBM+yTMEf)D~A(7-{lqQ#3AX+RJVf`bVNIdq5|NwOr#91Ry72mlg+ zOPAQRy_|_4M}&YG8eqtAp=VFCT)KMr99k0tJZL3$Ah5x-sne%S5$q@-?gt717?!2k^n w7FMJVv&4f20||9#@X$d5W;g{nNN5nlfd>mQ8c6U0CklZh(HmiNW;s_vYy9{r>*;_xR1$;P3GAcB9LUvC>+V z$&2-B=_WAqx`1$AQ?A+<|z0u?;ce?EE@ygWS9B;PK-Raol?$g@g z!q@2~bh!Ha`{n2B*X8l>^7Q!m`d5<1Uzf;IkHlr3&O?X5Xq?Dqn#g0B$KmAY?CtRG z@AB^N@$>ZdAaS?*{QU6o^WWj-0001)nVIqO^!fVw>g@0G^Y!HB>Ly^5Hj2{e>+WV| zX4~H5A^8LW002J#EC2ui02=@s000L6z@Km^G$cwDOtMl+7>H1)fz(kfI3Nayvru$M z&nOWAGfg0bbSzDPOiVC@SeQBi*0FrdqhEUfCn#blBNGIBH;Iahd;}mPf@3Ejh$134 z9+{dRiF_a@azYyz03IR{1qC7vJFTue4FwS*e;6A=DkKm$1p>YztvtfRBEAJT5F{!; z1|1-=zQz&L5yLzY(FF}49R>&_0tGKQGU=NA`1Z> z93t2_K#*V#0l|Fj;31&k0UHrGbbz6ufD9KHF}?`)!p24(FEYB2Q9uKX3K|5oV8N25 zj2t|2$Y7CUhs>5NS_sfkfuaE63pj!beRv=!QK3OC?1a&QLIDdsqDq}gb*fSd72v(F zAfanl8Z;h=ec-jM1Pd?xAy7b2!hp8}eAJjb7p`3i1Qj5-P$5H(9y$UG9!xlJj~p2) zT=~B0RTJRokGz7 diff --git a/install/update/new/adm/images/icon_folder_lock.gif b/install/update/new/adm/images/icon_folder_lock.gif deleted file mode 100644 index 7afb092a8f1db6878d8ac80c4cf6840edce929e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 681 zcmV;a0#^M;Nk%w1VH*G&0M!5h$_dg%Ixj%$H>gP(dBh@b#*(t3legF1G1aU_W0Y~;q>+Q&(YP>)!0mixcK?`>g@0D@bdEW_51w%UteE>f`U+u!$U+w>+<;6 z+ur&5`tb4dT0g1-0o`MbTrqP*1e^!7i6z>bcOz{14z_4e`d^zQHRnVFepW@Z2Y z0NdW`2Bij}s4|2L6GI0Z92y<79X&j^x3sz%92;Lh3=W_<#Kp$P#Hs}h zKQtFCGBqaCCZj#q*gn)IH8LC*3IYcsA3Eme=;`PmG6Gx*GA1SS^FG-3JoNJ>G7uMX zGIZ=1NU)&6f;wcd0$5^z!-o(_ka$p`;sc2#IxJ(bpu-M{AVX3Nkimn=3;`Yt$ieCY zjSo8>$dtKa1rG$bJcIx-s^@^l5B}Vlh&l5?g9J#Cf*^1W*EJpPoWamRv7*(A0a_5i zVQVIj9x%WGD`0{|g#c)4HfV68Edn1ry!zlHY_e8TMxO@ZpP-f)YE> zW>~SdaRVNsaE)p}1c00u14w4rtdjuXuh&qZNa5qjffxk_p5+|kFWj3q8l)f%Wr~6b zh$&_WvDF6x(H4RmC=Er7iUkn{#N185$J*JZi2Gp>LjVK_6d+(g(X;ysI6{mdQ6d5Z P4G`!-glOSGNDu%!s{lm(^`qKhKY^J)Ze_({r&#i-O} z_V)Pt`uoh?>-F{b>G1aW`S~n)x|*`c#o6oZ^Z5Jx{LatQDR;T~`ug|y`Q_~M@A30c zj>IByw7 z&jMvb0x`~L6R6gT6~I!_qjWae@1}F8(@qWkzoPxdmdy!!E|64(S{2)EU-WfE>Pe?3;-xF HL=XTw3P?}z diff --git a/install/update/new/adm/images/icon_sync.gif b/install/update/new/adm/images/icon_sync.gif deleted file mode 100644 index 16223dfd9a4b92754df7790c789cec24b7d67976..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 251 zcmVNk%w1VGsZi0K^{v^}>7e%aZrDTJh7W`L09zq$~BncK((G@7=-h*t7Vu zPVDRH?&8q=ofi19OY_N&_^?RsKR{g?>#zjFGgGW?$$ z?CR$InhySz0PO7SA^8LW0018VEC2ui01yBW000Ge;3tY!U{udFe#?juUMy?L#|dJ9 z$$ShbozFnl$VeoB0pPt9S0)IePTylP6CeKYo1s_U%WH9vwMy zEY^ fg@u@HtQiE9{Ka{=`$Tz_bHq6X1T_-06&b7n>9J!# diff --git a/install/update/new/adm/images/icon_trace.gif b/install/update/new/adm/images/icon_trace.gif deleted file mode 100644 index 5c622e9a9dc22036b560f2ef5bbc6b910abf6903..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 307 zcmZ?wbhEHb6`11UtW9k z;`8^PKY#!E@$0uy`3&QVna1TaOe$vDH_UZxobT8$^~f9KNB-W3_MHl~Ri z_51JNfB*mg{{8#s&!1nve*N_6)5nh=-@kwV`t|FlPoF-1{21s$uuHKJia%Kx85qnN zbU<<-KQXWc9Eg6TJh3KZ`;s8nhYS4VPQP-KvdmNTQ~uD!>#)7s^+<(6%!Zk%XSb!u tX-clWme$Q7-I#lyFLP=RK(7o6YFx>g+usN=oj_T%#VQnKdw{Qf+s6F2#8aMmmBX8~`79gE9mnrY0tpZxK!g+{1QH)w9u^HmM3^W}(kM>Ogi$&Y4T$$SE(~K3f`=fCW}-qo9${FPjfD}M zjd8&+N|1CI7DbF8#0e@wMHpTXLJ-QvVi-It0@ZMl^z8 zL?DbnD9&-5zzaA*F${}hB#aRx#gKF)5JZ9y7KudTf`H*9M$lnVLy9(I2uiRl7mM-J zK_nVwVHA(Y1zNPovJ@TR1s*4<83>IF@i2smmJytc#$sY(ju#?PR)`B!BsvokL7^lW z3Bf3g;3z>s2o{No5F!wap%^9bJdBbd7#B$eVN4KshKX`K2O~rfLU=(?Rop4=J>a_1(y7#zr)o*k?CGDN{4NG!9wbmBx|J@HMtx)fX`I!<~W;=Dv zIla8}=thuyG0C2@2T(lw1DxbB0nOvCEvmfYb>_2$j-pD}{N0tuzo|CLNwewROWD=7 z@0$5_ULtLQjwczDO$5!pGg|NBs}W?@hhb z)uC0_=F2N)pShj3dX1@Dsl9FVr|mYFq`9lBdUQuJ>k9m7`CsY$OR~OdvV#YhCi@$C zx$X<#>i*pq)I|fYwy4U>oAoXeK6@)Ck(_e4)}cU+%7p7IX_htnK9C*MaMf9LuNRE= z)|bBa;n`p92giEfsBIcOv-3H?ajvBf80%|sy==)bjx>+?ucjo5A7- z*9_Nnr#HT}kXw|xsLI-XscqI~Nx1m^vFe1z$xE$;*Bi{O2}^aChdy2E+3Ne##6_DW z_2-_gmC1L`p6VK&EZyqMytD24cwSlG>8{7hb{vmN%Ql2rDZXc}^g6reyiXN}=j|B&BXLJtE{q0HrTXh5{X@P~&7gNx;@Zi>-Cq|WC)&T&ysBE0xbaYvY${JtGMr)6e>5yV zrm=KR<=L9XrnW!*?q?Y~+hkdS+9r`Gp6y7z`s4G5p0X_Yb=KrR(sd5rA7~v(l}yVV zpag84UoZpUCI^2%(2=ue7V4<6cvCuVdY$?m^WVsj`l^g-tp1mf3EZyZd?^D@f14nw z*V(Go10BK73B@pbkSNfp6p|~~^Q_FyJM8*s!HIBH>~nqimgsEnoMNYDlZ3w+3U+0c za8q;fJ9BwABqb}{HzfL6-;=z)DgWU=f0ACXCr-cr-M_Pl_D@E$$X5HtG?VvDf4(sO zvrTgyci;3s*f6+Dnm7pli+6)^v{RDNBTXom$a6h@VELpysZk}DYTdFD(`fRGr@C}Q z?)+sQz}Uz+48>+?vawTA>~*Fz0)_KHqUNl}x$>1}utDY5bV1IFVtd-#pSb;6mP=lF zxLXC9s|v4qFEtVwc)|Uw%5%{d%$3@OiVPi^`7}ysQ@be1ES4-g#Z8m diff --git a/install/update/new/adm/images/loading.gif b/install/update/new/adm/images/loading.gif deleted file mode 100644 index e1ed0883e07c63f3a36f9ee38318ffabdfe44147..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1320 zcmd6l{c9U_9LGOt)7<6K<~f(UB$vxmAJ&H~TlbKzUA3ESll8uJwt_Hp&><)jMP);L zm|QM*NnEn6Bh6&Z3@cmf9>f+l?VPUcL23mN9Qag_IhEqWZ^A%@so#rp-u?p*?x%ad zzMt3k{kg&9K)h=#1R+>KaPya6%@&KPzTRfHJ6*KX>2lzgb~l*K1W6hU1|vlojg(%m zKUg}tW9P2-u6%Ui@?vHBjGqs_oKg})!y7mCpzWiFN|TqDKGo@Tk*4M^Zmck@Cm4>n z8TPTU#~Id3yII!b<@kWd>q}+xucQ=@kMnUn=MU_C>D2?p*S(y7`G=p!kCb=p9P8=r zYmct}`1)7H$;u1+Qti=LynFMd#ZN9?UFuvP=luMh7xxV&1+R|_g(K0}nx~)J+tj?O ztEYD$IduMmtNFvF-OoJVxglPjn(+sMU*7zYb~EsQeS&|PhWj5L-P*Uke{D2YtHYkb z-}Q9>2-;O=bxlC5h)7DysG**$ts{uKTC%=DDNaa6onDwMAJglMr4pq(Ha#Qgs43ZG zcyqRFFrD?(%*~f;Jf(LpEYwVx7On~BWa{k&jtkBk&ZJLX^I6Rn$DA&0{7`@!VBb7< z99^H`L(^WD)7H7+>&(&F@N8nsygvKQZ6WvP#YQS2*shG_&427VX?^5GX5QB)-+J=9 zw!~cTw{7f3p z0QNq$f_xwjC9u0uf3+wnjEhTi8rTR<46BN*BI3J|qVQV>{28>Z3mCc(V8P~ec@?)E zDv)tl%vN6^)2P8ojjRv6NRqJ)GJ_LYz(zalz#uoPl_i0Kx~eRPD_P4+Zgw!F<~meB zB_(`7-q zS`7*zS?2gnS&45iNNwXqZIlGZo!%MI4C@6&u?*dxQCj`Ic_lnvoG9fr0&2^()g@8? d2uOVTp3nbwY83?`yc#5-wJ)159KZv+{{|9CDcS%4 diff --git a/install/update/new/adm/images/no_avatar.gif b/install/update/new/adm/images/no_avatar.gif deleted file mode 100644 index ad73330e713ec9a21f97366b326a8c66afe5e9bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 930 zcmV;T16}+_Nk%w1VPpVg0M!5h!_3s-=IPqth19I^!oe!#m?2-;pXx4 z_2lU6!_Cz8_xS1U@6p)a$I#d1>FxCP_uJv+;pOS&>FnoQ6%sUqgoT9?6&QSdUl0ifhLMtk1_=<1 zTL1zIlbw)hY95S;PU3YWDB_uL7! z03h|FX24w^3i*en7j3nYtKz;q!c zu?v_ExZHIB)3%wg2-w6KOD7}$nLJU|WYjX~DVU5<8uhf2(a5EpOfvEaby7%18LLX- zxJIH@Ll#Fh{7MMoD1>AOEsQAeYr%bK|IxEoHD5A#TIT^&x3nELaZAmCo1rbJx4}ZD z@w|q3#xk7G8VeET@|ffyw{9lv1?}<>R}N=+K2mC+s?kU^(X9sRB5ERz+7hdz?==z@ zEdscJQ4EHQ04-S9E`q>A0S)&w6!3uTb%+2XG>!-m!t;XyKuI1b@Bnd!0xN>9D3BqV z2?`>rilAVk775u^4UoVD0!4|mgG!(PvF5=C{Dyqc9U2>?0AM63Y;eX2DjX<@3MY`! z0S69x!a)aNbU;Ccr%-^u;TIHgcnSw!oFF1B5puCXgD0M%f`VE+U|@@=q%hzWApA!o zEFbW91qwUrg2ELf+!rJ)CCo>K3Gf~1i2?0Rv7wW?P%uRX=}{Sr2<1glfR?)y5XA%G zff>sRH#YI5nYxJSL$AcLo<$N*>&8ITG~mqx^(Dk?D`f$6J~Y#Iar EJ3isPuK)l5 diff --git a/install/update/new/adm/images/no_image.png b/install/update/new/adm/images/no_image.png deleted file mode 100644 index 1061ee3b8fffaaef55c7a819438d50c02ddc33db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 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 diff --git a/install/update/new/adm/images/phpbb_logo.svg b/install/update/new/adm/images/phpbb_logo.svg deleted file mode 100644 index 2a24106..0000000 --- a/install/update/new/adm/images/phpbb_logo.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/install/update/new/adm/images/progress_bar.gif b/install/update/new/adm/images/progress_bar.gif deleted file mode 100644 index 1ae265152cad03d45dd8bd834adde294ee644c8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1353 zcmZ?wbhEHblwcHK*v!bVWXY1JPoIAN{Q26oYy0-?TeD`((xppp=tUelbm(b8?`1*9 znKNhp|NsBnw{Hw!p!lEL&ow02*)hP?NY8+o5h$qmlZDlYfssK6qyS_r1IvE{j}5E# zTD(5H`+tH)UrOe@j4Y-}Av{dV=Sy<$SFC$q^Zx&V1qB{DQteHSjz$(%^DnF@@md=t z+03BOW)PAhzQOfRYRlQ=lAmY%wqJi|QL|6s`ql5{ar>6v{$J5h)l}0`*VxhA+1ky< z!NVkC6xZH0t!Mhw8M9~2t)1VtpnKlJrHdEMTrp=AH(S!Ol^a%XTC#l0njPDBZQHYP z@8T0aGadPwW^Ya~=x&EGX za$*68p9m=Ym>HNExPXv>Mbbcasnddzpzi9u_t@HEe#~4RnRa89N0K-rLNz~JwMc-c z=%GDVk|NEoM?ddW?3lQ`a-kqXp)|1y)rnPTOsqnCVikH5t1z5cg~`M!%qLc1HL(iY ziB&k6ScUV6Rk)g1h1-c$c$ip)=ZRH#n^=XdqfQtYvn%VZ`yDQgw4er)UO?E4 zG}?&ude0I+aCWBTh&{G)+1Z^EH2%S&yR*F@2^#-k(M{6WB}?Lfl40@y3ddLk8ZD?9 zg$ociBaL=%^s=MQ51jIZB#U7`y9^j^TNb@FZ#UFVO{XJzi2OxCoPcgy&uO1 reI`&k%nR$;Tn^vIGfg}7`&j -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -*/ -define('IN_PHPBB', true); -define('ADMIN_START', true); -define('NEED_SID', true); - -// Include files -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -require($phpbb_root_path . 'common.' . $phpEx); -require($phpbb_root_path . 'includes/functions_acp.' . $phpEx); -require($phpbb_root_path . 'includes/functions_admin.' . $phpEx); -require($phpbb_root_path . 'includes/functions_module.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup('acp/common'); -// End session management - -// Have they authenticated (again) as an admin for this session? -if (!isset($user->data['session_admin']) || !$user->data['session_admin']) -{ - login_box('', $user->lang['LOGIN_ADMIN_CONFIRM'], $user->lang['LOGIN_ADMIN_SUCCESS'], true, false); -} - -// Is user any type of admin? No, then stop here, each script needs to -// check specific permissions but this is a catchall -if (!$auth->acl_get('a_')) -{ - send_status_line(403, 'Forbidden'); - trigger_error('NO_ADMIN'); -} - -// We define the admin variables now, because the user is now able to use the admin related features... -define('IN_ADMIN', true); - -// Some oft used variables -$file_uploads = (@ini_get('file_uploads') == '1' || strtolower(@ini_get('file_uploads')) === 'on') ? true : false; -$module_id = $request->variable('i', ''); -$mode = $request->variable('mode', ''); - -// Set custom style for admin area -$template->set_custom_style(array( - array( - 'name' => 'adm', - 'ext_path' => 'adm/style/', - ), -), $phpbb_admin_path . 'style'); - -$template->assign_var('T_ASSETS_PATH', $phpbb_root_path . 'assets'); -$template->assign_var('T_TEMPLATE_PATH', $phpbb_admin_path . 'style'); - -// Instantiate new module -$module = new p_master(); - -// Instantiate module system and generate list of available modules -$module->list_modules('acp'); - -// Select the active module -$module->set_active($module_id, $mode); - -// Assign data to the template engine for the list of modules -// We do this before loading the active module for correct menu display in trigger_error -$module->assign_tpl_vars(append_sid("{$phpbb_admin_path}index.$phpEx")); - -// Load and execute the relevant module -$module->load_active(); - -// Generate the page -adm_page_header($module->get_page_title()); - -$template->set_filenames(array( - 'body' => $module->get_tpl_name(), -)); - -adm_page_footer(); diff --git a/install/update/new/adm/style/acp_attachments.html b/install/update/new/adm/style/acp_attachments.html deleted file mode 100644 index 7a66f17..0000000 --- a/install/update/new/adm/style/acp_attachments.html +++ /dev/null @@ -1,495 +0,0 @@ - - - - - - « {L_BACK} - - -

{L_TITLE}

- -

{L_TITLE_EXPLAIN}

- - -
-

{L_WARNING}

-

{WARNING_MSG}

-
- - - -
-

{L_NOTIFY}

-

{NOTIFY_MSG}

-
- - - -

{L_UPLOADING_FILES}

- - - :: {upload.FILE_INFO}
- {upload.DENIED}{upload.ERROR_MSG}{L_SUCCESSFULLY_UPLOADED} -

- - - - - - -
- - - - - -
- {options.LEGEND} - - -
-

{options.TITLE_EXPLAIN}
-
{options.CONTENT}
-
- - - -
- -
- {L_SUBMIT} -   - -
- - -
-

{L_SECURE_DOWNLOAD_NOTICE}

-
- - -
- {L_SECURE_TITLE} -

{L_DOWNLOAD_ADD_IPS_EXPLAIN}

-
-
-
-
-
-

{L_EXCLUDE_ENTERED_IP}
-
-
-
- -

- -

-
- -
- {L_REMOVE_IPS} - -

{L_DOWNLOAD_REMOVE_IPS_EXPLAIN}

-
-
-
-
- -

- -

-
- - -

{L_NO_IPS_DEFINED}

- - {S_FORM_TOKEN} - -
- - - - - - -
-
- - - - {L_LEGEND} -
-
-
-
-
-

{L_SPECIAL_CATEGORY_EXPLAIN}
-
{S_CATEGORY_SELECT}
-
-
-
-
checked="checked" />
-
-
-
-
checked="checked" />
-
-
-
-
-
 src="{ROOT_PATH}images/spacer.gif"src="{UPLOAD_ICON_SRC}" id="image_upload_icon" alt="" title="" /> 
-
-
-
-
-
-
-
-
{ASSIGNED_EXTENSIONS}
[{L_GO_TO_EXTENSIONS} ]
-
-
-
-

{L_ALLOWED_FORUMS_EXPLAIN}
-
-
-
-
- -

-   - -

- {S_FORM_TOKEN} -
- -
- - -
-
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - -
{L_EXTENSION_GROUP}{L_SPECIAL_CATEGORY}{L_OPTIONS}
 
{groups.GROUP_NAME} -
» {L_NOT_ALLOWED_IN_PM} -
» {L_ONLY_ALLOWED_IN_PM} -
» {L_NOT_ALLOWED_IN_PM_POST} -
» {L_ALLOWED_IN_PM_POST} -
{groups.CATEGORY} {ICON_EDIT}  {ICON_DELETE} 
-

- {L_CREATE_GROUP}{L_COLON} - -

- {S_FORM_TOKEN} -
-
- - - - - -
-
- {L_ADD_EXTENSION} -
-
-
-
-
-
-
{GROUP_SELECT_OPTIONS}
-
- -

- -

- {S_FORM_TOKEN} -
-
- -
- -
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - -
{L_EXTENSION}{L_EXTENSION_GROUP}{L_DELETE}
 
{extensions.EXTENSION}{extensions.GROUP_OPTIONS}
- -

-   - -

- {S_FORM_TOKEN} -
-
- - - -
- -
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_FILENAME}{L_FILEDATE}{L_FILESIZE}{L_ATTACH_POST_ID}{L_ATTACH_TO_POST}{L_DELETE}
{orphan.REAL_FILENAME}{orphan.FILETIME}{orphan.FILESIZE}{L_ATTACH_ID}{L_COLON}
 {L_MARK_ALL} :: {L_UNMARK_ALL}{L_MARK_ALL} :: {L_UNMARK_ALL}
- -
-

{L_NO_ATTACHMENTS}

-
- - - - - - - -

-   - -

- - - {S_FORM_TOKEN} -
-
- - - -
- -
- {L_TITLE} - - - - - - - - - - - - - - - {% for attachments in attachments %} - - - - - - - {% endfor %} - -
{L_FILENAME}{L_POSTED}{L_FILESIZE}{L_MARK}
- {{ lang('EXTENSION_GROUP') ~ lang('COLON') }} {{ attachments.EXT_GROUP_NAME }} - {% if attachments.S_IN_MESSAGE %} -
{{ attachments.L_DOWNLOAD_COUNT }} -
{{ lang('IN') }} {{ lang('PRIVATE_MESSAGE') }} - {% else %} -
{{ attachments.REAL_FILENAME }} - {% if attachments.COMMENT %}
{{ attachments.COMMENT }}{% endif %} -
{{ attachments.L_DOWNLOAD_COUNT }} -
{{ lang('TOPIC') ~ lang('COLON') }} {{ attachments.TOPIC_TITLE }} - {% endif %} -
{{ attachments.FILETIME }}
{{ lang('POST_BY_AUTHOR') }} {{ attachments.ATTACHMENT_POSTER }}
{{ attachments.FILESIZE }}
- -
-

{L_NO_ATTACHMENTS}

-
- - - - - - -
- {L_DISPLAY_LOG}{L_COLON}  {S_LIMIT_DAYS} {L_SORT_BY}{L_COLON} {S_SORT_KEY} {S_SORT_DIR} - -
- -
- - -
-
-

- {L_MARK_ALL} • - {L_UNMARK_ALL} -

-
- - {S_FORM_TOKEN} -
-
- - -
- {L_RESYNC_STATS} -
-
-

{L_RESYNC_FILES_STATS_EXPLAIN}
-
-
-
-
- - - - diff --git a/install/update/new/adm/style/acp_avatar_options_upload.html b/install/update/new/adm/style/acp_avatar_options_upload.html deleted file mode 100644 index 666950e..0000000 --- a/install/update/new/adm/style/acp_avatar_options_upload.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
-
-
- - -
-

{L_UPLOAD_AVATAR_URL_EXPLAIN}
-
-
- diff --git a/install/update/new/adm/style/acp_ban.html b/install/update/new/adm/style/acp_ban.html deleted file mode 100644 index d0eab75..0000000 --- a/install/update/new/adm/style/acp_ban.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - -

{L_ACP_BAN_EXPLAIN}

- -

{L_TITLE}

- -

{L_EXPLAIN}

- - - -
- -
- {L_TITLE} -
-
-
-
[ {L_FIND_USERNAME} ]
-
-
-
-
- -
-
-

{L_BAN_EXCLUDE_EXPLAIN}
-
-
-
-
-
-
-
-
-
-
-
- -

-   - -

-{S_FORM_TOKEN} -
-
- -

- -

{L_UNBAN_TITLE}

- -

{L_UNBAN_EXPLAIN}

- -
- -
- {L_UNBAN_TITLE} - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -

-   - -

- {S_FORM_TOKEN} -
- - - -

{L_NO_BAN_CELL}

- {S_FORM_TOKEN} - - - - -
- - diff --git a/install/update/new/adm/style/acp_contact.html b/install/update/new/adm/style/acp_contact.html deleted file mode 100644 index c46a2d7..0000000 --- a/install/update/new/adm/style/acp_contact.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - -

{L_ACP_CONTACT_SETTINGS}

- -

{L_ACP_CONTACT_SETTINGS_EXPLAIN}

- -
-
- {L_GENERAL_OPTIONS} -
-

{L_CONTACT_US_ENABLE_EXPLAIN}
-
- - -
-
-
- - -
- {L_CONTACT_US_INFO_PREVIEW} -

{CONTACT_US_INFO_PREVIEW}

-
- - -
- {L_CONTACT_US_INFO} -

{L_CONTACT_US_INFO_EXPLAIN}

- - - -
-
-
- -
- -
- -
- - - - - - - - - -
-
{L_OPTIONS}{L_COLON} {BBCODE_STATUS} :: {IMG_STATUS} :: {FLASH_STATUS} :: {URL_STATUS} :: {SMILIES_STATUS}
-
-
- -
-   - - {S_FORM_TOKEN} -
-
- - diff --git a/install/update/new/adm/style/acp_database.html b/install/update/new/adm/style/acp_database.html deleted file mode 100644 index d3433a8..0000000 --- a/install/update/new/adm/style/acp_database.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - -

{L_ACP_RESTORE}

- -

{L_ACP_RESTORE_EXPLAIN}

- - -
- -
- {L_RESTORE_OPTIONS} -
-
-
-
- -

-   -   -

- {S_FORM_TOKEN} -
-
- -
-

{L_ACP_NO_ITEMS}

-
- - - -

{L_ACP_BACKUP}

- -

{L_ACP_BACKUP_EXPLAIN}

- - - -
- -
- {L_BACKUP_OPTIONS} -
-
-
- -
-
-
-
-
- -
-
-
-
-
-
{L_SELECT_ALL} :: {L_DESELECT_ALL}
-
- -

-   - -

- {S_FORM_TOKEN} -
-
- - - - diff --git a/install/update/new/adm/style/acp_ext_actions.html b/install/update/new/adm/style/acp_ext_actions.html deleted file mode 100644 index 6b59ab7..0000000 --- a/install/update/new/adm/style/acp_ext_actions.html +++ /dev/null @@ -1,7 +0,0 @@ -{% for action in enabled.actions %} - {{ action.L_ACTION }}{% if not action.S_LAST_ROW %} | {% endif %} -{% endfor %} - -{% for action in disabled.actions %} - {{ action.L_ACTION }}{% if not action.S_LAST_ROW %} | {% endif %} -{% endfor %} diff --git a/install/update/new/adm/style/acp_ext_list.html b/install/update/new/adm/style/acp_ext_list.html deleted file mode 100644 index e578312..0000000 --- a/install/update/new/adm/style/acp_ext_list.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - -

{L_EXTENSIONS_ADMIN}

- -

{L_EXTENSIONS_EXPLAIN}

- -
- {L_BROWSE_EXTENSIONS_DATABASE}{L_VERSIONCHECK_FORCE_UPDATE_ALL}{L_SETTINGS} -
- - - - - - - - - - - - - - - - class="hidden"> - - - - - - - - - - - - class="hidden"> - - - - - - - - - - - -
{L_EXTENSION_NAME}{L_CURRENT_VERSION}{L_EXTENSION_OPTIONS}{L_EXTENSION_ACTIONS}
{L_EXTENSIONS_ENABLED}
{enabled.META_DISPLAY_NAME} - - {enabled.META_VERSION} - - - {enabled.META_VERSION} - - {L_DETAILS} - -
{L_EXTENSIONS_DISABLED}
{disabled.META_DISPLAY_NAME} - - {disabled.META_VERSION} - - - {disabled.META_VERSION} - - - {L_DETAILS} - - -
- - - - - - - - - - - - - - - - - - - - - -
{L_EXTENSION_INSTALL_HEADLINE}
{L_EXTENSION_INSTALL_EXPLAIN}
{L_EXTENSION_UPDATE_HEADLINE}
{L_EXTENSION_UPDATE_EXPLAIN}
{L_EXTENSION_REMOVE_HEADLINE}
{L_EXTENSION_REMOVE_EXPLAIN}
- - diff --git a/install/update/new/adm/style/acp_forums.html b/install/update/new/adm/style/acp_forums.html deleted file mode 100644 index f51ce98..0000000 --- a/install/update/new/adm/style/acp_forums.html +++ /dev/null @@ -1,524 +0,0 @@ - - - - - - - - - « {L_BACK} - -

{L_TITLE} :: {FORUM_NAME}

- -

{L_FORUM_EDIT_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -
- -
- {L_FORUM_SETTINGS} - -
-
-
-
- -
-
-
-
-
-
-
- - - - -
-
-
-
- -
-

{L_COPY_PERMISSIONS_EXPLAIN}
-
-
- -
-
-
-
-
-

{L_FORUM_DESC_EXPLAIN}
-
-
- -
-
-
-

{L_FORUM_IMAGE_EXPLAIN}
-
- -
{L_FORUM_IMAGE}
- -
-
-

{L_FORUM_PASSWORD_EXPLAIN}
-
-
-
-

{L_FORUM_PASSWORD_CONFIRM_EXPLAIN}
-
-
- -
-

{L_FORUM_PASSWORD_UNSET_EXPLAIN}
-
-
- -
-
-
-
- -
- -
-
- {L_GENERAL_FORUM_SETTINGS} -
-

{L_DISPLAY_ACTIVE_TOPICS_EXPLAIN}
-
-
-
-
-
- -
-
- {L_GENERAL_FORUM_SETTINGS} - -
-
-
-
-
-

{L_LIST_SUBFORUMS_EXPLAIN}
-
-
-
-
-

{L_LIMIT_SUBFORUMS_EXPLAIN}
-
-
-
-
-

{L_LIST_INDEX_EXPLAIN}
-
-
-
-
-

{L_ENABLE_POST_REVIEW_EXPLAIN}
-
-
-
-
-

{L_ENABLE_QUICK_REPLY_EXPLAIN}
-
-
-
-
-

{L_ENABLE_INDEXING_EXPLAIN}
-
-
-
-
-
-
-
-
-
-

{L_ENABLE_RECENT_EXPLAIN}
-
-
-
-
-

{L_FORUM_TOPICS_PAGE_EXPLAIN}
-
-
- -
- -
- {L_FORUM_PRUNE_SETTINGS} - -
-

{L_FORUM_AUTO_PRUNE_EXPLAIN}
-
-
-
-
-

{L_AUTO_PRUNE_FREQ_EXPLAIN}
-
{L_DAYS}
-
-
-

{L_AUTO_PRUNE_DAYS_EXPLAIN}
-
{L_DAYS}
-
-
-

{L_AUTO_PRUNE_VIEWED_EXPLAIN}
-
{L_DAYS}
-
-
-

{L_PRUNE_OLD_POLLS_EXPLAIN}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

{L_FORUM_PRUNE_SHADOW_EXPLAIN}
-
-
-
-
-

{L_AUTO_PRUNE_SHADOW_FREQ_EXPLAIN}
-
{L_DAYS}
-
-
-

{L_AUTO_PRUNE_SHADOW_DAYS_EXPLAIN}
-
{L_DAYS}
-
- -
-
- - - -
-
- {L_FORUM_RULES} - -
-

{L_FORUM_RULES_LINK_EXPLAIN}
-
-
- -
-
-
{FORUM_RULES_PREVIEW}
-
- -
-

{L_FORUM_RULES_EXPLAIN}
-
-
- -
-
- -
-
- - - -
- {L_SUBMIT} -   - - {S_FORM_TOKEN} -
-
- - - - « {L_BACK} - -

{L_FORUM_DELETE}

- -

{L_FORUM_DELETE_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -
- -
- {L_FORUM_DELETE} -
-
-
{FORUM_NAME}
-
- -
-
-
- -
- -
- - -
-
-
- -
- -
- - -

- -

- {S_FORM_TOKEN} -
-
- - - - - -

{L_FORUM_ADMIN}

- -

{L_FORUM_ADMIN_EXPLAIN}

- -

{L_PROGRESS_EXPLAIN}

- - - - - -

{L_FORUM_ADMIN}

- -

{L_FORUM_ADMIN_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - - - - -
-

{L_NOTIFY}

-

{L_FORUM_RESYNCED}

-
- - -

{NAVIGATION} [{L_EDIT} | {L_DELETE} | {L_RESYNC}]

- - - - - - - - - - - - - -
{forums.FOLDER_IMAGE} -
{forums.FORUM_IMAGE}
- {forums.FORUM_NAME}{forums.FORUM_NAME} -
{forums.FORUM_DESCRIPTION} -

{L_TOPICS}{L_COLON} {forums.FORUM_TOPICS} / {L_POSTS}{L_COLON} {forums.FORUM_POSTS} -
- - {ICON_MOVE_UP} - - {ICON_MOVE_DOWN} - {ICON_EDIT} - - {ICON_SYNC} - - {ICON_SYNC_DISABLED} - - {ICON_DELETE} -
- - -
- -
- {L_SELECT_FORUM}{L_COLON} - - - {S_FORM_TOKEN} -
-
- -
- -
- - - - - {S_FORM_TOKEN} -
-
- - - - diff --git a/install/update/new/adm/style/acp_groups.html b/install/update/new/adm/style/acp_groups.html deleted file mode 100644 index 8651b63..0000000 --- a/install/update/new/adm/style/acp_groups.html +++ /dev/null @@ -1,335 +0,0 @@ - - - - - - - « {L_BACK} - -

{L_ACP_GROUPS_MANAGE}

- -

{L_GROUP_EDIT_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -
- -
- {L_GROUP_DETAILS} -
-
for="group_name">{L_GROUP_NAME}{L_COLON}
-
{GROUP_NAME}
-
-
-
-
-
- -
-
- -
-

{L_GROUP_TYPE_EXPLAIN}
-
- {% EVENT acp_group_types_prepend %} - - - - - {% EVENT acp_group_types_append %} -
-
- - - - - -
-

{L_COPY_PERMISSIONS_EXPLAIN}
-
-
- -
- -
- {L_GROUP_OPTIONS_SAVE} - - -
-

{L_GROUP_FOUNDER_MANAGE_EXPLAIN}
-
-
- -
-

{L_GROUP_SKIP_AUTH_EXPLAIN}
-
-
-
-
-
-
-
-
-
-
-
-

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

{L_GROUP_MESSAGE_LIMIT_EXPLAIN}
-
-
-
-

{L_GROUP_MAX_RECIPIENTS_EXPLAIN}
-
-
-
-

{L_GROUP_COLOR_EXPLAIN}
-
- -        - [ {L_COLOUR_SWATCH} ] - -
-
-
-
-
-
-
- -
- {L_GROUP_AVATAR} -
-

{L_AVATAR_EXPLAIN}
-
{AVATAR}
-
-
-
-
-
-
-
- -
-

{avatar_drivers.L_EXPLAIN}

- {avatar_drivers.OUTPUT} -
- -
-
- -
- {L_SUBMIT} -   - - {S_FORM_TOKEN} -
-
- - - - « {L_BACK} - -

{L_GROUP_MEMBERS} :: {GROUP_NAME}

- -

{L_GROUP_MEMBERS_EXPLAIN}

- -
- -
- » {L_MAKE_DEFAULT_FOR_ALL} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_USERNAME}{L_GROUP_DEFAULT}{L_JOINED}{L_POSTS}{L_MARK}
{L_GROUP_LEAD}
{leader.USERNAME}{leader.USERNAME}{L_YES}{L_NO}{leader.JOINED}{leader.USER_POSTS}
{L_GROUPS_NO_MODS}
{L_GROUP_APPROVED}
{L_GROUP_PENDING}
{member.USERNAME}{member.USERNAME}{L_YES}{L_NO}{member.JOINED}{member.USER_POSTS}
{L_GROUPS_NO_MEMBERS}
- - -
- - -

{L_MARK_ALL}{L_UNMARK_ALL}

-
- -

{L_ADD_USERS}

- -

{L_ADD_USERS_EXPLAIN}

- -
- {L_ADD_USERS} -
-
-
-
-
-
-

{L_USER_GROUP_DEFAULT_EXPLAIN}
-
-
-
-
-

{L_USERNAMES_EXPLAIN}
-
-
[ {L_FIND_USERNAME} ]
-
- -

- -

- {S_FORM_TOKEN} -
-
- - - -

{L_ACP_GROUPS_MANAGE}

- -

{L_ACP_GROUPS_MANAGE_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -

{L_USER_DEF_GROUPS}

- -

{L_USER_DEF_GROUPS_EXPLAIN}

- -
- - - - - - - - - - - - - - - - - - - - - - -
{L_GROUP}{L_TOTAL_MEMBERS}{L_PENDING_MEMBERS}{L_OPTIONS}{L_ACTION}
{L_NO_GROUPS_CREATED}
- - -
- - {L_CREATE_GROUP}{L_COLON} - - - {S_FORM_TOKEN} -
-
- -

{L_SPECIAL_GROUPS}

- -

{L_SPECIAL_GROUPS_EXPLAIN}

- - - - - - - - - - - - - - - - - - - - - - - - - -
{L_GROUP}{L_TOTAL_MEMBERS}{L_PENDING_MEMBERS}{L_OPTIONS}{L_ACTION}
style="color: #{groups.GROUP_COLOR}">{groups.GROUP_NAME}{groups.TOTAL_MEMBERS}{groups.PENDING_MEMBERS}{L_SETTINGS}{L_MEMBERS}{L_DELETE}{L_DELETE}
- - - - diff --git a/install/update/new/adm/style/acp_help_phpbb.html b/install/update/new/adm/style/acp_help_phpbb.html deleted file mode 100644 index 7d3c503..0000000 --- a/install/update/new/adm/style/acp_help_phpbb.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - -

{L_ACP_HELP_PHPBB}

- -
-
- -
-

{L_SEND_STATISTICS}

-

{L_EXPLAIN_SEND_STATISTICS}

-
- -
-
- -
- {providers.NAME} - -
-
{providers.values.KEY}
-
{providers.values.VALUE}
-
- -
- -
-
-
-
-
- checked="checked" /> - -
-
{L_SEND_STATISTICS_LONG}
-
-
- - -
-

- - -

- {S_FORM_TOKEN} -
-
-
-
-
-

- {% for providers in providers %} - {% for values in providers.values %} - - {% endfor %} - {% endfor %} - -

-
-
- - diff --git a/install/update/new/adm/style/acp_icons.html b/install/update/new/adm/style/acp_icons.html deleted file mode 100644 index 45fe7f8..0000000 --- a/install/update/new/adm/style/acp_icons.html +++ /dev/null @@ -1,282 +0,0 @@ - - - - - - - - - « {L_BACK} - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- -
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_CONFIG}
{L_URL}{L_LOCATION}{L_SMILIES_CODE}{L_SMILIES_EMOTION}{L_WIDTH}{L_HEIGHT}{L_ALT_TEXT}{L_DISPLAY_ON_POSTING}{L_ORDER}{L_ADD} ({L_MARK_ALL})
{items.TEXT_ALT}[{items.IMG}] - - - - -
{L_ADD_SMILEY_CODE}
{L_NO_ICONS}
- -

-   - -

- {S_FORM_TOKEN} -
-
- - - - « {L_BACK} - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- -
- {L_IMPORT} - - -

{L_NO_PAK_OPTIONS}

- - -
-
-
-
-

{L_CURRENT_EXPLAIN}
-
- -
-

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
cC`x+nh2#)Yp8<{!w7-D1GE_#0eJ|BtsyG z;0H>ep&z19Dk_m?72BYIHPfKDJuEM;;{MVjym#j=;kt`Qyl=HT%Job-mN-j3pG(1} zVErh4ZWSK)H%$5lzp)6irV(UWccY0n>56Z0tm6OuF|J;o#|M7t{dn&7b9m;`CFNRF zH)8II6ciD=n@gRq#cvJEpc^`B9)}GnXmQtZhnStLamjM*jU5X~(zCj#VQ#H&j(ZNL z9^zzjh$7xT$RwJ~H-~*E?}|IcaYV6O1BIa8A;1EeN04%aq*N)TD$;ML9u^_zp&KjcdTTvQ z#N0D+!9jb@Csh`W#W)U6@wA`3FtzUSCjBMy>56;IN6Z_88bw@T7{cMd{>VgBuh!6N zHVKY}Qn?J zblEk0nML=LpZXQ$Y-}WKB{XVvv>Htm2;QM!<2x}6O0P=n+)SCkwqcn|qdL6v66U5k z13U3ijA~CSY&GUG27o5Q5(kLFXotuiLsmzF72mRLH=wy-+xV&K)sIWlP8x4HzTi;OtzWCxN5VYHBOaV+_>+n98&mRbyxM3VegC{Hx zHLa@Y`tpe`zdr6copo$7-(!Aq*b7k=fA&Ml7;)I-nT826gbI!qlg0?o!F=PI`1Da`sSaO2jH8hRmP zi+OKYVx0EZWZ_aUub8m1>3lA1>|>pZazDxQGg04 z9yjko)3shDHwf8wyM^z3=ezjDtFIyFy5}A;30Xs)Zg%(H1Le}c_fNiz8&@vFr?Xj> zg)j^WTda!C?tK#1PllCcO=}U>`{Q2UIKteok&+^8lh`(=FcYj|&VK}*;3XH&-PXD} zFhoERtGH5-$^^P&qfPk!|khhy7xJXZW<+)Ei< z1?^jDqcBoJ5)tWy%4bFY)9-yBfA*ulfXymz8pg;W6ESC9_G?!=BcaM#UAp$GufKtB zeEr+_oiBe8^RqJu+wFlcsrhnW_F2zH6!^<$GWjPg%%i-#O?NX;M#CuaPNU1MpcvIJ zg2U0S@D8)iEbVSo)tZhbX}d0bLieZN{{g=D{r?3+H|S(W4~XN0;FLkyLyH$((_!jb z*F=+ETb$52dIaupj2#flyia;Ex~?Oa%i)z*U&kN5^j-Y+m;MoEDrH0+Z_m3@h?3#e zCgyw|u(^f{9Ku3VbFhe+9eaNy(B#Nt=mf2-?mgYXHSazOQR5=Oc9*$@A)rNsEMm1b zOcM+5y^B}=<~4$#A&defexhI#Sxcc8aY|&OQy1+q6B#nnE`1wapiIqxO>k{Phpm~g z*r(a;D<)ZS1{(iG@-6?xyhcgd62=jHWo@2}to z0lxg({}6LilL*7G_l{bV+{zZ_lYT z)z$;B`+h_yLtcY8WXkUhz%SZcf5t z6hDS~PiPva6yG2BA&)ZB;*}686ZiB>sA&bBg|>r{EXU8TF_s1;$!d{4Xkc#;=$q)78e(B_r3dQ@Yxirex+DK zsgOs~2~c0#f)*ukEt|j@%CQ7MM z7k=q^6mvO*e76@;0c1{e{Cy(g9Pgor@%aupwSX>G)AAHe8CzOu4_y6mV$iba=s7Go zH&70@)%|3+0W%5D6L2-=9p-14#-3L0VHnU2s3qYb@&hEEuY~M44sKk(hG(9+jyU)P zw(1Qf+Pq^UXIXHVBFyD`biX(6Vw=E;_%(j3>D>yb4c{jPAqSQe*aN1xjEpU5bgw$$ z()AR&Ec-+2>L7Dk=~wy^kd<@tTivzcRthj&3-xvz8ezSC`xc&m{uT=cD>lcC>1w+x zd)%GlKBv9K@!sK_&LwE71SYAPY2H}YCeeh8HElw*Y6sMhk%1-ywe>vOc3$1Li~`)a zjX8hiyc98+q=43D76&Xa6&W2sH%#@m2wB7$NpAZh!0pn7?@yjjb92FHn7jbcrYw*kbieBA{c+y*w8uOS)~l#cG%)Ov_C7 zn66~mwsK2(&mtt!mUJD|cB~W>-kY|CVx@%A^aPxoOSp_Kps9Q6n%(P``M0B1*ZSR2PrS2Ch;L4L_R4DLXTi3}HMBOn2YH>tyx=hGX zlwSKor~3#**|6eN%5C}2kl$VC1VWAX$XrvNMJZHjZUXZ$9VgD_H5kN~nD3nO*^MMJ zeTFdbo_-lkEvKG|dj))^AJZ&O4YVu-s8BPpVqa1BZrp}W!RF%DlL*@)^Ihi6JuNa- z?y)!vjw!|+z|o~NEp@qcpSpkhy4DE>bd$%sKfrw*?D*MxRe+Kk0-MAkFDbaHGRqhz zS&o(#hd7RgO>UX_O=cBOaAYtww7lBE6>SPzT6u?SokXpt4q6rh)v|q6UG2ojRqp|c zQLSshPYiG!=6_*+idh`=LevFK>k90sA>V~TfL60bkaU=qMc2`pX6iWoj-a|vc5;yH z1a{aMUBl|VCt%6k13GHp`^uTi6BSs7b!->wpNDcqb&`9|^1IBxKJm$%LTFvUWc6EG z2`#u-(r5O#+bH79KFdY`TLreO}$S z^a7U{!ihVW^H*@<(?3~=DE>Y3*O)hUH%4)!L~NMH6RAKT0(Wvb_^i&Q7(rxkaWi3A7TlZ* z+jZ6WyT?6Jbm!=|+jQb!(42qD{2wD*$T9TP>7G(mD=5e!r6|3tv@=ptH=YR4c5jkw zMy$z(01M7d%ykw-F>sR(ti)H_bO!MT^BbJSixg2I13-iug<%hf<2XY0O}0)D5%^malf-D-Hqzkk4NjBFu? zS*sd6p@rtq(QGW}^9W${iujq9>Rs`~fwnsW-NwWGEww%6xQb`=HMm+t7|#MWZL!^K zZYEJ&(DW31nMfFf$_+%sI3X04ZNaomxP=^ILKcLC&hr&~A%Q*)bh0xh-OF|zg6z<} zOsM&@uM@dg)<63SIY+P6-gyc#S6yFD;`rb3?)xJoowzli-VcVagVeu-O^6!RC+ZDYk`ABLRQmE_;gsU&)uHHI9H%a$Y#p_wT^-N z+mUhvIs8$FaJAhEKY6`Ux>?NUu(ee~saWWNAlGKSseTuW#nHgljotm6s%j4%YUkm# zJ>}>Ena(x)K|mE5C>Qgn2MO+Pcv`^YI4!|zrh|?>4L{N0C5CdYC(XSE#km75i=6A= zqt8EwT5S{CTkAY@eWd;K=xzmZ@*As-Q2XF?8Ec!{Xtg`Y=bWDK1&Bti(Sr>mgzbq7 zk`sD_tkX#ymoC!ge)z0NGm{fAP2RTxyu9q)j$%0Eur+!o({cIgW$1A#+w%Ze7Nb?? z8HQ9$!_eV4E^N!7W`M+UP^l2Mt!-54V&bBDx1vi3Y>h^+BT%d*eyzMfl0%R<3cC}LuAh9VeQwR?g2S#hkUpJ0=&X1g|K z=cW}*%}xjF1a7QB(Fp0!hHnvdZ{go@1P%0G=@wqIQ z28M|RE&bft5;@pEKksZL~)U2w&CyYGv3(}pzuDmG0T8jeW zgXzgh9=fZ<6-6OxjV9K&s%W-5&~#miqF${jVUA!PV-HzF(D4ulfdGW1wRKdRZCt05 zRmvs87x&%`ViuYpkv))wzn}ThlaB2;F6J*^SA{f59*=b%<3fOzg>AbqP3xr2_6+kM zWH+Lk&31&qkC3OUz3-Xpn3|kWZE+mK^L=b=)v!T_i$r)-TD@9@M}cbk`Grk{9{K^( zhaZMmSYAV;)xpghSGoR*T6*iq?=D4@x z#Bu&t&=7Y@oQ7{$Q{GG(-s~U^YW4dq+(!lsj%R$4Io$2re&p&U&@M3T!FQ7D#qNJkd< zEb|LYCwm~K)D9DD(ADI~MP!DqV}5Q1w{G3Ul`EIvIF1rTht+?xT2t9?{bm-DmEUc`lb%~SBOiwA--Xnf~B97MKJ_#({c#ioiM;Y6)T@*_dOwU|W zkX@uWKMFWPhz{Ib0X7e=@8Ay;zsY=||AELZj1#Oh1+=uUnD-%p6Tq%ty^Pz>-NgLt z3@p=9AT|iu24NGSZf$NMq|==X*a(@<^f>?Jm31twZm4zMxON4X=4TXOyCIYP(fFw4 zb5D}TpfavAKYiGtrQbXYCVaHYr zEgxadFxL+n+jaBY!;)IdMT`pyT3R8?6H_RZ%2;20!~={D`sCM{A0O0UQ0UuUjA|!F zzGNcqb4eK|>H;@8Q9-Fx#OB5p9bpa4Rtp`1_K5Ix2;QYjbA;c9VdzW)nrU{0nJ8C~ zYpP}W!xoOq7DT>}Mzf7(vxQo%fjY0YZDD$90u$vD-P?u1zR(43I276rK>F`VGMbGh z?%i8Jt=?2~xXk%pyE3olC@wxMB97G{X!44&)3|?``2psi5BpZv4b05Z#S9CkWsRg@ zJc)5(K~sw}EehIH2k3Reox<9?55LKL-=IeM%#RYR)737Q25(sgoIp7@KZ7y>SX2=Glj>Tv(`0y7O1y@<*bjP8_m-aawU*aS_k+u+9R}AZ+54 zGt*PJdi9cW(t}(^_NEyqujME^_V^ak;x!Po>}+h?RqMH^kV#x<&?MvlXJ#&AYipI_ z3J?VTpx31G{#vTW0ev9#nDtgnktbp_7*^m_wT3!HEY75} zgIGkx6j6(qy#+=LO!QJyH8PjexTYc!jd^`R>`A?AXD&iD^1dF)18I}-!ZflLg_;suifroZEcf6 zHj&S{>NVwD(l^~pTsJKnn(BX|QcPW~53-v#uPJAZ4uC8xWFB8@hRLux^-1P4=mSmG zUn)He_iKb~+lw)gqoc%!8&kwB zPBb$;sa%fsgthfe_`a_Mx8wajm*|_{p+ep_49T>JNZ(aDUD6#x+NHplrqTOG=2I#b zV6hNMyW={zdSxCiuQKn0$4s~3Q9VM-PYC_M*90;tVn5@4gyLYuQUx~8;%R|Q;;8{m z!m?cjo7ZXgKmG{wGY5Su8VaeZ?Kb~Z()+{8L`0v0?qF_i2Dw}g9j~LDL|j8e9fV=} zTV?uw>TnVIy&?rrpxHTwyq^hIE;=n(01~&;37B3ftDmOtLX&tg)-Jw z77+w~g~Iwgn@R_LOHCoBHr84Z{D`8We4<0R+O7$(>Wk1U!bSs4M3@2y!D8pqzx)=V zhh6AG0vL8-lxqfO980ERRS@-qWSQM(CM^Dz=c&_a3M9G8{rv0{a;~j_&S2f`vcp2w z(GC;5{K!LO=S<_O-ae1%x*;eL?0++y;0VjP5NP5?e#K|;G z?}43k$5wJr9>bJ#Y*^e2>F21zmubZu;He33Ah_Hw=>0;>pb^A)ebvWo&R`Wknybk;0?~e>WuhM>e)--| zqSlpD$$bV-|M%i{2Z17vDo{p;bg=#~`Q3wBh*!A}TDQLg1~kIJ{|epgbDZ;^@yQRE zzhJ({^zjtL(+1i+^Zm?^@bo{e>*jAD@eLdjGJ*2K%zXri z!vdbgPM~lkN6jMUhqh(Gb#3+gs9_THsu$yDk2>%o_GKKr260%=>lk$4_p#7?g^#|- ze3|)wm_K5^!d$@xj&lmy|KDDjK3P?rYy8>sKBp&TXrLJyjHO022qGHA3|9PLVwtk6 zN>x&olu62b$-j~>e#zH-PgOLfMnb%Ly;`8)m9ZNcMDQ|n1Kl*x&FQn}`@Cyy2BilM zea_z99AEuGbGm!4wf1^{@6%ANfD#K&k&Wa5vM$R~Z??%lRY_kZX@)~10akQbSi)qB zZ?j=V6q`vTqQ!B720d#^$sQ_{%we)-4T{DYqt1Hpe1LOT6E$@1usX@JWGnd%86@wK z56NK?75`>hTX&miCUM9TvV}YYE!Y~;OFZ>cB1@7WO;a@5?b4bKZM#%Y*>EAY_WP;< zZ?|VHN@iJFw4zJIlJzSUUmd#<&*UwcJm^a2u&3G=(Vq}tLbGSB1v5=v3U^v9Gs*Nt+oK-gYuE|8P zZL5@*W>E4f)66ujhK7usHKLgVOz`uy1g_b1$!;#WyT#B$Q||OU*-rjN4nU_~y_6T& zCZfshN=mIIo5&Bz<76E%8*4ZqNn@mJwz;&7!>K+pnP6}v#Fmx5YREL3z1bzvjF$H5 zt(9_P4h66Ho{X7>W{k;mp5z&ijfSud{r(ClSw;G@kNlqe3R*Og?qhO@3>W$m=THkl zG)buqWHYo_4?)W{r|V9cXc?!pVK(IGH%d0Z9>kXyBlLCISl44SqnjxxpeGPz^^qSM+mo2fdWhpX^4*$pk6FhJt6Hg-ETA4PM?8t4}) zay>@wBP%gSxo)mBN%&_r=jT{#yjqlE;9P(uRTEX)WLnPrTxoU@Jd2Y;(m@7_$$eHU zzWO_zEq3z~ry>rHy+Z-U>IponG|9eQ{W&j?V`LZkZ)oX;%HG^mH6KKiJ$TS^Jx#Vk z3$~ox(~3Px<4K}5?Evh^vlB6njzrk7+*9&o)AX`@ZkZM_If7*fx4wC0D-KiCXQJJ1 ziDV|lI>G^R@={c0lFd||WFy%?ULi-xHu7%%^(1NDMbDwi5>3SFBCE+$S_ zt5pjdv_OlNG_A>{2V-96;n5H)yKVG#ScsG9Q^VvQY&L!n7Sp^2w^H#vwPu>lo@Sf@ z>OCDBjj(?>xPHcYT->qh9pQ2EC$fY5lk6lHNv+Hc7Acwt)JxWqE#yaJ6Ilk`@n%sQ zku*z^L?utN%Hj0C9HbaLAE0MV1rDE`PSevyE?P6!pRQ!6n6#u?@%4~NXBN%oIRXxe zFD?Yw$21H1^*l|p>B=W-$SU$O86f{5?~x;9sEkduTC{72UQeFDjhJ6i#$k2oM9Z?Y z$xnr9$geKNOtlCPEOC*>w>Gt`Z5Sp+v(+zUP0Q7(OP=p~4m{UUYfqo_fJMnJaaim- z8{o@}5r22VNp^F|;FkW|obxLAg!~uT4K3Z(qBheC(LC}nbXq;0e=RI6>QFP5p_!@a z?zGsaDh>7xhv@CF(BoN1rbrOO$e0`!ObRFI+Nx-~cEoC>LWwNB)-;mY6za@)jL*&l z7@CNg$Of#1E7?@lM_wT>l0ou0d7tbgr&_)ETt&;qRAQV zD#gB85(JxaUXr7e51^Ay&Y(4zI^%-`aeH<%=rX|-$#n~i#u zjk}`D#=3hQWN~`S%}K(TvIl;zRb4Hq?Nc(>;U2Pd%6(2Ufd_^I9J~;6D;YfNE>`T; zT9)$!`6Jm)-XNclArdrep+-dOBKJbe^)&ejSr09ijLZddLy~5uX{ttSL9ju3HAsMc zY~U`>z~YL9luexFw#nZn7j|q5VHmaKjQVT_suf?YmE07oa%P)JcCnt~^RsmvAB*&U z%ms6W&8{k0LspR&$O-Z`*+!0%5t7Vhf!Rb8iTcQcHNdup+CHVO3No-o-;i1JY8#-gU@J9JP+p$!GiwCV}^osApvYFg@nps>k;+c<+ zMA$PFU_4CWS>G8pO-X|+BQKK|$sqX%ZSl{bXKq$v0(G0^>@;9^Od6s3OTJb=y)i`lvA6);yaDc<3A>t(a zPO{rChdh?^YcfDSBL747kn!0bAfmlQ{!H#Cy`;13Q?yV&mgPJ{eoOX~ zcgc2gjwH~t?HeVcy-wDaz5AleWRhG<6Qcm*Y^GS6892f;nP9>_xu%LmuEkU{DO%FB zb>xQSJXPOU&(0WWUtf-~n~6F~*&JF{)PT9m%ZCo9?~&)pap;756FTuE<)UjpETZ+5 zz2h=UCz_!|D^6~xMn63sBREmRmOd9gWedX)%}TT^&EPsVI;%cn{`>H`0DFf+Oh&0n z*3zoD*IabTOYJ5b$)n^|vV&~PIZ0B^Sp;S8wD@9*QM58j(!^uKkJe&*bSl7!af1RH zu#6j>n0*`mAp_wC)7`j!R!@hII=|j^Y7)E71PJ1?C6o8v7D+0>br1Okd7b=)th)A% zwkzpV)3kW;B3oL@9vn9Q)iA|CWTC&}Vyz#kbThawQ<{?hWqAyk+^2kYbEUa-#*JP^ zlBTdN6Lq_agJ&XqH5w{`ZL{1Cms8l5lfUn_DU19ZI@SKxmZC{lYSGGVK!<&ovI|d4 zdWcOAeaSeI`Z#J~%q^zZ_ZP+qf-q82>5mLtzFI?_pD76q{WF&*t|Ce@jJu1_xx62X zy1P`urPD=VfvQ=S-EN{udE_k|s7yxp-;9@`MvfT;FE`4dJi+ro2*~ox9mBQL}M6B?umVpZYiye;s~B!!B3xi9ve4pLQhY(I$c(xY_hgV z(M+aonk1#|qojI_{H~2fgBGn^&)|6;#>PhR)<6D^fx$sIj*}078zrgq?ev{0j73bx zb`Vb1uz&CWV)5do=wH{5?ygSt{jy|}z1y~}-*x+yLtblJ(NtR+W~rX}OtPyJ6L{y% zH*nv|J~71MVc0WUU}Cd zTGqa%MQtgXl=QSr+N^}Tw;cyj6yd$?+wkem9dKMHm%e#r*)~P4V{l*}mMrbf+x5!cMDe8}4F(&aNg;CEB@J(J-P5N}WB=a0OqfJX`&O+b z=aVL{*8`k8H-aFDnlAOsm8tWYOtq|xsWv~#lN%l*)v|X|bm<9S#^q-i9T{cgM_9GG zA6KqiR(mj-Y`i>ESiNQ)svR8&g8;Q!4HqtqVEOW1m2Slx-B9Uj6e{<;tJ?nqQ)48v TQ%*nO00000NkvXXu0mjf_(V-w diff --git a/images/avatars/gallery/Flics/Flic_87.png b/images/avatars/gallery/Flics/Flic_87.png deleted file mode 100644 index 09596437d7585469c8ab18c41c7d959b43ba3b01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27500 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 Hu0mjfgm_5C diff --git a/images/avatars/gallery/Flics/Flic_88.png b/images/avatars/gallery/Flics/Flic_88.png deleted file mode 100644 index e0b62e0dc0f64932a0125ed45c77b0097a2eddd8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28368 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 diff --git a/images/avatars/gallery/Flics/Flic_89.png b/images/avatars/gallery/Flics/Flic_89.png deleted file mode 100644 index ebd3c1098d333d9d508ad13382b54a57cf5f233d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28675 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
D4tSVOaE@^(vr4HKk!QKcl|v9XCt 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 R5@7%U002ovPDHLkV1njMN!0)V diff --git a/images/avatars/gallery/Flics/Flic_93.png b/images/avatars/gallery/Flics/Flic_93.png deleted file mode 100644 index 0f1fda2a1841a20d246d66b963deca7b336c6ad7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27376 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 diff --git a/images/avatars/gallery/Flics/Flic_95.png b/images/avatars/gallery/Flics/Flic_95.png deleted file mode 100644 index f6efce4cc42dc1475bb2ce9c735d7ac2023b078e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28121 zcmV*HKxn^-P)ENkluDjJ>Ly-Y!4t+s->V5v{b2L zPzqYAR52(8Emf)*l!BHjRSZf&OO+}HrJ$us6@yaHQl*MPDQKxu#h?_lRHJz^w z58sUUuSNT~G5QOn+z5{M0J6OlLU$f6*j|*SpcJ(BOQP&=MZ1ZV-iCs|&nW$CfNUM? z#Lz!OC(zdl3RCV0Bpi}X9K!Jd1ltI1I7%US)3z6@Ta|*=K5ayDY&E`mfVA3XwD|^U zgLH`nu7y;A?lBxc2H?g4+X)>13dj4<9)v%F%eEJ=o0Njqv^X#Vcz7*uhPUDO!=~)r zZ?swuxYi_kosC(A|Lh&4)DHmL=f=v1ki-Lsw?(*u~(0NOjyK8bb$;2khRyn)~E;P^~%j;LgNu$`c8 zDU3Etti-YJqWPOUW;U@j`kx}>!Mr#d(`2F9NaIl>`VI*Zv{c%Ex9*j?~% z;`kEU18CpH$Pc1Djzu_UQt0MY3fg=UVigd&3q));%G(Y)?gd;MP+)z{y_V>fmCI?> z;IaU?qUVw4D=Sl+DwgTe)ob-WmVwtAt#_f_g$Z3id&GzUxDohQ@Tai0GO2_r1?@(y zfHwiAhfLXf03_Ung1QaAds^{wgZPq;r2D^q8$G<~PV$sOIO+hn`g5^yaaRtAfB)ne z`p;jE1Y;1Q!2uXEjQ_)EpFn#7lR1g@eY|iV+WqipxESB;lBuN(nh57_`pM81_%Y*q z50cThBgNLDaC+O(sWLhMZlJe^%Dx{YT&$E;Kyw83_v9M~Y;Fxl;O#*B3|@W~K7!wG z!0*6k;Sw)HtP@UvmLh09fNB7Ra1VChM~(0AG)e(92F~Q$-8rXMq3j_=!ZfobX`FWU z@4zdup6o5i>!&dBaX_~pzZtqc@F;v8_N*;Jj9Mz7aXPIvM&E@G{vays5zTOEJ%IC) zVvH0{GfpyJ=^)MUGj_$BpTYX_#>U=&`nD#!jZ{yqn3X|?4buo0^4q88H^Qh74 zTY&4Eq|`kq^dT$N%?ijODluqCH0f{+S{jQTanj}C_4o$s(f)wKWMkOg#rhnAKf<*$ z-L^2@44S|Pd)gEWKO&u5Zw;<535iw)Xuc*lE4!K7KktV7FwinQirJ4zY%pM~SR zN?nw2-3;0e_$5;+trrs0bR65`0r{akr4XQ!i5=U)D0-)VWuDsRB2WYlOlQ3aHgo{m4h&!=Re~L59Z4aqc z>PFBwrGE$he((#4VZ3s3k^{pi1AN6B0HvheAP40rWu-2kgnt*7wuhC1Hn+CJFTn%B zFOChR$f%^GnxUfSBhhr4XtN|-NkUdjatMANe!%v)TA^+OZ4JB|-t?s_UQ$3~?lt*< zKUIx*(+Se-hTZ3G_(gcN?cp`6ZUQX>{~`Qab6)lRAldB4h#+4pDwaJCw^We?AY;!G zpV$RI4ZF6-*o?Xfw1?s6;bn7PHJXgi#cj8`nRBHLmHgx+Y$D`l=Gz2^;6H)4*&bpu z>K4#$fp^0j7QBm#TWjm7rZ9$5*-rzlqPf$oR$Jf~;8nJV+Nin#v@HA_{5ZTYK}sRj ze5?{t6g_59mpBRK2uTQr44Z72O0s2XC`I{Cd=>pxp-l z5FW1kNiJ+-JJpDMUm;vgXKl-^6n_WTZS?7_@Cy_|*AePO(E8w);QJeX1Ak->pmCza zEC$OMq9XeDwZc%ACTap{CS=3q#}9rFekxkh#H$lQ`)&C5;A~TGVaPbuEERg84A7J& z>BRpDz6UnP8ff>zFT-nE@iOE2_!obwIgX&S;}i7Okxyvi z`V_e`-p?S>Ka)0HDkEJ@?DKCj&1$tBegPheeG+v__TPNF?J+D?%i$lwyQpOwgbqGB zNjKJs2<+s=vQMWkUZSxtuF~>leYB##FUpxV_6sxAQ^hjv{rCjEee@VzD-?q9#5(_M zhJ@RaHRpkI0iTAC!13>zi&Uq8#$Y`I?}nGP?5)9WE=XiD@lOcFt+WAXSLo!0amu0i zhL;Zl1ljVG;cDa*Lw9uS{20Cd-XYop$R@8(#||0doJ20$%6{|k2Ka6GV!V@CygCK6 zt?*yLceM1a_}E<3!sS$xu}>-}Hu&0fkv{!=jINi8G(0p&efeC=`fvc45Ds0sa-Dv0 z_+xr~{~`Kp>=G%=o3F(_=ZxEqjcp}`8}KjSQtXpjggODV74V_acRyhSQB9=5#ES%XH|}S$cKf2lU>t`2!Fyv* zvS?!q(hU8#Sp34TQJ82W@lWilm2}W}0sjEr4d>g^LsZ8BXrko>uxM4%?c$ZIbZTro z_`PbVpYquZ={jKx0L9-aB-hVJj?({q@DYtoUbP1p&8)G=WW(L1_3DM!!Uy3|Ym=Nu zNe68^{5SBrw)Mb;he8&P#A-;ZlMT`hPm%iPm&=imZ5_ujg`4v);eze?)+))Mt%3gzU{qnsA*I%7lUIr)oNj5T}C<` zKR-Lnkkc(|^5pnBF|{2~AE-CkwEOIB}6? z3|pMN!d%#=;KQ)7y$neMtrva{{v$Z{XbDn{ixsfNEwjjko4h_vC&tF<%=iTD{rChO zKYtO=8VuWMx-#35W+Wv!xon(iR#6__0Plq_#NGL9B@MK@;UB^4tn|*sfZ`CD))$7U zmUE4Hw~qi9U%oo0T|86rJQ_o~6-#Aur9+ZmWfu4Rybh+z$ys~0NdS3%NMDhOf8&a@ z8eRs!2^VY)f@N(5=Fw&N6L_<&0T`u-yfTSgKHQP(gh^COvx1fhAmHB&lnkIk0tLr9 zx*ncuNUBvEfglYqv~WnlVH<%bDx>4pEFL}v&6TYgU}NH#=S@3na}cbgfp!l5NBBPY z4jTgyTvSMm*{N13v?>raDMS%CPNijlqSnFfDBIwC^%+qq?dYAN+30A2czD`Wq2nXo z1}ebm8u-FvQN3?w0yl0J0c1#Ai@HQ%J&oHO1S@HvvEG9J1O78OA9v?LsrZVF?~`=h zC~YEOY7!_&B$|Oqh)UUsDuAN)fOmHwC#t`rJ8N32V$k?6*bpdcBV+!?DAGE*Cs>gg z2o;6kRT42+B?o|E{S1EddRdSM{{()GT9*5bD~X_$;D3W3f*+5gLlgbu`ghqNC+im} z1C#=gsD_uI%y1BF)SN~UO`-zU3^88EJ6_R zoZ@5Y;Ov=ZdWH2z#ODe#u1bQWjWWO ztaNa$a+fnxe9b0L5&>K6SgXk!E`SI&nmHDe!ZhTZqw*9fAFw$tm1QQd=SaXP!i}wc z3o=0=WXEkUV?{{?jrBVG2>dLZY2}Og^ExO77c}JoSKgJB0bu+)fJ)4&vrYoUmc&d9 z&TLF5Fzu7nit?&V3UpS0WB7cAj+)!M=Fv|ntRLU@vUCDySK%MSJK-%Yc_Y56M0({U z;L1p(mm~?eoTxC&jT>{S7RXfK!^V~|3g9W~@k)R!gs#MPv(@`rpo8!$6sB5YB>Qi^ z-S!w3(igA?KL%%;d65J6X9W%QxYU<(DGSJ)N`j?|RlMR7;AN3^dBvX>9~r>4Kv&?u zgMVgwj7IBeO@528A zPdD;#UJA-(+!V5e%8(#e`+#klT;+!+>jRGC@D&Q{B$4VA&`R)6;5X`hP-soP8Kha` zJ7uaE#IR+NXxYLPnPQ1d*&~B*SKS@w|9(v7Yw*9qp6z+eC)f4>>d+|)Q|%k@#s%-h z$1!ZBNa7Q^PA2?NRw7MQn`Tfq)qe}#(b>ZH5nAE9mBa7lAO{?7B?&2sq*DtVPxuV{ z@9;mtW44FCkU9x8)~hhS0=*3Hfcs|Oz`Gy=7PQ)slmg#I1mHC!JS!Fh(yW39=Ha2y z5hM(M&G~s=wP0`2Sj=1_5E039yjy%_nm4iqEN(sPT6dm;sY$Qk8}fk)djoiaEoFgR z`4;Z`TX+wy6e;0q3bg-cuS|m^%g*xr-YswLOYK`%Rd-i!!^~(j8YIn(7E53W5XdYJ zVPPC$Y!lc&%pXVC5f1;-A1`4X#$iK%u|)(}w!lCD286IQvSu_Rjf7^?v}Wn)o?dI; za?iW^{m#wI%389ky1S~gtGd66Q}^b*=brPObKd8Bdk_NIpR&Eg_V?NTF54-drXGP6 zwNB?!1ySE!NRb$|$oS+z%M}Hbuq7CEgFv3M@&*Js^gRWSFL28{bq(NqF8lH7y3OBS z^S9I0ST*Kpm=<=zN%AucOZC}Fp@wNH5$;5xp_?=XqsyE+_s7`g_VP<_z3Z}HGN#t8 zAn-eb@74FsO^u37ckl$Vo7RM=h+YUi?|*2n{(0E3%bIyOBz!os+#GUJS9xInn%8Fu z)-Q1Le}dP-PFLH242$~8WlE=%}DEjkkU+4WVuziqilWKG=@`qMv znyyY$U=g4i^(yMs3To9N8np^Rt1CC^tiWxD+d;`2LenCLP4-o$qMA9isP zDIol}OI_=F1~*SfTT(DuF&i;ELFfoxBBS7o#S_Yfb)H8XIyoy|rPPF*7xOmTZ?gR! z+m(ITskd;r60+U~=6!JgInZu|30w>zZbaSJ&nXD|7GY zmC`y~LKgU5vqo#tK{wljxI3|J&sp$1*Hx}pT3<%3QLmVV;Xlz#`(N~{J3i7nN7Hus@-FTi&k4GwO+q(5$(xr#&#CJR7dQ9e`D)d5 z1z$Ka4cH@_K)hGu@PWpv$Af@5)W>^WIT*|>%h=d>gZHsJl}mfLaFaxL1#8#Gz0gP4 zIql9M?)au_*Uhe}-6@!w9IAFQgcjqN^-wdm9fnq%kGeV)VD6p60h+c|r1yB}`2w_f zoHzQ$!|od$>V_H0*@a=S`{2!CS_aq}HoOxkn!?sP2G}~3)_kUIQfc!m5!R+ByDvfO zO3U6IINU=~2zQu7>jX{gw)euwj^W-WS31<%g_;QH&8vDBU3J5tzzi6?%6nB5I6)8uy!TaJVZdu3^M=v< z>e9?Z`ZbA;o`pLXppKuLSD@W|4Yv^Crm3~&aW#Q!?!_(zK)zgJ^Y>W`Jq;7a;c~QF z3o2IAnkG!kf*G^f zECq+SPs^DikXld)D0&+htp#TbB6I>Cb}i+diqtybZilhcmo3F^Xg2J0-KImfy{-vc z^r{J}den4J^*fAO6Hd7Xt!KU;LFh*?%NV`_veiEt!}Gj0s5b>qrQga8F8?oLFOGJI z!VDL#^*V=x3_10;fy)YmCWW~#}mr6bb=MRmDaU# zKZvanZZ*=bA^U2WQqU|UQYi(O?|BNkMy;mYu2HQjV09^O2$wnLk*ofu9yEHL!$C(q zZs}{TW{vnfWIGW@zHa~q4_-hDA3$|iqP4#QojH3wJ?&g2!!_nw! zh8DoGbeQoZG#)A*I9Tr^)Zn^~ax>G^VQA`1YHWV5Q`_$_d!4{t2&s&cJOTWQ)%D0c<@9jr%Tc#-g{~(2nMz+z+5hh@*vaz@hKL zD=ovXmJkL$f*|O1ZueKT&Y--8z^NTkthUGf0Giay5;|&U=s7&-73fY0BLjH^VfX;J z0}gI+)Z7NV;tKp43thO~&JYzvzt{QhcifktNf`}%AK93WfB8$F#n1f6M-Y$Oa9r;J za0d{+AHXsVq-`C}`cmX%-J^aKK{I=uz+DIdtg#uijW~OH8c%=Z{dn}uaeVRrJcG9` z-$1?LK-U0+|8z~`hgz@KaA?EzJmfQJeD>2ng!1wNe)IEhz_#sPr*+rkegI8eyPs_v zEka&EA>@(?{M=9c5I*qOL->ntyo^72?j_uqTST>7g4bw34}BOikfAH^pgjPuTlhhM zpxOK&#EE00_=i9HDg4w=d>p^?`7fwvyM*5BH5^3T51O9`LI*Uu!=W*rQEM^H_xmZN4T7?z{uykF4r`_k!g<+`Ra$O&~t|6JQk;|ko zHq?)qsd0SrqwmK@-v1tGv6zBSzxj3vg%!4-*X!EvxF0}Evps}8RLanGVG^A8o*2b@ zkB`FfA3?F^V5wNf^3obET%E&PR|wzb>$pt#R#sNgs8!*6bUcD*+y~$(uzYbV78}z* zoB$2<jwuK_Ci5H;Z>Q29wQNyKeTjt*g(&VT0k1kRo~rhfMg z6p&0Oksy3J`zdeYcOjuvgYcPUn!Fgw+3vTvA3!^U$klE+!a%8|{af5FL)XgWGZ-mk zaPIgRe)y@!;4~bptQK*7ei?6Ex`yw+eF@jD&taWF3V05|t=1c=ss}+NU=gnpF-6yM z37M&dTkAe-&%a+FM&lV2ybS64E%S(GYZV5=5Vx|>pU+}^cmR_G>!FjAI8C^YjSeDT z$icEK?g<%c4;!jI3w`eeAWYVS5`#9W(*#99wKZ1{27X3(<|lokU>b2tKR0{I1n% zybmHM*jG1oWU~o=s9`{hP|-x3;*=a{AfJOBkMovpMn|g&;fR+hf3j{TS zwi&rjNcIv2U1(`;0iXY!FT%EB_{D$p^QutD{1Sbc6vl`8kxnvit0@n8Cwa?MQeC(< zP2Nc^gf(OV*~iG>2gWZ{V4)KMz*`pd+>5s#FCqxu^T^ ziXHqXQt8HXf$Im(p2lZB^ONW+uu33gf*LM;)|Dwt+hxL^BQC zxG|4k{k8v&XJ2@c1zo46g0{Pf=!GFI`nRVLCwl3X^LXw2o5wVwW;*A&YZ}D&%d4 zMqx-L|E=Ht0-pQkx0Pf>M*^FKsnId4+Z$WK_Uh|xDVFIHzyAk+N~b%8(Y`zyl?r?U zCZGv$Z2@Z$O#)usb>Y^kFzxsz=Q9c3rR%f!H~-<+@v)D67^fE(@hkuS*YN83H)wJO zboQ0`UwHAmxNz|@4b4~UYzWNCdBUie5NIhT;U;*rHqMJntLpo&Kld&C9NqcxCmutJ z1wc7m$2Xh}*=!0iI|fH!?7k=YTs9Mv{Et$Yj^p+^hXV`U&>u1lqdRCjRNl@I$YghZ z|BwC*fB2_gQr!(B0&G7*s=A1NBMiLw-B_TJD$l;! zKIAOWRcdwo@t41b_nw=<)c7d8(7&ZI#HkvNgFpK6|HD_F|F-&l;hlFQ04-||u-|&f zK1y3%FXDIp*B|25*WbYB{?$LjL+4H-bR+lDxK~3%gUDu5SYyAfQ;LhqKK}HNe`4(1 zsS_jdMEv{VKJ4ke66SCG+P~{{4hIr+GyO0B;;Y8z{_THi9_*Hr<-rd0_aT``$SH68 zUNa3`xNs5w^}qctu3ewq1etOX-&Z1)7Wfei;yyt~wN~%-2tus|WAhtrlY?x8#d%+Q z`y&4ME6?H|fA*(T-r+9JyXkw&#Q6)C6li4@hu98q?GyoX_X8ikAE^0SYt!{+zH;BZ zb_;Gf0&jnEoOU?M=5P{jz{xf4@(;^A{h#BHpX%M_@Oa;1hk-Nd12s&ppTby06L zDBw^%6F8+`>t3!hW=q&DQH$9B{F&$R^HaNB;P&#fyZ%r=D5iPKNR|Y3`YsHuvY7J4hI!}KA&}e z`qQ7p3*UYTm1{nvGGyZJp9n}Hh)Rs+?bui3orh)5}9qsSYUnFF$+I1GmRg5 z@(Dcs#CtG4JjgNi2n3EN0uIAKf#UGH)wOk8r5n1uZ@9kd=lNb6G#Pt|eJ);`#oY1= z)=FjdOklgQxP-5M^E-Ir(X+R-XpeJ`4GmywY#499dvya+VS>w#+cpMSTyoho#@X-K z=n%$7hA>Qb?=R#qz-Gr{D*tM|u3&34qI-E(;k8t*qC(v)EU)2>cP`<|>;l${1aLBg?$PhI4|CZMI6UMYLaG z_Bw$B4bNZu$W!n4p8CN1%rE`luk&D|<;tO3tlAUfBhUyHIysXPPlJ2?wexuO{F|y$ zrzwnwDUcue$OrL*?|BGAeFY^FsGs@wF}EBtEHdJLX4A1%>fsI+8Ft*OIl`!*@LDWa@Gc9*_uhI3FMt1S zymRF`7ME91CX9de%(M8|$3BGVW8(-}Tx8FVPfv30f+|3Q5x3D#@M*>J=rkLD zV5Qd*+OIg$poKwD&15s)&;RXDn=k(LD_C1E@*LGcBAJZi_{11Af3tu^aBGzco_+q? zunEvdKl(xZ@KZmC_dRkBgGNnn&Uw1!j#qvQ8((JCkgovV*~GFZsteGi|(XKD>xom)_VzkL2Jy7DqE zym*gM^IMSdoO1kfRPdxD+{LR1d z6u$UJf383iF{W7ckByCP2)GqI^eRPuY#@)%{qis3@kh=glTN}Xke=t?bTX~!E}hO6 zi^VWTH<3A4R@SzC6E@vR-nWn!@Fs=^acp=9nmniYG{b~p+prP|nDGQOLK6yTjXFHS z=s9)uJCFjvZzeeB6u%KC44dPNbMBOHx7@>yz1e)fQC#Fc2%>Rq+rpU>lXz%m8lU2R z&$GBB3w`i8uPy@zJ_hqyoI8C2FMQ|aO>@iMHt2%Q!9|y6*uKu@_gX~z5l0=g3I*b2 zGiiMKQ=hC>U_9YgYI0aBs(w5bG=*&K9nvZf=L>L zT)MGWuhFHT9IsoxqGy-RS0|*6hNGTKe!3oA<+o1vjM~Ptt{we#2zY@D%RIaa2!_wCU6C;-a!yKNlTc@nY3G6 zK&=jkDP<|p(2qdgArY7{8wQ(3;d)MEyHhtq;Hp;ZDrac|niLZW0V)D<12RKE;B(ol zTrPuDDoN;cwYHl@zv)?o-htele*V=xm5zUdH*fYYe6br)(>)kBWq zp;#EE22iX@hK$TG?3{Z#8TD8rE9aw zxf-nG;t-Z?tM8^q2hnHiXjCg|d^DY7w~(>cmX=T{SCGkNcNMm#=}M)_7dpURU0ug@ z3S075&zfK+vxKJ5k2kN(;?nE_O4S#9e#@yUIN+rU`3M^0KsWkd0 zkE1X?g|}Y#F3!)Fu)4g6w_bZmjW>1b38c#&_bZvPQ|%W6@IE5G`K@Jj3>tUQ1{{;;4fbuFc=T`rLKSQRFw8 zazAk+&vR9E?}RNGw_#J1*u~A{y@)!VFQC4*s)~g;n1Ci@$Kx@ISVyvN5dFuFBRenz zn`2*Q5h@l-1mC4=tnM#d+QNF*^kzX1D*N16M3kQV2D_aebxQbkMlMfPN5 zWQYZfd#ck>nS(f(#cxgSr2yBNBNwYc%Vttoq0{R8?Yb_CEGRzDM+zb$&>rr!fc7hn zI%qjxH)5}ze+%mrQcJuc|AKC!ZHhIP$trhq$`swT>!?(!NTm`;r&BNt9f^ED^2biF zUmmIi%XfS(qxT7bBV!buK{p#iNO9-$IoNhgRs00UNLUjnBrQ0_Rb^_1I1vR`tJSfv zu!wS5Tr)(5eJ3WykV+?2-g^m?ZWU)*b-JMG`E;CNc|j#wU?XrLcPW0vdE>`Ci5rP;J6h7#`xjCFx`_ zwI5*%uFl{$r%p_vuaL(QK^3fIo(5r)v6_}9+MHrbvz2=-q&p3>vvMA}&@{t!TFb`ohqdFuES zF1&jk@k{{^Kk>AJCr?RAY5V&Twf4Rp+8|`dUOb@%xz+F8iUOu5wL55 z`JX#=9H85UwF=M?z8}D(>nax`=<+qLAv@uASXNT#EaXNT;EB?&ep42M)qU z(N@-=+XGlQ5Z#NaZ&n(MO|c_`N! z$mKGa&Kd;sswxhWW0a1j3Q2n|`j6!4R?9GAu~y~SIrwgFaS^3*W#e4LujytTt}TGg zveoXcVh$!ub?`?tD6Cv8nY4z72HMqCj@5A~qH>i-s@)v4W{9(iIKm*j4C)m30i^!1^( zvdl3X8*_K$5cnPjQZWpshN8KeYm=M<$xR%vbIq+~Z*?sGb}AKEsWf4WcTbjc&(1HQ z$|5Lf$S?x!@L)euiFj*2#D=f$n;3c=X0H=C$e<7shGm)O&deajDl5W}s_uIp>h*>a z)gHzmXclx^v%!np#)D{z(>?sflsK#2Tah6VR^U zh=ktj1P(X?BM8ECr%oW1N;b8i!6j&wT5Zo#(kUK;06<(toQVLaY94MMVb?L$_fZp< zvQjBJ&H!7#ax=-#W2N`$W^L{eh(b&5JgH0Lvvzu7=!%(@C1|RuH^)5l0;~DVMO*DV#nr#q->#!liOmfdX-pJw=Cr1Rj2;Q(WQ_@-85>AstS@^9hT< zsM`WpoS>Pi|85a9-7J*6Iz=zS*7gCkCJ2&uJYP_bEJebjyZeOOcO&ScJ!(SJnwM88 z4ys@fRsl@br5vmY;9g^GWescV#dht`>0*7^46+;>p5NN+WwzD*S#juHh*T+`^YV~K-w+XHxM_g)$iKosA6Fz zl_N=!2)H)_o#)imy*$&JYm$N@S8*t9^O*H5O@S8X_3>pym|!DQVythz!lyOV9jD8-_Oo3sQs5Q1OB#510#d| zELTxsVlP%eTtRd_5~24xfdh`~Y*kVI;K&drMu#b$K%IBPaS#NzDVY5Z0V4?LB#qk_ zaWe!GkC2FHZ#BXuL@nrIsWeR6-T?OwbCYpo-*3zAHfk z1=>AwKzAPZ2WUL5d^Up<)02^qc$URt39ftR?r|@L2-ovGtS>F2US)m3?XRr`-JOEJ zDF{)iT2r8DS_s=T@%Tfh@Xvqg@8OX%GkmYN&O<r$010(Nrxm~u7&Y;B#6#_Hem5Eml!#g$bwYPFWoZYyM+ zIzh8yF}RL{wZ%o0mRAt^{vD0GkBe1%9tJ*=ahqpiB9}?4=Nj`iEwj~emTj%q+3sf? zb+ag=Q z6GVSs0i(l1O0WXida;bK2jbJ3E>;o<<`>YYR;8$S@2?v|(4NOP37RJTBhjK-EYjWX z0oa(1Q>(Mcd1|@hV1-;3x@jSnNJKeDA!p|HF46suqYj$Sc8$$tdB-5#?Ci{O6f$Wf zYzx(01is(V5_yd-wz{x@;_`|DPCf5tSA323*%uzjJi4ICI${kMdCiP49IAcOkB^)zx8A ztObH*^KgAXz})Nt{Ca(x==VEBMin|sg^se5xJ_1f+t9ZIA4X+BK)dA(`E4lQ6SyP= zozCagy}-7UU(JZ`I> zbMuR+(Al6L+%^cr4q>jWuPNcTLP0=>wM+xHNyv60No&fJZn!7!VgE1;R8!wdQw2st zBAY=XomPTxR4OR1ZO-RzM8Ns#+>0OxR9^X9j-bW179Rnu_yDy1ivQ1Edk4vNooC+9 zO`Ussa>5`Cav(ARf&@Vlph$u_NTjGNidsvSrTxdX>)oy0s;%9!UG{F-F8j0n$(AgM zG$m7{M3EFT4Uqr^fFu|Yh)4i~379<7)4BVm?>VQthXY^$Odf>qMLp=A+xMPx?m5rz zeWtF&p*72IJkM}AgitUj&DYh_gD8_m05~bdIc&>DyuY7GVh$#!Ft~@Xhe|^5v!kmQ zNK|oeE|Gwp%VKyM3xM&%OeK-->!tc&CgO0++~6&`ZXnDiWB7d1*U5nx((%Ok$DD++ zxEBdFHZi45*ec3Pp?ke&-)7_gPqfRjlGNW(&$5;Fg#&(+mz7F$i!|%#?3z5Y(b1`R z44Fi75E@azk`k0wRl#FuOe^c6!wAT7@wiO3GpdkU;`a>U5|EjMQa~oYr+T`P>F<>Q zI+h79A&XR2NXTu=LX6L35>o`5fXmK2nkN`WSxpTFnC6*O z3jJN(D0N);!{Pk%lU9mMv{WiB8;;-WLn%QUrqhcTNlfx$ro65O&}1pPb~=?v{;ID( zx-FB*{5j9@n>o`o+C`$-6W=@?(Y^bluyQ&1x9Hp=#eAXQARscK&Vo!C20CF(0c$oE zllM!|_^e4#tXzhZp{com&ll%>rQ%O2OC6^EmD)3j%b1qZ6?VESy&RhT$l+snYsYTqXFvZ{ zuj9J=J%*m91&!|R9wZY<1cQOR@h75a@>D#5biq^tj8G&3ALo#NYZ|k!I#3IN*{f{g400pHBB0 zCcW}qULSg?#qaYn(LiHI(Mu3#%&40X$XwS!oRFE>th{9Sd^B#EG_yMt5@B?viocv5 zQ#Berj(EmG&Q;*32CpeHX-}LwjZi3nnKNpKnUG^BA{|ob>>VJ`CGhyXGSNh8+PVQt z<5)gFj8ISluW`) zJ^lEXK7V>JeXr2cgZ{vDuVLzo0YLjC#o?yX8T52@(@={i1n4y3NGB393^bZJR9Z^& z`_6={SinLH`sa(^9 zz{WW;skBTrv38EwZJTELXHPs0lV|Xq$G#%d_(}y%H_q(zS4+is(w(ZNE={w`cC>fV zOwPCm6($y-*)+B=OrRtzQ{+NM6}D152C_8UySv`QzJo__@Cr zDKw|>j>Etv*6Rxfm~1tKtrv-b0r@_W%1S1iI{v+(5?o)-H04~b0kX8 zyWjr^_ulzA+`IKwn1u04D_y+!Rai-O`VL*!*i=nTnAFUf5KYG|nsJmR%wtEB@I?mb8*Qw%X-`~ro1RAn;yyk00w9GeLz z#uo;)EfbbJKV>it#7qP6IGUPU@z#!=2nK^#dCd}O;_Gi%kLs!lXkuXTp81F5JYr6j zGB{6JO*ORMKBSn;{!mB)INowOhiGad(Zs7~vSx2Kn@fxN(`*`j`wrq58_W-X`tv-M zS6JzWaaAT-&T*V}o~O-Et&1IeAf7;FMS0$UV=Tw9;n)tnqaqlIK=bHlK&FUfP&G{J_ngp3f@2f zLzXnAV(UO6ndEz$@*NDr=;Qn5l(SM#toKSRT^#P!SUli1$`*&--QA0RcJE4d`>_wG z5HzNYZOa4*M8Z&X1A`6~u+X&qi6nY@`mlTV`*`8yH*omKai*Ih)AT&+lw-J(f8`9r zJNaKPn6jb_uER7f{GN&V(cS~NX6Zt#U%e8&{ZSk}eiCi%9q8?i;{LmD!+-tH{}H9( zAX866s5F9P{{WNIVn-fdLlzK;v=-~oG&Q9{=}|Ssn$SbNgiBY)+o~?l66fAZS>pBk z2VxkYq0l(ay&!0QpBJI>3Z{?6F{2XV=9X5ppYB9U+iA46bx32ko^D4von>d&2Z6ZY z&_j}O=rz|>MwB)xVfK0q?;LN?aNTaxtO3yONug2opH#5z%s;Y%Wr|s$N zmY_)24rA((4A@Ipx4*L+r+fO*(b+|qI?&zIi-A}ii9$EG9b4Wm63j#6kE9$f#~J3j zfJDHijiOmNEhKZ^zP=3?Uw>!1)0e<%bin;rLl=Td1jvEgvfna)na zvh9JZ3bg57z%&)DtF+Oh33l?zR632Wt{&NKg=yWX7j#Na)eriyMpx`lErw(U^vU^?Wl7k*P6sIDr0!6b zXVh_Q7lzL_zJa;0Xmo&S-VT*}z;!1$Y*HS>RZ_ao>z(d3Ojjl8&C@jQY|FBgQ*Eb_ zNM{fU`bRyGFu%pLI(+mv`ud}UieM2uMbXB*I03!Ggf$Eg!r=f?nH&;K1&8sbNP`kw zo#~_*5@?6_7aN3_TP570#1(af1d8_%iMRXx5Akomd=B6L?ziCgGX3m)3Xip1jwt|+ z#S{4qQ`MMZs0my}r7KrYdY@fczIro1H_(*Ip(CH7y}c8W1#@}H8Qn-Uk^t=Z$z}*)@eq(Z4=8i{0zBf11pgK3&fQhkK4q9VuppMCyiELpq&cW?ci1aQ%p!?t7G@#U|hkFPqX$cH*nFEJamXydJ~VG#za;>cLMAVg9^1&_wqcjj?FX)1BRD zYH5SC(I`v6Dd6!iJ?748z%?}Znq^Bcf96b-1%nXTw6MM&>lQCUe>@J&Fi=ri!Y)ZD zvN^>2qUi4*fT_61aID@~4DH?B5?Ga>z5LoX96R2`bkqlv?m}e{%I=;%{Pf9RV(#2I zSh{FFFh-vUNX={(O-(Hv!j@}b_3?6iQcm>}Eqy$l>M}2fz7%B8dCd~&LJSi~JBlPnic zAQp@Bn#y%(@c2CNhk_`tuEf{xxeK$ZYw*dj<7htJjsd2g$vJF7ES?t)VkmgxyGp&p zG+a2p5nucA!!XoQCOz_?_4fCpv%9A_eham$@Df)|>C?S{X)Mv6_fbcwRl;b|ff#nZ z|1p-YS`K5RqtHC5bQUe_*x77uSkOcwISx}t(@7+@LVYmZhdjbGyT z;-UMtqPwRTAMV|c9FxK*04EIZ_xZ76=_0I}I~Vh+t5M7J@)?FSo~~+8wR{3;+7KAXfhGGE)fUfUO}2FlT9QN@?Z)md5@4ttsK{2nkGzsT1>_Ye*lYX zYH|DORR~1Fa7sgX?&hWzyt!>V z(wU5SpExgXqq?X2;HR=|+k(F0x|<5!OGV3x!|3T~WB2nEyU&$gDe7(NTU4D$oYuB> z?EU00Y8&dr4qfnJxkofPQNgAgufy!w4fwZbU%>OfeI4zcU5p)|x~dXi{QSLml&bRj zknZe7E}kSTj%;ef?Xr8JIY)TEQvA;y^1FbP$?7s8HQj)>EDV2b1@uS=vz9HutXU2C ze}D8OJ~@0873F34{C#)gYhV66X3VGuNgdV3Dr_WO-97l}lTTyMNBfF?YNg(s^i!SY zl1)(rn3DI%!fVz-`}4p5S1eh*0n650kJ5^2lvdWD>vRipIoW}xd(Bf(X=*98O#C6! zh@E)D`ZfGCq&bHzZlFWM%KN=u>E=izf;DTFW6rFZ7>Eua91h}-zVl5y`pEq#XNsv_ z9eOwbg^A%c@6jZ9Azxo845fg^Epi{;PCaJe;x66vMnjj#JWFhT(dx*qUB z^Lq003^`ZPeO<0KnNGv!^FjA`mBZJh~Pu{2#rE}KDTYt!Jh*MIc{+D;xFG(rAj zf($YJwVL`T>e~Fq*n};Nhwk5shaS2YWdzT)K5N1XJAQLZ8~*Gs{|@^4H`>>Y=YI0HNX7@`ps7R*sbn0Qs!d!6p1$%?e?fhpl1>z`8HRy7Z{Lis zGTrK`tMc8Q@0u}9{L_!0!mnOHO_9p7aq79n{T>4Z^{dmFmB;_mkHz$ zJS&x<2wo~HQ|aKbY0Y6i(2rcKZX}mYzd>eoN!=E8K zFi=b~QKC!zPwM|rx#>Rau~zCU{1GZ&D*9XlcE0s#&qy3*C!UWiO-5U73-g6V}%+nh@ z7KLML!n~AQ9+3yy+aJZVPwd2VFTWwdA6f!Ai}3F{d>DWB-~Jejmn_V8T0`S+1-RTo z6Bua;kZGnT0WT+m=nZ^_Go!__+`7?fw8i zdE#mGN2A=AGpyA`ZNp^>nb<$uGEr7pi;9|h>5Z+AJdRML^i1E&eI9aCAuiS8p{O%8xp!;+)Y)8bUa!%L1Osb!{k(yt;P<)S*G+k3uGwRscvrMxm zp79dDxX&+Sv<8AVZH&}f@(SkEpODjdM*OW_zFe6%0`^3*fPW^(j0_n+ezCFT-` z-r3WOcsh+W>sKQj3ds~4Ybk^&k;&qXH{QnngGXf}5pxL0#C)Rp2=I5wN6tyIp(XZVU?7f`_72p}s0Elhqb-Gp7*D3~@@w0qp*;733C zIgT7VA)CQjm8M=szL8xPCHBtcyNgh{@s0;k(=Zz=*5AzQ4wKCq)0p~r7bPb4czw9x zbN5MeG%i_zp7vI3d*SC8=IP_xCT*pr~<3v-7>|_`0X1qV1 zOrW{-G}f(OGv>u)xwkEC?F=aAg7>Maf*d>VdwcfbTVG8h;PZ_M?qYSG?m#Q&)y{?H zj6E^Az87D59XsCHjlFC{0y1&^tU5$}NR53#Q&_^Mi&m_|>KnF5-_BjU5{B11X26Oy zZqSO0vn*47udbVk>iSuzo-v!To8w{WII!m(y#MyAF!{IW6qj%vrG7`v9d2&~Y$GXQ zHPf`vM$nvWj)|j;zR~c0FAsRm%o*7A-iH_6f01g-mMlOx%rGA79&?>G0X=!D6@Af| zO!5nrc(3CpP7Q)L3}m8qP$zH+mOI$M6nK4plvmf`t}lKY;nH$M$|~i)iv1WbWTGYn zw4vn`4!NSbUOG-}{YJ*``djYA>%V>i2j1T?c#klLa-n3H`V!sZIqG4me5`{A!`XaC zkqU`q3MC~pzh#fw^Z}n2^XJVW;Q6EwDO&WhFo9q<|LG#&_hJ3IH827JxS7n@*3D#0 zWlbDBe2k6Lg2!Ww=w01Ha~Y;Oskf*EE}^n*zMI#F@~T>Hpm=W;cRl)TRMgCX&mR=K zI~W`jRTBXkM3vtt3 z?5Bl2Qu*$pK1;cYtw{rI*vSagJzxF~zp*=ODvlla2*>vC!6zT?LOj|lJBy}G>5_)4 z81)-!)8PIT4LgcvAR0$3o_(WKOdk}Y3@-jMCJV=UD{5!kLZ5I(2>dJ@ZozO;`tX} z#h#D%Bc0B|Fp8|7l}^K?Rev;!UqAl}4j%p#_uhRQw%l|*f}s#x%gkr>dEmDBYVW-B zE`Ivt(>VI+Nv7w7*rJ8{9W`}sKC2uieOXm4Hf*^Y4RaUC6chflEo(|46E&^zAzoH! z$*Sw*fv1yk%v-uj{w5;)#b5jwJ)Lc^ZENru3Effzsa(z(rM$Lt|Flg$oaw~j%i>Y>_jaM{bPJyP;s2Ge3CI$$ z0hnf1ejmJd^49Z}fZzAmL7%T`(0ochX-86`iIhc3u=V!Mxc~0kQCC+3g=TOI-BeK( zn2w8WZ~Y!mJ^gDmooeMXt~APcy>1gAvF2F~_4x85590P)H$msPgLCtHJe|giFTRFf zJo7x$aA2a6Oc=i3cAP)q*MFXrgDK9#cPTaxjcX4C!&tfDW~{qus|2g8vIeTE$?wx$ zmlSBjfhRUHlTPt3mw&5x;TJzb)3HN@Er+(I;}SM?@_?)48vZum^L;54@aH@IC_ob> zU=umKeAyyA{LnpEyLJ`A97`mm$hYk~cH!^-{>SLb&~$h7fK$faAR7Ssz=+qmT}EL(k@1g*G^OSLXL(1sqa=v*fb@57OOdr*cr4A-2{ zL?~3*@#eOd-rD`a^**mxrje=@y8kHW5{3|sV#%TfShsd1_I$V(2M-^E#_=ZGB)Oc4 z8TB=||GqnM=+IH@`2D-``b0ox@x2nsqK3uAiOEONQrxD!Ar?6MeZARb3qX(=B4!hOG<)lmOk z+i|+byH+uN##YguG*CZhK5Aynkx+^Kvn+E;_G=Ww}g2dCx8#wzDg-;%bRvN;u{`25z*ICQ)TiB!7qGhqvb@~}-z zdS0?6_En@Z+{)-Wo7uZrMGm~kuFawCbt~{NTHf zVJ({vsmoutol3sw7j;e9!9U|88Cz_T*Xuz|O}%Vp;_oZ5w68t>z3E=Vq?X6)gU{#Z zVfvt|DovB2_ebRWxzzW0?DIn&1@%D{iU5kREnhGXD;CX{V6}F3BgRf|TebvF(^NUn zkQqedF3x$`04EkI-Y3OIl1!!umn|5e$Z*=~s5ozp~#B#SW>!&%+cZNvfjJx+CeFtEp?n7t;}m#?7Lu zgyB>gWZ8m7%$Zq-4Xc*n>6hNb2m23WAQnd^n?=A+xV>HhoWM(!(N>sH86oAf((adGH=QM0qp~u5F9ZhG{vJe8o!YQR-bPd%p3-HmIrwe;^25H?G(u zE7ldCXoJOr)C~{9B@yHZgK1_jlx$_xcc>f0A6^1BBc#$;`TK<>1hfXbaAQL~VY>!p zkrH(D^r9~slduUO#rT@0DTNvw{8EO^COD~d1__yB)?l-;c-^6Hzx5{k(RUw1O=Y=+ ztO$*1yJ+f)V<43yi;9442X%V5IYi=%BopHPO!q5KNnJglA#Vsp(P$=9`~kaQq+x0a z^(R!h_(N9}G=x?72-?uTD-7sRK_=MBCG)Xz@dA0hv$r47cpSN0PNo27rJ+&v8D*?;0QHXbwfN_t+XEnk4+$}fayWjpg=FgoCcgWuH#gNX~IN2FTJZ*~c z0=%50wiWu)V2OFc;Zj6OD=x*Yn6%QTdjV5lE=nThOtvya`@4~d51f62LETKvl7G<) zro&F}oPR_K6HT*hK_lkOsKa$Dm*F>Wyp0bI97ZgjByc9YUJra;FFb}JJGwCMbXO5D zk-!2nu}-l+Vr7s>GM>xeaTtS%l}`*p63syo=~S zj9#?|6V6ZIbbacNK%`G9otBW<1#slL`PooQz^-45TesYdQtP zpY@{vbq6mz$IrtRm9;Po&&W3M3aqOdG(}P2^9NyBCe)-ZI=R@7d#TXS`(*bQCQ?S` z6LE`3FqH;eGH(v%)YsvKAju>Xu!*(#JYLM1QHxtPtikOBY<7Ju z*)rfQD+g2!ZXxYP(poHw&^j{QhU~2y;`=;MUQxT7knO)(Arp1ggO)F)mg%;}@OU0q zQp&8ee--}7*kd2P2wYWpDZcUGU0AzpF@E*hTiE{oN9gH~()bo~G=G-qA%OFG@(DLy zV-^EgfF%G+GRXwkB1PxVnt@wySclEmt--AN8VR^aBrOnv=Jk(mZr*Cy&NY)$LI9p&S|*Yy zq%#?W0s$;vG!HkgUybY6EXSPsI*zX}jVzdyhso{<3ONB#km>6I#sb2F1`%Z9bMZsjt}sHr5gs)Wn7^7raqAAFGr6jl2S>`{=G zPqgCpo|$S{t|6C8a~Z)cT;oPwew5lqy+r+APKPfsbY?c6`zYnUpyeAHs<0qSmQ zAr&s(5bf_lJk~$#!@{?feg!ww8Sv?2@ZtFuMH6aFEb*B$P4q=$INH>L-5(#o2L}$L zskL3gpc6EaJSc?fAYg?H&QRbAFDt%=LIJE=ya0FJyaDT1EJa0G1S$cu2;k5ZR5T6# z@(LLKz!=_v^Ying6FvC&WS?B$IlYK;1;Y`PS5y!E)uh^}oz&BXPjLYD1fBUMRabhV ziBpYGE2u9}cTlsChi=g9W-fvt{yY=h;KsHjzxm;qm&;{)rQ#in^V;nc9myaIaA( zspKSV_mtO_2AVjuMrtE(Z0k7dYr#XFEs zvhc+o5+`d}CJ#Sz(fe!~BS-U34Qgjr5t@L{hoE1Wv~*f=~M!S$9J)z#d)qM=!?`_)T`8Xs$;VEdot>B2hC5d zMn1i6rIu2G(F|bQ7SrtFW_9Srj+BF%fC`O%a;M>CMe0sS(e&P62u2_@_9SD8T|3bk zLrYH*s&erLB$`8(P0evEa;^`TYQt4yL0hShsTYt>xs#ZlV;ECij-aVjklH|ff!a*X zqP$}n%wZx311lFXia62MxQhy(gE=MYc>FodHc=sruOG`2MiU)&q$ODF%eXi(;9z-$ z22Hs{PxU;dsv5i{gv{$5Gi0K~lgHa*XzodlILV6Tusb=nH4(4lr4~~2koU!F)NiTx zsJ2TDxJwx{AM#ymGj$iWjtWfd6auu7AG)xVNU>9K2Ng`UnPK%3JI)K25emTw2J;SJA*TmWyLi2c=#GVUIGArkRuy?`in_@Pi*KwF=_GG41V2m6}}SrOcY98}LRV&?;sl`)Qz z-}6b`u@H45buINUwVnDk^&XX+j^mnc(8T#4%6m#`&n_)MDy> zY8UkjY6lgitjU~wXiXPrUTQY-5&sDCokw(`$p@@Z!X~1#ic}lx^Eo!=BT*Y=UKL>v z$GgN}6K3`V0`P=Fg%!JFWffV=#^Kg}bjLGL#{rpO-4^@K2B+#%)}Rckf%-gkJGGno zCG|V%G?ks~1xz()VdT5Zt;lznm6U&q*DzSNV--5<*o-6m7R|UgO4wFbYM^f}DcBTE zgC`hvN1WfpzwwprjJ?5)vqU40PT}dmbd(5k4LsQaiJsksv~?ElwZ zng7Ohm2dpH=iEDEkK@>h?bwd9wb@8YAV5@Tg%A>`5CznNMBxXJ_z(Iw@aG_YAW$mN zgtQGsh!mQnfus$=@zywwJ^Q}g<@=m-XIf`*;^i*>cIL4jk8d(_&U?aj-c#Jk+iE9MZ)`Ado3}9B!_w?mijs zCHYbee5LIl)Bk`E+EnQy7phn+ni@|B;RE(MeUjc8!)2{cY(_hPMC(YwX0xGh=Lj2n=;Vk%pEP2D&0w0DsT72i zn~qimS-#T5t%W@5oE{>eH2X|(NB+|_Mt`6F7X54b_w*m>J9K3;3kCt&5Ph8fA^jSB zz>;y_)U%|fzC+NA0Q*NRrRMZ>LBZzXh20W65)s43bBRQvoo2?S8d^bCuG_dVo5gaW zrojzfVXPUrcF?Ec_w=vmx9IcqO?qV`3vC6oQTiM7S^7ux^Z0*qd#X&=bK$yf;3aof zn=83!kg!uDCUzwa-S3g`#sU;%(y}%TnXa9XWy%d)yPL+`a#=4CJZFYZ$Zefz4=X_* zq2Hiir!Ucep#MqFV;x`ZW9E=bk^MO_=X{@J1x1T2IU&8PIEA&PB z0)3ly*ZR$ZcB7jpRbTn-KXEqah`R*DZ5N(bSG(q;O$ z^cDKSqo7UDU#DNCe?ae}W!xtSUY?%%Q9#y_>ff5};YP+r%au4hEMXBgH$d2QnwjRh z(#&8%#cB&TW;3{RzW|4Yh$t`Qiz~&{IQ=vF75Jc??|`N#{5E}#{vN$2?rOu9lnOLs zT}>I36l_fwxRqtH@%7j)iKGkyHbP=C&H7X8N;3sny41k+yJ^fWm-Xk39%MmFUFb0U zzWtKaHjN2(9!&Mx4@=@(%LNyy?p zY4@tDK@(zo9ADM)$tO4Q{=1iu$z%zI@RP@QassZk#_F(A&n2ec`M2Ii-IX}=;x{#j z4@25hRN5Y$7K1csQase0aY&`=!u%ZGxp)Ejd>)B}71-LQDbc9c@Yl=lVsLN}Upn~$ z+{Y5Jrzj-iE+9@xX~ud5f{>-tE4cXfpRsiRzJ@LgkaL*~F8$>KW@l%Z;%d0WJYBj_ zT@9MiZn`)oylVJTv4BfVvYETn`Z-LX7Z(?GYCc$63U#lZo~*9DafOx?l1&%=bXRb@ zu7_(Meu$56{zpHDnKEi^m25N9|HJ#2-$SKR>A@DUy85=&qz|*f*OE%mLa~T?qs4}o zk?d)-_s!??NUvnjYT2=zy<642pt0!;L%@i9vKuIs%E)H(n4Fx#_~c#*LARaWDI-8 zCv?0O3Pt2{1^&AlIFVjKSE}nl6GBF|SCeq1(;5A$o;}ya1XFGA)c#OGQ)`>1g{l1q zkV*~cXXRWjk9@wM!o3Gu$m(j))M%FxfTp0bZJUr~nP_$WtfT?3EF3+40{u)km*9mV z&vP*}G>l0?Ed;-E?yG80`zhE;rLw+@p2AaCgQgQrD$v496SarqxX5I3s8p(-LDrE< zwUN;=>_2cQl>HUV!Vs9)JB6X)T@S&$dH|HmmB(u9DL8dCXiAcxh1Fo4)X3-aC>Be) z>7OLiG;#RIF$@mwgzGqg)}Z$6PYqyd-$8xWM{7_uwpy)r+SYoog(T6aBAplMdER*}u-;4r10*1QTdDNP(CX!jQ831&v8&sL?@ zO;`!+W13lsB zaZJfF*Zhs=;(Z<8=L%K)4S&XU#oyqbltjt9gm%)p@i%Ty>iD^y(hlk;^orph=5g?Iemm|+JbZj-+Mk>dwB^QQPTnzdWS+z_bHneMaf{@Y zWL~)BekI?<^`lQ*9rq)xCw-ri&(!4iVxm4Wb8hZ&T}j{5`A$C;z8Ak!EZW{pO_5`} z1G#ct2+Bdrm8%WPLCck^4f1SvAXm+DlTzC5NUp^z2d#6&YqgfN-i%VfFT?M{f$fgv zT39(~*_H>SR-pWd)_RbXx>G5&3BLsi@fyni2XBQB!Y3$)F0;x(%cfS7R#%dwjU?r5 zTB<=L*&5iNcth)tXr=B3aEIYHaOVYh2fT-3@N(!fq#U&DXcd6j0H`*CqD>^#bx5(R z0F*P&Hy)l}&elZt;QNE{TciM-*017vC*JuGuGk*jg{~Yldt!i=!#4tojXH`pkx~rS zS^!q6tHwC>*5K;%fNTiYdkt)Yw&C7Zcpv4^Sy2vJ`y}w+B~slW;(Aj04jqMeXr(?1 zz*gXSxv6bwy&C0els5ym2egWgpnMH}0ry{m--iP@vOO^uf^yJWuQF-s2V5V+roRck zQ&)nk0T-uPsSWMBX!Bx}7o)re<^Avxa-5wge+|D39{_;EcpliEtfi_PwAP3Lx&#|{ zJre6yl8Te-I>6P7`$#oTH!I?{xevYQ%T=1_UH~>^l1{1TasM@VKYR?X*q+3tq#U$n zNPrt53P`Or__dy-yqT2Vq(e1`4ZO;B_vVlT7jPI{&c;D-AI5MPN5FR6-v$U@Mfom# zm~!YERt{QY;`v((sBY9Mx zF?1oUZFja4l!Lag7@i_F96-{80O~euy3JavE0AOt;hA4+g<3ajZ#Ev9LM&?hm!Q*^ zpx=Y|;LD`w5SreFuYZmEui)N(yfY3*O&ZveQw~~Hnc(UL6049_p9EZY>L|KdE4dCE ztBf<;Z=`m|NrSI`;F`v2ZF14@a+J%_^=mZgdjZ)A0LV%As|30Oczy=1Sm|L#m4lWl zKG~PS16rvKNUhsZZbo?xHc(eH;)9c{t5~4T*Q}?$t}^&lb@fvzO{0~7WIf+cR3l8B zeR%vN{r=DpE^8j13wL8s-6$_d`9+jND7T_~S(Dg?avyw@a_DlUjX`r9LC@`chu%AMBt@^0 zV~WAM3?2It%KI=du5<^y9Ub0*#@<26;Dybe*G|xd3R(fa8oq(T=oWx=J-iN^q`%b- za|(?lY1B|6i4+Z8HyNB_qT!sLqk63eP!6E{Ba}m!-@O!rw*`J3-a{76M39l+ufcttxq!f=fRLBsWMs!>CkrcsAZ>S?KX?gtX^Hlx`GNy`Hu{7w9R z9^OVVbP-Qa%X?!D;cy_WJ)EP4;c8=$@2f)#dl7)G{d z$d-7{S7H9ygJAqV{64OQ;H3Kv{33i19)=q~jWVRA37XbElInBtgIeiZ0oQ8WE06`a zW@;kQgzcVK7q3OXvDWKQ-U}bc;rI&5mvADzh&kGg>r=Kn+6;NvjJEsG3f-=Q;Gf8G zH<0Vv?#nbO%y$q;+ug{T7`h_72GCsw->0=cDhmEjaql1D6Sh0pi~%k+t$`mSDL3dS zvfYPDLUHjmwNFK)m&^lOj?;&$ufaFj?oy*#N}%yrJ_COfE|b7EmQf6w$jX)$;9eWhBCRsiuZ+n- z-un|F_HpeW&KtxR!}-7@{Qh!c&S0U541(HJxd&?qNumc+C)OVtfO1`pcqUcFi>pxq5WOfhiN z#U~`ET2_Sam_$=DPqdlBS_veXn4V^-u7)3nm)q`UJz5H&ZGazz2j+S~bD~LUyPpYX zNHp|EDrLJX*%O~Uo)?!@p2A;*?@z8fN}UecGWZer_IcmJrZ%u;MB_n3VZ@2nar>pU z;xzNz`QGTIIMr^j-PKyv$)IuHzX1OQ>@E0q7$Q!z?LHexCG$k9A_36IS#V2U3x5Y* zVY|PzsFOka7{#aCsztq>rkeE>5fn*9qd@@hEq5hLa>PPuHg(V51wR1WUd$yAS|7!b z-L&{mu&blc0B2LoxzviHNLuYj)+AhSF=>`+IsA2alkI*lR-FhMpJIOkKM1=ueThWV zQd&&FWJWl2+2*2(UdQ+8+->o4jXAPVH%y zY8m`(_!G9ru#`aKm3RQYyP+&Gg!yZ4%0z^)>SOf%Kl#R92XnDJv*KOW9>h7 zl3satA00b$&JOIp4>v7@R={QW1$eaWgIPdX2aQ+%7Wn({>ZaDLu&Du>aO{Qp$@9as zZ|FEx!jM+=FEh}!5;l`!u0v-=M(M@3chk?ey+QkjPGAn&4;deDPN~?;gN_$+Eqn}q zjm%M+9c3M~RTM*ZOVexS4UI+SQ`Lree>s4BEC^`-(UVA(^R#kVFJ08r-IDe=#Uu`w zw+|eqXI|MsTi)GIr-w&PKSaCJjHez+)`Gb&QG6gXXouQ6sQHy;&ungR8DAgZ4T2@8Oj#Yk@a1Z#K`fI#7|oaBg&ret+mF zjaEXs1h93Nignk?fN^4uj92K@-S5-WTXxXS{U1^gNdPA70G5sy^DPQ~eAu-{>){XJ zon-RUzOoA1TKIeL#+J5%h1U2dyp}HdqQ!880O5mUCrtwNb(d*HZ;wfyTGGvP9g<4X z?!(9E|F-X<-|TviP7jaROR%Xz^Cr!Z*ez56z5;#;9&SXl(E3;q`T=dj=E#sqI* zEV}Jfo0@J6|Iq1kw14OX?r2)o-$z9xz(TMws4gHII(^o_^^5Iq8rb+dhAb1pTsr`* z4F}sQxEp>R91Dj-Egojnc~gUg}4} z&4n6+REZ+mzUKq_->o}MIXqS&-_1aZO&uE!j5Zx=Jm@RoqwscE+Z=b+KwA%g4<2k= zi@XU($O>L z%r47JicLl?ImMzW+axqbms1SdA)7n;89y+ z&k|^V4F4V6YpVmo^W%ien7B&}RV4^%@6a(ieSVbsd%EcGsnhff0DJkJJv2OC$t+;$ zAe>Us#{6=FYv3V@lg)~Yfki z{bMJQUJ}ra7{FXS(@oix&8VeHy{?PX!f8p}i_miTuPFv?n~e@+1+>q=pQQNou_A6* zGiZfEQ%_wzQG0c)gx2Jcs=3~iXU?D=K?R3vQ)xqu_m>Zyq=!@c-VlI1pT702HV8iq z?}1OZyK(EIPxKY^E5F7$h+bqA4Jmq?%GrNis2m?`9@wL*jFR(@{y%NyzfpQ_!TCgpaRP3ZH>f zRG%-t;54&8#+~qw$wHd3vI3ffpN2mRf5lcOc+(IPjg!sAiJn5_V%Kp(8IX9}8JPHp zOd*Pu!j!@z_`+N}@jJ<8o4B9mp!GdCJ)U)v#M=Dk(hvyv7(jj+O=K`bDA^8R z8zWYg)TsrYtOHg{|Hb4%GJ&F)@lKL}u_B_%Fh!0_f#XpC;MfwsRq}m{q1yvL2_LaJ zg;@iw0{;}g4Zf$@mFwh>gXAg#t^%Mc`40IG(hH!aiKVre#nqC7rY+ z09gDlen;oM?eV+41M6(} zp_<-@*T6S$9~-HN*(qY}mK9y<=F1P92$q8g5PL-fEs|g)Km7!M~Vpm#>th3SB50wb?OesOv*KZG)^#1 zvX^ZSEmc-QW4#4G0iUk70tTw&3Mv)c9IlLu*T%sj^@gKVltH7_{TBWaJZgJfsj>_j z&;8TzGgK!duD~hjyX1(5Psm(tlBXo~1S6&-Ubotp?hyQM@P6B4nW`*<#ySiC3;b@a zA8MSAB}Y&Zpylc;6=g)_@e$Gik}U#odeP_XIQ(PymsIEB+$y=f1M6(}VIdu-_&~S= z_80SkR*DoBsM~j_T=Z@CKUW=+O4DeBIEy0E0FSVyjE+bXPE3nBhUzH%&+xy(r)>9s zraapnScF3OC-8FkA@~Yd%z6u_9s`z|7se5ud9k@io2atR)1OVQeR@w%JkwfLuhmpo zty0}^U#m;c^Su5x^{mh9uS@W^{JF&1N}jinw1YkihlJ}QCR|)PBUtDc@bC%vIe3gR zs7?TlbqxMK{9E`@_z&TW%##!_DPzE{^Rtv(K?#lO3ed9=EA*;>Neow%HF1 zIR0`!a8D@-tI6L<8AV~$e!8xY_MI6G$49us8;YOl*#mLo%{J>kzv((2Ie0c}^9zk{ zTs(8DqbBB=i{wxcb3vMZtEa5N#JkD-E#i3K5eZ(~nf*|PJYH|U*oO)Dk?1Nvg+`Ag z4Nw-6U&DqS#DqIDH!e@L!y9zo6Fo^0vuQX06@@{?fWYub0|tW= z89-zdgChAiAd(5#1|0J|evj*k!BVCkr4s=0&3v0c&(lYSWsV4qVVU!pQw82Bu;AOd zzH?k}cHkNAaVU6RQt!-O^MMh=Jpns@m&)B#EO(LT70BUl&G{IAI~RCj{?l<3einWb z>;F7}3}~K%Aq(mx&{A=_J*lE-8z%W7T>lw-$;_8bn28yCJAsNfNt!M}WsJthMreF= zn8ruWQy2zj@%gz)N&`*;%CrMh$7iojk}df=anjFN_!R27G~YHceVF4JC*?d}&YR|X zZoKF3=e&D*_P9O2K!sunuys?ZtJi>6Ds|(&Z-9>HTTcTwO|>ecdk6kc_`l%~s6*6= zpv9Y8%5AuM5B?qeP55TGn7(2b3bajZaD2mQ6jsJ*3{Z`Yo;P3x_#K56lTee;q)be1 zn)LT1D`FbFEmhrZhC_ z2VoY1*JEPrWAOjLPr$tPl{R(1De6qnSTQ{3aP>3zHTbLWU%>-d9Y=7aA(evhII%`Y z&e7=bS@SzWYAF>Zr>K~gIPKbe7m|2xMRG!MIx~1-0PuzxJcoR*Kt2+$tEZ33-7o+Y z08t2^KT+^r_=oUM;KR1ZQ`a1Y3tyqK?dR^bS&2Pq=p0>9q9@!lU0SS2l$gO<$DBNg$vQ)CZX2;6<@UZY}iKvR4O zB?x~Dx@yWQRMnya`M`3vSw|xlvRkbwn?JhGO+a{^y2?N38s)3P=ihWSax*Ze7VlyM z#v2b7Xd9HFCX>*nr$a&ZAdB7;t(vafxvK7KK4P2O?VgPQMi~j#7BadQZ7J*XE8C_d zHoiXm+WtdITxpwTan^3qJ_&gB6714->3*rlJ`FXVigLX_tA{Ra_yGwun}w1}Ne!s1 zN>zoT>zmJO ze7+y~lbi9lfomafEZNn#@I5)7QJ6#W>?cQ8tTBhK9a|iC4!aL!{q*{0xYec#VbWhs zDrLI^7X!6htPdyd1tc0o?8aCID==N!bBY7I$f4qwMKkLX1u!OjQ|zQBlM? zn7f>wol2oXy7LD#wr9&VxBGyAKJZLx<(}&Z)0eF?=t?E>3p6yGPh9mqW8WC z!klGaFpOv)5HV0q*tNxWh;HiN6*SQlyvIsd$7HA6rftC!v=2Ircw&7|AMntX#@e`Z z*oUBlb?k%%313L+r+8Ul$Pg#EtoJ$}(209Sr124EJ^yZv!OaKld-{$RcE zh@tGD47%Jv5#qJ3FGU%yPxO%zt(%^N>zC{+a=#`ebTljD&S8H-Q7v{gKiEy_U5ASg zU(+<`h6%%@7LUo_A!H$F8-Mpov(mpR!_bU$i=Lr~0ml?O7lQ~)bvLd)xb#6+?!hWH zTYSJo^*|E?p!J|0fH{O$41nwR`vU2>1T|ef*OB)_uHTzdNW9jcMWCq?e)yOSLxb)% zYU9pfUxMU*#dEyd5bDy#!|Fp730IY188FQl%tV|3W4H_gPVc+VP9cT_EOrOY$BjW~ zw$EtW9716$Lp-X`b~Umxm`8u9>+9}K8+aaE0?p}mVNr7(hv0L=JrbkAGfnfBrWyay z_r*v1w1Wp8y3*>5JBNJ2j+7u+O8e0rm}7$RLaV8l$A@r1nUMoc;x3ok0F{Xb$0 zM|$u>?1snfFb<<{-jS25;U04Eo*Jsj@QOCJ`mR=|W{*3yy^g~Knoxv* z=Fq|VK72EYKr_dk+o265Ajq6HodrQAh6-L469}3*?gS1X_!RF@^LrhN??AU2@}L!} zs?;;?91m5ffd|cQkdt*cLdMag=8ikZBhcf~fwnie~nGwwW(K)d^3YF4PVMjyN_VPoi^sqkVcbfLla0(hQ}APA1Y`){9yxx566f7Ab%p(B-yV`(~%v&Uv|c5w#hPc7oLAH9R$`2BCe zB>;C(q^RP-ANTt9It~kHTp?F>dWrRtPQ)=qVwuS$a6B8w(c{6M1KMaR|uGFb%MK$^{4oF3`e%=S3U8SPIz@*|a%oQ?Nn#tqL!VDfiwSbfJMa26>j(4Y0$MxkhuCJ`2O)l8BY;b2z;)g=2I-Pp~m`vMR9C z5l~@a@<*4h-KTC-tMxZ|g5ofNwo1*S7T@wM5=|zVkV50CzFqKRkE*pwRa_@96_vh? z>nNU_$CD4Apclew9xyPz2to50IFG;zo5P^dz2gyhT^p9`N;vu5X2&APd^GqzP7EY23OP|RXFmx8J5(%Fb7_>{Nn?cQ|KiO}tK5iYgv0WI@DFj z8bRXu0UGVDY$!z^Mj~f`GRXw8nG`u)Nwi<2dqo$aS0~Z_0Vc{$cfvi)|*(Z)(EHyZY-CuQm)GWdaI2lo^(~EQX$3OQ) zJS?Ht!lse8MS>j`Eny_W{CRM88Tp%TTDF5r*Kea#ZQxF+jN8;!$~COfeXY?#g<8k5 z`(yBRuxLoodz;5&UAu+%KDvQ#|M{Ev=fCt7{GBhoDAykZTbBTSlFcL~Y~kIuz#Tc- z1O!*g)vX?~Smve*Sel!OL^m8PI@@;f^_TtxFTL`5C`J+)i<-X`8{q5-x2Lwjr~DlY zSy6{8z3Y2eUaJxm6`Z6ziUb`ylt%CA6uTi=8K>YksMcBhiSWz-)JH54Ck-WxC_$-eBra7qB;F-ztwi{Xp;+? z?YQI4;h>^T!dfxN9Y)n(k3{&;$pz%HNep8VIu!SO^ZT#iYv1?|EUNA-I2Jfx3-k>G zz`|ugbJ30y6dFAfk?3P|&tmgPl&ww|HFCACZPUCV92_iu&X33V^B=vB7oR?l#hEF% zo+n$kYe#^GaEQKpVcGSW@Jy zE>%&b#x!y;7CDQQU56c^)eT`Q*Be-?HBo7_&}?_mq;L7XYs;&6_2PT@g`fW1CO2Sb ziq^DojUiB!-;b}{zz5fFg;0tREGR<0!)wjbI&Mi__|MLy}+kg6tIK4OzkDhM|8iV&cMe}VHCKVw$zUQ}TY-`+F z*^khF^EDuH9LcBIEC#ee@xG<;9=CBd3-mc;qEg&@4`e+^0jpuyb{7SAx-Jmn? zTgb_|bE%~4OT=b_Uo8QHEe)yIYB16JLFXl5?T9{=O_n}ZCQUA$n7xC8nS7gsz zv4Af=|0#Uo(@&9DQ}SDHgSfbY=SkEV5_5xGs$6T3LxlPf8`Q?ka1Jc|JP8#uQxaMR z%cXHG%Rx4o*!4m=-xAH2h@1G*^UqSgIXN~9Jx1Vgq3D6i^Yqf;oY{d5LqjqaLpl|w zF=FJ7?8M=2@VB2hxk#|Rg_mD_1Iy*Abir@_=?`)8*ew3;&wO5j9t^CJpQmYE$7ydb zy!#wd^hxr$CJg;3S2<@!%&gG-`j9mice!dhD^YC-JZT z(O2=z;}7GvUj9DbyLuD0^cl>K%(a1B?JTW^dRC$5}Z?1c-e8er{}hV!Nr4}{Ndxr@cRVVn;%?3 zt=YoMue^?*dhQ9FU7APWt?vtu5hK?;L;bw|!QioyxHRecTBgKul5l*VG>68;?YuPQ>vGU-%r(Qg!}!|NU!t`_fgMJ-&b(RsBKG6soMR zQx$HsI`~DZx_^yaY$~6XfCU=_*mDz)MAoq#R2ogJtW~jEsiIV=!S+b#^v1#5Tr z9Kv(pSe?jSwkF6TK-qbXyiP(5EBzppJ$LF+W7{@51UL7ykp0bRhGWn(hEP>Bc>Fth zztgqk3=B3q%f>>?>*gt+c=$9HXQ%MJ*MEeU|NIRqST}It$Cq&W*qoeuXdmet29N+mw4V}jIkx9nCNZr3opZph^qC0Nk>}4DV(2~@a20K_#EQ1pZv&dyq zNKhp|y*Q7UX~2(^$-=Wq0CUV`**{E7v|mb8VGG=}UJT6)e~`i9er7OVIdU zC1>DVI9!^OMcWfMJ0Ryh1mN(163BQeg9g2O;f=R(d$ojgGKpie)0i#hF+WqJf|5fv znUH%jY6#wkVm2e)?Gq;!@mt@11+TpMWBe2qqhdBa1R6Uk?{A*=x?@>XR>Fex*qM`f z;@lZ}H*{P2CPA{}cDpNu!%j9T_&u9kY_(d4VC_{nF^qadLi zdiyxFzfbKIYSnRzXRqQgfYzZ_!6wkwV_~|8`KdgHPMm&fs)7WGtkvqssyxahxQ`v= z&RPWyRLq__iCl3?K4THG`>d|6V1=4TV8={T3Y)9AL86~oI)xO0xOV+RbeeSuX5dE^ zp8m0;6muCEhK^h|g>*U*EhAh`E@w#iILB+ZR$vXdnHc!PMI&kpl_%1S-kMnZ~5rI1He<)Ec86upU%`>BQ^| zrb)~!@Qu&eNmvX*Y<4pibl0}AQm&#+f}Nh5$8;fwum0Ru@Zkp^;Dbw-sB-Ht2^I#7 ztN3)WfO97n;MYs=J1ufh8!_L*LLmb$9hVO45Ri@=I#iMb%3{|D6#ky|w=U%H$`BR` zS=3u?+*&S4@pEnrI_Iv@ciEW*OdUT1GntXkd;;2{+&x;e7CH6x8`tsO?|lbV0#4^K z$@LP2DU`@@dEP=cL;Hn|4kUvM#8x4q9M3Gy%l)uvZO=S*4ol>4T);*|&|lny#9;u9 z53Dxo;8?Ki7^fEJkW9p>s&5vHVK8VK0pLsbl4X{E(6=4S#xgmX?YNjJTa-KQ~Ch{0aD3Nau~7QabznIym7w#b6I!-|TeogO zr*D7u%U{B0pL-fXyN>p%fl{R=^C{-j68cfFabF-tGs64E`<$YE=Hl`EQ;#B(h!N=i zs3isC7R_GAVF9f&>h!q^^TD4zevB%$3eVek=mIJ^0*lqL*%*a%0u>4hmYf#b0^6W)o3mumB?=6lenZ%8Q2X%9ZWNHkMJGC)Mbuhl)@v} z;w0e3`Ds`kTe_GsFd93jaIG*GMWv}VeEHLlO`K)w$5zRZa)f?6{nBTG4DY;KGR17|O?$p4VH${V*KQ_he zLmURsxH@ijG!b^N6P;X`9r+=PKqXPKn=n`%Y8E$g4A1k(F$^qB7o}T8Cf665bVnti z_db5&JrOcs28o|I#%NuJp=k;d1e;^IQrN@qDnk&6z(Y0}NB;Ejp+UKjZ~;>3UAM)0 z2a+)p3o}z#C0DD~o8;~u(y4@WCU#ABQ!XT&qe*VKRkcec5;%8y2@g|Yn=cl~&9*cy zYoskcz;PHr;{z)r1a7F4Wp{F62D4OQeQ$ID<#*W8D$OQZRPh-)cELg}gCt!&*Ox?$ ztjv2P6&5n*uuk*V?@6J{*Mz*^=4A;Lw~b>+aKySh@r-c^TM;FOtr=tnD!aYex%(#$3utT9*jr+Q4>V1~>7_a8 zNE-#$3l`&4IYGt@}UES4p>}Y9PPm4g<5w;!X z-PmtX9&_YGxojG(jzxv1gIcqVYO{q?i}P}yc)n3%aGy!;_w*xYWl^&&2dbuSHQ$k= zJ%GUkF=!68RIif{I6)Qm3<+chqmbe`xi}{)yvo%+SQoIY{sigW3VKxZM5pxTiS8w6 zR1|jp9ukJ>sT^Xownn23$MyEi9=I0ihK4i8W@vm9O#-b_YoOh>urN1GdFoq(8k#85 zi3C{MBMG#=vwy2vTsdQktf%Q$4%60Ewssf_M#XF5kS*SnI{8X zBzNcL`$1H!#IDxL@;nT2SU|H7R>}EZ2OoH+(}kicNT(A!ie%JdjVgFf z3Oa@s!PcS*?|FlTSix4>?#;(g7z9>=#z-Vg=@cwnhNBk@3A^YnOsx+aM?4mTKBXfT z?}YB=xc5{Dc%9j73WlMF1t(gAN_)5)$OiYt_kENr4e5fZRD9$9PL!K*92U?#YOTQz z7ITNhoJhn!_Mkm+u>-|Oe92@Sjb02+L&n~o(KVBxHO`O109o@-2|_V z!Cx!aXzf$92S)D^Cs&;`*bWP59BS_eA2P#W*)COk^PUHmLZdO0i4d9~@Cjr=RiB*5 z58Wtqr9e7?X&TaP3`3>Q)czRUxBzr5dq}+ejSw5*xXWTdKpTdESgTDScO^)?4-B`e zhB>gia-YIi-Y2?h^qfKCocWuN!PJ()b9K88YPBZj=8A)c>}(+afsexi8m}`o*wN|Q zBx?U-yTz#BQ9|MBBu?&OM`A(s##aX33`ILQcUa{eDgv(T=ldQk4C}oX15Hzr%chY| zB}2ywCxyCxv)p{)HZ6*56d$8ZeqCnF%>8g8G@b1S@$DP0dMG^x=#dchB z4p&xh7I1jJDW@#94ufV zf^p|aL2hQdu&E6~uSDVuBz)s727BT1VZp#q9nsXum*M2EFjQxjn$CyHfLYQt!iOy2 zAqN>#a0;I5QGS6G-|#bXH0r+}^1Qb-iV>hG-oy$GFm+*#ghgrIF)qoz&13@3kuA!up7az*WSEO;Itc6i$Ni=)X9 zVX}J>?2Ml0%XKPyHRv9=b`XdmhtqYHn$|CTlNyHwv@DB_57~Cy$Q^nI8&=tIN4woc zt=^L0j|x>)cMS}~<$5m4?%jrX6OtWd}z7BeTnt+$WE0$Pd=lC-8E zn@J**PD5)<4%Nwp>Q0RK z4u-2u?!<8PM90^iKw|@FG};ojAYech+1DgzES0Jfpb%W84)y64UIRZxI*o%aVN1~aabIUgI(>9F(y}Ip<9+sj^p;7 ziGj!v4266ajkbl4ZY|T5oQ(dt1m!A0*XvWZa~^uOR;}aaN(o)tk#2bH_6k{pBrwExdunLbIDo>%?c{odTO_UdJNX0#a( z1jr5v8F{3U6tZLqq>v?B4vZcC$Ok^c2mS*70`rx?fWjEtGROjpKp_c%ffxzPNFL3! zW_qu^Dl7NQyK|oRW>#l)S9euqW!5^U`gCUA<$d4#-skt6v(aDE|B3FM#pJ#p?n@5O zb6NBj@}7fPCXhk!5}qF>o^9I*;{+?4I|`nISkrm1)9YcANtWy-CDSvG6?`40qokdt zXK=f&jhvSyWJ37P3258&_mKg2DP^AZ0!~@-BLA5F9R16uIdQ^b_k&;$G~Liq$h*+> ztk*5gRj^Z^!Pd?$Y|A7JE*!^J=LD8|yQ>n=b1WVqOfn8X!YIbpZjbpu77Q5@Zd)G+H%+FL{8U_qnX95k=$zieyG=3N(U;-J0Q_d(*2$bu3D3wZtErT{q z+GW=kp|9}krhTvNduMTr78=DLhQ;+>)rdV~JA^uMIT)13UYbyY#zq<@cIq6^4g zx;yx7Ph&!XBS{`ZC7=z{O(froJm#|C+k{OYq}EVF1d=#aNj6M7f$vE`jTI zQ>fO7C0r17u*u^iBF- z&_6$o343A}z^e5@p>3>bHPIJ=pq^k;=D5U@2$nQ7l z-^PSNlcE;L`o7O!S<)2pp86b3qI7WWT(zXmw>y2bIz4omZXr{LCkbGpz#4F;?hz>E zn|w%8R!aqrQH19Z94&ncvf-KpYF*cuW--?n@VeYI_xh*w59t3we+^lp1=F1Hyy+@~ z_N03B8-q`85(5el0#mcqLBF5XmBS?QJolORNbyS|1;fX)&K0q*$7fc#tGLEmMIhO(0;RNwOW3eiPFFr8|S~wW-W-&h;*6`}J4I z3SuIl2>@LIq}f)5FG(V4WwFT9XH;}{I6G&VCdx&V@VHF161HniSR5mRD}z|TU0j$! zxs+G%439rga@KY%=SYb)5|SU@xIY&yqQpMDcr1G}<%7qtEQ5weauchZ3bswj$4 zZ?ss*q53U=6$(dZcnFNndtHK2Bp7}nH>6P^A!ACKIkw4EIyxk}uA@{epu@EE{Q!O1 zwykOG=|lRRX%Kvoq@VQy&Y9NepU}xk2NFnHtqu!W8oH)_=b2_w%!eh;K?x)f2@G;? zI#RU)a~MWA=8$R}&$Cf1=GEA;);Nx*v8Mvr#xw@LNO~8v{R-&6q@$Az!T>_QA7HoM z+DjS3FjSgpW2R%0Bm^o{;|-w_SmHQ=&%`_~ydsrqr952MRt=%o^QW<=Kc%;(G4Msw zyP)ltB-xMY{z(Rr;@{nEA|L<)o#an0=fZVt93Ka{JB6<4C>C-|A!jhA2Fo(lxHdmA zX6nkCip3mKm10d0dWjWd9xj~_(nbbIRi@K`?Y zG1c^A7xFO8B*}`U0>Sdo?PYzywk=p@_6h|QU5%d}d;DS{k9NCqh;NT6%mb<}E2ByoyLwSd{V3T)R>(;Njlxki9374z8I-c_k4sW~A% zLqS=@5XK$Q5-9GYBEUO6>9FY@~V)>gN(4lp>UtBbO968HqpLNSMhr5Tlg?jWI_4P2@qlQo)b3eQ{X zG1Q@dI@rf6FH`4+%9f^>NC&$NlI@UAe4l=0+(BH&hHYEu_kHy#32{)JOHs#6q;00x z%EL`U(oqW#c(i?~qU}q)Cn0?djIQPp*xIcwYTFGg-88+#^p6Hvoz%t*A7EsW9TsIo;!uD9}^y@eQXj1SwCP^4Zuxt|3Mlr%5LL6m@CNh{fUM_<-OPowGul0ivelI{whz!G^bzV>Nx=lY+ z(9JJaaqY$;O69y7GmiHIC+m^qb!>Z*d-&FAysV2Lb2TZ!MvSebpkSNTJA1(CBZYCr zRHMH|f0-_hGk_GXN6`9y0LwI=Iu{X;2Y1)-v$r0gUTdk}Ns=niQu$=07=yG+2Jxa3 zAlI{y&w1**Pl$TmJ_151_sO^dnIw}*;Iu)CCTW7zN87mbvsGNbxq!vx8O+UB6pW+E z<#{d}gn`k9Fs6j!JIGS)N-7yJBrLrX%|f;s5s|8=9=ef*yV{I8nbQKi&)9~kB`^sh z_HMi~`XT)T`V-?0;J7x5g`6t>p_pT84>vY;aQDtCbi%P%t*FuzKpe|rYMHS4Y3Lb{ zJ;K`U`{??^WFf>b_X3odH?n!Jh;D( zpZl9H;s&9UgwzJH>2kfY!t~@XxktY-_`DLzb`S_)pqV&$C!SMpTDHRPx=(+Pew8+ld$Sa)6nv?eA0$gwy|VR< zdK=wdAJ<=8#NtAgP0dDcvxPWhL(?Ab>*x*-YhT6*!Uz$QP5^N%lOP-F+H`QwC@1oJ zro?0Ov(POak)vUw-Bj?dtZreZT0*5#+)LUCsZIao^k320OB=A$O>M=@?RXvm8A_hu zXVmBrMO z6mghD(D|}9+KBxqyHeW^%&1iI!BXD^JmtZ;C+``ili`}k&F7)#EOgf*^m;ymAVNrJ zr=V^6C({`CJV~m*&$Mc$E>_|a8vJ}#t2$Pvmb7~_T0oJhHm7&6ptlutk6-eoOSvD> zuVYNmo)Wi5(#ZEiBuNU_v0>X8Fm{PAN!QWa?jY<03Z7>r%rG4fm5jkL?UDm;HV@OY zknotz6zp~TOhTUH8f2a$k9oKf`VC~TT{>lNB&&3v_yO@94&uBW&tfYnKtH7V&Erla z1GX8Ht=PeC;=$D-1zLf?-8AZFy$_RCgZ>WvS$g)wqovu4%I7_mB!z+pogfU0+$z{G zYy&~dhhOhA-9lckjoz-{8AU?QkMbx(4X@B`lYr&mlwIhiq2|$fZK<3m;HH{8=Q)#v zOcWw(PQeu3$C*mDc{M4a&bpU03t*6eoMPfInd43<6E#u~^}!rFY-C$W9@mW~7K{$k zB+lOY#ZS3!Cu#DIX&5I4O?Ja|Z7eO$BIf=WEc7QY&f-Il!o8>hd;Q1I{1*FKcW+4-RO_DS zJbcd!*FR*LhIaDauQ5pol>UsZA53667TOGlA8$NV$s>@Nnyw%d=yZOMl4K7w`JT`* zT`c5qvv3Vo-ciRe(ZD)XEA*QeHAA;QHLVsV^wQmn1_Vbur2FdT_U)bB<~Nz9-KkA>ydB8aXIMzw zGNPqd_Re$?9)qp`JIzWvUC>5>(>b+QhW5fQ08xPS!4CnyL$@>7v~va=*VF6!*s9f0 z$b0;$se+!CbY171<2Rl#iq!h#?&+%&G0MvOSnDe-N6@ z`O=r3;W*PS?g>;ds32c@BL+BzPYoDN~wUG%ZqB=r!7e*$?cjkgGA3EH0PLV$*Hg7Fr6>ZL`e*km!Xxf zAuY~BW4h^^xAC~0pSq+|o5SSNnI8QhAZ)9Ou%(5`C!37r*fw7Iz)LDMB%N%+W|@SI z-wl1(cr>1m&}em3!Ef(0&}?_$2cf!O-@9(Il5yLeE*`CKAx;wY{9^qKK-)Iw(IsHJ zdPMl=eHwhhqD=ot7ZzJDXZ+~c!%x;?ed zVY=>pPFa#-0@k)Mi=OTwf&s~H?d+QIp*o+S4JF-4US44yey)PBatk-ZH5AegBPKpA z;4~(f^^gVI==ApHlmhcZ!uDWQ74z~Gk}XNnBP4ltUQ(`*_fQ~o*A$@XM9WT|En#{| za^8EihHlSSuf}z3EE4ik!JFu_AM~7Qsv#s&jl{*HcoC6iD!BA>4A@ZT8?>PaT%s9B z3={W_TMDul{rgD6t~#wvx0@!GVW-z-X1I6lNK{|{w3Sbz3iB{Hd}?xBCfZ) z>J`guk6~L?zn2tj*em+8*`>)yoZVI=w(aFloiWXZnfuV!{{f zu&XZ55H^BdYqj^o=7+dL*rX7aS$t=eY?IP({X6w0?ysz)&gUIAGTSoo5+NHtXER9N z+X&Lv3=OaIbU3Ls$o#J3AeSq^vh54KpBEN1C2qX@6$)iIj*EJI2T2@Ha)xW{(7(#^ zs>lz4%`#0aRx1j!T^8R^0=d9;@8Oy%zAV`;CT!9;BJSh*Rt*nVH_+{8O-!D}Gz`3O zZIRD6t0GU1agQ8B$LF;Kf6C7D#w6BY=myG_S=hD%$IYo!yU4oOpbccZ9&CcvYSt$W z+9&9bj2@7}vP=U@GZm>b>^8Gx6DimNCfkEm)c}^~FJ7|Adi#EW2dkR|ZASq&gv=mh zw{9%q`qI2QhW*d=Awu?P9(|kNgOjd9*L4(%<-z`4Y{=B}ob>`GqQMKFnOmAU=3@VHFd45>AXwUC~kGSc>Ft3xgzN=Ec5``QFWpA>!H-k5M_knh`SBWkkB*PK4%4(0V3q1T zEX%$S4eCmQrt1dg7p|)pRNvi3qrT1WV}*8={vy4UrW(TJ;4y}<&6msSw}OoYEA^4V z7UAxrb;LY&b9sJj*d$r}et=fHtH!NXim+{KBHdoVk#(+aY~#_|7W^Po$A;-5Yra9i zGRO{IzZ{XnT$;nLzeE2yy>gs&NE6BBi-c_M(xlj^E){4)$$Rp=JbK+Wg1{fAGrmH9 zZnTh|Jy%NDG{RO=m9|aTVuB%a>U6|peXzR0>k?J02Gij)zes+6huN{51EZG(a+hU~*Q(zjL(?(!>=l&`aBRCfL za%s+UP%7nBipjuDCfnB5E`5fx?7GVuhD0nQ;IfK9H+VAHT!Zy<_eHK$mLX}i`?NhGjU)O9$t z$cE=VCYz+1q>lh_lzWHD9$Q1R)5U|84Q%h$IZnElV#Bdyo!1xV@Zyc-ESbjxph|z4 z{sz5$&;^EJ(gvT$;iq+JlWZvctQT-952+h4Eel?*zyh_Ncj^1+FVXhs!5Bva?eV5+ zm?K2XvlZB;xmT=1;Oeao-n#n`8{0Jnjjn5lH2|e7Z8Ro;dF&LEL|xyi;iqrk$L7v1 z$HKlj6=eKenxDy%?1+%b6>)kXCci*`>fq-{P%6)0arp%W++~MMbR|HO7in1z78Y+P z*rd1*kkpx^*{vr}#Hpry^w~01iv=vslwlFJWTa@N@H^ce-oC$rJG7)+5QM7mbzMIc zy5ppbjMwu6+edoAW+7{xHcF=V$Q}lU6`J>Kt-e$WD|zefcu|1$yqu6Sm{g z&M{io#g}>33phZFKtmy`mNX1g?kc zTi9U26mlLaOhIwMbD6y60EqFseZuPBsW_YS-q94Du~Ulm;`&_oWqspER+c3V$^_Idi1Y0O#9=isq}H#%L^T5a^hP#qs8 zOAtm1h}~uf?&c1PyuQpdG))8Jf+k~kdwr~L)zD|6jm|fe0!qsudwBp^GC9aZH|Q^L zp8v(q9n-Q24K%NC(@AOb_chC=lz2un`U=Cp_Gr`23WAkbF z$GI)fCIu(!9|`Xb)6pD0;F=_v@Ao?Y+;zP#^XE6|Kcjz0wnw%Z88NI{~FJuVbrrM#yA%h?W-g~`nM z#TKEO%8z(e1m|AhYUa{83F{?v69K$8;4(I2IM zn|_VHAqRcGkAA;%*6YiXhjMKj3snn60=Ls_quK4U2_#2`EgOYNWtxP`L#2?1XIlhJ zS92tTc?`o)piR7MJZGU%93kL-+qR=|8Smqvm+8;Y|C9b2{e8NPjNMD8%M6;l_A>op z`giG1(sQ&SC#5d>y$<5&Y|`u?2@JB5yz46HD*c>Fwxi~ns&!uK5-!iNq4S5ZH3WGm z+qGes#_2v=k{}F&(L=I;Tl7u(Q}q8p2Aq6uS)rk>*baw_)_Cqgm98+rVZdeisC3lLg0o8JCMAWMf%r} zHN)@He@OoY{Ro!?xXT9GGBUuvLVp@rf*mM%(ely{lhjZ@(a?!?^b*H za!Z=&hCZ=1CY&!!js{yq&?MPN+OxJ=8se9by}R$xU#GuMzkShxyDXqBAnS%-raz7> z(GC$oOOFOxkZQOe*eDw@tTRZsNk|%t?bxtwdxC=k>)jN!z9jJTFBQn+I94{yL(8r} zf1dsr{R8?N^na#rA2Z+2jV?N975Z1`uhJi-7msuEQ4(#at4ob@x0C7mha zxDJclP|%%tJc88{YrnIDRY%TMD%F=(tE} zv||>o$mt1^v)-X2q?zM6O!1R91#R%(oo0fyPKt4c zjG1Ud&?X=m2J{g8|MtT^9tHB{W)ZS{SsZB^aN=dgQy+*KB=vp$ixa^ zdym^!zfYbM(~&%%>$ob>CLu|$?S6`Pnn0KwFU^LE;}{834HH_^h@>h1WBRl7_v!yg ze+TCTxbp;>PA|}(r@umfn4X!|WYSfS9cjowlN5UpT9~my%re=|D`=7$l4dx0n5py% z_~36hQq=tM(o8j_G(p5vbKp(uv0ohc6ZHR~zfOOP-Z{&jcpgBLHAsT}17r#Ii*#k$ zlcoeM9dp~IBXkoTcYOy%uLny@&n0Y*>%cILiHs$Xtaek}Yo)4O#{o@lk_IQBrRmgn z>;`?E{y6RnCo-Nu)eeE%^%Q-UsD7e1lp-F0rfK@LLq=9Qhpfh4MV4^?hW-w{ zLWk3wd{k!vnmqjbkVX4%(tj5jV5cepO>#&ZlQg+Y+Twkt+6-YU>Ist5eu!tSjU=cv zGftjn@|@C-?le=ZGto{4SvFP_M{55~Q^)j!ZSOI1^lQlKO%m=u(Ep8ohYqH_fYSy| z0Q(I6rNIN|PkDYN>85F#s7`$nNk48TI_?KH{)XGf)cf<%0wYT^$L8~C>RC@B*`uvq zik~&uNYaz0S*AD=(4NxC+YSP`Umtk=x@?Lp62U2jVG0ddzt?G^cUz4(}j}_ z`TyH1_un|KI*OmUGqVpniDM@?el#IX8l<9>HfljaP!Lc`qEZwB;!%)5@Du+Fe+EAQ z0wK{BA!thlN`-_%o=rm1#z{k=vG-wn-?KaSa=v%gsndqUk9oM+J<=x|uh)0(%zi)j zY&K@o1GqZ>p=jf7h*`h8GV9sJi9}Pb+Pq{WpbwW94eH%^B$J3_It;UXN)n%ZmK;HJ z@c)VYo}4D#xG$EZXtMTxasrWLkCPn`|A|6Z%jJ?pKn{`7 zgdf(LBLkzgG@3>%ruCO-XoZWEt;W{_l&zpNbjtT8VtKA-McZs#-qZre>|a%bu8yzG zRzI^X7Ma^mBAVCZg>$y-$ZMe;x{$X^hWpHZ2pwcn1OSZ)$bNq4gGx9C+GWj(* zOXfGaXdI%sh)#lM$+yW7Y*E49kJ<1b-YYBf_+HOLqgBMgTnE#+u6@X9w3~?L=Y0FR zk^5WO|2s8J93iTTJK`sCO7hEe-qyzPa&$`Eg#!xM!!E< zF-MUaTkT@Ih`M&MKNp~=bmFqPt_#oiHY}O^)!WMk=gJ!OE(Te$)sd$l!u^muLtZC; zAg_@Bu62=(h$hu~m>efxB~OrI)=y(SF(F6Z4r6kYB(ep@!L?4_N_Vi(#)KR8`!tz& zIS)#y_3xFBA>h_7FB)80)M)i6?NGA2Wr}={e3_ggFOiqYjr;xKdPK{UPmmYL^W*?N zVuG#2wpj|1kr%0M^*l72BRG)nV8-uqh)p80Nt-#2v#v%H$=a0ceA(d2l15JtC0j!# z$uaUdMB@F5yhz?9;obgVEux7`BG?J?9r7?D={~w~(wiiwPhBfqY!__1iEu@w5u5Jx z%Jp0;+Ikcg$!cBTTv=mo+3*00-Wz7k*+HHrPm&*zUm$8Y5w5-ZgZC0m1bY-wdx>C& zh@bVH#SvGzsmdmitM!b7xgdu+UmwW@nDBb`cbjcDk;}_@P)e<7F{gjll-mYp*ktcE zOxowqgO(BU6nUKdnEZykM6QySeBf@PNn3r2JV%a`$B4@MPU4KiV_P{2p)skqn`FN0 zqs3->n9Vlpci}l^Q|%`A&&GF1HJ)^L0PlZB*$E%jWW4Jm0&& zWE=(g$n~1R`HDuhgP~-}#3xUZC&)L+t0IyJCbjo{@(ekE2UIXgRALHBxiHTAEt7Uc zwk|hty^}|c?e+-UZI{=J_PDP5G4Oq#_oMFlIgw0r;j2pq7s?uq-cYg>BB%LdnI+Ck5XRBN^o^g@bb5EyOWTdudz;To+@fTczY z6Wd4e-J@SXb7T+RS`2YV;SG~&L^PB2Ceja^z;&%?(g0a!Wgj=@=J3YJzoF4+P%I$q zifC-7USNOLIz+P_*e^_^ldX$j_Wyh@wC~B!#{S=9(_LL?;7iAz$Jows=rGLsRtGj- z)*HwwN{MKSgSi!k&!AFS#Kku+;O(oItte63_WS2{4LMjTVQ1CvRzB&;;c@$uk%Xtt zy$Mwq#j{6`p;#P2IFv1u46bOl(X!q}lzP31n>TObo$GV_$${^0{%bM)rgV(P+0*~T z*w`38|MVB(dY)~-VbYDtdIMR62R&TdXxW-3*KamkC@qw6ff!XmZ{=il;qglfla(GVGmB2bD?{)oK+tuDu0ql4%-|w^pm+ zuYY+BSFc=&nrWs#Ez#lkJdf8a;q}*E!TkKK zp=c>*U`3NblaoIE>jGgI+7_$V8@5rmZQqWOkE+U`3O8R<25M$Q(4AEtEQmG;g^-#8iGq9q`T)D2-AFyOvWOb7T zL0~15*AEW0v{<27WUI|UB{1+JZ$4kZEZZ!f&%@|QEV=H|(y}FL*r9AmWne`UwUm-Z zQ?}ibiVUwbSh-w9tJS{iFw4NZ%ERR36pEvx@wXb+-^IrK*q*67?p5|8*Q!>lY`2=- z$1urcU_}$vlyVb2#bxa<)TmSzQLoo=?@JksjZa{Fd{?XkZzc9TOwT@qk&$g5k~lgD zLhiAOMx%*gsU;INu(Fw`(S)R;wZZc8GM1K>?<9hjNj z`+p@8*@B>lQmN8!-NYWrphkK8r%rU%JINxBL($x1M3dodHXF9hq($!EoKeH>-aSd- zM%aM0SlU+Bn3|f!j`YzV{Xm+xIc6tq-THgq&cV2-|;-o`5(W-^yS%F z%rkr)^^s@$XKAI)Go}x&+w`CGizlMU_9g5SNj*Z^ap~%-xNB1z*Jy4e^L+KETYZ@R z?KqNJ%+1v?B#-K3yr#(NOGNekk)0zmuIikOt2?=$TkhY?s~Y`X@Ej%2@LUuMqvM+k zlCBHLlxaRF11(dgHYfuvQ>Hd311(dgHYfuvQ>Hd311(dgHYfuvQ>Hd311(dgHYfuv zQ>He^cU?fHy2YELt~%2!QI=@4ORK@xPPF$>_U&esvP4V2x{+Ngwbl<(te(8EENLCww>j0N~n6N_|d;YBK=quKxZEj$cB19FQH`|H9pTPTjVpyyvh_vf_`9|46$(T>dKx?%G6|~kp0N@@h?j5A`P90SqCCzYA9(TyryuH+n%0O$47@!qc;2U(Tp1>l13d!{(&N;al ztj3e8KJohsc=sx_D*^uJ(OyT&9Yo7Xw;#8hL3;@O>IB*&INt}q2cL$O>q2LkQuoTpNL7*Ttq?b9Iq4 zssPJuA=))aEt_0XycOw%B-1%u_h!$IPQn9QwH6n%0NpbNMg~fz|jVz77|NsLAwp@dMvD<(e8O+uU)=` z7B1*Ocddbq!HUs$v0O1wPjz3h64Iwb!&BZ@L%hjw!f&KFz7OpSq{JDd+W`!0AI^`! zXW#+4#r3>b2AU9@S`PuL$8{WU!OD9?sqii=nx@SSgC(S(oty5X$L_rguTrg9f*^>w ziO_#7m>DuDB%S!be)_@N2LW8gYyu6iUBJsW856yT`TQ8~K7`}L@VoGbWTBhanvbCI z;#dVgiXC}7;Mxq|kA%Qh*H$y0eg{C{``rJCb2eE)Sq}cNA#meAN^~_aIvK zZ{P*zv{J{&0=J(mbeCH?_>^isfF|Jp3t$;igj4HjQZZV^skH*mwYmTXECgIP%Vm>h zCea*9OWlqd@|fF=XxYz_1?(jJ4*V9r1w(fYj;J;Ho+`~%&?Hv(0(|JjIDUe(dRkYa zCjr;Jh?Y)#)*Ll|H=j}(|H3Gq`zva4Er8eKd#p#h6OsNclKMD~{}=uV{1H3^kGL+h zRho;St=3BIz|!7MalAvt>VCjgz;$o*jy6Mw3mW*hE83LO38jed0;*F(FIP z?nJv2?I3&v-UI(Fe93i@&C*-~jT7sO*ePGsl}eY$7hKmfPRv%36HO_SKBhfYn?P!` z7~Z9&w+)+-!ttNOq3fcWA?dn+Ch7_J+gQO}6h#E!T-Wm%6)P6BOjAfol7XMY(bwT! zuFJ_l8?P1c@51*ZI}Bu+VM~z&{*@{bO3RXLDhb~+ut9gjzYVW(T~jkO7eM1Nd=-9% z3}ukUVrI~EiWW60D}^D&X{sr05||{cHF!bIyO1C{MX45}o?On+fw$9SnKuhGTR~e5 z{|>xv%Da#t#0i20o(3t@5r)z1Tq&)T^ekvo>n`{^@N(DX&KJ-+;BUe^ZhI&1kPKNA zO|@ILM|gi6Bhe}q9A>DEmGC7AdD}VR8+OBAfpe~Fu2-`WwCCZk!-eTSpd%wmx~`|<7>-=mPO*xqSPq?sYnmiH53A6t z=aGBh@4%~E*Itii6KFl~tMF5GKZzvKp?lC!234ZSw3#5@aeTktr+Cdi2Y(gzT@PU{ zg7!=B3vg~mPe&nXPBzDJQmlj&p^hxoY?=w*o5`b{@K@mNuE#K4%@)uef?tDI&bSAq z3~a9BBt)XcriOV=8t*hgLxJ=l{0h9r^-!jx*#O!i_*HmE!##x&X$H=rN?{1*_58*R z8;y|CBwB;|b@+>L&h?OPr?i8{>+zT2FEtziyo0J3sTMii#czz1==w;Jd@M2{+~CIV z^`yg3&*S!e+cu^G{4)H6yTMFPUiaz^u4|Y|kHCKh-_w-du#+;b!VjA9k?R&O@EgSv z4Gi6&g`FL=q`S+M!DY2e3|Jg1I@WiAj-S7XbXDyKp3^L!Yu0<0!i(Xz;NkWTWco@o zXiMNffuE&D(=3rmHHA?lP2hHm2f+*b;??VP_VT9`poW!;drYfaOk0v-m#z)b8;6h5 z-eV_eq*Qj2sv-zrznNXGgRjB+;Wlnt(^pzSQ^?uw(BjpN$MY@;(n`X`3=yLFS z_yhQC`v-Mm1VaKM(ZMPmUa?fuUjheph2hl8Icd6?u8G+ zpST`7D=nbyhQA9hYwKI9DPdAAWnx%3#rg-Y)0zGO>c|Cj$D$qzuvqyw2J#Xh{PE#q zCdJMV3}QIi0G5^%GvYbsnsa%xxwTP?;HB^$c*ONIqye-$;Xj2plijG>C;spz)x1=t z+Qf7l8Y$AL3ztpGE$`_z0KR|f9R2V>FC9Ab300!lq+6;08#Bkek%_=>`Lreacr%u8+n;(?li=h2PGsdaLknfY*9r{Sjfc;=2rN=onv?6mp=gC zMe`W6_u+payX*8gtt1MGf}rN2U{owd`W99ROk@EP2}GbkDjbiwj%7UVehZ}25sx3A z85UOthEbP=P8#TLwH8LRbyVj`PcaOWW^A{rz;D34E{kvt8h@vMf_KBeLavq`@7PE* zPBz|wEf6+|EIfKVObk->JaLj_qcE8u5cb4Gmo&!=s~Ek(@$8S40ZkM336oxyJS4q} z%%Mp)Z2?Tu&$LtpQQGapx;j2iGbs~_UFqlW_uyfdMYslybs7Fk_+j|&cD^|I{Jh>h zEQTN~Q4Uiw3J|9d17+~AFeQwbBWX`e(p7hOA#c%Rua9}5nDFAXX<~g0SaO2-umC0? zS^)VRY?6u?J^?gst2`ed<|qQWb{0i~U^_JczYZUBJ+)~7jrCLb@8REvgI2%HZr%V0 z3oC~|c^~#XLW65DjdCMQ6jc|XsIJ3lB$22AQ(6J5RiC&uYP+FKk%S3^mPFhik}eNZ z82MC@0hRrLBH@|zvt74*GMN8=h5yangx*qGK#SmigrA0Yx9TPQX(j&VuwwFo1YCl0 zzDFKl6Qaha7c&4P?LakC$tJ|RmYxvcIwn7gsX!HqBacGqQ`rls0*3%j*Mhe>>V^LX zzTtX`SZM)`br$|B_+fZ?bGz0itr)BVz)IkfCbldWI)kP$O)^h<3`V|+$%FGznUwUX zY@o{lI^Uc(d77`oe+?gXJuQj6?$sMy*DzN7@KShdGdkn+DgdbNz@vo)pE~pYC}dQH zEK_^Mvo5u!0MHfU5U!YOAyTf1`e*ocN=cfrr0W7Eh}+5v+E#;7yL>BYI0 z!If5N;3l;)u;r0(eBOXK!FcVw>v~)hl}6B*iGP9r8&)&vfIn4-FDdXXWSP<}hRav6 zfh|BwLdFpfDYeu z3LygN1pHn2ZP)eJlJB~JDHOtg2j36>D!i!Xo!I>tFymN}$a^G&pz5C3Vu|Gc_-o_d zE@seg>#EmN{?MLTt0gm2S{ZzFgg+uAEwO3hdkPQV)x$BHGeXc14t@mx1>6f)oEATY z8UpSA*(CgNlK|Km6R{y#EMEzN>(gcmMF=T#6_e*h#(0P`!<8wdwM-vp7%SadwOQN zXYD~_fO!Wm&gpZ$^R3VCeeOcsX8tMjE#|kFPcV)8+Zte=r>-@z=(-%2wkFL8m`#p+ z!EIxUAP75`Yv42GFNo$Of4;{;9KtVGKM3zp`%V@j!qJ*LuSRhhdJ9+PTy@=0*Vb!U z{7y#H!gnpW*J|%uyiKyAF}Yy;OtAd}GbfY6d!RYm|Rya zyNhwJgC;S_{P)b)ng5jeHE#Ss-N9;r)k4le3q`Tg@rtNK=pqE4VAMsye|{a5@H!8T zS5Nuvc`ke}dgevxyJ7pF_T79RjiD1Hy$MV*Z=Lg^fLe%~pb4ZcAT$h9fx2V^_gv~_i6B;>coB#VzZ={$XspUt^$P7SLkJ6cWia;t9zV4ATl-T$o&3B$tCMjJKKpk&XV6os3}%#a01L1qD6D z|NbYhZ}I0pVt$Lc7Y*kVN<~{JI4!KEp5xTPD&}W-UqH25hUYpBZWDsC;J~%!GN|#R z)kGLwwN=mx3Kn zh7PKnFqkit{^A3`1oOMhZ!`a1hTGJw*@V!Bp88y;=dkKf6;Ry8b>*7iqZ7=3&ipJh zTa!;;CXP%x4u@bll@iLOf;w;ktXe6dIvvflVu-~PNTjj~ zyjUU$n+`}SG2vS%X@)cvpaiUc%ls?m)B=Z%&P-2)-`&fxl|idL?q~i3<{vRXr3HbJ z(8}kzLNm76Z-5 z?A+h!IjlaS!&&4;MdsVgw`Au7-x<09q|>@%?LoTb%Np;xnF8PHCFH4b~Qk zI(UHZSIhs#nHm4KUoMoLnLE&Q14cY8txz|%Ee4v|=?SzWcn&-abpUz7^<&*I{)Fez zk9&LX+Y`ak+Xc(sa(kc!UNK+bYBYgNimN#_1|yl}8S6;yeiWLq^<=xHW-Jvi;GbbH zejfg(G^NE8yias`t_vbq!bB5Lv{w9JbuU_g)&e+f@mJct0;vYWv~;b(p@M1&UZtqc zzsReE)iVTpa1USl4U-KzG2vCkmHU(+1&`apS2pjHa#?%x`FZ3|?_6EU*tf3d9ntKa>uH zsVm{$yCIO-3A@E9HxFH3({oru1S`6O*6j3yMO8eQ7g8WigN;HH z%_~xsw#XI)1YN|ViGZ~5DwUY`x^9HmsDcN+&;BKY=sujR`W?NO!Gh>nxE6ouyn=-r z5-hM*ttIT*DvMd`z0u~6sn!+Y+X#3o59+V^4DWWBPzQIv1W(cTU0%zIpCCMgnsQd_ zP|e&&s|kmY=uyR0utf0aay8_gq28-DMs#0mqo4}E4WF|^0k3WWS{EfVhHLbaNc&>Davd_iOF(IV&D zEb#8ZFx}aSPS2s;QP#C!nhM^b^b)M%BqO(wkk+PY!mun@woRw0fn%uq5HR_z%>%>a zj|fIB1hA%}+Wl(bmcAFgGgi6qprM)s4OfwQ{ap>N2;MqqUd=Uwg^>Eua|JA)5!M>m zp655Xa8SQT1hXIAYYjw2^@9IopBkJ`t7FXVn40bJd3uEU!ZCu`(FRdzm5U=bkGwiHxh#^_+SdN(hEptb8P z2J4=TU?CSPH)|c@ICa%)bt-GmbhA0E$#h16=Q>qX6m(_6SAy$0p))psC-<><@@yiR z`BOtTf6b@C{bXsTb`MKs9if@Nb2{#nUqp0xa)^d$AeKl(ZWV(iV3}3~mL45=xDUa7 zbhw)z!HTeI++$0MSv-MMHXvZGayaF7Os7&Ihz|GNgK6k)%rfS9AJ7szy|}i9=}~C+ zQ9Q(|`X@2l?2ps2Dh>~e2N+K!&@-?ThQZP+jup&96$E~#=lnoKSoA13%VOF{q|)%k z?W$Ew+`ffUu>h95WZDX1hJODQJG0XhXk%E+-{lcKorzo6Gnhl6;-TOI2CJ#A8=+fm zJ61RPAg*Ur#8J%KhwhWSU#y|o9m%4x!b&QiG@ z_g=`cc!Vr&=@{ zMNiDf;Epa>rmn!FC~dy_L*|c|Z+3c)?TY)s(GD>GfH}DIl?I(BX9QlS=eQkh}%iv#l5C!(ay6j&{#Ru=J71Ji|QN>AAHl zwmN7hnBT+-l}{W^Yj&L5aWBU%gl8M;^hDYbTN$)o=C_!KS85mws)z@bZP@Oikm6?r z?s82m<}1u+Iz88R#8w4O=KT`$>#J+*Bk7k^8iC*Gxj*n>60&qqR0VK_*vI@DGtuce zZ#1?lXuFty%*?I!193BPwX{FCngiaBO$s}3cm@StS9Jyk?h{wrilAA{-(#L+YHR)2 zgol)0RPLrXx?2!*dR_N*)C!&Ky}>gGR)2H{nP-@(POo7ju@ymklKH#L*m^sVLr(-{ zWP*ZnH%&L-n>GSX3xV5)t}PKnsl!)=O%*pZ6t~rd5cy^1(N3>tBVl%W0&9$J=09T| zXh&yO;J^%AR1KgQ?}4kQ;Cmk6I?y~9n$LSb5{9;B^L!v9V3Be?UtKNJfUWsR5HQ*6 z4a6hNZ!pg>XF9#c^~6>K?K8}mm_|D~3skWLY^MOzufj8IrUloC!L?%W0(zexDDXh= z)EC=sr$Rsq%|C$8)L4j2Lq|Fp$H+i8_74vrru%r~t>0j7w!#zBH#+1$WPXqN(@w8_ zJ+ak58(?NOqhsB3m{nL2e9&|SoxtbngwM1nC>oq60#i4_9isp4>!`t`)*XcIZV{YV z%tUWCjiJ6A_6_&r(LF;r!0S+77y7!h_?w@ArxWI*vAs@+!`TJ`CORKJ&>!( zwZ?4=nN$n|U0Lj+V;$JlkB3JFuxCdvb`q>yI-y)GT&ISr1 znSX{Y=xSRHw7VPxs76Q-x}M=W(KDS_jqn-pcrWS8RY50UhS#9hPpwKsWkT4U2fNlT zbPq|-_vahmrSKz%juEO{I*uK^ISlu8W4J$uy*v9bGT4n>{oNSq$srN5V9?d%6VLOQ ze!U-qU{2)=xIoZ?_O79y`TNW_nT5N$IU9^^(AE?U;0Z<)k?DFcwa~NXp{ljh>Ru*S zaS9MjaS4~{Dc7h`r}33Rk(x**JXPKv%Kiu5SX>V+Uw!sKO zYf@1|O4a#AmE5O8J#*{`UU=ph@^eLuPtRa#W)3r~{Do2(nN$+PJNhxQa}YxVz39qj zV4Cea9sK$~H~c+5ISrR?)!UWB?%_c^yl0rX z3lHraz+hhwY|DZ!{X`Bd*RbCJmv7w0G}mXe7c_~T%zw;$ojKR;&NnNzLED6=Ia~d= zIG<_Z;k~rd#bOLv#rWJJJR<7sQ`?_*t4DX)*Sh-$` zbKlX|jgg@NwU#3X9#Z#xy(|M`FY6~6O>pQ5KLi{9=W`g(HMH?k8)5ADaUo&B&gmJ+kLpYIDT;u0aK zK85cwU4ei?mS@VD44tkaaPpp4VM@je?=|I?cP3|WV|1M2zljT%uhDHrasAdECXp0?PcDOldq?oZ z;r%$ul>1aX4oAMJI)uwpaLLv4yoH@BHwy)=z|%t)(+P^pwtr5rfAZ$L7@L?zrNX{E zSG6}yLyd3n8?w4$gv^BSHa3?vT_w05U%r8JA6-IsHcf}?$JLu-EE@V|ZtF|TPc#4D z-8{?nhOuj~r_*y-OB`pu!c25}B5Mf|qktxA)gy6>W7LEw4sh|>O}zcyNBH@h??I<~ z?Cj}5iOpe_N&&*3%tL5@z&9~E3U$@35F+Ep+P1h8_HzIj)WuNI0W^qbMdDa*L+eeqKn-$xjtut0D7;!TZ-D*OF8Mkd*zB!6duHVAO&;Xt6Hpop z=(>h{v52>SdjU@#ewe@YH49UKt#I7SH*YHl3_Yx;3aIcV990Y3+LncwZ7D|*_e;iN zNT(9WCX>jfl1LM_gVcN3STO`8(pQp&{5<|aS43y9WFCdu=)r zuzY7FHzoT9GjAxLq8l#HV-CWR6MQnC)FG6)zW@8$uT%=)@?C=8Bsk9JPCtony!s-B276g_9Q92b9ZeuR%Pe$O z87s#&XsZkns}#;ddq(i`iDQK9D#oW~m$a*C=&^l!@R?(e!JzAf&gKv{M~Si`SN;}J zR;smUu5!O(xq^wAS!Nz*KfH($3UjR?LKjFUX7k9 zLQFvwx~8NbEkN$$wvC?dtb)&q9H_PrVH-_BeeS{~y!O^vwT=PyeQ56po;bJ?I zg!aYfPQs*vh@*((QRnmlO__mQYbGeVmT$zh zW3E)e-@frKW(&ngvax#81p|^@cv5YjoIrYSmdLgK}mE*ciziI4WrkbM*X41)JAse5X#yjUf#*>de zf~S}}2YQhp%mQ(h4y|00?R*vySkXA`JstsVvb|kyPHcnLB7&&e5BK-sOV2%x6Gsjz zV1E3@FY(FsTQFJi8^dQ?+cNRFXP?635ATIef%Vc!1iq=+In`gQY98u1s9$R#tqX+` zlJVH8=Pe@7&lT%Jcj>4rty9)wMC;)!6zn}+S;DWk1YFw5H!nSX41H{CaqY4Pj=OL? zc_yw7*zGVwCwwJ3HLW*amG;hy%oJ8&5xW2xm^8#6VBCdOkKejUWB`9psC}C2rtBoy(2fOWbURZdTzpt=%(F5XI?|-MKWfsg!afd0uv^%C$|?h}wl?`P`GBk?001 z_LqZEny^3FA8Dqwl`~w4a!bTEXiep;pFlbhhZlqn^y4?*!G)_g zmO$q5T`rx(tEZmAfstX%6-$_ynZfA9B*v$v*+M|eF?-OR%_?ytNTEc?#wMmPN2hBA zg*=x2g|ME!9Gy~EkO%+*vV=fZDwa_yRWLO*i#$PV=^RvhEM}pLPL$20U@O4D`Of0X z&0Dy7dra*?E|WnznS@Q4yK^}V?HGb((78Nk?atI*xEkX!^X8`Y-sac_4PliRL5nM$ zIdu|85AKJl8|sf>v^fm)c2n2^9jn|FHtAo$PSAbg2|IF{g>4MOh8?$% za*~*wo>dMfuGg%uWFm%vzHTJrakUCPmPWxh@Y=g?;=S|lqd-`1Pt0K7o;^5z^eDG1u4lF{(w;fL}2 zXI{ZmhaVw4I($(y|NZj4^Z4FRUq`-JRBqB30^*TFhw$o|-$7z%Kj!oVF5MiZn@!;Q z*d)$hyoJePfUf>M=oxwlA6&kQOLu0W_lzKjX9$pu!TxT*+!&kqDo0e7$EE<^mhnM(?0fsbXTbfDbO+#N}Jl(CiEb zhaWI)%8&!f!qF_x0f`U;R4zNA@8goOAhE6y|36R>RG)DHJJQ zafuH-~t>b;8%pwPliV^-L33vIBsXz~tlvO2s)A7U0I{6soR=Pp(|X|M~v+ab({x zJg0zKnwh4=LzOQ%A8dhXT_eqnPy* z^~>mvxk#`O&E@lvb23fB))f{B6sMQnU&}TS=X}}-SS@ZaFW+_1Y#<&;&_o2bWqDtJ z`E=!(#||guw?{FHAOw>0m#^W^fA|`%kKR!ZvG`kwQ^y{|siQ}r^WNhl&vVh!+mD^Y zyYW%}9EJzF;SfM+KhT{)GG<1A#-VYHP_%TYuAR_kZh?NM-j7a9D{uw2Oez7(3cnLa zldBQAL$k10ERu-?W@qU@hDMj7W5(m?>&e03xC$@1YHk{H|K!f}It1S>sx5a%nAbv*ioMicw*{$DHkmc-9$urzg;fsD`5T zM+OJv&;ma?c%1-za{VU$_m6+x6fy~y5FFS&j4wQU94U7O-t;XcI_aakrw^x2zksgp z9(L+t?~Weq+u4U~G6tVc)z?3OXFmNL;<1EkuWZL806D@IPa&60p|3lu<{>VcP9^K( z`kv1@%RF1#gGn%w$+!}-{D~V5^mQX{+x*4ve2+3Ma1mTK-OOWuJ9duXx#wR-HkadT z2YUv)G1A`!c7;qfhZkP{0`?s^7;?#PP?$t8MMEjiwVa2HFJQ$JwgR`|1p=-^&2Rm% zv5Mfg(p!h*v#xlc98C_lO2L<_RSLi`^TkpQk#a2x`;+Up@IU_gr}+5V&E}A~9=fv` zyn6a1Ms^I4F9(4$u7sS^red!Oz{+X`L5 ztx~^^l8vq#={CbS@&u0OvaaPXns?ARtfhH?`QhNR8= z{2c_962SJfxlpu0C_d>=#_sLPDS>J=_finnK+~2j=3SiQuHga1En5kGiF3G4m=ziW z!Sp$vX2x)A-v}Ptw@1yFwxi}`b6>RC+wi2l6a|^HjIAwoRf`rVV8!DxSS%2RsVnFj zr|LPLf^CCVbe(zOF3P4Y@j!tl;uSz@G7;g57_X0w<1hZ^XL$eO6(#gg&>>(Vj6}@F zlgAI@E3cf!qkDH_Znl6*#i_Sb!t<&Gj;=w5bj?6o9MO;5L&PhNQecXkVR2R07C3_f zeUX-BtS0(i;%d2E8Zpjyb~=x;%x5td3w{I&_MqzWaS<`-(fbgEfUwCPsGs%k7EOZh zEjnmdZw|>+yuK$(0GCy}o_Ze6Nn6hm%I2M8=G!QXyAlr+XgVu6je+7J7X+y4x)`6H z#rJ;lI?i6W$akS@h!|YYL(H~t=#jlR^Ww93;pC@~&7_pGNgH=^mX+RX5KJR1tlF-? zR9$F3t;8B>KJ-X!X$!4Un9KWtv`f-iY>Iz&W)5@tQZ(n5U(^9-S!vR})^xhHZ*1;S zS5FqHbRvSN`TPRzx9rzy*04;_R`E8LR;qhG9xTwrt(0m4I6U-^u3X34=P%%m_dkpr zL*sK-wcEdYCtm*allc5|CosIDUpbqrzyi{lB*p7tW@?VlgXKlMT;Z<4#SRQZSI!_p ztyY~S@W^|ad$0vU(>%5%`Asd-38kPv8{-c5v^A61YqF zY7vB7Ad^cIwt%jYUm*U~2)QOonTu`Ph!KW3Q-nJ+J%?(g+TeaszxoQ$HgOw?bULYA zCqG+2LAjgP7T7G?R3Il)@fBq+1;TSYx>~SNLas)+4cfgNBCrrP4Ka#uW^PVB_vlu+ zbPAt-@-duw;Tb&k$X+B9api8}Vv9pWEPdp<(n|Z{KvJ#6^(5te4W`AFUf{Agwty8+ z*sx<3VK$i>N~J2Dr=nD}1ci0NA>#{Z-E^KkXNc z^pWP;VjO#BW=^@A%yTX7CjCf}5XcgAveiH)%k#Y&Xwh8ckK?ZD`-Px=$aL1d5gm*N z3N#7ZveZ=$SwQ*5=bppYzW4$L2YXbtZsuUig@S-?L=qZ|XQ_y4VqYvBqN%+dn*nzD$}z_ZKRBoe}D9sR)-7mwZzyR#2@vE!&09 zwWfWq%iXd`*l~++SCoV6EEJlqwd`F+HX}z~qZ7fadTNms$HDmI4A#e)n!@wUA?C-} zVzJdgGno2DIuMP>ftM(1*Yk1p_8nDe#g%l+*r<-z6+WwdQQWMF>uC{N(x#o0lYOvl zTV+$XZT{7o9aSLqJOK@G9S`|pNx9rQt$Bobnt4&St!IjJz=yB)Rzrzv zoSMlm>zpe@oOy;BYwJebh1hDK{fzl9nZIVPiwx1SVaT#I_!PnT^b86`x{2en`gUST znsTdP85IYc;AnSeWt_Js`x;iZseB$Yg(3`X-33Dq?l|*Er`LABgO+E0kNJnp|IVCS zPbUT|sxDQP=RZC*gFFvEP=e?PX$t(%XcE+8XI&lP=tZ!^$8pU#j zjmPA@qTAx7!m_C|9fD-mgE>%$JzGonG5o zVk?4Hi%I6UnSaduA=6pSM`8+c%;IQrEtD#lAZ$`~J&F_lDr}>TAuc73wk&9zsLy$Y zj@NpAYys0U;W{3sCubF$on)=V`;6~|aZJN_T=F!frZ0*rG(EdMpWgaBQd7k%Y zx_f$h&YiunxB&tnNC3P69uRm)JVa5nBukb=$(H3fc3Fy#BtBD$?NVH+%4It)|B;fd zvQtj1DkX|-#jz+_6lF=YNXe8)5d?&j0Cus!p0jgbedT$-o>}ZJ_THVv0(ch>x~Kc= z?|gsnvpP|yUO)ibA5+7NIYX)RlGt*U3Oka?s-$q}XrAk?`62{)-O%T4BMIs)R0Nb; zhhRk`DALvP6U8-O%hWxV;^h-Gxv$jfxIC6oMP(IY6LkdFQT|>x6I~!q@kl>Q{Ts*g z`WI>}2d@(}Eu^8w1Q;5hfGbJCWOl^W);d@n3`1Lds{** zcNI620wGbU*63&xYTuU;Rmz_7J3<|zHm~`@mKoPAXnsQyRl-s%Rr1AB^>0d*>akj# zXX4LY{l&ck&;Wp?Bw<1XM zfuO)&Bq);H(O3k@wm2rnb139Wu%Z#9JCbX*CfP@yjwT^RVrYB7D9Ln{l#Vt+_v|OpfaokzohYgLe8ORk&gsrHm zuq3q0_WshV?y^G)gBo+Lg)uob7K>1$?V=8r?K`^LkVwVoW-cn_swzBd<Vl(kDrKdAO|gv>+0QI_W~-qpfk16@7sbT_N9_O&Y> zvWFh`P~)7-m6~$2=61S#H~V?a8Z`uN)(nB|FR0(5E>cfZsWn^JGUJ8^O+usoFn0WR)ph<+Zr9&_Cx1tfGJ5vNTw3eKyy@VGyYpGJj zNG8i7c4ZAV_qX0~xCNq06=yt?&H5YaH>n7jY6WPw29QS)L1}&r|(W3CrG{wTYX;(WZt}(sH#1+jSZbalB$gY&Gn&$wUz=WfYoaCc_H$A5A_;hjC-@Xo;;I&%H=A`r7Gv^5ll_F zpu95-1L3f~W~nH9C-af9Y3nk=>C7@RdC{K=w;(0D~{ z=~^WpoyYU8jHB_l7P{hb(#GLjiutl?r!|~P?u&&o#z!WQ&lMH4@?5@cwvnsrcq;kj zzSSYC@Hn3An-{GI;*t0^>}E z{-IG-iBrf?CRiPOxPiqug6eS<5U@=6A<ZccI`xy1h)NfP8mMvzL<3xM9z%&Pwrl%F z#ADVKNCdj(bV7|nL03C-{xUMzLg2^@n}7*y(RdWeWW42@FY|L)sL+_F{2raiqFAZS zSN^2&Nyqh`w;g9ZY#0w9aIU#R4(DUkkEqYfF|~YQs}MI5Xd9`|V40w4bgfHc8C89| z(zF*`)ak0Vx>yRB504LCKJBtT;Z^R_H+^!-?!4ugkjgF z15a@?wV$;bM(Jo$D0E}i`X`fmgF2yhH`wEg)Mu#OR2!A1QVq$%+o@#Zxm3h=Q=e}* z&Ajwt0OeUg8w*|2(h2XnB6Uc+c1ZZ_k!nUCcZK*gibTENRKo_wAoy}JXsceJ^tcNu9 zOv0dRw51XXu&8AQuG~r|Lof}`@f2vP8iazG$y|SQ{vyr|4$TF+v_3<&8XHV-QN&P(azSZhb@}W|z;ppk}jYJNT-?iN}Ta=8a(WR2f7&dS0!4@i& zjH|hMo_8g?Ri4T-w&%;vjuf_U*?^53IuVZrF4l6$8o1bmOu1`=Cjq=zsp8e6Cy*%= zl|#=0*=y9VQ^%$-d&9={>S%H%&msWLTts`x&_xv$m+p1^TtAAXGNMt7zg<xrR!$28RwJ;K?(K4%pq%hQ8j;Ne5dKz?$l)(G2)aAdsMl@O=^o-@0-3ziLmKBu_`+-N z33kn)<2%zJb6A|dckC4RFf-H5>eTNJ8w ze484iG6bphUBlnUgh`_mKA|D1wt_rTMB_~ zBWxOL=VqLj@A`E6Iy{aUngZGZdMJh0$V3kR_{MR#1Wpf6rdW~sQ|b??fi>O4br9DZ zXbI|hU#c}5Z=Jn>ryjaDNFXMXM;CEey(4tB zHB08kgoN!V$93o&;%I@(=`aa?L}Zz~H(3zY)^24!uI)}j*4)20PMpP={y`YVq?-*> z|AqQByQQ#r{I&MbsdMUX2UchOP+YM>d%_|4Y<@eOk8oTa;bvM zSRUE&0z#ZmXLlRgJKGd&0+V#-&}B=73i7!UCdP7v&1bt5+By=jq7k;!6$8y7XB&Io zdCjvHhjVmodlE7UaoLj>2JyzJv&{nVUFx&c*Ba+=)5i4%nq-5!jBj3{K27}+^$`Tl zIA>^@hDx=DSC5{+$~;(%IPX1Y!vbX|_vuCXsB5BVuvB zny$VPuGCxn&`5%n4BDD^37Kc=Pp^bl7&{`LUgJbeyNblg4N)mY6VbhX8DCf^PW4kMp0Ar`e@ zg~N!)qY7TT?x0q&`L3wos#NMseh*Akico4-KrIz3N=;x~wo_gh3P5SLE9A;l2}6Tp zh$o_m(gmaO2tnmF7D0rCLR>RnEGxMLWJ6CUI$2P3JpgX*#cnNH0hoKV&E_Vlyd7$)&NO*Iw2iY z=eJFmgoWmBOmR(*^ONsGgj8Hk950(K(n&*VEO{@Gl}i;kCOa`g>RJEAVeHtp3AgUq zs^&N+Y<%p{&7>Gif9&JcqbCakBV(U)J@1bQ+eLBjnRC2Z<7NX*!lu4Oy-i8Q{W+=| zv$&g7_wOG+gEIq{aQCgZsAmF#ODB?K3r8c17%oJYsxi481*zjZs5>6Yqb1lSo3Ii9 zCZk~lz|9q=X&|1ABVw6TpbX%0=(4q{jVj$xTrvPH0Jgaf0Z-mlWiFh%6oBpfHY461 zLy<07sn#$uI)PhuY*e7l>1MX89DUk85vXjwn0@Qa`TrCNhd&oJ&5X3I+YYL=`n0WW z&h17H-}i$0$cRK^JX;p!z1#b)^}McS#HpvLU!x9E(=1B%N?hT&cRz|xeds;hFr(on zJ`6LASX*pSuEy$)T)v2bizArG<`IiU5vqEa=+7|e1w021$B}m8nsQb5lo*TL%WMP| zBW!?-G|v$p8%XlYRnj+X=#-&gF?etCUb5RDZ1PS%ly|AFBzE7o6Y)e$!B8$&)VkW! z$+=yK1Jp`Y)QZ(9;Di)V=Ld(rd1-9?7dY1w%7M8rZ=Jn>mw$L%-8UgCma7;V&0w+$ zObZ{WcnlWz*1y)7v4rsDyc%#B;V`;3Y*zc?c`ly(@t?-F-M8QLph?Jy-$ng8^(>W` z`ceSczOfgd`DY)+{@vTvrZ$tnN=9MEEGc0N4k8ZX(a{84O%jjyrNKPPV>$S`CI^t(CuOo3sJhA6)_RBB1~3OjiWUaI&{TXbhb}!Z$~(3 zDwnrVzG(-+{?1+)M7B_z_5HdEbzY9jhu%%w(7kbs+MiUq15bbCXQAnaDjb@ot92QU zZL=z~0;v}_Wk@ExPW@}@4eFm$yPGd1Sqr7I*FQ88>g`O2y4u?&!LloL;iq3|fF1+iZduM$o zd-9c+Ucn###b03}S7^Y$enN_nxRh*DBpSn^$DUF9u=lR}vFE^j1kF`@I9stYe)7}5 zfs5zP;F~Y}O;G(*bzA4vq%|=_{Z|Cg{VMeYr8a_z>?IPh(BSa6E{W9LkyeT6(oyP_ znpE>e57JCTx#|%ER&PQjtW&BplL-im-a-y3?x+q*3qWkb=fRzQOyycErqM7W?NLNJ zVpl#~!o2O8t;T5rFf^XQz|bf*Z{C1pGOiqXML~w2I&u*I=d0hs_(Yz?V|{?8&YJGE z_l`r@cke^$K4Qgi=Yx-Oj=FL($F9%Yhw<=J??*nH!5s$=t4igvVtwhq|1olzakZf? zH%~flR@laWH)_akeU0j;K1KZ`)hWppvn<477S0Y_R{J8(rjoBJu4X7_TWZMn;e?6g zwzP7!dbUE~Y=YsbvsegLEX0bmV?RdRRDhXn5yGuQo#7H7ljd&SQIfTb#gBrHpOCIC=ti@J z#^krUV=&Ve>bWX`tHQ0=Dse-N?v`Xge&EGM)P&g~fLYL441!LUK0oQtuG%U$=ekp z9v&TB6%zhqq0x+R_>iG%pZV;ke(I_Hw`>bfWb-&bco|VEf<4SkQU2ToH}+lIpvaJIhJ$)*d#kJ&K%!Fr72a8N@n!lXlG$V}J9!_@5t5j-{gcXh9mw)H? z)x9kKrN8?U&Ye1@-sdu7IPvBW)GirP-9xLlIjsn(Rx>wHNGdTJ70Jd)IMR$7&PR&*aq!}w%cXK*g2&GyTRiAUz zeQs$$pj<;!rtD9FQ-Q|ySdkFY8xyeNkzjp`$dP7YZCjiboI ztI^Rd7M7l#4#MvvU-vOo^5J-^b3U5cg^zsvr|`Ky|DPDScwUO$vfNG9;X2MF!F%@K zi&!$Hp6%LqHx54XZdF`o_AMZ;W*AHTVCrGK>%AXFh)E#{I(&Hmue|iU0`Pm^{u+kq zcA-Wk(lmWltI~2q=1f@B8t#7J5yVq%s+df!jdQ&B@MDN2l8vgT64)YW?~LeUanGx( zHXZ3U6iXH4OJ$roe-Zg&J2v%n5;Oy*VNKbq1|D)FV=tmIO50+gjC`&%3D*^{*hgq~ z6Kwvf)oqlD6-1)uqV`12r9_t+9h*SdG>~K=u`ClN*CKOqZI}I(aEXOwgl=AEfeJ^$ z>e}7gfq2YPYa6fnov#hKiIP2YPRkEn@5SL~K8*7x-o&}%Zy-B5#64czx&$6M>vU%i z?mhCv{2U`xnOATWsAIm~O@cBPFyZi9IkN>=y^zMCkAu~3t0Mv9H zZ+-t2!uKLKPH*{w=ANsEZM$y8orjL74c>M8oruQc(<;77WFF9D1q|Y#P-2hY3F0`OlXU zif51Rk}D#fjM8x;SGo4o(D*^6Qp1^Z0~i_^S7&8KOe6?TA`wGdG7g(g-G6ZyxpG@v_ed;pplenv1U9P1w0-KeG2fit*t=eC@CP2Wr*w zf}cM6>_^ePVKet3gEdo zH~D4#QMyrHX9Bzavg|>MifF!&aVpgsPQ5*VOT%NqcTB#l4zRKTOtTebsrfH$QqlYdQMt4^)ZeelUw0&1l z2swzXLBJb0djj2kTkynuM)AKPbnIsnJm8Z!(-Uk+l3?@z~$OxOqsXK1ofwIBKMu` zDeT|76S1f@=RD+l>1X)TIP%%zG%u6o$hggAd9ofRQqWa!)tKp>-EHXTPS07iJ`l-8XHoG)Whr+15Vk`5yNlOFQe9#;Q5myxS%T;a+ic)kNoVf zsJ^9w<+4(V>k8~;hMd@A)c!`!Nm&dxU&{F1?QPhxaRZLMeF1xRZkep`0zjw%#+Bp- zGT8!7(?M?Ay&VxVtlG`CS2~MOx+BE|a@2Q5*kCa-5H@v$nNUVpSAdDL*mP9KcDW}m zZ2mSQVYIa;)t=1-bFE&-$+sJjVRq9D<{rF}!ZDFA@|yuXaL?`7w`YgibLl_Sz`~W^ zz;50ipiavcEe9}}vKg_sPE)zr%r$u4^z)1*QfjV#<4o3TtO;l{qq%wFYNmdrLT$Tc zFMj2B|De&v!&m?6FEKGTf{F1Fy!HK8CY|x_2OohIjbrQ1J$U5l4>0MxY5fY6y?t9S zHgXBYVqPWPGGZt7G!Cna4~=GEStfRE->iW0 z=YTC5HL-C^ci<+vrZlD4tB6i5WCTw+DjjXEew$95naE>kB%^-M<$6=w=L#jfar}%b zCPxn4$^Pls?({XSy!P_fnG~7=?V)$R2gy`gRX2AI$C7@e+8L~jh5SSS;{r)FB_yj4Qx7&L z<1*D})_!rMh-u=!eS7f#zV%%kJAEDpSnW-^)oh8bDleZ8TpEEDiD2ud-bweKt#Q~4 zlC25Syc5<1$ne66$Crg-SrvoDKqhU!cl0DW(_SKd-H@^;|HI97`U@_tQ9vp(z)M67bXy+5QI4mosk|(sVt4V`oLpsh3nhOiky z-=-aiCsOd|ubSdwAEer+KnB~N8wP>OikNh@ThZCph7)Hl;Piz-gr>IP zocb@1;3x~j_(To|_Uyn1o;rfQ$@UMR%P-08eX0l$mdOTFHFD8((AYDa`F7O`Rq zx|=0#TF~P0By2N+LLm!ZG6lXQ$NQ;mGu!%1OUGZF(|Al;J*45zy|=)Mn0WEkAK;DS zXHc$Gv13agB4Lwlt|XY`xoz7R92%wDdm2x@E)SAZu)l>xJm}nCba#)S-~3 z{iUX9`HqfWgjr;;jKXmv#7zsDge16Ogpo+4Q+2!cv2wAn4~sLd1w#^5`roy6qe|j$ zeD4kP6QXRcfLpe2#M*gCCkY;sKHk(0l zoIBf6?Yony_U})f!_62sHE4`>>V77~hkVa}miNiI8hV(uYR?;f!xgq~?7@={-AiYC z9p^3%;n>M@bhkWqZQF#-_LOoO&%2V@&7>?8%Q$(aA7MkEbTv)aC!J|(wi|q2w{29a zwJUwhNN)Mgc3kui4&(Tl3n-Q<*s`G;hwt8xJNE8GcXvBN1a_&W<9Y#bGxvsb*iC(u zj#lPAoZ%z8rKh=$<7Nd-06Rjxk9wk3t!$~+s&h7$1acK<8aK?t67vuaGjU^gC!RWd z5Z`?5hd6m|00WmtkS~<5eai-H-Pnt$6(MZiRgNnuEC5{zd)B1(XK}Bo!DLr1cbZOl zwtrB$-`*Wt6lB{sZ$P>|3Bxo3Vip-{c5H8Z!FA@OIH!bd*ME`gdN35yUf`2|;N#b* z%4#0w^$<53XesIu>LcnJ3T<{h7nO1muItR1q!Pg!f7t`Ogs8it4Ua!?4=mHfo2TAJ zu2{nH(-$y45x84-XL=HvtAU$27tGs6LKE=lV$$9CL=HbX+mFj5n9 zcY7Miwm70OYuRga=*He0?`pNGb{P^*>~>_n2)4{G?bC*soC(y0U~T&ba2t0P+|;{3p6jA!$RM=jic$8EUx_C1KvMXgu_ z@kC7ZFKjy6wg)$G+{mEG zv5SM4kP0e=;}x#YMBHs0+VeFLx-X3s=c^Tki=ICK;5=ctJ?}H=_g+-^IArg zpjB8%1ZIy7JJW4Aa?gJ3+qE4U`!P92DxH9?Ys-R6w!x>B+1}jc$0vccS_QFqvbo2y zfUO9M-ILT0s4r44QkSUOs%F7Di5nHPcIqJYG3r?=jo^T%L{M!j<>I0`6gTr%X>uL` zw<2Mc^cD;KQ358A2rQ$S9AV3<#21$k&?0POn!JX?yf-Hy^qA#Ef+cX3D^--MRX7A$ zYC(whVh|u{pCs5FZAl#5e=Bxu?o(74VIArAq=I)@kTv&(>^KBX=Bm$8e*`osW?{~M zN@$I9k^=Z3b(H#R>ILdFRa&L(UKeqrf!2w@!QM|jLv5V9sgH7bacU{6v%PCZ0zS=?tKmE@kccsFzTjXP)EUVg|tT$h^R0s@K|HV}(O&_Sn~oQLNr z5alW%Fo~M$@F$Cc58IjAYXC+f6+>ff2{zb*k zhMuN=Kz$j3%UzVASN$Mb9M>ag8r4QUPJJ8!VBJgZWr<1VwFtDi;8WA{ub!j;B`#>*IO@t&@6$`b6U@rCwWVCz2GN?=AYkC5LQ3gb^o#r0H-#f2C%y>}bw; zDak5rBbJG_jwHh2B`5k-A&^Z}eY`R3qGV%1H=9}z!pk4FgE~yzOZ^P>*A1PZ3RvfH zy@0lXx}W+O^&|pETampiC)vim2s&IFU3%@Bfwr7=8itOx_9V!XfPAEe%ez|mGEY?`Jal};iSV}7o1!UC1;0>{Q&3>3U2l{(+|;H(a4&CsbG)W1NG zA77{bp87U*ZdEsN6=J=DCO|zweFy<)J*z!{?=ex9k$E{cj8QFu%|=<}*}8^}lS`yx zNKzqAb|q$}*2?eCW<8vl@F3f#EeSLquCuD3O^prI$El~O*Qn>I7pN2K<%rf3XmV_6 z>PhOO)Pq!Ss|NFzvHvnbm;aAA7SdWBNv&mxvnq}qk4MqgoBbxvC|Phz6#p4g^K}Me2*x52%7nrImxv7S|fIF6uA>zy!1;0`OWMQdyUO);>lF zT3WNwtyj_Fny_TZjIe=pM-masTouTwj*p`w9!5%@`n{Zx&s@jhzWdPDiyK$ssBy=6E!4LTC0g%E71B7IM;`%C#d$dpMu}e(nFHQ_CvVjM3EwFR>)EM>QP z0&5MLEcQ|AL)2qb=NgYc8RBS)vt=fa6y>~UV!(-En^A%p@^MX4Xhy^mQ6y6_=5=UA zpoJR$ot^M-G84FeXoa;z=Hs~z5H_#X_Q(pPsK1wbocccXchuigN2z+N23{-B1SoMX z0qh+JfLlTQ|MtrDH;$_e>kI2T`HwO`-^6-c2$1f?mepdcthv|n0KkoW`m zSNK1Qkf0SpEhH(Is;$(DI88``5~Y=skhRzL-gkCp&f$4yc5_qW+s^Db-F>Xb_Rh?n z^PV&B?>xOKX+rridPpMq{#~Y8s7)+5b&MHduE}OH%|^#YU|J@$>MhMoE@Qc><1}kW z$>&}rdmcr5;W&y_pij{!=r`!U)9=uq(ABgj%Mvs>^e5>b(r?ly>6r}Y+ktdXr+rt_ zdooHf^57G;MJC&%6?A6k`;uTg7F?IFRQC?qdQ0QdN`#89Q-SQ^!)cGnqrXLegZ?S~ z5&e7m0$rw4IT^A5tqa&0`Ye5#odqM)4(h-alD(VhVRu29fjAH?H9JKs+6Z+j! zg@OyqwtC{s;)0ri#^+43dv%@49zAKl_Mn7?=jh`|!r@~iz`aKo>0qybCcSk8NpihK zzd}!7ukLNi6v!eQ+QJRO<|_-w>?UkOr*j-`XMV;`q2Lh=W7lad$<^pUc56e$knPQv zm#Hjzntl~YSbRpmO`oT4()Ha8nigosJ4O8hNrFx0yjhz{8d3Lh>_0`)lz}$zMK}h@ zv^l$h5hEgO*|w{!#c^%8p0lfUNp%8M+1FSq60)+2&!GW?>|sf8jMCpj5+0Z7cabFA z5?$WOV7-Dik0iMSuv7F@-n+Avx+i{OBW|#?VUrZQ8;+pGggb86F<}O5TqEreePmWi zGt0JiRj(vjv7zzrdkS}I1Dj-<$)UeVzd*lEU!ea?e@K_MGr(>@lXq~8{t5ka`bBzw z-aE0E)NRsILm9kE-y zrc;GYlG$}^xSqSC?@4O$tGKzYu(YC3^@ot{PzxQOp_k}C(0`)u(Cx<`-VSI2*kStn z^jZ2Oy$@M-XvUHT(@OPa0Ron?3q3F3~-dC4-ngzLS~LjVhlP6HEW zutizPO#!J;@Zh>m{8?!gQx)>M$+fwb1wT}{T8eOGRl$!ige*td9S_tiFxZHuVIqpp z`}~(KRV-IStP+wryA3z;V~~`JUAFrSyBAn5VE`_kmUokp9!U* z1vFX;ZTM|OBqj(WGzp#5E-5BUh@m57qLBAp+rrXv8Q(ec19*i|&Y|+&?tzz`cL90G zV49hxm3JAjn#~rjU%QHnpM8pYy~YE;e3X78`QNzzuhG5q&{GetxsDwJdH!FYAhJjC z(#tQyvg|k^hssX_3Ys*gnQNd)4L(zC9h*;sDT45mNcE2&(fvYqbQ0YE0@c-dE+`71R@IvOw&T8Qo*_R-{U+ta$ECI z0}5Jlx|>Y5{?Dtm!p24!)oKlXtA(|-60$7Bv@8^h_wd2_zhQM{6&61a)qf2nXvt}B zW|AUXsZy!MX(p-W6$&`8e>&4Tj1J(Q>9g>gpPs zJiOoJN+}#XG=s^>sm$gU(8ebwF*`dSA1<|8J+4DwAHvo@4KQdH`azmBvm}T#x4`!B zlmfxX$S97^&SjQprfFc7sVT5&f-Ut_tF<^;Rp;|i*=uk?V}oVgV$#H67{*QAXf&VL z)N<{}(ODEmMq&`sR1EUy80O{|Igj}W%;j+2gaY(r(Qfd$QAqGf%WD;2Ss%cxXp zn>?ei|G+e+rw>7;oN5Br(W7%XFg+dD^7uWeO@JFJdkrLL($A(TOV1Xxa=A*EIp5}~ z;W!SC&CbU)>6BoTaa_;C!s2tVEc=PiL{WsbwGC9O_00ET&}9xPY?5YK1)7XqtJRqp z8*FB^Wpc{>nZrjgK0XmATpE&b4s*;yGl!oFugn{UAxfn+G#ZU;He)D}DMww6PUr1D zGtxZ24JL@iCJeR&VJDKITCG;xyg?9dYit2w-}pEV9-3hSZlqF&ZQGceUu0Ukn)QYT002ovPDHLkV1i0df=d7Z diff --git a/images/avatars/gallery/Flics/Flic_98.png b/images/avatars/gallery/Flics/Flic_98.png deleted file mode 100644 index c3f17a032f1eeca3abb0ef0d46c850ad672f5a29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24449 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%0DgLJT_W>H?p^WZY`$f$OEIyG*a` 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

- -

- -

- - {S_FORM_TOKEN} - - - - - -

{L_TITLE}

- -

{L_EXPLAIN}

- - -
-

{L_NOTIFY}

-

{NOTICE}

-
- - -
- - - -
- - {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_TITLE}{L_CODE}{L_EMOTION}{L_OPTIONS}
{L_NOT_DISPLAYED}
{items.ALT_TEXT}{items.CODE}{items.EMOTION} - - {ICON_MOVE_UP} - - {ICON_MOVE_DOWN} - {ICON_EDIT} {ICON_DELETE} -
{L_ACP_NO_ITEMS}
- -

-     -

- {S_FORM_TOKEN} -
-
- - - - diff --git a/install/update/new/adm/style/acp_language.html b/install/update/new/adm/style/acp_language.html deleted file mode 100644 index 5e3ac95..0000000 --- a/install/update/new/adm/style/acp_language.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - « {L_BACK} - -

{L_LANGUAGE_PACK_DETAILS}

- -
- -
- {LANG_LOCAL_NAME} -
-
-
-
-
-
-
-
-
-
-
{LANG_ISO}
-
-
-
-
-
- -

- -

- {S_FORM_TOKEN} -
-
- - -

{L_MISSING_FILES}

- -
- {L_MISSING_LANG_FILES} - - » {missing_files.FILE_NAME}
- -
- - - -

{L_MISSING_VARS_EXPLAIN}

- -
- {L_MISSING_LANG_VARIABLES} - -
-
- -
{missing_varfile.variable.VAR_NAME}
- -
- -
- - - -

{L_ACP_LANGUAGE_PACKS}

- -

{L_ACP_LANGUAGE_PACKS_EXPLAIN}

- -
- {L_BROWSE_LANGUAGE_PACKS_DATABASE} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_LANGUAGE_PACK_NAME}{L_LANGUAGE_PACK_LOCALNAME}{L_LANGUAGE_PACK_ISO}{L_LANGUAGE_PACK_USED_BY}{L_OPTIONS}
{L_INSTALLED_LANGUAGE_PACKS}
{lang.ENGLISH_NAME} {lang.TAG}{lang.LOCAL_NAME}{lang.ISO}{lang.USED_BY}{L_DELETE}
{L_UNINSTALLED_LANGUAGE_PACKS}
{notinst.NAME}{notinst.LOCAL_NAME}{notinst.ISO}{L_INSTALL}
- - - - diff --git a/install/update/new/adm/style/acp_main.html b/install/update/new/adm/style/acp_main.html deleted file mode 100644 index b8d337c..0000000 --- a/install/update/new/adm/style/acp_main.html +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - -

{L_PERMISSIONS_TRANSFERRED}

- -

{L_PERMISSIONS_TRANSFERRED_EXPLAIN}

- - - -

{L_WELCOME_PHPBB}

- -

{L_ADMIN_INTRO}

- - -
-

{L_UPDATE_INCOMPLETE} {L_MORE_INFORMATION}

-
- -
-

{L_VERSIONCHECK_FAIL}

-

{VERSIONCHECK_FAIL_REASON}

-

{L_VERSIONCHECK_FORCE_UPDATE} · {L_MORE_INFORMATION}

-
- -
-

{L_VERSION_NOT_UP_TO_DATE_TITLE}

-

{L_VERSIONCHECK_FORCE_UPDATE} · {L_MORE_INFORMATION}

-
- - -
-

{UPGRADE_INSTRUCTIONS}

-
- - - -
-

{L_WARNING}

-

{L_NO_SEARCH_INDEX}

-
- - - -
-

{L_WARNING}

-

{L_REMOVE_INSTALL}

-
- - - - -
-

{L_ERROR_MBSTRING_FUNC_OVERLOAD}

-

{L_ERROR_MBSTRING_FUNC_OVERLOAD_EXPLAIN}

-
- - - -
-

{L_ERROR_MBSTRING_ENCODING_TRANSLATION}

-

{L_ERROR_MBSTRING_ENCODING_TRANSLATION_EXPLAIN}

-
- - - -
-

{L_ERROR_MBSTRING_HTTP_INPUT}

-

{L_ERROR_MBSTRING_HTTP_INPUT_EXPLAIN}

-
- - - -
-

{L_ERROR_MBSTRING_HTTP_OUTPUT}

-

{L_ERROR_MBSTRING_HTTP_OUTPUT_EXPLAIN}

-
- - - - -
-

{L_WRITABLE_CONFIG}

-
- - - -
-

{L_PHP_VERSION_OLD}

-
- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% if S_TOTAL_ORPHAN %} - - - {% else %} - {% endif %} - - {% if S_VERSIONCHECK %} - - - - - {% endif %} - -
{{ lang('STATISTIC') }}{{ lang('VALUE') }}
{{ lang('BOARD_STARTED') ~ lang('COLON') }}{{ START_DATE }}
{{ lang('AVATAR_DIR_SIZE') ~ lang('COLON') }}{{ AVATAR_DIR_SIZE }}
{{ lang('DATABASE_SIZE') ~ lang('COLON') }}{{ DBSIZE }}
{{ lang('UPLOAD_DIR_SIZE') ~ lang('COLON') }}{{ UPLOAD_DIR_SIZE }}
{{ lang('DATABASE_SERVER_INFO') ~ lang('COLON') }}{{ DATABASE_INFO }}
{{ lang('GZIP_COMPRESSION') ~ lang('COLON') }}{{ GZIP_COMPRESSION }}
{{ lang('PHP_VERSION') ~ lang('COLON') }}{{ PHP_VERSION_INFO }}
{{ lang('NUMBER_ORPHAN') ~ lang('COLON') }} - {% if TOTAL_ORPHAN > 0 %} - {{ TOTAL_ORPHAN }} - {% else %} - {{ TOTAL_ORPHAN }} - {% endif %} -
{{ lang('BOARD_VERSION') ~ lang('COLON') }} - {{ BOARD_VERSION }}{{ lang('VERSIONCHECK_FORCE_UPDATE') }} ] -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ lang('STATISTIC') }}{{ lang('VALUE') }}
{{ lang('NUMBER_POSTS') ~ lang('COLON') }}{{ TOTAL_POSTS }}
{{ lang('POSTS_PER_DAY') ~ lang('COLON') }}{{ POSTS_PER_DAY }}
{{ lang('NUMBER_TOPICS') ~ lang('COLON') }}{{ TOTAL_TOPICS }}
{{ lang('TOPICS_PER_DAY') ~ lang('COLON') }}{{ TOPICS_PER_DAY }}
{{ lang('NUMBER_USERS') ~ lang('COLON') }}{{ TOTAL_USERS }}
{{ lang('USERS_PER_DAY') ~ lang('COLON') }}{{ USERS_PER_DAY }}
{{ lang('NUMBER_FILES') ~ lang('COLON') }}{{ TOTAL_FILES }}
{{ lang('FILES_PER_DAY') ~ lang('COLON') }}{{ FILES_PER_DAY }}
  
-
- - -
- {L_STATISTIC_RESYNC_OPTIONS} - -
-
-

 
-
-
-
- -
-
-

 
-
-
-
- -
-
-

{L_RESYNC_STATS_EXPLAIN}
-
-
-
- -
-
-

{L_RESYNC_POSTCOUNTS_EXPLAIN}
-
-
-
- -
-
-

{L_RESYNC_POST_MARKING_EXPLAIN}
-
-
-
- - -
-
-

{L_PURGE_SESSIONS_EXPLAIN}
-
-
-
- - -
-
-

{L_PURGE_CACHE_EXPLAIN}
-
-
-
- - -
- - - -

{L_ADMIN_LOG}

- -

{L_ADMIN_LOG_INDEX_EXPLAIN}

- - - - - - - - - - - - - - - - - - - - - - -
{L_USERNAME}{L_IP}{L_TIME}{L_ACTION}
{log.USERNAME}{log.IP}{log.DATE}{log.ACTION}
- - - -

{L_INACTIVE_USERS}

- -

{L_INACTIVE_USERS_EXPLAIN_INDEX}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_USERNAME}{L_JOINED}{L_INACTIVE_DATE}{L_LAST_VISIT}{L_INACTIVE_REASON}
- {inactive.USERNAME_FULL} -
{L_POSTS}{L_COLON} {inactive.POSTS} [{L_SEARCH_USER_POSTS}] -
{inactive.JOINED}{inactive.INACTIVE_DATE}{inactive.LAST_VISIT} - {inactive.REASON} -
{inactive.REMINDED_EXPLAIN} -
{L_NO_INACTIVE_USERS}
- - - - - diff --git a/install/update/new/adm/style/acp_modules.html b/install/update/new/adm/style/acp_modules.html deleted file mode 100644 index f4040da..0000000 --- a/install/update/new/adm/style/acp_modules.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - « {L_BACK} - -

{L_TITLE} :: {MODULENAME}

- -

{L_EDIT_MODULE_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -
- -
- {L_GENERAL_OPTIONS} -
-

- {L_MODULE_LANGNAME_EXPLAIN}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
style="display: none;"> -
-

{L_MODULE_DISPLAYED_EXPLAIN}
-
-
-
-
-

- {L_CHOOSE_MODULE_EXPLAIN}
-
-
-
-

- {L_CHOOSE_MODE_EXPLAIN}
-
-
-
- -

- - - -   - -

- {S_FORM_TOKEN} -
-
- - - -

{L_ACP_MODULE_MANAGEMENT}

- -

{L_ACP_MODULE_MANAGEMENT_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - - - - - - - -
{NAVIGATION} [{L_EDIT} | {L_DELETE} | {L_DISABLE}{L_ENABLE}]
- - - - - - - - - - - - - - -
{modules.MODULE_IMAGE}{modules.MODULE_TITLE} [{L_HIDDEN_MODULE}] {L_DISABLE}{L_ENABLE}  - - {ICON_MOVE_UP} - - {ICON_MOVE_DOWN} - {ICON_EDIT} - {ICON_DELETE} -
- - -
 
- -
- -
- - - - -
- -
- -
- -
- - - - - -
- -
- -
 

- -
-
- {L_SELECT_MODULE}{L_COLON} - - -
-
- - - - diff --git a/install/update/new/adm/style/acp_permission_roles.html b/install/update/new/adm/style/acp_permission_roles.html deleted file mode 100644 index 670d5e1..0000000 --- a/install/update/new/adm/style/acp_permission_roles.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - « {L_BACK} - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- » {L_SET_ROLE_PERMISSIONS} - -
- -
- {L_ROLE_DETAILS} -
-
-
-
-
-

{L_ROLE_DESCRIPTION_EXPLAIN}
-
-
- -

- - {S_FORM_TOKEN} -

-
- - - -

{L_ROLE_ASSIGNED_TO}

- - - - - -

- - - - » {L_BACK_TO_TOP}
-

- -

- -

{L_ACL_TYPE}

- -
- -
-
- -
- -
style="display: none;"> -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_ACL_SETTING}{L_ACL_YES}{L_ACL_NO}{L_ACL_NEVER}
{auth.mask.PERMISSION}
-
-
- -
- -
- -
- - {S_FORM_TOKEN} -
-
- - » {L_BACK_TO_TOP}
-
- - - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- - - - - - - - - - - - - - - - - - -
{L_ROLE_NAME}{L_OPTIONS}
{roles.ROLE_NAME} -
{roles.ROLE_DESCRIPTION} -
{L_VIEW_ASSIGNED_ITEMS}{L_VIEW_ASSIGNED_ITEMS} - - {ICON_MOVE_UP} - - {ICON_MOVE_DOWN} - {ICON_EDIT} - {ICON_DELETE} -
- -
- {L_CREATE_ROLE}{L_COLON}
- {S_FORM_TOKEN} -
-
- - - - - -

{L_ROLE_ASSIGNED_TO}

- - - - - - - - diff --git a/install/update/new/adm/style/acp_posting_buttons.html b/install/update/new/adm/style/acp_posting_buttons.html deleted file mode 100644 index 614d6fa..0000000 --- a/install/update/new/adm/style/acp_posting_buttons.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- diff --git a/install/update/new/adm/style/acp_ranks.html b/install/update/new/adm/style/acp_ranks.html deleted file mode 100644 index d373657..0000000 --- a/install/update/new/adm/style/acp_ranks.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - « {L_BACK} - - - -

{L_ACP_MANAGE_RANKS}

- -

{L_ACP_RANKS_EXPLAIN}

- -
- -
- {L_ACP_RANKS} - - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
style="display: none;"> -
-
-
-
-
- - - -

- - -   - - {S_FORM_TOKEN} -

-
-
- - - -

{L_ACP_MANAGE_RANKS}

- -

{L_ACP_RANKS_EXPLAIN}

- -
-
- {L_ACP_MANAGE_RANKS} - - - - - - - - - - - - - - - - - - - - - - - - -
{L_RANK_IMAGE}{L_RANK_TITLE}{L_RANK_MINIMUM}{L_ACTION}
{ranks.RANK_TITLE}  -  {ranks.RANK_TITLE}  -  {ranks.MIN_POSTS}{ICON_EDIT} {ICON_DELETE}
- -

- - {S_FORM_TOKEN} -

-
-
- - - - diff --git a/install/update/new/adm/style/acp_search.html b/install/update/new/adm/style/acp_search.html deleted file mode 100644 index 9962005..0000000 --- a/install/update/new/adm/style/acp_search.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - -

{L_ACP_SEARCH_SETTINGS}

- -

{L_ACP_SEARCH_SETTINGS_EXPLAIN}

- - - - - - - -

{L_ACP_SEARCH_INDEX}

- - -

{L_CONTINUE_EXPLAIN}

- -
-
- {L_SUBMIT} -   - - {S_FORM_TOKEN} -
-
- - -

{L_ACP_SEARCH_INDEX_EXPLAIN}

- - - - - -
- -
- - {backend.S_HIDDEN_FIELDS} - - {L_INDEX_STATS}{L_COLON} {backend.L_NAME} ({L_ACTIVE}) - - - - - - - - - - - - - - - - - - - - - - -
{backend.L_NAME} ({L_ACTIVE})
{L_STATISTIC}{L_VALUE}{L_STATISTIC}{L_VALUE}
{backend.data.STATISTIC_1}{L_COLON}{backend.data.VALUE_1}{backend.data.STATISTIC_2}{L_COLON}{backend.data.VALUE_2}
- - - -

- - - - - - - -

- {S_FORM_TOKEN} -
- -
- - - - - - - diff --git a/install/update/new/adm/style/acp_styles.html b/install/update/new/adm/style/acp_styles.html deleted file mode 100644 index c09294b..0000000 --- a/install/update/new/adm/style/acp_styles.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - « {L_BACK} - - - -
- -
-

{MESSAGE_TITLE}

-

{MESSAGE_TEXT}

- - - - - {S_HIDDEN_FIELDS} - -
-   - -
- -
- -
- - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- {L_BROWSE_STYLES_DATABASE} -
- -
-{S_HIDDEN_FIELDS} -{S_FORM_TOKEN} - - - -
-
-
-
-
-
-
-
{STYLE_PATH}
-
-
-
-
{STYLE_VERSION}
-
-
-
-
{STYLE_COPYRIGHT}
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- -
- -
- {L_SUBMIT} -   - - {S_FORM_TOKEN} -
- - - - - - - - - - - - {STYLES_LIST_EXTRA} - - - - - - - - - - - - - - - - - - {styles_list.EXTRA} - - - - -
{L_STYLE_NAME}{L_STYLE_PHPBB_VERSION}{L_STYLE_USED_BY}{L_ACTIONS} 
- - - - - {styles_list.STYLE_NAME} -
{styles_list.STYLE_COPYRIGHT}
- - {styles_list.STYLE_NAME} - - -
{styles_list.COMMENT}
- - -
{L_STYLE_PATH}{L_COLON} {styles_list.STYLE_PATH_FULL}
- -
{styles_list.STYLE_PHPBB_VERSION}{styles_list.USERS} - - | - - {styles_list.actions.L_ACTION} - - {styles_list.actions.HTML} - - - - {% if styles_list.STYLE_NAME !== 'prosilver' %} - - {% endif %} - - -   - - - - -
- - - -
- - - -
- - -
- - - - diff --git a/install/update/new/adm/style/acp_users_overview.html b/install/update/new/adm/style/acp_users_overview.html deleted file mode 100644 index 2af669a..0000000 --- a/install/update/new/adm/style/acp_users_overview.html +++ /dev/null @@ -1,169 +0,0 @@ -
- -
- {L_ACP_USER_OVERVIEW} -
-

{L_NAME_CHARS_EXPLAIN}
-
-
[ {L_USE_PERMISSIONS} ]
-
- -
-
-
{USER_INACTIVE_REASON}
-
- -
-
-
{USER_REGISTERED}
-
- -
-
-
{REGISTERED_IP}
-
[ {L_WHOIS} ]
-
- -
-
-
{USER_LASTACTIVE}
-
-
-
-
- - - {USER_POSTS} - - {USER_POSTS} - - - - ({L_POSTS_IN_QUEUE}) - - ({L_POSTS_IN_QUEUE}) - -
-
-
-
-
{USER_WARNINGS}
-
-
-

{L_FOUNDER_EXPLAIN}
-
-
-
-
-
-
-
-
-

{L_CHANGE_PASSWORD_EXPLAIN}
-
-
-
-

{L_CONFIRM_PASSWORD_EXPLAIN}
-
-
- - -

- - - {S_FORM_TOKEN} -

- -
-
- - - - - -
- -
- {L_USER_TOOLS} -
-
-
-
- - -

- - {S_FORM_TOKEN} -

- -
- -
- - -
-
- {L_DELETE_USER} -
-

{L_DELETE_USER_EXPLAIN}
-
- - - - {L_USER_NO_POSTS_TO_DELETE} - -
-
-

- - - {S_FORM_TOKEN} -

-
-
- - diff --git a/install/update/new/adm/style/acp_users_prefs.html b/install/update/new/adm/style/acp_users_prefs.html deleted file mode 100644 index 358f3d5..0000000 --- a/install/update/new/adm/style/acp_users_prefs.html +++ /dev/null @@ -1,151 +0,0 @@ - - -
- -
- {L_UCP_PREFS_PERSONAL} - -
-
-
-
-
-
-
-
-
-
-
-

{L_ALLOW_PM_EXPLAIN}
-
-
-
-
-
-
-
-
-
-

{L_NOTIFY_METHOD_EXPLAIN}
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-

{L_BOARD_DATE_FORMAT_EXPLAIN}
-
-
style="display:none;">
-
- -
- -
- {L_UCP_PREFS_POST} - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
- -
- {L_UCP_PREFS_VIEW} - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{S_TOPIC_SORT_DAYS}
-
-
-
-
{S_TOPIC_SORT_KEY}
-
-
-
-
{S_TOPIC_SORT_DIR}
-
-
-
-
{S_POST_SORT_DAYS}
-
-
-
-
{S_POST_SORT_KEY}
-
-
-
-
{S_POST_SORT_DIR}
-
- -
- -
- - {S_FORM_TOKEN} -
- -
diff --git a/install/update/new/adm/style/acp_users_signature.html b/install/update/new/adm/style/acp_users_signature.html deleted file mode 100644 index 40f0fc2..0000000 --- a/install/update/new/adm/style/acp_users_signature.html +++ /dev/null @@ -1,52 +0,0 @@ - - -
- - -
- {L_ADMIN_SIG_PREVIEW} -

{SIGNATURE_PREVIEW}

-
- - -
- {L_SIGNATURE} -

{L_SIGNATURE_EXPLAIN}

- - - -
-
-
-
-
- - - - - - - - - -
-
{L_OPTIONS}{L_COLON} {BBCODE_STATUS} :: {IMG_STATUS} :: {FLASH_STATUS} :: {URL_STATUS} :: {SMILIES_STATUS}
-
-
- -
-   - - {S_FORM_TOKEN} -
-
diff --git a/install/update/new/adm/style/admin.css b/install/update/new/adm/style/admin.css deleted file mode 100644 index 3243d0e..0000000 --- a/install/update/new/adm/style/admin.css +++ /dev/null @@ -1,2736 +0,0 @@ -/* phpBB 3.3 Admin Style Sheet - ------------------------------------------------------------------------ - Original author: subBlue ( http://www.subblue.com/ ) - Copyright (c) phpBB Limited - - For full copyright and license information, please see - the docs/CREDITS.txt file. - ------------------------------------------------------------------------ -*/ - -/* General markup styles ----------------------------------------- */ -* { - /* Reset browsers default margin, padding and font sizes */ - margin: 0; - padding: 0; - font-size: 100%; -} - -abbr { - text-decoration: none; -} - -body, div, p, th, td, li, dd { - font-size: x-small; - voice-family: "\"}\""; - voice-family: inherit; - font-size: small; -} - -html>body, html>div, html>p, html>th, html>td, html>li, html>dd { - font-size: small; -} - -html { - color: #536482; - background: #DBD7D1; - /* Always show a scrollbar for short pages - stops the jump when the scrollbar appears. non-ie browsers */ - height: 100%; - margin-bottom: 1px; - word-wrap: break-word; -} - -body { - /* Text-Sizing with ems: http://www.clagnut.com/blog/348/ */ - font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; - color: #536482; - background: #DBD7D1; - font-size: 62.5%; /* This sets the default font size to be equivalent to 10px */ - margin: 10px 15px; -} - -code, samp { - font-size: 1.2em; -} - -img { - border: 0; -} - -h1 { - font-family: "Trebuchet MS", Helvetica, sans-serif; - font-size: 1.70em; - font-weight: normal; - color: #333333; -} - -h2, caption { - font-family: "Trebuchet MS", Helvetica, sans-serif; - font-size: 1.40em; - font-weight: normal; - color: #115098; - text-align: left; - margin-top: 25px; -} - -.rtl h2, .rtl caption { - text-align: right; -} - -h3, h4 { - font-family: "Trebuchet MS", Helvetica, sans-serif; - font-size: 1.20em; - text-decoration: none; - line-height: 1.20em; - margin-top: 25px; -} - -p { - margin-bottom: 0.7em; - line-height: 1.40em; - font-size: 0.90em; -} - -ul { - list-style: disc; - margin: 0 0 1em 2em; -} - -.rtl ul { - margin: 0 2em 1em 0; -} - -hr { - border: 0 none; - border-top: 1px dashed #999999; - margin-bottom: 5px; - padding-bottom: 5px; - height: 1px; -} - -.centered-text { - text-align: center; -} - -.search-box { - float: left; -} - -.rtl .search-box { - float: right; -} - -.small { - font-size: 0.85em; -} - -.hidden { - display: none; -} - -@media only screen and (max-width: 800px), only screen and (max-device-width: 800px) -{ - body { - margin: 5px 5px 0; - } -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - html, body { - height: auto; - margin: 0; - padding: 0; - } -} - - -/* General links */ -a:link, a:visited { - color: #105289; - text-decoration: none; -} - -a:hover { - color: #BC2A4D; - text-decoration: underline; -} - -a:active { - color: #368AD2; - text-decoration: none; -} - -.install-body p a { - font-weight: bold; -} - -a#maincontent, a#acl, a#assigned_to { - display: block; -} - -/* List items */ -ul, ol { - list-style-position: inside; - margin-left: 1em; -} - -li { - display: list-item; - list-style-type: inherit; -} - - -/* Main blocks ----------------------------------------- */ -#wrap { - padding: 0 0 15px 0; - min-width: 615px; -} - -#page-header { - text-align: right; - background: url("../images/phpbb_logo.svg") top left no-repeat; - height: 54px; - font-size: 0.85em; - margin-bottom: 10px; -} - -.rtl #page-header { - text-align: left; - background: url("../images/phpbb_logo.svg") top right no-repeat; -} - -#page-header h1 { - color: #767676; - font-family: "Trebuchet MS",Helvetica,sans-serif; - font-size: 1.70em; - padding-top: 10px; -} - -#page-header p { - font-size: 1.00em; -} - -#page-header p#skip { - display: none; -} - -#page-body { - min-width: 650px; -} - -.copyright { - font-size: 0.75em; - text-align: center; -} - -#content { - padding: 30px 10px 10px; - position: relative; -} - -#content h1 { - color: #115098; - line-height: 1.2em; - margin-bottom: 0; -} - -#main { - float: right; - width: 100%; - margin: 0 0 0 -210px; -} - -.rtl #main { - float: left; - margin: 0 -210px 0 0; -} - -.main { - margin-left: 210px; -} - -.rtl .main { - margin-left: 0; - margin-right: 210px; -} - -#page-body.simple-page-body { - padding: 0; - padding-right: 10px; - min-width: 0; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - #wrap, #page-body, #page-body.simple-page-body { - padding: 0; - min-width: 300px; - } - - #page-header { - margin: 5px; - padding-left: 160px; - height: auto; - min-height: 54px; - overflow: hidden; - } - - .rtl #page-header { - padding-right: 160px; - padding-left: 0; - } - - #page-header h1 { - font-size: 1.2em; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - #page-header fieldset { - margin-top: 5px; - } - - #main, .rtl #main, .main, .rtl .main { - float: none; - width: auto; - margin: 0; - } - - #content { - background: #F3F3F3 url("../images/innerbox_bg.gif") repeat-x top; - padding: 5px; - } - - #page-footer { - padding: 0 5px 5px; - } -} - -@media only screen and (max-width: 400px), only screen and (max-device-width: 400px) -{ - #page-header { - background-size: 76px 26.5px; - padding-left: 80px; - min-height: 30px; - } - - .rtl #page-header { - padding-right: 80px; - } - - #page-header h1 { - padding-top: 0; - font-size: 1.1em; - } -} - - -/* Tabbed menu -----------------------------------------*/ -#tabs { - font-family: Arial, Helvetica, sans-serif; - line-height: normal; - margin: 0 7px; - position: relative; - z-index: 2; -} - -#tabs > ul { - list-style: none; - margin: 0; - padding: 0; -} - -#tabs .tab { - display: inline-block; - float: left; - font-size: 0.85em; - font-weight: bold; - line-height: 14px; -} - -.rtl #tabs .tab { - float: right; -} - -#tabs .tab > a { - background: #D4D6DA; - background: -moz-linear-gradient(top, #CACBCF 0%, #D4D6DA 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #CACBCF), color-stop(100%, #D4D6DA)); - background: -webkit-linear-gradient(top, #CACBCF 0%, #D4D6DA 100%); - background: -o-linear-gradient(top, #CACBCF 0%, #D4D6DA 100%); - background: -ms-linear-gradient(top, #CACBCF 0%, #D4D6DA 100%); - background: linear-gradient(to bottom, #CACBCF 0%, #D4D6DA 100%); - border: 1px solid #BBB; - border-bottom-width: 0; - border-radius: 5px 5px 0 0; - color: #767676; - display: block; - font-weight: bold; - margin: 1px 1px 2px 0; - padding: 6px 9px 4px; - position: relative; - text-decoration: none; - text-transform: uppercase; - white-space: nowrap; - cursor: pointer; -} - -#tabs .tab > a:hover { - background: #F1F1EE; - border-color: #C0BFBB; - color: #BC2A4D; -} - -#tabs .activetab > a, -#tabs .activetab > a:hover { - background: #DCDEE2; - background: -moz-linear-gradient(top, #F2F2F2 0%, #DCDEE2 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F2F2F2), color-stop(100%, #DCDEE2)); - background: -webkit-linear-gradient(top, #F2F2F2 0%, #DCDEE2 100%); - background: -o-linear-gradient(top, #F2F2F2 0%, #DCDEE2 100%); - background: -ms-linear-gradient(top, #F2F2F2 0%, #DCDEE2 100%); - background: linear-gradient(to bottom, #F2F2F2 0%, #DCDEE2 100%); - border-color: #999; - border-bottom: 2px solid #DCDEE2; - box-shadow: 0 1px 1px #FFF inset; - color: #23649F; - margin: 0 1px 0 0; - padding: 7px 10px 4px; -} - -#tabs .activetab > a:hover { - color: #115098; -} - -/* Responsive tabs -----------------------------------------*/ -.responsive-tab { - position: relative; -} - -.responsive-tab > a.responsive-tab-link { - display: block; - font-size: 16px; - position: relative; - width: 16px; - line-height: 14px; - text-decoration: none; - padding-left: 9px !important; - padding-right: 9px !important; -} - -.responsive-tab .responsive-tab-link:before { - content: ''; - position: absolute; - left: 10px; - top: 7px; - height: .125em; - width: 14px; - border-bottom: 0.125em solid #767676; - border-top: 0.375em double #767676; -} - -.responsive-tab .responsive-tab-link:hover:before { - border-color: #BC2A4D; -} - -.responsive-tab.activetab .responsive-tab-link:before { - border-color: #23649F; -} - -.responsive-tab.activetab .responsive-tab-link:hover:before { - border-color: #115098; -} - -#tabs .dropdown, #minitabs .dropdown { - top: 20px; - margin-right: -2px; - font-weight: normal; -} - -#tabs .dropdown-right .dropdown { - margin-left: -2px; -} - -#tabs .dropdown-contents { - list-style: none; - margin: 0; -} - -#tabs .dropdown li { - border-bottom: 1px dotted #DCDCDC; -} - -#tabs .dropdown li:last-child { - border-bottom: none; -} - -#tabs .dropdown a { - display: block; - padding: 4px 8px; - text-align: right; -} - -/* Main Panel ----------------------------------------- */ -#acp { - position: relative; - top: -2px; - margin: 0 0 2px; - padding: 3px 1px; - min-width: 550px; - background: #F3F3F3 url("../images/innerbox_bg.gif") repeat-x top; - border: 1px #999999 solid; - border-radius: 5px; - box-shadow: #FFF 0 0 0 1px inset; -} - -#acp:first-child { - top: 0; -} - -.panel { - background: #F3F3F3 url("../images/innerbox_bg.gif") repeat-x top; - padding: 5px 0; - border-radius: 5px; - overflow: hidden; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - #acp { - min-width: 0; - min-height: 0; - border-radius: 0; - border-width: 1px 0; - background: #fff; - padding: 1px 0; - box-shadow: none; - } -} - -/* Sub-navigation Menu ----------------------------------------- */ - -/* Menu */ -#menu { - float: left; - width: 200px; - font-size: 1.00em; - padding: 0; - border-right: 1px solid #CCCFD3; - position: relative; -} - -.rtl #menu { - float: right; - border: none; - border-left: 1px solid #CCCFD3; -} - -#menu p { - font-size: 0.85em; -} - -#menu ul { - list-style: none; - margin: 0; - padding: 0; - word-wrap: normal; -} - -/* Default list state */ -#menu li, #menu .header { - padding: 0; - margin: 0; - font-size: 0.85em; - font-weight: bold; - display: block; -} - -/* Link styles for the sub-section links */ -#menu li span { - display: block; - padding: 3px 3px 3px 8px; - margin: 1px 0; - text-decoration: none; - font-weight: normal; - color: #138ECB; -} - -.rtl #menu li span { - padding: 3px 8px 3px 3px; -} - -#menu li a:hover, #menu li a:hover span { - text-decoration: none; - background-color: #FFFFFF; - color: #BC2A4D; -} - -#menu li a:active, #menu li a:active span { - color: #F632A0; -} - -#menu li#activemenu a span { - text-decoration: none; - font-weight: bold; - color: #1180B7; - background: transparent url("../images/arrow_right.gif") 0% 50% no-repeat; -} - -.rtl #menu li#activemenu a span { - background: transparent url("../images/arrow_left.gif") 100% 50% no-repeat; -} - -#menu li#activemenu a:hover span, #menu li#activemenu span { - text-decoration: none; - font-weight: bold; - color: #BC2A4D; - background: #FFFFFF url("../images/arrow_right.gif") 1% 50% no-repeat; -} - -.rtl #menu li#activemenu a:hover span, .rtl #menu li#activemenu span { - background: #FFFFFF url("../images/arrow_left.gif") 99% 50% no-repeat; -} - -#menu li a:active, #menu li a:active span, #menu li#activemenu a:active span { - color: #F632A0; -} - -#menu li span.completed { - text-decoration: none; - padding: 3px 3px 3px 12px; - background: url("../images/arrow_down.gif") 1% 50% no-repeat; -} - -.rtl #menu li span.completed { - text-decoration: none; - padding: 3px 12px 3px 3px; - background: url("../images/arrow_down.gif") 99% 50% no-repeat; -} - -#menu .header { - font-family: Tahoma, Helvetica, sans-serif; - display: block; - font-weight: bold; - color: #115098; - border-bottom: 1px solid #327AA5; - padding: 4px 0 2px; - margin-top: 15px; - text-transform: uppercase; - font-size: 0.75em; - text-decoration: none; - cursor: inherit; - outline-style: none; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - #menu, .rtl #menu { - float: none; - width: auto; - border-width: 0; - max-width: 200px; - margin: 0 auto 10px; - } - - #menu p { - text-align: center; - } - - #menu .menu-block.active { - margin: 0 -5px; - padding: 0 5px 3px; - background: rgba(255, 255, 255, .5); - border-radius: 5px; - } - - #menu .menu-block.no-header.active { - padding-top: 3px; - } - - #menu .menu-block .header { - margin-top: 5px; - cursor: pointer; - border-bottom-width: 0; - position: relative; - text-decoration: underline; - } - - #menu .menu-block .header:focus, #menu .menu-block.active .header { - color: #D31141; - text-decoration: none; - } - - #menu .menu-block ul { - display: none; - } - - .nojs #menu .menu-block:hover ul, #menu .menu-block.active ul, #menu .menu-block.no-header ul { - display: block; - } - - #menu .menu-block li:last-child { - border-bottom: 1px solid #327AA5; - } - - #menu .menu-block:last-child li:last-child, #menu .menu-block.active li:last-child { - border-bottom-width: 0; - } - - #menu .menu-block li a span { - border-radius: 2px; - } -} - - -/* Table styles ----------------------------------------- */ - -table { - width: 100%; - border: 1px solid #CCCFD3; - background-color: #FFFFFF; - padding: 1px; -} - -th { - padding: 3px 4px; - color: #FFFFFF; - background: #70AED3 url("../images/gradient2b.gif") bottom left repeat-x; - border-top: 1px solid #6DACD2; - border-bottom: 1px solid #327AA5; - text-align: left; - font-size: 0.75em; - text-transform: uppercase; -} - -td { - text-align: left; - font-size: 0.85em; - padding: 4px; - line-height: 1.20em; -} - -.rtl th, .rtl td { - text-align: right; -} - -.table1 { - clear: both; - border-spacing: 1px; - border-collapse: separate; -} - -.table2 { - display: inline-block; - border-spacing: 1px; - border-collapse: separate; -} - -.lside { - display: flex; - align-items: stretch; - width: 100%; -} - -.tabled { - width: 1%; -} - -dt#color_palette_placeholder table { - margin-right: 5px; - width: 80px; -} - -#color_palette_placeholder td { - padding: 0; -} - -table.type2 { - border: none; - background: none; - padding: 0; -} - -table.type2 th { - background: none; - border-top: none; - text-align: center; - color: #115098; - padding: 2px 0; -} - -table.type2 td { - padding: 0; - font-size: 1em; -} - -table.type2 td.name { - padding: 2px; - vertical-align: middle; -} - -table.type3 { - float: right; - width: 300px; - border: none; - background-color: transparent; - padding: 0; -} - -.rtl table.type3 { - float: left; -} - -table.type3 thead th { - background-color: transparent; - border-top: none; - text-align: center; - color: #115098; - padding: 0 3px; - font-size: 0.85em; - font-weight: normal; - text-transform: none; -} - -table.type3 tbody th { - border-top: none; - text-align: left; - text-transform: none; - padding: 0; - border: none; - font-size: 0.90em; - font-weight: normal; - width: 100%; -} - -.rtl table.type3 tbody th { - text-align: right; -} - -table.type3 td { - text-align: center; - padding: 1px; -} - -th.name { - text-align: left; - width: auto; -} - -.rtl th.name { - text-align: right; -} - -td.name { - text-align: left; - font-weight: bold; -} - -.rtl td.name { - text-align: right; -} - -.entry { - text-align: left; - font-weight: normal; -} - -.rtl .entry { - text-align: right; -} - -.row1 { - background-color: #F9F9F9; -} - -table.zebra-table tbody tr:nth-child(odd) { - background-color: #F9F9F9; -} - -.row2 { - word-break: break-all; - background-color: #DCEBFE; -} - -table.zebra-table tbody tr:nth-child(even) { - background-color: #DCEBFE; -} - -.row3 { background-color: #DBDFE2; } -.row4 { background-color: #E4E8EB; } -.col1 { background-color: #DCEBFE; } -.col2 { background-color: #F9F9F9; } - -/* 4 row background colours for trees */ -.row1a { background-color: #F9F9F9; } -.row1b { background-color: #F6F6F6; } -.row2a { background-color: #E7EEF4; } -.row2b { background-color: #E3EBF2; } - -tr.row-highlight:hover td { background-color: #DBDFE2; } - -.spacer { - background-color: #DBDFE2; - height: 1px; - line-height: 1px; -} - -/* Deactivated row */ -.row-inactive { - color: #999; -} -.row-inactive a, .row-inactive strong { - color: #888; -} -.row-inactive a:hover { - color: #BC2A4D; -} - -/* Specific tables */ -table.forums td.folder { - width: 27px; - text-align: center; -} - -table td.actions { - vertical-align: middle; - width: 100px; - text-align: center; - white-space: nowrap; -} - -table tr:first-child td.actions .up, table tr:last-child td.actions .down { - display: none; -} - -table tr:first-child td.actions .up-disabled, table tr:last-child td.actions .down-disabled { - display: inline !important; -} - -table.styles td.users, table td.mark { - text-align: center; -} - -table.fixed-width-table { - table-layout: fixed; - word-break: break-word; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - table.responsive, table.responsive tbody, table.responsive tr, table.responsive td { - display: block; - } - - table.responsive thead, table.responsive th, table.responsive colgroup { - display: none; - } - - table.responsive.show-header thead, table.responsive.show-header th:first-child, table.responsive caption { - display: block; - width: auto !important; - text-align: left !important; - margin: 0; - } - - table.responsive { - background: transparent none; - border-width: 0; - padding: 0; - } - - table.responsive caption { - padding: 3px 4px; - color: #FFFFFF; - background: #70AED3 url("../images/gradient2b.gif") bottom left repeat-x; - border-top: 1px solid #6DACD2; - border-bottom: 1px solid #327AA5; - text-align: left; - font-size: 0.75em; - font-weight: bold; - text-transform: uppercase; - } - - table.responsive.show-header th:first-child span.rank-img, table.responsive.no-caption caption, table.responsive.no-header thead { - display: none; - } - - table.responsive tr { - margin: 2px 0; - border: 1px solid #CCCFD3; - background-color: #FFFFFF; - padding: 1px 1px 0; - overflow: hidden; - } - - table.responsive tr.row1 td { background-color: #F9F9F9; } - table.responsive tr.row2 td { background-color: #DCEBFE; } - table.responsive tr.row3 td { background-color: #DBDFE2; } - table.responsive tr.row4 td { background-color: #E4E8EB; } - table.responsive tr.col1 td { background-color: #DCEBFE; } - table.responsive tr.col2 td { background-color: #F9F9F9; } - table.responsive tr.row1a td { background-color: #F9F9F9; } - table.responsive tr.row1b td { background-color: #F6F6F6; } - table.responsive tr.row2a td { background-color: #E7EEF4; } - table.responsive tr.row2b td { background-color: #E3EBF2; } - - table.responsive td { - width: auto !important; - text-align: left !important; - padding: 4px; - margin-bottom: 1px; - } - - .rtl table.responsive td { - text-align: right !important; - } - - table.responsive td.empty { - display: none !important; - } - - table.responsive td > dfn { - display: inline-block !important; - } - - table.responsive td > dfn:after { - content: ':'; - padding-right: 5px; - } - - table.responsive.two-columns td { - width: 50% !important; - float: left; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - - .rtl table.responsive.two-columns td { - float: right; - } - - table.responsive.two-columns td:nth-child(2n+1) { - clear: left; - } - - table.responsive span.rank-img { - float: none; - padding-right: 5px; - } - - table.responsive#memberlist td:first-child input[type="checkbox"] { - float: right; - } - - /* Specific tables */ - table.responsive.forums td.folder { - float: left; - width: 27px; - background: transparent; - } - .rtl table.responsive.forums td.folder { - float: right; - } - - table.responsive.forums td.forum-desc { - margin-left: 35px; - min-height: 27px; - background: transparent; - } - - .rtl table.responsive.forums td.forum-desc { - margin-left: 0; - margin-right: 35px; - } - - table.responsive td.actions { - clear: both; - text-align: right !important; - } - - .rtl table.responsive td.actions { - text-align: left !important; - } - - table.responsive.styles tr.responsive-style-row td:first-child { - padding-left: 4px !important; - padding-right: 4px !important; - } - - table.responsive.styles td:first-child > dfn, table.responsive td.actions > dfn { - display: none !important; - } - - .horizontal-palette td:nth-child(2n), .vertical-palette tr:nth-child(2n) { - display: none; - } - - .colour-palette a { - display: inline-block !important; - } -} - -/* General form styles -----------------------------------------*/ -fieldset { - margin: 15px 0; - padding: 10px; - border-top: 1px solid #D7D7D7; - border-right: 1px solid #CCCCCC; - border-bottom: 1px solid #CCCCCC; - border-left: 1px solid #D7D7D7; - background-color: #FFFFFF; - position: relative; - border-radius: 3px; -} - -fieldset h2 { - margin-top: 0; -} - -.rtl fieldset { - border-top: 1px solid #D7D7D7; - border-right: 1px solid #D7D7D7; - border-bottom: 1px solid #CCCCCC; - border-left: 1px solid #CCCCCC; -} - -fieldset p { - font-size: 0.85em; -} - -legend { - padding: 1px 0; - font-family: Tahoma,arial,Verdana,Sans-serif; - font-size: .9em; - font-weight: bold; - color: #115098; - margin-top: -.4em; - position: relative; - text-transform: none; - line-height: 1.2em; - top: -.2em; - vertical-align: middle; -} - -input, textarea { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 0.90em; - font-weight: normal; - vertical-align: middle; - padding: 2px; - color: #111111; - border-left: 1px solid #AFAEAA; - border-top: 1px solid #AFAEAA; - border-right: 1px solid #D5D5C8; - border-bottom: 1px solid #D5D5C8; - background-color: #E3DFD8; -} - -.rtl input, .rtl textarea { - border-left: 1px solid #D5D5C8; - border-top: 1px solid #AFAEAA; - border-right: 1px solid #AFAEAA; - border-bottom: 1px solid #D5D5C8; -} - -input:hover, textarea:hover { - border-left: 1px solid #AFAEAA; - border-top: 1px solid #AFAEAA; - border-right: 1px solid #AFAEAA; - border-bottom: 1px solid #AFAEAA; - background-color: #E9E9E2; -} - -input.langvalue, textarea.langvalue { - width: 90%; -} - -input[type="number"] { - width: 60px; - -moz-padding-end: 0; -} - -optgroup, select { - background-color: #FAFAFA; - border: 1px solid #666666; - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 0.85em; - font-weight: normal; - font-style: normal; - cursor: pointer; - padding: 1px; - vertical-align: middle; - width: auto; - color: #000; -} - -select:focus { - outline-style: none; -} - -optgroup { - font-size: 1.00em; - font-weight: bold; -} - -optgroup.disabled-options { - display: none; - background-color: gray; -} - -option { - padding: 0 1em 0 0; - color: #000; -} - -option.disabled-option { - color: graytext; -} - -.rtl option { - padding: 0 0 0 1em; -} - -.sep { - font-weight: bold; -} - -.username-coloured { - font-weight: bold; -} - -textarea { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 0.85em; - width: 60%; - padding: 2px; -} - -label { - cursor: pointer; - font-size: 0.85em; - padding: 0 5px 0 0; -} - -.rtl label { - padding: 0 0 0 5px; -} - -label input { - font-size: 1.00em; - vertical-align: middle; -} - -label img { - vertical-align: middle; -} - -fieldset.quick, p.quick { - margin: 0 0 5px; - padding: 5px 0 0; - border: none; - background-color: transparent; - text-align: right; -} - -.rtl fieldset.quick, .rtl p.quick { - text-align: left; -} - -fieldset.quick legend { - display: none; -} - -fieldset.tabulated { - background: none; - margin: 0; - margin-top: 5px; - padding: 0; - border: 0; -} - -fieldset.tabulated legend { - display: none; -} - -fieldset.nobg { - margin: 15px 0 0 0; - padding: 0; - border: none; - background-color: transparent; -} - -fieldset.display-options { - margin: 15px 0 2px 0; - padding: 0 0 4px 0; - border: none; - background-color: transparent; - text-align: center; - font-size: 0.85em; -} - -fieldset.display-options select, fieldset.display-options input, fieldset.display-options label { - font-size: 1.00em; - vertical-align: middle; -} - -select option.disabled { - background-color: #bbb; - color: #fff; -} - -/* Special case inputs */ -select#board_timezone, -select#full_folder_action { - width: 95%; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - fieldset { - padding: 5px; - } - - fieldset.quick, p.quick { - float: none !important; - text-align: center; - } - - fieldset.display-options { - clear: both; - } -} - -/* Definition list layout for forms - Other general def. list properties defined in prosilver_main.css ----------------------------------------- */ -dl { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 1.00em; -} - -dt { - float: left; - width: auto; -} - -.rtl dt { - float: right; -} - -dd { color: #666666;} -dd + dd { padding-top: 5px;} -dt span { padding: 0 5px 0 0;} -.rtl dt span { padding: 0 0 0 5px;} - -dt .explain { font-style: italic;} - -dt label { - font-size: 1.00em; - text-align: left; - font-weight: bold; - color: #4A5A73; -} - -.rtl dt label { - text-align: right; -} - -dd label { - font-size: 1.00em; - white-space: nowrap; - margin: 0 10px 0 0; - color: #4A5A73; -} - -.rtl dd label { - margin: 0 0 0 10px; -} - -html>body dd label input { vertical-align: text-bottom;} /* Tweak for Moz to align checkboxes/radio buttons nicely */ - -dd input { - font-size: 1.00em; - max-width: 100%; - margin: 2px 0; -} - -dd select { - font-size: 100%; - font-size: 1em; - width: auto; - max-width: 100%; - margin: 2px 0; -} - -dd textarea { - font-size: 0.90em; - width: 90%; -} - -fieldset dl { - margin-bottom: 10px; - font-size: 0.85em; -} - -fieldset dt { - width: 45%; - text-align: left; - border: none; - border-right: 1px solid #CCCCCC; - padding-top: 3px; -} - -.rtl fieldset dt { - text-align: right; - border: none; - border-left: 1px solid #CCCCCC; -} - -fieldset #color_palette_placeholder { - padding-top: 0; -} - -fieldset dd { - margin: 0 0 0 45%; - padding: 0 0 0 5px; - border: none; - border-left: 1px solid #CCCCCC; - vertical-align: top; - font-size: 1.00em; -} - -.rtl fieldset dd { - margin: 0 45% 0 0; - padding: 0 5px 0 0; - border: none; - border-right: 1px solid #CCCCCC; -} - -dd.full, .rtl dd.full { - margin: 0; - border: 0; - padding: 0; - padding-top: 3px; - text-align: center; - width: 95%; -} - -/* Hover highlights for form rows */ -fieldset dl:hover dt, fieldset dl:hover dd { - border-color: #666666; -} - -fieldset dl:hover dt label { - color: #000000; -} - -fieldset dl dd label:hover { - color: #BC2A4D; -} - -input:focus, textarea:focus { - border: 1px solid #BC2A4D; - background-color: #E9E9E2; - color: #BC2A4D; - outline-style: none; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - fieldset dl { - margin-bottom: 5px; - padding-bottom: 5px; - border-bottom: 1px solid #e8e8e8; - } - - fieldset > dl:last-child, fieldset > form:last-child > dl:last-child { - border-bottom-width: 0; - margin-bottom: 0; - } - - fieldset dt, .rtl fieldset dt, fieldset dd, .rtl fieldset dd { - border-width: 0; - margin-left: 0; - margin-right: 0; - float: none; - width: auto; - } - - fieldset .responsive-columns dt { - float: left; - } - - .ltr fieldset dd { - padding-left: 20px; - } - - .rtl fieldset dd { - padding-right: 20px; - } - - select, dd select, dd input { - max-width: 300px; - } - - input[type="number"], dd input[type="number"] { - max-width: 70px; - } -} - -@media only screen and (max-width: 400px), only screen and (max-device-width: 400px) -{ - select, dd select, dd input { - max-width: 240px; - } -} - -/* Submit button fieldset or paragraph ----------------------------------------- */ -fieldset.submit-buttons { - text-align: center; - border: none; - background-color: transparent; - margin: 0; - padding: 4px; - margin-top: -1px; -} - -p.submit-buttons { - text-align: center; - margin: 0; - padding: 4px; - margin-top: 10px; -} - -fieldset.submit-buttons input, p.submit-buttons input { - padding: 3px 2px; -} - -fieldset.submit-buttons legend { - display: none; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - p.submit-buttons { - margin-top: 0; - } -} - -/* Input field styles ----------------------------------------- */ - -input.radio, input.checkbox, input.permissions-checkbox { - width: auto !important; - background-color: transparent; - border: none; - cursor: pointer; -} - -input.full, -textarea.full { - width: 99%; -} - -input.medium { width: 50%;} -input.narrow { width: 25%;} -input.tiny { width: 10%;} -input.autowidth { width: auto !important;} -.box2 .inputbox { background-color: #E9E9E9;} - -/* Form button styles ----------------------------------------- */ -a.button1, input.button1, -a.button2, input.button2 { - width: auto !important; - padding: 1px 3px 0 3px; - font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; - color: #000; - font-size: 0.85em; - background: #EFEFEF url("../images/bg_button.gif") repeat-x top; - cursor: pointer; -} - -a.button1, input.button1 { - font-weight: bold; - border: 1px solid #666666; -} - -/* Alternative button */ -a.button2, input.button2 { - border: 1px solid #666666; -} - -/* 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 { - text-decoration: none; - color: #000000; - padding: 4px 8px; -} - -/* Hover states */ -a.button1:hover, input.button1:hover, -a.button2:hover, input.button2:hover { - border: 1px solid #BC2A4D; - background: #EFEFEF url("../images/bg_button.gif") repeat bottom; - color: #BC2A4D; -} - -input.disabled { - font-weight: normal; - color: #666666; -} - -/* Focus states */ -input.button1:focus, input.button2:focus { - outline-style: none; -} - -/* jQuery popups ----------------------------------------- */ -.phpbb_alert { - background-color: #FFFFFF; - border: 1px solid #999999; - position: fixed; - display: none; - top: 150px; - left: 0; - right: 0; - width: 620px; - margin: 0 auto; - z-index: 50; - padding: 25px; - padding: 0 25px 20px 25px; -} - -.phpbb_alert .alert_close { - display: block; - float: right; - width: 16px; - height: 16px; - overflow: hidden; - text-decoration: none !important; - background: transparent url("../images/alert_close.png") 0 0 no-repeat; - margin-top: -7px; - margin-right: -31px; -} -.phpbb_alert .alert_close:hover { - background-position: 0 -16px; -} - - -.phpbb_alert p { - margin: 8px 0; - padding-bottom: 8px; -} - -.phpbb_alert label { - display: block; - margin: 8px 0; - padding-bottom: 8px; -} - -.phpbb_alert div.alert_text > p, -.phpbb_alert div.alert_text > label, -.phpbb_alert div.alert_text > select, -.phpbb_alert div.alert_text > textarea, -.phpbb_alert div.alert_text > input { - font-size: 0.9em; -} - -#darkenwrapper { - display: none; - position: relative; - z-index: 44; -} - -#darken { - position: fixed; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-color: #000000; - opacity: 0.5; - z-index: 45; -} - -@media only screen and (max-height: 500px), only screen and (max-device-width: 500px) -{ - .phpbb_alert { - top: 25px; - } -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - .phpbb_alert { - width: auto; - margin: 0 25px; - } -} - -#loading_indicator { - background: #000000 url("../images/loading.gif") center center no-repeat; - border-radius: 5px; - display: none; - opacity: 0.8; - margin-top: -50px; - margin-left: -50px; - height: 50px; - width: 50px; - position: fixed; - left: 50%; - top: 50%; - z-index: 51; -} - -/* Pagination ----------------------------------------- */ -.pagination { - font-size: .85em; - height: 1%; /* IE tweak (holly hack) */ - width: auto; - text-align: right; - margin: 5px 0; -} - -.top-pagination { - float: right; - margin: 15px 0 5px 0; -} - -.rtl .pagination { - text-align: left; - float: left; -} - -li.pagination { - margin-top: 0; -} - -.pagination img { - vertical-align: middle; -} - -.pagination ul { - display: inline-block; - *display: inline; /* IE7 inline-block hack */ - *zoom: 1; - margin-left: 0; - margin-bottom: 0; -} - -li.pagination ul { - margin-top: -2px; - vertical-align: middle; -} - -.pagination ul li, dl .pagination ul li, dl.icon .pagination ul li { - display: inline; - padding: 0; - font-size: 100%; - line-height: normal; -} - -.pagination li a, .pagnation li span, li .pagination li a, li .pagnation li span, .pagination li.active span, .pagination li.ellipsis span { - font-weight: normal; - text-decoration: none; - padding: 0 2px; - border: 1px solid transparent; - font-size: 0.9em; - line-height: 1.5em; -} - -.pagination li a, .pagination li a:link, .pagination li a:visited { - color: #5C758C; - background-color: #ECEDEE; - border-color: #B4BAC0; -} - -.pagination li.ellipsis span { - background-color: transparent; - color: #000000; -} - -.pagination li.active span { - color: #FFFFFF; - background-color: #4692BF; - border-color: #4692BF; -} - -.pagination li a:hover, .pagination .active a:hover { - color: #FFFFFF; - background-color: #368AD2; - border-color: #368AD2; -} - -.pagination li a:active, .pagination li.active a:active { - color: #5C758C; - background-color: #ECEDEE; - border-color: #B4BAC0; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - .pagination, .rtl .pagination { - float: none; - text-align: center; - margin: 5px 0; - } - - .pagination li a, .pagination li span { - display: inline-block; - min-width: 10px; - } -} - -/* Action Highlighting ----------------------------------------- */ -.successbox, .errorbox, .warningbox { - padding: 8px; - margin: 10px 0; - color: #FFFFFF; - text-align: center; - clear: both; -} - -.success { - color: #228822; -} - -.error { - color: #BC2A4D; -} - -.successbox { - background-color: #228822; -} - -.errorbox { - background-color: #BC2A4D; -} - -.warningbox { - background-color: #fca600; -} - -.successbox h3, .errorbox h3 { - color: #FFFFFF; - margin: 0 0 0.5em; - font-size: 1.10em; - font-family: "Lucida Grande",Verdana,Helvetica,Arial,sans-serif; -} - -.successbox p, .errorbox p { - color: #FFFFFF; - font-size: 0.85em; - margin-bottom: 0; -} - -.errorbox a:link, .errorbox a:active, .errorbox a:visited, -.successbox a:link, .successbox a:active, .successbox a:visited { - color: #DBD7D1; - text-decoration: underline; - font-weight: bold; -} - -.errorbox a:hover, .successbox a:hover { - color: #FFFFFF; - text-decoration: none; - 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; - line-height: 6em; -} - -#errorpage #content { - padding-top: 10px; -} - -#errorpage #content h1 { - color: #DF075C; -} - -#errorpage #content h2 { - margin-top: 20px; - margin-bottom: 5px; - border-bottom: 1px solid #CCCCCC; - padding-bottom: 5px; - color: #333333; -} - -/* Tooltip for permission roles */ -.tooltip { - width: 200px; - color: #000; - text-align: center; - border: 1px solid #AAA; -} - -.tooltip span.top { - background: #EFEFEF; - font-weight: bold; - padding: 2px; -} - -.tooltip span.bottom { - padding: 5px; - color: #000000; - background: #FFFFFF; -} - -/* - Format Buttons for signature editor -*/ -#format-buttons { - margin: 15px 0 2px 0; -} - -#format-buttons input, #format-buttons select { - vertical-align: middle; -} - -.row, fieldset dl { - overflow: hidden; -} - -/* Syntax Highlighting ----------------------------------------- */ -.sourcenum { - color: gray; - font-family: Monaco, 'Courier New', monospace; - font-size: 1.25em; - font-weight: bold; - line-height: 1.20em; - text-align: right; - padding: 0; -} - -.rtl .sourcenum { - text-align: left; -} - -.source { - font-family: Monaco, 'Courier New', monospace; - font-size: 1.25em; - line-height: 1.20em; - padding: 0; -} - -.syntaxbg { - color: #FFFFFF; -} - -.syntaxcomment { - color: #FF8000; -} - -.syntaxdefault { - color: #0000BB; -} - -.syntaxhtml { - color: #000000; -} - -.syntaxkeyword { - color: #007700; -} - -.syntaxstring { - color: #DD0000; -} - -/* Permission interface ----------------------------------------- */ - -.column1, .column2 { - width: 48%; - float: left; -} - -.ltr .column2, .rtl .column1 { - float: right; -} - -fieldset.permissions legend { - text-transform: none; -} - -fieldset.permissions legend input{ - height: 1.1em; -} - -/* Permission sections */ -fieldset.permissions .permissions-simple { - text-align: left; - padding-top: 3px; -} - -.rtl fieldset.permissions .permissions-simple { - text-align: right; -} - -fieldset.permissions .permissions-advanced { - padding: 10px 0 0 5px; - vertical-align: top; - clear: right; -} - -.rtl fieldset.permissions .permissions-advanced { - padding: 10px 5px 0 0; - clear: left; -} - -fieldset.permissions .permissions-switch { - float: right; -} - -.rtl fieldset.permissions .permissions-switch { - float: left; -} - -fieldset.permissions .padding { -} - -.permissions-switch { - margin-top: -6px; - font-size: .9em; -} - -.permissions-switch a { - text-decoration: underline; -} - -.permissions-reset { - padding-bottom: 10px; -} - -.permissions-reset a { - font-size: .85em; -} - -/* Tabbed menu */ -.permissions-category { - line-height: normal; - margin: 0 0 -1px 7px; - min-width: 570px; - font-size: 0.85em; -} - -.rtl .permissions-category { - margin: 0 7px -1px 0; -} - -.permissions-category ul { - margin: 0; - padding: 0; - list-style: none; -} - -.permissions-category li { - display: inline; - margin: 0; - padding: 0; - font-size: 1em; - font-weight: bold; -} - -.permissions-category a { - float: left; - background: url("../images/bg_tabs_alt1.gif") no-repeat 0% -35px; - margin: 0 1px 0 0; - padding: 0 0 0 6px; - text-decoration: none; - position: relative; -} - -.rtl .permissions-category a { - float: right; -} - -.permissions-category a span.tabbg { - float: left; - display: block; - background: url("../images/bg_tabs_alt2.gif") no-repeat 100% -35px; - padding: 7px 12px 6px 6px; - color: #536482; - white-space: nowrap; -} - -.rtl .permissions-category a span.tabbg { - float: right; -} - -/* Commented Backslash Hack hides rule from IE5-Mac \*/ -.permissions-category a span.tabbg, .rtl .permissions-category a span.tabbg { float: none;} -/* End hack */ - -.permissions-category a:hover span.tabbg { - color: #DD6900; -} - -.permissions-category .activetab a { - background-position: 0 0; -} - -.permissions-category .activetab a span.tabbg { - background-position: 100% 0; - padding-bottom: 7px; - color: #333333; -} - -.permissions-category a:hover { - background-position: 0 -70px; -} - -.permissions-category a:hover span.tabbg { - background-position: 100% -70px; -} - -.permissions-category .activetab a:hover span.tabbg { - color: #333333; - background-position: 100% 0; -} - -.permissions-category .activetab a:hover { - background-position: 0 0; -} - -.permissions-category a span.colour { - border: 1px solid #536482; - display: block; - float: left; - width: 10px; - height: 10px; - margin: 0 5px 0 0; -} - -/* Most browsers will have to live with a left aligned icon in RTL mode, as (currently) only Firefox 3.0 Alpha 3 renders it correctly without destroying it -.rtl .permissions-category a span.colour { - float: right; - margin: 0 0 0 5px; -} -*/ - -.permissions-category .activetab span.colour { - border-color: #333333; -} - -.permissions-category a:hover span.colour { - border-color: #DD6900; -} - -.permissions-category .activetab a:hover span.colour { - border-color: #333333; -} - -/* Permission preset colours */ -.permissions-preset-yes span.colour, -.yes { - background-color: #86F786; -} - -.permissions-preset-custom span.colour { - background-color: #B2BBDD; -} - -.permissions-preset-never span.colour { - background-color: #DD0000; -} - -.permissions-preset-no span.colour, -.never { - background-color: #EFB0B2; -} - -/* Permission panel ----------------------------------------- */ -.permissions-panel { - float: left; - background-color: #CADCEB; - width: 100%; - border-radius: 5px; - overflow: hidden; - padding: 5px 0; -} - -.rtl .permissions-panel { - float: right; -} - -/* Permission table ----------------------------------------- */ -.permissions-panel .tablewrap { - margin: 0 10px; -} - -.permissions-panel table { - width: 100%; -} - -.permissions-panel th { - text-transform: none; -} - -.permissions-panel th.value { - text-align: center; -} - -.permissions-panel th.name { - text-align: left; - width: auto; - text-transform: none; -} - -.rtl .permissions-panel th.name { - text-align: right; -} - -.permissions-panel th.permissions-name { - border: none; - color: #536482; - font-weight: normal; -} - -.permissions-panel th.permissions-name a.trace { - display: inline; -} - -.permissions-panel th.row3 { - background-image: none; - background-color: #D1D7DC; - color: #536482; - border: none; -} - -.permissions-panel th.row4 { - background-image: none; - background-color: #E4E8EB; - color: #536482; - border: none; -} - -.permissions-panel th a:link, .permissions-panel th a:hover, .permissions-panel th a:visited { - display: block; - color: #FFFFFF; - text-decoration: underline; -} - -.permissions-panel td.permissions-yes label:hover { - background-color: #86F786; -} - -.permissions-panel td.permissions-no label:hover { - background-color: #EFB0B2; -} - -.permissions-panel td.permissions-never label:hover { - background-color: #DD0000; -} - -.permissions-panel td { - padding: 0; - text-align: center; - width: 10%; -} - -.permissions-panel td label { - display: block; - margin: 0; - padding: 0; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - .column1, .column2 { - float: none !important; - width: auto; - } - - .permissions-simple { - clear: both; - } - - .permissions-simple td, .permissions-simple dd { - width: auto !important; - margin-left: 0 !important; - margin-right: 0 !important; - } - - .permissions-simple dd { - margin-top: 5px; - } - - .permissions-panel .tablewrap { - margin: 0 5px; - } - - .permissions-category { - min-width: 0; - margin: 0 !important; - } - - .permissions-category a, .permissions-category a span.tabbg { - display: block; - float: none !important; - background: transparent none; - } - - .permissions-category a { - background: #d9e5ee; - margin: 5px 0; - padding: 0 !important; - border-radius: 3px; - text-decoration: underline; - } - - .permissions-category .activetab a { - background-color: #dd6900; - color: #fff; - } - - .permissions-category a span.tabbg { - color: inherit !important; - padding-top: 6px !important; - padding-bottom: 6px !important; - } - - .permissions-category .activetab span.colour { - border-color: #fff; - } -} - -/* Avatars gallery ----------------------------------------- */ -#gallery { - display: block; - margin: 0 -5px; - padding: 0; - overflow: hidden; -} - -#gallery li { - display: block; - float: left; - border: 1px solid #ccc; - border-radius: 2px; - background: #fff; - padding: 5px; - margin: 5px; -} - -#gallery li:hover { - background-color: #eee; -} - -#gallery li label { - display: block; - text-align: center; - padding: 0; -} - -/* Dropdown menu -----------------------------------------*/ -.dropdown { - position: absolute; - left: 0; - top: 22px; - z-index: 2; - border: 1px solid transparent; - border-radius: 5px; - padding: 9px 0 0; -} - -.dropdown-up .dropdown { - top: auto; - bottom: 18px; - padding: 0 0 9px; -} - -.dropdown-left .dropdown { - left: auto; - right: 0; -} - -.dropdown .pointer, .dropdown .pointer-inner { - position: absolute; - width: 0; - height: 0; - border-top-width: 0; - border-bottom: 10px solid transparent; - border-left: 10px dashed transparent; - border-right: 10px dashed transparent; - -webkit-transform: rotate(360deg); /* better anti-aliasing in webkit */ - display: block; -} - -.dropdown-up .pointer, .dropdown-up .pointer-inner { - border-bottom-width: 0; - border-top: 10px solid transparent; -} - -.dropdown .pointer { - right: auto; - left: 10px; - top: 0; - z-index: 3; -} - -.dropdown-up .pointer { - bottom: 0; - top: auto; -} - -.dropdown-left .dropdown .pointer { - left: auto; - right: 10px; -} - -.dropdown .pointer-inner { - top: auto; - bottom: -11px; - left: -10px; -} - -.dropdown-up .pointer-inner { - bottom: auto; - top: -11px; -} - -.dropdown .pointer { - border-color: #B9B9B9 transparent; -} - -.dropdown .pointer-inner { - border-color: #FFF transparent; -} - -.dropdown .dropdown-contents { - z-index: 2; - overflow: hidden; - overflow-y: auto; - background: #fff; - border: 1px solid #b9b9b9; - border-radius: 5px; - padding: 5px; - position: relative; - min-width: 40px; - max-height: 200px; - box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2); - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.dropdown-up .dropdown-contents { - box-shadow: 1px 0 5px rgba(0, 0, 0, 0.2); -} - -.dropdown li { - float: none; - margin: 0; - white-space: nowrap; - text-align: left; -} - -.rtl .dropdown li { - text-align: right; -} -.wrap .dropdown li, .dropdown.wrap li { - white-space: normal; -} - -.dropdown li:before, .dropdown li:after { - 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%; - direction: ltr; -} - -.phpinfo td, .phpinfo th, .phpinfo h2, .phpinfo h1 { - text-align: left; -} - -.requirements_not_met { - padding: 5px; - background-color: #BC2A4D; -} - -.requirements_not_met dt label, .requirements_not_met dd p { - color: #FFFFFF; - font-size: 1.4em; -} - -@media only screen and (max-width: 700px), only screen and (max-device-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; } -} - -.clearfix { - overflow: hidden; -} - -.pagination:after, -#page-header:after, -#page-body:after, -#tabs:after, -#tabs > ul:after, -#tabs li:after, -#acp:after, -#content:after { - content: ''; - 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/install/update/new/adm/style/admin.js b/install/update/new/adm/style/admin.js deleted file mode 100644 index 5fdd073..0000000 --- a/install/update/new/adm/style/admin.js +++ /dev/null @@ -1,316 +0,0 @@ -/** -* phpBB3 ACP functions -*/ - -/** -* Parse document block -*/ -function parse_document(container) -{ - var test = document.createElement('div'), - oldBrowser = (typeof test.style.borderRadius == 'undefined'); - - delete test; - - /** - * Navigation - */ - container.find('#menu').each(function() { - var menu = $(this), - blocks = menu.children('.menu-block'); - - if (!blocks.length) { - return; - } - - // Set onclick event - blocks.children('a.header').click(function() { - var parent = $(this).parent(); - if (!parent.hasClass('active')) { - parent.siblings().removeClass('active'); - } - parent.toggleClass('active'); - }); - - // Set active menu - menu.find('#activemenu').parents('.menu-block').addClass('active'); - - // Check if there is active menu - if (!blocks.filter('.active').length) { - blocks.filter(':first').addClass('active'); - } - }); - - /** - * Responsive tables - */ - container.find('table').not('.not-responsive').each(function() { - var $this = $(this), - th = $this.find('thead > tr > th'), - columns = th.length, - headers = [], - totalHeaders = 0, - i, headersLength; - - // Find columns - $this.find('colgroup:first').children().each(function(i) { - var column = $(this); - $this.find('td:nth-child(' + (i + 1) + ')').addClass(column.prop('className')); - }); - - // Styles table - if ($this.hasClass('styles')) { - $this.find('td:first-child[style]').each(function() { - var style = $(this).attr('style'); - if (style.length) { - $(this).parent('tr').attr('style', style.toLowerCase().replace('padding', 'margin')).addClass('responsive-style-row'); - } - }); - } - - // Find each header - if (!$this.data('no-responsive-header')) - { - th.each(function(column) { - var cell = $(this), - colspan = parseInt(cell.attr('colspan')), - dfn = cell.attr('data-dfn'), - text = dfn ? dfn : $.trim(cell.text()); - - if (text == ' ') text = ''; - colspan = isNaN(colspan) || colspan < 1 ? 1 : colspan; - - for (i=0; i - $this.addClass('responsive'); - - if (totalHeaders < 2) { - $this.addClass('show-header'); - return; - } - - $this.find('tbody > tr').each(function() { - var row = $(this), - cells = row.children('td'), - column = 0; - - if (cells.length == 1) { - row.addClass('big-column'); - return; - } - - cells.each(function() { - var cell = $(this), - colspan = parseInt(cell.attr('colspan')), - text = $.trim(cell.text()); - - if (headersLength <= column) { - return; - } - - if ((text.length && text !== '-') || cell.children().length) { - if (headers[column] != '') { - cell.prepend('' + headers[column] + ''); - } - } - else { - cell.addClass('empty'); - } - - colspan = isNaN(colspan) || colspan < 1 ? 1 : colspan; - column += colspan; - }); - }); - - // Remove in disabled extensions list - $this.find('tr.ext_disabled > .empty:nth-child(2) + .empty').siblings(':first-child').children('dfn').remove(); - }); - - /** - * Hide empty responsive tables - */ - container.find('table.responsive > tbody').each(function() { - var items = $(this).children('tr'); - if (items.length == 0) - { - $(this).parent('table:first').addClass('responsive-hide'); - } - }); - - /** - * Fieldsets with empty - */ - container.find('fieldset dt > span:last-child').each(function() { - var $this = $(this); - if ($this.html() == ' ') { - $this.addClass('responsive-hide'); - } - - }); - - /** - * Responsive tabs - */ - container.find('#tabs').not('[data-skip-responsive]').each(function() { - var $this = $(this), - $body = $('body'), - ul = $this.children(), - tabs = ul.children().not('[data-skip-responsive]'), - links = tabs.children('a'), - item = ul.append('').find('li.responsive-tab'), - menu = item.find('.dropdown-contents'), - maxHeight = 0, - lastWidth = false, - responsive = false; - - links.each(function() { - var link = $(this); - maxHeight = Math.max(maxHeight, Math.max(link.outerHeight(true), link.parent().outerHeight(true))); - }) - - function check() { - var width = $body.width(), - height = $this.height(); - - if (arguments.length == 0 && (!responsive || width <= lastWidth) && height <= maxHeight) { - return; - } - - tabs.show(); - item.hide(); - - lastWidth = width; - height = $this.height(); - if (height <= maxHeight) { - responsive = false; - if (item.hasClass('dropdown-visible')) { - phpbb.toggleDropdown.call(item.find('a.responsive-tab-link').get(0)); - } - return; - } - - responsive = true; - item.show(); - menu.html(''); - - var availableTabs = tabs.filter(':not(.activetab, .responsive-tab)'), - total = availableTabs.length, - i, tab; - - for (i = total - 1; i >= 0; i --) { - tab = availableTabs.eq(i); - menu.prepend(tab.clone(true).removeClass('tab')); - tab.hide(); - if ($this.height() <= maxHeight) { - menu.find('a').click(function() { check(true); }); - return; - } - } - menu.find('a').click(function() { check(true); }); - } - - phpbb.registerDropdown(item.find('a.responsive-tab-link'), item.find('.dropdown'), {visibleClass: 'activetab', verticalDirection: 'down'}); - - check(true); - $(window).resize(check); - }); -} - -/** - * Extension actions helper functions - */ -function move_to_enabled(element) -{ - var disabled_header = document.querySelector('#ext_disabled_header'); - disabled_header.parentNode.insertBefore(element, disabled_header); - element.classList.remove('ext_disabled'); - element.classList.add('ext_enabled'); -} -function move_to_disabled(element) -{ - var table_body = document.querySelector('#ext_disabled_header').parentNode; - table_body.appendChild(element); - element.classList.remove('ext_enabled'); - element.classList.add('ext_disabled'); -} -function set_actions(container, actions) { - container.innerHTML = ''; - for (var i = 0; i < actions.length; i++) { - var a = document.createElement('a'); - a.href = actions[i].U_ACTION.split('&').join('&'); // replace all occurances - a.title = actions[i].L_ACTION_EXPLAIN; - if (actions[i].COLOR) { - a.style = actions[i].COLOR; - } - a.innerHTML = actions[i].L_ACTION; - // ajaxify this action as well - phpbb.ajaxify({ - selector: a, - refresh: true, - callback: actions[i].ACTION_AJAX - }); - - container.appendChild(a); - - if (i < actions.length - 1) { - container.innerHTML += ' | '; - } - } -} -function show_enabled_header() { - document.querySelector('#ext_enabled_header').classList.remove('hidden'); -} -function show_disabled_header() { - document.querySelector('#ext_disabled_header').classList.remove('hidden'); -} -function hide_disabled_header_if_empty() { - if (!document.querySelector('.ext_disabled')) { - document.querySelector('#ext_disabled_header').classList.add('hidden'); - } -} -function hide_enabled_header_if_empty() { - if (!document.querySelector('.ext_enabled')) { - document.querySelector('#ext_enabled_header').classList.add('hidden'); - } -} - -/** -* Run onload functions -*/ -(function($) { - $(document).ready(function() { - // Swap .nojs and .hasjs - $('body.nojs').toggleClass('nojs hasjs'); - - // Focus forms - $('form[data-focus]:first').each(function() { - $('#' + this.getAttribute('data-focus')).focus(); - }); - - parse_document($('body')); - - $('#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/install/update/new/adm/style/ajax.js b/install/update/new/adm/style/ajax.js deleted file mode 100644 index 39b63e4..0000000 --- a/install/update/new/adm/style/ajax.js +++ /dev/null @@ -1,360 +0,0 @@ -/* global phpbb, statsData */ - -(function($) { // Avoid conflicts with other libraries - -'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 = $('', { - type: 'hidden', - name: 'send_statistics_response', - value: JSON.stringify(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('&', '&'), - type: 'POST', - data: statsData, - 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 - * an item is moved up. It moves the row up or down, and deactivates / - * activates any up / down icons that require it (the ones at the top or bottom). - */ -phpbb.addAjaxCallback('row_down', function(res) { - if (typeof res.success === 'undefined' || !res.success) { - return; - } - - var $firstTr = $(this).parents('tr'), - $secondTr = $firstTr.next(); - - $firstTr.insertAfter($secondTr); -}); - -phpbb.addAjaxCallback('row_up', function(res) { - if (typeof res.success === 'undefined' || !res.success) { - return; - } - - var $secondTr = $(this).parents('tr'), - $firstTr = $secondTr.prev(); - - $secondTr.insertBefore($firstTr); -}); - -/** - * This callback replaces activate links with deactivate links and vice versa. - * It does this by replacing the text, and replacing all instances of "activate" - * in the href with "deactivate", and vice versa. - */ -phpbb.addAjaxCallback('activate_deactivate', function(res) { - var $this = $(this), - newHref = $this.attr('href'); - - $this.text(res.text); - - if (newHref.indexOf('deactivate') !== -1) { - newHref = newHref.replace('deactivate', 'activate'); - } else { - newHref = newHref.replace('activate', 'deactivate'); - } - - $this.attr('href', newHref); -}); - -/** - * The removes the parent row of the link or form that triggered the callback, - * and is good for stuff like the removal of forums. - */ -phpbb.addAjaxCallback('row_delete', function(res) { - if (res.SUCCESS !== false) { - $(this).parents('tr').remove(); - } -}); - -/** - * Callbacks for extension actions - */ -phpbb.addAjaxCallback('ext_enable', function(res) { - if (res.EXT_ENABLE_SUCCESS) { - move_to_enabled(this.parentNode.parentNode); - set_actions(this.parentNode, res.ACTIONS); - show_enabled_header(); - hide_disabled_header_if_empty(); - } -}); -phpbb.addAjaxCallback('ext_delete_data', function(res) { - if (res.EXT_DELETE_DATA_SUCCESS) { - move_to_disabled(this.parentNode.parentNode); - set_actions(this.parentNode, res.ACTIONS); - show_disabled_header(); - hide_enabled_header_if_empty(); - } -}); -phpbb.addAjaxCallback('ext_disable', function(res) { - if (res.EXT_DISABLE_SUCCESS) { - move_to_disabled(this.parentNode.parentNode); - set_actions(this.parentNode, res.ACTIONS); - show_disabled_header(); - hide_enabled_header_if_empty(); - } -}); - -/** - * Handler for submitting permissions form in chunks - * This call will submit permissions forms in chunks of 5 fieldsets. - */ -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]; - - // Set proper start values for handling refresh of page - var permissionSubmitSize = 0, - permissionRequestCount = 0, - forumIds = [], - permissionSubmitFailed = false; - - if ($submitAllButton !== $submitButton) { - fieldsetList = $form.find('fieldset#' + $submitButton.closest('fieldset.permissions').id); - } - - $.each(fieldsetList, function (key, value) { - dataSetIndex = Math.floor(key / 5); - var $fieldset = $('fieldset#' + value.id); - if (key % 5 === 0) { - 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[dataSetIndex] += '&' + roleInput.attr('name') + '=' + - $fieldset.find('select[name="' + roleInput.attr('name') + '"]').val(); - } - }); - - permissionSubmitSize = formDataSets.length; - - // Add each forum ID to forum ID list to preserve selected forums - $.each($form.find('input[type=hidden][name^=forum_id]'), function (key, value) { - if (value.name.match(/^forum_id\[([0-9]+)\]$/)) { - forumIds.push(value.value); - } - }); - - /** - * Handler for submitted permissions form chunk - * - * @param {object} res Object returned by AJAX call - */ - function handlePermissionReturn(res) { - permissionRequestCount++; - var $dark = $('#darkenwrapper'); - - if (res.S_USER_WARNING) { - phpbb.alert(res.MESSAGE_TITLE, res.MESSAGE_TEXT); - permissionSubmitFailed = true; - } else if (!permissionSubmitFailed && res.S_USER_NOTICE) { - // Display success message at the end of submitting the form - if (permissionRequestCount >= permissionSubmitSize) { - var $alert = phpbb.alert(res.MESSAGE_TITLE, res.MESSAGE_TEXT); - var $alertBoxLink = $alert.find('p.alert_text > a'); - - // Create form to submit instead of normal "Back to previous page" link - if ($alertBoxLink) { - // Remove forum_id[] from URL - $alertBoxLink.attr('href', $alertBoxLink.attr('href').replace(/(&forum_id\[\]=[0-9]+)/g, '')); - var previousPageForm = '
'; - $.each(forumIds, function (key, value) { - previousPageForm += ''; - }); - previousPageForm += '
'; - - $alertBoxLink.on('click', function (e) { - var $previousPageForm = $(previousPageForm); - $('body').append($previousPageForm); - e.preventDefault(); - $previousPageForm.submit(); - }); - } - - // Do not allow closing alert - $dark.off('click'); - $alert.find('.alert_close').hide(); - - if (typeof res.REFRESH_DATA !== 'undefined') { - setTimeout(function () { - // Create forum to submit using POST. This will prevent - // exceeding the maximum length of URLs - var form = '
'; - $.each(forumIds, function (key, value) { - form += ''; - }); - form += '
'; - $form = $(form); - $('body').append($form); - - // Hide the alert even if we refresh the page, in case the user - // presses the back button. - $dark.fadeOut(phpbb.alertTime, function () { - if (typeof $alert !== 'undefined') { - $alert.hide(); - } - }); - - // Submit form - $form.submit(); - }, res.REFRESH_DATA.time * 1000); // Server specifies time in seconds - } - } - } - } - - // Create AJAX request for each form data set - $.each(formDataSets, function (key, formData) { - $.ajax({ - url: $form.action, - type: 'POST', - data: formData + '&' + $submitButton.name + '=' + encodeURIComponent($submitButton.value) + - '&creation_time=' + $form.find('input[type=hidden][name=creation_time]')[0].value + - '&form_token=' + $form.find('input[type=hidden][name=form_token]')[0].value + - '&' + $form.children('input[type=hidden]').serialize() + - '&' + $form.find('input[type=checkbox][name^=inherit]').serialize(), - success: handlePermissionReturn, - error: handlePermissionReturn - }); - }); -} - -$('[data-ajax]').each(function() { - var $this = $(this), - ajax = $this.attr('data-ajax'); - - if (ajax !== 'false') { - var fn = (ajax !== 'true') ? ajax : null; - phpbb.ajaxify({ - selector: this, - refresh: $this.attr('data-refresh') !== undefined, - callback: fn - }); - } -}); - -/** -* Automatically resize textarea -*/ -$(function() { - phpbb.resizeTextArea($('textarea:not(.no-auto-resize)'), {minHeight: 75}); - - var $setPermissionsForm = $('form#set-permissions'); - if ($setPermissionsForm.length) { - $setPermissionsForm.on('submit', function (e) { - submitPermissions(); - e.preventDefault(); - }); - $setPermissionsForm.find('input[type=submit]').click(function() { - $('input[type=submit]', $(this).parents($('form#set-permissions'))).removeAttr('data-clicked'); - $(this).attr('data-clicked', true); - }); - } - - if ($('#acp_help_phpbb')) { - phpbb.prepareSendStats(); - } -}); - - -})(jQuery); // Avoid conflicts with other libraries diff --git a/install/update/new/adm/style/captcha_recaptcha.html b/install/update/new/adm/style/captcha_recaptcha.html deleted file mode 100644 index 563bd98..0000000 --- a/install/update/new/adm/style/captcha_recaptcha.html +++ /dev/null @@ -1,15 +0,0 @@ - -
-
- - - {L_RECAPTCHA_INVISIBLE} - -
-
-
- -{L_RECAPTCHA_NOT_AVAILABLE} - diff --git a/install/update/new/adm/style/installer_convert.html b/install/update/new/adm/style/installer_convert.html deleted file mode 100644 index aa16542..0000000 --- a/install/update/new/adm/style/installer_convert.html +++ /dev/null @@ -1,87 +0,0 @@ - -

{TITLE}

- -
-

{ERROR_TITLE}

-

{ERROR_MSG}

-
- - -
- - {errors.TITLE} -

{errors.DESCRIPTION}

- -
- -

{BODY}

-{CONTENT} - -

onclick="return false;">{L_SUBMIT}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_AVAILABLE_CONVERTORS}
{L_SOFTWARE}{L_VERSION}{L_AUTHOR}{L_CONVERT_OPTIONS}
{convertors.SOFTWARE}{convertors.VERSION}{convertors.AUTHOR}{L_CONVERT}
{L_NO_CONVERTORS}---
- - -
- - - - -
- -
- - {checks.LEGEND} -

{checks.LEGEND_EXPLAIN}

- - -
-

{checks.TITLE_EXPLAIN}
-
{checks.RESULT}
-
- - - -
- - - diff --git a/install/update/new/adm/style/installer_footer.html b/install/update/new/adm/style/installer_footer.html deleted file mode 100644 index 81a85d1..0000000 --- a/install/update/new/adm/style/installer_footer.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - -{$SCRIPTS} - - - diff --git a/install/update/new/adm/style/installer_form.html b/install/update/new/adm/style/installer_form.html deleted file mode 100644 index 592d361..0000000 --- a/install/update/new/adm/style/installer_form.html +++ /dev/null @@ -1,57 +0,0 @@ -

{FORM_TITLE}

-
- - -
- - - - - -
- -
- - {options.LEGEND} - -
-

{options.TITLE_EXPLAIN}
-
- - - - - - - - - - - - - - - checked /> {options.OPTIONS.label} - - -
-
- - - -
- - - -
- {L_SUBMIT} - - disabled="disabled" /> - -
- -
diff --git a/install/update/new/adm/style/installer_header.html b/install/update/new/adm/style/installer_header.html deleted file mode 100644 index 704db9e..0000000 --- a/install/update/new/adm/style/installer_header.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - {META} - {PAGE_TITLE} - - - - - -
- - -
-
- -
- -
-
- - -
-
diff --git a/install/update/new/adm/style/installer_install.html b/install/update/new/adm/style/installer_install.html deleted file mode 100644 index 53a91f2..0000000 --- a/install/update/new/adm/style/installer_install.html +++ /dev/null @@ -1,13 +0,0 @@ - -

{TITLE}

-

{CONTENT}

- -
-
- {L_SUBMIT} - -
-
- - - diff --git a/install/update/new/adm/style/installer_main.html b/install/update/new/adm/style/installer_main.html deleted file mode 100644 index f14fe4d..0000000 --- a/install/update/new/adm/style/installer_main.html +++ /dev/null @@ -1,6 +0,0 @@ - - -

{TITLE}

-

{BODY}

- - diff --git a/install/update/new/adm/style/installer_update.html b/install/update/new/adm/style/installer_update.html deleted file mode 100644 index 48cc07f..0000000 --- a/install/update/new/adm/style/installer_update.html +++ /dev/null @@ -1,13 +0,0 @@ - -

{TITLE}

-

{CONTENT}

- -
-
- {L_SUBMIT} - -
-
- - - diff --git a/install/update/new/adm/style/installer_update_file_status.html b/install/update/new/adm/style/installer_update_file_status.html deleted file mode 100644 index a27bfa6..0000000 --- a/install/update/new/adm/style/installer_update_file_status.html +++ /dev/null @@ -1,80 +0,0 @@ - -

{L_FILES_DELETED}

- -

{L_FILES_DELETED_EXPLAIN}

- -
- {L_STATUS_DELETED} - -
-
{deleted.DIR_PART}{deleted.FILE_PART}
-
- -
- - - - -

{L_FILES_CONFLICT}

- -

{L_FILES_CONFLICT_EXPLAIN}

- -
- {L_STATUS_CONFLICT} - -
-
{conflict.DIR_PART}{conflict.FILE_PART}
-
- -
- - - - -

{L_FILES_MODIFIED}

- -

{L_FILES_MODIFIED_EXPLAIN}

- -
- {L_STATUS_MODIFIED} - -
-
{modified.DIR_PART}{modified.FILE_PART}
-
- -
- - - - -

{L_FILES_NEW}

- -

{L_FILES_NEW_EXPLAIN}

- - - - - - -

{L_FILES_NOT_MODIFIED}

- -

{L_FILES_NOT_MODIFIED_EXPLAIN}

- - - - diff --git a/install/update/new/adm/style/overall_footer.html b/install/update/new/adm/style/overall_footer.html deleted file mode 100644 index 7a5b620..0000000 --- a/install/update/new/adm/style/overall_footer.html +++ /dev/null @@ -1,46 +0,0 @@ -
-
-
-
-
- - -
- - - - - - - - -{$SCRIPTS} - - - diff --git a/install/update/new/adm/style/overall_header.html b/install/update/new/adm/style/overall_header.html deleted file mode 100644 index fa361d6..0000000 --- a/install/update/new/adm/style/overall_header.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - -{META} -{PAGE_TITLE} - - - - - - - - -{$STYLESHEETS} - - - - - - - - - -
- - -
-
- -
- -
-
- - - -
- -
-
- {% if CONTAINER_EXCEPTION !== false %} -
-

{{ lang('CONTAINER_EXCEPTION') }}


-

{{ lang('EXCEPTION') }}{{ lang('COLON') }} {{ CONTAINER_EXCEPTION.getMessage() }}

-
{{ CONTAINER_EXCEPTION.getTraceAsString() }}
-
- {% endif %} diff --git a/install/update/new/adm/style/permission_forum_copy.html b/install/update/new/adm/style/permission_forum_copy.html deleted file mode 100644 index 0560648..0000000 --- a/install/update/new/adm/style/permission_forum_copy.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - -

{L_ACP_FORUM_PERMISSIONS_COPY}

- -

{L_ACP_FORUM_PERMISSIONS_COPY_EXPLAIN}

- -
- -
- {L_LOOK_UP_FORUM} - -
-

{L_COPY_PERMISSIONS_FORUM_FROM_EXPLAIN}
-
-
-
- -
- {L_LOOK_UP_FORUM} -

{L_LOOK_UP_FORUMS_EXPLAIN}

- -
-

{L_COPY_PERMISSIONS_FORUM_TO_EXPLAIN}
-
-
-
- -
- {L_SUBMIT} -   - - {S_HIDDEN_FIELDS} - {S_FORM_TOKEN} -
- -
- - diff --git a/install/update/new/adm/style/permission_mask.html b/install/update/new/adm/style/permission_mask.html deleted file mode 100644 index 26aa5e0..0000000 --- a/install/update/new/adm/style/permission_mask.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - -
-

{p_mask.NAME} [{p_mask.L_ACL_TYPE}]

- - -
-
- - - - - - {p_mask.f_mask.PADDING}{p_mask.f_mask.PADDING}{p_mask.f_mask.NAME} - - - -
-
- {% if p_mask.f_mask.role_options %} -
- -
- {% else %} -
{L_NO_ROLE_AVAILABLE}
- {% endif %} -
- - - - - -
- - - diff --git a/install/update/new/adm/style/permissions.js b/install/update/new/adm/style/permissions.js deleted file mode 100644 index af8e21a..0000000 --- a/install/update/new/adm/style/permissions.js +++ /dev/null @@ -1,304 +0,0 @@ -/** -* Hide and show all checkboxes -* status = true (show boxes), false (hide boxes) -*/ -function display_checkboxes(status) { - var form = document.getElementById('set-permissions'); - var cb = document.getElementsByTagName('input'); - var display; - - //show - if (status) { - display = 'inline'; - } - //hide - else { - display = 'none'; - } - - for (var i = 0; i < cb.length; i++ ) { - if (cb[i].className === 'permissions-checkbox') { - cb[i].style.display = display; - } - } -} - -/** -* Change opacity of element -* e = element -* value = 0 (hidden) till 10 (fully visible) -*/ -function set_opacity(e, value) { - e.style.opacity = value/10; - - //IE opacity currently turned off, because of its astronomical stupidity - //e.style.filter = 'alpha(opacity=' + value*10 + ')'; -} - -/** -* Reset the opacity and checkboxes -* block_id = id of the element that needs to be toggled -*/ -function toggle_opacity(block_id) { - var cb = document.getElementById('checkbox' + block_id); - var fs = document.getElementById('perm' + block_id); - - if (cb.checked) { - set_opacity(fs, 5); - } else { - set_opacity(fs, 10); - } -} - -/** -* Reset the opacity and checkboxes -* value = 0 (checked) and 1 (unchecked) -* except_id = id of the element not to hide -*/ -function reset_opacity(status, except_id) { - var perm = document.getElementById('set-permissions'); - var fs = perm.getElementsByTagName('fieldset'); - var opacity = 5; - - if (status) { - opacity = 10; - } - - for (var i = 0; i < fs.length; i++ ) { - if (fs[i].className !== 'quick') { - set_opacity(fs[i], opacity); - } - } - - if (typeof(except_id) !== 'undefined') { - set_opacity(document.getElementById('perm' + except_id), 10); - } - - //reset checkboxes too - marklist('set-permissions', 'inherit', !status); -} - -/** -* Check whether we have a full radiobutton row of true -* index = offset for the row of inputs (0 == first row, 1 == second, 2 == third), -* rb = array of radiobuttons -*/ -function get_radio_status(index, rb) { - for (var i = index; i < rb.length; i = i + 3 ) { - if (rb[i].checked !== true) { - if (i > index) { - //at least one is true, but not all (custom) - return 2; - } - //first one is not true - return 0; - } - } - - // all radiobuttons true - return 1; -} - -/** -* Set tab colours -* id = panel the tab needs to be set for, -* init = initialising on open, -* quick = If no calculation needed, this contains the colour -*/ -function set_colours(id, init, quick) { - var table = document.getElementById('table' + id); - var tab = document.getElementById('tab' + id); - - if (typeof(quick) !== 'undefined') { - tab.className = 'permissions-preset-' + quick + ' activetab'; - return; - } - - var rb = table.getElementsByTagName('input'); - var colour = 'custom'; - - var status = get_radio_status(0, rb); - - if (status === 1) { - colour = 'yes'; - } else if (status === 0) { - // We move on to No - status = get_radio_status(1, rb); - - if (status === 1) { - colour = 'no'; - } else if (status === 0) { - // We move on to Never - status = get_radio_status(2, rb); - - if (status === 1) { - colour = 'never'; - } - } - } - - if (init) { - tab.className = 'permissions-preset-' + colour; - } else { - tab.className = 'permissions-preset-' + colour + ' activetab'; - } -} - -/** -* Initialise advanced tab colours on first load -* block_id = block that is opened -*/ -function init_colours(block_id) { - var block = document.getElementById('advanced' + block_id); - var panels = block.getElementsByTagName('div'); - var tab = document.getElementById('tab' + id); - - for (var i = 0; i < panels.length; i++) { - if (panels[i].className === 'permissions-panel') { - set_colours(panels[i].id.replace(/options/, ''), true); - } - } - - tab.className = tab.className + ' activetab'; -} - -/** -* Show/hide option panels -* value = suffix for ID to show -* adv = we are opening advanced permissions -* view = called from view permissions -*/ -function swap_options(pmask, fmask, cat, adv, view) { - id = pmask + fmask + cat; - active_option = active_pmask + active_fmask + active_cat; - - var old_tab = document.getElementById('tab' + active_option); - var new_tab = document.getElementById('tab' + id); - var adv_block = document.getElementById('advanced' + pmask + fmask); - - if (adv_block.style.display === 'block' && adv === true) { - phpbb.toggleDisplay('advanced' + pmask + fmask, -1); - reset_opacity(1); - display_checkboxes(false); - return; - } - - // no need to set anything if we are clicking on the same tab again - if (new_tab === old_tab && !adv) { - return; - } - - // init colours - if (adv && (pmask + fmask) !== (active_pmask + active_fmask)) { - init_colours(pmask + fmask); - display_checkboxes(true); - reset_opacity(1); - } else if (adv) { - //Checkbox might have been clicked, but we need full visibility - display_checkboxes(true); - reset_opacity(1); - } - - // set active tab - old_tab.className = old_tab.className.replace(/\ activetab/g, ''); - new_tab.className = new_tab.className + ' activetab'; - - if (id === active_option && adv !== true) { - return; - } - - phpbb.toggleDisplay('options' + active_option, -1); - - //hiding and showing the checkbox - if (document.getElementById('checkbox' + active_pmask + active_fmask)) { - phpbb.toggleDisplay('checkbox' + pmask + fmask, -1); - - if ((pmask + fmask) !== (active_pmask + active_fmask)) { - document.getElementById('checkbox' + active_pmask + active_fmask).style.display = 'inline'; - } - } - - if (!view) { - phpbb.toggleDisplay('advanced' + active_pmask + active_fmask, -1); - } - - if (!view) { - phpbb.toggleDisplay('advanced' + pmask + fmask, 1); - } - phpbb.toggleDisplay('options' + id, 1); - - active_pmask = pmask; - active_fmask = fmask; - active_cat = cat; -} - -/** -* Mark all radio buttons in one panel -* id = table ID container, s = status ['y'/'u'/'n'] -*/ -function mark_options(id, s) { - var t = document.getElementById(id); - - if (!t) { - return; - } - - var rb = t.getElementsByTagName('input'); - - for (var r = 0; r < rb.length; r++) { - if (rb[r].id.substr(rb[r].id.length-1) === s) { - rb[r].checked = true; - } - } -} - -function mark_one_option(id, field_name, s) { - var t = document.getElementById(id); - - if (!t) { - return; - } - - var rb = t.getElementsByTagName('input'); - - for (var r = 0; r < rb.length; r++) { - if (rb[r].id.substr(rb[r].id.length-field_name.length-3, field_name.length) === field_name && rb[r].id.substr(rb[r].id.length-1) === s) { - rb[r].checked = true; - } - } -} - -/** -* Reset role dropdown field to Select role... if an option gets changed -*/ -function reset_role(id) { - var t = document.getElementById(id); - - if (!t) { - return; - } - - 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'; -} - -/** -* Load role and set options accordingly -*/ -function set_role_settings(role_id, target_id) { - settings = role_options[role_id]; - - if (!settings) { - return; - } - - // Mark all options to no (unset) first... - mark_options(target_id, 'u'); - - for (var r in settings) { - mark_one_option(target_id, r, (settings[r] === 1) ? 'y' : 'n'); - } -} diff --git a/install/update/new/adm/style/progress_bar.html b/install/update/new/adm/style/progress_bar.html deleted file mode 100644 index 1e58257..0000000 --- a/install/update/new/adm/style/progress_bar.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - -
-

{L_PROGRESS}

- {L_PROGRESS} -

{L_PROGRESS_EXPLAIN}

-
- - - - diff --git a/install/update/new/adm/style/simple_footer.html b/install/update/new/adm/style/simple_footer.html deleted file mode 100644 index dd9dc90..0000000 --- a/install/update/new/adm/style/simple_footer.html +++ /dev/null @@ -1,27 +0,0 @@ - -

-
- - - - - - - - -{$SCRIPTS} - - - diff --git a/install/update/new/adm/style/simple_header.html b/install/update/new/adm/style/simple_header.html deleted file mode 100644 index a8a32bf..0000000 --- a/install/update/new/adm/style/simple_header.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - -{META} -{PAGE_TITLE} - - - - - -{$STYLESHEETS} - - - - - - - -
diff --git a/install/update/new/assets/cookieconsent/cookieconsent.min.css b/install/update/new/assets/cookieconsent/cookieconsent.min.css deleted file mode 100644 index d4d4390..0000000 --- a/install/update/new/assets/cookieconsent/cookieconsent.min.css +++ /dev/null @@ -1,6 +0,0 @@ -.cc-window{opacity:1;-webkit-transition:opacity 1s ease;transition:opacity 1s ease}.cc-window.cc-invisible{opacity:0}.cc-animate.cc-revoke{-webkit-transition:transform 1s ease;-webkit-transition:-webkit-transform 1s ease;transition:-webkit-transform 1s ease;transition:transform 1s ease;transition:transform 1s ease,-webkit-transform 1s ease}.cc-animate.cc-revoke.cc-top{-webkit-transform:translateY(-2em);transform:translateY(-2em)}.cc-animate.cc-revoke.cc-bottom{-webkit-transform:translateY(2em);transform:translateY(2em)}.cc-animate.cc-revoke.cc-active.cc-top{-webkit-transform:translateY(0);transform:translateY(0)}.cc-animate.cc-revoke.cc-active.cc-bottom{-webkit-transform:translateY(0);transform:translateY(0)}.cc-revoke:hover{-webkit-transform:translateY(0);transform:translateY(0)}.cc-grower{max-height:0;overflow:hidden;-webkit-transition:max-height 1s;transition:max-height 1s} -.cc-revoke,.cc-window{position:fixed;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:Helvetica,Calibri,Arial,sans-serif;font-size:16px;line-height:1.5em;display:-webkit-box;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;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner{padding:1em 1.8em;width:100%;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.cc-revoke{padding:.5em}.cc-revoke:hover{text-decoration:underline}.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;text-decoration:underline}.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-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{-webkit-box-flex:1;-ms-flex:1 0 auto;flex:1 0 auto}.cc-window.cc-banner{-webkit-box-align:center;-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{display:block;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;max-width:100%;margin-right:1em}.cc-compliance{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:justify;align-content:space-between}.cc-floating .cc-compliance>.cc-btn{-webkit-box-flex:1;-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-floating,.cc-window.cc-left,.cc-window.cc-right{left:0;right:0}.cc-window.cc-banner{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner .cc-compliance{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto}.cc-window.cc-floating{max-width:none}.cc-window .cc-message{margin-bottom:1em}.cc-window.cc-banner{-webkit-box-align:unset;-ms-flex-align:unset;align-items:unset}.cc-window.cc-banner .cc-message{margin-right:0}} -.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;-webkit-box-flex:0;-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;margin-bottom: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/install/update/new/assets/cookieconsent/cookieconsent.min.js b/install/update/new/assets/cookieconsent/cookieconsent.min.js deleted file mode 100644 index 1e3dccf..0000000 --- a/install/update/new/assets/cookieconsent/cookieconsent.min.js +++ /dev/null @@ -1 +0,0 @@ -!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){return e.replace(/{{([a-z][a-z0-9\-_]*)}}/gi,function(e){return t(arguments[1])||""})},getCookie:function(e){var t=("; "+document.cookie).split("; "+e+"=");return t.length<2?void 0:t.pop().split(";").shift()},setCookie:function(e,t,i,n,o,s){var r=new Date;r.setHours(r.getHours()+24*(i||365));var a=[e+"="+t,"expires="+r.toUTCString(),"path="+(o||"/")];n&&a.push("domain="+n),s&&a.push("secure"),document.cookie=a.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=0;if(0===e.length)return n;for(t=0,i=e.length;t=128?"#000":"#fff"},getLuminance:function(e){var t=parseInt(this.normaliseHex(e),16),i=38+(t>>16),n=38+(t>>8&255),o=38+(255&t);return"#"+(16777216+65536*(i<255?i<1?0:i:255)+256*(n<255?n<1?0:n:255)+(o<255?o<1?0:o:255)).toString(16).slice(1)},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},traverseDOMPath:function(e,i){return e&&e.parentNode?t.hasClass(e,i)?e:this.traverseDOMPath(e.parentNode,i):null}};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)&&void 0!==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(){var n={enabled:!0,container:null,cookie:{name:"cookieconsent_status",path:"/",domain:"",expiryDays:365,secure:!1},onPopupOpen:function(){},onPopupClose:function(){},onInitialise:function(e){},onStatusChange:function(e,t){},onRevokeChoice:function(){},onNoCookieLaw:function(e,t){},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:"https://www.cookiesandyou.com",close:"❌",target:"_blank",policy:"Cookie Policy"},elements:{header:'{{header}} ',message:'{{message}}',messagelink:'{{message}} {{link}}',dismiss:'{{dismiss}}',allow:'{{allow}}',deny:'{{deny}}',link:'{{link}}',close:'{{close}}'},window:'',revokeBtn:'
{{policy}}
',compliance:{info:'
{{dismiss}}
',"opt-in":'
{{deny}}{{allow}}
',"opt-out":'
{{deny}}{{allow}}
'},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,dismissOnWindowClick:!1,ignoreClicksFrom:["cc-revoke","cc-btn"],autoOpen:!0,autoAttach:!0,whitelistPage:[],blacklistPage:[],overrideHTML:null};function o(){this.initialise.apply(this,arguments)}function s(e){this.openingTimeout=null,t.removeClass(e,"cc-invisible")}function r(t){t.style.display="none",t.removeEventListener(e.transitionEnd,this.afterTransition),this.afterTransition=null}function a(){var e=this.options.position.split("-"),t=[];return e.forEach(function(e){t.push("cc-"+e)}),t}function c(n){var o=this.options,s=document.createElement("div"),r=o.container&&1===o.container.nodeType?o.container:document.body;s.innerHTML=n;var a=s.children[0];return a.style.display="none",t.hasClass(a,"cc-window")&&e.hasTransition&&t.addClass(a,"cc-invisible"),this.onButtonClick=function(n){var o=t.traverseDOMPath(n.target,"cc-btn")||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()}.bind(this),a.addEventListener("click",this.onButtonClick),o.autoAttach&&(r.firstChild?r.insertBefore(a,r.firstChild):r.appendChild(a)),a}function l(e){return"000000"==(e=t.normaliseHex(e))?"#222":t.getLuminance(e)}function u(e,t){for(var i=0,n=e.length;i=0;o&&t(n);return o}.call(this)&&(this.options.enabled=!1),u(this.options.blacklistPage,location.pathname)&&(this.options.enabled=!1),u(this.options.whitelistPage,location.pathname)&&(this.options.enabled=!0);var o=this.options.window.replace("{{classes}}",function(){var i=this.options,n="top"==i.position||"bottom"==i.position?"banner":"floating";t.isMobile()&&(n="floating");var o=["cc-"+n,"cc-type-"+i.type,"cc-theme-"+i.theme];i.static&&o.push("cc-static");o.push.apply(o,a.call(this));(function(i){var n=t.hash(JSON.stringify(i)),o="cc-color-override-"+n,s=t.isPlainObject(i);this.customStyleSelector=s?o:null,s&&function(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],a.padding&&s[o+" .cc-btn"].push("padding: "+a.padding),"transparent"!=a.background&&(s[o+" .cc-btn:hover, "+o+" .cc-btn:focus"]=["background-color: "+(a.hover||l(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 u=document.createElement("style");document.head.appendChild(u),e.customStyles[i]={references:1,element:u.sheet};var h=-1;for(var p in s)s.hasOwnProperty(p)&&u.sheet.insertRule(p+"{"+s[p].join(";")+"}",++h)}(n,i,"."+o);return s}).call(this,this.options.palette);this.customStyleSelector&&o.push(this.customStyleSelector);return o}.call(this).join(" ")).replace("{{children}}",function(){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];o||(o=i.layouts.basic);return t.interpolateString(o,function(t){return e[t]})}.call(this)),s=this.options.overrideHTML;if("string"==typeof s&&s.length&&(o=s),this.options.static){var r=c.call(this,'
'+o+"
");r.style.display="",this.element=r.firstChild,this.element.style.display="none",t.addClass(this.element,"cc-invisible")}else this.element=c.call(this,o);(function(){var i=this.setStatus.bind(this),n=this.close.bind(this),o=this.options.dismissOnTimeout;"number"==typeof o&&o>=0&&(this.dismissTimeout=window.setTimeout(function(){i(e.status.dismiss),n(!0)},Math.floor(o)));var s=this.options.dismissOnScroll;if("number"==typeof s&&s>=0){var r=function(t){window.pageYOffset>Math.floor(s)&&(i(e.status.dismiss),n(!0),window.removeEventListener("scroll",r),this.onWindowScroll=null)};this.options.enabled&&(this.onWindowScroll=r,window.addEventListener("scroll",r))}var a=this.options.dismissOnWindowClick,c=this.options.ignoreClicksFrom;if(a){var l=function(o){for(var s=!1,r=o.path.length,a=c.length,u=0;uo&&(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)}}}.call(this),this.options.autoOpen&&this.autoOpen()},o.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.onWindowClick&&(window.removeEventListener("click",this.onWindowClick),this.onWindowClick=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,function(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}}}(this.options.palette),this.options=null},o.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},o.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},o.prototype.fadeIn=function(){var i=this.element;if(e.hasTransition&&i&&(this.afterTransition&&r.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"}this.openingTimeout=setTimeout(s.bind(this,i),20)}},o.prototype.fadeOut=function(){var i=this.element;e.hasTransition&&i&&(this.openingTimeout&&(clearTimeout(this.openingTimeout),s.bind(this,i)),t.hasClass(i,"cc-invisible")||(this.options.static&&(this.element.parentNode.style.maxHeight=""),this.afterTransition=r.bind(this,i),i.addEventListener(e.transitionEnd,this.afterTransition),t.addClass(i,"cc-invisible")))},o.prototype.isOpen=function(){return this.element&&""==this.element.style.display&&(!e.hasTransition||!t.hasClass(this.element,"cc-invisible"))},o.prototype.toggleRevokeButton=function(e){this.revokeBtn&&(this.revokeBtn.style.display=e?"":"none")},o.prototype.revokeChoice=function(e){this.options.enabled=!0,this.clearStatus(),this.options.onRevokeChoice.call(this),e||this.autoOpen()},o.prototype.hasAnswered=function(t){return Object.keys(e.status).indexOf(this.getStatus())>=0},o.prototype.hasConsented=function(t){var i=this.getStatus();return i==e.status.allow||i==e.status.dismiss},o.prototype.autoOpen=function(e){!this.hasAnswered()&&this.options.enabled?this.open():this.hasAnswered()&&this.options.revokable&&this.toggleRevokeButton(!0)},o.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,n.secure),this.options.onStatusChange.call(this,i,s)):this.clearStatus()},o.prototype.getStatus=function(){return t.getCookie(this.options.cookie.name)},o.prototype.clearStatus=function(){var e=this.options.cookie;t.setCookie(e.name,"",-1,e.domain,e.path)},o}(),e.Location=function(){var e={timeout:5e3,services:["ipinfo"],serviceDefinitions:{ipinfo:function(){return{url:"//ipinfo.io",headers:["Accept: application/json"],callback:function(e,t){try{var i=JSON.parse(t);return i.error?s(i):{code:i.country}}catch(e){return s({error:"Invalid response ("+e+")"})}}}},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?s({error:i.statusMessage}):{code:i.countryCode}}catch(e){return s({error:"Invalid response ("+e+")"})}}}},maxmind:function(){return{url:"//js.maxmind.com/js/apis/geoip2/v2.1/geoip2.js",isScript:!0,callback:function(e){window.geoip2?geoip2.country(function(t){try{e({code:t.country.iso_code})}catch(t){e(s(t))}},function(t){e(s(t))}):e(new Error("Unexpected response format. The downloaded script should have exported `geoip2` to the global scope"))}}}}};function i(i){t.deepExtend(this.options={},e),t.isPlainObject(i)&&t.deepExtend(this.options,i),this.currentServiceIndex=-1}function n(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 o(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("Content-type","application/x-www-form-urlencoded"),Array.isArray(o))for(var r=0,a=o.length;r3&&t(s)}),s.send(n)}function s(e){return new Error("Error ["+(e.code||"UNKNOWN")+"]: "+e.error)}return i.prototype.getNextService=function(){var e;do{e=this.getServiceByIdx(++this.currentServiceIndex)}while(this.currentServiceIndex=0,revokable:t.revokable.indexOf(e)>=0,explicitAction:t.explicitAction.indexOf(e)>=0}},i.prototype.applyLaw=function(e,t){var i=this.get(t);return i.hasLaw||(e.enabled=!1,"function"==typeof e.onNoCookieLaw&&e.onNoCookieLaw(t,i)),this.options.regionalLaw&&(i.revokable&&(e.revokable=!0),i.explicitAction&&(e.dismissOnScroll=!1,e.dismissOnTimeout=!1)),e},i}(),e.initialise=function(i,n,o){var s=new e.Law(i.law);n||(n=function(){}),o||(o=function(){});var r=Object.keys(e.status),a=t.getCookie("cookieconsent_status");r.indexOf(a)>=0?n(new e.Popup(i)):e.getCountryCode(i,function(t){delete i.law,delete i.location,t.code&&(i=s.applyLaw(i,t.code)),n(new e.Popup(i))},function(t){delete i.law,delete i.location,o(t,new e.Popup(i))})},e.getCountryCode=function(t,i,n){t.law&&t.law.countryCode?i({code:t.law.countryCode}):t.location?new e.Location(t.location).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/install/update/new/assets/javascript/core.js b/install/update/new/assets/javascript/core.js deleted file mode 100644 index bedbd23..0000000 --- a/install/update/new/assets/javascript/core.js +++ /dev/null @@ -1,1823 +0,0 @@ -/* global bbfontstyle */ - -var phpbb = {}; -phpbb.alertTime = 100; - -(function($) { // Avoid conflicts with other libraries - -'use strict'; - -// define a couple constants for keydown functions. -var keymap = { - TAB: 9, - ENTER: 13, - ESC: 27, - ARROW_UP: 38, - ARROW_DOWN: 40 -}; - -var $dark = $('#darkenwrapper'); -var $loadingIndicator; -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 - * - * @returns {object} Returns loadingIndicator. - */ -phpbb.loadingIndicator = function() { - if (!$loadingIndicator) { - $loadingIndicator = $('
', { - 'id': 'loading_indicator', - 'class': 'loading_indicator' - }); - $loadingIndicator.appendTo('#page-footer'); - } - - if (!$loadingIndicator.is(':visible')) { - $loadingIndicator.fadeIn(phpbb.alertTime); - // Wait 60 seconds and display an error if nothing has been returned by then. - phpbb.clearLoadingTimeout(); - phpbbAlertTimer = setTimeout(function() { - phpbb.showTimeoutMessage(); - }, 60000); - } - - return $loadingIndicator; -}; - -/** - * Show timeout message - */ -phpbb.showTimeoutMessage = function () { - var $alert = $('#phpbb_alert'); - - if ($loadingIndicator.is(':visible')) { - phpbb.alert($alert.attr('data-l-err'), $alert.attr('data-l-timeout-processing-req')); - } -}; - -/** - * Clear loading alert timeout -*/ -phpbb.clearLoadingTimeout = function() { - if (phpbbAlertTimer !== null) { - clearTimeout(phpbbAlertTimer); - phpbbAlertTimer = null; - } -}; - - -/** -* Close popup alert after a specified delay -* -* @param {int} delay Delay in ms until darkenwrapper's click event is triggered -*/ -phpbb.closeDarkenWrapper = function(delay) { - phpbbAlertTimer = setTimeout(function() { - $('#darkenwrapper').trigger('click'); - }, delay); -}; - -/** - * Display a simple alert similar to JSs native alert(). - * - * You can only call one alert or confirm box at any one time. - * - * @param {string} title Title of the message, eg "Information" (HTML). - * @param {string} msg Message to display (HTML). - * - * @returns {object} Returns the div created. - */ -phpbb.alert = function(title, msg) { - var $alert = $('#phpbb_alert'); - $alert.find('.alert_title').html(title); - $alert.find('.alert_text').html(msg); - - $(document).on('keydown.phpbb.alert', function(e) { - if (e.keyCode === keymap.ENTER || e.keyCode === keymap.ESC) { - phpbb.alert.close($alert, true); - e.preventDefault(); - e.stopPropagation(); - } - }); - phpbb.alert.open($alert); - - return $alert; -}; - -/** -* Handler for opening an alert box. -* -* @param {jQuery} $alert jQuery object. -*/ -phpbb.alert.open = function($alert) { - if (!$dark.is(':visible')) { - $dark.fadeIn(phpbb.alertTime); - } - - if ($loadingIndicator && $loadingIndicator.is(':visible')) { - $loadingIndicator.fadeOut(phpbb.alertTime, function() { - $dark.append($alert); - $alert.fadeIn(phpbb.alertTime); - }); - } else if ($dark.is(':visible')) { - $dark.append($alert); - $alert.fadeIn(phpbb.alertTime); - } else { - $dark.append($alert); - $alert.show(); - $dark.fadeIn(phpbb.alertTime); - } - - $alert.on('click', function(e) { - e.stopPropagation(); - }); - - $dark.one('click', function(e) { - phpbb.alert.close($alert, true); - e.preventDefault(); - e.stopPropagation(); - }); - - $alert.find('.alert_close').one('click', function(e) { - phpbb.alert.close($alert, true); - e.preventDefault(); - }); -}; - -/** -* Handler for closing an alert box. -* -* @param {jQuery} $alert jQuery object. -* @param {bool} fadedark Whether to remove dark background. -*/ -phpbb.alert.close = function($alert, fadedark) { - var $fade = (fadedark) ? $dark : $alert; - - $fade.fadeOut(phpbb.alertTime, function() { - $alert.hide(); - }); - - $alert.find('.alert_close').off('click'); - $(document).off('keydown.phpbb.alert'); -}; - -/** - * Display a simple yes / no box to the user. - * - * You can only call one alert or confirm box at any one time. - * - * @param {string} msg Message to display (HTML). - * @param {function} callback Callback. Bool param, whether the user pressed - * yes or no (or whatever their language is). - * @param {bool} fadedark Remove the dark background when done? Defaults - * to yes. - * - * @returns {object} Returns the div created. - */ -phpbb.confirm = function(msg, callback, fadedark) { - var $confirmDiv = $('#phpbb_confirm'); - $confirmDiv.find('.alert_text').html(msg); - fadedark = typeof fadedark !== 'undefined' ? fadedark : true; - - $(document).on('keydown.phpbb.alert', function(e) { - if (e.keyCode === keymap.ENTER || e.keyCode === keymap.ESC) { - var name = (e.keyCode === keymap.ENTER) ? 'confirm' : 'cancel'; - - $('input[name="' + name + '"]').trigger('click'); - e.preventDefault(); - e.stopPropagation(); - } - }); - - $confirmDiv.find('input[type="button"]').one('click.phpbb.confirmbox', function(e) { - var confirmed = this.name === 'confirm'; - - callback(confirmed); - $confirmDiv.find('input[type="button"]').off('click.phpbb.confirmbox'); - phpbb.alert.close($confirmDiv, fadedark || !confirmed); - - e.preventDefault(); - e.stopPropagation(); - }); - - phpbb.alert.open($confirmDiv); - - return $confirmDiv; -}; - -/** - * Turn a querystring into an array. - * - * @argument {string} string The querystring to parse. - * @returns {object} The object created. - */ -phpbb.parseQuerystring = function(string) { - var params = {}, i, split; - - string = string.split('&'); - for (i = 0; i < string.length; i++) { - split = string[i].split('='); - params[split[0]] = decodeURIComponent(split[1]); - } - return params; -}; - - -/** - * Makes a link use AJAX instead of loading an entire page. - * - * This function will work for links (both standard links and links which - * invoke confirm_box) and forms. It will be called automatically for links - * and forms with the data-ajax attribute set, and will call the necessary - * callback. - * - * For more info, view the following page on the phpBB wiki: - * http://wiki.phpbb.com/JavaScript_Function.phpbb.ajaxify - * - * @param {object} options Options. - */ -phpbb.ajaxify = function(options) { - var $elements = $(options.selector), - refresh = options.refresh, - callback = options.callback, - overlay = (typeof options.overlay !== 'undefined') ? options.overlay : true, - isForm = $elements.is('form'), - isText = $elements.is('input[type="text"], textarea'), - eventName; - - if (isForm) { - eventName = 'submit'; - } else if (isText) { - eventName = 'keyup'; - } else { - eventName = 'click'; - } - - $elements.on(eventName, function(event) { - var action, method, data, submit, that = this, $this = $(this); - - if ($this.find('input[type="submit"][data-clicked]').attr('data-ajax') === 'false') { - 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 responseText, errorText = false; - try { - responseText = JSON.parse(jqXHR.responseText); - responseText = responseText.message; - } catch (e) {} - if (typeof responseText === 'string' && responseText.length > 0) { - errorText = responseText; - } else 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) { - var alert; - - phpbb.clearLoadingTimeout(); - - // Is a confirmation required? - if (typeof res.S_CONFIRM_ACTION === 'undefined') { - // If a confirmation is not required, display an alert and call the - // callbacks. - if (typeof res.MESSAGE_TITLE !== 'undefined') { - alert = phpbb.alert(res.MESSAGE_TITLE, res.MESSAGE_TEXT); - } else { - $dark.fadeOut(phpbb.alertTime); - - if ($loadingIndicator) { - $loadingIndicator.fadeOut(phpbb.alertTime); - } - } - - if (typeof phpbb.ajaxCallbacks[callback] === 'function') { - phpbb.ajaxCallbacks[callback].call(that, res); - } - - // If the server says to refresh the page, check whether the page should - // be refreshed and refresh page after specified time if required. - if (res.REFRESH_DATA) { - if (typeof refresh === 'function') { - refresh = refresh(res.REFRESH_DATA.url); - } else if (typeof refresh !== 'boolean') { - refresh = false; - } - - phpbbAlertTimer = setTimeout(function() { - if (refresh) { - window.location = res.REFRESH_DATA.url; - } - - // Hide the alert even if we refresh the page, in case the user - // presses the back button. - $dark.fadeOut(phpbb.alertTime, function() { - if (typeof alert !== 'undefined') { - alert.hide(); - } - }); - }, res.REFRESH_DATA.time * 1000); // Server specifies time in seconds - } - } else { - // If confirmation is required, display a dialog to the user. - phpbb.confirm(res.MESSAGE_BODY, function(del) { - if (!del) { - return; - } - - phpbb.loadingIndicator(); - data = $('
' + res.S_HIDDEN_FIELDS + '
').serialize(); - $.ajax({ - url: res.S_CONFIRM_ACTION, - type: 'POST', - data: data + '&confirm=' + res.YES_VALUE + '&' + $('form', '#phpbb_confirm').serialize(), - success: returnHandler, - error: errorHandler - }); - }, false); - } - } - - // If the element is a form, POST must be used and some extra data must - // be taken from the form. - var runFilter = (typeof options.filter === 'function'); - data = {}; - - if (isForm) { - action = $this.attr('action').replace('&', '&'); - data = $this.serializeArray(); - method = $this.attr('method') || 'GET'; - - if ($this.find('input[type="submit"][data-clicked]')) { - submit = $this.find('input[type="submit"][data-clicked]'); - data.push({ - name: submit.attr('name'), - value: submit.val() - }); - } - } else if (isText) { - var name = $this.attr('data-name') || this.name; - action = $this.attr('data-url').replace('&', '&'); - data[name] = this.value; - method = 'POST'; - } else { - action = this.href; - data = null; - method = 'GET'; - } - - var sendRequest = function() { - var dataOverlay = $this.attr('data-overlay'); - if (overlay && (typeof dataOverlay === 'undefined' || dataOverlay === 'true')) { - phpbb.loadingIndicator(); - } - - var request = $.ajax({ - url: action, - type: method, - data: data, - success: returnHandler, - error: errorHandler, - cache: false - }); - - request.always(function() { - if ($loadingIndicator && $loadingIndicator.is(':visible')) { - $loadingIndicator.fadeOut(phpbb.alertTime); - } - }); - }; - - // If filter function returns false, cancel the AJAX functionality, - // and return true (meaning that the HTTP request will be sent normally). - if (runFilter && !options.filter.call(this, data, event, sendRequest)) { - return; - } - - sendRequest(); - event.preventDefault(); - }); - - if (isForm) { - $elements.find('input:submit').click(function () { - var $this = $(this); - - // Remove data-clicked attribute from any submit button of form - $this.parents('form:first').find('input:submit[data-clicked]').removeAttr('data-clicked'); - - $this.attr('data-clicked', 'true'); - }); - } - - return this; -}; - -phpbb.search = { - cache: { - data: [] - }, - tpl: [], - container: [] -}; - -/** - * Get cached search data. - * - * @param {string} id Search ID. - * @returns {bool|object} Cached data object. Returns false if no data exists. - */ -phpbb.search.cache.get = function(id) { - if (this.data[id]) { - return this.data[id]; - } - return false; -}; - -/** - * Set search cache data value. - * - * @param {string} id Search ID. - * @param {string} key Data key. - * @param {string} value Data value. - */ -phpbb.search.cache.set = function(id, key, value) { - if (!this.data[id]) { - this.data[id] = { results: [] }; - } - this.data[id][key] = value; -}; - -/** - * Cache search result. - * - * @param {string} id Search ID. - * @param {string} keyword Keyword. - * @param {Array} results Search results. - */ -phpbb.search.cache.setResults = function(id, keyword, results) { - this.data[id].results[keyword] = results; -}; - -/** - * Trim spaces from keyword and lower its case. - * - * @param {string} keyword Search keyword to clean. - * @returns {string} Cleaned string. - */ -phpbb.search.cleanKeyword = function(keyword) { - return $.trim(keyword).toLowerCase(); -}; - -/** - * Get clean version of search keyword. If textarea supports several keywords - * (one per line), it fetches the current keyword based on the caret position. - * - * @param {jQuery} $input Search input|textarea. - * @param {string} keyword Input|textarea value. - * @param {bool} multiline Whether textarea supports multiple search keywords. - * - * @returns string Clean string. - */ -phpbb.search.getKeyword = function($input, keyword, multiline) { - if (multiline) { - var line = phpbb.search.getKeywordLine($input); - keyword = keyword.split('\n').splice(line, 1); - } - return phpbb.search.cleanKeyword(keyword); -}; - -/** - * Get the textarea line number on which the keyword resides - for textareas - * that support multiple keywords (one per line). - * - * @param {jQuery} $textarea Search textarea. - * @returns {int} The line number. - */ -phpbb.search.getKeywordLine = function ($textarea) { - var selectionStart = $textarea.get(0).selectionStart; - return $textarea.val().substr(0, selectionStart).split('\n').length - 1; -}; - -/** - * Set the value on the input|textarea. If textarea supports multiple - * keywords, only the active keyword is replaced. - * - * @param {jQuery} $input Search input|textarea. - * @param {string} value Value to set. - * @param {bool} multiline Whether textarea supports multiple search keywords. - */ -phpbb.search.setValue = function($input, value, multiline) { - if (multiline) { - var line = phpbb.search.getKeywordLine($input), - lines = $input.val().split('\n'); - lines[line] = value; - value = lines.join('\n'); - } - $input.val(value); -}; - -/** - * Sets the onclick event to set the value on the input|textarea to the - * selected search result. - * - * @param {jQuery} $input Search input|textarea. - * @param {object} value Result object. - * @param {jQuery} $row Result element. - * @param {jQuery} $container jQuery object for the search container. - */ -phpbb.search.setValueOnClick = function($input, value, $row, $container) { - $row.click(function() { - phpbb.search.setValue($input, value.result, $input.attr('data-multiline')); - phpbb.search.closeResults($input, $container); - }); -}; - -/** - * Runs before the AJAX search request is sent and determines whether - * there is a need to contact the server. If there are cached results - * already, those are displayed instead. Executes the AJAX request function - * itself due to the need to use a timeout to limit the number of requests. - * - * @param {Array} data Data to be sent to the server. - * @param {object} event Onkeyup event object. - * @param {function} sendRequest Function to execute AJAX request. - * - * @returns {boolean} Returns false. - */ -phpbb.search.filter = function(data, event, sendRequest) { - var $this = $(this), - dataName = ($this.attr('data-name') !== undefined) ? $this.attr('data-name') : $this.attr('name'), - minLength = parseInt($this.attr('data-min-length'), 10), - searchID = $this.attr('data-results'), - keyword = phpbb.search.getKeyword($this, data[dataName], $this.attr('data-multiline')), - cache = phpbb.search.cache.get(searchID), - key = event.keyCode || event.which, - proceed = true; - data[dataName] = keyword; - - // No need to search if enter was pressed - // for selecting a value from the results. - if (key === keymap.ENTER) { - return false; - } - - if (cache.timeout) { - clearTimeout(cache.timeout); - } - - var timeout = setTimeout(function() { - // Check min length and existence of cache. - if (minLength > keyword.length) { - proceed = false; - } else if (cache.lastSearch) { - // Has the keyword actually changed? - if (cache.lastSearch === keyword) { - proceed = false; - } else { - // Do we already have results for this? - if (cache.results[keyword]) { - var response = { - keyword: keyword, - results: cache.results[keyword] - }; - phpbb.search.handleResponse(response, $this, true); - proceed = false; - } - - // If the previous search didn't yield results and the string only had characters added to it, - // then we won't bother sending a request. - if (keyword.indexOf(cache.lastSearch) === 0 && cache.results[cache.lastSearch].length === 0) { - phpbb.search.cache.set(searchID, 'lastSearch', keyword); - phpbb.search.cache.setResults(searchID, keyword, []); - proceed = false; - } - } - } - - if (proceed) { - sendRequest.call(this); - } - }, 350); - phpbb.search.cache.set(searchID, 'timeout', timeout); - - return false; -}; - -/** - * Handle search result response. - * - * @param {object} res Data received from server. - * @param {jQuery} $input Search input|textarea. - * @param {bool} fromCache Whether the results are from the cache. - * @param {function} callback Optional callback to run when assigning each search result. - */ -phpbb.search.handleResponse = function(res, $input, fromCache, callback) { - if (typeof res !== 'object') { - return; - } - - var searchID = $input.attr('data-results'), - $container = $(searchID); - - if (this.cache.get(searchID).callback) { - callback = this.cache.get(searchID).callback; - } else if (typeof callback === 'function') { - this.cache.set(searchID, 'callback', callback); - } - - if (!fromCache) { - this.cache.setResults(searchID, res.keyword, res.results); - } - - this.cache.set(searchID, 'lastSearch', res.keyword); - this.showResults(res.results, $input, $container, callback); -}; - -/** - * Show search results. - * - * @param {Array} results Search results. - * @param {jQuery} $input Search input|textarea. - * @param {jQuery} $container Search results container element. - * @param {function} callback Optional callback to run when assigning each search result. - */ -phpbb.search.showResults = function(results, $input, $container, callback) { - var $resultContainer = $('.search-results', $container); - this.clearResults($resultContainer); - - if (!results.length) { - $container.hide(); - return; - } - - var searchID = $container.attr('id'), - tpl, - row; - - if (!this.tpl[searchID]) { - tpl = $('.search-result-tpl', $container); - this.tpl[searchID] = tpl.clone().removeClass('search-result-tpl'); - tpl.remove(); - } - tpl = this.tpl[searchID]; - - $.each(results, function(i, item) { - row = tpl.clone(); - row.find('.search-result').html(item.display); - - if (typeof callback === 'function') { - callback.call(this, $input, item, row, $container); - } - row.appendTo($resultContainer).show(); - }); - $container.show(); - - phpbb.search.navigateResults($input, $container, $resultContainer); -}; - -/** - * Clear search results. - * - * @param {jQuery} $container Search results container. - */ -phpbb.search.clearResults = function($container) { - $container.children(':not(.search-result-tpl)').remove(); -}; - -/** - * Close search results. - * - * @param {jQuery} $input Search input|textarea. - * @param {jQuery} $container Search results container. - */ -phpbb.search.closeResults = function($input, $container) { - $input.off('.phpbb.search'); - $container.hide(); -}; - -/** - * Navigate search results. - * - * @param {jQuery} $input Search input|textarea. - * @param {jQuery} $container Search results container. - * @param {jQuery} $resultContainer Search results list container. - */ -phpbb.search.navigateResults = function($input, $container, $resultContainer) { - // Add a namespace to the event (.phpbb.search), - // so it can be unbound specifically later on. - // Rebind it, to ensure the event is 'dynamic'. - $input.off('.phpbb.search'); - $input.on('keydown.phpbb.search', function(event) { - var key = event.keyCode || event.which, - $active = $resultContainer.children('.active'); - - switch (key) { - // Close the results - case keymap.ESC: - phpbb.search.closeResults($input, $container); - break; - - // Set the value for the selected result - case keymap.ENTER: - if ($active.length) { - var value = $active.find('.search-result > span').text(); - - phpbb.search.setValue($input, value, $input.attr('data-multiline')); - } - - phpbb.search.closeResults($input, $container); - - // Do not submit the form - event.preventDefault(); - break; - - // Navigate the results - case keymap.ARROW_DOWN: - case keymap.ARROW_UP: - var up = key === keymap.ARROW_UP, - $children = $resultContainer.children(); - - if (!$active.length) { - if (up) { - $children.last().addClass('active'); - } else { - $children.first().addClass('active'); - } - } else if ($children.length > 1) { - if (up) { - if ($active.is(':first-child')) { - $children.last().addClass('active'); - } else { - $active.prev().addClass('active'); - } - } else { - if ($active.is(':last-child')) { - $children.first().addClass('active'); - } else { - $active.next().addClass('active'); - } - } - - $active.removeClass('active'); - } - - // Do not change cursor position in the input element - event.preventDefault(); - break; - } - }); -}; - -$('#phpbb').click(function() { - var $this = $(this); - - if (!$this.is('.live-search') && !$this.parents().is('.live-search')) { - phpbb.search.closeResults($('input, textarea'), $('.live-search')); - } -}); - -phpbb.history = {}; - -/** -* Check whether a method in the native history object is supported. -* -* @param {string} fn Method name. -* @returns {bool} Returns true if the method is supported. -*/ -phpbb.history.isSupported = function(fn) { - return !(typeof history === 'undefined' || typeof history[fn] === 'undefined'); -}; - -/** -* Wrapper for the pushState and replaceState methods of the -* native history object. -* -* @param {string} mode Mode. Either push or replace. -* @param {string} url New URL. -* @param {string} [title] Optional page title. -* @param {object} [obj] Optional state object. -*/ -phpbb.history.alterUrl = function(mode, url, title, obj) { - var fn = mode + 'State'; - - if (!url || !phpbb.history.isSupported(fn)) { - return; - } - if (!title) { - title = document.title; - } - if (!obj) { - obj = null; - } - - history[fn](obj, title, url); -}; - -/** -* Wrapper for the native history.replaceState method. -* -* @param {string} url New URL. -* @param {string} [title] Optional page title. -* @param {object} [obj] Optional state object. -*/ -phpbb.history.replaceUrl = function(url, title, obj) { - phpbb.history.alterUrl('replace', url, title, obj); -}; - -/** -* Wrapper for the native history.pushState method. -* -* @param {string} url New URL. -* @param {string} [title] Optional page title. -* @param {object} [obj] Optional state object. -*/ -phpbb.history.pushUrl = function(url, title, obj) { - phpbb.history.alterUrl('push', url, title, obj); -}; - -/** -* Hide the optgroups that are not the selected timezone -* -* @param {bool} keepSelection Shall we keep the value selected, or shall the -* user be forced to repick one. -*/ -phpbb.timezoneSwitchDate = function(keepSelection) { - var $timezoneCopy = $('#timezone_copy'); - var $timezone = $('#timezone'); - var $tzDate = $('#tz_date'); - var $tzSelectDateSuggest = $('#tz_select_date_suggest'); - - if ($timezoneCopy.length === 0) { - // We make a backup of the original dropdown, so we can remove optgroups - // instead of setting display to none, because IE and chrome will not - // hide options inside of optgroups and selects via css - $timezone.clone() - .attr('id', 'timezone_copy') - .css('display', 'none') - .attr('name', 'tz_copy') - .insertAfter('#timezone'); - } else { - // Copy the content of our backup, so we can remove all unneeded options - $timezone.html($timezoneCopy.html()); - } - - if ($tzDate.val() !== '') { - $timezone.children('optgroup').remove(':not([data-tz-value="' + $tzDate.val() + '"])'); - } - - if ($tzDate.val() === $tzSelectDateSuggest.attr('data-suggested-tz')) { - $tzSelectDateSuggest.css('display', 'none'); - } else { - $tzSelectDateSuggest.css('display', 'inline'); - } - - var $tzOptions = $timezone.children('optgroup[data-tz-value="' + $tzDate.val() + '"]').children('option'); - - if ($tzOptions.length === 1) { - // If there is only one timezone for the selected date, we just select that automatically. - $tzOptions.prop('selected', true); - keepSelection = true; - } - - if (typeof keepSelection !== 'undefined' && !keepSelection) { - var $timezoneOptions = $timezone.find('optgroup option'); - if ($timezoneOptions.filter(':selected').length <= 0) { - $timezoneOptions.filter(':first').prop('selected', true); - } - } -}; - -/** -* Display the date/time select -*/ -phpbb.timezoneEnableDateSelection = function() { - $('#tz_select_date').css('display', 'block'); -}; - -/** -* Preselect a date/time or suggest one, if it is not picked. -* -* @param {bool} forceSelector Shall we select the suggestion? -*/ -phpbb.timezonePreselectSelect = function(forceSelector) { - - // The offset returned here is in minutes and negated. - var offset = (new Date()).getTimezoneOffset(); - var sign = '-'; - - if (offset < 0) { - sign = '+'; - offset = -offset; - } - - var minutes = offset % 60; - var hours = (offset - minutes) / 60; - - if (hours < 10) { - hours = '0' + hours.toString(); - } else { - hours = hours.toString(); - } - - if (minutes < 10) { - minutes = '0' + minutes.toString(); - } else { - minutes = minutes.toString(); - } - - var prefix = 'UTC' + sign + hours + ':' + minutes; - var prefixLength = prefix.length; - var selectorOptions = $('option', '#tz_date'); - var i; - - var $tzSelectDateSuggest = $('#tz_select_date_suggest'); - - for (i = 0; i < selectorOptions.length; ++i) { - var option = selectorOptions[i]; - - if (option.value.substring(0, prefixLength) === prefix) { - if ($('#tz_date').val() !== option.value && !forceSelector) { - // We do not select the option for the user, but notify him, - // that we would suggest a different setting. - phpbb.timezoneSwitchDate(true); - $tzSelectDateSuggest.css('display', 'inline'); - } else { - option.selected = true; - phpbb.timezoneSwitchDate(!forceSelector); - $tzSelectDateSuggest.css('display', 'none'); - } - - var suggestion = $tzSelectDateSuggest.attr('data-l-suggestion'); - - $tzSelectDateSuggest.attr('title', suggestion.replace('%s', option.innerHTML)); - $tzSelectDateSuggest.attr('value', suggestion.replace('%s', option.innerHTML.substring(0, 9))); - $tzSelectDateSuggest.attr('data-suggested-tz', option.innerHTML); - - // Found the suggestion, there cannot be more, so return from here. - return; - } - } -}; - -phpbb.ajaxCallbacks = {}; - -/** - * Adds an AJAX callback to be used by phpbb.ajaxify. - * - * See the phpbb.ajaxify comments for information on stuff like parameters. - * - * @param {string} id The name of the callback. - * @param {function} callback The callback to be called. - */ -phpbb.addAjaxCallback = function(id, callback) { - if (typeof callback === 'function') { - phpbb.ajaxCallbacks[id] = callback; - } - return this; -}; - -/** - * This callback handles live member searches. - */ -phpbb.addAjaxCallback('member_search', function(res) { - phpbb.search.handleResponse(res, $(this), false, phpbb.getFunctionByName('phpbb.search.setValueOnClick')); -}); - -/** - * This callback alternates text - it replaces the current text with the text in - * the alt-text data attribute, and replaces the text in the attribute with the - * current text so that the process can be repeated. - */ -phpbb.addAjaxCallback('alt_text', function() { - var $anchor, - updateAll = $(this).data('update-all'), - altText; - - if (updateAll !== undefined && updateAll.length) { - $anchor = $(updateAll); - } else { - $anchor = $(this); - } - - $anchor.each(function() { - var $this = $(this); - altText = $this.attr('data-alt-text'); - $this.attr('data-alt-text', $.trim($this.text())); - $this.attr('title', altText); - $this.children('span').text(altText); - }); -}); - -/** - * This callback is based on the alt_text callback. - * - * It replaces the current text with the text in the alt-text data attribute, - * and replaces the text in the attribute with the current text so that the - * process can be repeated. - * Additionally it replaces the class of the link's parent - * and changes the link itself. - */ -phpbb.addAjaxCallback('toggle_link', function() { - var $anchor, - updateAll = $(this).data('update-all') , - toggleText, - toggleUrl, - toggleClass; - - if (updateAll !== undefined && updateAll.length) { - $anchor = $(updateAll); - } else { - $anchor = $(this); - } - - $anchor.each(function() { - var $this = $(this); - - // Toggle link url - toggleUrl = $this.attr('data-toggle-url'); - $this.attr('data-toggle-url', $this.attr('href')); - $this.attr('href', toggleUrl); - - // Toggle class of link parent - toggleClass = $this.attr('data-toggle-class'); - $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); - }); -}); - -/** -* Automatically resize textarea -* -* This function automatically resizes textarea elements when user -* types text. -* -* @param {jQuery} $items jQuery object(s) to resize -* @param {object} [options] Optional parameter that adjusts default -* configuration. See configuration variable -* -* Optional parameters: -* minWindowHeight {number} Minimum browser window height when textareas are resized. Default = 500 -* minHeight {number} Minimum height of textarea. Default = 200 -* maxHeight {number} Maximum height of textarea. Default = 500 -* heightDiff {number} Minimum difference between window and textarea height. Default = 200 -* resizeCallback {function} Function to call after resizing textarea -* resetCallback {function} Function to call when resize has been canceled - -* Callback function format: function(item) {} -* this points to DOM object -* item is a jQuery object, same as this -*/ -phpbb.resizeTextArea = function($items, options) { - // Configuration - var configuration = { - minWindowHeight: 500, - minHeight: 200, - maxHeight: 500, - heightDiff: 200, - resizeCallback: function() {}, - resetCallback: function() {} - }; - - if (phpbb.isTouch) { - return; - } - - if (arguments.length > 1) { - configuration = $.extend(configuration, options); - } - - function resetAutoResize(item) { - var $item = $(item); - if ($item.hasClass('auto-resized')) { - $(item) - .css({ height: '', resize: '' }) - .removeClass('auto-resized'); - configuration.resetCallback.call(item, $item); - } - } - - function autoResize(item) { - function setHeight(height) { - height += parseInt($item.css('height'), 10) - $item.innerHeight(); - $item - .css({ height: height + 'px', resize: 'none' }) - .addClass('auto-resized'); - configuration.resizeCallback.call(item, $item); - } - - var windowHeight = $(window).height(); - - if (windowHeight < configuration.minWindowHeight) { - resetAutoResize(item); - return; - } - - var maxHeight = Math.min( - Math.max(windowHeight - configuration.heightDiff, configuration.minHeight), - configuration.maxHeight - ), - $item = $(item), - height = parseInt($item.innerHeight(), 10), - scrollHeight = (item.scrollHeight) ? item.scrollHeight : 0; - - if (height < 0) { - return; - } - - if (height > maxHeight) { - setHeight(maxHeight); - } else if (scrollHeight > (height + 5)) { - setHeight(Math.min(maxHeight, scrollHeight)); - } - } - - $items.on('focus change keyup', function() { - $(this).each(function() { - autoResize(this); - }); - }).change(); - - $(window).resize(function() { - $items.each(function() { - if ($(this).hasClass('auto-resized')) { - autoResize(this); - } - }); - }); -}; - -/** -* Check if cursor in textarea is currently inside a bbcode tag -* -* @param {object} textarea Textarea DOM object -* @param {Array} startTags List of start tags to look for -* For example, Array('[code]', '[code=') -* @param {Array} endTags List of end tags to look for -* For example, Array('[/code]') -* -* @returns {boolean} True if cursor is in bbcode tag -*/ -phpbb.inBBCodeTag = function(textarea, startTags, endTags) { - var start = textarea.selectionStart, - lastEnd = -1, - lastStart = -1, - i, index, value; - - if (typeof start !== 'number') { - return false; - } - - value = textarea.value.toLowerCase(); - - for (i = 0; i < startTags.length; i++) { - var tagLength = startTags[i].length; - if (start >= tagLength) { - index = value.lastIndexOf(startTags[i], start - tagLength); - lastStart = Math.max(lastStart, index); - } - } - if (lastStart === -1) { - return false; - } - - if (start > 0) { - for (i = 0; i < endTags.length; i++) { - index = value.lastIndexOf(endTags[i], start - 1); - lastEnd = Math.max(lastEnd, index); - } - } - - return (lastEnd < lastStart); -}; - - -/** -* Adjust textarea to manage code bbcode -* -* This function allows to use tab characters when typing code -* and keeps indentation of previous line of code when adding new -* line while typing code. -* -* Editor's functionality is changed only when cursor is between -* [code] and [/code] bbcode tags. -* -* @param {object} textarea Textarea DOM object to apply editor to -*/ -phpbb.applyCodeEditor = function(textarea) { - // list of allowed start and end bbcode code tags, in lower case - var startTags = ['[code]', '[code='], - startTagsEnd = ']', - endTags = ['[/code]']; - - if (!textarea || typeof textarea.selectionStart !== 'number') { - return; - } - - if ($(textarea).data('code-editor') === true) { - return; - } - - function inTag() { - return phpbb.inBBCodeTag(textarea, startTags, endTags); - } - - /** - * Get line of text before cursor - * - * @param {boolean} stripCodeStart If true, only part of line - * after [code] tag will be returned. - * - * @returns {string} Line of text - */ - function getLastLine(stripCodeStart) { - var start = textarea.selectionStart, - value = textarea.value, - index = value.lastIndexOf('\n', start - 1); - - value = value.substring(index + 1, start); - - if (stripCodeStart) { - for (var i = 0; i < startTags.length; i++) { - index = value.lastIndexOf(startTags[i]); - if (index >= 0) { - var tagLength = startTags[i].length; - - value = value.substring(index + tagLength); - if (startTags[i].lastIndexOf(startTagsEnd) !== tagLength) { - index = value.indexOf(startTagsEnd); - - if (index >= 0) { - value = value.substr(index + 1); - } - } - } - } - } - - return value; - } - - /** - * Append text at cursor position - * - * @param {string} text Text to append - */ - function appendText(text) { - var start = textarea.selectionStart, - end = textarea.selectionEnd, - value = textarea.value; - - textarea.value = value.substr(0, start) + text + value.substr(end); - textarea.selectionStart = textarea.selectionEnd = start + text.length; - } - - $(textarea).data('code-editor', true).on('keydown', function(event) { - var key = event.keyCode || event.which; - - // intercept tabs - if (key === keymap.TAB && - !event.ctrlKey && - !event.shiftKey && - !event.altKey && - !event.metaKey) { - if (inTag()) { - appendText('\t'); - event.preventDefault(); - return; - } - } - - // intercept new line characters - if (key === keymap.ENTER) { - if (inTag()) { - var lastLine = getLastLine(true), - code = '' + /^\s*/g.exec(lastLine); - - if (code.length > 0) { - appendText('\n' + code); - event.preventDefault(); - } - } - } - }); -}; - -/** - * Show drag and drop animation when textarea is present - * - * This function will enable the drag and drop animation for a specified - * textarea. - * - * @param {HTMLElement} textarea Textarea DOM object to apply editor to - */ -phpbb.showDragNDrop = function(textarea) { - if (!textarea) { - return; - } - - $('body').on('dragenter dragover', function () { - $(textarea).addClass('drag-n-drop'); - }).on('dragleave dragout dragend drop', function() { - $(textarea).removeClass('drag-n-drop'); - }); - $(textarea).on('dragenter dragover', function () { - $(textarea).addClass('drag-n-drop-highlight'); - }).on('dragleave dragout dragend drop', function() { - $(textarea).removeClass('drag-n-drop-highlight'); - }); -}; - -/** -* List of classes that toggle dropdown menu, -* list of classes that contain visible dropdown menu -* -* Add your own classes to strings with comma (probably you -* will never need to do that) -*/ -phpbb.dropdownHandles = '.dropdown-container.dropdown-visible .dropdown-toggle'; -phpbb.dropdownVisibleContainers = '.dropdown-container.dropdown-visible'; - -/** -* Dropdown toggle event handler -* This handler is used by phpBB.registerDropdown() and other functions -*/ -phpbb.toggleDropdown = function() { - var $this = $(this), - options = $this.data('dropdown-options'), - parent = options.parent, - visible = parent.hasClass('dropdown-visible'), - direction; - - if (!visible) { - // Hide other dropdown menus - $(phpbb.dropdownHandles).each(phpbb.toggleDropdown); - - // Figure out direction of dropdown - direction = options.direction; - var verticalDirection = options.verticalDirection, - offset = $this.offset(); - - if (direction === 'auto') { - if (($(window).width() - $this.outerWidth(true)) / 2 > offset.left) { - direction = 'right'; - } else { - direction = 'left'; - } - } - parent.toggleClass(options.leftClass, direction === 'left') - .toggleClass(options.rightClass, direction === 'right'); - - if (verticalDirection === 'auto') { - var height = $(window).height(), - top = offset.top - $(window).scrollTop(); - - verticalDirection = (top < height * 0.7) ? 'down' : 'up'; - } - parent.toggleClass(options.upClass, verticalDirection === 'up') - .toggleClass(options.downClass, verticalDirection === 'down'); - } - - options.dropdown.toggle(); - parent.toggleClass(options.visibleClass, !visible) - .toggleClass('dropdown-visible', !visible); - - // Check dimensions when showing dropdown - // !visible because variable shows state of dropdown before it was toggled - if (!visible) { - var windowWidth = $(window).width(); - - options.dropdown.find('.dropdown-contents').each(function() { - var $this = $(this); - - $this.css({ - marginLeft: 0, - left: 0, - marginRight: 0, - maxWidth: (windowWidth - 4) + 'px' - }); - - var offset = $this.offset().left, - width = $this.outerWidth(true); - - if (offset < 2) { - $this.css('left', (2 - offset) + 'px'); - } else if ((offset + width + 2) > windowWidth) { - $this.css('margin-left', (windowWidth - offset - width - 2) + 'px'); - } - - // Check whether the vertical scrollbar is present. - $this.toggleClass('dropdown-nonscroll', this.scrollHeight === $this.innerHeight()); - - }); - var freeSpace = parent.offset().left - 4; - - if (direction === 'left') { - options.dropdown.css('margin-left', '-' + freeSpace + 'px'); - - // Try to position the notification dropdown correctly in RTL-responsive mode - if (options.dropdown.hasClass('dropdown-extended')) { - var contentWidth, - fullFreeSpace = freeSpace + parent.outerWidth(); - - options.dropdown.find('.dropdown-contents').each(function() { - contentWidth = parseInt($(this).outerWidth(), 10); - $(this).css({ marginLeft: 0, left: 0 }); - }); - - var maxOffset = Math.min(contentWidth, fullFreeSpace) + 'px'; - options.dropdown.css({ - width: maxOffset, - marginLeft: -maxOffset - }); - } - } else { - options.dropdown.css('margin-right', '-' + (windowWidth + freeSpace) + 'px'); - } - } - - // Prevent event propagation - if (arguments.length > 0) { - try { - var e = arguments[0]; - e.preventDefault(); - e.stopPropagation(); - } catch (error) { } - } - return false; -}; - -/** -* Toggle dropdown submenu -*/ -phpbb.toggleSubmenu = function(e) { - $(this).siblings('.dropdown-submenu').toggle(); - e.preventDefault(); -}; - -/** -* Register dropdown menu -* Shows/hides dropdown, decides which side to open to -* -* @param {jQuery} toggle Link that toggles dropdown. -* @param {jQuery} dropdown Dropdown menu. -* @param {Object} options List of options. Optional. -*/ -phpbb.registerDropdown = function(toggle, dropdown, options) { - var ops = { - parent: toggle.parent(), // Parent item to add classes to - direction: 'auto', // Direction of dropdown menu. Possible values: auto, left, right - verticalDirection: 'auto', // Vertical direction. Possible values: auto, up, down - visibleClass: 'visible', // Class to add to parent item when dropdown is visible - leftClass: 'dropdown-left', // Class to add to parent item when dropdown opens to left side - rightClass: 'dropdown-right', // Class to add to parent item when dropdown opens to right side - upClass: 'dropdown-up', // Class to add to parent item when dropdown opens above menu item - downClass: 'dropdown-down' // Class to add to parent item when dropdown opens below menu item - }; - if (options) { - ops = $.extend(ops, options); - } - ops.dropdown = dropdown; - - ops.parent.addClass('dropdown-container'); - toggle.addClass('dropdown-toggle'); - - toggle.data('dropdown-options', ops); - - toggle.click(phpbb.toggleDropdown); - $('.dropdown-toggle-submenu', ops.parent).click(phpbb.toggleSubmenu); -}; - -/** -* Get the HTML for a color palette table. -* -* @param {string} dir Palette direction - either v or h -* @param {int} width Palette cell width. -* @param {int} height Palette cell height. -*/ -phpbb.colorPalette = function(dir, width, height) { - var r, g, b, - numberList = new Array(6), - color = '', - html = ''; - - numberList[0] = '00'; - numberList[1] = '40'; - numberList[2] = '80'; - numberList[3] = 'BF'; - numberList[4] = 'FF'; - - var tableClass = (dir === 'h') ? 'horizontal-palette' : 'vertical-palette'; - html += ''; - - for (r = 0; r < 5; r++) { - if (dir === 'h') { - html += ''; - } - - for (g = 0; g < 5; g++) { - if (dir === 'v') { - html += ''; - } - - for (b = 0; b < 5; b++) { - color = '' + numberList[r] + numberList[g] + numberList[b]; - html += ''; - } - - if (dir === 'v') { - html += ''; - } - } - - if (dir === 'h') { - html += ''; - } - } - html += '
'; - html += '
'; - return html; -}; - -/** -* Register a color palette. -* -* @param {jQuery} el jQuery object for the palette container. -*/ -phpbb.registerPalette = function(el) { - var orientation = el.attr('data-color-palette') || el.attr('data-orientation'), // data-orientation kept for backwards compat. - height = el.attr('data-height'), - width = el.attr('data-width'), - target = el.attr('data-target'), - bbcode = el.attr('data-bbcode'); - - // Insert the palette HTML into the container. - el.html(phpbb.colorPalette(orientation, width, height)); - - // Add toggle control. - $('#color_palette_toggle').click(function(e) { - el.toggle(); - e.preventDefault(); - }); - - // Attach event handler when a palette cell is clicked. - $(el).on('click', 'a', function(e) { - var color = $(this).attr('data-color'); - - if (bbcode) { - bbfontstyle('[color=#' + color + ']', '[/color]'); - } else { - $(target).val(color); - } - e.preventDefault(); - }); -}; - -/** -* Set display of page element -* -* @param {string} id The ID of the element to change -* @param {int} action Set to 0 if element display should be toggled, -1 for -* hiding the element, and 1 for showing it. -* @param {string} type Display type that should be used, e.g. inline, block or -* other CSS "display" types -*/ -phpbb.toggleDisplay = function(id, action, type) { - if (!type) { - type = 'block'; - } - - var $element = $('#' + id); - - var display = $element.css('display'); - if (!action) { - action = (display === '' || display === type) ? -1 : 1; - } - $element.css('display', ((action === 1) ? type : 'none')); -}; - -/** -* Toggle additional settings based on the selected -* option of select element. -* -* @param {jQuery} el jQuery select element object. -*/ -phpbb.toggleSelectSettings = function(el) { - el.children().each(function() { - var $this = $(this), - $setting = $($this.data('toggle-setting')); - $setting.toggle($this.is(':selected')); - - // Disable any input elements that are not visible right now - if ($this.is(':selected')) { - $($this.data('toggle-setting') + ' input').prop('disabled', false); - } else { - $($this.data('toggle-setting') + ' input').prop('disabled', true); - } - }); -}; - -/** -* Get function from name. -* Based on http://stackoverflow.com/a/359910 -* -* @param {string} functionName Function to get. -* @returns function -*/ -phpbb.getFunctionByName = function (functionName) { - var namespaces = functionName.split('.'), - func = namespaces.pop(), - context = window; - - for (var i = 0; i < namespaces.length; i++) { - context = context[namespaces[i]]; - } - return context[func]; -}; - -/** -* Register page dropdowns. -*/ -phpbb.registerPageDropdowns = function() { - var $body = $('body'); - - $body.find('.dropdown-container').each(function() { - var $this = $(this), - $trigger = $this.find('.dropdown-trigger:first'), - $contents = $this.find('.dropdown'), - options = { - direction: 'auto', - verticalDirection: 'auto' - }, - data; - - if (!$trigger.length) { - data = $this.attr('data-dropdown-trigger'); - $trigger = data ? $this.children(data) : $this.children('a:first'); - } - - if (!$contents.length) { - data = $this.attr('data-dropdown-contents'); - $contents = data ? $this.children(data) : $this.children('div:first'); - } - - if (!$trigger.length || !$contents.length) { - return; - } - - if ($this.hasClass('dropdown-up')) { - options.verticalDirection = 'up'; - } - if ($this.hasClass('dropdown-down')) { - options.verticalDirection = 'down'; - } - if ($this.hasClass('dropdown-left')) { - options.direction = 'left'; - } - if ($this.hasClass('dropdown-right')) { - options.direction = 'right'; - } - - phpbb.registerDropdown($trigger, $contents, options); - }); - - // Hide active dropdowns when click event happens outside - $body.click(function(e) { - var $parents = $(e.target).parents(); - if (!$parents.is(phpbb.dropdownVisibleContainers)) { - $(phpbb.dropdownHandles).each(phpbb.toggleDropdown); - } - }); -}; - -/** - * Handle avatars to be lazy loaded. - */ -phpbb.lazyLoadAvatars = function loadAvatars() { - $('.avatar[data-src]').each(function () { - var $avatar = $(this); - - $avatar - .attr('src', $avatar.data('src')) - .removeAttr('data-src'); - }); -}; - -var recaptchaForm = $('.g-recaptcha').parents('form'); -var submitButton = null; -var programaticallySubmitted = false; - -phpbb.recaptchaOnLoad = function () { - // Listen to submit buttons in order to know which one was pressed - $('input[type="submit"]').each(function () { - $(this).on('click', function () { - submitButton = this; - }); - }); - - recaptchaForm.on('submit', function (e) { - if (!programaticallySubmitted) { - grecaptcha.execute(); - e.preventDefault(); - } - }); -} - -phpbb.recaptchaOnSubmit = function () { - programaticallySubmitted = true; - // If concrete button was clicked (e.g. preview instead of submit), - // let's trigger the same action - if (submitButton) { - submitButton.click(); - } else { - // Rename input[name="submit"] so that we can submit the form - if (typeof recaptchaForm.submit !== 'function') { - recaptchaForm.submit.name = 'submit_btn'; - } - recaptchaForm.submit(); - } -} - -// reCAPTCHA doesn't accept callback functions nested inside objects -// so we need to make this helper functions here -window.phpbbRecaptchaOnLoad = function() { - phpbb.recaptchaOnLoad(); -} -window.phpbbRecaptchaOnSubmit = function() { - phpbb.recaptchaOnSubmit(); -} - -$(window).on('load', phpbb.lazyLoadAvatars); - -/** -* Apply code editor to all textarea elements with data-bbcode attribute -*/ -$(function() { - $('textarea[data-bbcode]').each(function() { - phpbb.applyCodeEditor(this); - }); - - phpbb.registerPageDropdowns(); - - $('[data-color-palette], [data-orientation]').each(function() { - phpbb.registerPalette($(this)); - }); - - // Update browser history URL to point to specific post in viewtopic.php - // when using view=unread#unread link. - phpbb.history.replaceUrl($('#unread[data-url]').data('url')); - - // Hide settings that are not selected via select element. - $('select[data-togglable-settings]').each(function() { - var $this = $(this); - - $this.change(function() { - phpbb.toggleSelectSettings($this); - }); - phpbb.toggleSelectSettings($this); - }); -}); - -})(jQuery); // Avoid conflicts with other libraries diff --git a/install/update/new/assets/javascript/editor.js b/install/update/new/assets/javascript/editor.js deleted file mode 100644 index 24cbc09..0000000 --- a/install/update/new/assets/javascript/editor.js +++ /dev/null @@ -1,418 +0,0 @@ -/** -* bbCode control by subBlue design [ www.subBlue.com ] -* Includes unixsafe colour palette selector by SHS` -*/ - -// Startup variables -var imageTag = false; -var theSelection = false; -var bbcodeEnabled = true; - -// Check for Browser & Platform for PC & IE specific bits -// More details from: http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html -var clientPC = navigator.userAgent.toLowerCase(); // Get client info -var clientVer = parseInt(navigator.appVersion, 10); // Get browser version - -var is_ie = ((clientPC.indexOf('msie') !== -1) && (clientPC.indexOf('opera') === -1)); -var is_win = ((clientPC.indexOf('win') !== -1) || (clientPC.indexOf('16bit') !== -1)); -var baseHeight; - -/** -* Fix a bug involving the TextRange object. From -* http://www.frostjedi.com/terra/scripts/demo/caretBug.html -*/ -function initInsertions() { - var doc; - - if (document.forms[form_name]) { - doc = document; - } else { - doc = opener.document; - } - - var textarea = doc.forms[form_name].elements[text_name]; - - if (is_ie && typeof(baseHeight) !== 'number') { - textarea.focus(); - baseHeight = doc.selection.createRange().duplicate().boundingHeight; - - if (!document.forms[form_name]) { - document.body.focus(); - } - } -} - -/** -* bbstyle -*/ -function bbstyle(bbnumber) { - if (bbnumber !== -1) { - bbfontstyle(bbtags[bbnumber], bbtags[bbnumber+1]); - } else { - insert_text('[*]'); - document.forms[form_name].elements[text_name].focus(); - } -} - -/** -* Apply bbcodes -*/ -function bbfontstyle(bbopen, bbclose) { - theSelection = false; - - var textarea = document.forms[form_name].elements[text_name]; - - textarea.focus(); - - if ((clientVer >= 4) && is_ie && is_win) { - // Get text selection - theSelection = document.selection.createRange().text; - - if (theSelection) { - // Add tags around selection - document.selection.createRange().text = bbopen + theSelection + bbclose; - textarea.focus(); - theSelection = ''; - return; - } - } else if (textarea.selectionEnd && (textarea.selectionEnd - textarea.selectionStart > 0)) { - mozWrap(textarea, bbopen, bbclose); - textarea.focus(); - theSelection = ''; - return; - } - - //The new position for the cursor after adding the bbcode - var caret_pos = getCaretPosition(textarea).start; - var new_pos = caret_pos + bbopen.length; - - // Open tag - insert_text(bbopen + bbclose); - - // Center the cursor when we don't have a selection - // Gecko and proper browsers - if (!isNaN(textarea.selectionStart)) { - textarea.selectionStart = new_pos; - textarea.selectionEnd = new_pos; - } - // IE - else if (document.selection) { - var range = textarea.createTextRange(); - range.move("character", new_pos); - range.select(); - storeCaret(textarea); - } - - textarea.focus(); -} - -/** -* Insert text at position -*/ -function insert_text(text, spaces, popup) { - var textarea; - - if (!popup) { - textarea = document.forms[form_name].elements[text_name]; - } else { - textarea = opener.document.forms[form_name].elements[text_name]; - } - - if (spaces) { - text = ' ' + text + ' '; - } - - // Since IE9, IE also has textarea.selectionStart, but it still needs to be treated the old way. - // Therefore we simply add a !is_ie here until IE fixes the text-selection completely. - if (!isNaN(textarea.selectionStart) && !is_ie) { - var sel_start = textarea.selectionStart; - var sel_end = textarea.selectionEnd; - - mozWrap(textarea, text, ''); - textarea.selectionStart = sel_start + text.length; - textarea.selectionEnd = sel_end + text.length; - } else if (textarea.createTextRange && textarea.caretPos) { - if (baseHeight !== textarea.caretPos.boundingHeight) { - textarea.focus(); - storeCaret(textarea); - } - - var caret_pos = textarea.caretPos; - caret_pos.text = caret_pos.text.charAt(caret_pos.text.length - 1) === ' ' ? caret_pos.text + text + ' ' : caret_pos.text + text; - } else { - textarea.value = textarea.value + text; - } - - if (!popup) { - textarea.focus(); - } -} - -/** -* Add inline attachment at position -*/ -function attachInline(index, filename) { - insert_text('[attachment=' + index + ']' + filename + '[/attachment]'); - document.forms[form_name].elements[text_name].focus(); -} - -/** -* Add quote text to message -*/ -function addquote(post_id, username, l_wrote, attributes) { - var message_name = 'message_' + post_id; - var theSelection = ''; - var divarea = false; - var i; - - if (l_wrote === undefined) { - // Backwards compatibility - l_wrote = 'wrote'; - } - if (typeof attributes !== 'object') { - attributes = {}; - } - - if (document.all) { - divarea = document.all[message_name]; - } else { - divarea = document.getElementById(message_name); - } - - // Get text selection - not only the post content :( - // IE9 must use the document.selection method but has the *.getSelection so we just force no IE - if (window.getSelection && !is_ie && !window.opera) { - theSelection = window.getSelection().toString(); - } else if (document.getSelection && !is_ie) { - theSelection = document.getSelection(); - } else if (document.selection) { - theSelection = document.selection.createRange().text; - } - - if (theSelection === '' || typeof theSelection === 'undefined' || theSelection === null) { - if (divarea.innerHTML) { - theSelection = divarea.innerHTML.replace(/
/ig, '\n'); - theSelection = theSelection.replace(//ig, '\n'); - theSelection = theSelection.replace(/<\;/ig, '<'); - theSelection = theSelection.replace(/>\;/ig, '>'); - theSelection = theSelection.replace(/&\;/ig, '&'); - theSelection = theSelection.replace(/ \;/ig, ' '); - } else if (document.all) { - theSelection = divarea.innerText; - } else if (divarea.textContent) { - theSelection = divarea.textContent; - } else if (divarea.firstChild.nodeValue) { - theSelection = divarea.firstChild.nodeValue; - } - } - - if (theSelection) { - if (bbcodeEnabled) { - attributes.author = username; - insert_text(generateQuote(theSelection, attributes)); - } else { - insert_text(username + ' ' + l_wrote + ':' + '\n'); - var lines = split_lines(theSelection); - for (i = 0; i < lines.length; i++) { - insert_text('> ' + lines[i] + '\n'); - } - } - } -} - -/** -* 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) { - var lines = text.split('\n'); - var splitLines = new Array(); - var j = 0; - var i; - - for(i = 0; i < lines.length; i++) { - if (lines[i].length <= 80) { - splitLines[j] = lines[i]; - j++; - } else { - var line = lines[i]; - var splitAt; - do { - splitAt = line.indexOf(' ', 80); - - if (splitAt === -1) { - splitLines[j] = line; - j++; - } else { - splitLines[j] = line.substring(0, splitAt); - line = line.substring(splitAt); - j++; - } - } - while(splitAt !== -1); - } - } - return splitLines; -} - -/** -* From http://www.massless.org/mozedit/ -*/ -function mozWrap(txtarea, open, close) { - var selLength = (typeof(txtarea.textLength) === 'undefined') ? txtarea.value.length : txtarea.textLength; - var selStart = txtarea.selectionStart; - var selEnd = txtarea.selectionEnd; - var scrollTop = txtarea.scrollTop; - - var s1 = (txtarea.value).substring(0,selStart); - var s2 = (txtarea.value).substring(selStart, selEnd); - var s3 = (txtarea.value).substring(selEnd, selLength); - - txtarea.value = s1 + open + s2 + close + s3; - txtarea.selectionStart = selStart + open.length; - txtarea.selectionEnd = selEnd + open.length; - txtarea.focus(); - txtarea.scrollTop = scrollTop; - - return; -} - -/** -* Insert at Caret position. Code from -* http://www.faqts.com/knowledge_base/view.phtml/aid/1052/fid/130 -*/ -function storeCaret(textEl) { - if (textEl.createTextRange && document.selection) { - textEl.caretPos = document.selection.createRange().duplicate(); - } -} - -/** -* Caret Position object -*/ -function caretPosition() { - var start = null; - var end = null; -} - -/** -* Get the caret position in an textarea -*/ -function getCaretPosition(txtarea) { - var caretPos = new caretPosition(); - - // simple Gecko/Opera way - if (txtarea.selectionStart || txtarea.selectionStart === 0) { - caretPos.start = txtarea.selectionStart; - caretPos.end = txtarea.selectionEnd; - } - // dirty and slow IE way - else if (document.selection) { - // get current selection - var range = document.selection.createRange(); - - // a new selection of the whole textarea - var range_all = document.body.createTextRange(); - range_all.moveToElementText(txtarea); - - // calculate selection start point by moving beginning of range_all to beginning of range - var sel_start; - for (sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start++) { - range_all.moveStart('character', 1); - } - - txtarea.sel_start = sel_start; - - // we ignore the end value for IE, this is already dirty enough and we don't need it - caretPos.start = txtarea.sel_start; - caretPos.end = txtarea.sel_start; - } - - return caretPos; -} - -/** -* Allow to use tab character when typing code -* Keep indentation of last line of code when typing code -*/ -(function($) { - $(document).ready(function() { - var doc, textarea; - - // find textarea, make sure browser supports necessary functions - if (document.forms[form_name]) { - doc = document; - } else { - doc = opener.document; - } - - if (!doc.forms[form_name]) { - return; - } - - textarea = doc.forms[form_name].elements[text_name]; - - phpbb.applyCodeEditor(textarea); - if ($('#attach-panel').length) { - phpbb.showDragNDrop(textarea); - } - - $('textarea').on('keydown', function (e) { - if (e.which === 13 && (e.metaKey || e.ctrlKey)) { - $(this).closest('form').find(':submit').click(); - } - }); - }); -})(jQuery); - diff --git a/install/update/new/assets/javascript/installer.js b/install/update/new/assets/javascript/installer.js deleted file mode 100644 index a11b76b..0000000 --- a/install/update/new/assets/javascript/installer.js +++ /dev/null @@ -1,615 +0,0 @@ -/** - * 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 = $('
'); - $title = $(''); - $title.text(messages[i].title); - $msgElement.append($title); - - if (messages[i].hasOwnProperty('description')) { - $description = $('

'); - $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 = $('

'); - $downloadBox.addClass('download-box'); - - $title = $(''); - $title.text(downloadArray[i].title); - $downloadBox.append($title); - - if (downloadArray[i].hasOwnProperty('msg')) { - $content = $('

'); - $content.text(downloadArray[i].msg); - $downloadBox.append($content); - } - - $link = $(''); - $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 = $('

'); - $progressBar.attr('id', 'progress-bar'); - $progressText = $('

'); - $progressText.attr('id', 'progress-bar-text'); - $progressFiller = $('

'); - $progressFiller.attr('id', 'progress-bar-filler'); - $progressFillerText = $('

'); - $progressFillerText.attr('id', 'progress-bar-filler-text'); - - $statusText = $('

'); - $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 = $('

'); - $header.attr('id', 'header-container'); - $contentWrapper.append($header); - - var $description = $('
'); - $description.attr('id', 'description-container'); - $contentWrapper.append($description); - - var $errorContainer = $('
'); - $errorContainer.attr('id', 'error-container'); - $contentWrapper.append($errorContainer); - - var $warningContainer = $('
'); - $warningContainer.attr('id', 'warning-container'); - $contentWrapper.append($warningContainer); - - var $progressContainer = $('
'); - $progressContainer.attr('id', 'progress-bar-container'); - $contentWrapper.append($progressContainer); - - var $logContainer = $('
'); - $logContainer.attr('id', 'log-container'); - $contentWrapper.append($logContainer); - - var $installerContentWrapper = $('
'); - $installerContentWrapper.attr('id', 'content-container'); - $contentWrapper.append($installerContentWrapper); - - var $installerDownloadWrapper = $('
'); - $installerDownloadWrapper.attr('id', 'download-wrapper'); - $installerContentWrapper.append($installerDownloadWrapper); - - var $updaterFileStatusWrapper = $('
'); - $updaterFileStatusWrapper.attr('id', 'file-status-wrapper'); - $installerContentWrapper.append($updaterFileStatusWrapper); - - var $formWrapper = $('
'); - $formWrapper.attr('id', 'form-wrapper'); - $installerContentWrapper.append($formWrapper); - - var $spinner = $('
'); - $spinner.attr('id', 'loading_indicator'); - $spinner.html(' '); - $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/install/update/new/assets/javascript/jquery-3.4.1.min.js b/install/update/new/assets/javascript/jquery-3.4.1.min.js deleted file mode 100644 index a1c07fd..0000000 --- a/install/update/new/assets/javascript/jquery-3.4.1.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0 object(property: value). Requires attach_id to be one of the object properties. - */ -phpbb.plupload.setData = function(data) { - // Make sure that the array keys are reset. - phpbb.plupload.ids = phpbb.plupload.data = []; - phpbb.plupload.data = data; - - for (var i = 0; i < data.length; i++) { - phpbb.plupload.ids.push(Number(data[i].attach_id)); - } -}; - -/** - * Update the attachment data in the HTML and the phpbb & phpbb.plupload objects. - * - * @param {Array} data Array containing the new data to use. - * @param {string} action The action that required the update. Used to update the inline attachment bbcodes. - * @param {int} index The index from phpbb.plupload_ids that was affected by the action. - * @param {Array} downloadUrl Optional array of download urls to update. - */ -phpbb.plupload.update = function(data, action, index, downloadUrl) { - - phpbb.plupload.updateBbcode(action, index); - phpbb.plupload.setData(data); - phpbb.plupload.updateRows(downloadUrl); - phpbb.plupload.clearParams(); - phpbb.plupload.updateMultipartParams(phpbb.plupload.getSerializedData()); -}; - -/** - * Update the relevant elements and hidden data for all attachments. - * - * @param {Array} downloadUrl Optional array of download urls to update. - */ -phpbb.plupload.updateRows = function(downloadUrl) { - for (var i = 0; i < phpbb.plupload.ids.length; i++) { - phpbb.plupload.updateRow(i, downloadUrl); - } -}; - -/** - * Insert a row for a new attachment. This expects an HTML snippet in the HTML - * using the id "attach-row-tpl" to be present. This snippet is cloned and the - * data for the file inserted into it. The row is then appended or prepended to - * #file-list based on the attach_order setting. - * - * @param {object} file Plupload file object for the new attachment. - */ -phpbb.plupload.insertRow = function(file) { - var row = $(phpbb.plupload.rowTpl); - - row.attr('id', file.id); - row.find('.file-name').html(plupload.xmlEncode(file.name)); - row.find('.file-size').html(plupload.formatSize(file.size)); - - if (phpbb.plupload.order === 'desc') { - $('#file-list').prepend(row); - } else { - $('#file-list').append(row); - } -}; - -/** - * Update the relevant elements and hidden data for an attachment. - * - * @param {int} index The index from phpbb.plupload.ids of the attachment to edit. - * @param {Array} downloadUrl Optional array of download urls to update. - */ -phpbb.plupload.updateRow = function(index, downloadUrl) { - var attach = phpbb.plupload.data[index], - row = $('[data-attach-id="' + attach.attach_id + '"]'); - - // Add the link to the file - if (typeof downloadUrl !== 'undefined' && typeof downloadUrl[index] !== 'undefined') { - var url = downloadUrl[index].replace('&', '&'), - link = $(''); - - link.attr('href', url).html(attach.real_filename); - row.find('.file-name').html(link); - } - - row.find('textarea').attr('name', 'comment_list[' + index + ']'); - phpbb.plupload.updateHiddenData(row, attach, index); -}; - -/** - * Update hidden input data for an attachment. - * - * @param {object} row jQuery object for the attachment row. - * @param {object} attach Attachment data object from phpbb.plupload.data - * @param {int} index Attachment index from phpbb.plupload.ids - */ -phpbb.plupload.updateHiddenData = function(row, attach, index) { - row.find('input[type="hidden"]').remove(); - - for (var key in attach) { - if (!attach.hasOwnProperty(key)) { - return; - } - - var input = $('') - .attr('type', 'hidden') - .attr('name', 'attachment_data[' + index + '][' + key + ']') - .attr('value', attach[key]); - $(row).append(input); - } -}; - -/** - * Deleting a file removes it from the queue and fires an AJAX event to the - * server to tell it to remove the temporary attachment. The server - * responds with the updated attachment data list so that any future - * uploads can maintain state with the server - * - * @param {object} row jQuery object for the attachment row. - * @param {int} attachId Attachment id of the file to be removed. - */ -phpbb.plupload.deleteFile = function(row, attachId) { - // If there's no attach id, then the file hasn't been uploaded. Simply delete the row. - if (typeof attachId === 'undefined') { - var file = phpbb.plupload.uploader.getFile(row.attr('id')); - phpbb.plupload.uploader.removeFile(file); - - row.slideUp(100, function() { - row.remove(); - phpbb.plupload.hideEmptyList(); - }); - } - - var index = phpbb.plupload.getIndex(attachId); - row.find('.file-status').toggleClass('file-uploaded file-working'); - - if (index === false) { - return; - } - var fields = {}; - fields['delete_file[' + index + ']'] = 1; - - var always = function() { - row.find('.file-status').removeClass('file-working'); - }; - - var done = function(response) { - if (typeof response !== 'object') { - return; - } - - // trigger_error() was called which likely means a permission error was encountered. - if (typeof response.title !== 'undefined') { - phpbb.plupload.uploader.trigger('Error', { message: response.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; - } - - // 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(); - - if (row.attr('id')) { - var file = phpbb.plupload.uploader.getFile(row.attr('id')); - phpbb.plupload.uploader.removeFile(file); - } - row.slideUp(100, function() { - row.remove(); - // Hide the file list if it's empty now. - phpbb.plupload.hideEmptyList(); - }); - phpbb.plupload.uploader.trigger('FilesRemoved'); - }; - - $.ajax(phpbb.plupload.config.url, { - type: 'POST', - data: $.extend(fields, phpbb.plupload.getSerializedData()), - headers: phpbb.plupload.config.headers - }) - .always(always) - .done(done); -}; - -/** - * Check the attachment list and hide its container if it's empty. - */ -phpbb.plupload.hideEmptyList = function() { - if (!$('#file-list').children().length) { - $('#file-list-container').slideUp(100); - } -}; - -/** - * Update the indices used in inline attachment bbcodes. This ensures that the - * bbcodes correspond to the correct file after a file is added or removed. - * This should be called before the phpbb.plupload,data and phpbb.plupload.ids - * arrays are updated, otherwise it will not work correctly. - * - * @param {string} action The action that occurred -- either "addition" or "removal" - * @param {int} index The index of the attachment from phpbb.plupload.ids that was affected. - */ -phpbb.plupload.updateBbcode = function(action, index) { - var textarea = $('#message', phpbb.plupload.form), - text = textarea.val(), - removal = (action === 'removal'); - - // Return if the bbcode isn't used at all. - if (text.indexOf('[attachment=') === -1) { - return; - } - - function runUpdate(i) { - var regex = new RegExp('\\[attachment=' + i + '\\](.*?)\\[\\/attachment\\]', 'g'); - text = text.replace(regex, function updateBbcode(_, fileName) { - // Remove the bbcode if the file was removed. - if (removal && index === i) { - return ''; - } - var newIndex = i + ((removal) ? -1 : 1); - return '[attachment=' + newIndex + ']' + fileName + '[/attachment]'; - }); - } - - // Loop forwards when removing and backwards when adding ensures we don't - // corrupt the bbcode index. - var i; - if (removal) { - for (i = index; i < phpbb.plupload.ids.length; i++) { - runUpdate(i); - } - } else { - for (i = phpbb.plupload.ids.length - 1; i >= index; i--) { - runUpdate(i); - } - } - - textarea.val(text); -}; - -/** - * Get Plupload file objects based on their upload status. - * - * @param {int} status Plupload status - plupload.DONE, plupload.FAILED, - * plupload.QUEUED, plupload.STARTED, plupload.STOPPED - * - * @returns {Array} The Plupload file objects matching the status. - */ -phpbb.plupload.getFilesByStatus = function(status) { - var files = []; - - $.each(phpbb.plupload.uploader.files, function(i, file) { - if (file.status === status) { - files.push(file); - } - }); - return files; -}; - -/** - * Check whether the user has reached the maximun number of files that he's allowed - * to upload. If so, disables the uploader and marks the queued files as failed. Otherwise - * makes sure that the uploader is enabled. - * - * @returns {bool} True if the limit has been reached. False if otherwise. - */ -phpbb.plupload.handleMaxFilesReached = function() { - // If there is no limit, the user is an admin or moderator. - if (!phpbb.plupload.maxFiles) { - return false; - } - - if (phpbb.plupload.maxFiles <= phpbb.plupload.ids.length) { - // Fail the rest of the queue. - phpbb.plupload.markQueuedFailed(phpbb.plupload.lang.TOO_MANY_ATTACHMENTS); - // Disable the uploader. - phpbb.plupload.disableUploader(); - phpbb.plupload.uploader.trigger('Error', { message: phpbb.plupload.lang.TOO_MANY_ATTACHMENTS }); - - return true; - } else if (phpbb.plupload.maxFiles > phpbb.plupload.ids.length) { - // Enable the uploader if the user is under the limit - phpbb.plupload.enableUploader(); - } - return false; -}; - -/** - * Disable the uploader - */ -phpbb.plupload.disableUploader = function() { - $('#add_files').addClass('disabled'); - phpbb.plupload.uploader.disableBrowse(); -}; - -/** - * Enable the uploader - */ -phpbb.plupload.enableUploader = function() { - $('#add_files').removeClass('disabled'); - phpbb.plupload.uploader.disableBrowse(false); -}; - -/** - * Mark all queued files as failed. - * - * @param {string} error Error message to present to the user. - */ -phpbb.plupload.markQueuedFailed = function(error) { - var files = phpbb.plupload.getFilesByStatus(plupload.QUEUED); - - $.each(files, function(i, file) { - $('#' + file.id).find('.file-progress').hide(); - phpbb.plupload.fileError(file, error); - }); -}; - -/** - * Marks a file as failed and sets the error message for it. - * - * @param {object} file Plupload file object that failed. - * @param {string} error Error message to present to the user. - */ -phpbb.plupload.fileError = function(file, error) { - file.status = plupload.FAILED; - file.error = error; - $('#' + file.id).find('.file-status') - .addClass('file-error') - .attr({ - 'data-error-title': phpbb.plupload.lang.ERROR, - 'data-error-message': error - }); -}; - - -/** - * Set up the Plupload object and get some basic data. - */ -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'); - -/** - * Insert inline attachment bbcode. - */ -$fileList.on('click', '.file-inline-bbcode', function(e) { - var attachId = $(this).parents('.attach-row').attr('data-attach-id'), - index = phpbb.plupload.getIndex(attachId); - - attachInline(index, phpbb.plupload.data[index].real_filename); - e.preventDefault(); -}); - -/** - * Delete a file. - */ -$fileList.on('click', '.file-delete', function(e) { - var row = $(this).parents('.attach-row'), - attachId = row.attr('data-attach-id'); - - phpbb.plupload.deleteFile(row, attachId); - e.preventDefault(); -}); - -/** - * Display the error message for a particular file when the error icon is clicked. - */ -$fileList.on('click', '.file-error', function(e) { - phpbb.alert($(this).attr('data-error-title'), $(this).attr('data-error-message')); - e.preventDefault(); -}); - -/** - * Fires when an error occurs. - */ -phpbb.plupload.uploader.bind('Error', function(up, error) { - error.file.name = plupload.xmlEncode(error.file.name); - - // The error message that Plupload provides for these is vague, so we'll be more specific. - if (error.code === plupload.FILE_EXTENSION_ERROR) { - error.message = plupload.translate('Invalid file extension:') + ' ' + error.file.name; - } else if (error.code === plupload.FILE_SIZE_ERROR) { - error.message = plupload.translate('File too large:') + ' ' + error.file.name; - } - phpbb.alert(phpbb.plupload.lang.ERROR, error.message); -}); - -/** - * Fires before a given file is about to be uploaded. This allows us to - * send the real filename along with the chunk. This is necessary because - * for some reason the filename is set to 'blob' whenever a file is chunked - * - * @param {object} up The plupload.Uploader object - * @param {object} file The plupload.File object that is about to be uploaded - */ -phpbb.plupload.uploader.bind('BeforeUpload', function(up, file) { - if (phpbb.plupload.handleMaxFilesReached()) { - return; - } - - phpbb.plupload.updateMultipartParams({ real_filename: file.name }); -}); - -/** - * Fired when a single chunk of any given file is uploaded. This parses the - * response from the server and checks for an error. If an error occurs it - * is reported to the user and the upload of this particular file is halted - * - * @param {object} up The plupload.Uploader object - * @param {object} file The plupload.File object whose chunk has just - * been uploaded - * @param {object} response The response object from the server - */ -phpbb.plupload.uploader.bind('ChunkUploaded', function(up, file, response) { - if (response.chunk >= response.chunks - 1) { - return; - } - - var json = {}; - try { - json = $.parseJSON(response.response); - } catch (e) { - file.status = plupload.FAILED; - up.trigger('FileUploaded', file, { - response: JSON.stringify({ - error: { - message: 'Error parsing server response.' - } - }) - }); - } - - // If trigger_error() was called, then a permission error likely occurred. - if (typeof json.title !== 'undefined') { - json.error = { message: json.message }; - } - - if (json.error) { - file.status = plupload.FAILED; - up.trigger('FileUploaded', file, { - response: JSON.stringify({ - error: { - message: json.error.message - } - }) - }); - } -}); - -/** - * Fires when files are added to the queue. - */ -phpbb.plupload.uploader.bind('FilesAdded', function(up, files) { - // Prevent unnecessary requests to the server if the user already uploaded - // the maximum number of files allowed. - if (phpbb.plupload.handleMaxFilesReached()) { - return; - } - - // Switch the active tab if the style supports it - if (typeof activateSubPanel === 'function') { - activateSubPanel('attach-panel'); // jshint ignore: line - } - - // Show the file list if there aren't any files currently. - var $fileListContainer = $('#file-list-container'); - if (!$fileListContainer.is(':visible')) { - $fileListContainer.show(100); - } - - $.each(files, function(i, file) { - phpbb.plupload.insertRow(file); - }); - - up.bind('UploadProgress', function(up, file) { - $('.file-progress-bar', '#' + file.id).css('width', file.percent + '%'); - $('#file-total-progress-bar').css('width', up.total.percent + '%'); - }); - - // Do not allow more files to be added to the running queue. - phpbb.plupload.disableUploader(); - - // Start uploading the files once the user has selected them. - up.start(); -}); - - -/** - * Fires when an entire file has been uploaded. It checks for errors - * returned by the server otherwise parses the list of attachment data and - * appends it to the next file upload so that the server can maintain state - * with regards to the attachments in a given post - * - * @param {object} up The plupload.Uploader object - * @param {object} file The plupload.File object that has just been - * uploaded - * @param {string} response The response string from the server - */ -phpbb.plupload.uploader.bind('FileUploaded', function(up, file, response) { - var json = {}, - row = $('#' + file.id), - error; - - // Hide the progress indicator. - row.find('.file-progress').hide(); - - try { - json = JSON.parse(response.response); - } catch (e) { - error = 'Error parsing server response.'; - } - - // If trigger_error() was called, then a permission error likely occurred. - if (typeof json.title !== 'undefined') { - error = json.message; - up.trigger('Error', { message: error }); - - // The rest of the queue will fail. - phpbb.plupload.markQueuedFailed(error); - } else if (json.error) { - error = json.error.message; - } - - if (typeof error !== 'undefined') { - phpbb.plupload.fileError(file, error); - } else if (file.status === plupload.DONE) { - file.attachment_data = json.data[0]; - - row.attr('data-attach-id', file.attachment_data.attach_id); - row.find('.file-inline-bbcode').show(); - row.find('.file-status').addClass('file-uploaded'); - phpbb.plupload.update(json.data, 'addition', 0, [json.download_url]); - } -}); - -/** - * Fires when the entire queue of files have been uploaded. - */ -phpbb.plupload.uploader.bind('UploadComplete', function() { - // Hide the progress bar - setTimeout(function() { - $('#file-total-progress-bar').fadeOut(500, function() { - $(this).css('width', 0).show(); - }); - }, 2000); - - // Re-enable the uploader - phpbb.plupload.enableUploader(); -}); - -})(jQuery); // Avoid conflicts with other libraries diff --git a/install/update/new/common.php b/install/update/new/common.php deleted file mode 100644 index e25274d..0000000 --- a/install/update/new/common.php +++ /dev/null @@ -1,166 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* Minimum Requirement: PHP 7.1.3 -*/ - -if (!defined('IN_PHPBB')) -{ - exit; -} - -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_ENVIRONMENT')) -{ - @define('PHPBB_ENVIRONMENT', 'production'); -} - -if (!defined('PHPBB_INSTALLED')) -{ - // Redirect the user to the installer - require($phpbb_root_path . 'includes/functions.' . $phpEx); - - // We have to generate a full HTTP/1.1 header here since we can't guarantee to have any of the information - // available as used by the redirect function - $server_name = (!empty($_SERVER['HTTP_HOST'])) ? strtolower($_SERVER['HTTP_HOST']) : ((!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME')); - $server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT'); - $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 1 : 0; - - if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') - { - $secure = 1; - $server_port = 443; - } - - $script_name = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : getenv('PHP_SELF'); - if (!$script_name) - { - $script_name = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : getenv('REQUEST_URI'); - } - - // $phpbb_root_path accounts for redirects from e.g. /adm - $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\filesystem(); - $script_path = $phpbb_filesystem->clean_path($script_path); - - $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; - header('Location: ' . $url); - exit; -} - -// 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); -include($phpbb_root_path . 'includes/functions_compatibility.' . $phpEx); - -require($phpbb_root_path . 'includes/constants.' . $phpEx); -require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - -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(); - -// Set up 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')); - -$phpbb_container->get('dbal.conn')->set_debug_sql_explain($phpbb_container->getParameter('debug.sql_explain')); -$phpbb_container->get('dbal.conn')->set_debug_load_time($phpbb_container->getParameter('debug.load_time')); -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) -{ - @include($phpbb_root_path . 'includes/hooks/' . $hook . '.' . $phpEx); -} - -/** -* Main event which is triggered on every page -* -* You can use this event to load function files and initiate objects -* -* NOTE: At this point the global session ($user) and permissions ($auth) -* do NOT exist yet. If you need to use the user object -* (f.e. to include language files) or need to check permissions, -* please use the core.user_setup event instead! -* -* @event core.common -* @since 3.1.0-a1 -*/ -$phpbb_dispatcher->dispatch('core.common'); diff --git a/install/update/new/composer.json b/install/update/new/composer.json deleted file mode 100644 index 57c7d74..0000000 --- a/install/update/new/composer.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "name": "phpbb/phpbb", - "description": "phpBB Forum Software application", - "type": "project", - "keywords": ["phpbb", "forum"], - "homepage": "https://www.phpbb.com", - "license": "GPL-2.0-only", - "authors": [ - { - "name": "phpBB Limited", - "email": "operations@phpbb.com", - "homepage": "https://www.phpbb.com/go/authors" - } - ], - "support": { - "issues": "https://tracker.phpbb.com", - "forum": "https://www.phpbb.com/community/", - "wiki": "https://wiki.phpbb.com", - "irc": "irc://irc.freenode.org/phpbb" - }, - "scripts": { - "post-update-cmd": "echo 'You MUST manually modify the clean-vendor-dir target in build/build.xml when adding or upgrading dependencies.'" - }, - "replace": { - "phpbb/phpbb-core": "self.version" - }, - "require": { - "php": "^7.1.3", - "ext-json": "*", - "bantu/ini-get-wrapper": "~1.0", - "google/recaptcha": "~1.1", - "guzzlehttp/guzzle": "~6.3", - "lusitanian/oauth": "^0.8.1", - "marc1706/fast-image-size": "^1.1", - "patchwork/utf8": "^1.1", - "s9e/text-formatter": "^2.0", - "symfony/config": "~3.4", - "symfony/console": "~3.4", - "symfony/debug": "~3.4", - "symfony/dependency-injection": "~3.4", - "symfony/event-dispatcher": "~3.4", - "symfony/filesystem": "~3.4", - "symfony/finder": "~3.4", - "symfony/http-foundation": "~3.4", - "symfony/http-kernel": "~3.4", - "symfony/process": "^3.4", - "symfony/proxy-manager-bridge": "~3.4", - "symfony/routing": "~3.4", - "symfony/twig-bridge": "~3.4", - "symfony/yaml": "~3.4", - "twig/twig": "^1.0 || ^2.0" - }, - "require-dev": { - "fabpot/goutte": "~3.2", - "facebook/webdriver": "~1.6", - "laravel/homestead": "~7.0", - "phing/phing": "~2.4", - "phpunit/dbunit": "~4.0", - "phpunit/phpunit": "^7.0", - "squizlabs/php_codesniffer": "~3.4", - "symfony/browser-kit": "~3.4", - "symfony/css-selector": "~3.4", - "symfony/dom-crawler": "~3.4", - "sami/sami": "^4.1" - }, - "extra": { - "branch-alias": { - "dev-master": "3.3.x-dev" - } - }, - "config": { - "platform": { - "php": "7.1.3" - } - } -} diff --git a/install/update/new/composer.lock b/install/update/new/composer.lock deleted file mode 100644 index 272c0fb..0000000 --- a/install/update/new/composer.lock +++ /dev/null @@ -1,4410 +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#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "bbbc187ca0c5d8f13e6358d529412446", - "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.2.3", - "source": { - "type": "git", - "url": "https://github.com/google/recaptcha.git", - "reference": "98c4a6573b27e8b0990ea8789c74ea378795134c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/google/recaptcha/zipball/98c4a6573b27e8b0990ea8789c74ea378795134c", - "reference": "98c4a6573b27e8b0990ea8789c74ea378795134c", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.2.20|^2.15", - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7.5.11" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.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 protects websites from spam and abuse.", - "homepage": "https://www.google.com/recaptcha/", - "keywords": [ - "Abuse", - "captcha", - "recaptcha", - "spam" - ], - "time": "2019-08-16T15:48:25+00:00" - }, - { - "name": "guzzlehttp/guzzle", - "version": "6.5.2", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", - "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", - "shasum": "" - }, - "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.6.1", - "php": ">=5.5" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.1" - }, - "suggest": { - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.5-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "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", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "time": "2019-12-23T11:57:10+00:00" - }, - { - "name": "guzzlehttp/promises", - "version": "v1.3.1", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "time": "2016-12-20T10:07:11+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "1.6.1", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" - }, - "suggest": { - "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Schultze", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "time": "2019-07-01T23:21:34+00:00" - }, - { - "name": "lusitanian/oauth", - "version": "v0.8.11", - "source": { - "type": "git", - "url": "https://github.com/Lusitanian/PHPoAuthLib.git", - "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/fc11a53db4b66da555a6a11fce294f574a8374f9", - "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "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." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.1-dev" - } - }, - "autoload": { - "psr-0": { - "OAuth": "src", - "OAuth\\Unit": "tests" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "David Desberg", - "email": "david@daviddesberg.com" - }, - { - "name": "Elliot Chance", - "email": "elliotchance@gmail.com" - }, - { - "name": "Pieter Hordijk", - "email": "info@pieterhordijk.com" - } - ], - "description": "PHP 5.3+ oAuth 1/2 Library", - "keywords": [ - "Authentication", - "authorization", - "oauth", - "security" - ], - "time": "2016-07-12T22:15:00+00:00" - }, - { - "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/package-versions", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", - "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0.0", - "php": "^7.1.0" - }, - "require-dev": { - "composer/composer": "^1.6.3", - "doctrine/coding-standard": "^5.0.1", - "ext-zip": "*", - "infection/infection": "^0.7.1", - "phpunit/phpunit": "^7.5.17" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-11-15T16:17:10+00:00" - }, - { - "name": "ocramius/proxy-manager", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/Ocramius/ProxyManager.git", - "reference": "e18ac876b2e4819c76349de8f78ccc8ef1554cd7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/e18ac876b2e4819c76349de8f78ccc8ef1554cd7", - "reference": "e18ac876b2e4819c76349de8f78ccc8ef1554cd7", - "shasum": "" - }, - "require": { - "ocramius/package-versions": "^1.1.1", - "php": "^7.1.0", - "zendframework/zend-code": "^3.1.0" - }, - "require-dev": { - "couscous/couscous": "^1.5.2", - "ext-phar": "*", - "humbug/humbug": "dev-master@DEV", - "nikic/php-parser": "^3.0.4", - "phpbench/phpbench": "^0.12.2", - "phpstan/phpstan": "^0.6.4", - "phpunit/phpunit": "^5.6.4", - "phpunit/phpunit-mock-objects": "^3.4.1", - "squizlabs/php_codesniffer": "^2.7.0" - }, - "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-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.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.io/" - } - ], - "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": "2017-05-04T11:12:50+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.99", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "shasum": "" - }, - "require": { - "php": "^7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "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": "2018-07-02T15:55:56+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/container", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "time": "2017-02-14T16:28:37+00:00" - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "time": "2016-08-06T14:39:51+00:00" - }, - { - "name": "psr/log", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2019-11-01T11:05:21+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "s9e/regexp-builder", - "version": "1.4.3", - "source": { - "type": "git", - "url": "https://github.com/s9e/RegexpBuilder.git", - "reference": "59d0167a909659d718f53964f7653d2c83a5f8fe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/s9e/RegexpBuilder/zipball/59d0167a909659d718f53964f7653d2c83a5f8fe", - "reference": "59d0167a909659d718f53964f7653d2c83a5f8fe", - "shasum": "" - }, - "require": { - "lib-pcre": ">=7.2", - "php": ">=5.5.1" - }, - "require-dev": { - "phpunit/phpunit": "<5.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "s9e\\RegexpBuilder\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Single-purpose library that generates regular expressions that match a list of strings.", - "homepage": "https://github.com/s9e/RegexpBuilder/", - "keywords": [ - "regexp" - ], - "time": "2019-04-26T17:55:23+00:00" - }, - { - "name": "s9e/text-formatter", - "version": "2.3.1", - "source": { - "type": "git", - "url": "https://github.com/s9e/TextFormatter.git", - "reference": "65a0605f163b8ffcf7145357f167b153f31cd168" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/s9e/TextFormatter/zipball/65a0605f163b8ffcf7145357f167b153f31cd168", - "reference": "65a0605f163b8ffcf7145357f167b153f31cd168", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-filter": "*", - "lib-pcre": ">=8.13", - "php": ">=7.1", - "s9e/regexp-builder": "^1.4" - }, - "require-dev": { - "matthiasmullie/minify": "*", - "phpunit/phpunit": "^7 || 8.2.*" - }, - "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", - "extra": { - "version": "2.3.1" - }, - "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-12-26T19:14:01+00:00" - }, - { - "name": "symfony/config", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "a599a867d0e4a07c342b5f1e656b3915a540ddbe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/a599a867d0e4a07c342b5f1e656b3915a540ddbe", - "reference": "a599a867d0e4a07c342b5f1e656b3915a540ddbe", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3", - "symfony/finder": "<3.3" - }, - "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0", - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "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 Config Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T10:45:41+00:00" - }, - { - "name": "symfony/console", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "1ee23b3b659b06c622f2bd2492a229e416eb4586" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1ee23b3b659b06c622f2bd2492a229e416eb4586", - "reference": "1ee23b3b659b06c622f2bd2492a229e416eb4586", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/debug": "~2.8|~3.0|~4.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/process": "<3.3" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~3.3|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.3|~4.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "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 Console Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T10:04:45+00:00" - }, - { - "name": "symfony/debug", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "f72e33fdb1170b326e72c3157f0cd456351dd086" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/f72e33fdb1170b326e72c3157f0cd456351dd086", - "reference": "f72e33fdb1170b326e72c3157f0cd456351dd086", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "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-kernel": "~2.8|~3.0|~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "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 Debug Component", - "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "0d201916bfb3af939fec3c0c8815ea16c60ac1a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0d201916bfb3af939fec3c0c8815ea16c60ac1a2", - "reference": "0d201916bfb3af939fec3c0c8815ea16c60ac1a2", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" - }, - "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", - "symfony/proxy-manager-bridge": "<3.4", - "symfony/yaml": "<3.4" - }, - "provide": { - "psr/container-implementation": "1.0" - }, - "require-dev": { - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "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 DependencyInjection Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T08:33:36+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "f9031c22ec127d4a2450760f81a8677fe8a10177" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f9031c22ec127d4a2450760f81a8677fe8a10177", - "reference": "f9031c22ec127d4a2450760f81a8677fe8a10177", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "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 EventDispatcher Component", - "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "00cdad0936d06fab136944bc2342b762b1c3a4a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/00cdad0936d06fab136944bc2342b762b1c3a4a2", - "reference": "00cdad0936d06fab136944bc2342b762b1c3a4a2", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "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 Filesystem Component", - "homepage": "https://symfony.com", - "time": "2019-11-25T16:36:22+00:00" - }, - { - "name": "symfony/finder", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "290ae21279b37bfd287cdcce640d51204e84afdf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/290ae21279b37bfd287cdcce640d51204e84afdf", - "reference": "290ae21279b37bfd287cdcce640d51204e84afdf", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-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": "2019-11-17T21:55:15+00:00" - }, - { - "name": "symfony/http-foundation", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "d2d0cfe8e319d9df44c4cca570710fcf221d4593" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d2d0cfe8e319d9df44c4cca570710fcf221d4593", - "reference": "d2d0cfe8e319d9df44c4cca570710fcf221d4593", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" - }, - "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "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 HttpFoundation Component", - "homepage": "https://symfony.com", - "time": "2019-11-28T12:52:59+00:00" - }, - { - "name": "symfony/http-kernel", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "c42c8339acb28cfff0fb1786948db4d23d609ff7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/c42c8339acb28cfff0fb1786948db4d23d609ff7", - "reference": "c42c8339acb28cfff0fb1786948db4d23d609ff7", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0", - "symfony/debug": "^3.3.3|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php56": "~1.8" - }, - "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", - "symfony/var-dumper": "<3.3", - "twig/twig": "<1.34|<2.4,>=2" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/cache": "~1.0", - "symfony/browser-kit": "~2.8|~3.0|~4.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.10|^4.0.10", - "symfony/dom-crawler": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" - }, - "suggest": { - "symfony/browser-kit": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" - }, - "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 HttpKernel Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T13:50:37+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.13.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "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 for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2019-11-27T14:18:11+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-php70", - "version": "v1.13.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "af23c7bb26a73b850840823662dda371484926c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/af23c7bb26a73b850840823662dda371484926c4", - "reference": "af23c7bb26a73b850840823662dda371484926c4", - "shasum": "" - }, - "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" - }, - "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 7.0+ 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/process", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "9a4545c01e1e4f473492bd52b71e574dcc401ca2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/9a4545c01e1e4f473492bd52b71e574dcc401ca2", - "reference": "9a4545c01e1e4f473492bd52b71e574dcc401ca2", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "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 Process Component", - "homepage": "https://symfony.com", - "time": "2019-11-28T10:05:51+00:00" - }, - { - "name": "symfony/proxy-manager-bridge", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/proxy-manager-bridge.git", - "reference": "3c185a0e45ea13334aaf7b0fa9726922816ebec6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/3c185a0e45ea13334aaf7b0fa9726922816ebec6", - "reference": "3c185a0e45ea13334aaf7b0fa9726922816ebec6", - "shasum": "" - }, - "require": { - "ocramius/proxy-manager": "~0.4|~1.0|~2.0", - "php": "^5.5.9|>=7.0.8", - "symfony/dependency-injection": "~3.4|~4.0" - }, - "require-dev": { - "symfony/config": "~2.8|~3.0|~4.0" - }, - "type": "symfony-bridge", - "extra": { - "branch-alias": { - "dev-master": "3.4-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-08-29T14:54:55+00:00" - }, - { - "name": "symfony/routing", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "b689ccd48e234ea404806d94b07eeb45f9f6f06a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/b689ccd48e234ea404806d94b07eeb45f9f6f06a", - "reference": "b689ccd48e234ea404806d94b07eeb45f9f6f06a", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/config": "<3.3.1", - "symfony/dependency-injection": "<3.3", - "symfony/yaml": "<3.4" - }, - "require-dev": { - "doctrine/annotations": "~1.0", - "psr/log": "~1.0", - "symfony/config": "^3.3.1|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" - }, - "suggest": { - "doctrine/annotations": "For using the annotation loader", - "symfony/config": "For using the all-in-one router or any loader", - "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": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Routing\\": "" - }, - "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 Routing Component", - "homepage": "https://symfony.com", - "keywords": [ - "router", - "routing", - "uri", - "url" - ], - "time": "2019-12-01T08:33:36+00:00" - }, - { - "name": "symfony/twig-bridge", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/twig-bridge.git", - "reference": "49b824ddc7f2d250a1f172349cd9a111d63287c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/49b824ddc7f2d250a1f172349cd9a111d63287c0", - "reference": "49b824ddc7f2d250a1f172349cd9a111d63287c0", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "twig/twig": "^1.41|^2.10" - }, - "conflict": { - "symfony/console": "<3.4", - "symfony/form": "<3.4.31|>=4.0,<4.3.4" - }, - "require-dev": { - "fig/link-util": "^1.0", - "symfony/asset": "~2.8|~3.0|~4.0", - "symfony/console": "~3.4|~4.0", - "symfony/dependency-injection": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/form": "^3.4.31|^4.3.4", - "symfony/http-foundation": "^3.3.11|~4.0", - "symfony/http-kernel": "~3.2|~4.0", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/routing": "~2.8|~3.0|~4.0", - "symfony/security": "^2.8.31|^3.3.13|~4.0", - "symfony/security-acl": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~2.8.10|~3.1.4|~3.2|~4.0", - "symfony/web-link": "~3.3|~4.0", - "symfony/workflow": "~3.3|~4.0", - "symfony/yaml": "~2.8|~3.0|~4.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/web-link": "For using the WebLinkExtension", - "symfony/yaml": "For using the YamlExtension" - }, - "type": "symfony-bridge", - "extra": { - "branch-alias": { - "dev-master": "3.4-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": "2019-11-30T08:19:08+00:00" - }, - { - "name": "symfony/yaml", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "dab657db15207879217fc81df4f875947bf68804" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/dab657db15207879217fc81df4f875947bf68804", - "reference": "dab657db15207879217fc81df4f875947bf68804", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/console": "<3.4" - }, - "require-dev": { - "symfony/console": "~3.4|~4.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "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 Yaml Component", - "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" - }, - { - "name": "twig/twig", - "version": "v2.12.2", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "d761fd1f1c6b867ae09a7d8119a6d95d06dc44ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/d761fd1f1c6b867ae09a7d8119a6d95d06dc44ed", - "reference": "d761fd1f1c6b867ae09a7d8119a6d95d06dc44ed", - "shasum": "" - }, - "require": { - "php": "^7.0", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" - }, - "require-dev": { - "psr/container": "^1.0", - "symfony/debug": "^3.4|^4.2", - "symfony/phpunit-bridge": "^4.4@dev|^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.12-dev" - } - }, - "autoload": { - "psr-0": { - "Twig_": "lib/" - }, - "psr-4": { - "Twig\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Twig Team", - "homepage": "https://twig.symfony.com/contributors", - "role": "Contributors" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], - "time": "2019-11-11T16:52:09+00:00" - }, - { - "name": "zendframework/zend-code", - "version": "3.4.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-code.git", - "reference": "268040548f92c2bfcba164421c1add2ba43abaaa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-code/zipball/268040548f92c2bfcba164421c1add2ba43abaaa", - "reference": "268040548f92c2bfcba164421c1add2ba43abaaa", - "shasum": "" - }, - "require": { - "php": "^7.1", - "zendframework/zend-eventmanager": "^2.6 || ^3.0" - }, - "conflict": { - "phpspec/prophecy": "<1.9.0" - }, - "require-dev": { - "doctrine/annotations": "^1.7", - "ext-phar": "*", - "phpunit/phpunit": "^7.5.16 || ^8.4", - "zendframework/zend-coding-standard": "^1.0", - "zendframework/zend-stdlib": "^2.7 || ^3.0" - }, - "suggest": { - "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", - "zendframework/zend-stdlib": "Zend\\Stdlib component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4.x-dev", - "dev-develop": "3.5.x-dev", - "dev-dev-4.0": "4.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Code\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", - "keywords": [ - "ZendFramework", - "code", - "zf" - ], - "time": "2019-12-10T19:21:15+00:00" - }, - { - "name": "zendframework/zend-eventmanager", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-eventmanager.git", - "reference": "a5e2583a211f73604691586b8406ff7296a946dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/a5e2583a211f73604691586b8406ff7296a946dd", - "reference": "a5e2583a211f73604691586b8406ff7296a946dd", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "athletic/athletic": "^0.1", - "container-interop/container-interop": "^1.1.0", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-stdlib": "^2.7.3 || ^3.0" - }, - "suggest": { - "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", - "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev", - "dev-develop": "3.3-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\EventManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Trigger and listen to events within a PHP application", - "homepage": "https://github.com/zendframework/zend-eventmanager", - "keywords": [ - "event", - "eventmanager", - "events", - "zf2" - ], - "time": "2018-04-25T15:33:34+00:00" - } - ], - "packages-dev": [ - { - "name": "blackfire/php-sdk", - "version": "v1.21.0", - "source": { - "type": "git", - "url": "https://github.com/blackfireio/php-sdk.git", - "reference": "1aa41771641ac268c5a2a0fc520e0da0e1f6698a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/blackfireio/php-sdk/zipball/1aa41771641ac268c5a2a0fc520e0da0e1f6698a", - "reference": "1aa41771641ac268c5a2a0fc520e0da0e1f6698a", - "shasum": "" - }, - "require": { - "composer/ca-bundle": "^1.0", - "php": ">=5.2.0" - }, - "require-dev": { - "symfony/http-client": "^4.3" - }, - "suggest": { - "ext-blackfire": "The C version of the Blackfire probe", - "ext-zlib": "To push config to remote profiling targets" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5.x-dev" - } - }, - "autoload": { - "files": [ - "src/autostart.php" - ], - "psr-4": { - "Blackfire\\": "src/Blackfire" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Blackfire.io", - "email": "support@blackfire.io" - } - ], - "description": "Blackfire.io PHP SDK", - "keywords": [ - "performance", - "profiler", - "uprofiler", - "xhprof" - ], - "time": "2019-12-05T12:48:12+00:00" - }, - { - "name": "composer/ca-bundle", - "version": "1.2.5", - "source": { - "type": "git", - "url": "https://github.com/composer/ca-bundle.git", - "reference": "62e8fc2dc550e5d6d8c9360c7721662670f58149" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/62e8fc2dc550e5d6d8c9360c7721662670f58149", - "reference": "62e8fc2dc550e5d6d8c9360c7721662670f58149", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", - "psr/log": "^1.0", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\CaBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", - "keywords": [ - "cabundle", - "cacert", - "certificate", - "ssl", - "tls" - ], - "time": "2019-12-11T14:44:42+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "doctrine/coding-standard": "^6.0", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2019-10-21T16:45:58+00:00" - }, - { - "name": "fabpot/goutte", - "version": "v3.2.3", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/Goutte.git", - "reference": "3f0eaf0a40181359470651f1565b3e07e3dd31b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/3f0eaf0a40181359470651f1565b3e07e3dd31b8", - "reference": "3f0eaf0a40181359470651f1565b3e07e3dd31b8", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "^6.0", - "php": ">=5.5.0", - "symfony/browser-kit": "~2.1|~3.0|~4.0", - "symfony/css-selector": "~2.1|~3.0|~4.0", - "symfony/dom-crawler": "~2.1|~3.0|~4.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3.3 || ^4" - }, - "type": "application", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Goutte\\": "Goutte" - }, - "exclude-from-classmap": [ - "Goutte/Tests" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "A simple PHP Web Scraper", - "homepage": "https://github.com/FriendsOfPHP/Goutte", - "keywords": [ - "scraper" - ], - "time": "2018-06-29T15:13:57+00:00" - }, - { - "name": "facebook/webdriver", - "version": "1.7.1", - "source": { - "type": "git", - "url": "https://github.com/facebook/php-webdriver.git", - "reference": "e43de70f3c7166169d0f14a374505392734160e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/e43de70f3c7166169d0f14a374505392734160e5", - "reference": "e43de70f3c7166169d0f14a374505392734160e5", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ext-zip": "*", - "php": "^5.6 || ~7.0", - "symfony/process": "^2.8 || ^3.1 || ^4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.0", - "jakub-onderka/php-parallel-lint": "^0.9.2", - "php-coveralls/php-coveralls": "^2.0", - "php-mock/php-mock-phpunit": "^1.1", - "phpunit/phpunit": "^5.7", - "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", - "squizlabs/php_codesniffer": "^2.6", - "symfony/var-dumper": "^3.3 || ^4.0" - }, - "suggest": { - "ext-SimpleXML": "For Firefox profile creation" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-community": "1.5-dev" - } - }, - "autoload": { - "psr-4": { - "Facebook\\WebDriver\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "description": "A PHP client for Selenium WebDriver", - "homepage": "https://github.com/facebook/php-webdriver", - "keywords": [ - "facebook", - "php", - "selenium", - "webdriver" - ], - "time": "2019-06-13T08:02:18+00:00" - }, - { - "name": "laravel/homestead", - "version": "v7.20.0", - "source": { - "type": "git", - "url": "https://github.com/laravel/homestead.git", - "reference": "cae38adcfdde1de1c4581e7a33872adaf9fbf926" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laravel/homestead/zipball/cae38adcfdde1de1c4581e7a33872adaf9fbf926", - "reference": "cae38adcfdde1de1c4581e7a33872adaf9fbf926", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "symfony/console": "~3.3|~4.0", - "symfony/process": "~3.3|~4.0", - "symfony/yaml": "~3.3|~4.0" - }, - "require-dev": { - "phly/changelog-generator": "^2.2", - "phpunit/phpunit": "^5.7 || ^6.0" - }, - "bin": [ - "bin/homestead" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "psr-4": { - "Laravel\\Homestead\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "description": "A virtual machine for web artisans.", - "time": "2018-12-11T02:04:35+00:00" - }, - { - "name": "michelf/php-markdown", - "version": "1.9.0", - "source": { - "type": "git", - "url": "https://github.com/michelf/php-markdown.git", - "reference": "c83178d49e372ca967d1a8c77ae4e051b3a3c75c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/michelf/php-markdown/zipball/c83178d49e372ca967d1a8c77ae4e051b3a3c75c", - "reference": "c83178d49e372ca967d1a8c77ae4e051b3a3c75c", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": ">=4.3 <5.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "Michelf\\": "Michelf/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Michel Fortin", - "email": "michel.fortin@michelf.ca", - "homepage": "https://michelf.ca/", - "role": "Developer" - }, - { - "name": "John Gruber", - "homepage": "https://daringfireball.net/" - } - ], - "description": "PHP Markdown", - "homepage": "https://michelf.ca/projects/php-markdown/", - "keywords": [ - "markdown" - ], - "time": "2019-12-02T02:32:27+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.9.4", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/579bb7356d91f9456ccd505f24ca8b667966a0a7", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "replace": { - "myclabs/deep-copy": "self.version" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, - "files": [ - "src/DeepCopy/deep_copy.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "time": "2019-12-15T19:12:40+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v3.1.5", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", - "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "time": "2018-02-28T20:30:58+00:00" - }, - { - "name": "phar-io/manifest", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "phar-io/version": "^2.0", - "php": "^5.6 || ^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2018-07-08T19:23:20+00:00" - }, - { - "name": "phar-io/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "time": "2018-07-08T19:19:57+00:00" - }, - { - "name": "phing/phing", - "version": "2.16.1", - "source": { - "type": "git", - "url": "https://github.com/phingofficial/phing.git", - "reference": "cbe0f969e434e269af91b4160b86fe899c6e07c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phingofficial/phing/zipball/cbe0f969e434e269af91b4160b86fe899c6e07c7", - "reference": "cbe0f969e434e269af91b4160b86fe899c6e07c7", - "shasum": "" - }, - "require": { - "php": ">=5.2.0", - "symfony/yaml": "^3.1 || ^4.0" - }, - "require-dev": { - "ext-pdo_sqlite": "*", - "mikey179/vfsstream": "^1.6", - "pdepend/pdepend": "2.x", - "pear/archive_tar": "1.4.x", - "pear/http_request2": "dev-trunk", - "pear/net_growl": "dev-trunk", - "pear/pear-core-minimal": "1.10.1", - "pear/versioncontrol_git": "@dev", - "pear/versioncontrol_svn": "~0.5", - "phpdocumentor/phpdocumentor": "2.x", - "phploc/phploc": "~2.0.6", - "phpmd/phpmd": "~2.2", - "phpunit/phpunit": ">=3.7", - "sebastian/git": "~1.0", - "sebastian/phpcpd": "2.x", - "siad007/versioncontrol_hg": "^1.0", - "simpletest/simpletest": "^1.1", - "squizlabs/php_codesniffer": "~2.2" - }, - "suggest": { - "pdepend/pdepend": "PHP version of JDepend", - "pear/archive_tar": "Tar file management class", - "pear/versioncontrol_git": "A library that provides OO interface to handle Git repository", - "pear/versioncontrol_svn": "A simple OO-style interface for Subversion, the free/open-source version control system", - "phpdocumentor/phpdocumentor": "Documentation Generator for PHP", - "phploc/phploc": "A tool for quickly measuring the size of a PHP project", - "phpmd/phpmd": "PHP version of PMD tool", - "phpunit/php-code-coverage": "Library that provides collection, processing, and rendering functionality for PHP code coverage information", - "phpunit/phpunit": "The PHP Unit Testing Framework", - "sebastian/phpcpd": "Copy/Paste Detector (CPD) for PHP code", - "siad007/versioncontrol_hg": "A library for interfacing with Mercurial repositories.", - "tedivm/jshrink": "Javascript Minifier built in PHP" - }, - "bin": [ - "bin/phing" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.16.x-dev" - } - }, - "autoload": { - "classmap": [ - "classes/phing/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "classes" - ], - "license": [ - "LGPL-3.0" - ], - "authors": [ - { - "name": "Michiel Rook", - "email": "mrook@php.net" - }, - { - "name": "Phing Community", - "homepage": "https://www.phing.info/trac/wiki/Development/Contributors" - } - ], - "description": "PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.", - "homepage": "https://www.phing.info/", - "keywords": [ - "build", - "phing", - "task", - "tool" - ], - "time": "2018-01-25T13:18:09+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", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/dbunit.git", - "reference": "e77b469c3962b5a563f09a2a989f1c9bd38b8615" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/e77b469c3962b5a563f09a2a989f1c9bd38b8615", - "reference": "e77b469c3962b5a563f09a2a989f1c9bd38b8615", - "shasum": "" - }, - "require": { - "ext-pdo": "*", - "ext-simplexml": "*", - "php": "^7.1", - "phpunit/phpunit": "^7.0", - "symfony/yaml": "^3.0 || ^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "PHPUnit extension for database interaction testing", - "homepage": "https://github.com/sebastianbergmann/dbunit/", - "keywords": [ - "database", - "testing", - "xunit" - ], - "abandoned": true, - "time": "2018-02-07T06:47:59+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "6.1.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^7.1", - "phpunit/php-file-iterator": "^2.0", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1 || ^4.0", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "suggest": { - "ext-xdebug": "^2.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2018-10-31T16:06:48+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "050bedf145a257b1ff02746c31894800e5122946" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", - "reference": "050bedf145a257b1ff02746c31894800e5122946", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2018-09-13T20:33:42+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "2.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2019-06-07T04:22:29+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2019-09-17T06:23:10+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "7.5.18", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "fcf6c4bfafaadc07785528b06385cce88935474d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fcf6c4bfafaadc07785528b06385cce88935474d", - "reference": "fcf6c4bfafaadc07785528b06385cce88935474d", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.1", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "myclabs/deep-copy": "^1.7", - "phar-io/manifest": "^1.0.2", - "phar-io/version": "^2.0", - "php": "^7.1", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0.7", - "phpunit/php-file-iterator": "^2.0.1", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1", - "sebastian/comparator": "^3.0", - "sebastian/diff": "^3.0", - "sebastian/environment": "^4.0", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0", - "sebastian/version": "^2.0.1" - }, - "conflict": { - "phpunit/phpunit-mock-objects": "*" - }, - "require-dev": { - "ext-pdo": "*" - }, - "suggest": { - "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "7.5-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2019-12-06T05:14:37+00:00" - }, - { - "name": "pimple/pimple", - "version": "v3.2.3", - "source": { - "type": "git", - "url": "https://github.com/silexphp/Pimple.git", - "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32", - "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "psr/container": "^1.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev" - } - }, - "autoload": { - "psr-0": { - "Pimple": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Pimple, a simple Dependency Injection Container", - "homepage": "http://pimple.sensiolabs.org", - "keywords": [ - "container", - "dependency injection" - ], - "time": "2018-01-21T07:42:36+00:00" - }, - { - "name": "sami/sami", - "version": "v4.1.2", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/Sami.git", - "reference": "19b8a82b858bd31544c468317c8307188ccb4022" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/Sami/zipball/19b8a82b858bd31544c468317c8307188ccb4022", - "reference": "19b8a82b858bd31544c468317c8307188ccb4022", - "shasum": "" - }, - "require": { - "blackfire/php-sdk": "^1.5.18", - "michelf/php-markdown": "~1.3", - "nikic/php-parser": "~3.0", - "php": "^7.1.3", - "phpdocumentor/reflection-docblock": "~2.0", - "pimple/pimple": "~3.0", - "symfony/console": "~3.0|~4.0", - "symfony/filesystem": "~3.0|~4.0", - "symfony/finder": "~3.0|~4.0", - "symfony/process": "~3.0|~4.0", - "symfony/yaml": "~3.0|~4.0", - "twig/twig": "~2.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "~4.0" - }, - "bin": [ - "sami.php" - ], - "type": "application", - "extra": { - "branch-alias": { - "dev-master": "4.1-dev" - } - }, - "autoload": { - "psr-4": { - "Sami\\": "Sami/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Sami, an API documentation generator", - "homepage": "http://sami.sensiolabs.org", - "keywords": [ - "phpdoc" - ], - "abandoned": true, - "time": "2018-07-02T13:20:39+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" - }, - { - "name": "sebastian/comparator", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", - "shasum": "" - }, - "require": { - "php": "^7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2018-07-12T15:12:46+00:00" - }, - { - "name": "sebastian/diff", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "time": "2019-02-04T06:01:07+00:00" - }, - { - "name": "sebastian/environment", - "version": "4.2.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", - "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.5" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2019-11-20T08:46:58+00:00" - }, - { - "name": "sebastian/exporter", - "version": "3.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2019-09-14T09:02:43+00:00" - }, - { - "name": "sebastian/global-state", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.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": "2017-04-27T15:39:26+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2018-10-04T04:07:39+00:00" - }, - { - "name": "sebastian/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.5.3", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", - "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "bin": [ - "bin/phpcs", - "bin/phpcbf" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards" - ], - "time": "2019-12-04T04:46:47+00:00" - }, - { - "name": "symfony/browser-kit", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/browser-kit.git", - "reference": "2e4c991e27a97a8c27745720b030ff85a5cebdf6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2e4c991e27a97a8c27745720b030ff85a5cebdf6", - "reference": "2e4c991e27a97a8c27745720b030ff85a5cebdf6", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/dom-crawler": "~2.8|~3.0|~4.0" - }, - "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\BrowserKit\\": "" - }, - "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 BrowserKit Component", - "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" - }, - { - "name": "symfony/css-selector", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "f819f71ae3ba6f396b4c015bd5895de7d2f1f85f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/f819f71ae3ba6f396b4c015bd5895de7d2f1f85f", - "reference": "f819f71ae3ba6f396b4c015bd5895de7d2f1f85f", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "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": "2019-10-01T11:57:37+00:00" - }, - { - "name": "symfony/dom-crawler", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "6bcffd2eabc4ca087faaaf54e26c8ff3a40284f3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/6bcffd2eabc4ca087faaaf54e26c8ff3a40284f3", - "reference": "6bcffd2eabc4ca087faaaf54e26c8ff3a40284f3", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/css-selector": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "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 DomCrawler Component", - "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-06-13T22:48:21+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^7.1.3", - "ext-json": "*" - }, - "platform-dev": [], - "platform-overrides": { - "php": "7.1.3" - } -} diff --git a/install/update/new/config/default/config.yml b/install/update/new/config/default/config.yml deleted file mode 100644 index e8d0536..0000000 --- a/install/update/new/config/default/config.yml +++ /dev/null @@ -1 +0,0 @@ -# phpBB's config file (This line is needed because of the packager) diff --git a/install/update/new/config/default/container/parameters.yml b/install/update/new/config/default/container/parameters.yml deleted file mode 100644 index 8fcb401..0000000 --- a/install/update/new/config/default/container/parameters.yml +++ /dev/null @@ -1,22 +0,0 @@ -parameters: - # Disable the usage of the super globals (_GET, _POST, _SERVER...) - core.disable_super_globals: true - - # Datetime class to use - datetime.class: \phpbb\datetime - - # Mimetype guesser priorities - mimetype.guesser.priority.lowest: -2 - mimetype.guesser.priority.low: -1 - mimetype.guesser.priority.default: 0 - mimetype.guesser.priority.high: 1 - mimetype.guesser.priority.highest: 2 - - # List of default password driver types - passwords.algorithms: - - passwords.driver.argon2id - - passwords.driver.argon2i - - passwords.driver.bcrypt_2y - - passwords.driver.bcrypt - - passwords.driver.salted_md5 - - passwords.driver.phpass diff --git a/install/update/new/config/default/container/services.yml b/install/update/new/config/default/container/services.yml deleted file mode 100644 index 2d47200..0000000 --- a/install/update/new/config/default/container/services.yml +++ /dev/null @@ -1,176 +0,0 @@ -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_ucp.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/install/update/new/config/default/container/services_attachment.yml b/install/update/new/config/default/container/services_attachment.yml deleted file mode 100644 index c56ced2..0000000 --- a/install/update/new/config/default/container/services_attachment.yml +++ /dev/null @@ -1,40 +0,0 @@ -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/install/update/new/config/default/container/services_auth.yml b/install/update/new/config/default/container/services_auth.yml deleted file mode 100644 index 1540bea..0000000 --- a/install/update/new/config/default/container/services_auth.yml +++ /dev/null @@ -1,110 +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: - - '@captcha.factory' - - '@config' - - '@dbal.conn' - - '@passwords.manager' - - '@request' - - '@user' - - '%core.root_path%' - - '%core.php_ext%' - tags: - - { name: auth.provider } - - auth.provider.apache: - class: phpbb\auth\provider\apache - arguments: - - '@config' - - '@dbal.conn' - - '@language' - - '@request' - - '@user' - - '%core.root_path%' - - '%core.php_ext%' - tags: - - { name: auth.provider } - - auth.provider.ldap: - class: phpbb\auth\provider\ldap - arguments: - - '@config' - - '@dbal.conn' - - '@language' - - '@user' - tags: - - { name: auth.provider } - - auth.provider.oauth: - class: phpbb\auth\provider\oauth\oauth - arguments: - - '@config' - - '@dbal.conn' - - '@auth.provider.db' - - '@dispatcher' - - '@language' - - '@request' - - '@auth.provider.oauth.service_collection' - - '@user' - - '%tables.auth_provider_oauth_token_storage%' - - '%tables.auth_provider_oauth_states%' - - '%tables.auth_provider_oauth_account_assoc%' - - '%tables.users%' - - '%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/install/update/new/config/default/container/services_avatar.yml b/install/update/new/config/default/container/services_avatar.yml deleted file mode 100644 index d96aa62..0000000 --- a/install/update/new/config/default/container/services_avatar.yml +++ /dev/null @@ -1,73 +0,0 @@ -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/install/update/new/config/default/container/services_captcha.yml b/install/update/new/config/default/container/services_captcha.yml deleted file mode 100644 index e462c43..0000000 --- a/install/update/new/config/default/container/services_captcha.yml +++ /dev/null @@ -1,59 +0,0 @@ -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/install/update/new/config/default/container/services_console.yml b/install/update/new/config/default/container/services_console.yml deleted file mode 100644 index b662102..0000000 --- a/install/update/new/config/default/container/services_console.yml +++ /dev/null @@ -1,287 +0,0 @@ -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.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/install/update/new/config/default/container/services_content.yml b/install/update/new/config/default/container/services_content.yml deleted file mode 100644 index 6717c20..0000000 --- a/install/update/new/config/default/container/services_content.yml +++ /dev/null @@ -1,73 +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' - - '@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/install/update/new/config/default/container/services_cron.yml b/install/update/new/config/default/container/services_cron.yml deleted file mode 100644 index 70f70e3..0000000 --- a/install/update/new/config/default/container/services_cron.yml +++ /dev/null @@ -1,248 +0,0 @@ -services: - cron.manager: - class: phpbb\cron\manager - arguments: - - '@cron.task_collection' - - '@routing.helper' - - '%core.root_path%' - - '%core.php_ext%' - - cron.lock_db: - class: phpbb\lock\db - arguments: - - cron_lock - - '@config' - - '@dbal.conn' - - cron.controller: - class: phpbb\cron\controller\cron - - cron.event_listener: - class: phpbb\cron\event\cron_runner_listener - arguments: - - '@cron.lock_db' - - '@cron.manager' - - '@request' - tags: - - { name: kernel.event_subscriber } - -# ----- 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/install/update/new/config/default/container/services_db.yml b/install/update/new/config/default/container/services_db.yml deleted file mode 100644 index d538177..0000000 --- a/install/update/new/config/default/container/services_db.yml +++ /dev/null @@ -1,71 +0,0 @@ -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/install/update/new/config/default/container/services_event.yml b/install/update/new/config/default/container/services_event.yml deleted file mode 100644 index 5696275..0000000 --- a/install/update/new/config/default/container/services_event.yml +++ /dev/null @@ -1,26 +0,0 @@ -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/install/update/new/config/default/container/services_feed.yml b/install/update/new/config/default/container/services_feed.yml deleted file mode 100644 index e8bac4b..0000000 --- a/install/update/new/config/default/container/services_feed.yml +++ /dev/null @@ -1,126 +0,0 @@ -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/install/update/new/config/default/container/services_files.yml b/install/update/new/config/default/container/services_files.yml deleted file mode 100644 index ba1fdb4..0000000 --- a/install/update/new/config/default/container/services_files.yml +++ /dev/null @@ -1,57 +0,0 @@ -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/install/update/new/config/default/container/services_filesystem.yml b/install/update/new/config/default/container/services_filesystem.yml deleted file mode 100644 index 828f907..0000000 --- a/install/update/new/config/default/container/services_filesystem.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - filesystem: - class: phpbb\filesystem\filesystem diff --git a/install/update/new/config/default/container/services_help.yml b/install/update/new/config/default/container/services_help.yml deleted file mode 100644 index 1bff001..0000000 --- a/install/update/new/config/default/container/services_help.yml +++ /dev/null @@ -1,27 +0,0 @@ -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/install/update/new/config/default/container/services_hook.yml b/install/update/new/config/default/container/services_hook.yml deleted file mode 100644 index 10a8418..0000000 --- a/install/update/new/config/default/container/services_hook.yml +++ /dev/null @@ -1,7 +0,0 @@ -services: - hook_finder: - class: phpbb\hook\finder - arguments: - - '%core.root_path%' - - '%core.php_ext%' - - '@cache.driver' diff --git a/install/update/new/config/default/container/services_http.yml b/install/update/new/config/default/container/services_http.yml deleted file mode 100644 index 49cfbf5..0000000 --- a/install/update/new/config/default/container/services_http.yml +++ /dev/null @@ -1,23 +0,0 @@ -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/install/update/new/config/default/container/services_language.yml b/install/update/new/config/default/container/services_language.yml deleted file mode 100644 index 8201fbf..0000000 --- a/install/update/new/config/default/container/services_language.yml +++ /dev/null @@ -1,22 +0,0 @@ -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/install/update/new/config/default/container/services_migrator.yml b/install/update/new/config/default/container/services_migrator.yml deleted file mode 100644 index c63b087..0000000 --- a/install/update/new/config/default/container/services_migrator.yml +++ /dev/null @@ -1,64 +0,0 @@ -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/install/update/new/config/default/container/services_mimetype_guesser.yml b/install/update/new/config/default/container/services_mimetype_guesser.yml deleted file mode 100644 index 432470d..0000000 --- a/install/update/new/config/default/container/services_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/install/update/new/config/default/container/services_module.yml b/install/update/new/config/default/container/services_module.yml deleted file mode 100644 index a057e55..0000000 --- a/install/update/new/config/default/container/services_module.yml +++ /dev/null @@ -1,10 +0,0 @@ -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/install/update/new/config/default/container/services_notification.yml b/install/update/new/config/default/container/services_notification.yml deleted file mode 100644 index 6c3cea3..0000000 --- a/install/update/new/config/default/container/services_notification.yml +++ /dev/null @@ -1,224 +0,0 @@ -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/install/update/new/config/default/container/services_password.yml b/install/update/new/config/default/container/services_password.yml deleted file mode 100644 index a9adbeb..0000000 --- a/install/update/new/config/default/container/services_password.yml +++ /dev/null @@ -1,156 +0,0 @@ -parameters: - passwords.driver.argon2_memory_cost: 1024 - passwords.driver.argon2_threads: 2 - passwords.driver.argon2_time_cost: 2 - 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.argon2i: - class: phpbb\passwords\driver\argon2i - arguments: - - '@config' - - '@passwords.driver_helper' - - '%passwords.driver.argon2_memory_cost%' - - '%passwords.driver.argon2_threads%' - - '%passwords.driver.argon2_time_cost%' - tags: - - { name: passwords.driver } - - passwords.driver.argon2id: - class: phpbb\passwords\driver\argon2id - parent: passwords.driver.argon2i - tags: - - { name: 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/install/update/new/config/default/container/services_php.yml b/install/update/new/config/default/container/services_php.yml deleted file mode 100644 index 2934996..0000000 --- a/install/update/new/config/default/container/services_php.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - php_ini: - class: bantu\IniGetWrapper\IniGetWrapper diff --git a/install/update/new/config/default/container/services_profilefield.yml b/install/update/new/config/default/container/services_profilefield.yml deleted file mode 100644 index 90b2283..0000000 --- a/install/update/new/config/default/container/services_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/install/update/new/config/default/container/services_report.yml b/install/update/new/config/default/container/services_report.yml deleted file mode 100644 index 2c5b3bf..0000000 --- a/install/update/new/config/default/container/services_report.yml +++ /dev/null @@ -1,53 +0,0 @@ -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/install/update/new/config/default/container/services_routing.yml b/install/update/new/config/default/container/services_routing.yml deleted file mode 100644 index 0bf0a33..0000000 --- a/install/update/new/config/default/container/services_routing.yml +++ /dev/null @@ -1,77 +0,0 @@ -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' - - '@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/install/update/new/config/default/container/services_text_formatter.yml b/install/update/new/config/default/container/services_text_formatter.yml deleted file mode 100644 index 4e4abf6..0000000 --- a/install/update/new/config/default/container/services_text_formatter.yml +++ /dev/null @@ -1,84 +0,0 @@ -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.acp_utils: - class: phpbb\textformatter\s9e\acp_utils - arguments: - - '@text_formatter.s9e.factory' - - 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/install/update/new/config/default/container/services_text_reparser.yml b/install/update/new/config/default/container/services_text_reparser.yml deleted file mode 100644 index 4bc49f5..0000000 --- a/install/update/new/config/default/container/services_text_reparser.yml +++ /dev/null @@ -1,109 +0,0 @@ -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/install/update/new/config/default/container/services_twig.yml b/install/update/new/config/default/container/services_twig.yml deleted file mode 100644 index 6f70155..0000000 --- a/install/update/new/config/default/container/services_twig.yml +++ /dev/null @@ -1,86 +0,0 @@ -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' - - '@template.twig.environment' - - '@language' - tags: - - { name: twig.extension } - - template.twig.extensions.avatar: - class: phpbb\template\twig\extension\avatar - tags: - - { name: twig.extension } - - template.twig.extensions.config: - class: phpbb\template\twig\extension\config - arguments: - - '@config' - tags: - - { name: twig.extension } - - template.twig.extensions.routing: - class: phpbb\template\twig\extension\routing - arguments: - - '@routing.helper' - tags: - - { name: twig.extension } - - template.twig.extensions.username: - class: phpbb\template\twig\extension\username - 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/install/update/new/config/default/container/services_ucp.yml b/install/update/new/config/default/container/services_ucp.yml deleted file mode 100644 index 861fa4a..0000000 --- a/install/update/new/config/default/container/services_ucp.yml +++ /dev/null @@ -1,17 +0,0 @@ -services: - phpbb.ucp.controller.reset_password: - class: phpbb\ucp\controller\reset_password - arguments: - - '@config' - - '@dbal.conn' - - '@dispatcher' - - '@controller.helper' - - '@language' - - '@log' - - '@passwords.manager' - - '@request' - - '@template' - - '@user' - - '%tables.users%' - - '%core.root_path%' - - '%core.php_ext%' diff --git a/install/update/new/config/default/container/services_user.yml b/install/update/new/config/default/container/services_user.yml deleted file mode 100644 index 7e634c6..0000000 --- a/install/update/new/config/default/container/services_user.yml +++ /dev/null @@ -1,20 +0,0 @@ -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/install/update/new/config/default/container/tables.yml b/install/update/new/config/default/container/tables.yml deleted file mode 100644 index 4aed357..0000000 --- a/install/update/new/config/default/container/tables.yml +++ /dev/null @@ -1,78 +0,0 @@ -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/install/update/new/config/default/routing/cron.yml b/install/update/new/config/default/routing/cron.yml deleted file mode 100644 index 5a63416..0000000 --- a/install/update/new/config/default/routing/cron.yml +++ /dev/null @@ -1,3 +0,0 @@ -phpbb_cron_run: - path: /{cron_type} - defaults: { _controller: cron.controller:handle } diff --git a/install/update/new/config/default/routing/feed.yml b/install/update/new/config/default/routing/feed.yml deleted file mode 100644 index 22c9ea5..0000000 --- a/install/update/new/config/default/routing/feed.yml +++ /dev/null @@ -1,35 +0,0 @@ -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/install/update/new/config/default/routing/help.yml b/install/update/new/config/default/routing/help.yml deleted file mode 100644 index 8d43839..0000000 --- a/install/update/new/config/default/routing/help.yml +++ /dev/null @@ -1,7 +0,0 @@ -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/install/update/new/config/default/routing/report.yml b/install/update/new/config/default/routing/report.yml deleted file mode 100644 index c386770..0000000 --- a/install/update/new/config/default/routing/report.yml +++ /dev/null @@ -1,17 +0,0 @@ -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/install/update/new/config/default/routing/routing.yml b/install/update/new/config/default/routing/routing.yml deleted file mode 100644 index a5e9265..0000000 --- a/install/update/new/config/default/routing/routing.yml +++ /dev/null @@ -1,32 +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. -# - -phpbb_cron_routing: - resource: cron.yml - prefix: /cron - -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 - -phpbb_ucp_routing: - resource: ucp.yml - prefix: /user diff --git a/install/update/new/config/default/routing/ucp.yml b/install/update/new/config/default/routing/ucp.yml deleted file mode 100644 index 06bd7c3..0000000 --- a/install/update/new/config/default/routing/ucp.yml +++ /dev/null @@ -1,7 +0,0 @@ -phpbb_ucp_reset_password_controller: - path: /reset_password - defaults: { _controller: phpbb.ucp.controller.reset_password:reset } - -phpbb_ucp_forgot_password_controller: - path: /forgot_password - defaults: { _controller: phpbb.ucp.controller.reset_password:request } diff --git a/install/update/new/config/installer/config.yml b/install/update/new/config/installer/config.yml deleted file mode 100644 index 979dbbc..0000000 --- a/install/update/new/config/installer/config.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: ../default/config.yml } diff --git a/install/update/new/config/installer/container/environment.yml b/install/update/new/config/installer/container/environment.yml deleted file mode 100644 index 40a3c7a..0000000 --- a/install/update/new/config/installer/container/environment.yml +++ /dev/null @@ -1,3 +0,0 @@ -imports: - - { resource: services.yml } - - { resource: parameters.yml } diff --git a/install/update/new/config/installer/container/parameters.yml b/install/update/new/config/installer/container/parameters.yml deleted file mode 100644 index f11f7e2..0000000 --- a/install/update/new/config/installer/container/parameters.yml +++ /dev/null @@ -1,5 +0,0 @@ -imports: - - { resource: ../../default/container/parameters.yml } - -parameters: - installer.create_config_file.options: [] diff --git a/install/update/new/config/installer/container/services.yml b/install/update/new/config/installer/container/services.yml deleted file mode 100644 index 7203c0a..0000000 --- a/install/update/new/config/installer/container/services.yml +++ /dev/null @@ -1,104 +0,0 @@ -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/install/update/new/config/installer/container/services_file_updater.yml b/install/update/new/config/installer/container/services_file_updater.yml deleted file mode 100644 index 9d39bb8..0000000 --- a/install/update/new/config/installer/container/services_file_updater.yml +++ /dev/null @@ -1,38 +0,0 @@ -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/install/update/new/config/installer/container/services_install_console.yml b/install/update/new/config/installer/container/services_install_console.yml deleted file mode 100644 index 41d3aa4..0000000 --- a/install/update/new/config/installer/container/services_install_console.yml +++ /dev/null @@ -1,61 +0,0 @@ -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/install/update/new/config/installer/container/services_install_controller.yml b/install/update/new/config/installer/container/services_install_controller.yml deleted file mode 100644 index 5aaba0f..0000000 --- a/install/update/new/config/installer/container/services_install_controller.yml +++ /dev/null @@ -1,73 +0,0 @@ -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/install/update/new/config/installer/container/services_install_data.yml b/install/update/new/config/installer/container/services_install_data.yml deleted file mode 100644 index 5de0017..0000000 --- a/install/update/new/config/installer/container/services_install_data.yml +++ /dev/null @@ -1,55 +0,0 @@ -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/install/update/new/config/installer/container/services_install_database.yml b/install/update/new/config/installer/container/services_install_database.yml deleted file mode 100644 index 33f5965..0000000 --- a/install/update/new/config/installer/container/services_install_database.yml +++ /dev/null @@ -1,71 +0,0 @@ -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/install/update/new/config/installer/container/services_install_filesystem.yml b/install/update/new/config/installer/container/services_install_filesystem.yml deleted file mode 100644 index 65b2a6e..0000000 --- a/install/update/new/config/installer/container/services_install_filesystem.yml +++ /dev/null @@ -1,28 +0,0 @@ -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/install/update/new/config/installer/container/services_install_finish.yml b/install/update/new/config/installer/container/services_install_finish.yml deleted file mode 100644 index 6a46d8f..0000000 --- a/install/update/new/config/installer/container/services_install_finish.yml +++ /dev/null @@ -1,44 +0,0 @@ -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/install/update/new/config/installer/container/services_install_navigation.yml b/install/update/new/config/installer/container/services_install_navigation.yml deleted file mode 100644 index d7151eb..0000000 --- a/install/update/new/config/installer/container/services_install_navigation.yml +++ /dev/null @@ -1,42 +0,0 @@ -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/install/update/new/config/installer/container/services_install_obtain_data.yml b/install/update/new/config/installer/container/services_install_obtain_data.yml deleted file mode 100644 index 010aba8..0000000 --- a/install/update/new/config/installer/container/services_install_obtain_data.yml +++ /dev/null @@ -1,59 +0,0 @@ -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/install/update/new/config/installer/container/services_install_requirements.yml b/install/update/new/config/installer/container/services_install_requirements.yml deleted file mode 100644 index c03eb1f..0000000 --- a/install/update/new/config/installer/container/services_install_requirements.yml +++ /dev/null @@ -1,37 +0,0 @@ -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/install/update/new/config/installer/container/services_installer.yml b/install/update/new/config/installer/container/services_installer.yml deleted file mode 100644 index 57181b2..0000000 --- a/install/update/new/config/installer/container/services_installer.yml +++ /dev/null @@ -1,119 +0,0 @@ -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/install/update/new/config/installer/container/services_update_database.yml b/install/update/new/config/installer/container/services_update_database.yml deleted file mode 100644 index bb97cff..0000000 --- a/install/update/new/config/installer/container/services_update_database.yml +++ /dev/null @@ -1,40 +0,0 @@ -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/install/update/new/config/installer/container/services_update_filesystem.yml b/install/update/new/config/installer/container/services_update_filesystem.yml deleted file mode 100644 index c0a0467..0000000 --- a/install/update/new/config/installer/container/services_update_filesystem.yml +++ /dev/null @@ -1,72 +0,0 @@ -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/install/update/new/config/installer/container/services_update_obtain_data.yml b/install/update/new/config/installer/container/services_update_obtain_data.yml deleted file mode 100644 index 999976a..0000000 --- a/install/update/new/config/installer/container/services_update_obtain_data.yml +++ /dev/null @@ -1,53 +0,0 @@ -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/install/update/new/config/installer/container/services_update_requirements.yml b/install/update/new/config/installer/container/services_update_requirements.yml deleted file mode 100644 index 6b851de..0000000 --- a/install/update/new/config/installer/container/services_update_requirements.yml +++ /dev/null @@ -1,41 +0,0 @@ -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/install/update/new/config/installer/routing/environment.yml b/install/update/new/config/installer/routing/environment.yml deleted file mode 100644 index 7a1f588..0000000 --- a/install/update/new/config/installer/routing/environment.yml +++ /dev/null @@ -1,2 +0,0 @@ -core.default: - resource: installer.yml diff --git a/install/update/new/config/installer/routing/installer.yml b/install/update/new/config/installer/routing/installer.yml deleted file mode 100644 index 66b8893..0000000 --- a/install/update/new/config/installer/routing/installer.yml +++ /dev/null @@ -1,67 +0,0 @@ -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/install/update/new/config/production/config.yml b/install/update/new/config/production/config.yml deleted file mode 100644 index 979dbbc..0000000 --- a/install/update/new/config/production/config.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: ../default/config.yml } diff --git a/install/update/new/config/production/container/environment.yml b/install/update/new/config/production/container/environment.yml deleted file mode 100644 index 40a3c7a..0000000 --- a/install/update/new/config/production/container/environment.yml +++ /dev/null @@ -1,3 +0,0 @@ -imports: - - { resource: services.yml } - - { resource: parameters.yml } diff --git a/install/update/new/config/production/container/parameters.yml b/install/update/new/config/production/container/parameters.yml deleted file mode 100644 index 0447646..0000000 --- a/install/update/new/config/production/container/parameters.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: ../../default/container/parameters.yml } diff --git a/install/update/new/config/production/container/services.yml b/install/update/new/config/production/container/services.yml deleted file mode 100644 index b302f0f..0000000 --- a/install/update/new/config/production/container/services.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: ../../default/container/services.yml } diff --git a/install/update/new/config/production/routing/environment.yml b/install/update/new/config/production/routing/environment.yml deleted file mode 100644 index 301183b..0000000 --- a/install/update/new/config/production/routing/environment.yml +++ /dev/null @@ -1,2 +0,0 @@ -core.default: - resource: ../../default/routing/routing.yml diff --git a/install/update/new/cron.php b/install/update/new/cron.php deleted file mode 100644 index c99b772..0000000 --- a/install/update/new/cron.php +++ /dev/null @@ -1,37 +0,0 @@ - -* @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\HttpFoundation\RedirectResponse; - -/** -*/ -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); - -// Do not update users last page entry -$user->session_begin(false); -$auth->acl($user->data); - -$cron_type = $request->variable('cron_type', ''); - -$get_params_array = $request->get_super_global(\phpbb\request\request_interface::GET); - -/** @var \phpbb\controller\helper $controller_helper */ -$controller_helper = $phpbb_container->get('controller.helper'); -$response = new RedirectResponse( - $controller_helper->route('phpbb_cron_run', $get_params_array, false), - 301 -); -$response->send(); diff --git a/install/update/new/download/file.php b/install/update/new/download/file.php deleted file mode 100644 index 6d0796d..0000000 --- a/install/update/new/download/file.php +++ /dev/null @@ -1,321 +0,0 @@ - -* @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); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); - -// Thank you sun. -if (isset($_SERVER['CONTENT_TYPE'])) -{ - if ($_SERVER['CONTENT_TYPE'] === 'application/x-java-archive') - { - exit; - } -} -else if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'Java') !== false) -{ - exit; -} - -if (isset($_GET['avatar'])) -{ - 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_ENVIRONMENT')) - { - @define('PHPBB_ENVIRONMENT', 'production'); - } - - if (!defined('PHPBB_INSTALLED') || empty($dbms) || empty($acm_type)) - { - exit; - } - - require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/functions.' . $phpEx); - require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx); - require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - - // Setup class loader first - $phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/", $phpEx); - $phpbb_class_loader_ext->register(); - - // Set up 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); - - /* @var $config \phpbb\config\config */ - $config = $phpbb_container->get('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->variable('avatar', ''); - $avatar_group = false; - $exit = false; - - if (isset($filename[0]) && $filename[0] === 'g') - { - $avatar_group = true; - $filename = substr($filename, 1); - } - - // '==' is not a bug - . as the first char is as bad as no dot at all - if (strpos($filename, '.') == false) - { - send_status_line(403, 'Forbidden'); - $exit = true; - } - - if (!$exit) - { - $ext = substr(strrchr($filename, '.'), 1); - $stamp = (int) substr(stristr($filename, '_'), 1); - $filename = (int) $filename; - $exit = set_modified_headers($stamp, $browser); - } - if (!$exit && !in_array($ext, array('png', 'gif', 'jpg', 'jpeg'))) - { - // no way such an avatar could exist. They are not following the rules, stop the show. - send_status_line(403, 'Forbidden'); - $exit = true; - } - - - if (!$exit) - { - if (!$filename) - { - // no way such an avatar could exist. They are not following the rules, stop the show. - send_status_line(403, 'Forbidden'); - } - else - { - send_avatar_to_browser(($avatar_group ? 'g' : '') . $filename . '.' . $ext, $browser); - } - } - file_gc(); -} - -// implicit else: we are not in avatar mode -include($phpbb_root_path . 'common.' . $phpEx); -require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx); - -$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'); - trigger_error('ATTACHMENT_FUNCTIONALITY_DISABLED'); -} - -if (!$attach_id) -{ - send_status_line(404, 'Not Found'); - trigger_error('NO_ATTACHMENT_SELECTED'); -} - -$sql = 'SELECT attach_id, post_msg_id, topic_id, in_message, poster_id, is_orphan, physical_filename, real_filename, extension, mimetype, filesize, filetime - FROM ' . ATTACHMENTS_TABLE . " - WHERE attach_id = $attach_id"; -$result = $db->sql_query($sql); -$attachment = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -if (!$attachment) -{ - send_status_line(404, 'Not Found'); - trigger_error('ERROR_NO_ATTACHMENT'); -} -else if (!download_allowed()) -{ - send_status_line(403, 'Forbidden'); - trigger_error($user->lang['LINKAGE_FORBIDDEN']); -} -else -{ - $attachment['physical_filename'] = utf8_basename($attachment['physical_filename']); - - if (!$attachment['in_message'] && !$config['allow_attachments'] || $attachment['in_message'] && !$config['allow_pm_attach']) - { - send_status_line(404, 'Not Found'); - trigger_error('ATTACHMENT_FUNCTIONALITY_DISABLED'); - } - - if ($attachment['is_orphan']) - { - // We allow admins having attachment permissions to see orphan attachments... - $own_attachment = ($auth->acl_get('a_attach') || $attachment['poster_id'] == $user->data['user_id']) ? true : false; - - if (!$own_attachment || ($attachment['in_message'] && !$auth->acl_get('u_pm_download')) || (!$attachment['in_message'] && !$auth->acl_get('u_download'))) - { - send_status_line(404, 'Not Found'); - trigger_error('ERROR_NO_ATTACHMENT'); - } - - // Obtain all extensions... - $extensions = $cache->obtain_attach_extensions(true); - } - else - { - if (!$attachment['in_message']) - { - phpbb_download_handle_forum_auth($db, $auth, $attachment['topic_id']); - - $sql = 'SELECT forum_id, post_visibility - FROM ' . POSTS_TABLE . ' - WHERE post_id = ' . (int) $attachment['post_msg_id']; - $result = $db->sql_query($sql); - $post_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - 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'); - trigger_error('ERROR_NO_ATTACHMENT'); - } - } - else - { - // Attachment is in a private message. - $post_row = array('forum_id' => false); - phpbb_download_handle_pm_auth($db, $auth, $user->data['user_id'], $attachment['post_msg_id']); - } - - $extensions = array(); - if (!extension_allowed($post_row['forum_id'], $attachment['extension'], $extensions)) - { - send_status_line(403, 'Forbidden'); - trigger_error(sprintf($user->lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachment['extension'])); - } - } - - $download_mode = (int) $extensions[$attachment['extension']]['download_mode']; - $display_cat = $extensions[$attachment['extension']]['display_cat']; - - if (($display_cat == ATTACHMENT_CATEGORY_IMAGE || $display_cat == ATTACHMENT_CATEGORY_THUMB) && !$user->optionget('viewimg')) - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - - /** - * Event to modify data before sending file to browser - * - * @event core.download_file_send_to_browser_before - * @var int attach_id The attachment ID - * @var array attachment Array with attachment data - * @var int display_cat Attachment category - * @var int download_mode File extension specific download mode - * @var array extensions Array with file extensions data - * @var string mode Download mode - * @var bool thumbnail Flag indicating if the file is a thumbnail - * @since 3.1.6-RC1 - * @changed 3.1.7-RC1 Fixing wrong name of a variable (replacing "extension" by "extensions") - */ - $vars = array( - 'attach_id', - 'attachment', - 'display_cat', - 'download_mode', - 'extensions', - 'mode', - 'thumbnail', - ); - extract($phpbb_dispatcher->trigger_event('core.download_file_send_to_browser_before', compact($vars))); - - if ($thumbnail) - { - $attachment['physical_filename'] = 'thumb_' . $attachment['physical_filename']; - } - else if ($display_cat == ATTACHMENT_CATEGORY_NONE && !$attachment['is_orphan'] && !phpbb_http_byte_range($attachment['filesize'])) - { - // Update download count - phpbb_increment_downloads($db, $attachment['attach_id']); - } - - if ($display_cat == ATTACHMENT_CATEGORY_IMAGE && $mode === 'view' && (strpos($attachment['mimetype'], 'image') === 0) && (strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7)) - { - wrap_img_in_html(append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'id=' . $attachment['attach_id']), $attachment['real_filename']); - file_gc(); - } - else - { - // Determine the 'presenting'-method - if ($download_mode == PHYSICAL_LINK) - { - // This presenting method should no longer be used - if (!@is_dir($phpbb_root_path . $config['upload_path'])) - { - send_status_line(500, 'Internal Server Error'); - trigger_error($user->lang['PHYSICAL_DOWNLOAD_NOT_POSSIBLE']); - } - - redirect($phpbb_root_path . $config['upload_path'] . '/' . $attachment['physical_filename']); - file_gc(); - } - else - { - send_file_to_browser($attachment, $config['upload_path'], $display_cat); - file_gc(); - } - } -} diff --git a/install/update/new/ext/phpbb/viglink/acp/viglink_helper.php b/install/update/new/ext/phpbb/viglink/acp/viglink_helper.php deleted file mode 100644 index 36bf313..0000000 --- a/install/update/new/ext/phpbb/viglink/acp/viglink_helper.php +++ /dev/null @@ -1,147 +0,0 @@ - - * @license GNU General Public License, version 2 (GPL-2.0) - * - */ - -namespace phpbb\viglink\acp; - -/** - * Class to handle allowing or disallowing VigLink services - */ -class viglink_helper -{ - /** @var \phpbb\cache\driver\driver_interface $cache */ - protected $cache; - - /** @var \phpbb\config\config $config */ - protected $config; - - /** @var \phpbb\file_downloader $file_downloader */ - protected $file_downloader; - - /** @var \phpbb\language\language $language */ - protected $language; - - /** @var \phpbb\log\log $log */ - protected $log; - - /** @var \phpbb\user $user */ - protected $user; - - /** @var bool Use SSL or not */ - protected $use_ssl = false; - - /** - * Constructor - * - * @param \phpbb\cache\driver\driver_interface $cache - * @param \phpbb\config\config $config - * @param \phpbb\file_downloader $file_downloader - * @param \phpbb\language\language $language - * @param \phpbb\log\log $log - * @param \phpbb\user $user - */ - public function __construct(\phpbb\cache\driver\driver_interface $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader, \phpbb\language\language $language, \phpbb\log\log $log, \phpbb\user $user) - { - $this->cache = $cache; - $this->config = $config; - $this->file_downloader = $file_downloader; - $this->language = $language; - $this->log = $log; - $this->user = $user; - } - - /** - * Obtains the latest VigLink services information from phpBB - * - * @param bool $force_update Ignores cached data. Defaults to false. - * @param bool $force_cache Force the use of the cache. Override $force_update. - * - * @throws \RuntimeException - * - * @return void - */ - public function set_viglink_services($force_update = false, $force_cache = false) - { - $cache_key = '_versioncheck_viglink_' . $this->use_ssl; - - $info = $this->cache->get($cache_key); - - if ($info === false && $force_cache) - { - throw new \RuntimeException($this->language->lang('VERSIONCHECK_FAIL')); - } - - if ($info === false || $force_update) - { - try - { - $info = $this->file_downloader->get('www.phpbb.com', '/viglink', 'enabled', 443); - } - 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->language, 'lang'), $prepare_parameters)); - } - - if ($info === '0') - { - $this->set_viglink_configs(array( - 'allow_viglink_phpbb' => false, - )); - } - else - { - $info = '1'; - $this->set_viglink_configs(array( - 'allow_viglink_phpbb' => true, - )); - } - - $this->cache->put($cache_key, $info, 86400); // 24 hours - } - } - - /** - * Sets VigLink service configs as determined by phpBB - * - * @param array $data Array of VigLink file data. - * - * @return void - */ - protected function set_viglink_configs($data) - { - $viglink_configs = array( - 'allow_viglink_phpbb', - 'phpbb_viglink_api_key', - ); - - foreach ($viglink_configs as $cfg_name) - { - if (array_key_exists($cfg_name, $data) && ($data[$cfg_name] != $this->config[$cfg_name] || !isset($this->config[$cfg_name]))) - { - $this->config->set($cfg_name, $data[$cfg_name]); - } - } - - $this->config->set('viglink_last_gc', time(), false); - } - - /** - * Log a VigLink error message to the error log - * - * @param string $message The error message - */ - public function log_viglink_error($message) - { - $user_id = empty($this->user->data) ? ANONYMOUS : $this->user->data['user_id']; - $user_ip = empty($this->user->ip) ? '' : $this->user->ip; - - $this->log->add('critical', $user_id, $user_ip, 'LOG_VIGLINK_CHECK_FAIL', false, array($message)); - } -} diff --git a/install/update/new/ext/phpbb/viglink/composer.json b/install/update/new/ext/phpbb/viglink/composer.json deleted file mode 100644 index e1e73f3..0000000 --- a/install/update/new/ext/phpbb/viglink/composer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "phpbb/viglink", - "type": "phpbb-extension", - "description": "The VigLink extension for phpBB makes it possible to earn revenue, without any change to the user experience, when users post and follow links to commercial sites.", - "homepage": "https://www.phpbb.com", - "version": "1.0.5", - "keywords": ["phpbb", "extension", "viglink"], - "license": "GPL-2.0-only", - "authors": [ - { - "name": "phpBB Limited", - "email": "operations@phpbb.com", - "homepage": "https://www.phpbb.com/go/authors" - } - ], - "require": { - "php": ">=5.4", - "phpbb/phpbb": ">=3.2.0", - "composer/installers": "~1.0" - }, - "extra": { - "display-name": "VigLink", - "soft-require": { - "phpbb/phpbb": ">=3.2.0-b1,<4.0.0@dev" - } - } -} diff --git a/install/update/new/ext/phpbb/viglink/composer.lock b/install/update/new/ext/phpbb/viglink/composer.lock deleted file mode 100644 index 1f8e919..0000000 --- a/install/update/new/ext/phpbb/viglink/composer.lock +++ /dev/null @@ -1,2443 +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#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "b80efb4b6261de83a1e263bb46ddfa8b", - "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": "composer/installers", - "version": "v1.7.0", - "source": { - "type": "git", - "url": "https://github.com/composer/installers.git", - "reference": "141b272484481432cda342727a427dc1e206bfa0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/141b272484481432cda342727a427dc1e206bfa0", - "reference": "141b272484481432cda342727a427dc1e206bfa0", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0" - }, - "replace": { - "roundcube/plugin-installer": "*", - "shama/baton": "*" - }, - "require-dev": { - "composer/composer": "1.0.*@dev", - "phpunit/phpunit": "^4.8.36" - }, - "type": "composer-plugin", - "extra": { - "class": "Composer\\Installers\\Plugin", - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Installers\\": "src/Composer/Installers" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kyle Robinson Young", - "email": "kyle@dontkry.com", - "homepage": "https://github.com/shama" - } - ], - "description": "A multi-framework Composer library installer", - "homepage": "https://composer.github.io/installers/", - "keywords": [ - "Craft", - "Dolibarr", - "Eliasis", - "Hurad", - "ImageCMS", - "Kanboard", - "Lan Management System", - "MODX Evo", - "Mautic", - "Maya", - "OXID", - "Plentymarkets", - "Porto", - "RadPHP", - "SMF", - "Thelia", - "Whmcs", - "WolfCMS", - "agl", - "aimeos", - "annotatecms", - "attogram", - "bitrix", - "cakephp", - "chef", - "cockpit", - "codeigniter", - "concrete5", - "croogo", - "dokuwiki", - "drupal", - "eZ Platform", - "elgg", - "expressionengine", - "fuelphp", - "grav", - "installer", - "itop", - "joomla", - "known", - "kohana", - "laravel", - "lavalite", - "lithium", - "magento", - "majima", - "mako", - "mediawiki", - "modulework", - "modx", - "moodle", - "osclass", - "phpbb", - "piwik", - "ppi", - "puppet", - "pxcms", - "reindex", - "roundcube", - "shopware", - "silverstripe", - "sydes", - "symfony", - "typo3", - "wordpress", - "yawik", - "zend", - "zikula" - ], - "time": "2019-08-12T15:00:31+00:00" - }, - { - "name": "google/recaptcha", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/google/recaptcha.git", - "reference": "98c4a6573b27e8b0990ea8789c74ea378795134c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/google/recaptcha/zipball/98c4a6573b27e8b0990ea8789c74ea378795134c", - "reference": "98c4a6573b27e8b0990ea8789c74ea378795134c", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.2.20|^2.15", - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7.5.11" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.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 protects websites from spam and abuse.", - "homepage": "https://www.google.com/recaptcha/", - "keywords": [ - "Abuse", - "captcha", - "recaptcha", - "spam" - ], - "time": "2019-08-16T15:48:25+00:00" - }, - { - "name": "guzzlehttp/guzzle", - "version": "6.5.2", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", - "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", - "shasum": "" - }, - "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.6.1", - "php": ">=5.5" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.1" - }, - "suggest": { - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.5-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "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", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "time": "2019-12-23T11:57:10+00:00" - }, - { - "name": "guzzlehttp/promises", - "version": "v1.3.1", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "time": "2016-12-20T10:07:11+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "1.6.1", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" - }, - "suggest": { - "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Schultze", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "time": "2019-07-01T23:21:34+00:00" - }, - { - "name": "lusitanian/oauth", - "version": "v0.8.11", - "source": { - "type": "git", - "url": "https://github.com/Lusitanian/PHPoAuthLib.git", - "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/fc11a53db4b66da555a6a11fce294f574a8374f9", - "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "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." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.1-dev" - } - }, - "autoload": { - "psr-0": { - "OAuth": "src", - "OAuth\\Unit": "tests" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "David Desberg", - "email": "david@daviddesberg.com" - }, - { - "name": "Elliot Chance", - "email": "elliotchance@gmail.com" - }, - { - "name": "Pieter Hordijk", - "email": "info@pieterhordijk.com" - } - ], - "description": "PHP 5.3+ oAuth 1/2 Library", - "keywords": [ - "Authentication", - "authorization", - "oauth", - "security" - ], - "time": "2018-02-14T22:37:14+00:00" - }, - { - "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/package-versions", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", - "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0.0", - "php": "^7.1.0" - }, - "require-dev": { - "composer/composer": "^1.6.3", - "doctrine/coding-standard": "^5.0.1", - "ext-zip": "*", - "infection/infection": "^0.7.1", - "phpunit/phpunit": "^7.5.17" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-11-15T16:17:10+00:00" - }, - { - "name": "ocramius/proxy-manager", - "version": "2.2.3", - "source": { - "type": "git", - "url": "https://github.com/Ocramius/ProxyManager.git", - "reference": "4d154742e31c35137d5374c998e8f86b54db2e2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/4d154742e31c35137d5374c998e8f86b54db2e2f", - "reference": "4d154742e31c35137d5374c998e8f86b54db2e2f", - "shasum": "" - }, - "require": { - "ocramius/package-versions": "^1.1.3", - "php": "^7.2.0", - "zendframework/zend-code": "^3.3.0" - }, - "require-dev": { - "couscous/couscous": "^1.6.1", - "ext-phar": "*", - "humbug/humbug": "1.0.0-RC.0@RC", - "nikic/php-parser": "^3.1.1", - "padraic/phpunit-accelerator": "dev-master@DEV", - "phpbench/phpbench": "^0.12.2", - "phpstan/phpstan": "dev-master#856eb10a81c1d27c701a83f167dc870fd8f4236a as 0.9.999", - "phpstan/phpstan-phpunit": "dev-master#5629c0a1f4a9c417cb1077cf6693ad9753895761", - "phpunit/phpunit": "^6.4.3", - "squizlabs/php_codesniffer": "^2.9.1" - }, - "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-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.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.io/" - } - ], - "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": "2019-08-10T08:37:15+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.99", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "shasum": "" - }, - "require": { - "php": "^7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "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": "2018-07-02T15:55:56+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": "phpbb/phpbb", - "version": "3.3.0-RC1", - "source": { - "type": "git", - "url": "https://github.com/phpbb/phpbb-app.git", - "reference": "664db37d53bb5490e701d4e016f7df2434e2418e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpbb/phpbb-app/zipball/664db37d53bb5490e701d4e016f7df2434e2418e", - "reference": "664db37d53bb5490e701d4e016f7df2434e2418e", - "shasum": "" - }, - "require": { - "bantu/ini-get-wrapper": "~1.0", - "ext-json": "*", - "google/recaptcha": "~1.1", - "guzzlehttp/guzzle": "~6.3", - "lusitanian/oauth": "^0.8.1", - "marc1706/fast-image-size": "^1.1", - "patchwork/utf8": "^1.1", - "php": ">=7.1", - "s9e/text-formatter": "^2.0", - "symfony/config": "~3.4", - "symfony/console": "~3.4", - "symfony/debug": "~3.4", - "symfony/dependency-injection": "~3.4", - "symfony/event-dispatcher": "~3.4", - "symfony/filesystem": "~3.4", - "symfony/finder": "~3.4", - "symfony/http-foundation": "~3.4", - "symfony/http-kernel": "~3.4", - "symfony/proxy-manager-bridge": "~3.4", - "symfony/routing": "~3.4", - "symfony/twig-bridge": "~3.4", - "symfony/yaml": "~3.4", - "twig/twig": "^1.0 || ^2.0" - }, - "replace": { - "phpbb/phpbb-core": "self.version" - }, - "require-dev": { - "fabpot/goutte": "~3.2", - "facebook/webdriver": "~1.6", - "laravel/homestead": "~7.0", - "phing/phing": "~2.4", - "phpunit/dbunit": "~4.0", - "phpunit/phpunit": "^7.0", - "squizlabs/php_codesniffer": "~3.4", - "symfony/browser-kit": "~3.4", - "symfony/css-selector": "~3.4", - "symfony/dom-crawler": "~3.4" - }, - "type": "project", - "extra": { - "branch-alias": { - "dev-master": "3.3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-only" - ], - "authors": [ - { - "name": "phpBB Limited", - "email": "operations@phpbb.com", - "homepage": "https://www.phpbb.com/go/authors" - } - ], - "description": "phpBB Forum Software application", - "homepage": "https://www.phpbb.com", - "keywords": [ - "forum", - "phpbb" - ], - "time": "2019-12-21T09:51:05+00:00" - }, - { - "name": "psr/container", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "time": "2017-02-14T16:28:37+00:00" - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "time": "2016-08-06T14:39:51+00:00" - }, - { - "name": "psr/log", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2019-11-01T11:05:21+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "s9e/regexp-builder", - "version": "1.4.3", - "source": { - "type": "git", - "url": "https://github.com/s9e/RegexpBuilder.git", - "reference": "59d0167a909659d718f53964f7653d2c83a5f8fe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/s9e/RegexpBuilder/zipball/59d0167a909659d718f53964f7653d2c83a5f8fe", - "reference": "59d0167a909659d718f53964f7653d2c83a5f8fe", - "shasum": "" - }, - "require": { - "lib-pcre": ">=7.2", - "php": ">=5.5.1" - }, - "require-dev": { - "phpunit/phpunit": "<5.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "s9e\\RegexpBuilder\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Single-purpose library that generates regular expressions that match a list of strings.", - "homepage": "https://github.com/s9e/RegexpBuilder/", - "keywords": [ - "regexp" - ], - "time": "2019-04-26T17:55:23+00:00" - }, - { - "name": "s9e/text-formatter", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/s9e/TextFormatter.git", - "reference": "26d6ee3a931a25acfea3096f62f0cc42172f3859" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/s9e/TextFormatter/zipball/26d6ee3a931a25acfea3096f62f0cc42172f3859", - "reference": "26d6ee3a931a25acfea3096f62f0cc42172f3859", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-filter": "*", - "lib-pcre": ">=8.13", - "php": ">=7.1", - "s9e/regexp-builder": "^1.4" - }, - "require-dev": { - "matthiasmullie/minify": "*", - "phpunit/phpunit": "^7 || 8.2.*" - }, - "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", - "extra": { - "version": "2.3.0" - }, - "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-11-17T16:03:56+00:00" - }, - { - "name": "symfony/config", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "a599a867d0e4a07c342b5f1e656b3915a540ddbe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/a599a867d0e4a07c342b5f1e656b3915a540ddbe", - "reference": "a599a867d0e4a07c342b5f1e656b3915a540ddbe", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3", - "symfony/finder": "<3.3" - }, - "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0", - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "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 Config Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T10:45:41+00:00" - }, - { - "name": "symfony/console", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "1ee23b3b659b06c622f2bd2492a229e416eb4586" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1ee23b3b659b06c622f2bd2492a229e416eb4586", - "reference": "1ee23b3b659b06c622f2bd2492a229e416eb4586", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/debug": "~2.8|~3.0|~4.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/process": "<3.3" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~3.3|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.3|~4.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "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 Console Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T10:04:45+00:00" - }, - { - "name": "symfony/debug", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "f72e33fdb1170b326e72c3157f0cd456351dd086" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/f72e33fdb1170b326e72c3157f0cd456351dd086", - "reference": "f72e33fdb1170b326e72c3157f0cd456351dd086", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "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-kernel": "~2.8|~3.0|~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "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 Debug Component", - "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "0d201916bfb3af939fec3c0c8815ea16c60ac1a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0d201916bfb3af939fec3c0c8815ea16c60ac1a2", - "reference": "0d201916bfb3af939fec3c0c8815ea16c60ac1a2", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" - }, - "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", - "symfony/proxy-manager-bridge": "<3.4", - "symfony/yaml": "<3.4" - }, - "provide": { - "psr/container-implementation": "1.0" - }, - "require-dev": { - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "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 DependencyInjection Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T08:33:36+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "f9031c22ec127d4a2450760f81a8677fe8a10177" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f9031c22ec127d4a2450760f81a8677fe8a10177", - "reference": "f9031c22ec127d4a2450760f81a8677fe8a10177", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "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 EventDispatcher Component", - "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "00cdad0936d06fab136944bc2342b762b1c3a4a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/00cdad0936d06fab136944bc2342b762b1c3a4a2", - "reference": "00cdad0936d06fab136944bc2342b762b1c3a4a2", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "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 Filesystem Component", - "homepage": "https://symfony.com", - "time": "2019-11-25T16:36:22+00:00" - }, - { - "name": "symfony/finder", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "290ae21279b37bfd287cdcce640d51204e84afdf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/290ae21279b37bfd287cdcce640d51204e84afdf", - "reference": "290ae21279b37bfd287cdcce640d51204e84afdf", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-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": "2019-11-17T21:55:15+00:00" - }, - { - "name": "symfony/http-foundation", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "d2d0cfe8e319d9df44c4cca570710fcf221d4593" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d2d0cfe8e319d9df44c4cca570710fcf221d4593", - "reference": "d2d0cfe8e319d9df44c4cca570710fcf221d4593", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" - }, - "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "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 HttpFoundation Component", - "homepage": "https://symfony.com", - "time": "2019-11-28T12:52:59+00:00" - }, - { - "name": "symfony/http-kernel", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "c42c8339acb28cfff0fb1786948db4d23d609ff7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/c42c8339acb28cfff0fb1786948db4d23d609ff7", - "reference": "c42c8339acb28cfff0fb1786948db4d23d609ff7", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0", - "symfony/debug": "^3.3.3|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php56": "~1.8" - }, - "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", - "symfony/var-dumper": "<3.3", - "twig/twig": "<1.34|<2.4,>=2" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/cache": "~1.0", - "symfony/browser-kit": "~2.8|~3.0|~4.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.10|^4.0.10", - "symfony/dom-crawler": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" - }, - "suggest": { - "symfony/browser-kit": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" - }, - "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 HttpKernel Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T13:50:37+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.13.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "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 for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2019-11-27T14:18:11+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-php70", - "version": "v1.13.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "af23c7bb26a73b850840823662dda371484926c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/af23c7bb26a73b850840823662dda371484926c4", - "reference": "af23c7bb26a73b850840823662dda371484926c4", - "shasum": "" - }, - "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" - }, - "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 7.0+ 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": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/proxy-manager-bridge.git", - "reference": "3c185a0e45ea13334aaf7b0fa9726922816ebec6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/3c185a0e45ea13334aaf7b0fa9726922816ebec6", - "reference": "3c185a0e45ea13334aaf7b0fa9726922816ebec6", - "shasum": "" - }, - "require": { - "ocramius/proxy-manager": "~0.4|~1.0|~2.0", - "php": "^5.5.9|>=7.0.8", - "symfony/dependency-injection": "~3.4|~4.0" - }, - "require-dev": { - "symfony/config": "~2.8|~3.0|~4.0" - }, - "type": "symfony-bridge", - "extra": { - "branch-alias": { - "dev-master": "3.4-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-08-29T14:54:55+00:00" - }, - { - "name": "symfony/routing", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "b689ccd48e234ea404806d94b07eeb45f9f6f06a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/b689ccd48e234ea404806d94b07eeb45f9f6f06a", - "reference": "b689ccd48e234ea404806d94b07eeb45f9f6f06a", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/config": "<3.3.1", - "symfony/dependency-injection": "<3.3", - "symfony/yaml": "<3.4" - }, - "require-dev": { - "doctrine/annotations": "~1.0", - "psr/log": "~1.0", - "symfony/config": "^3.3.1|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" - }, - "suggest": { - "doctrine/annotations": "For using the annotation loader", - "symfony/config": "For using the all-in-one router or any loader", - "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": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Routing\\": "" - }, - "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 Routing Component", - "homepage": "https://symfony.com", - "keywords": [ - "router", - "routing", - "uri", - "url" - ], - "time": "2019-12-01T08:33:36+00:00" - }, - { - "name": "symfony/twig-bridge", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/twig-bridge.git", - "reference": "49b824ddc7f2d250a1f172349cd9a111d63287c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/49b824ddc7f2d250a1f172349cd9a111d63287c0", - "reference": "49b824ddc7f2d250a1f172349cd9a111d63287c0", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "twig/twig": "^1.41|^2.10" - }, - "conflict": { - "symfony/console": "<3.4", - "symfony/form": "<3.4.31|>=4.0,<4.3.4" - }, - "require-dev": { - "fig/link-util": "^1.0", - "symfony/asset": "~2.8|~3.0|~4.0", - "symfony/console": "~3.4|~4.0", - "symfony/dependency-injection": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/form": "^3.4.31|^4.3.4", - "symfony/http-foundation": "^3.3.11|~4.0", - "symfony/http-kernel": "~3.2|~4.0", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/routing": "~2.8|~3.0|~4.0", - "symfony/security": "^2.8.31|^3.3.13|~4.0", - "symfony/security-acl": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~2.8.10|~3.1.4|~3.2|~4.0", - "symfony/web-link": "~3.3|~4.0", - "symfony/workflow": "~3.3|~4.0", - "symfony/yaml": "~2.8|~3.0|~4.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/web-link": "For using the WebLinkExtension", - "symfony/yaml": "For using the YamlExtension" - }, - "type": "symfony-bridge", - "extra": { - "branch-alias": { - "dev-master": "3.4-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": "2019-11-30T08:19:08+00:00" - }, - { - "name": "symfony/yaml", - "version": "v3.4.36", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "dab657db15207879217fc81df4f875947bf68804" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/dab657db15207879217fc81df4f875947bf68804", - "reference": "dab657db15207879217fc81df4f875947bf68804", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/console": "<3.4" - }, - "require-dev": { - "symfony/console": "~3.4|~4.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "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 Yaml Component", - "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" - }, - { - "name": "twig/twig", - "version": "v2.12.2", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "d761fd1f1c6b867ae09a7d8119a6d95d06dc44ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/d761fd1f1c6b867ae09a7d8119a6d95d06dc44ed", - "reference": "d761fd1f1c6b867ae09a7d8119a6d95d06dc44ed", - "shasum": "" - }, - "require": { - "php": "^7.0", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" - }, - "require-dev": { - "psr/container": "^1.0", - "symfony/debug": "^3.4|^4.2", - "symfony/phpunit-bridge": "^4.4@dev|^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.12-dev" - } - }, - "autoload": { - "psr-0": { - "Twig_": "lib/" - }, - "psr-4": { - "Twig\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Twig Team", - "homepage": "https://twig.symfony.com/contributors", - "role": "Contributors" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], - "time": "2019-11-11T16:52:09+00:00" - }, - { - "name": "zendframework/zend-code", - "version": "3.4.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-code.git", - "reference": "268040548f92c2bfcba164421c1add2ba43abaaa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-code/zipball/268040548f92c2bfcba164421c1add2ba43abaaa", - "reference": "268040548f92c2bfcba164421c1add2ba43abaaa", - "shasum": "" - }, - "require": { - "php": "^7.1", - "zendframework/zend-eventmanager": "^2.6 || ^3.0" - }, - "conflict": { - "phpspec/prophecy": "<1.9.0" - }, - "require-dev": { - "doctrine/annotations": "^1.7", - "ext-phar": "*", - "phpunit/phpunit": "^7.5.16 || ^8.4", - "zendframework/zend-coding-standard": "^1.0", - "zendframework/zend-stdlib": "^2.7 || ^3.0" - }, - "suggest": { - "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", - "zendframework/zend-stdlib": "Zend\\Stdlib component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4.x-dev", - "dev-develop": "3.5.x-dev", - "dev-dev-4.0": "4.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Code\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", - "keywords": [ - "ZendFramework", - "code", - "zf" - ], - "time": "2019-12-10T19:21:15+00:00" - }, - { - "name": "zendframework/zend-eventmanager", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-eventmanager.git", - "reference": "a5e2583a211f73604691586b8406ff7296a946dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/a5e2583a211f73604691586b8406ff7296a946dd", - "reference": "a5e2583a211f73604691586b8406ff7296a946dd", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "athletic/athletic": "^0.1", - "container-interop/container-interop": "^1.1.0", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-stdlib": "^2.7.3 || ^3.0" - }, - "suggest": { - "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", - "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev", - "dev-develop": "3.3-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\EventManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Trigger and listen to events within a PHP application", - "homepage": "https://github.com/zendframework/zend-eventmanager", - "keywords": [ - "event", - "eventmanager", - "events", - "zf2" - ], - "time": "2018-04-25T15:33:34+00:00" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "phpbb/phpbb": 10 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.4" - }, - "platform-dev": [] -} diff --git a/install/update/new/ext/phpbb/viglink/styles/all/theme/viglink.css b/install/update/new/ext/phpbb/viglink/styles/all/theme/viglink.css deleted file mode 100644 index 96c5137..0000000 --- a/install/update/new/ext/phpbb/viglink/styles/all/theme/viglink.css +++ /dev/null @@ -1,18 +0,0 @@ -/* phpBB VigLink Extension Style Sheet - ------------------------------------------------------------------------ - Copyright (c) phpBB Limited - - For full copyright and license information, please see - the docs/CREDITS.txt file. - ------------------------------------------------------------------------ -*/ - -.viglink-header { - background: url("images/VigLink_logo.png") no-repeat 0 0; - padding-bottom: 18px; - padding-left: 142px; -} - -.send-stats-tile > .viglink-header-h2 { - margin-bottom: 10px; -} diff --git a/install/update/new/feed.php b/install/update/new/feed.php deleted file mode 100644 index e384489..0000000 --- a/install/update/new/feed.php +++ /dev/null @@ -1,58 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -* Idea and original RSS Feed 2.0 MOD (Version 1.0.8/9) by leviatan21 -* Original MOD: http://www.phpbb.com/community/viewtopic.php?f=69&t=1214645 -* MOD Author Profile: http://www.phpbb.com/community/memberlist.php?mode=viewprofile&u=345763 -* MOD Author Homepage: http://www.mssti.com/phpbb3/ -* -**/ - -use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\Routing\Exception\InvalidParameterException; - -/** -* @ignore -**/ -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); - -/** @var \phpbb\controller\helper $controller_helper */ -$controller_helper = $phpbb_container->get('controller.helper'); - -$forum_id = $request->variable('f', 0); -$topic_id = $request->variable('t', 0); -$mode = $request->variable('mode', ''); - -if ($forum_id !== 0) -{ - $url = $controller_helper->route('phpbb_feed_forum', array('forum_id' => $forum_id), false); -} -else if ($topic_id !== 0) -{ - $url = $controller_helper->route('phpbb_feed_topic', array('topic_id' => $topic_id), false); -} -else -{ - try - { - $url = $controller_helper->route('phpbb_feed_overall', array('mode' => $mode), false); - } - catch (InvalidParameterException $e) - { - $url = $controller_helper->route('phpbb_feed_index'); - } -} - -$response = new RedirectResponse($url, 301); -$response->send(); diff --git a/install/update/new/includes/acp/acp_attachments.php b/install/update/new/includes/acp/acp_attachments.php deleted file mode 100644 index feeccbe..0000000 --- a/install/update/new/includes/acp/acp_attachments.php +++ /dev/null @@ -1,1730 +0,0 @@ - -* @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_attachments -{ - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\language\language */ - protected $language; - - /** @var ContainerBuilder */ - protected $phpbb_container; - - /** @var \phpbb\template\template */ - protected $template; - - /** @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_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->variable('action', ''); - - $form_key = 'acp_attach'; - 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); - } - - switch ($mode) - { - case 'attach': - $l_title = 'ACP_ATTACHMENT_SETTINGS'; - break; - - case 'extensions': - $l_title = 'ACP_MANAGE_EXTENSIONS'; - break; - - case 'ext_groups': - $l_title = 'ACP_EXTENSION_GROUPS'; - break; - - case 'orphan': - $l_title = 'ACP_ORPHAN_ATTACHMENTS'; - break; - - case 'manage': - $l_title = 'ACP_MANAGE_ATTACHMENTS'; - break; - - default: - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - - $this->tpl_name = 'acp_attachments'; - $this->page_title = $l_title; - - $template->assign_vars(array( - 'L_TITLE' => $user->lang[$l_title], - 'L_TITLE_EXPLAIN' => $user->lang[$l_title . '_EXPLAIN'], - 'U_ACTION' => $this->u_action) - ); - - switch ($mode) - { - case 'attach': - - if (!function_exists('get_supported_image_types')) - { - include($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - } - - $sql = 'SELECT group_name, cat_id - FROM ' . EXTENSION_GROUPS_TABLE . ' - WHERE cat_id > 0 - ORDER BY cat_id'; - $result = $db->sql_query($sql); - - $s_assigned_groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $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); - - $l_legend_cat_images = $user->lang['SETTINGS_CAT_IMAGES'] . ' [' . $user->lang['ASSIGNED_GROUP'] . ': ' . ((!empty($s_assigned_groups[ATTACHMENT_CATEGORY_IMAGE])) ? implode($user->lang['COMMA_SEPARATOR'], $s_assigned_groups[ATTACHMENT_CATEGORY_IMAGE]) : $user->lang['NO_EXT_GROUP']) . ']'; - - $display_vars = array( - 'title' => 'ACP_ATTACHMENT_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_ATTACHMENT_SETTINGS', - - 'img_max_width' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'img_max_height' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'img_link_width' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'img_link_height' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - - 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'upload_path' => array('lang' => 'UPLOAD_DIR', 'validate' => 'wpath', 'type' => 'text:25:100', 'explain' => true), - 'display_order' => array('lang' => 'DISPLAY_ORDER', 'validate' => 'bool', 'type' => 'custom', 'method' => 'display_order', 'explain' => true), - 'attachment_quota' => array('lang' => 'ATTACH_QUOTA', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_filesize' => array('lang' => 'ATTACH_MAX_FILESIZE', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_filesize_pm' => array('lang' => 'ATTACH_MAX_PM_FILESIZE','validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false), - 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false), - 'secure_downloads' => array('lang' => 'SECURE_DOWNLOADS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'secure_allow_deny' => array('lang' => 'SECURE_ALLOW_DENY', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_allow_deny', 'explain' => true), - 'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'check_attachment_content' => array('lang' => 'CHECK_CONTENT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend2' => $l_legend_cat_images, - 'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int: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_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']), - ) - ); - - /** - * Event to add and/or modify acp_attachement configurations - * - * @event core.acp_attachments_config_edit_add - * @var array display_vars Array of config values to display and process - * @var string mode Mode of the config page we are displaying - * @var boolean submit Do we display the form or process the submission - * @since 3.1.11-RC1 - */ - $vars = array('display_vars', 'mode', 'submit'); - extract($phpbb_dispatcher->trigger_event('core.acp_attachments_config_edit_add', compact($vars))); - - $this->new_config = $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 (count($error)) - { - $submit = false; - } - - // We go through the display_vars to make sure no one is trying to set variables he/she is not allowed to... - foreach ($display_vars['vars'] as $config_name => $null) - { - if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false) - { - continue; - } - - $this->new_config[$config_name] = $config_value = $cfg_array[$config_name]; - - if (in_array($config_name, array('attachment_quota', 'max_filesize', 'max_filesize_pm'))) - { - $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) - { - $config->set($config_name, $config_value); - } - } - - $this->perform_site_list(); - - if ($submit) - { - $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 (!count($error)) - { - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - } - - $template->assign_var('S_ATTACHMENT_SETTINGS', true); - - // Secure Download Options - Same procedure as with banning - $allow_deny = ($this->new_config['secure_allow_deny']) ? 'ALLOWED' : 'DISALLOWED'; - - $sql = 'SELECT * - FROM ' . SITELIST_TABLE; - $result = $db->sql_query($sql); - - $defined_ips = ''; - $ips = array(); - - while ($row = $db->sql_fetchrow($result)) - { - $value = ($row['site_ip']) ? $row['site_ip'] : $row['site_hostname']; - if ($value) - { - $defined_ips .= '' . $value . ''; - $ips[$row['site_id']] = $value; - } - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_SECURE_DOWNLOADS' => $this->new_config['secure_downloads'], - 'S_DEFINED_IPS' => ($defined_ips != '') ? true : false, - 'S_WARNING' => (count($error)) ? true : false, - - 'WARNING_MSG' => implode('
', $error), - 'DEFINED_IPS' => $defined_ips, - - 'L_SECURE_TITLE' => $user->lang['DEFINE_' . $allow_deny . '_IPS'], - 'L_IP_EXCLUDE' => $user->lang['EXCLUDE_FROM_' . $allow_deny . '_IP'], - 'L_REMOVE_IPS' => $user->lang['REMOVE_' . $allow_deny . '_IPS']) - ); - - // Output relevant options - foreach ($display_vars['vars'] 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' => (isset($user->lang[$vars])) ? $user->lang[$vars] : $vars) - ); - - continue; - } - - $type = explode(':', $vars['type']); - - $l_explain = ''; - if ($vars['explain'] && isset($vars['lang_explain'])) - { - $l_explain = (isset($user->lang[$vars['lang_explain']])) ? $user->lang[$vars['lang_explain']] : $vars['lang_explain']; - } - else if ($vars['explain']) - { - $l_explain = (isset($user->lang[$vars['lang'] . '_EXPLAIN'])) ? $user->lang[$vars['lang'] . '_EXPLAIN'] : ''; - } - - $content = build_cfg_template($type, $config_key, $this->new_config, $config_key, $vars); - if (empty($content)) - { - continue; - } - - $template->assign_block_vars('options', array( - 'KEY' => $config_key, - 'TITLE' => $user->lang[$vars['lang']], - 'S_EXPLAIN' => $vars['explain'], - 'TITLE_EXPLAIN' => $l_explain, - 'CONTENT' => $content, - ) - ); - - unset($display_vars['vars'][$config_key]); - } - - break; - - case 'extensions': - - if ($submit || isset($_POST['add_extension_check'])) - { - if ($submit) - { - // Change Extensions ? - $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 = count($extension_change_list); $i < $size; $i++) - { - $extensions[$extension_change_list[$i]]['group_id'] = $group_select_list[$i]; - } - - $sql = 'SELECT * - FROM ' . EXTENSIONS_TABLE . ' - ORDER BY extension_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['group_id'] != $extensions[$row['extension_id']]['group_id']) - { - $sql = 'UPDATE ' . EXTENSIONS_TABLE . ' - SET group_id = ' . (int) $extensions[$row['extension_id']]['group_id'] . ' - WHERE extension_id = ' . $row['extension_id']; - $db->sql_query($sql); - - $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->variable('extension_id_list', array(0)); - - if (count($extension_id_list)) - { - $sql = 'SELECT extension - FROM ' . EXTENSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('extension_id', $extension_id_list); - $result = $db->sql_query($sql); - - $extension_list = ''; - while ($row = $db->sql_fetchrow($result)) - { - $extension_list .= ($extension_list == '') ? $row['extension'] : ', ' . $row['extension']; - } - $db->sql_freeresult($result); - - $sql = 'DELETE - FROM ' . EXTENSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('extension_id', $extension_id_list); - $db->sql_query($sql); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXT_DEL', false, array($extension_list)); - } - } - - // Add Extension? - $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 (!count($error)) - { - $sql = 'SELECT extension_id - FROM ' . EXTENSIONS_TABLE . " - WHERE extension = '" . $db->sql_escape($add_extension) . "'"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $error[] = sprintf($user->lang['EXTENSION_EXIST'], $add_extension); - } - $db->sql_freeresult($result); - - if (!count($error)) - { - $sql_ary = array( - 'group_id' => $add_extension_group, - 'extension' => $add_extension - ); - - $db->sql_query('INSERT INTO ' . EXTENSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXT_ADD', false, array($add_extension)); - } - } - } - - if (!count($error)) - { - $notify[] = $user->lang['EXTENSIONS_UPDATED']; - } - - $cache->destroy('_extensions'); - } - - $template->assign_vars(array( - 'S_EXTENSIONS' => true, - 'ADD_EXTENSION' => (isset($add_extension)) ? $add_extension : '', - 'GROUP_SELECT_OPTIONS' => (isset($_POST['add_extension_check'])) ? $this->group_select('add_group_select', $add_extension_group, 'extension_group') : $this->group_select('add_group_select', false, 'extension_group')) - ); - - $sql = 'SELECT * - FROM ' . EXTENSIONS_TABLE . ' - ORDER BY group_id, extension'; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $old_group_id = $row['group_id']; - do - { - $s_spacer = false; - - $current_group_id = $row['group_id']; - if ($old_group_id != $current_group_id) - { - $s_spacer = true; - $old_group_id = $current_group_id; - } - - $template->assign_block_vars('extensions', array( - 'S_SPACER' => $s_spacer, - 'EXTENSION_ID' => $row['extension_id'], - 'EXTENSION' => $row['extension'], - 'GROUP_OPTIONS' => $this->group_select('group_select[]', $row['group_id'])) - ); - } - while ($row = $db->sql_fetchrow($result)); - } - $db->sql_freeresult($result); - - break; - - case 'ext_groups': - - $template->assign_var('S_EXTENSION_GROUPS', true); - - if ($submit) - { - $action = $request->variable('action', ''); - $group_id = $request->variable('g', 0); - - if ($action != 'add' && $action != 'edit') - { - trigger_error('NO_MODE', E_USER_ERROR); - } - - if (!$group_id && $action == 'edit') - { - trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if ($group_id) - { - $sql = 'SELECT * - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $result = $db->sql_query($sql); - $ext_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$ext_row) - { - trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - else - { - $ext_row = array(); - } - - $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) - { - $error[] = $user->lang['NO_EXT_GROUP_NAME']; - } - - // Check New Group Name - if ($new_group_name) - { - $sql = 'SELECT group_id - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($new_group_name)) . "'"; - if ($group_id) - { - $sql .= ' AND group_id <> ' . $group_id; - } - $result = $db->sql_query($sql); - - if ($db->sql_fetchrow($result)) - { - $error[] = sprintf($user->lang['EXTENSION_GROUP_EXIST'], $new_group_name); - } - $db->sql_freeresult($result); - } - - if (!count($error)) - { - // Ok, build the update/insert array - $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->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; - - if ($max_filesize == $config['max_filesize']) - { - $max_filesize = 0; - } - - if (!count($allowed_forums)) - { - $forum_select = false; - } - - $group_ary = array( - 'group_name' => $group_name, - '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, - 'allowed_forums'=> ($forum_select) ? serialize($allowed_forums) : '', - 'allow_in_pm' => ($allow_in_pm) ? 1 : 0, - ); - - if ($action == 'add') - { - $group_ary['download_mode'] = INLINE_LINK; - } - - $sql = ($action == 'add') ? 'INSERT INTO ' . EXTENSION_GROUPS_TABLE . ' ' : 'UPDATE ' . EXTENSION_GROUPS_TABLE . ' SET '; - $sql .= $db->sql_build_array((($action == 'add') ? 'INSERT' : 'UPDATE'), $group_ary); - $sql .= ($action == 'edit') ? " WHERE group_id = $group_id" : ''; - - $db->sql_query($sql); - - if ($action == 'add') - { - $group_id = $db->sql_nextid(); - } - - $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->variable('extensions', array(0)); - - if ($action == 'edit' && count($extension_list)) - { - $sql = 'UPDATE ' . EXTENSIONS_TABLE . " - SET group_id = 0 - WHERE group_id = $group_id"; - $db->sql_query($sql); - } - - if (count($extension_list)) - { - $sql = 'UPDATE ' . EXTENSIONS_TABLE . " - SET group_id = $group_id - WHERE " . $db->sql_in_set('extension_id', $extension_list); - $db->sql_query($sql); - } - - $cache->destroy('_extensions'); - - if (!count($error)) - { - $notify[] = $user->lang['SUCCESS_EXTENSION_GROUP_' . strtoupper($action)]; - } - } - - $cat_lang = array( - ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'], - ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'], - ); - - $group_id = $request->variable('g', 0); - $action = (isset($_POST['add'])) ? 'add' : $action; - - switch ($action) - { - case 'delete': - - if (confirm_box(true)) - { - $sql = 'SELECT group_name - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $result = $db->sql_query($sql); - $group_name = (string) $db->sql_fetchfield('group_name'); - $db->sql_freeresult($result); - - $sql = 'DELETE - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $db->sql_query($sql); - - // Set corresponding Extensions to a pending Group - $sql = 'UPDATE ' . EXTENSIONS_TABLE . " - SET group_id = 0 - WHERE group_id = $group_id"; - $db->sql_query($sql); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXTGROUP_DEL', false, array($group_name)); - - $cache->destroy('_extensions'); - - trigger_error($user->lang['EXTENSION_GROUP_DELETED'] . adm_back_link($this->u_action)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'group_id' => $group_id, - 'action' => 'delete', - ))); - } - - break; - - case 'edit': - - if (!$group_id) - { - trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql = 'SELECT * - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $result = $db->sql_query($sql); - $ext_group_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $forum_ids = (!$ext_group_row['allowed_forums']) ? array() : unserialize(trim($ext_group_row['allowed_forums'])); - - // no break; - - case 'add': - - if ($action == 'add') - { - $ext_group_row = array( - 'group_name' => $request->variable('group_name', '', true), - 'cat_id' => 0, - 'allow_group' => 1, - 'allow_in_pm' => 1, - 'upload_icon' => '', - 'max_filesize' => 0, - ); - - $forum_ids = array(); - } - - $sql = 'SELECT * - FROM ' . EXTENSIONS_TABLE . " - WHERE group_id = $group_id - OR group_id = 0 - ORDER BY extension"; - $result = $db->sql_query($sql); - $extensions = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - if ($ext_group_row['max_filesize'] == 0) - { - $ext_group_row['max_filesize'] = (int) $config['max_filesize']; - } - - $max_filesize = get_formatted_filesize($ext_group_row['max_filesize'], false, array('mb', 'kb', 'b')); - $size_format = $max_filesize['si_identifier']; - $ext_group_row['max_filesize'] = $max_filesize['value']; - - $img_path = $config['upload_icons_path']; - - $filename_list = ''; - $no_image_select = false; - - $imglist = filelist($phpbb_root_path . $img_path); - - if (!empty($imglist[''])) - { - $imglist = array_values($imglist); - $imglist = $imglist[0]; - - foreach ($imglist as $key => $img) - { - if (!$ext_group_row['upload_icon']) - { - $no_image_select = true; - $selected = ''; - } - else - { - $selected = ($ext_group_row['upload_icon'] == $img) ? ' selected="selected"' : ''; - } - - if (strlen($img) > 255) - { - continue; - } - - $filename_list .= ''; - } - } - - $i = 0; - $assigned_extensions = ''; - foreach ($extensions as $num => $row) - { - if ($row['group_id'] == $group_id && $group_id) - { - $assigned_extensions .= ($i) ? ', ' . $row['extension'] : $row['extension']; - $i++; - } - } - - $s_extension_options = ''; - foreach ($extensions as $row) - { - $s_extension_options .= '' . $row['extension'] . ''; - } - - $template->assign_vars(array( - 'IMG_PATH' => $img_path, - 'ACTION' => $action, - 'GROUP_ID' => $group_id, - 'GROUP_NAME' => $ext_group_row['group_name'], - 'ALLOW_GROUP' => $ext_group_row['allow_group'], - 'ALLOW_IN_PM' => $ext_group_row['allow_in_pm'], - 'UPLOAD_ICON_SRC' => $phpbb_root_path . $img_path . '/' . $ext_group_row['upload_icon'], - 'EXTGROUP_FILESIZE' => $ext_group_row['max_filesize'], - 'ASSIGNED_EXTENSIONS' => $assigned_extensions, - - 'S_CATEGORY_SELECT' => $this->category_select('special_category', $group_id, 'category'), - 'S_EXT_GROUP_SIZE_OPTIONS' => size_select_options($size_format), - 'S_EXTENSION_OPTIONS' => $s_extension_options, - 'S_FILENAME_LIST' => $filename_list, - 'S_EDIT_GROUP' => true, - 'S_NO_IMAGE' => $no_image_select, - 'S_FORUM_IDS' => (count($forum_ids)) ? true : false, - - 'U_EXTENSIONS' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&mode=extensions"), - 'U_BACK' => $this->u_action, - - 'L_LEGEND' => $user->lang[strtoupper($action) . '_EXTENSION_GROUP']) - ); - - $s_forum_id_options = ''; - - /** @todo use in-built function **/ - - $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql, 600); - - $right = $cat_right = $padding_inc = 0; - $padding = $forum_list = $holding = ''; - $padding_store = array('0' => ''); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) - { - // Non-postable forum with no subforums, don't display - continue; - } - - if (!$auth->acl_get('f_list', $row['forum_id'])) - { - // if the user does not have permissions to list this forum skip - continue; - } - - if ($row['left_id'] < $right) - { - $padding .= '   '; - $padding_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - $padding = empty($padding_store[$row['parent_id']]) ? '' : $padding_store[$row['parent_id']]; - } - - $right = $row['right_id']; - - $selected = (in_array($row['forum_id'], $forum_ids)) ? ' selected="selected"' : ''; - - if ($row['left_id'] > $cat_right) - { - // make sure we don't forget anything - $s_forum_id_options .= $holding; - $holding = ''; - } - - if ($row['right_id'] - $row['left_id'] > 1) - { - $cat_right = max($cat_right, $row['right_id']); - - $holding .= ''; - } - else - { - $s_forum_id_options .= $holding . ''; - $holding = ''; - } - } - - if ($holding) - { - $s_forum_id_options .= $holding; - } - - $db->sql_freeresult($result); - unset($padding_store); - - $template->assign_vars(array( - 'S_FORUM_ID_OPTIONS' => $s_forum_id_options) - ); - - break; - } - - $sql = 'SELECT * - FROM ' . EXTENSION_GROUPS_TABLE . ' - ORDER BY allow_group DESC, allow_in_pm DESC, group_name'; - $result = $db->sql_query($sql); - - $old_allow_group = $old_allow_pm = 1; - while ($row = $db->sql_fetchrow($result)) - { - $s_add_spacer = ($old_allow_group != $row['allow_group'] || $old_allow_pm != $row['allow_in_pm']) ? true : false; - - $template->assign_block_vars('groups', array( - 'S_ADD_SPACER' => $s_add_spacer, - 'S_ALLOWED_IN_PM' => ($row['allow_in_pm']) ? true : false, - 'S_GROUP_ALLOWED' => ($row['allow_group']) ? true : false, - - 'U_EDIT' => $this->u_action . "&action=edit&g={$row['group_id']}", - 'U_DELETE' => $this->u_action . "&action=delete&g={$row['group_id']}", - - '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']], - ) - ); - - $old_allow_group = $row['allow_group']; - $old_allow_pm = $row['allow_in_pm']; - } - $db->sql_freeresult($result); - - break; - - case 'orphan': - - /* @var $pagination \phpbb\pagination */ - $pagination = $this->phpbb_container->get('pagination'); - - if ($submit) - { - $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 (count($delete_files)) - { - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', $delete_files) . ' - AND is_orphan = 1'; - $result = $db->sql_query($sql); - - $delete_files = array(); - while ($row = $db->sql_fetchrow($result)) - { - $this->attachment_manager->unlink($row['physical_filename'], 'file'); - - if ($row['thumbnail']) - { - $this->attachment_manager->unlink($row['physical_filename'], 'thumbnail'); - } - - $delete_files[$row['attach_id']] = $row['real_filename']; - } - $db->sql_freeresult($result); - } - - if (count($delete_files)) - { - $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($delete_files)); - $db->sql_query($sql); - - $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)); - } - - $upload_list = array(); - foreach ($add_files as $attach_id) - { - if (!isset($delete_files[$attach_id]) && !empty($post_ids[$attach_id])) - { - $upload_list[$attach_id] = $post_ids[$attach_id]; - } - } - unset($add_files); - - if (count($upload_list)) - { - $template->assign_var('S_UPLOADING_FILES', true); - - $sql = 'SELECT forum_id, forum_name - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - - $forum_names = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_names[$row['forum_id']] = $row['forum_name']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT forum_id, topic_id, post_id, poster_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $upload_list); - $result = $db->sql_query($sql); - - $post_info = array(); - while ($row = $db->sql_fetchrow($result)) - { - $post_info[$row['post_id']] = $row; - } - $db->sql_freeresult($result); - - // Select those attachments we want to change... - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($upload_list)) . ' - AND is_orphan = 1'; - $result = $db->sql_query($sql); - - $files_added = $space_taken = 0; - while ($row = $db->sql_fetchrow($result)) - { - $post_row = $post_info[$upload_list[$row['attach_id']]]; - - $template->assign_block_vars('upload', array( - 'FILE_INFO' => sprintf($user->lang['UPLOADING_FILE_TO'], $row['real_filename'], $post_row['post_id']), - 'S_DENIED' => (!$auth->acl_get('f_attach', $post_row['forum_id'])) ? true : false, - 'L_DENIED' => (!$auth->acl_get('f_attach', $post_row['forum_id'])) ? sprintf($user->lang['UPLOAD_DENIED_FORUM'], $forum_names[$row['forum_id']]) : '') - ); - - if (!$auth->acl_get('f_attach', $post_row['forum_id'])) - { - continue; - } - - // Adjust attachment entry - $sql_ary = array( - 'in_message' => 0, - 'is_orphan' => 0, - 'poster_id' => $post_row['poster_id'], - 'post_msg_id' => $post_row['post_id'], - 'topic_id' => $post_row['topic_id'], - ); - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE attach_id = ' . $row['attach_id']; - $db->sql_query($sql); - - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_attachment = 1 - WHERE post_id = ' . $post_row['post_id']; - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_attachment = 1 - WHERE topic_id = ' . $post_row['topic_id']; - $db->sql_query($sql); - - $space_taken += $row['filesize']; - $files_added++; - - $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) - { - $config->increment('upload_dir_size', $space_taken, false); - $config->increment('num_files', $files_added, false); - } - } - } - - $template->assign_vars(array( - '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_limit($sql, $attachments_per_page, $start); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('orphan', array( - 'FILESIZE' => get_formatted_filesize($row['filesize']), - 'FILETIME' => $user->format_date($row['filetime']), - 'REAL_FILENAME' => utf8_basename($row['real_filename']), - 'PHYSICAL_FILENAME' => utf8_basename($row['physical_filename']), - 'ATTACH_ID' => $row['attach_id'], - 'POST_IDS' => (!empty($post_ids[$row['attach_id']])) ? $post_ids[$row['attach_id']] : '', - 'U_FILE' => append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'mode=view&id=' . $row['attach_id'])) - ); - } - $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->variable('delete', array('' => 0))) : array(); - - if (count($delete_files)) - { - // Select those attachments we want to delete... - $sql = 'SELECT real_filename - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', $delete_files) . ' - AND is_orphan = 0'; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $deleted_filenames[] = $row['real_filename']; - } - $db->sql_freeresult($result); - - if ($num_deleted = $this->attachment_manager->delete('attach', $delete_files)) - { - if (count($delete_files) != $num_deleted) - { - $error[] = $user->lang['FILES_GONE']; - } - - $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 - { - $error[] = $user->lang['NO_FILES_TO_DELETE']; - } - } - } - - if ($action == 'stats') - { - $this->handle_stats_resync(); - } - - $stats_error = $this->check_stats_accuracy(); - - if ($stats_error) - { - $error[] = $stats_error; - } - - $template->assign_vars(array( - 'S_MANAGE' => true, - )); - - $start = $request->variable('start', 0); - - // Sort keys - $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']); - $sort_by_text = array('f' => $user->lang['FILENAME'], 't' => $user->lang['FILEDATE'], 's' => $user->lang['FILESIZE'], 'x' => $user->lang['EXTENSION'], 'd' => $user->lang['DOWNLOADS'],'p' => $user->lang['ATTACH_POST_TYPE'], 'u' => $user->lang['AUTHOR']); - $sort_by_sql = array('f' => 'a.real_filename', 't' => 'a.filetime', 's' => 'a.filesize', 'x' => 'a.extension', 'd' => 'a.download_count', 'p' => 'a.in_message', 'u' => 'u.username'); - - $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); - - $min_filetime = ($sort_days) ? (time() - ($sort_days * 86400)) : ''; - $limit_filetime = ($min_filetime) ? " AND a.filetime >= $min_filetime " : ''; - $start = ($sort_days && isset($_POST['sort'])) ? 0 : $start; - - $attachments_per_page = (int) $config['topics_per_page']; - - $stats = $this->get_attachment_stats($limit_filetime); - $num_files = $stats['num_files']; - $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); - - // If the user is trying to reach the second half of the attachments list, fetch it starting from the end - $store_reverse = false; - $sql_limit = $attachments_per_page; - - if ($start > $num_files / 2) - { - $store_reverse = true; - - // Select the sort order. Add time sort anchor for non-time sorting cases - $sql_sort_anchor = ($sort_key != 't') ? ', a.filetime ' . (($sort_dir == 'd') ? 'ASC' : 'DESC') : ''; - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'ASC' : 'DESC') . $sql_sort_anchor; - $sql_limit = $pagination->reverse_limit($start, $sql_limit, $num_files); - $sql_start = $pagination->reverse_start($start, $sql_limit, $num_files); - } - else - { - // Select the sort order. Add time sort anchor for non-time sorting cases - $sql_sort_anchor = ($sort_key != 't') ? ', a.filetime ' . (($sort_dir == 'd') ? 'DESC' : 'ASC') : ''; - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC') . $sql_sort_anchor; - $sql_start = $start; - } - - $attachments_list = array(); - - // Just get the files - $sql = 'SELECT a.*, u.username, u.user_colour, t.topic_title - FROM ' . ATTACHMENTS_TABLE . ' a - LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = a.poster_id) - LEFT JOIN ' . TOPICS_TABLE . " t ON (a.topic_id = t.topic_id) - WHERE a.is_orphan = 0 - $limit_filetime - ORDER BY $sql_sort_order"; - $result = $db->sql_query_limit($sql, $sql_limit, $sql_start); - - $i = ($store_reverse) ? $sql_limit - 1 : 0; - - // Store increment value in a variable to save some conditional calls - $i_increment = ($store_reverse) ? -1 : 1; - while ($attachment_row = $db->sql_fetchrow($result)) - { - $attachments_list[$i] = $attachment_row; - $i = $i + $i_increment; - } - $db->sql_freeresult($result); - - $base_url = $this->u_action . "&$u_sort_param"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_files, $attachments_per_page, $start); - - $template->assign_vars(array( - 'TOTAL_FILES' => $num_files, - 'TOTAL_SIZE' => get_formatted_filesize($total_size), - - 'S_LIMIT_DAYS' => $s_limit_days, - 'S_SORT_KEY' => $s_sort_key, - 'S_SORT_DIR' => $s_sort_dir) - ); - - // Grab extensions - $extensions = $cache->obtain_attach_extensions(true); - - 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('
', "\n"), $row['attach_comment']) : ''; - $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' => 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'], - - 'L_DOWNLOAD_COUNT' => $user->lang($l_downloaded_viewed, (int) $row['download_count']), - - 'S_IN_MESSAGE' => (bool) $row['in_message'], - - 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}") . "#p{$row['post_msg_id']}", - 'U_FILE' => append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'mode=view&id=' . $row['attach_id'])) - ); - } - - break; - } - - if (count($error)) - { - $template->assign_vars(array( - 'S_WARNING' => true, - 'WARNING_MSG' => implode('
', $error)) - ); - } - - if (count($notify)) - { - $template->assign_vars(array( - 'S_NOTIFY' => true, - 'NOTIFY_MSG' => implode('
', $notify)) - ); - } - } - - /** - * Get attachment file count and size of upload directory - * - * @param $limit string Additional limit for WHERE clause to filter stats by. - * @return array Returns array with stats: num_files and upload_dir_size - */ - public function get_attachment_stats($limit = '') - { - $sql = 'SELECT COUNT(a.attach_id) AS num_files, SUM(a.filesize) AS upload_dir_size - FROM ' . ATTACHMENTS_TABLE . " a - WHERE a.is_orphan = 0 - $limit"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - return array( - 'num_files' => (int) $row['num_files'], - 'upload_dir_size' => (float) $row['upload_dir_size'], - ); - } - - /** - * Set config attachment stat values - * - * @param $stats array Array of config key => value pairs to set. - * @return null - */ - public function set_attachment_stats($stats) - { - foreach ($stats as $key => $value) - { - $this->config->set($key, $value, true); - } - } - - /** - * Check accuracy of attachment statistics. - * - * @return bool|string Returns false if stats are correct or error message - * otherwise. - */ - public function check_stats_accuracy() - { - // Get fresh stats. - $stats = $this->get_attachment_stats(); - - // Get current files stats - $num_files = (int) $this->config['num_files']; - $total_size = (float) $this->config['upload_dir_size']; - - if (($num_files != $stats['num_files']) || ($total_size != $stats['upload_dir_size'])) - { - $u_resync = $this->u_action . '&action=stats'; - - return $this->user->lang( - 'FILES_STATS_WRONG', - (int) $stats['num_files'], - get_formatted_filesize($stats['upload_dir_size']), - '', - '' - ); - } - return false; - } - - /** - * Handle stats resync. - * - * @return null - */ - public function handle_stats_resync() - { - if (!confirm_box(true)) - { - confirm_box(false, $this->user->lang['RESYNC_FILES_STATS_CONFIRM'], build_hidden_fields(array( - 'i' => $this->id, - 'mode' => 'manage', - 'action' => 'stats', - ))); - } - 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'); - } - - } - - /** - * Build Select for category items - */ - function category_select($select_name, $group_id = false, $key = '') - { - global $db, $user; - - $types = array( - ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'], - ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'], - ); - - if ($group_id) - { - $sql = 'SELECT cat_id - FROM ' . EXTENSION_GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - - $cat_type = (!($row = $db->sql_fetchrow($result))) ? ATTACHMENT_CATEGORY_NONE : $row['cat_id']; - - $db->sql_freeresult($result); - } - else - { - $cat_type = ATTACHMENT_CATEGORY_NONE; - } - - $group_select = ''; - - return $group_select; - } - - /** - * Extension group select - */ - function group_select($select_name, $default_group = false, $key = '') - { - global $db, $user; - - $group_select = ''; - - return $group_select; - } - - /** - * Test Settings - */ - function test_upload(&$error, $upload_dir, $create_directory = false) - { - global $user, $phpbb_root_path; - - // Does the target directory exist, is it a directory and writable. - if ($create_directory) - { - if (!file_exists($phpbb_root_path . $upload_dir)) - { - @mkdir($phpbb_root_path . $upload_dir, 0777); - - try - { - $this->filesystem->phpbb_chmod($phpbb_root_path . $upload_dir, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - - if (!file_exists($phpbb_root_path . $upload_dir)) - { - $error[] = sprintf($user->lang['NO_UPLOAD_DIR'], $upload_dir); - return; - } - - if (!is_dir($phpbb_root_path . $upload_dir)) - { - $error[] = sprintf($user->lang['UPLOAD_NOT_DIR'], $upload_dir); - return; - } - - if (!$this->filesystem->is_writable($phpbb_root_path . $upload_dir)) - { - $error[] = sprintf($user->lang['NO_WRITE_UPLOAD'], $upload_dir); - return; - } - } - - /** - * Perform operations on sites for external linking - */ - function perform_site_list() - { - global $db, $user, $request, $phpbb_log; - - if (isset($_REQUEST['securesubmit'])) - { - // Grab the list of entries - $ips = $request->variable('ips', ''); - $ip_list = array_unique(explode("\n", $ips)); - $ip_list_log = implode(', ', $ip_list); - - $ip_exclude = (int) $request->variable('ipexclude', false, false, \phpbb\request\request_interface::POST); - - $iplist = array(); - $hostlist = array(); - - foreach ($ip_list as $item) - { - if (preg_match('#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})[ ]*\-[ ]*([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#', trim($item), $ip_range_explode)) - { - // Don't ask about all this, just don't ask ... ! - $ip_1_counter = $ip_range_explode[1]; - $ip_1_end = $ip_range_explode[5]; - - while ($ip_1_counter <= $ip_1_end) - { - $ip_2_counter = ($ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[2] : 0; - $ip_2_end = ($ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[6]; - - if ($ip_2_counter == 0 && $ip_2_end == 254) - { - $ip_2_counter = 256; - - $iplist[] = "'$ip_1_counter.*'"; - } - - while ($ip_2_counter <= $ip_2_end) - { - $ip_3_counter = ($ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[3] : 0; - $ip_3_end = ($ip_2_counter < $ip_2_end || $ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[7]; - - if ($ip_3_counter == 0 && $ip_3_end == 254) - { - $ip_3_counter = 256; - - $iplist[] = "'$ip_1_counter.$ip_2_counter.*'"; - } - - while ($ip_3_counter <= $ip_3_end) - { - $ip_4_counter = ($ip_3_counter == $ip_range_explode[3] && $ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[4] : 0; - $ip_4_end = ($ip_3_counter < $ip_3_end || $ip_2_counter < $ip_2_end) ? 254 : $ip_range_explode[8]; - - if ($ip_4_counter == 0 && $ip_4_end == 254) - { - $ip_4_counter = 256; - - $iplist[] = "'$ip_1_counter.$ip_2_counter.$ip_3_counter.*'"; - } - - while ($ip_4_counter <= $ip_4_end) - { - $iplist[] = "'$ip_1_counter.$ip_2_counter.$ip_3_counter.$ip_4_counter'"; - $ip_4_counter++; - } - $ip_3_counter++; - } - $ip_2_counter++; - } - $ip_1_counter++; - } - } - else if (preg_match('#^([0-9]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})$#', trim($item)) || preg_match('#^[a-f0-9:]+\*?$#i', trim($item))) - { - $iplist[] = "'" . trim($item) . "'"; - } - else if (preg_match('#^([\w\-_]\.?){2,}$#is', trim($item))) - { - $hostlist[] = "'" . trim($item) . "'"; - } - else if (preg_match("#^([a-z0-9\-\*\._/]+?)$#is", trim($item))) - { - $hostlist[] = "'" . trim($item) . "'"; - } - } - - $sql = 'SELECT site_ip, site_hostname - FROM ' . SITELIST_TABLE . " - WHERE ip_exclude = $ip_exclude"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $iplist_tmp = array(); - $hostlist_tmp = array(); - do - { - if ($row['site_ip']) - { - if (strlen($row['site_ip']) > 40) - { - continue; - } - - $iplist_tmp[] = "'" . $row['site_ip'] . "'"; - } - else if ($row['site_hostname']) - { - if (strlen($row['site_hostname']) > 255) - { - continue; - } - - $hostlist_tmp[] = "'" . $row['site_hostname'] . "'"; - } - // break; - } - while ($row = $db->sql_fetchrow($result)); - - $iplist = array_unique(array_diff($iplist, $iplist_tmp)); - $hostlist = array_unique(array_diff($hostlist, $hostlist_tmp)); - unset($iplist_tmp); - unset($hostlist_tmp); - } - $db->sql_freeresult($result); - - if (count($iplist)) - { - foreach ($iplist as $ip_entry) - { - $sql = 'INSERT INTO ' . SITELIST_TABLE . " (site_ip, ip_exclude) - VALUES ($ip_entry, $ip_exclude)"; - $db->sql_query($sql); - } - } - - if (count($hostlist)) - { - foreach ($hostlist as $host_entry) - { - $sql = 'INSERT INTO ' . SITELIST_TABLE . " (site_hostname, ip_exclude) - VALUES ($host_entry, $ip_exclude)"; - $db->sql_query($sql); - } - } - - if (!empty($ip_list_log)) - { - // Update log - $log_entry = ($ip_exclude) ? 'LOG_DOWNLOAD_EXCLUDE_IP' : 'LOG_DOWNLOAD_IP'; - $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->variable('unip', array(0)); - - if (count($unip_sql)) - { - $l_unip_list = ''; - - // Grab details of ips for logging information later - $sql = 'SELECT site_ip, site_hostname - FROM ' . SITELIST_TABLE . ' - WHERE ' . $db->sql_in_set('site_id', $unip_sql); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $l_unip_list .= (($l_unip_list != '') ? ', ' : '') . (($row['site_ip']) ? $row['site_ip'] : $row['site_hostname']); - } - $db->sql_freeresult($result); - - $sql = 'DELETE FROM ' . SITELIST_TABLE . ' - WHERE ' . $db->sql_in_set('site_id', $unip_sql); - $db->sql_query($sql); - - $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)); - } - } - - /** - * Write display_order config field - */ - function display_order($value, $key = '') - { - $radio_ary = array(0 => 'DESCENDING', 1 => 'ASCENDING'); - - return h_radio('config[display_order]', $radio_ary, $value, $key); - } - - /** - * Adjust all three max_filesize config vars for display - */ - function max_filesize($value, $key = '') - { - // Determine size var and adjust the value accordingly - $filesize = get_formatted_filesize($value, false, array('mb', 'kb', 'b')); - $size_var = $filesize['si_identifier']; - $value = $filesize['value']; - - // size and maxlength must not be specified for input of type number - return ' '; - } - - /** - * Write secure_allow_deny config field - */ - function select_allow_deny($value, $key = '') - { - $radio_ary = array(1 => 'ORDER_ALLOW_DENY', 0 => 'ORDER_DENY_ALLOW'); - - return h_radio('config[' . $key . ']', $radio_ary, $value, $key); - } - -} diff --git a/install/update/new/includes/acp/acp_bbcodes.php b/install/update/new/includes/acp/acp_bbcodes.php deleted file mode 100644 index 5e39055..0000000 --- a/install/update/new/includes/acp/acp_bbcodes.php +++ /dev/null @@ -1,480 +0,0 @@ - -* @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_bbcodes -{ - var $u_action; - - function main($id, $mode) - { - global $db, $user, $template, $cache, $request, $phpbb_dispatcher, $phpbb_container; - global $phpbb_log; - - $user->add_lang('acp/posting'); - - // Set up general vars - $action = $request->variable('action', ''); - $bbcode_id = $request->variable('bbcode', 0); - - $this->tpl_name = 'acp_bbcodes'; - $this->page_title = 'ACP_BBCODES'; - $form_key = 'acp_bbcodes'; - - add_form_key($form_key); - - // Set up mode-specific vars - switch ($action) - { - case 'add': - $bbcode_match = $bbcode_tpl = $bbcode_helpline = ''; - $display_on_posting = 0; - break; - - case 'edit': - $sql = 'SELECT bbcode_match, bbcode_tpl, display_on_posting, bbcode_helpline - FROM ' . BBCODES_TABLE . ' - WHERE bbcode_id = ' . $bbcode_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['BBCODE_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $bbcode_match = $row['bbcode_match']; - $bbcode_tpl = htmlspecialchars($row['bbcode_tpl']); - $display_on_posting = $row['display_on_posting']; - $bbcode_helpline = $row['bbcode_helpline']; - break; - - case 'modify': - $sql = 'SELECT bbcode_id, bbcode_tag - FROM ' . BBCODES_TABLE . ' - WHERE bbcode_id = ' . $bbcode_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['BBCODE_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // No break here - - case 'create': - $display_on_posting = $request->variable('display_on_posting', 0); - - $bbcode_match = $request->variable('bbcode_match', ''); - $bbcode_tpl = htmlspecialchars_decode($request->variable('bbcode_tpl', '', true)); - $bbcode_helpline = $request->variable('bbcode_helpline', '', true); - break; - } - - // Do major work - switch ($action) - { - case 'edit': - case 'add': - - $tpl_ary = array( - 'S_EDIT_BBCODE' => true, - 'U_BACK' => $this->u_action, - 'U_ACTION' => $this->u_action . '&action=' . (($action == 'add') ? 'create' : 'modify') . (($bbcode_id) ? "&bbcode=$bbcode_id" : ''), - - 'L_BBCODE_USAGE_EXPLAIN'=> sprintf($user->lang['BBCODE_USAGE_EXPLAIN'], '', ''), - 'BBCODE_MATCH' => $bbcode_match, - 'BBCODE_TPL' => $bbcode_tpl, - 'BBCODE_HELPLINE' => $bbcode_helpline, - 'DISPLAY_ON_POSTING' => $display_on_posting, - ); - - $bbcode_tokens = array('TEXT', 'SIMPLETEXT', 'INTTEXT', 'IDENTIFIER', 'NUMBER', 'EMAIL', 'URL', 'LOCAL_URL', 'RELATIVE_URL', 'COLOR'); - - /** - * Modify custom bbcode template data before we display the add/edit form - * - * @event core.acp_bbcodes_edit_add - * @var string action Type of the action: add|edit - * @var array tpl_ary Array with custom bbcode add/edit data - * @var int bbcode_id When editing: the bbcode id, - * when creating: 0 - * @var array bbcode_tokens Array of bbcode tokens - * @since 3.1.0-a3 - */ - $vars = array('action', 'tpl_ary', 'bbcode_id', 'bbcode_tokens'); - extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_edit_add', compact($vars))); - - $template->assign_vars($tpl_ary); - - foreach ($bbcode_tokens as $token) - { - $template->assign_block_vars('token', array( - 'TOKEN' => '{' . $token . '}', - 'EXPLAIN' => ($token === 'LOCAL_URL') ? $user->lang(array('tokens', $token), generate_board_url() . '/') : $user->lang(array('tokens', $token)), - )); - } - - return; - - break; - - case 'modify': - case 'create': - - $sql_ary = $hidden_fields = array(); - - /** - * Modify custom bbcode data before the modify/create action - * - * @event core.acp_bbcodes_modify_create - * @var string action Type of the action: modify|create - * @var array sql_ary Array with new bbcode data - * @var int bbcode_id When editing: the bbcode id, - * when creating: 0 - * @var bool display_on_posting Display bbcode on posting form - * @var string bbcode_match The bbcode usage string to match - * @var string bbcode_tpl The bbcode HTML replacement string - * @var string bbcode_helpline The bbcode help line string - * @var array hidden_fields Array of hidden fields for use when - * submitting form when $warn_unsafe is true - * @since 3.1.0-a3 - */ - $vars = array( - 'action', - 'sql_ary', - 'bbcode_id', - 'display_on_posting', - 'bbcode_match', - 'bbcode_tpl', - 'bbcode_helpline', - 'hidden_fields', - ); - extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_modify_create', compact($vars))); - - $acp_utils = $phpbb_container->get('text_formatter.acp_utils'); - $bbcode_info = $acp_utils->analyse_bbcode($bbcode_match, $bbcode_tpl); - $warn_unsafe = ($bbcode_info['status'] === $acp_utils::BBCODE_STATUS_UNSAFE); - - if ($bbcode_info['status'] === $acp_utils::BBCODE_STATUS_INVALID_TEMPLATE) - { - trigger_error($user->lang['BBCODE_INVALID_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - if ($bbcode_info['status'] === $acp_utils::BBCODE_STATUS_INVALID_DEFINITION) - { - trigger_error($user->lang['BBCODE_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (!$warn_unsafe && !check_form_key($form_key)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (!$warn_unsafe || confirm_box(true)) - { - $data = $this->build_regexp($bbcode_match, $bbcode_tpl); - - // Make sure the user didn't pick a "bad" name for the BBCode tag. - $hard_coded = array('code', 'quote', 'quote=', 'attachment', 'attachment=', 'b', 'i', 'url', 'url=', 'img', 'size', 'size=', 'color', 'color=', 'u', 'list', 'list=', 'email', 'email=', 'flash', 'flash='); - - if (($action == 'modify' && strtolower($data['bbcode_tag']) !== strtolower($row['bbcode_tag'])) || ($action == 'create')) - { - $sql = 'SELECT 1 as test - FROM ' . BBCODES_TABLE . " - WHERE LOWER(bbcode_tag) = '" . $db->sql_escape(strtolower($data['bbcode_tag'])) . "'"; - $result = $db->sql_query($sql); - $info = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Grab the end, interrogate the last closing tag - if (isset($info['test']) && $info['test'] === '1' - || in_array(strtolower($data['bbcode_tag']), $hard_coded) - || (preg_match('#\[/([^[]*)]$#', $bbcode_match, $regs) && in_array(strtolower($regs[1]), $hard_coded)) - ) - { - trigger_error($user->lang['BBCODE_INVALID_TAG_NAME'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - if (substr($data['bbcode_tag'], -1) === '=') - { - $test = substr($data['bbcode_tag'], 0, -1); - } - else - { - $test = $data['bbcode_tag']; - } - - if (strlen($data['bbcode_tag']) > 16) - { - trigger_error($user->lang['BBCODE_TAG_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (strlen($bbcode_match) > 4000) - { - trigger_error($user->lang['BBCODE_TAG_DEF_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (strlen($bbcode_helpline) > 255) - { - trigger_error($user->lang['BBCODE_HELPLINE_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql_ary = array_merge($sql_ary, array( - 'bbcode_tag' => $data['bbcode_tag'], - 'bbcode_match' => $bbcode_match, - 'bbcode_tpl' => $bbcode_tpl, - 'display_on_posting' => $display_on_posting, - 'bbcode_helpline' => $bbcode_helpline, - 'first_pass_match' => $data['first_pass_match'], - 'first_pass_replace' => $data['first_pass_replace'], - 'second_pass_match' => $data['second_pass_match'], - 'second_pass_replace' => $data['second_pass_replace'] - )); - - if ($action == 'create') - { - $sql = 'SELECT MAX(bbcode_id) as max_bbcode_id - FROM ' . BBCODES_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $bbcode_id = (int) $row['max_bbcode_id'] + 1; - - // Make sure it is greater than the core bbcode ids... - if ($bbcode_id <= NUM_CORE_BBCODES) - { - $bbcode_id = NUM_CORE_BBCODES + 1; - } - } - else - { - $bbcode_id = NUM_CORE_BBCODES + 1; - } - - if ($bbcode_id > BBCODE_LIMIT) - { - trigger_error($user->lang['TOO_MANY_BBCODES'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql_ary['bbcode_id'] = (int) $bbcode_id; - - $db->sql_query('INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary)); - $cache->destroy('sql', BBCODES_TABLE); - $phpbb_container->get('text_formatter.cache')->invalidate(); - - $lang = 'BBCODE_ADDED'; - $log_action = 'LOG_BBCODE_ADD'; - } - else - { - $sql = 'UPDATE ' . BBCODES_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE bbcode_id = ' . $bbcode_id; - $db->sql_query($sql); - $cache->destroy('sql', BBCODES_TABLE); - $phpbb_container->get('text_formatter.cache')->invalidate(); - - $lang = 'BBCODE_EDITED'; - $log_action = 'LOG_BBCODE_EDIT'; - } - - $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)); - } - else - { - confirm_box(false, $user->lang['BBCODE_DANGER'], build_hidden_fields(array_merge($hidden_fields, array( - 'action' => $action, - 'bbcode' => $bbcode_id, - 'bbcode_match' => $bbcode_match, - 'bbcode_tpl' => htmlspecialchars($bbcode_tpl), - 'bbcode_helpline' => $bbcode_helpline, - 'display_on_posting' => $display_on_posting, - ))) - , 'confirm_bbcode.html'); - } - - break; - - case 'delete': - - $sql = 'SELECT bbcode_tag - FROM ' . BBCODES_TABLE . " - WHERE bbcode_id = $bbcode_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - 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); - $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()) - { - $json_response = new \phpbb\json_response; - $json_response->send(array( - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $user->lang['BBCODE_DELETED'], - 'REFRESH_DATA' => array( - 'time' => 3 - ) - )); - } - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'bbcode' => $bbcode_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action)) - ); - } - } - - break; - } - - $u_action = $this->u_action; - - $template_data = array( - 'U_ACTION' => $this->u_action . '&action=add', - ); - - $sql_ary = array( - 'SELECT' => 'b.*', - 'FROM' => array(BBCODES_TABLE => 'b'), - 'ORDER_BY' => 'b.bbcode_tag', - ); - - /** - * Modify custom bbcode template data before we display the form - * - * @event core.acp_bbcodes_display_form - * @var string action Type of the action: modify|create - * @var array sql_ary The SQL array to get custom bbcode data - * @var array template_data Array with form template data - * @var string u_action The u_action link - * @since 3.1.0-a3 - */ - $vars = array('action', 'sql_ary', 'template_data', 'u_action'); - extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_display_form', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - - $template->assign_vars($template_data); - - while ($row = $db->sql_fetchrow($result)) - { - $bbcodes_array = array( - 'BBCODE_TAG' => $row['bbcode_tag'], - 'U_EDIT' => $u_action . '&action=edit&bbcode=' . $row['bbcode_id'], - 'U_DELETE' => $u_action . '&action=delete&bbcode=' . $row['bbcode_id'], - ); - - /** - * Modify display of custom bbcodes in the form - * - * @event core.acp_bbcodes_display_bbcodes - * @var array row Array with current bbcode data - * @var array bbcodes_array Array of bbcodes template data - * @var string u_action The u_action link - * @since 3.1.0-a3 - */ - $vars = array('bbcodes_array', 'row', 'u_action'); - extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_display_bbcodes', compact($vars))); - - $template->assign_block_vars('bbcodes', $bbcodes_array); - - } - $db->sql_freeresult($result); - } - - /* - * Build regular expression for custom bbcode - */ - function build_regexp(&$bbcode_match, &$bbcode_tpl) - { - $bbcode_match = trim($bbcode_match); - $bbcode_tag = preg_replace('/.*?\[([a-z0-9_-]+).*/i', '$1', $bbcode_match); - - 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); - } - - return array( - 'bbcode_tag' => $bbcode_tag, - 'first_pass_match' => '/(?!)/', - 'first_pass_replace' => '', - // Use a non-matching, valid regexp to effectively disable this BBCode - 'second_pass_match' => '/(?!)/', - 'second_pass_replace' => '' - ); - } -} diff --git a/install/update/new/includes/acp/acp_board.php b/install/update/new/includes/acp/acp_board.php deleted file mode 100644 index cd72a87..0000000 --- a/install/update/new/includes/acp/acp_board.php +++ /dev/null @@ -1,1172 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @todo add cron intervals to server settings? (database_gc, queue_interval, session_gc, search_gc, cache_gc, warnings_gc) -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -class acp_board -{ - var $u_action; - var $new_config; - - function main($id, $mode) - { - 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'); - - $submit = (isset($_POST['submit']) || isset($_POST['allow_quick_reply_enable'])) ? true : false; - - $form_key = 'acp_board'; - add_form_key($form_key); - - /** - * Validation types are: - * string, int, bool, - * script_path (absolute path in url - beginning with / and no trailing slash), - * rpath (relative), rwpath (realtive, writable), path (relative path, but able to escape the root), wpath (writable) - */ - switch ($mode) - { - case 'settings': - $display_vars = array( - 'title' => 'ACP_BOARD_SETTINGS', - 'vars' => array( - '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' => '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), - 'board_disable_msg' => false, - 'default_lang' => array('lang' => 'DEFAULT_LANGUAGE', 'validate' => 'lang', 'type' => 'select', 'function' => 'language_select', 'params' => array('{CONFIG_VALUE}'), 'explain' => false), - 'default_dateformat' => array('lang' => 'DEFAULT_DATE_FORMAT', 'validate' => 'string', 'type' => 'custom', 'method' => 'dateformat_select', 'explain' => true), - 'board_timezone' => array('lang' => 'SYSTEM_TIMEZONE', 'validate' => 'timezone', 'type' => 'custom', 'method' => 'timezone_select', 'explain' => true), - - 'legend2' => 'BOARD_STYLE', - 'default_style' => array('lang' => 'DEFAULT_STYLE', 'validate' => 'int', 'type' => 'select', 'function' => 'style_select', 'params' => array('{CONFIG_VALUE}', false), 'explain' => true), - 'guest_style' => array('lang' => 'GUEST_STYLE', 'validate' => 'int', 'type' => 'select', 'function' => 'style_select', 'params' => array($this->guest_style_get(), false), 'explain' => true), - 'override_user_style' => array('lang' => 'OVERRIDE_STYLE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend3' => 'WARNINGS', - 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - - 'legend4' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'features': - $display_vars = array( - 'title' => 'ACP_BOARD_FEATURES', - 'vars' => array( - 'legend1' => 'ACP_BOARD_FEATURES', - 'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_topic_notify' => array('lang' => 'ALLOW_TOPIC_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_forum_notify' => array('lang' => 'ALLOW_FORUM_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_report' => array('lang' => 'ALLOW_PM_REPORT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig' => array('lang' => 'ALLOW_SIG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_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), - 'display_last_subject' => array('lang' => 'DISPLAY_LAST_SUBJECT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'display_unapproved_posts' => array('lang' => 'DISPLAY_UNAPPROVED_POSTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'custom', 'method' => 'quick_reply', 'explain' => true), - - 'legend2' => 'ACP_SUBMIT_CHANGES', - ) - ); - 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); - - /* - * First grab the settings for enabling/disabling the avatar - * driver and afterwards grab additional settings the driver - * might have. - */ - $avatar_vars += $phpbb_avatar_manager->get_avatar_settings($driver); - $avatar_vars += $driver->prepare_form_acp($user); - } - - $display_vars = array( - 'title' => 'ACP_AVATAR_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_AVATAR_SETTINGS', - - 'avatar_min_width' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), - 'avatar_min_height' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), - 'avatar_max_width' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), - 'avatar_max_height' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), - - 'allow_avatar' => array('lang' => 'ALLOW_AVATARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - ) - ); - - if (!empty($avatar_vars)) - { - $display_vars['vars'] += $avatar_vars; - } - break; - - case 'message': - $display_vars = array( - 'title' => 'ACP_MESSAGE_SETTINGS', - 'lang' => 'ucp', - 'vars' => array( - 'legend1' => 'GENERAL_SETTINGS', - 'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'full_folder_action' => array('lang' => 'FULL_FOLDER_ACTION', 'validate' => 'int', 'type' => 'select', 'method' => 'full_folder_select', 'explain' => true), - 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'pm_max_recipients' => array('lang' => 'PM_MAX_RECIPIENTS', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), - - 'legend2' => 'GENERAL_OPTIONS', - 'allow_mass_pm' => array('lang' => 'ALLOW_MASS_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_bbcode_pm' => array('lang' => 'ALLOW_BBCODE_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_smilies_pm' => array('lang' => 'ALLOW_SMILIES_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_pm' => array('lang' => 'ALLOW_SIG_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'print_pm' => array('lang' => 'ALLOW_PRINT_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'forward_pm' => array('lang' => 'ALLOW_FORWARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_img_pm' => array('lang' => 'ALLOW_IMG_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_flash_pm' => array('lang' => 'ALLOW_FLASH_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'enable_pm_icons' => array('lang' => 'ENABLE_PM_ICONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'post': - $display_vars = array( - 'title' => 'ACP_POST_SETTINGS', - 'vars' => array( - 'legend1' => 'GENERAL_OPTIONS', - 'allow_topic_notify' => array('lang' => 'ALLOW_TOPIC_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_forum_notify' => array('lang' => 'ALLOW_FORUM_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - '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), - 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'custom', 'method' => 'quick_reply', 'explain' => true), - - 'legend2' => 'POSTING', - 'bump_type' => false, - 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'delete_time' => array('lang' => 'DELETE_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'display_last_edited' => array('lang' => 'DISPLAY_LAST_EDITED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int:0:9999999999', 'type' => 'number:0:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'bump_interval' => array('lang' => 'BUMP_INTERVAL', 'validate' => 'int:0', 'type' => 'custom', 'method' => 'bump_interval', 'explain' => true), - 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), - 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), - 'smilies_per_page' => array('lang' => 'SMILIES_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), - 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int:2:127', 'type' => 'number:2:127', 'explain' => false), - 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int:0:999999', 'type' => 'number:0:999999', 'explain' => true), - 'min_post_chars' => array('lang' => 'MIN_CHAR_LIMIT', 'validate' => 'int:1:999999', 'type' => 'number:1:999999', 'explain' => true), - 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'), - 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'signature': - $display_vars = array( - 'title' => 'ACP_SIGNATURE_SETTINGS', - 'vars' => array( - 'legend1' => 'GENERAL_OPTIONS', - 'allow_sig' => array('lang' => 'ALLOW_SIG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_bbcode' => array('lang' => 'ALLOW_SIG_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_img' => array('lang' => 'ALLOW_SIG_IMG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_flash' => array('lang' => 'ALLOW_SIG_FLASH', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_smilies' => array('lang' => 'ALLOW_SIG_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_links' => array('lang' => 'ALLOW_SIG_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend2' => 'GENERAL_SETTINGS', - 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'), - 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'registration': - $display_vars = array( - 'title' => 'ACP_REGISTER_SETTINGS', - 'vars' => array( - 'legend1' => 'GENERAL_SETTINGS', - 'max_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int:8:180', 'type' => false, 'method' => false, 'explain' => false,), - - 'require_activation' => array('lang' => 'ACC_ACTIVATION', 'validate' => 'int', 'type' => 'select', 'method' => 'select_acc_activation', 'explain' => true), - 'new_member_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'number:0:255', 'explain' => true, 'append' => ' ' . $user->lang['POSTS']), - 'new_member_group_default'=> array('lang' => 'NEW_MEMBER_GROUP_DEFAULT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'min_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int:1', 'type' => 'custom:5:180', 'method' => 'username_length', 'explain' => true), - 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), - 'allow_name_chars' => array('lang' => 'USERNAME_CHARS', 'validate' => 'string', 'type' => 'select', 'method' => 'select_username_chars', 'explain' => true), - 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), - 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - - 'legend2' => 'GENERAL_OPTIONS', - 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_emailreuse' => array('lang' => 'ALLOW_EMAIL_REUSE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'enable_confirm' => array('lang' => 'VISUAL_CONFIRM_REG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), - 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - - 'legend3' => 'COPPA', - 'coppa_enable' => array('lang' => 'ENABLE_COPPA', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'coppa_mail' => array('lang' => 'COPPA_MAIL', 'validate' => 'string', 'type' => 'textarea:5:40', 'explain' => true), - 'coppa_fax' => array('lang' => 'COPPA_FAX', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => false), - - 'legend4' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'feed': - $display_vars = array( - 'title' => 'ACP_FEED_MANAGEMENT', - 'vars' => array( - 'legend1' => 'ACP_FEED_GENERAL', - 'feed_enable' => array('lang' => 'ACP_FEED_ENABLE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_item_statistics' => array('lang' => 'ACP_FEED_ITEM_STATISTICS', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), - 'feed_http_auth' => array('lang' => 'ACP_FEED_HTTP_AUTH', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), - - 'legend2' => 'ACP_FEED_POST_BASED', - 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true), - 'feed_overall' => array('lang' => 'ACP_FEED_OVERALL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_forum' => array('lang' => 'ACP_FEED_FORUM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_topic' => array('lang' => 'ACP_FEED_TOPIC', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - - 'legend3' => 'ACP_FEED_TOPIC_BASED', - 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true), - 'feed_topics_new' => array('lang' => 'ACP_FEED_TOPICS_NEW', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_topics_active' => array('lang' => 'ACP_FEED_TOPICS_ACTIVE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_news_id' => array('lang' => 'ACP_FEED_NEWS', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_news_forums', 'explain' => true), - - 'legend4' => 'ACP_FEED_SETTINGS_OTHER', - 'feed_overall_forums' => array('lang' => 'ACP_FEED_OVERALL_FORUMS', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_exclude_id' => array('lang' => 'ACP_FEED_EXCLUDE_ID', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_exclude_forums', 'explain' => true), - ) - ); - break; - - case 'cookie': - $display_vars = array( - 'title' => 'ACP_COOKIE_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_COOKIE_SETTINGS', - '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:enabled_disabled', 'explain' => true), - 'cookie_notice' => array('lang' => 'COOKIE_NOTICE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), - ) - ); - break; - - case 'load': - $display_vars = array( - 'title' => 'ACP_LOAD_SETTINGS', - 'vars' => array( - 'legend1' => 'GENERAL_SETTINGS', - 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int:60:9999999999', 'type' => 'number:60:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'read_notification_expire_days' => array('lang' => 'READ_NOTIFICATION_EXPIRE_DAYS', 'validate' => 'int:0', 'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - - 'legend2' => 'GENERAL_OPTIONS', - 'load_notifications' => array('lang' => 'LOAD_NOTIFICATIONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_db_track' => array('lang' => 'YES_POST_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_db_lastread' => array('lang' => 'YES_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_anon_lastread' => array('lang' => 'YES_ANON_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_online' => array('lang' => 'YES_ONLINE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_online_guests' => array('lang' => 'YES_ONLINE_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_onlinetrack' => array('lang' => 'YES_ONLINE_TRACK', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_unreads_search' => array('lang' => 'YES_UNREAD_SEARCH', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - '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', - 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - - 'legend4' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'auth': - $display_vars = array( - 'title' => 'ACP_AUTH_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_AUTH_SETTINGS', - 'auth_method' => array('lang' => 'AUTH_METHOD', 'validate' => 'string', 'type' => 'select:1:toggable', 'method' => 'select_auth_method', 'explain' => false), - ) - ); - break; - - case 'server': - $display_vars = array( - 'title' => 'ACP_SERVER_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_SERVER_SETTINGS', - 'gzip_compress' => array('lang' => 'ENABLE_GZIP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'use_system_cron' => array('lang' => 'USE_SYSTEM_CRON', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend2' => 'PATH_SETTINGS', - 'enable_mod_rewrite' => array('lang' => 'MOD_REWRITE_ENABLE', 'validate' => 'bool', 'type' => 'custom', 'method' => 'enable_mod_rewrite', 'explain' => true), - 'smilies_path' => array('lang' => 'SMILIES_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - 'icons_path' => array('lang' => 'ICONS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - 'upload_icons_path' => array('lang' => 'UPLOAD_ICONS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - 'ranks_path' => array('lang' => 'RANKS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - - 'legend3' => 'SERVER_URL_SETTINGS', - 'force_server_vars' => array('lang' => 'FORCE_SERVER_VARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'server_protocol' => array('lang' => 'SERVER_PROTOCOL', 'validate' => 'string', 'type' => 'text:10:10', 'explain' => true), - 'server_name' => array('lang' => 'SERVER_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), - 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), - 'script_path' => array('lang' => 'SCRIPT_PATH', 'validate' => 'script_path', 'type' => 'text::255', 'explain' => true), - - 'legend4' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'security': - $display_vars = array( - 'title' => 'ACP_SECURITY_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_SECURITY_SETTINGS', - 'allow_autologin' => array('lang' => 'ALLOW_AUTOLOGIN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_password_reset' => array('lang' => 'ALLOW_PASSWORD_RESET', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - 'ip_check' => array('lang' => 'IP_VALID', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true), - 'browser_check' => array('lang' => 'BROWSER_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'forwarded_for_check' => array('lang' => 'FORWARDED_FOR_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - '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), - 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), - 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), - 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), - 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), - 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'ip_login_limit_use_forwarded' => array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1:99999', 'type' => 'number:-1:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'form_token_sid_guests' => array('lang' => 'FORM_SID_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - ) - ); - break; - - case 'email': - $display_vars = array( - 'title' => 'ACP_EMAIL_SETTINGS', - 'vars' => array( - '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_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), - 'smtp_host' => array('lang' => 'SMTP_SERVER', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => true), - 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), - 'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true), - 'smtp_username' => array('lang' => 'SMTP_USERNAME', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true), - 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true), - 'smtp_verify_peer' => array('lang' => 'SMTP_VERIFY_PEER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'smtp_verify_peer_name' => array('lang' => 'SMTP_VERIFY_PEER_NAME', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'smtp_allow_self_signed'=> array('lang' => 'SMTP_ALLOW_SELF_SIGNED','validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - default: - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - - /** - * Event to add and/or modify acp_board configurations - * - * @event core.acp_board_config_edit_add - * @var array display_vars Array of config values to display and process - * @var string mode Mode of the config page we are displaying - * @var boolean submit Do we display the form or process the submission - * @since 3.1.0-a4 - */ - $vars = array('display_vars', 'mode', 'submit'); - extract($phpbb_dispatcher->trigger_event('core.acp_board_config_edit_add', compact($vars))); - - if (isset($display_vars['lang'])) - { - $user->add_lang($display_vars['lang']); - } - - $this->new_config = clone $config; - $cfg_array = (isset($_REQUEST['config'])) ? $request->variable('config', array('' => ''), true) : $this->new_config; - $error = array(); - - // We validate the complete config if wished - validate_config_vars($display_vars['vars'], $cfg_array, $error); - - 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; - } - - // We go through the display_vars to make sure no one is trying to set variables he/she is not allowed to... - foreach ($display_vars['vars'] as $config_name => $data) - { - if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false) - { - continue; - } - - if ($config_name == 'auth_method' || $config_name == 'feed_news_id' || $config_name == 'feed_exclude_id') - { - continue; - } - - if ($config_name == 'guest_style') - { - if (isset($cfg_array[$config_name])) - { - $this->guest_style_set($cfg_array[$config_name]); - } - continue; - } - - $this->new_config[$config_name] = $config_value = $cfg_array[$config_name]; - - if ($submit) - { - if (isset($data['type']) && strpos($data['type'], 'password') === 0 && $config_value === '********') - { - /** - * Do not update password fields if the content is ********, - * because that is the password replacement we use to not - * send the password to the output - */ - continue; - } - - $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', 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) - { - $cache->destroy('_feed_news_forum_ids'); - $cache->destroy('_feed_excluded_forum_ids'); - - $this->store_feed_forums(FORUM_OPTION_FEED_NEWS, 'feed_news_id'); - $this->store_feed_forums(FORUM_OPTION_FEED_EXCLUDE, 'feed_exclude_id'); - } - - 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; - $old_auth_config = array(); - foreach ($auth_providers as $provider) - { - /** @var \phpbb\auth\provider\provider_interface $provider */ - if ($fields = $provider->acp()) - { - // Check if we need to create config fields for this plugin and save config when submit was pressed - foreach ($fields as $field) - { - if (!isset($config[$field])) - { - $config->set($field, ''); - } - - if (!isset($cfg_array[$field]) || strpos($field, 'legend') !== false) - { - continue; - } - - if (substr($field, -9) === '_password' && $cfg_array[$field] === '********') - { - // Do not update password fields if the content is ********, - // because that is the password replacement we use to not - // send the password to the output - continue; - } - - $old_auth_config[$field] = $this->new_config[$field]; - $config_value = $cfg_array[$field]; - $this->new_config[$field] = $config_value; - - if ($submit) - { - $updated_auth_settings = true; - $config->set($field, $config_value); - } - } - } - unset($fields); - } - - if ($submit && (($cfg_array['auth_method'] != $this->new_config['auth_method']) || $updated_auth_settings)) - { - $method = basename($cfg_array['auth_method']); - if (array_key_exists('auth.provider.' . $method, $auth_providers)) - { - $provider = $auth_providers['auth.provider.' . $method]; - if ($error = $provider->init()) - { - foreach ($old_auth_config as $config_name => $config_value) - { - $config->set($config_name, $config_value); - } - trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); - } - $config->set('auth_method', basename($cfg_array['auth_method'])); - } - else - { - trigger_error('NO_AUTH_PLUGIN', E_USER_ERROR); - } - } - } - - 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) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_' . strtoupper($mode)); - - $message = $user->lang('CONFIG_UPDATED'); - $message_type = E_USER_NOTICE; - if (!$config['email_enable'] && in_array($mode, array('email', 'registration')) && - in_array($config['require_activation'], array(USER_ACTIVATION_SELF, USER_ACTIVATION_ADMIN))) - { - $message .= '

' . $user->lang('ACC_ACTIVATION_WARNING'); - $message_type = E_USER_WARNING; - } - trigger_error($message . adm_back_link($this->u_action), $message_type); - } - - $this->tpl_name = 'acp_board'; - $this->page_title = $display_vars['title']; - - $template->assign_vars(array( - 'L_TITLE' => $user->lang[$display_vars['title']], - 'L_TITLE_EXPLAIN' => $user->lang[$display_vars['title'] . '_EXPLAIN'], - - 'S_ERROR' => (count($error)) ? true : false, - 'ERROR_MSG' => implode('
', $error), - - 'U_ACTION' => $this->u_action) - ); - - // Output relevant page - foreach ($display_vars['vars'] 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' => (isset($user->lang[$vars])) ? $user->lang[$vars] : $vars) - ); - - continue; - } - - $type = explode(':', $vars['type']); - - $l_explain = ''; - if ($vars['explain'] && isset($vars['lang_explain'])) - { - $l_explain = (isset($user->lang[$vars['lang_explain']])) ? $user->lang[$vars['lang_explain']] : $vars['lang_explain']; - } - else if ($vars['explain']) - { - $l_explain = (isset($user->lang[$vars['lang'] . '_EXPLAIN'])) ? $user->lang[$vars['lang'] . '_EXPLAIN'] : ''; - } - - $content = build_cfg_template($type, $config_key, $this->new_config, $config_key, $vars); - - if (empty($content)) - { - continue; - } - - $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'] && !empty($l_explain), - 'TITLE_EXPLAIN' => $l_explain, - 'CONTENT' => $content, - ) - ); - - unset($display_vars['vars'][$config_key]); - } - - if ($mode == 'auth') - { - $template->assign_var('S_AUTH', true); - - foreach ($auth_providers as $provider) - { - $auth_tpl = $provider->get_acp_template($this->new_config); - if ($auth_tpl) - { - if (array_key_exists('BLOCK_VAR_NAME', $auth_tpl)) - { - foreach ($auth_tpl['BLOCK_VARS'] as $block_vars) - { - $template->assign_block_vars($auth_tpl['BLOCK_VAR_NAME'], $block_vars); - } - } - $template->assign_vars($auth_tpl['TEMPLATE_VARS']); - $template->assign_block_vars('auth_tpl', array( - 'TEMPLATE_FILE' => $auth_tpl['TEMPLATE_FILE'], - )); - } - } - } - } - - /** - * Select auth method - */ - function select_auth_method($selected_method, $key = '') - { - global $phpbb_container; - - /* @var $auth_providers \phpbb\auth\provider_collection */ - $auth_providers = $phpbb_container->get('auth.provider_collection'); - $auth_plugins = array(); - - foreach ($auth_providers as $key => $value) - { - if (!($value instanceof \phpbb\auth\provider\provider_interface)) - { - continue; - } - $auth_plugins[] = str_replace('auth.provider.', '', $key); - } - - sort($auth_plugins); - - $auth_select = ''; - foreach ($auth_plugins as $method) - { - $selected = ($selected_method == $method) ? ' selected="selected"' : ''; - $auth_select .= "'; - } - - return $auth_select; - } - - /** - * Select mail authentication method - */ - function mail_auth_select($selected_method, $key = '') - { - global $user; - - $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 .= ''; - } - - return $s_smtp_auth_options; - } - - /** - * Select full folder action - */ - function full_folder_select($value, $key = '') - { - global $user; - - return ''; - } - - /** - * Select ip validation - */ - function select_ip_check($value, $key = '') - { - $radio_ary = array(4 => 'ALL', 3 => 'CLASS_C', 2 => 'CLASS_B', 0 => 'NO_IP_VALIDATION'); - - return h_radio('config[ip_check]', $radio_ary, $value, $key); - } - - /** - * Select referer validation - */ - function select_ref_check($value, $key = '') - { - $radio_ary = array(REFERER_VALIDATE_PATH => 'REF_PATH', REFERER_VALIDATE_HOST => 'REF_HOST', REFERER_VALIDATE_NONE => 'NO_REF_VALIDATION'); - - return h_radio('config[referer_validation]', $radio_ary, $value, $key); - } - - /** - * Select account activation method - */ - function select_acc_activation($selected_value, $value) - { - global $user, $config; - - $act_ary = array( - 'ACC_DISABLE' => array(true, USER_ACTIVATION_DISABLE), - 'ACC_NONE' => array(true, USER_ACTIVATION_NONE), - 'ACC_USER' => array($config['email_enable'], USER_ACTIVATION_SELF), - 'ACC_ADMIN' => array($config['email_enable'], USER_ACTIVATION_ADMIN), - ); - - $act_options = ''; - foreach ($act_ary as $key => $data) - { - list($available, $value) = $data; - $selected = ($selected_value == $value) ? ' selected="selected"' : ''; - $class = (!$available) ? ' class="disabled-option"' : ''; - $act_options .= ''; - } - - return $act_options; - } - - /** - * Maximum/Minimum username length - */ - function username_length($value, $key = '') - { - global $user; - - return ' ' . $user->lang['MIN_CHARS'] . '   ' . $user->lang['MAX_CHARS']; - } - - /** - * Allowed chars in usernames - */ - function select_username_chars($selected_value, $key) - { - global $user; - - $user_char_ary = array('USERNAME_CHARS_ANY', 'USERNAME_ALPHA_ONLY', 'USERNAME_ALPHA_SPACERS', 'USERNAME_LETTER_NUM', 'USERNAME_LETTER_NUM_SPACERS', 'USERNAME_ASCII'); - $user_char_options = ''; - foreach ($user_char_ary as $user_type) - { - $selected = ($selected_value == $user_type) ? ' selected="selected"' : ''; - $user_char_options .= ''; - } - - return $user_char_options; - } - - /** - * Minimum password length - */ - function password_length($value, $key) - { - global $user; - - return ' ' . $user->lang['MIN_CHARS']; - } - - /** - * Required chars in passwords - */ - function select_password_chars($selected_value, $key) - { - global $user; - - $pass_type_ary = array('PASS_TYPE_ANY', 'PASS_TYPE_CASE', 'PASS_TYPE_ALPHA', 'PASS_TYPE_SYMBOL'); - $pass_char_options = ''; - foreach ($pass_type_ary as $pass_type) - { - $selected = ($selected_value == $pass_type) ? ' selected="selected"' : ''; - $pass_char_options .= ''; - } - - return $pass_char_options; - } - - /** - * Select bump interval - */ - function bump_interval($value, $key) - { - global $user; - - $s_bump_type = ''; - $types = array('m' => 'MINUTES', 'h' => 'HOURS', 'd' => 'DAYS'); - foreach ($types as $type => $lang) - { - $selected = ($this->new_config['bump_type'] == $type) ? ' selected="selected"' : ''; - $s_bump_type .= ''; - } - - return ' '; - } - - /** - * Board disable option and message - */ - function board_disable($value, $key) - { - $radio_ary = array(1 => 'YES', 0 => 'NO'); - - return h_radio('config[board_disable]', $radio_ary, $value) . '
'; - } - - /** - * Global quick reply enable/disable setting and button to enable in all forums - */ - function quick_reply($value, $key) - { - global $user; - - $radio_ary = array(1 => 'YES', 0 => 'NO'); - - return h_radio('config[allow_quick_reply]', $radio_ary, $value) . - '

'; - } - - /** - * Select guest timezone - */ - function timezone_select($value, $key) - { - global $template, $user; - - $timezone_select = phpbb_timezone_select($template, $user, $value, true); - - return ''; - } - - /** - * Get guest style - */ - public function guest_style_get() - { - global $db; - - $sql = 'SELECT user_style - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . ANONYMOUS; - $result = $db->sql_query($sql); - - $style = (int) $db->sql_fetchfield('user_style'); - $db->sql_freeresult($result); - - return $style; - } - - /** - * Set guest style - * - * @param int $style_id The style ID - */ - public function guest_style_set($style_id) - { - global $db; - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_style = ' . (int) $style_id . ' - WHERE user_id = ' . ANONYMOUS; - $db->sql_query($sql); - } - - /** - * Select default dateformat - */ - function dateformat_select($value, $key) - { - global $user, $config; - - // Let the format_date function operate with the acp values - $old_tz = $user->timezone; - try - { - $user->timezone = new DateTimeZone($config['board_timezone']); - } - catch (\Exception $e) - { - // If the board timezone is invalid, we just use the users timezone. - } - - $dateformat_options = ''; - - foreach ($user->lang['dateformats'] as $format => $null) - { - $dateformat_options .= ''; - } - - $dateformat_options .= ''; - - // Reset users date options - $user->timezone = $old_tz; - - return " - "; - } - - /** - * Select multiple forums - */ - function select_news_forums($value, $key) - { - $forum_list = make_forum_select(false, false, true, true, true, false, true); - - // Build forum options - $s_forum_options = ''; - - return $s_forum_options; - } - - function select_exclude_forums($value, $key) - { - $forum_list = make_forum_select(false, false, true, true, true, false, true); - - // Build forum options - $s_forum_options = ''; - - return $s_forum_options; - } - - function store_feed_forums($option, $key) - { - global $db, $cache, $request; - - // Get key - $values = $request->variable($key, array(0 => 0)); - - // Empty option bit for all forums - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_options = forum_options - ' . (1 << $option) . ' - WHERE ' . $db->sql_bit_and('forum_options', $option, '<> 0'); - $db->sql_query($sql); - - // Already emptied for all... - if (count($values)) - { - // Set for selected forums - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_options = forum_options + ' . (1 << $option) . ' - WHERE ' . $db->sql_in_set('forum_id', $values); - $db->sql_query($sql); - } - - // Empty sql cache for forums table because options changed - $cache->destroy('sql', FORUMS_TABLE); - } - - /** - * Option to enable/disable removal of 'app.php' from URLs - * - * Note that if mod_rewrite is on, URLs without app.php will still work, - * but any paths generated by the controller helper url() method will not - * contain app.php. - * - * @param int $value The current config value - * @param string $key The config key - * @return string The HTML for the form field - */ - function enable_mod_rewrite($value, $key) - { - global $user; - - // Determine whether mod_rewrite is enabled on the server - // NOTE: This only works on Apache servers on which PHP is NOT - // installed as CGI. In that case, there is no way for PHP to - // determine whether or not the Apache module is enabled. - // - // To be clear on the value of $mod_rewite: - // null = Cannot determine whether or not the server has mod_rewrite - // enabled - // false = Can determine that the server does NOT have mod_rewrite - // enabled - // true = Can determine that the server DOES have mod_rewrite_enabled - $mod_rewrite = null; - if (function_exists('apache_get_modules')) - { - $mod_rewrite = (bool) in_array('mod_rewrite', apache_get_modules()); - } - - // If $message is false, mod_rewrite is enabled. - // Otherwise, it is not and we need to: - // 1) disable the form field - // 2) make sure the config value is set to 0 - // 3) append the message to the return - $value = ($mod_rewrite === false) ? 0 : $value; - $message = $mod_rewrite === null ? 'MOD_REWRITE_INFORMATION_UNAVAILABLE' : ($mod_rewrite === false ? 'MOD_REWRITE_DISABLED' : false); - - // Let's do some friendly HTML injection if we want to disable the - // form field because h_radio() has no pretty way of doing so - $field_name = 'config[enable_mod_rewrite]' . ($message === 'MOD_REWRITE_DISABLED' ? '" disabled="disabled' : ''); - - return h_radio($field_name, array(1 => 'YES', 0 => 'NO'), $value) . - ($message !== false ? '
' . $user->lang($message) . '' : ''); - } - - function send_test_email($value, $key) - { - global $user; - - return ''; - } -} diff --git a/install/update/new/includes/acp/acp_database.php b/install/update/new/includes/acp/acp_database.php deleted file mode 100644 index c1c7488..0000000 --- a/install/update/new/includes/acp/acp_database.php +++ /dev/null @@ -1,616 +0,0 @@ - -* @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_database -{ - var $db_tools; - var $u_action; - public $page_title; - - function main($id, $mode) - { - global $cache, $db, $user, $template, $table_prefix, $request; - global $phpbb_root_path, $phpbb_container, $phpbb_log; - - $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->variable('action', ''); - - $form_key = 'acp_database'; - add_form_key($form_key); - - $template->assign_vars(array( - 'MODE' => $mode - )); - - switch ($mode) - { - case 'backup': - - $this->page_title = 'ACP_BACKUP'; - - switch ($action) - { - case 'download': - $type = $request->variable('type', ''); - $table = array_intersect($this->db_tools->sql_list_tables(), $request->variable('table', array(''))); - $format = $request->variable('method', ''); - - if (!count($table)) - { - trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (!check_form_key($form_key)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $store = true; - $structure = false; - $schema_data = false; - - if ($type == 'full' || $type == 'structure') - { - $structure = true; - } - - if ($type == 'full' || $type == 'data') - { - $schema_data = true; - } - - @set_time_limit(1200); - @set_time_limit(0); - - $time = time(); - - $filename = 'backup_' . $time . '_' . unique_id(); - - /** @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); - - foreach ($table as $table_name) - { - // Get the table structure - if ($structure) - { - $extractor->write_table($table_name); - } - else - { - // We might wanna empty out all that junk :D - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $extractor->flush('DELETE FROM ' . $table_name . ";\n"); - break; - - case 'mssql_odbc': - case 'mssqlnative': - $extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n"); - break; - - case 'oracle': - $extractor->flush('TRUNCATE TABLE ' . $table_name . "/\n"); - break; - - default: - $extractor->flush('TRUNCATE TABLE ' . $table_name . ";\n"); - break; - } - } - - // Data - if ($schema_data) - { - $extractor->write_data($table_name); - } - } - - $extractor->write_end(); - - $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; - - default: - $tables = $this->db_tools->sql_list_tables(); - asort($tables); - foreach ($tables as $table_name) - { - if (strlen($table_prefix) === 0 || stripos($table_name, $table_prefix) === 0) - { - $template->assign_block_vars('tables', array( - 'TABLE' => $table_name - )); - } - } - unset($tables); - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action . '&action=download' - )); - - $available_methods = array('gzip' => 'zlib', 'bzip2' => 'bz2'); - - foreach ($available_methods as $type => $module) - { - if (!@extension_loaded($module)) - { - continue; - } - - $template->assign_block_vars('methods', array( - 'TYPE' => $type - )); - } - - $template->assign_block_vars('methods', array( - 'TYPE' => 'text' - )); - break; - } - break; - - case 'restore': - - $this->page_title = 'ACP_RESTORE'; - - switch ($action) - { - case 'submit': - $delete = $request->variable('delete', ''); - $file = $request->variable('file', ''); - - $backup_info = $this->get_backup_file($phpbb_root_path . 'store/', $file); - - 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); - } - - if ($delete) - { - if (confirm_box(true)) - { - 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 - { - confirm_box(false, $user->lang['DELETE_SELECTED_BACKUP'], build_hidden_fields(array('delete' => $delete, 'file' => $file))); - } - } - else if (confirm_box(true)) - { - switch ($backup_info['extension']) - { - case 'sql': - $fp = fopen($backup_info['file_name'], 'rb'); - $read = 'fread'; - $seek = 'fseek'; - $eof = 'feof'; - $close = 'fclose'; - $fgetd = 'fgetd'; - break; - - case 'sql.bz2': - $fp = bzopen($backup_info['file_name'], 'r'); - $read = 'bzread'; - $seek = ''; - $eof = 'feof'; - $close = 'bzclose'; - $fgetd = 'fgetd_seekless'; - break; - - case 'sql.gz': - $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()) - { - case 'mysqli': - case 'sqlite3': - while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false) - { - $db->sql_query($sql); - } - break; - - case 'postgres': - $delim = ";\n"; - while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false) - { - $query = trim($sql); - - if (substr($query, 0, 13) == 'CREATE DOMAIN') - { - list(, , $domain) = explode(' ', $query); - $sql = "SELECT domain_name - FROM information_schema.domains - WHERE domain_name = '$domain';"; - $result = $db->sql_query($sql); - if (!$db->sql_fetchrow($result)) - { - $db->sql_query($query); - } - $db->sql_freeresult($result); - } - else - { - $db->sql_query($query); - } - - if (substr($query, 0, 4) == 'COPY') - { - while (($sub = $fgetd($fp, "\n", $read, $seek, $eof)) !== '\.') - { - if ($sub === false) - { - trigger_error($user->lang['RESTORE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - pg_put_line($db->get_db_connect_id(), $sub . "\n"); - } - pg_put_line($db->get_db_connect_id(), "\\.\n"); - pg_end_copy($db->get_db_connect_id()); - } - } - break; - - case 'oracle': - while (($sql = $fgetd($fp, "/\n", $read, $seek, $eof)) !== false) - { - $db->sql_query($sql); - } - break; - - case 'mssql_odbc': - case 'mssqlnative': - while (($sql = $fgetd($fp, "GO\n", $read, $seek, $eof)) !== false) - { - $db->sql_query($sql); - } - break; - } - - $close($fp); - - // Purge the cache due to updated data - $cache->purge(); - - $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 - { - confirm_box(false, $user->lang['RESTORE_SELECTED_BACKUP'], build_hidden_fields(array('file' => $file))); - } - - default: - $backup_files = $this->get_file_list($phpbb_root_path . 'store/'); - - if (!empty($backup_files)) - { - krsort($backup_files); - - foreach ($backup_files as $name => $file) - { - $template->assign_block_vars('files', array( - 'FILE' => sha1($file), - 'NAME' => $user->format_date($name, 'd-m-Y H:i', true), - 'SUPPORTED' => true, - )); - } - } - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action . '&action=submit' - )); - break; - } - break; - } - } - - /** - * 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) - { - $backup_data = []; - - $file_list = $this->get_file_list($directory); - $supported_extensions = $this->get_supported_extensions(); - - foreach ($file_list as $file) - { - 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)) - { - $backup_data = [ - 'file_name' => $directory . $file, - 'extension' => $matches[2], - ]; - break; - } - } - - return $backup_data; - } - - /** - * 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) - { - $supported_extensions = $this->get_supported_extensions(); - - $dh = @opendir($directory); - - $backup_files = []; - - if ($dh) - { - while (($file = readdir($dh)) !== false) - { - if (preg_match('#^backup_(\d{10,})_(?:[a-z\d]{16}|[a-z\d]{32})\.(sql(?:\.(?:gz|bz2))?)$#i', $file, $matches)) - { - if (in_array($matches[2], $supported_extensions)) - { - $backup_files[(int) $matches[1]] = $file; - } - } - } - closedir($dh); - } - - return $backup_files; - } - - /** - * Get supported extensions for backup - * - * @return array List of supported extensions - */ - protected function get_supported_extensions() - { - $extensions = ['sql']; - $available_methods = ['sql.gz' => 'zlib', 'sql.bz2' => 'bz2']; - - foreach ($available_methods as $type => $module) - { - if (!@extension_loaded($module)) - { - continue; - } - $extensions[] = $type; - } - - return $extensions; - } -} - -// get how much space we allow for a chunk of data, very similar to phpMyAdmin's way of doing things ;-) (hey, we only do this for MySQL anyway :P) -function get_usable_memory() -{ - $val = trim(@ini_get('memory_limit')); - - if (preg_match('/(\\d+)([mkg]?)/i', $val, $regs)) - { - $memory_limit = (int) $regs[1]; - switch ($regs[2]) - { - - case 'k': - case 'K': - $memory_limit *= 1024; - break; - - case 'm': - case 'M': - $memory_limit *= 1048576; - break; - - case 'g': - case 'G': - $memory_limit *= 1073741824; - break; - } - - // how much memory PHP requires at the start of export (it is really a little less) - if ($memory_limit > 6100000) - { - $memory_limit -= 6100000; - } - - // allow us to consume half of the total memory available - $memory_limit /= 2; - } - else - { - // set the buffer to 1M if we have no clue how much memory PHP will give us :P - $memory_limit = 1048576; - } - - return $memory_limit; -} - -function sanitize_data_mssql($text) -{ - $data = preg_split('/[\n\t\r\b\f]/', $text); - preg_match_all('/[\n\t\r\b\f]/', $text, $matches); - - $val = array(); - - foreach ($data as $value) - { - if (strlen($value)) - { - $val[] = "'" . $value . "'"; - } - if (count($matches[0])) - { - $val[] = 'char(' . ord(array_shift($matches[0])) . ')'; - } - } - - return implode('+', $val); -} - -function sanitize_data_oracle($text) -{ -// $data = preg_split('/[\0\n\t\r\b\f\'"\/\\\]/', $text); -// preg_match_all('/[\0\n\t\r\b\f\'"\/\\\]/', $text, $matches); - $data = preg_split('/[\0\b\f\'\/]/', $text); - preg_match_all('/[\0\r\b\f\'\/]/', $text, $matches); - - $val = array(); - - foreach ($data as $value) - { - if (strlen($value)) - { - $val[] = "'" . $value . "'"; - } - if (count($matches[0])) - { - $val[] = 'chr(' . ord(array_shift($matches[0])) . ')'; - } - } - - return implode('||', $val); -} - -function sanitize_data_generic($text) -{ - $data = preg_split('/[\n\t\r\b\f]/', $text); - preg_match_all('/[\n\t\r\b\f]/', $text, $matches); - - $val = array(); - - foreach ($data as $value) - { - if (strlen($value)) - { - $val[] = "'" . $value . "'"; - } - if (count($matches[0])) - { - $val[] = "'" . array_shift($matches[0]) . "'"; - } - } - - return implode('||', $val); -} - -// modified from PHP.net -function fgetd(&$fp, $delim, $read, $seek, $eof, $buffer = 8192) -{ - $record = ''; - $delim_len = strlen($delim); - - while (!$eof($fp)) - { - $pos = strpos($record, $delim); - if ($pos === false) - { - $record .= $read($fp, $buffer); - if ($eof($fp) && ($pos = strpos($record, $delim)) !== false) - { - $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR); - return substr($record, 0, $pos); - } - } - else - { - $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR); - return substr($record, 0, $pos); - } - } - - return false; -} - -function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192) -{ - static $array = array(); - static $record = ''; - - if (!count($array)) - { - while (!$eof($fp)) - { - if (strpos($record, $delim) !== false) - { - $array = explode($delim, $record); - $record = array_pop($array); - break; - } - else - { - $record .= $read($fp, $buffer); - } - } - if ($eof($fp) && strpos($record, $delim) !== false) - { - $array = explode($delim, $record); - $record = array_pop($array); - } - } - - if (count($array)) - { - return array_shift($array); - } - - return false; -} diff --git a/install/update/new/includes/acp/acp_extensions.php b/install/update/new/includes/acp/acp_extensions.php deleted file mode 100644 index 8696654..0000000 --- a/install/update/new/includes/acp/acp_extensions.php +++ /dev/null @@ -1,771 +0,0 @@ - -* @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\exception\exception_interface; -use phpbb\exception\version_check_exception; - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -class acp_extensions -{ - var $u_action; - var $tpl_name; - var $page_title; - - private $config; - private $template; - private $user; - private $log; - private $request; - private $phpbb_dispatcher; - private $ext_manager; - private $phpbb_container; - private $php_ini; - - function main($id, $mode) - { - // Start the page - 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->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')); - - $this->page_title = 'ACP_EXTENSIONS'; - - $action = $this->request->variable('action', 'list'); - $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 = ($this->php_ini->getNumeric('max_execution_time') / 2); - $start_time = time(); - - // Cancel action - if ($this->request->is_set_post('cancel')) - { - $action = 'list'; - $ext_name = ''; - } - - if (in_array($action, array('enable', 'disable', 'delete_data')) && !check_link_hash($this->request->variable('hash', ''), $action . '.' . $ext_name)) - { - trigger_error('FORM_INVALID', E_USER_WARNING); - } - - /** - * Event to run a specific action on extension - * - * @event core.acp_extensions_run_action_before - * @var string action Action to run; if the event completes execution of the action, should be set to 'none' - * @var string u_action Url we are at - * @var string ext_name Extension name from request - * @var int safe_time_limit Safe limit of execution time - * @var int start_time Start time - * @var string tpl_name Template file to load - * @since 3.1.11-RC1 - * @changed 3.2.1-RC1 Renamed to core.acp_extensions_run_action_before, added tpl_name, added action 'none' - */ - $u_action = $this->u_action; - $tpl_name = ''; - $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name'); - extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_before', compact($vars))); - - // In case they have been updated by the event - $this->u_action = $u_action; - $this->tpl_name = $tpl_name; - - // 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); - - try - { - $md_manager->get_metadata('all'); - } - catch (exception_interface $e) - { - $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); - } - } - - // What are we doing? - switch ($action) - { - case 'none': - // Intentionally empty, used by extensions that execute additional actions in the prior event - break; - - case 'set_config_version_check_force_unstable': - $force_unstable = $this->request->variable('force_unstable', false); - - if ($force_unstable) - { - $s_hidden_fields = build_hidden_fields(array( - 'force_unstable' => $force_unstable, - )); - - confirm_box(false, $this->user->lang('EXTENSION_FORCE_UNSTABLE_CONFIRM'), $s_hidden_fields); - } - else - { - $this->config->set('extension_force_unstable', false); - trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - break; - - case 'list': - default: - if (confirm_box(true)) - { - $this->config->set('extension_force_unstable', true); - trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - - $this->list_enabled_exts(); - $this->list_disabled_exts(); - $this->list_available_exts(); - - $this->template->assign_vars(array( - 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=list&versioncheck_force=1', - 'FORCE_UNSTABLE' => $this->config['extension_force_unstable'], - 'U_ACTION' => $this->u_action, - )); - - $this->tpl_name = 'acp_ext_list'; - break; - - case 'enable_pre': - try - { - $md_manager->validate_enable(); - } - catch (exception_interface $e) - { - $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); - - $this->check_is_enableable($extension); - - if ($this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - if (confirm_box(true)) - { - redirect($this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name)); - } - else - { - confirm_box(false, $this->user->lang('EXTENSION_ENABLE_CONFIRM', $md_manager->get_metadata('display-name')), build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => 'enable_pre', - 'ext_name' => $ext_name, - ))); - } - break; - - case 'enable': - try - { - $md_manager->validate_enable(); - } - catch (exception_interface $e) - { - $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); - - $this->check_is_enableable($extension); - - try - { - while ($this->ext_manager->enable_step($ext_name)) - { - // Are we approaching the time limit? If so we want to pause the update and continue after refreshing - if ((time() - $start_time) >= $safe_time_limit) - { - meta_refresh(0, $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name)); - trigger_error('EXTENSION_ENABLE_IN_PROGRESS', E_USER_NOTICE); - } - } - - // Update custom style for admin area - $this->template->set_custom_style(array( - array( - 'name' => 'adm', - 'ext_path' => 'adm/style/', - ), - ), array($phpbb_root_path . 'adm/style')); - - $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name)); - } - catch (\phpbb\db\migration\exception $e) - { - trigger_error($this->user->lang('MIGRATION_EXCEPTION_ERROR', $e->getLocalisedMessage($this->user)), E_USER_WARNING); - } - - if ($this->request->is_ajax()) - { - $actions = $this->output_actions('enabled', [ - 'DISABLE' => $this->u_action . '&action=disable_pre&ext_name=' . urlencode($ext_name), - ]); - - $data = [ - 'EXT_ENABLE_SUCCESS' => true, - 'ACTIONS' => $actions, - 'REFRESH_DATA' => [ - 'url' => '', - 'time' => 0, - ], - ]; - - $json_response = new \phpbb\json_response; - $json_response->send($data); - } - - trigger_error($this->user->lang('EXTENSION_ENABLE_SUCCESS') . adm_back_link($this->u_action), E_USER_NOTICE); - break; - - case 'disable_pre': - if (!$this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - if (confirm_box(true)) - { - redirect($this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name)); - } - else - { - confirm_box(false, $this->user->lang('EXTENSION_DISABLE_CONFIRM', $md_manager->get_metadata('display-name')), build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => 'disable_pre', - 'ext_name' => $ext_name, - ))); - } - break; - - case 'disable': - if (!$this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - while ($this->ext_manager->disable_step($ext_name)) - { - // Are we approaching the time limit? If so we want to pause the update and continue after refreshing - if ((time() - $start_time) >= $safe_time_limit) - { - $this->template->assign_var('S_NEXT_STEP', true); - - meta_refresh(0, $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name)); - trigger_error('EXTENSION_DISABLE_IN_PROGRESS', E_USER_NOTICE); - } - } - $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_DISABLE', time(), array($ext_name)); - - if ($this->request->is_ajax()) - { - $actions = $this->output_actions('disabled', [ - 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($ext_name), - 'DELETE_DATA' => $this->u_action . '&action=delete_data_pre&ext_name=' . urlencode($ext_name), - ]); - - $data = [ - 'EXT_DISABLE_SUCCESS' => true, - 'ACTIONS' => $actions, - 'REFRESH_DATA' => [ - 'url' => '', - 'time' => 0, - ], - ]; - - $json_response = new \phpbb\json_response; - $json_response->send($data); - } - - trigger_error($this->user->lang('EXTENSION_DISABLE_SUCCESS') . adm_back_link($this->u_action), E_USER_NOTICE); - break; - - case 'delete_data_pre': - if ($this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - if (confirm_box(true)) - { - redirect($this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name)); - } - else - { - confirm_box(false, $this->user->lang('EXTENSION_DELETE_DATA_CONFIRM', $md_manager->get_metadata('display-name')), build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => 'delete_data_pre', - 'ext_name' => $ext_name, - ))); - } - break; - - case 'delete_data': - if ($this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - try - { - while ($this->ext_manager->purge_step($ext_name)) - { - // Are we approaching the time limit? If so we want to pause the update and continue after refreshing - if ((time() - $start_time) >= $safe_time_limit) - { - $this->template->assign_var('S_NEXT_STEP', true); - - meta_refresh(0, $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name)); - trigger_error('EXTENSION_DELETE_DATA_IN_PROGRESS', E_USER_NOTICE); - } - } - $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_PURGE', time(), array($ext_name)); - } - catch (\phpbb\db\migration\exception $e) - { - trigger_error($this->user->lang('MIGRATION_EXCEPTION_ERROR', $e->getLocalisedMessage($this->user)), E_USER_WARNING); - } - - if ($this->request->is_ajax()) - { - $actions = $this->output_actions('disabled', [ - 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($ext_name), - ]); - - $data = [ - 'EXT_DELETE_DATA_SUCCESS' => true, - 'ACTIONS' => $actions, - 'REFRESH_DATA' => [ - 'url' => '', - 'time' => 0, - ], - ]; - - $json_response = new \phpbb\json_response; - $json_response->send($data); - } - - trigger_error($this->user->lang('EXTENSION_DELETE_DATA_SUCCESS') . adm_back_link($this->u_action), E_USER_NOTICE); - break; - - case 'details': - // Output it to the template - $meta = $md_manager->get_metadata('all'); - $this->output_metadata_to_template($meta); - - if (isset($meta['extra']['version-check'])) - { - 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), - '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_vars(array( - 'S_VERSIONCHECK_FAIL' => true, - 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== 'VERSIONCHECK_FAIL') ? $message : '', - )); - } - $this->template->assign_var('S_VERSIONCHECK', true); - } - else - { - $this->template->assign_var('S_VERSIONCHECK', false); - } - - $this->template->assign_vars(array( - 'U_BACK' => $this->u_action . '&action=list', - 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')), - )); - - $this->tpl_name = 'acp_ext_details'; - break; - } - - /** - * Event to run after a specific action on extension has completed - * - * @event core.acp_extensions_run_action_after - * @var string action Action that has run - * @var string u_action Url we are at - * @var string ext_name Extension name from request - * @var int safe_time_limit Safe limit of execution time - * @var int start_time Start time - * @var string tpl_name Template file to load - * @since 3.1.11-RC1 - */ - $u_action = $this->u_action; - $tpl_name = $this->tpl_name; - $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name'); - extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_after', compact($vars))); - - // In case they have been updated by the event - $this->u_action = $u_action; - $this->tpl_name = $tpl_name; - } - - /** - * Lists all the enabled extensions and dumps to the template - * - * @return null - */ - public function list_enabled_exts() - { - $enabled_extension_meta_data = array(); - - foreach ($this->ext_manager->all_enabled() as $name => $location) - { - $md_manager = $this->ext_manager->create_extension_metadata_manager($name); - - try - { - $meta = $md_manager->get_metadata('all'); - $enabled_extension_meta_data[$name] = array( - 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), - 'META_VERSION' => $meta['version'], - ); - - 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 . '&action=details&versioncheck_force=1&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 (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, $message), - 'S_VERSIONCHECK' => false, - )); - } - catch (\RuntimeException $e) - { - $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; - } - } - - uasort($enabled_extension_meta_data, array($this, 'sort_extension_meta_data_table')); - - foreach ($enabled_extension_meta_data as $name => $block_vars) - { - $block_vars['NAME'] = $name; - $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); - - $this->template->assign_block_vars('enabled', $block_vars); - - $this->output_actions('enabled', array( - 'DISABLE' => $this->u_action . '&action=disable_pre&ext_name=' . urlencode($name), - )); - } - } - - /** - * Lists all the disabled extensions and dumps to the template - * - * @return null - */ - public function list_disabled_exts() - { - $disabled_extension_meta_data = array(); - - foreach ($this->ext_manager->all_disabled() as $name => $location) - { - $md_manager = $this->ext_manager->create_extension_metadata_manager($name); - - try - { - $meta = $md_manager->get_metadata('all'); - $disabled_extension_meta_data[$name] = array( - 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), - 'META_VERSION' => $meta['version'], - ); - - 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 . '&action=details&versioncheck_force=1&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 (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, $message), - 'S_VERSIONCHECK' => false, - )); - } - catch (\RuntimeException $e) - { - $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; - } - } - - uasort($disabled_extension_meta_data, array($this, 'sort_extension_meta_data_table')); - - foreach ($disabled_extension_meta_data as $name => $block_vars) - { - $block_vars['NAME'] = $name; - $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); - - $this->template->assign_block_vars('disabled', $block_vars); - - $this->output_actions('disabled', array( - 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), - 'DELETE_DATA' => $this->u_action . '&action=delete_data_pre&ext_name=' . urlencode($name), - )); - } - } - - /** - * Lists all the available extensions and dumps to the template - * - * @return null - */ - public function list_available_exts() - { - $uninstalled = array_diff_key($this->ext_manager->all_available(), $this->ext_manager->all_configured()); - - $available_extension_meta_data = array(); - - foreach ($uninstalled as $name => $location) - { - $md_manager = $this->ext_manager->create_extension_metadata_manager($name); - - try - { - $meta = $md_manager->get_metadata('all'); - $available_extension_meta_data[$name] = array( - 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), - 'META_VERSION' => $meta['version'], - ); - - 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 . '&action=details&versioncheck_force=1&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 (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, $message), - 'S_VERSIONCHECK' => false, - )); - } - } - - uasort($available_extension_meta_data, array($this, 'sort_extension_meta_data_table')); - - foreach ($available_extension_meta_data as $name => $block_vars) - { - $block_vars['NAME'] = $name; - $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); - - $this->template->assign_block_vars('disabled', $block_vars); - - $this->output_actions('disabled', array( - 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), - )); - } - } - - /** - * Output actions to a block - * - * @param string $block - * @param array $actions - * @return array List of actions to be performed on the extension - */ - private function output_actions($block, $actions) - { - $vars_ary = array(); - foreach ($actions as $lang => $options) - { - $url = $options; - if (is_array($options)) - { - $url = $options['url']; - } - - $vars = array( - 'L_ACTION' => $this->user->lang('EXTENSION_' . $lang), - 'L_ACTION_EXPLAIN' => (isset($this->user->lang['EXTENSION_' . $lang . '_EXPLAIN'])) ? $this->user->lang('EXTENSION_' . $lang . '_EXPLAIN') : '', - 'U_ACTION' => $url, - 'ACTION_AJAX' => 'ext_' . strtolower($lang), - ); - - if (isset($options['color'])) - { - $vars['COLOR'] = $options['color']; - } - - $this->template->assign_block_vars($block . '.actions', $vars); - - $vars_ary[] = $vars; - } - - return $vars_ary; - } - - /** - * Sort helper for the table containing the metadata about the extensions. - */ - protected function sort_extension_meta_data_table($val1, $val2) - { - return strnatcasecmp($val1['META_DISPLAY_NAME'], $val2['META_DISPLAY_NAME']); - } - - /** - * Outputs extension metadata into the template - * - * @param array $metadata Array with all metadata for the extension - * @return null - */ - public function output_metadata_to_template($metadata) - { - $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'] : '', - )); - } - } - - /** - * Checks whether the extension can be enabled. Triggers error if not. - * Error message can be set by the extension. - * - * @param \phpbb\extension\extension_interface $extension Extension to check - */ - protected function check_is_enableable(\phpbb\extension\extension_interface $extension) - { - $message = $extension->is_enableable(); - if ($message !== true) - { - if (empty($message)) - { - $message = $this->user->lang('EXTENSION_NOT_ENABLEABLE'); - } - else if (is_array($message)) - { - $message = implode('
', $message); - } - - trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING); - } - } -} diff --git a/install/update/new/includes/acp/acp_forums.php b/install/update/new/includes/acp/acp_forums.php deleted file mode 100644 index ba3901f..0000000 --- a/install/update/new/includes/acp/acp_forums.php +++ /dev/null @@ -1,2211 +0,0 @@ - -* @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_forums -{ - var $u_action; - var $parent_id = 0; - - function main($id, $mode) - { - global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher; - global $phpbb_admin_path, $phpbb_root_path, $phpEx, $phpbb_log; - - $user->add_lang('acp/forums'); - $this->tpl_name = 'acp_forums'; - $this->page_title = 'ACP_MANAGE_FORUMS'; - - $form_key = 'acp_forums'; - add_form_key($form_key); - - $action = $request->variable('action', ''); - $update = (isset($_POST['update'])) ? true : false; - $forum_id = $request->variable('f', 0); - - $this->parent_id = $request->variable('parent_id', 0); - $forum_data = $errors = array(); - if ($update && !check_form_key($form_key)) - { - $update = false; - $errors[] = $user->lang['FORM_INVALID']; - } - - // Check additional permissions - switch ($action) - { - case 'progress_bar': - $start = $request->variable('start', 0); - $total = $request->variable('total', 0); - - $this->display_progress_bar($start, $total); - break; - - case 'delete': - - if (!$auth->acl_get('a_forumdel')) - { - trigger_error($user->lang['NO_PERMISSION_FORUM_DELETE'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - break; - - case 'add': - - if (!$auth->acl_get('a_forumadd')) - { - trigger_error($user->lang['NO_PERMISSION_FORUM_ADD'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - break; - } - - // Major routines - if ($update) - { - switch ($action) - { - case 'delete': - $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 (count($errors)) - { - break; - } - - $auth->acl_clear_prefetch(); - $cache->destroy('sql', FORUMS_TABLE); - - trigger_error($user->lang['FORUM_DELETED'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); - - break; - - case 'edit': - $forum_data = array( - 'forum_id' => $forum_id - ); - - // No break here - - case 'add': - - $forum_data += array( - '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' => $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' => $request->variable('forum_rules', '', true), - 'forum_rules_uid' => '', - 'forum_rules_options' => 7, - 'forum_rules_bitfield' => '', - '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', true), - 'display_subforum_limit'=> $request->variable('display_subforum_limit', false), - 'display_on_index' => $request->variable('display_on_index', true), - 'forum_topics_per_page' => $request->variable('topics_per_page', 0), - 'enable_indexing' => $request->variable('enable_indexing', true), - 'enable_icons' => $request->variable('enable_icons', true), - '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), - ); - - /** - * Request forum data and operate on it (parse texts, etc.) - * - * @event core.acp_manage_forums_request_data - * @var string action Type of the action: add|edit - * @var array forum_data Array with new forum data - * @since 3.1.0-a1 - */ - $vars = array('action', 'forum_data'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_request_data', compact($vars))); - - // On add, add empty forum_options... else do not consider it (not updating it) - if ($action == 'add') - { - $forum_data['forum_options'] = 0; - } - - // Use link_display_on_index setting if forum type is link - if ($forum_data['forum_type'] == FORUM_LINK) - { - $forum_data['display_on_index'] = $request->variable('link_display_on_index', false); - } - - // Linked forums and categories are not able to be locked... - if ($forum_data['forum_type'] == FORUM_LINK || $forum_data['forum_type'] == FORUM_CAT) - { - $forum_data['forum_status'] = ITEM_UNLOCKED; - } - - $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->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->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 (!count($errors)) - { - $forum_perm_from = $request->variable('forum_perm_from', 0); - $cache->destroy('sql', FORUMS_TABLE); - - $copied_permissions = false; - // Copy permissions? - if ($forum_perm_from && $forum_perm_from != $forum_data['forum_id'] && - ($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')))) - { - copy_forum_permissions($forum_perm_from, $forum_data['forum_id'], ($action == 'edit') ? true : false); - phpbb_cache_moderators($db, $cache, $auth); - $copied_permissions = true; - } -/* Commented out because of questionable UI workflow - re-visit for 3.0.7 - else if (!$this->parent_id && $action != 'edit' && $auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')) - { - $this->copy_permission_page($forum_data); - return; - } -*/ - $auth->acl_clear_prefetch(); - - $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_data['forum_id']; - - $message = ($action == 'add') ? $user->lang['FORUM_CREATED'] : $user->lang['FORUM_UPDATED']; - - // redirect directly to permission settings screen if authed - if ($action == 'add' && !$copied_permissions && $auth->acl_get('a_fauth')) - { - $message .= '

' . sprintf($user->lang['REDIRECT_ACL'], '', ''); - - meta_refresh(4, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url)); - } - - trigger_error($message . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); - } - - break; - } - } - - switch ($action) - { - case 'move_up': - case 'move_down': - - if (!$forum_id) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - $sql = 'SELECT * - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - $move_forum_name = $this->move_forum_by($row, $action, 1); - - if ($move_forum_name !== false) - { - $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); - } - - if ($request->is_ajax()) - { - $json_response = new \phpbb\json_response; - $json_response->send(array('success' => ($move_forum_name !== false))); - } - - break; - - case 'sync': - if (!$forum_id) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - @set_time_limit(0); - - $sql = 'SELECT forum_name, (forum_topics_approved + forum_topics_unapproved + forum_topics_softdeleted) AS total_topics - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - if ($row['total_topics']) - { - $sql = 'SELECT MIN(topic_id) as min_topic_id, MAX(topic_id) as max_topic_id - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = ' . $forum_id; - $result = $db->sql_query($sql); - $row2 = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Typecast to int if there is no data available - $row2['min_topic_id'] = (int) $row2['min_topic_id']; - $row2['max_topic_id'] = (int) $row2['max_topic_id']; - - $start = $request->variable('start', $row2['min_topic_id']); - - $batch_size = 2000; - $end = $start + $batch_size; - - // Sync all topics in batch mode... - sync('topic', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, true); - - if ($end < $row2['max_topic_id']) - { - // We really need to find a way of showing statistics... no progress here - $sql = 'SELECT COUNT(topic_id) as num_topics - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = ' . $forum_id . ' - AND topic_id BETWEEN ' . $start . ' AND ' . $end; - $result = $db->sql_query($sql); - $topics_done = $request->variable('topics_done', 0) + (int) $db->sql_fetchfield('num_topics'); - $db->sql_freeresult($result); - - $start += $batch_size; - - $url = $this->u_action . "&parent_id={$this->parent_id}&f=$forum_id&action=sync&start=$start&topics_done=$topics_done&total={$row['total_topics']}"; - - meta_refresh(0, $url); - - $template->assign_vars(array( - 'U_PROGRESS_BAR' => $this->u_action . "&action=progress_bar&start=$topics_done&total={$row['total_topics']}", - 'UA_PROGRESS_BAR' => addslashes($this->u_action . "&action=progress_bar&start=$topics_done&total={$row['total_topics']}"), - 'S_CONTINUE_SYNC' => true, - 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $topics_done, $row['total_topics'])) - ); - - return; - } - } - - $url = $this->u_action . "&parent_id={$this->parent_id}&f=$forum_id&action=sync_forum"; - meta_refresh(0, $url); - - $template->assign_vars(array( - 'U_PROGRESS_BAR' => $this->u_action . '&action=progress_bar', - 'UA_PROGRESS_BAR' => addslashes($this->u_action . '&action=progress_bar'), - 'S_CONTINUE_SYNC' => true, - 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], 0, $row['total_topics'])) - ); - - return; - - break; - - case 'sync_forum': - - $sql = 'SELECT forum_name, forum_type - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - sync('forum', 'forum_id', $forum_id, false, true); - - $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'])); - - break; - - case 'add': - case 'edit': - - if ($update) - { - $forum_data['forum_flags'] = 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->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 - $row = array(); - - // Show form to create/modify a forum - if ($action == 'edit') - { - $this->page_title = 'EDIT_FORUM'; - $row = $this->get_forum_info($forum_id); - $old_forum_type = $row['forum_type']; - - if (!$update) - { - $forum_data = $row; - } - else - { - $forum_data['left_id'] = $row['left_id']; - $forum_data['right_id'] = $row['right_id']; - } - - // Make sure no direct child forums are able to be selected as parents. - $exclude_forums = array(); - foreach (get_forum_branch($forum_id, 'children') as $row) - { - $exclude_forums[] = $row['forum_id']; - } - - $parents_list = make_forum_select($forum_data['parent_id'], $exclude_forums, false, false, false); - - $forum_data['forum_password_confirm'] = $forum_data['forum_password']; - } - else - { - $this->page_title = 'CREATE_FORUM'; - - $forum_id = $this->parent_id; - $parents_list = make_forum_select($this->parent_id, false, false, false, false); - - // Fill forum data with default values - if (!$update) - { - $forum_data = array( - 'parent_id' => $this->parent_id, - 'forum_type' => FORUM_POST, - 'forum_status' => ITEM_UNLOCKED, - 'forum_name' => $request->variable('forum_name', '', true), - 'forum_link' => '', - 'forum_link_track' => false, - 'forum_desc' => '', - 'forum_rules' => '', - 'forum_rules_link' => '', - 'forum_image' => '', - 'forum_style' => 0, - 'display_subforum_list' => true, - 'display_subforum_limit' => false, - 'display_on_index' => true, - 'forum_topics_per_page' => 0, - 'enable_indexing' => true, - 'enable_icons' => true, - 'enable_prune' => false, - 'prune_days' => 7, - 'prune_viewed' => 7, - 'prune_freq' => 1, - 'enable_shadow_prune' => false, - 'prune_shadow_days' => 7, - 'prune_shadow_freq' => 1, - 'forum_flags' => FORUM_FLAG_POST_REVIEW + FORUM_FLAG_ACTIVE_TOPICS, - 'forum_options' => 0, - 'forum_password' => '', - 'forum_password_confirm'=> '', - ); - } - } - - /** - * Initialise data before we display the add/edit form - * - * @event core.acp_manage_forums_initialise_data - * @var string action Type of the action: add|edit - * @var bool update Do we display the form only - * or did the user press submit - * @var int forum_id When editing: the forum id, - * when creating: the parent forum id - * @var array row Array with current forum data - * empty when creating new forum - * @var array forum_data Array with new forum data - * @var string parents_list List of parent options - * @since 3.1.0-a1 - */ - $vars = array('action', 'update', 'forum_id', 'row', 'forum_data', 'parents_list'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_initialise_data', compact($vars))); - - $forum_rules_data = array( - 'text' => $forum_data['forum_rules'], - 'allow_bbcode' => true, - 'allow_smilies' => true, - 'allow_urls' => true - ); - - $forum_desc_data = array( - 'text' => $forum_data['forum_desc'], - 'allow_bbcode' => true, - 'allow_smilies' => true, - 'allow_urls' => true - ); - - $forum_rules_preview = ''; - - // Parse rules if specified - if ($forum_data['forum_rules']) - { - if (!isset($forum_data['forum_rules_uid'])) - { - // 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->variable('rules_allow_bbcode', false), $request->variable('rules_allow_urls', false), $request->variable('rules_allow_smilies', false)); - } - - // Generate preview content - $forum_rules_preview = generate_text_for_display($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options']); - - // decode... - $forum_rules_data = generate_text_for_edit($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_options']); - } - - // Parse desciption if specified - if ($forum_data['forum_desc']) - { - if (!isset($forum_data['forum_desc_uid'])) - { - // 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->variable('desc_allow_bbcode', false), $request->variable('desc_allow_urls', false), $request->variable('desc_allow_smilies', false)); - } - - // decode... - $forum_desc_data = generate_text_for_edit($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_options']); - } - - $forum_type_options = ''; - $forum_type_ary = array(FORUM_CAT => 'CAT', FORUM_POST => 'FORUM', FORUM_LINK => 'LINK'); - - foreach ($forum_type_ary as $value => $lang) - { - $forum_type_options .= ''; - } - - $styles_list = style_select($forum_data['forum_style'], true); - - $statuslist = ''; - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type = ' . FORUM_POST . " - AND forum_id <> $forum_id"; - $result = $db->sql_query_limit($sql, 1); - - $postable_forum_exists = false; - if ($db->sql_fetchrow($result)) - { - $postable_forum_exists = true; - } - $db->sql_freeresult($result); - - // Subforum move options - if ($action == 'edit' && $forum_data['forum_type'] == FORUM_CAT) - { - $subforums_id = array(); - $subforums = get_forum_branch($forum_id, 'children'); - - foreach ($subforums as $row) - { - $subforums_id[] = $row['forum_id']; - } - - $forums_list = make_forum_select($forum_data['parent_id'], $subforums_id); - - if ($postable_forum_exists) - { - $template->assign_vars(array( - 'S_MOVE_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $subforums_id)) // , false, true, false??? - ); - } - - $template->assign_vars(array( - 'S_HAS_SUBFORUMS' => ($forum_data['right_id'] - $forum_data['left_id'] > 1) ? true : false, - 'S_FORUMS_LIST' => $forums_list) - ); - } - else if ($postable_forum_exists) - { - $template->assign_vars(array( - 'S_MOVE_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $forum_id, false, true, false)) - ); - } - - $s_show_display_on_index = false; - - if ($forum_data['parent_id'] > 0) - { - // if this forum is a subforum put the "display on index" checkbox - if ($parent_info = $this->get_forum_info($forum_data['parent_id'])) - { - if ($parent_info['parent_id'] > 0 || $parent_info['forum_type'] == FORUM_CAT) - { - $s_show_display_on_index = true; - } - } - } - - if (strlen($forum_data['forum_password']) == 32) - { - $errors[] = $user->lang['FORUM_PASSWORD_OLD']; - } - - $template_data = array( - 'S_EDIT_FORUM' => true, - '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, - - 'U_BACK' => $this->u_action . '&parent_id=' . $this->parent_id, - 'U_EDIT_ACTION' => $this->u_action . "&parent_id={$this->parent_id}&action=$action&f=$forum_id", - - 'L_COPY_PERMISSIONS_EXPLAIN' => $user->lang['COPY_PERMISSIONS_' . strtoupper($action) . '_EXPLAIN'], - 'L_TITLE' => $user->lang[$this->page_title], - 'ERROR_MSG' => (count($errors)) ? implode('
', $errors) : '', - - 'FORUM_NAME' => $forum_data['forum_name'], - 'FORUM_DATA_LINK' => $forum_data['forum_link'], - 'FORUM_IMAGE' => $forum_data['forum_image'], - 'FORUM_IMAGE_SRC' => ($forum_data['forum_image']) ? $phpbb_root_path . $forum_data['forum_image'] : '', - 'FORUM_POST' => FORUM_POST, - 'FORUM_LINK' => FORUM_LINK, - 'FORUM_CAT' => FORUM_CAT, - 'PRUNE_FREQ' => $forum_data['prune_freq'], - 'PRUNE_DAYS' => $forum_data['prune_days'], - 'PRUNE_VIEWED' => $forum_data['prune_viewed'], - 'PRUNE_SHADOW_FREQ' => $forum_data['prune_shadow_freq'], - 'PRUNE_SHADOW_DAYS' => $forum_data['prune_shadow_days'], - 'TOPICS_PER_PAGE' => $forum_data['forum_topics_per_page'], - 'FORUM_RULES_LINK' => $forum_data['forum_rules_link'], - 'FORUM_RULES' => $forum_data['forum_rules'], - 'FORUM_RULES_PREVIEW' => $forum_rules_preview, - 'FORUM_RULES_PLAIN' => $forum_rules_data['text'], - 'S_BBCODE_CHECKED' => ($forum_rules_data['allow_bbcode']) ? true : false, - 'S_SMILIES_CHECKED' => ($forum_rules_data['allow_smilies']) ? true : false, - 'S_URLS_CHECKED' => ($forum_rules_data['allow_urls']) ? true : false, - 'S_FORUM_PASSWORD_SET' => (empty($forum_data['forum_password'])) ? false : true, - - 'FORUM_DESC' => $forum_desc_data['text'], - 'S_DESC_BBCODE_CHECKED' => ($forum_desc_data['allow_bbcode']) ? true : false, - 'S_DESC_SMILIES_CHECKED' => ($forum_desc_data['allow_smilies']) ? true : false, - 'S_DESC_URLS_CHECKED' => ($forum_desc_data['allow_urls']) ? true : false, - - 'S_FORUM_TYPE_OPTIONS' => $forum_type_options, - 'S_STATUS_OPTIONS' => $statuslist, - 'S_PARENT_OPTIONS' => $parents_list, - 'S_STYLES_OPTIONS' => $styles_list, - 'S_FORUM_OPTIONS' => make_forum_select(($action == 'add') ? $forum_data['parent_id'] : false, ($action == 'edit') ? $forum_data['forum_id'] : false, false, false, false), - 'S_SHOW_DISPLAY_ON_INDEX' => $s_show_display_on_index, - 'S_FORUM_POST' => ($forum_data['forum_type'] == FORUM_POST) ? true : false, - 'S_FORUM_ORIG_POST' => (isset($old_forum_type) && $old_forum_type == FORUM_POST) ? true : false, - 'S_FORUM_ORIG_CAT' => (isset($old_forum_type) && $old_forum_type == FORUM_CAT) ? true : false, - 'S_FORUM_ORIG_LINK' => (isset($old_forum_type) && $old_forum_type == FORUM_LINK) ? true : false, - 'S_FORUM_LINK' => ($forum_data['forum_type'] == FORUM_LINK) ? true : false, - 'S_FORUM_CAT' => ($forum_data['forum_type'] == FORUM_CAT) ? true : false, - 'S_ENABLE_INDEXING' => ($forum_data['enable_indexing']) ? true : false, - 'S_TOPIC_ICONS' => ($forum_data['enable_icons']) ? true : false, - 'S_DISPLAY_SUBFORUM_LIST' => ($forum_data['display_subforum_list']) ? true : false, - 'S_DISPLAY_SUBFORUM_LIMIT' => ($forum_data['display_subforum_limit']) ? true : false, - 'S_DISPLAY_ON_INDEX' => ($forum_data['display_on_index']) ? true : false, - 'S_PRUNE_ENABLE' => ($forum_data['enable_prune']) ? true : false, - 'S_PRUNE_SHADOW_ENABLE' => ($forum_data['enable_shadow_prune']) ? true : false, - 'S_FORUM_LINK_TRACK' => ($forum_data['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? true : false, - 'S_PRUNE_OLD_POLLS' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_POLL) ? true : false, - 'S_PRUNE_ANNOUNCE' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_ANNOUNCE) ? true : false, - 'S_PRUNE_STICKY' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_STICKY) ? true : false, - 'S_DISPLAY_ACTIVE_TOPICS' => ($forum_data['forum_type'] == FORUM_POST) ? ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) : true, - 'S_ENABLE_ACTIVE_TOPICS' => ($forum_data['forum_type'] == FORUM_CAT) ? ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) : false, - 'S_ENABLE_POST_REVIEW' => ($forum_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) ? true : false, - 'S_ENABLE_QUICK_REPLY' => ($forum_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) ? true : false, - 'S_CAN_COPY_PERMISSIONS' => ($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth'))) ? true : false, - ); - - /** - * Modify forum template data before we display the form - * - * @event core.acp_manage_forums_display_form - * @var string action Type of the action: add|edit - * @var bool update Do we display the form only - * or did the user press submit - * @var int forum_id When editing: the forum id, - * when creating: the parent forum id - * @var array row Array with current forum data - * empty when creating new forum - * @var array forum_data Array with new forum data - * @var string parents_list List of parent options - * @var array errors Array of errors, if you add errors - * ensure to update the template variables - * S_ERROR and ERROR_MSG to display it - * @var array template_data Array with new forum data - * @since 3.1.0-a1 - */ - $vars = array( - 'action', - 'update', - 'forum_id', - 'row', - 'forum_data', - 'parents_list', - 'errors', - 'template_data', - ); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_display_form', compact($vars))); - - $template->assign_vars($template_data); - - return; - - break; - - case 'delete': - - if (!$forum_id) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - $forum_data = $this->get_forum_info($forum_id); - - $subforums_id = array(); - $subforums = get_forum_branch($forum_id, 'children'); - - foreach ($subforums as $row) - { - $subforums_id[] = $row['forum_id']; - } - - $forums_list = make_forum_select($forum_data['parent_id'], $subforums_id); - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type = ' . FORUM_POST . " - AND forum_id <> $forum_id"; - $result = $db->sql_query_limit($sql, 1); - - if ($db->sql_fetchrow($result)) - { - $template->assign_vars(array( - 'S_MOVE_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $subforums_id, false, true)) // , false, true, false??? - ); - } - $db->sql_freeresult($result); - - $parent_id = ($this->parent_id == $forum_id) ? 0 : $this->parent_id; - - $template->assign_vars(array( - 'S_DELETE_FORUM' => true, - 'U_ACTION' => $this->u_action . "&parent_id={$parent_id}&action=delete&f=$forum_id", - 'U_BACK' => $this->u_action . '&parent_id=' . $this->parent_id, - - 'FORUM_NAME' => $forum_data['forum_name'], - 'S_FORUM_POST' => ($forum_data['forum_type'] == FORUM_POST) ? true : false, - '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' => (count($errors)) ? true : false, - 'ERROR_MSG' => (count($errors)) ? implode('
', $errors) : '') - ); - - return; - break; - - case 'copy_perm': - $forum_perm_from = $request->variable('forum_perm_from', 0); - - // Copy permissions? - if (!empty($forum_perm_from) && $forum_perm_from != $forum_id) - { - copy_forum_permissions($forum_perm_from, $forum_id, true); - phpbb_cache_moderators($db, $cache, $auth); - $auth->acl_clear_prefetch(); - $cache->destroy('sql', FORUMS_TABLE); - - $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_id; - - $message = $user->lang['FORUM_UPDATED']; - - // Redirect to permissions - if ($auth->acl_get('a_fauth')) - { - $message .= '

' . sprintf($user->lang['REDIRECT_ACL'], '', ''); - } - - trigger_error($message . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); - } - - break; - } - - // Default management page - if (!$this->parent_id) - { - $navigation = $user->lang['FORUM_INDEX']; - } - else - { - $navigation = '' . $user->lang['FORUM_INDEX'] . ''; - - $forums_nav = get_forum_branch($this->parent_id, 'parents', 'descending'); - foreach ($forums_nav as $row) - { - if ($row['forum_id'] == $this->parent_id) - { - $navigation .= ' -> ' . $row['forum_name']; - } - else - { - $navigation .= ' -> ' . $row['forum_name'] . ''; - } - } - } - - // Jumpbox - $forum_box = make_forum_select($this->parent_id, false, false, false, false); //make_forum_select($this->parent_id); - - if ($action == 'sync' || $action == 'sync_forum') - { - $template->assign_var('S_RESYNCED', true); - } - - $sql = 'SELECT * - FROM ' . FORUMS_TABLE . " - WHERE parent_id = $this->parent_id - ORDER BY left_id"; - $result = $db->sql_query($sql); - - $rowset = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[(int) $row['forum_id']] = $row; - } - $db->sql_freeresult($result); - - /** - * Modify the forum list data - * - * @event core.acp_manage_forums_modify_forum_list - * @var array rowset Array with the forums list data - * @since 3.1.10-RC1 - */ - $vars = array('rowset'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_modify_forum_list', compact($vars))); - - if (!empty($rowset)) - { - foreach ($rowset as $row) - { - $forum_type = $row['forum_type']; - - if ($row['forum_status'] == ITEM_LOCKED) - { - $folder_image = '' . $user->lang['LOCKED'] . ''; - } - else - { - switch ($forum_type) - { - case FORUM_LINK: - $folder_image = '' . $user->lang['LINK'] . ''; - break; - - default: - $folder_image = ($row['left_id'] + 1 != $row['right_id']) ? '' . $user->lang['SUBFORUM'] . '' : '' . $user->lang['FOLDER'] . ''; - break; - } - } - - $url = $this->u_action . "&parent_id=$this->parent_id&f={$row['forum_id']}"; - - $template->assign_block_vars('forums', array( - 'FOLDER_IMAGE' => $folder_image, - 'FORUM_IMAGE' => ($row['forum_image']) ? '' : '', - 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', - 'FORUM_NAME' => $row['forum_name'], - 'FORUM_DESCRIPTION' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), - 'FORUM_TOPICS' => $row['forum_topics_approved'], - 'FORUM_POSTS' => $row['forum_posts_approved'], - - 'S_FORUM_LINK' => ($forum_type == FORUM_LINK) ? true : false, - 'S_FORUM_POST' => ($forum_type == FORUM_POST) ? true : false, - - 'U_FORUM' => $this->u_action . '&parent_id=' . $row['forum_id'], - 'U_MOVE_UP' => $url . '&action=move_up', - 'U_MOVE_DOWN' => $url . '&action=move_down', - 'U_EDIT' => $url . '&action=edit', - 'U_DELETE' => $url . '&action=delete', - 'U_SYNC' => $url . '&action=sync') - ); - } - } - else if ($this->parent_id) - { - $row = $this->get_forum_info($this->parent_id); - - $url = $this->u_action . '&parent_id=' . $this->parent_id . '&f=' . $row['forum_id']; - - $template->assign_vars(array( - 'S_NO_FORUMS' => true, - - 'U_EDIT' => $url . '&action=edit', - 'U_DELETE' => $url . '&action=delete', - 'U_SYNC' => $url . '&action=sync') - ); - } - unset($rowset); - - $template->assign_vars(array( - 'ERROR_MSG' => (count($errors)) ? implode('
', $errors) : '', - 'NAVIGATION' => $navigation, - 'FORUM_BOX' => $forum_box, - 'U_SEL_ACTION' => $this->u_action, - 'U_ACTION' => $this->u_action . '&parent_id=' . $this->parent_id, - - 'U_PROGRESS_BAR' => $this->u_action . '&action=progress_bar', - 'UA_PROGRESS_BAR' => addslashes($this->u_action . '&action=progress_bar'), - )); - } - - /** - * Get forum details - */ - function get_forum_info($forum_id) - { - global $db; - - $sql = 'SELECT * - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error("Forum #$forum_id does not exist", E_USER_ERROR); - } - - return $row; - } - - /** - * Update forum data - */ - function update_forum_data(&$forum_data_ary) - { - 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 - * - * @event core.acp_manage_forums_validate_data - * @var array forum_data Array with new forum data - * @var array errors Array of errors, should be strings and not - * language key. - * @since 3.1.0-a1 - */ - $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_ary['forum_name'] == '') - { - $errors[] = $user->lang['FORUM_NAME_EMPTY']; - } - - /** - * 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('
', $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_ary['forum_rules']) > 4000) - { - $errors[] = $user->lang['FORUM_RULES_TOO_LONG']; - } - - if ($forum_data_ary['forum_password'] || $forum_data_ary['forum_password_confirm']) - { - if ($forum_data_ary['forum_password'] != $forum_data_ary['forum_password_confirm']) - { - $forum_data_ary['forum_password'] = $forum_data_ary['forum_password_confirm'] = ''; - $errors[] = $user->lang['FORUM_PASSWORD_MISMATCH']; - } - } - - if ($forum_data_ary['prune_days'] < 0 || $forum_data_ary['prune_viewed'] < 0 || $forum_data_ary['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_ary['forum_topics_per_page'], 'column_type' => 'USINT:0'), - ); - - if (!empty($forum_data_ary['forum_image']) && !file_exists($phpbb_root_path . $forum_data_ary['forum_image'])) - { - $errors[] = $user->lang['FORUM_IMAGE_NO_EXIST']; - } - - validate_range($range_test_ary, $errors); - - // Set forum flags - // 1 = link tracking - // 2 = prune old polls - // 4 = prune announcements - // 8 = prune stickies - // 16 = show active topics - // 32 = enable post review - $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_ary; - - unset($forum_data_sql['forum_link_track']); - unset($forum_data_sql['prune_old_polls']); - unset($forum_data_sql['prune_announce']); - unset($forum_data_sql['prune_sticky']); - unset($forum_data_sql['show_active']); - unset($forum_data_sql['enable_post_review']); - unset($forum_data_sql['enable_quick_reply']); - unset($forum_data_sql['forum_password_confirm']); - - // What are we going to do tonight Brain? The same thing we do everynight, - // 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 (count($errors)) - { - return $errors; - } - - // As we don't know the old password, it's kinda tricky to detect changes - if ($forum_data_sql['forum_password_unset']) - { - $forum_data_sql['forum_password'] = ''; - } - else if (empty($forum_data_sql['forum_password'])) - { - unset($forum_data_sql['forum_password']); - } - 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 - * - * @event core.acp_manage_forums_update_data_before - * @var array forum_data Array with forum data - * @var array forum_data_sql Array with data we are going to update - * If forum_data_sql[forum_id] is set, we update - * that forum, otherwise a new one is created. - * @since 3.1.0-a1 - */ - $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']); - - if ($is_new_forum) - { - // no forum_id means we're creating a new forum - unset($forum_data_sql['type_action']); - - if ($forum_data_sql['parent_id']) - { - $sql = 'SELECT left_id, right_id, forum_type - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $forum_data_sql['parent_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['PARENT_NOT_EXIST'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - if ($row['forum_type'] == FORUM_LINK) - { - $errors[] = $user->lang['PARENT_IS_LINK_FORUM']; - return $errors; - } - - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET left_id = left_id + 2, right_id = right_id + 2 - WHERE left_id > ' . $row['right_id']; - $db->sql_query($sql); - - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET right_id = right_id + 2 - WHERE ' . $row['left_id'] . ' BETWEEN left_id AND right_id'; - $db->sql_query($sql); - - $forum_data_sql['left_id'] = $row['right_id']; - $forum_data_sql['right_id'] = $row['right_id'] + 1; - } - else - { - $sql = 'SELECT MAX(right_id) AS right_id - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $forum_data_sql['left_id'] = $row['right_id'] + 1; - $forum_data_sql['right_id'] = $row['right_id'] + 2; - } - - $sql = 'INSERT INTO ' . FORUMS_TABLE . ' ' . $db->sql_build_array('INSERT', $forum_data_sql); - $db->sql_query($sql); - - $forum_data_ary['forum_id'] = $db->sql_nextid(); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_ADD', false, array($forum_data_ary['forum_name'])); - } - else - { - $row = $this->get_forum_info($forum_data_sql['forum_id']); - - if ($row['forum_type'] == FORUM_POST && $row['forum_type'] != $forum_data_sql['forum_type']) - { - // Has subforums and want to change into a link? - if ($row['right_id'] - $row['left_id'] > 1 && $forum_data_sql['forum_type'] == FORUM_LINK) - { - $errors[] = $user->lang['FORUM_WITH_SUBFORUMS_NOT_TO_LINK']; - return $errors; - } - - // we're turning a postable forum into a non-postable forum - if ($forum_data_sql['type_action'] == 'move') - { - $to_forum_id = $request->variable('to_forum_id', 0); - - if ($to_forum_id) - { - $errors = $this->move_forum_content($forum_data_sql['forum_id'], $to_forum_id); - } - else - { - return array($user->lang['NO_DESTINATION_FORUM']); - } - } - else if ($forum_data_sql['type_action'] == 'delete') - { - $errors = $this->delete_forum_content($forum_data_sql['forum_id']); - } - else - { - return array($user->lang['NO_FORUM_ACTION']); - } - - $forum_data_sql['forum_posts_approved'] = $forum_data_sql['forum_posts_unapproved'] = $forum_data_sql['forum_posts_softdeleted'] = $forum_data_sql['forum_topics_approved'] = $forum_data_sql['forum_topics_unapproved'] = $forum_data_sql['forum_topics_softdeleted'] = 0; - $forum_data_sql['forum_last_post_id'] = $forum_data_sql['forum_last_poster_id'] = $forum_data_sql['forum_last_post_time'] = 0; - $forum_data_sql['forum_last_poster_name'] = $forum_data_sql['forum_last_poster_colour'] = ''; - } - else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_LINK) - { - // Has subforums? - 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->variable('action_subforums', ''); - $subforums_to_id = $request->variable('subforums_to_id', 0); - - if ($action_subforums == 'delete') - { - $rows = get_forum_branch($row['forum_id'], 'children', 'descending', false); - - foreach ($rows as $_row) - { - // Do not remove the forum id we are about to change. ;) - if ($_row['forum_id'] == $row['forum_id']) - { - continue; - } - - $forum_ids[] = $_row['forum_id']; - $errors = array_merge($errors, $this->delete_forum_content($_row['forum_id'])); - } - - if (count($errors)) - { - return $errors; - } - - if (count($forum_ids)) - { - $sql = 'DELETE FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - // Delete forum ids from extension groups table - $sql = 'SELECT group_id, allowed_forums - FROM ' . EXTENSION_GROUPS_TABLE; - $result = $db->sql_query($sql); - - while ($_row = $db->sql_fetchrow($result)) - { - if (!$_row['allowed_forums']) - { - continue; - } - - $allowed_forums = unserialize(trim($_row['allowed_forums'])); - $allowed_forums = array_diff($allowed_forums, $forum_ids); - - $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . " - SET allowed_forums = '" . ((count($allowed_forums)) ? serialize($allowed_forums) : '') . "' - WHERE group_id = {$_row['group_id']}"; - $db->sql_query($sql); - } - $db->sql_freeresult($result); - - $cache->destroy('_extensions'); - } - } - else if ($action_subforums == 'move') - { - if (!$subforums_to_id) - { - return array($user->lang['NO_DESTINATION_FORUM']); - } - - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $subforums_to_id; - $result = $db->sql_query($sql); - $_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$_row) - { - return array($user->lang['NO_FORUM']); - } - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . " - WHERE parent_id = {$row['forum_id']}"; - $result = $db->sql_query($sql); - - while ($_row = $db->sql_fetchrow($result)) - { - $this->move_forum($_row['forum_id'], $subforums_to_id); - } - $db->sql_freeresult($result); - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET parent_id = $subforums_to_id - WHERE parent_id = {$row['forum_id']}"; - $db->sql_query($sql); - } - - // Adjust the left/right id - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET right_id = left_id + 1 - WHERE forum_id = ' . $row['forum_id']; - $db->sql_query($sql); - } - } - else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_POST) - { - // Changing a category to a forum? Reset the data (you can't post directly in a cat, you must use a forum) - $forum_data_sql['forum_posts_approved'] = 0; - $forum_data_sql['forum_posts_unapproved'] = 0; - $forum_data_sql['forum_posts_softdeleted'] = 0; - $forum_data_sql['forum_topics_approved'] = 0; - $forum_data_sql['forum_topics_unapproved'] = 0; - $forum_data_sql['forum_topics_softdeleted'] = 0; - $forum_data_sql['forum_last_post_id'] = 0; - $forum_data_sql['forum_last_post_subject'] = ''; - $forum_data_sql['forum_last_post_time'] = 0; - $forum_data_sql['forum_last_poster_id'] = 0; - $forum_data_sql['forum_last_poster_name'] = ''; - $forum_data_sql['forum_last_poster_colour'] = ''; - } - - if (count($errors)) - { - return $errors; - } - - if ($row['parent_id'] != $forum_data_sql['parent_id']) - { - if ($row['forum_id'] != $forum_data_sql['parent_id']) - { - $errors = $this->move_forum($forum_data_sql['forum_id'], $forum_data_sql['parent_id']); - } - else - { - $forum_data_sql['parent_id'] = $row['parent_id']; - } - } - - if (count($errors)) - { - return $errors; - } - - unset($forum_data_sql['type_action']); - - if ($row['forum_name'] != $forum_data_sql['forum_name']) - { - // the forum name has changed, clear the parents list of all forums (for safety) - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_parents = ''"; - $db->sql_query($sql); - } - - // Setting the forum id to the forum id is not really received well by some dbs. ;) - $forum_id = $forum_data_sql['forum_id']; - unset($forum_data_sql['forum_id']); - - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $forum_data_sql) . ' - WHERE forum_id = ' . $forum_id; - $db->sql_query($sql); - - // Add it back - $forum_data_ary['forum_id'] = $forum_id; - - $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 - * - * @event core.acp_manage_forums_update_data_after - * @var array forum_data Array with forum data - * @var array forum_data_sql Array with data we updated - * @var bool is_new_forum Did we create a forum or update one - * If you want to overwrite this value, - * ensure to set forum_data_sql[forum_id] - * @var array errors Array of errors, should be strings and not - * language key. - * @since 3.1.0-a1 - */ - $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; - } - - /** - * Move forum - */ - function move_forum($from_id, $to_id) - { - global $db, $user, $phpbb_dispatcher; - - $errors = array(); - - // Check if we want to move to a parent with link type - if ($to_id > 0) - { - $to_data = $this->get_forum_info($to_id); - - if ($to_data['forum_type'] == FORUM_LINK) - { - $errors[] = $user->lang['PARENT_IS_LINK_FORUM']; - } - } - - /** - * Event when we move all children of one forum to another - * - * This event may be triggered, when a forum is deleted - * - * @event core.acp_manage_forums_move_children - * @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 - */ - $vars = array('from_id', 'to_id', 'errors'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_children', compact($vars))); - - // Return if there were errors - if (!empty($errors)) - { - return $errors; - } - - $db->sql_transaction('begin'); - - $moved_forums = get_forum_branch($from_id, 'children', 'descending'); - $from_data = $moved_forums[0]; - $diff = count($moved_forums) * 2; - - $moved_ids = array(); - for ($i = 0, $size = count($moved_forums); $i < $size; ++$i) - { - $moved_ids[] = $moved_forums[$i]['forum_id']; - } - - // Resync parents - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET right_id = right_id - $diff, forum_parents = '' - WHERE left_id < " . $from_data['right_id'] . " - AND right_id > " . $from_data['right_id']; - $db->sql_query($sql); - - // Resync righthand side of tree - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET left_id = left_id - $diff, right_id = right_id - $diff, forum_parents = '' - WHERE left_id > " . $from_data['right_id']; - $db->sql_query($sql); - - if ($to_id > 0) - { - // Retrieve $to_data again, it may have been changed... - $to_data = $this->get_forum_info($to_id); - - // Resync new parents - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET right_id = right_id + $diff, forum_parents = '' - WHERE " . $to_data['right_id'] . ' BETWEEN left_id AND right_id - AND ' . $db->sql_in_set('forum_id', $moved_ids, true); - $db->sql_query($sql); - - // Resync the righthand side of the tree - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET left_id = left_id + $diff, right_id = right_id + $diff, forum_parents = '' - WHERE left_id > " . $to_data['right_id'] . ' - AND ' . $db->sql_in_set('forum_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 ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $moved_ids, true); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $diff = '+ ' . ($row['right_id'] - $from_data['left_id'] + 1); - } - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET left_id = left_id $diff, right_id = right_id $diff, forum_parents = '' - WHERE " . $db->sql_in_set('forum_id', $moved_ids); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - return $errors; - } - - /** - * Move forum content from one to another forum - */ - function move_forum_content($from_id, $to_id, $sync = true) - { - global $db, $phpbb_dispatcher; - - $errors = array(); - - /** - * Event when we move content from one forum to another - * - * @event core.acp_manage_forums_move_content - * @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, - * The content will not be moved. - * @since 3.1.0-a1 - */ - $vars = array('from_id', 'to_id', 'sync', 'errors'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_content', compact($vars))); - - // Return if there were errors - if (!empty($errors)) - { - return $errors; - } - - $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 - SET forum_id = $to_id - WHERE forum_id = $from_id"; - $db->sql_query($sql); - } - unset($table_ary); - - $table_ary = array(FORUMS_ACCESS_TABLE, FORUMS_TRACK_TABLE, FORUMS_WATCH_TABLE, MODERATOR_CACHE_TABLE); - - foreach ($table_ary as $table) - { - $sql = "DELETE FROM $table - WHERE forum_id = $from_id"; - $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 - sync('topic_moved'); - sync('forum', 'forum_id', $to_id, false, true); - } - - return array(); - } - - /** - * Remove complete forum - */ - function delete_forum($forum_id, $action_posts = 'delete', $action_subforums = 'delete', $posts_to_id = 0, $subforums_to_id = 0) - { - global $db, $user, $cache, $phpbb_log; - - $forum_data = $this->get_forum_info($forum_id); - - $errors = array(); - $log_action_posts = $log_action_forums = $posts_to_name = $subforums_to_name = ''; - $forum_ids = array($forum_id); - - if ($action_posts == 'delete') - { - $log_action_posts = 'POSTS'; - $errors = array_merge($errors, $this->delete_forum_content($forum_id)); - } - else if ($action_posts == 'move') - { - if (!$posts_to_id) - { - $errors[] = $user->lang['NO_DESTINATION_FORUM']; - } - else - { - $log_action_posts = 'MOVE_POSTS'; - - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $posts_to_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $errors[] = $user->lang['NO_FORUM']; - } - else - { - $posts_to_name = $row['forum_name']; - $errors = array_merge($errors, $this->move_forum_content($forum_id, $posts_to_id)); - } - } - } - - if (count($errors)) - { - return $errors; - } - - if ($action_subforums == 'delete') - { - $log_action_forums = 'FORUMS'; - $rows = get_forum_branch($forum_id, 'children', 'descending', false); - - foreach ($rows as $row) - { - $forum_ids[] = $row['forum_id']; - $errors = array_merge($errors, $this->delete_forum_content($row['forum_id'])); - } - - if (count($errors)) - { - return $errors; - } - - $diff = count($forum_ids) * 2; - - $sql = 'DELETE FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - } - else if ($action_subforums == 'move') - { - if (!$subforums_to_id) - { - $errors[] = $user->lang['NO_DESTINATION_FORUM']; - } - else - { - $log_action_forums = 'MOVE_FORUMS'; - - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $subforums_to_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $errors[] = $user->lang['NO_FORUM']; - } - else - { - $subforums_to_name = $row['forum_name']; - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . " - WHERE parent_id = $forum_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $this->move_forum($row['forum_id'], $subforums_to_id); - } - $db->sql_freeresult($result); - - // Grab new forum data for correct tree updating later - $forum_data = $this->get_forum_info($forum_id); - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET parent_id = $subforums_to_id - WHERE parent_id = $forum_id"; - $db->sql_query($sql); - - $diff = 2; - $sql = 'DELETE FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - } - } - - if (count($errors)) - { - return $errors; - } - } - else - { - $diff = 2; - $sql = 'DELETE FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - } - - // Resync tree - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET right_id = right_id - $diff - WHERE left_id < {$forum_data['right_id']} AND right_id > {$forum_data['right_id']}"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET left_id = left_id - $diff, right_id = right_id - $diff - WHERE left_id > {$forum_data['right_id']}"; - $db->sql_query($sql); - - // Delete forum ids from extension groups table - $sql = 'SELECT group_id, allowed_forums - FROM ' . EXTENSION_GROUPS_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$row['allowed_forums']) - { - continue; - } - - $allowed_forums = unserialize(trim($row['allowed_forums'])); - $allowed_forums = array_diff($allowed_forums, $forum_ids); - - $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . " - SET allowed_forums = '" . ((count($allowed_forums)) ? serialize($allowed_forums) : '') . "' - WHERE group_id = {$row['group_id']}"; - $db->sql_query($sql); - } - $db->sql_freeresult($result); - - $cache->destroy('_extensions'); - - $log_action = implode('_', array($log_action_posts, $log_action_forums)); - - switch ($log_action) - { - case 'MOVE_POSTS_MOVE_FORUMS': - $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': - $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': - $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': - $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_': - $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': - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS_FORUMS', false, array($forum_data['forum_name'])); - break; - - case '_FORUMS': - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_FORUMS', false, array($forum_data['forum_name'])); - break; - - case 'POSTS_': - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS', false, array($forum_data['forum_name'])); - break; - - default: - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_FORUM', false, array($forum_data['forum_name'])); - break; - } - - return $errors; - } - - /** - * Delete forum content - */ - function delete_forum_content($forum_id) - { - global $db, $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher; - - include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - - $db->sql_transaction('begin'); - - // Select then delete all attachments - $sql = 'SELECT a.topic_id - FROM ' . POSTS_TABLE . ' p, ' . ATTACHMENTS_TABLE . " a - WHERE p.forum_id = $forum_id - AND a.in_message = 0 - AND a.topic_id = p.topic_id"; - $result = $db->sql_query($sql); - - $topic_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - /** @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); - - // Before we remove anything we make sure we are able to adjust the post counts later. ;) - $sql = 'SELECT poster_id - FROM ' . POSTS_TABLE . ' - WHERE forum_id = ' . $forum_id . ' - AND post_postcount = 1 - AND post_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - - $post_counts = array(); - while ($row = $db->sql_fetchrow($result)) - { - $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1; - } - $db->sql_freeresult($result); - - switch ($db->get_sql_layer()) - { - case 'mysqli': - - // Delete everything else and thank MySQL for offering multi-table deletion - $tables_ary = array( - SEARCH_WORDMATCH_TABLE => 'post_id', - REPORTS_TABLE => 'post_id', - WARNINGS_TABLE => 'post_id', - BOOKMARKS_TABLE => 'topic_id', - TOPICS_WATCH_TABLE => 'topic_id', - TOPICS_POSTED_TABLE => 'topic_id', - POLL_OPTIONS_TABLE => 'topic_id', - POLL_VOTES_TABLE => 'topic_id', - ); - - $sql = 'DELETE ' . POSTS_TABLE; - $sql_using = "\nFROM " . POSTS_TABLE; - $sql_where = "\nWHERE " . POSTS_TABLE . ".forum_id = $forum_id\n"; - - foreach ($tables_ary as $table => $field) - { - $sql .= ", $table "; - $sql_using .= ", $table "; - $sql_where .= "\nAND $table.$field = " . POSTS_TABLE . ".$field"; - } - - $db->sql_query($sql . $sql_using . $sql_where); - - break; - - default: - - // Delete everything else and curse your DB for not offering multi-table deletion - $tables_ary = array( - 'post_id' => array( - SEARCH_WORDMATCH_TABLE, - REPORTS_TABLE, - WARNINGS_TABLE, - ), - - 'topic_id' => array( - BOOKMARKS_TABLE, - TOPICS_WATCH_TABLE, - TOPICS_POSTED_TABLE, - POLL_OPTIONS_TABLE, - POLL_VOTES_TABLE, - ) - ); - - // Amount of rows we select and delete in one iteration. - $batch_size = 500; - - foreach ($tables_ary as $field => $tables) - { - $start = 0; - - do - { - $sql = "SELECT $field - FROM " . POSTS_TABLE . ' - WHERE forum_id = ' . $forum_id; - $result = $db->sql_query_limit($sql, $batch_size, $start); - - $ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $ids[] = $row[$field]; - } - $db->sql_freeresult($result); - - if (count($ids)) - { - $start += count($ids); - - foreach ($tables as $table) - { - $db->sql_query("DELETE FROM $table WHERE " . $db->sql_in_set($field, $ids)); - } - } - } - while (count($ids) == $batch_size); - } - unset($ids); - - break; - } - - $table_ary = array(FORUMS_ACCESS_TABLE, FORUMS_TRACK_TABLE, FORUMS_WATCH_TABLE, LOG_TABLE, MODERATOR_CACHE_TABLE, POSTS_TABLE, TOPICS_TABLE, TOPICS_TRACK_TABLE); - - /** - * Perform additional actions before forum content deletion - * - * @event core.delete_forum_content_before_query - * @var array table_ary Array of tables from which all rows will be deleted that hold the forum_id - * @var int forum_id the forum id - * @var array topic_ids Array of the topic ids from the forum to be deleted - * @var array post_counts Array of counts of posts in the forum, by poster_id - * @since 3.1.6-RC1 - */ - $vars = array( - 'table_ary', - 'forum_id', - 'topic_ids', - 'post_counts', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_forum_content_before_query', compact($vars))); - - foreach ($table_ary as $table) - { - $db->sql_query("DELETE FROM $table WHERE forum_id = $forum_id"); - } - - // Set forum ids to 0 - $table_ary = array(DRAFTS_TABLE); - - foreach ($table_ary as $table) - { - $db->sql_query("UPDATE $table SET forum_id = 0 WHERE forum_id = $forum_id"); - } - - // Adjust users post counts - if (count($post_counts)) - { - foreach ($post_counts as $poster_id => $substract) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = 0 - WHERE user_id = ' . $poster_id . ' - AND user_posts < ' . $substract; - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts - ' . $substract . ' - WHERE user_id = ' . $poster_id . ' - AND user_posts >= ' . $substract; - $db->sql_query($sql); - } - } - - $db->sql_transaction('commit'); - - // Make sure the overall post/topic count is correct... - $sql = 'SELECT COUNT(post_id) AS stat - FROM ' . POSTS_TABLE . ' - WHERE post_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_posts', (int) $row['stat'], false); - - $sql = 'SELECT COUNT(topic_id) AS stat - FROM ' . TOPICS_TABLE . ' - WHERE topic_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_topics', (int) $row['stat'], false); - - $sql = 'SELECT COUNT(attach_id) as stat - FROM ' . ATTACHMENTS_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_files', (int) $row['stat'], false); - - $sql = 'SELECT SUM(filesize) as stat - FROM ' . ATTACHMENTS_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('upload_dir_size', (float) $row['stat'], false); - - return array(); - } - - /** - * Move forum position by $steps up/down - */ - function move_forum_by($forum_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 forum_id, forum_name, left_id, right_id - FROM ' . FORUMS_TABLE . " - WHERE parent_id = {$forum_row['parent_id']} - AND " . (($action == 'move_up') ? "right_id < {$forum_row['right_id']} ORDER BY right_id DESC" : "left_id > {$forum_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 (!count($target)) - { - // The forum 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 = $target['left_id']; - $right_id = $forum_row['right_id']; - - $diff_up = $forum_row['left_id'] - $target['left_id']; - $diff_down = $forum_row['right_id'] + 1 - $forum_row['left_id']; - - $move_up_left = $forum_row['left_id']; - $move_up_right = $forum_row['right_id']; - } - else - { - $left_id = $forum_row['left_id']; - $right_id = $target['right_id']; - - $diff_up = $forum_row['right_id'] + 1 - $forum_row['left_id']; - $diff_down = $target['right_id'] - $forum_row['right_id']; - - $move_up_left = $forum_row['right_id'] + 1; - $move_up_right = $target['right_id']; - } - - // Now do the dirty job - $sql = 'UPDATE ' . FORUMS_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, - forum_parents = '' - WHERE - left_id BETWEEN {$left_id} AND {$right_id} - AND right_id BETWEEN {$left_id} AND {$right_id}"; - $db->sql_query($sql); - - return $target['forum_name']; - } - - /** - * Display progress bar for syncinc forums - */ - function display_progress_bar($start, $total) - { - global $template, $user; - - adm_page_header($user->lang['SYNC_IN_PROGRESS']); - - $template->set_filenames(array( - 'body' => 'progress_bar.html') - ); - - $template->assign_vars(array( - 'L_PROGRESS' => $user->lang['SYNC_IN_PROGRESS'], - 'L_PROGRESS_EXPLAIN' => ($start && $total) ? sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $start, $total) : $user->lang['SYNC_IN_PROGRESS']) - ); - - adm_page_footer(); - } - - /** - * Display copy permission page - * Not used at the moment - we will have a look at it for 3.0.7 - */ - function copy_permission_page($forum_data) - { - global $phpEx, $phpbb_admin_path, $template, $user; - - $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_data['forum_id']; - $action = append_sid($this->u_action . "&parent_id={$this->parent_id}&f={$forum_data['forum_id']}&action=copy_perm"); - - $l_acl = sprintf($user->lang['COPY_TO_ACL'], '', ''); - - $this->tpl_name = 'acp_forums_copy_perm'; - - $template->assign_vars(array( - 'U_ACL' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url), - 'L_ACL_LINK' => $l_acl, - 'L_BACK_LINK' => adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), - 'S_COPY_ACTION' => $action, - 'S_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $forum_data['forum_id'], false, false, false), - )); - } - -} diff --git a/install/update/new/includes/acp/acp_help_phpbb.php b/install/update/new/includes/acp/acp_help_phpbb.php deleted file mode 100644 index 798cff5..0000000 --- a/install/update/new/includes/acp/acp_help_phpbb.php +++ /dev/null @@ -1,146 +0,0 @@ - -* @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/statistics/send"; - - $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)) - { - $decoded_response = json_decode(htmlspecialchars_decode($response), true); - - if ($decoded_response && isset($decoded_response['status']) && $decoded_response['status'] == 'ok') - { - 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), E_USER_WARNING); - } - } - - 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, - 'S_STATS' => $collector->get_data_raw(), - 'S_STATS_DATA' => json_encode($collector->get_data_raw()), - '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/install/update/new/includes/acp/acp_main.php b/install/update/new/includes/acp/acp_main.php deleted file mode 100644 index 27fac54..0000000 --- a/install/update/new/includes/acp/acp_main.php +++ /dev/null @@ -1,707 +0,0 @@ - -* @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_main -{ - var $u_action; - - function main($id, $mode) - { - 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')) - { - $this->tpl_name = 'acp_main'; - $this->page_title = 'ACP_MAIN'; - - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user->data['user_perm_from']; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $perm_from = get_username_string('full', $user_row['user_id'], $user_row['username'], $user_row['user_colour']); - - $template->assign_vars(array( - 'S_RESTORE_PERMISSIONS' => true, - 'U_RESTORE_PERMISSIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm'), - 'PERM_FROM' => $perm_from, - 'L_PERMISSIONS_TRANSFERRED_EXPLAIN' => sprintf($user->lang['PERMISSIONS_TRANSFERRED_EXPLAIN'], $perm_from, append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm')), - )); - - return; - } - - $action = $request->variable('action', ''); - - if ($action) - { - if ($action === 'admlogout') - { - $user->unset_admin(); - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - if (!confirm_box(true)) - { - switch ($action) - { - case 'online': - $confirm = true; - $confirm_lang = 'RESET_ONLINE_CONFIRM'; - break; - case 'stats': - $confirm = true; - $confirm_lang = 'RESYNC_STATS_CONFIRM'; - break; - case 'user': - $confirm = true; - $confirm_lang = 'RESYNC_POSTCOUNTS_CONFIRM'; - break; - case 'date': - $confirm = true; - $confirm_lang = 'RESET_DATE_CONFIRM'; - break; - case 'db_track': - $confirm = true; - $confirm_lang = 'RESYNC_POST_MARKING_CONFIRM'; - break; - case 'purge_cache': - $confirm = true; - $confirm_lang = 'PURGE_CACHE_CONFIRM'; - break; - case 'purge_sessions': - $confirm = true; - $confirm_lang = 'PURGE_SESSIONS_CONFIRM'; - break; - - default: - $confirm = true; - $confirm_lang = 'CONFIRM_OPERATION'; - } - - if ($confirm) - { - confirm_box(false, $user->lang[$confirm_lang], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - ))); - } - } - else - { - switch ($action) - { - - 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); - } - - $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()) - { - trigger_error('RESET_ONLINE_SUCCESS'); - } - break; - - 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); - } - - $sql = 'SELECT COUNT(post_id) AS stat - FROM ' . POSTS_TABLE . ' - WHERE post_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $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); - $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); - $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); - $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); - $config->set('upload_dir_size', (float) $db->sql_fetchfield('stat'), false); - $db->sql_freeresult($result); - - if (!function_exists('update_last_username')) - { - include($phpbb_root_path . "includes/functions_user.$phpEx"); - } - update_last_username(); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_STATS'); - - if ($request->is_ajax()) - { - trigger_error('RESYNC_STATS_SUCCESS'); - } - break; - - 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); - } - - // Resync post counts - $start = $max_post_id = 0; - - // Find the maximum post ID, we can only stop the cycle when we've reached it - $sql = 'SELECT MAX(forum_last_post_id) as max_post_id - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - $max_post_id = (int) $db->sql_fetchfield('max_post_id'); - $db->sql_freeresult($result); - - // No maximum post id? :o - if (!$max_post_id) - { - $sql = 'SELECT MAX(post_id) as max_post_id - FROM ' . POSTS_TABLE; - $result = $db->sql_query($sql); - $max_post_id = (int) $db->sql_fetchfield('max_post_id'); - $db->sql_freeresult($result); - } - - // Still no maximum post id? Then we are finished - if (!$max_post_id) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POSTCOUNTS'); - break; - } - - $step = ($config['num_posts']) ? (max((int) ($config['num_posts'] / 5), 20000)) : 20000; - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_posts = 0'); - - while ($start < $max_post_id) - { - $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id - FROM ' . POSTS_TABLE . ' - WHERE post_id BETWEEN ' . ($start + 1) . ' AND ' . ($start + $step) . ' - AND post_postcount = 1 AND post_visibility = ' . ITEM_APPROVED . ' - GROUP BY poster_id'; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - do - { - $sql = 'UPDATE ' . USERS_TABLE . " SET user_posts = user_posts + {$row['num_posts']} WHERE user_id = {$row['poster_id']}"; - $db->sql_query($sql); - } - while ($row = $db->sql_fetchrow($result)); - } - $db->sql_freeresult($result); - - $start += $step; - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POSTCOUNTS'); - - if ($request->is_ajax()) - { - trigger_error('RESYNC_POSTCOUNTS_SUCCESS'); - } - break; - - 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); - } - - $config->set('board_startdate', time() - 1); - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESET_DATE'); - - if ($request->is_ajax()) - { - trigger_error('RESET_DATE_SUCCESS'); - } - break; - - case 'db_track': - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); - break; - - default: - $db->sql_query('TRUNCATE TABLE ' . TOPICS_POSTED_TABLE); - break; - } - - // This can get really nasty... therefore we only do the last six months - $get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60); - - // Select forum ids, do not include categories - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type <> ' . FORUM_CAT; - $result = $db->sql_query($sql); - - $forum_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $db->sql_freeresult($result); - - // Any global announcements? ;) - $forum_ids[] = 0; - - // Now go through the forums and get us some topics... - foreach ($forum_ids as $forum_id) - { - $sql = 'SELECT p.poster_id, p.topic_id - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t - WHERE t.forum_id = ' . $forum_id . ' - AND t.topic_moved_id = 0 - AND t.topic_last_post_time > ' . $get_from_time . ' - AND t.topic_id = p.topic_id - AND p.poster_id <> ' . ANONYMOUS . ' - GROUP BY p.poster_id, p.topic_id'; - $result = $db->sql_query($sql); - - $posted = array(); - while ($row = $db->sql_fetchrow($result)) - { - $posted[$row['poster_id']][] = $row['topic_id']; - } - $db->sql_freeresult($result); - - $sql_ary = array(); - foreach ($posted as $user_id => $topic_row) - { - foreach ($topic_row as $topic_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user_id, - 'topic_id' => (int) $topic_id, - 'topic_posted' => 1, - ); - } - } - unset($posted); - - if (count($sql_ary)) - { - $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); - } - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POST_MARKING'); - - if ($request->is_ajax()) - { - trigger_error('RESYNC_POST_MARKING_SUCCESS'); - } - break; - - case 'purge_cache': - $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); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PURGE_CACHE'); - - if ($request->is_ajax()) - { - trigger_error('PURGE_CACHE_SUCCESS'); - } - break; - - 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); - } - - $tables = array(CONFIRM_TABLE, SESSIONS_TABLE); - - foreach ($tables as $table) - { - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $db->sql_query("DELETE FROM $table"); - break; - - default: - $db->sql_query("TRUNCATE TABLE $table"); - break; - } - } - - // let's restore the admin session - $reinsert_ary = array( - 'session_id' => (string) $user->session_id, - 'session_page' => (string) substr($user->page['page'], 0, 199), - 'session_forum_id' => $user->page['forum'], - 'session_user_id' => (int) $user->data['user_id'], - 'session_start' => (int) $user->data['session_start'], - 'session_last_visit' => (int) $user->data['session_last_visit'], - 'session_time' => (int) $user->time_now, - 'session_browser' => (string) trim(substr($user->browser, 0, 149)), - 'session_forwarded_for' => (string) $user->forwarded_for, - 'session_ip' => (string) $user->ip, - 'session_autologin' => (int) $user->data['session_autologin'], - 'session_admin' => 1, - 'session_viewonline' => (int) $user->data['session_viewonline'], - ); - - $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $reinsert_ary); - $db->sql_query($sql); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PURGE_SESSIONS'); - - if ($request->is_ajax()) - { - trigger_error('PURGE_SESSIONS_SUCCESS'); - } - break; - } - } - } - - // Version check - $user->add_lang('install'); - - if ($auth->acl_get('a_server') && version_compare(PHP_VERSION, '5.4.0', '<')) - { - $template->assign_vars(array( - 'S_PHP_VERSION_OLD' => true, - 'L_PHP_VERSION_OLD' => sprintf($user->lang['PHP_VERSION_OLD'], PHP_VERSION, '5.4.0', '', ''), - )); - } - - if ($auth->acl_get('a_board')) - { - $version_helper = $phpbb_container->get('version_helper'); - try - { - $recheck = $request->variable('versioncheck_force', false); - $updates_available = $version_helper->get_update_on_branch($recheck); - $upgrades_available = $version_helper->get_suggested_updates(); - if (!empty($upgrades_available)) - { - $upgrades_available = array_pop($upgrades_available); - } - - $template->assign_vars(array( - 'S_VERSION_UP_TO_DATE' => empty($updates_available), - 'S_VERSION_UPGRADEABLE' => !empty($upgrades_available), - 'UPGRADE_INSTRUCTIONS' => !empty($upgrades_available) ? $user->lang('UPGRADE_INSTRUCTIONS', $upgrades_available['current'], $upgrades_available['announcement']) : false, - )); - } - 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() !== 'VERSIONCHECK_FAIL') ? $message : '', - )); - } - } - else - { - // We set this template var to true, to not display an outdated version notice. - $template->assign_var('S_VERSION_UP_TO_DATE', true); - } - - // Incomplete update? - if (phpbb_version_compare($config['version'], PHPBB_VERSION, '<')) - { - $template->assign_var('S_UPDATE_INCOMPLETE', true); - } - - /** - * Notice admin - * - * @event core.acp_main_notice - * @since 3.1.0-RC3 - */ - $phpbb_dispatcher->dispatch('core.acp_main_notice'); - - // Get forum statistics - $total_posts = $config['num_posts']; - $total_topics = $config['num_topics']; - $total_users = $config['num_users']; - $total_files = $config['num_files']; - - $start_date = $user->format_date($config['board_startdate']); - - $boarddays = (time() - $config['board_startdate']) / 86400; - - $posts_per_day = sprintf('%.2f', $total_posts / $boarddays); - $topics_per_day = sprintf('%.2f', $total_topics / $boarddays); - $users_per_day = sprintf('%.2f', $total_users / $boarddays); - $files_per_day = sprintf('%.2f', $total_files / $boarddays); - - $upload_dir_size = get_formatted_filesize($config['upload_dir_size']); - - $avatar_dir_size = 0; - - if ($avatar_dir = @opendir($phpbb_root_path . $config['avatar_path'])) - { - while (($file = readdir($avatar_dir)) !== false) - { - if ($file[0] != '.' && $file != 'CVS' && strpos($file, 'index.') === false) - { - $avatar_dir_size += filesize($phpbb_root_path . $config['avatar_path'] . '/' . $file); - } - } - closedir($avatar_dir); - - $avatar_dir_size = get_formatted_filesize($avatar_dir_size); - } - else - { - // Couldn't open Avatar dir. - $avatar_dir_size = $user->lang['NOT_AVAILABLE']; - } - - if ($posts_per_day > $total_posts) - { - $posts_per_day = $total_posts; - } - - if ($topics_per_day > $total_topics) - { - $topics_per_day = $total_topics; - } - - if ($users_per_day > $total_users) - { - $users_per_day = $total_users; - } - - if ($files_per_day > $total_files) - { - $files_per_day = $total_files; - } - - if ($config['allow_attachments'] || $config['allow_pm_attach']) - { - $sql = 'SELECT COUNT(attach_id) AS total_orphan - FROM ' . ATTACHMENTS_TABLE . ' - WHERE is_orphan = 1 - AND filetime < ' . (time() - 3*60*60); - $result = $db->sql_query($sql); - $total_orphan = (int) $db->sql_fetchfield('total_orphan'); - $db->sql_freeresult($result); - } - else - { - $total_orphan = false; - } - - $dbsize = get_database_size(); - - $template->assign_vars(array( - 'TOTAL_POSTS' => $total_posts, - 'POSTS_PER_DAY' => $posts_per_day, - 'TOTAL_TOPICS' => $total_topics, - 'TOPICS_PER_DAY' => $topics_per_day, - 'TOTAL_USERS' => $total_users, - 'USERS_PER_DAY' => $users_per_day, - 'TOTAL_FILES' => $total_files, - 'FILES_PER_DAY' => $files_per_day, - 'START_DATE' => $start_date, - 'AVATAR_DIR_SIZE' => $avatar_dir_size, - 'DBSIZE' => $dbsize, - 'UPLOAD_DIR_SIZE' => $upload_dir_size, - 'TOTAL_ORPHAN' => $total_orphan, - '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, - 'U_ADMIN_LOG' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=logs&mode=admin'), - 'U_INACTIVE_USERS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=inactive&mode=list'), - 'U_VERSIONCHECK' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=update&mode=version_check'), - 'U_VERSIONCHECK_FORCE' => append_sid("{$phpbb_admin_path}index.$phpEx", '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, - 'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, - ) - ); - - $log_data = array(); - $log_count = false; - - if ($auth->acl_get('a_viewlogs')) - { - view_log('admin', $log_data, $log_count, 5); - - foreach ($log_data as $row) - { - $template->assign_block_vars('log', array( - 'USERNAME' => $row['username_full'], - 'IP' => $row['ip'], - 'DATE' => $user->format_date($row['time']), - 'ACTION' => $row['action']) - ); - } - } - - if ($auth->acl_get('a_user')) - { - $user->add_lang('memberlist'); - - $inactive = array(); - $inactive_count = 0; - - view_inactive_users($inactive, $inactive_count, 10); - - foreach ($inactive as $row) - { - $template->assign_block_vars('inactive', array( - 'INACTIVE_DATE' => $user->format_date($row['user_inactive_time']), - 'REMINDED_DATE' => $user->format_date($row['user_reminded_time']), - 'JOINED' => $user->format_date($row['user_regdate']), - 'LAST_VISIT' => (!$row['user_lastvisit']) ? ' - ' : $user->format_date($row['user_lastvisit']), - - 'REASON' => $row['inactive_reason'], - 'USER_ID' => $row['user_id'], - 'POSTS' => ($row['user_posts']) ? $row['user_posts'] : 0, - 'REMINDED' => $row['user_reminded'], - - 'REMINDED_EXPLAIN' => $user->lang('USER_LAST_REMINDED', (int) $row['user_reminded'], $user->format_date($row['user_reminded_time'])), - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview')), - 'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), - 'USER_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), - - 'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&mode=overview&u={$row['user_id']}"), - 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id={$row['user_id']}&sr=posts") : '', - )); - } - - $option_ary = array('activate' => 'ACTIVATE', 'delete' => 'DELETE'); - if ($config['email_enable']) - { - $option_ary += array('remind' => 'REMIND'); - } - - $template->assign_vars(array( - 'S_INACTIVE_USERS' => true, - 'S_INACTIVE_OPTIONS' => build_select($option_ary)) - ); - } - - // Warn if install is still present - if (!defined('IN_INSTALL') && !$phpbb_container->getParameter('allow_install_dir') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) - { - $template->assign_var('S_REMOVE_INSTALL', true); - } - - // Warn if no search index is created - if ($config['num_posts'] && class_exists($config['search_type'])) - { - $error = false; - $search_type = $config['search_type']; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if (!$search->index_created()) - { - $template->assign_vars(array( - 'S_SEARCH_INDEX_MISSING' => true, - 'L_NO_SEARCH_INDEX' => $user->lang('NO_SEARCH_INDEX', $search->get_name(), '', ''), - )); - } - } - - 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)); - } - - if (extension_loaded('mbstring')) - { - $template->assign_vars(array( - 'S_MBSTRING_LOADED' => true, - 'S_MBSTRING_FUNC_OVERLOAD_FAIL' => (intval(@ini_get('mbstring.func_overload')) & (MB_OVERLOAD_MAIL | MB_OVERLOAD_STRING)), - 'S_MBSTRING_ENCODING_TRANSLATION_FAIL' => (@ini_get('mbstring.encoding_translation') != 0), - 'S_MBSTRING_HTTP_INPUT_FAIL' => !in_array(@ini_get('mbstring.http_input'), array('pass', '')), - 'S_MBSTRING_HTTP_OUTPUT_FAIL' => !in_array(@ini_get('mbstring.http_output'), array('pass', '')), - )); - } - - // Fill dbms version if not yet filled - if (empty($config['dbms_version'])) - { - $config->set('dbms_version', $db->sql_server_info(true)); - } - - $this->tpl_name = 'acp_main'; - $this->page_title = 'ACP_MAIN'; - } -} diff --git a/install/update/new/includes/acp/acp_permissions.php b/install/update/new/includes/acp/acp_permissions.php deleted file mode 100644 index 59bf366..0000000 --- a/install/update/new/includes/acp/acp_permissions.php +++ /dev/null @@ -1,1346 +0,0 @@ - -* @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_permissions -{ - var $u_action; - var $permission_dropdown; - - /** - * @var $phpbb_permissions \phpbb\permissions - */ - protected $permissions; - - function main($id, $mode) - { - global $db, $user, $auth, $template, $phpbb_container, $request; - global $config, $phpbb_root_path, $phpEx; - - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - if (!class_exists('auth_admin')) - { - include($phpbb_root_path . 'includes/acp/auth.' . $phpEx); - } - - $this->permissions = $phpbb_container->get('acl.permissions'); - - $auth_admin = new auth_admin(); - - $user->add_lang('acp/permissions'); - add_permission_language(); - - $this->tpl_name = 'acp_permissions'; - - // Trace has other vars - if ($mode == 'trace') - { - $user_id = $request->variable('u', 0); - $forum_id = $request->variable('f', 0); - $permission = $request->variable('auth', ''); - - $this->tpl_name = 'permission_trace'; - - if ($user_id && isset($auth_admin->acl_options['id'][$permission]) && $auth->acl_get('a_viewauth')) - { - $this->page_title = sprintf($user->lang['TRACE_PERMISSION'], $this->permissions->get_permission_lang($permission)); - $this->permission_trace($user_id, $forum_id, $permission); - return; - } - trigger_error('NO_MODE', E_USER_ERROR); - } - - // Copy forum permissions - if ($mode == 'setting_forum_copy') - { - $this->tpl_name = 'permission_forum_copy'; - - if ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')) - { - $this->page_title = 'ACP_FORUM_PERMISSIONS_COPY'; - $this->copy_forum_permissions(); - return; - } - - trigger_error('NO_MODE', E_USER_ERROR); - } - - // Set some vars - $action = $request->variable('action', array('' => 0)); - $action = key($action); - $action = (isset($_POST['psubmit'])) ? 'apply_permissions' : $action; - - $all_forums = $request->variable('all_forums', 0); - $subforum_id = $request->variable('subforum_id', 0); - $forum_id = $request->variable('forum_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->variable('group_id', array(0)); - $select_all_groups = $request->variable('select_all_groups', 0); - - $form_name = 'acp_permissions'; - add_form_key($form_name); - - // If select all groups is set, we pre-build the group id array (this option is used for other screens to link to the permission settings screen) - if ($select_all_groups) - { - // Add default groups to selection - $sql_and = (!$config['coppa_enable']) ? " AND group_name <> 'REGISTERED_COPPA'" : ''; - - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . ' - WHERE group_type = ' . GROUP_SPECIAL . " - $sql_and"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $group_id[] = $row['group_id']; - } - $db->sql_freeresult($result); - } - - // Map usernames to ids and vice versa - if ($usernames) - { - $username = explode("\n", $usernames); - } - unset($usernames); - - if (count($username) && !count($user_id)) - { - user_get_id_name($user_id, $username); - - if (!count($user_id)) - { - trigger_error($user->lang['SELECTED_USER_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - unset($username); - - // Build forum ids (of all forums are checked or subforum listing used) - if ($all_forums) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id'; - $result = $db->sql_query($sql); - - $forum_id = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_id[] = (int) $row['forum_id']; - } - $db->sql_freeresult($result); - } - else if ($subforum_id) - { - $forum_id = array(); - foreach (get_forum_branch($subforum_id, 'children') as $row) - { - $forum_id[] = (int) $row['forum_id']; - } - } - - // Define some common variables for every mode - $permission_scope = (strpos($mode, '_global') !== false) ? 'global' : 'local'; - - // Showing introductionary page? - if ($mode == 'intro') - { - $this->page_title = 'ACP_PERMISSIONS'; - - $template->assign_vars(array( - 'S_INTRO' => true) - ); - - return; - } - - switch ($mode) - { - case 'setting_user_global': - case 'setting_group_global': - $this->permission_dropdown = array('u_', 'm_', 'a_'); - $permission_victim = ($mode == 'setting_user_global') ? array('user') : array('group'); - $this->page_title = ($mode == 'setting_user_global') ? 'ACP_USERS_PERMISSIONS' : 'ACP_GROUPS_PERMISSIONS'; - break; - - case 'setting_user_local': - case 'setting_group_local': - $this->permission_dropdown = array('f_', 'm_'); - $permission_victim = ($mode == 'setting_user_local') ? array('user', 'forums') : array('group', 'forums'); - $this->page_title = ($mode == 'setting_user_local') ? 'ACP_USERS_FORUM_PERMISSIONS' : 'ACP_GROUPS_FORUM_PERMISSIONS'; - break; - - case 'setting_admin_global': - case 'setting_mod_global': - $this->permission_dropdown = (strpos($mode, '_admin_') !== false) ? array('a_') : array('m_'); - $permission_victim = array('usergroup'); - $this->page_title = ($mode == 'setting_admin_global') ? 'ACP_ADMINISTRATORS' : 'ACP_GLOBAL_MODERATORS'; - break; - - case 'setting_mod_local': - case 'setting_forum_local': - $this->permission_dropdown = ($mode == 'setting_mod_local') ? array('m_') : array('f_'); - $permission_victim = array('forums', 'usergroup'); - $this->page_title = ($mode == 'setting_mod_local') ? 'ACP_FORUM_MODERATORS' : 'ACP_FORUM_PERMISSIONS'; - break; - - case 'view_admin_global': - case 'view_user_global': - case 'view_mod_global': - $this->permission_dropdown = ($mode == 'view_admin_global') ? array('a_') : (($mode == 'view_user_global') ? array('u_') : array('m_')); - $permission_victim = array('usergroup_view'); - $this->page_title = ($mode == 'view_admin_global') ? 'ACP_VIEW_ADMIN_PERMISSIONS' : (($mode == 'view_user_global') ? 'ACP_VIEW_USER_PERMISSIONS' : 'ACP_VIEW_GLOBAL_MOD_PERMISSIONS'); - break; - - case 'view_mod_local': - case 'view_forum_local': - $this->permission_dropdown = ($mode == 'view_mod_local') ? array('m_') : array('f_'); - $permission_victim = array('forums', 'usergroup_view'); - $this->page_title = ($mode == 'view_mod_local') ? 'ACP_VIEW_FORUM_MOD_PERMISSIONS' : 'ACP_VIEW_FORUM_PERMISSIONS'; - break; - - default: - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - - $template->assign_vars(array( - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN']) - ); - - // Get permission type - $permission_type = $request->variable('type', $this->permission_dropdown[0]); - - if (!in_array($permission_type, $this->permission_dropdown)) - { - trigger_error($user->lang['WRONG_PERMISSION_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Handle actions - if (strpos($mode, 'setting_') === 0 && $action) - { - switch ($action) - { - case 'delete': - if (confirm_box(true)) - { - // All users/groups selected? - $all_users = (isset($_POST['all_users'])) ? true : false; - $all_groups = (isset($_POST['all_groups'])) ? true : false; - - if ($all_users || $all_groups) - { - $items = $this->retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type); - - if ($all_users && count($items['user_ids'])) - { - $user_id = $items['user_ids']; - } - else if ($all_groups && count($items['group_ids'])) - { - $group_id = $items['group_ids']; - } - } - - if (count($user_id) || count($group_id)) - { - $this->remove_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id, $forum_id); - } - else - { - trigger_error($user->lang['NO_USER_GROUP_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - else - { - if (isset($_POST['cancel'])) - { - $u_redirect = $this->u_action . '&type=' . $permission_type; - foreach ($forum_id as $fid) - { - $u_redirect .= '&forum_id[]=' . $fid; - } - redirect($u_redirect); - } - - $s_hidden_fields = array( - 'i' => $id, - 'mode' => $mode, - 'action' => array($action => 1), - 'user_id' => $user_id, - 'group_id' => $group_id, - 'forum_id' => $forum_id, - 'type' => $permission_type, - ); - if (isset($_POST['all_users'])) - { - $s_hidden_fields['all_users'] = 1; - } - if (isset($_POST['all_groups'])) - { - $s_hidden_fields['all_groups'] = 1; - } - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); - } - break; - - 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)) - { - trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING); - } - - $this->set_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id); - break; - - 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)) - { - trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING); - } - - $this->set_all_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id); - break; - } - } - - // Go through the screens/options needed and present them in correct order - foreach ($permission_victim as $victim) - { - switch ($victim) - { - case 'forum_dropdown': - - if (count($forum_id)) - { - $this->check_existence('forum', $forum_id); - continue 2; - } - - $template->assign_vars(array( - 'S_SELECT_FORUM' => true, - 'S_FORUM_OPTIONS' => make_forum_select(false, false, true, false, false)) - ); - - break; - - case 'forums': - - if (count($forum_id)) - { - $this->check_existence('forum', $forum_id); - continue 2; - } - - $forum_list = make_forum_select(false, false, true, false, false, false, true); - - // Build forum options - $s_forum_options = ''; - foreach ($forum_list as $f_id => $f_row) - { - $s_forum_options .= ''; - } - - // Build subforum options - $s_subforum_options = $this->build_subforum_options($forum_list); - - $template->assign_vars(array( - 'S_SELECT_FORUM' => true, - 'S_FORUM_OPTIONS' => $s_forum_options, - 'S_SUBFORUM_OPTIONS' => $s_subforum_options, - 'S_FORUM_ALL' => true, - 'S_FORUM_MULTIPLE' => true) - ); - - break; - - case 'user': - - if (count($user_id)) - { - $this->check_existence('user', $user_id); - continue 2; - } - - $template->assign_vars(array( - 'S_SELECT_USER' => true, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_victim&field=username&select_single=true'), - )); - - break; - - case 'group': - - if (count($group_id)) - { - $this->check_existence('group', $group_id); - continue 2; - } - - $template->assign_vars(array( - 'S_SELECT_GROUP' => true, - 'S_GROUP_OPTIONS' => group_select_options(false, false, false), // Show all groups - )); - - break; - - case 'usergroup': - case 'usergroup_view': - - $all_users = (isset($_POST['all_users'])) ? true : false; - $all_groups = (isset($_POST['all_groups'])) ? true : false; - - if ((count($user_id) && !$all_users) || (count($group_id) && !$all_groups)) - { - if (count($user_id)) - { - $this->check_existence('user', $user_id); - } - - if (count($group_id)) - { - $this->check_existence('group', $group_id); - } - - continue 2; - } - - // 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 && count($items['user_ids'])) - { - $user_id = $items['user_ids']; - continue 2; - } - - if ($all_groups && count($items['group_ids'])) - { - $group_id = $items['group_ids']; - continue 2; - } - - $template->assign_vars(array( - 'S_SELECT_USERGROUP' => ($victim == 'usergroup') ? true : false, - 'S_SELECT_USERGROUP_VIEW' => ($victim == 'usergroup_view') ? true : false, - 'S_DEFINED_USER_OPTIONS' => $items['user_ids_options'], - 'S_DEFINED_GROUP_OPTIONS' => $items['group_ids_options'], - 'S_ADD_GROUP_OPTIONS' => group_select_options(false, $items['group_ids'], false), // Show all groups - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=add_user&field=username&select_single=true'), - )); - - break; - } - - // The S_ALLOW_SELECT parameter below is a measure to lower memory usage. - // If there are more than 5 forums selected the admin is not able to select all users/groups too. - // We need to see if the number of forums can be increased or need to be decreased. - - // Setting permissions screen - $s_hidden_fields = build_hidden_fields(array( - 'user_id' => $user_id, - 'group_id' => $group_id, - 'forum_id' => $forum_id, - 'type' => $permission_type, - )); - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - 'ANONYMOUS_USER_ID' => ANONYMOUS, - - 'S_SELECT_VICTIM' => 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 (count($forum_id)) - { - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id) . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql); - - $forum_names = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_names[] = $row['forum_name']; - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_FORUM_NAMES' => (count($forum_names)) ? true : false, - 'FORUM_NAMES' => implode($user->lang['COMMA_SEPARATOR'], $forum_names)) - ); - } - - return; - } - - // Setting permissions screen - $s_hidden_fields = build_hidden_fields(array( - 'user_id' => $user_id, - 'group_id' => $group_id, - 'forum_id' => $forum_id, - 'type' => $permission_type, - )); - - // Do not allow forum_ids being set and no other setting defined (will bog down the server too much) - 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' => (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, - 'S_HIDDEN_FIELDS' => $s_hidden_fields) - ); - - if (strpos($mode, 'setting_') === 0) - { - $template->assign_vars(array( - 'S_SETTING_PERMISSIONS' => true) - ); - - $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 - { - $template->assign_vars(array( - 'S_VIEWING_PERMISSIONS' => true) - ); - - $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)); - } - } - - /** - * Build +subforum options - */ - function build_subforum_options($forum_list) - { - global $user; - - $s_options = ''; - - $forum_list = array_merge($forum_list); - - foreach ($forum_list as $key => $row) - { - if ($row['disabled']) - { - continue; - } - - $s_options .= ''; - } - - return $s_options; - } - - /** - * Build dropdown field for changing permission types - */ - function build_permission_dropdown($options, $default_option, $permission_scope) - { - global $auth; - - $s_dropdown_options = ''; - foreach ($options as $setting) - { - if (!$auth->acl_get('a_' . str_replace('_', '', $setting) . 'auth')) - { - continue; - } - - $selected = ($setting == $default_option) ? ' selected="selected"' : ''; - $l_setting = $this->permissions->get_type_lang($setting, $permission_scope); - $s_dropdown_options .= ''; - } - - return $s_dropdown_options; - } - - /** - * Check if selected items exist. Remove not found ids and if empty return error. - */ - function check_existence($mode, &$ids) - { - global $db, $user; - - switch ($mode) - { - case 'user': - $table = USERS_TABLE; - $sql_id = 'user_id'; - break; - - case 'group': - $table = GROUPS_TABLE; - $sql_id = 'group_id'; - break; - - case 'forum': - $table = FORUMS_TABLE; - $sql_id = 'forum_id'; - break; - } - - if (count($ids)) - { - $sql = "SELECT $sql_id - FROM $table - WHERE " . $db->sql_in_set($sql_id, $ids); - $result = $db->sql_query($sql); - - $ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $ids[] = (int) $row[$sql_id]; - } - $db->sql_freeresult($result); - } - - if (!count($ids)) - { - trigger_error($user->lang['SELECTED_' . strtoupper($mode) . '_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - /** - * Apply permissions - */ - function set_permissions($mode, $permission_type, $auth_admin, &$user_id, &$group_id) - { - global $db, $cache, $user, $auth; - global $request; - - $psubmit = $request->variable('psubmit', array(0 => array(0 => 0))); - - // User or group to be set? - $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); - } - - // We loop through the auth settings defined in our submit - $ug_id = key($psubmit); - $forum_id = key($psubmit[$ug_id]); - - $settings = $request->variable('setting', array(0 => array(0 => array('' => 0))), false, \phpbb\request\request_interface::POST); - if (empty($settings) || empty($settings[$ug_id]) || empty($settings[$ug_id][$forum_id])) - { - trigger_error('WRONG_PERMISSION_SETTING_FORMAT', E_USER_WARNING); - } - - $auth_settings = $settings[$ug_id][$forum_id]; - - // Do we have a role we want to set? - $roles = $request->variable('role', array(0 => array(0 => 0)), false, \phpbb\request\request_interface::POST); - $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->variable('inherit', array(0 => array(0))); - - $ug_id = array($ug_id); - $forum_id = array($forum_id); - - if (count($inherit)) - { - foreach ($inherit as $_ug_id => $forum_id_ary) - { - // Inherit users/groups? - if (!in_array($_ug_id, $ug_id)) - { - $ug_id[] = $_ug_id; - } - - // Inherit forums? - $forum_id = array_merge($forum_id, array_keys($forum_id_ary)); - } - } - - $forum_id = array_unique($forum_id); - - // If the auth settings differ from the assigned role, then do not set a role... - if ($assigned_role) - { - if (!$this->check_assigned_role($assigned_role, $auth_settings)) - { - $assigned_role = 0; - } - } - - // Update the permission set... - $auth_admin->acl_set($ug_type, $forum_id, $ug_id, $auth_settings, $assigned_role); - - // Do we need to recache the moderator lists? - if ($permission_type == 'm_') - { - phpbb_cache_moderators($db, $cache, $auth); - } - - // Remove users who are now moderators or admins from everyones foes list - if ($permission_type == 'm_' || $permission_type == 'a_') - { - phpbb_update_foes($db, $auth, $group_id, $user_id); - } - - $this->log_action($mode, 'add', $permission_type, $ug_type, $ug_id, $forum_id); - - meta_refresh(5, $this->u_action); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); - } - - /** - * Apply all permissions - */ - 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 = (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_settings = $request->variable('setting', array(0 => array(0 => array('' => 0))), false, \phpbb\request\request_interface::POST); - $auth_roles = $request->variable('role', array(0 => array(0 => 0)), false, \phpbb\request\request_interface::POST); - $ug_ids = $forum_ids = array(); - - // We need to go through the auth settings - foreach ($auth_settings as $ug_id => $forum_auth_row) - { - $ug_id = (int) $ug_id; - $ug_ids[] = $ug_id; - - foreach ($forum_auth_row as $forum_id => $auth_options) - { - $forum_id = (int) $forum_id; - $forum_ids[] = $forum_id; - - // Check role... - $assigned_role = (isset($auth_roles[$ug_id][$forum_id])) ? (int) $auth_roles[$ug_id][$forum_id] : 0; - - // If the auth settings differ from the assigned role, then do not set a role... - if ($assigned_role) - { - if (!$this->check_assigned_role($assigned_role, $auth_options)) - { - $assigned_role = 0; - } - } - - // Update the permission set... - $auth_admin->acl_set($ug_type, $forum_id, $ug_id, $auth_options, $assigned_role, false); - } - } - - $auth_admin->acl_clear_prefetch(); - - // Do we need to recache the moderator lists? - if ($permission_type == 'm_') - { - phpbb_cache_moderators($db, $cache, $auth); - } - - // Remove users who are now moderators or admins from everyones foes list - if ($permission_type == 'm_' || $permission_type == 'a_') - { - phpbb_update_foes($db, $auth, $group_id, $user_id); - } - - $this->log_action($mode, 'add', $permission_type, $ug_type, $ug_ids, $forum_ids); - - if ($mode == 'setting_forum_local' || $mode == 'setting_mod_local') - { - meta_refresh(5, $this->u_action . '&forum_id[]=' . implode('&forum_id[]=', $forum_ids)); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action . '&forum_id[]=' . implode('&forum_id[]=', $forum_ids))); - } - else - { - meta_refresh(5, $this->u_action); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); - } - } - - /** - * Compare auth settings with auth settings from role - * returns false if they differ, true if they are equal - */ - function check_assigned_role($role_id, &$auth_settings) - { - global $db; - - $sql = 'SELECT o.auth_option, r.auth_setting - FROM ' . ACL_OPTIONS_TABLE . ' o, ' . ACL_ROLES_DATA_TABLE . ' r - WHERE o.auth_option_id = r.auth_option_id - AND r.role_id = ' . $role_id; - $result = $db->sql_query($sql); - - $test_auth_settings = array(); - while ($row = $db->sql_fetchrow($result)) - { - $test_auth_settings[$row['auth_option']] = $row['auth_setting']; - } - $db->sql_freeresult($result); - - // We need to add any ACL_NO setting from auth_settings to compare correctly - foreach ($auth_settings as $option => $setting) - { - if ($setting == ACL_NO) - { - $test_auth_settings[$option] = $setting; - } - } - - if (count(array_diff_assoc($auth_settings, $test_auth_settings))) - { - return false; - } - - return true; - } - - /** - * Remove permissions - */ - 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 = (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), (count($forum_id) ? $forum_id : false), $permission_type); - - // Do we need to recache the moderator lists? - if ($permission_type == 'm_') - { - phpbb_cache_moderators($db, $cache, $auth); - } - - $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') - { - meta_refresh(5, $this->u_action . '&forum_id[]=' . implode('&forum_id[]=', $forum_id)); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action . '&forum_id[]=' . implode('&forum_id[]=', $forum_id))); - } - else - { - meta_refresh(5, $this->u_action); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); - } - } - - /** - * Log permission changes - */ - function log_action($mode, $action, $permission_type, $ug_type, $ug_id, $forum_id) - { - global $db, $user, $phpbb_log, $phpbb_container; - - if (!is_array($ug_id)) - { - $ug_id = array($ug_id); - } - - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - // Logging ... first grab user or groupnames ... - $sql = ($ug_type == 'group') ? 'SELECT group_name as name, group_type FROM ' . GROUPS_TABLE . ' WHERE ' : 'SELECT username as name FROM ' . USERS_TABLE . ' WHERE '; - $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)) - { - $group_name = $group_helper->get_name($row['name']); - $l_ug_list .= (($l_ug_list != '') ? ', ' : '') . ((isset($row['group_type']) && $row['group_type'] == GROUP_SPECIAL) ? '' . $group_name . '' : $group_name); - } - $db->sql_freeresult($result); - - $mode = str_replace('setting_', '', $mode); - - if ($forum_id[0] == 0) - { - $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 - { - // Grab the forum details if non-zero forum_id - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id); - $result = $db->sql_query($sql); - - $l_forum_list = ''; - while ($row = $db->sql_fetchrow($result)) - { - $l_forum_list .= (($l_forum_list != '') ? ', ' : '') . $row['forum_name']; - } - $db->sql_freeresult($result); - - $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)); - } - } - - /** - * Display a complete trace tree for the selected permission to determine where settings are set/unset - */ - function permission_trace($user_id, $forum_id, $permission) - { - global $db, $template, $user, $auth, $request, $phpbb_container; - - if ($user_id != $user->data['user_id']) - { - $userdata = $auth->obtain_user_data($user_id); - } - else - { - $userdata = $user->data; - } - - if (!$userdata) - { - 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) - { - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql, 3600); - $forum_name = $db->sql_fetchfield('forum_name'); - $db->sql_freeresult($result); - } - - $back = $request->variable('back', 0); - - $template->assign_vars(array( - 'PERMISSION' => $this->permissions->get_permission_lang($permission), - 'PERMISSION_USERNAME' => $userdata['username'], - 'FORUM_NAME' => $forum_name, - - 'S_GLOBAL_TRACE' => ($forum_id) ? false : true, - - 'U_BACK' => ($back) ? build_url(array('f', 'back')) . "&f=$back" : '') - ); - - $template->assign_block_vars('trace', array( - 'WHO' => $user->lang['DEFAULT'], - 'INFORMATION' => $user->lang['TRACE_DEFAULT'], - - 'S_SETTING_NO' => true, - 'S_TOTAL_NO' => true) - ); - - $sql = 'SELECT DISTINCT g.group_name, g.group_id, g.group_type - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug ON (ug.group_id = g.group_id) - WHERE ug.user_id = ' . $user_id . ' - AND ug.user_pending = 0 - AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) - ORDER BY g.group_type DESC, g.group_id DESC'; - $result = $db->sql_query($sql); - - $groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $groups[$row['group_id']] = array( - 'auth_setting' => ACL_NO, - 'group_name' => $group_helper->get_name($row['group_name']), - ); - } - $db->sql_freeresult($result); - - $total = ACL_NO; - $add_key = (($forum_id) ? '_LOCAL' : ''); - - if (count($groups)) - { - // Get group auth settings - $hold_ary = $auth->acl_group_raw_data(array_keys($groups), $permission, $forum_id); - - foreach ($hold_ary as $group_id => $forum_ary) - { - $groups[$group_id]['auth_setting'] = $hold_ary[$group_id][$forum_id][$permission]; - } - unset($hold_ary); - - foreach ($groups as $id => $row) - { - switch ($row['auth_setting']) - { - case ACL_NO: - $information = $user->lang['TRACE_GROUP_NO' . $add_key]; - break; - - case ACL_YES: - $information = ($total == ACL_YES) ? $user->lang['TRACE_GROUP_YES_TOTAL_YES' . $add_key] : (($total == ACL_NEVER) ? $user->lang['TRACE_GROUP_YES_TOTAL_NEVER' . $add_key] : $user->lang['TRACE_GROUP_YES_TOTAL_NO' . $add_key]); - $total = ($total == ACL_NO) ? ACL_YES : $total; - break; - - case ACL_NEVER: - $information = ($total == ACL_YES) ? $user->lang['TRACE_GROUP_NEVER_TOTAL_YES' . $add_key] : (($total == ACL_NEVER) ? $user->lang['TRACE_GROUP_NEVER_TOTAL_NEVER' . $add_key] : $user->lang['TRACE_GROUP_NEVER_TOTAL_NO' . $add_key]); - $total = ACL_NEVER; - break; - } - - $template->assign_block_vars('trace', array( - 'WHO' => $row['group_name'], - 'INFORMATION' => $information, - - 'S_SETTING_NO' => ($row['auth_setting'] == ACL_NO) ? true : false, - 'S_SETTING_YES' => ($row['auth_setting'] == ACL_YES) ? true : false, - 'S_SETTING_NEVER' => ($row['auth_setting'] == ACL_NEVER) ? true : false, - 'S_TOTAL_NO' => ($total == ACL_NO) ? true : false, - 'S_TOTAL_YES' => ($total == ACL_YES) ? true : false, - 'S_TOTAL_NEVER' => ($total == ACL_NEVER) ? true : false) - ); - } - } - - // Get user specific permission... globally or for this forum - $hold_ary = $auth->acl_user_raw_data($user_id, $permission, $forum_id); - $auth_setting = (!count($hold_ary)) ? ACL_NO : $hold_ary[$user_id][$forum_id][$permission]; - - switch ($auth_setting) - { - case ACL_NO: - $information = ($total == ACL_NO) ? $user->lang['TRACE_USER_NO_TOTAL_NO' . $add_key] : $user->lang['TRACE_USER_KEPT' . $add_key]; - $total = ($total == ACL_NO) ? ACL_NEVER : $total; - break; - - case ACL_YES: - $information = ($total == ACL_YES) ? $user->lang['TRACE_USER_YES_TOTAL_YES' . $add_key] : (($total == ACL_NEVER) ? $user->lang['TRACE_USER_YES_TOTAL_NEVER' . $add_key] : $user->lang['TRACE_USER_YES_TOTAL_NO' . $add_key]); - $total = ($total == ACL_NO) ? ACL_YES : $total; - break; - - case ACL_NEVER: - $information = ($total == ACL_YES) ? $user->lang['TRACE_USER_NEVER_TOTAL_YES' . $add_key] : (($total == ACL_NEVER) ? $user->lang['TRACE_USER_NEVER_TOTAL_NEVER' . $add_key] : $user->lang['TRACE_USER_NEVER_TOTAL_NO' . $add_key]); - $total = ACL_NEVER; - break; - } - - $template->assign_block_vars('trace', array( - 'WHO' => $userdata['username'], - 'INFORMATION' => $information, - - 'S_SETTING_NO' => ($auth_setting == ACL_NO) ? true : false, - 'S_SETTING_YES' => ($auth_setting == ACL_YES) ? true : false, - 'S_SETTING_NEVER' => ($auth_setting == ACL_NEVER) ? true : false, - 'S_TOTAL_NO' => false, - 'S_TOTAL_YES' => ($total == ACL_YES) ? true : false, - 'S_TOTAL_NEVER' => ($total == ACL_NEVER) ? true : false) - ); - - if ($forum_id != 0 && isset($auth->acl_options['global'][$permission])) - { - if ($user_id != $user->data['user_id']) - { - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($userdata); - $auth_setting = $auth2->acl_get($permission); - } - else - { - $auth_setting = $auth->acl_get($permission); - } - - if ($auth_setting) - { - $information = ($total == ACL_YES) ? $user->lang['TRACE_USER_GLOBAL_YES_TOTAL_YES'] : $user->lang['TRACE_USER_GLOBAL_YES_TOTAL_NEVER']; - $total = ACL_YES; - } - else - { - $information = $user->lang['TRACE_USER_GLOBAL_NEVER_TOTAL_KEPT']; - } - - // If there is no auth information we do not need to worry the user by showing non-relevant data. - if ($auth_setting) - { - $template->assign_block_vars('trace', array( - 'WHO' => sprintf($user->lang['TRACE_GLOBAL_SETTING'], $userdata['username']), - 'INFORMATION' => sprintf($information, '", ''), - - 'S_SETTING_NO' => false, - 'S_SETTING_YES' => $auth_setting, - 'S_SETTING_NEVER' => !$auth_setting, - 'S_TOTAL_NO' => false, - 'S_TOTAL_YES' => ($total == ACL_YES) ? true : false, - 'S_TOTAL_NEVER' => ($total == ACL_NEVER) ? true : false) - ); - } - } - - // Take founder status into account, overwriting the default values - if ($userdata['user_type'] == USER_FOUNDER && strpos($permission, 'a_') === 0) - { - $template->assign_block_vars('trace', array( - 'WHO' => $userdata['username'], - 'INFORMATION' => $user->lang['TRACE_USER_FOUNDER'], - - 'S_SETTING_NO' => ($auth_setting == ACL_NO) ? true : false, - 'S_SETTING_YES' => ($auth_setting == ACL_YES) ? true : false, - 'S_SETTING_NEVER' => ($auth_setting == ACL_NEVER) ? true : false, - 'S_TOTAL_NO' => false, - 'S_TOTAL_YES' => true, - 'S_TOTAL_NEVER' => false) - ); - - $total = ACL_YES; - } - - // Total value... - $template->assign_vars(array( - 'S_RESULT_NO' => ($total == ACL_NO) ? true : false, - 'S_RESULT_YES' => ($total == ACL_YES) ? true : false, - 'S_RESULT_NEVER' => ($total == ACL_NEVER) ? true : false, - )); - } - - /** - * Handles copying permissions from one forum to others - */ - function copy_forum_permissions() - { - global $db, $auth, $cache, $template, $user, $request; - - $user->add_lang('acp/forums'); - - $submit = isset($_POST['submit']) ? true : false; - - if ($submit) - { - $src = $request->variable('src_forum_id', 0); - $dest = $request->variable('dest_forum_ids', array(0)); - - if (confirm_box(true)) - { - if (copy_forum_permissions($src, $dest)) - { - phpbb_cache_moderators($db, $cache, $auth); - - $auth->acl_clear_prefetch(); - $cache->destroy('sql', FORUMS_TABLE); - - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); - } - else - { - trigger_error($user->lang['SELECTED_FORUM_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - else - { - $s_hidden_fields = array( - 'submit' => $submit, - 'src_forum_id' => $src, - 'dest_forum_ids' => $dest, - ); - - $s_hidden_fields = build_hidden_fields($s_hidden_fields); - - confirm_box(false, $user->lang['COPY_PERMISSIONS_CONFIRM'], $s_hidden_fields); - } - } - - $template->assign_vars(array( - 'S_FORUM_OPTIONS' => make_forum_select(false, false, false, false, false), - )); - } - - /** - * Get already assigned users/groups - */ - function retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type) - { - 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' : ((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(); - - $sql = 'SELECT auth_option_id - FROM ' . ACL_OPTIONS_TABLE . ' - WHERE auth_option ' . $db->sql_like_expression($permission_type . $db->get_any_char()); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $option_ids[] = (int) $row['auth_option_id']; - } - $db->sql_freeresult($result); - - if (count($option_ids)) - { - $sql = 'SELECT DISTINCT role_id - FROM ' . ACL_ROLES_DATA_TABLE . ' - WHERE ' . $db->sql_in_set('auth_option_id', $option_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $role_ids[] = (int) $row['role_id']; - } - $db->sql_freeresult($result); - } - - 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 (count($role_ids)) - { - $sql_where = 'AND ' . $db->sql_in_set('a.auth_role_id', $role_ids); - } - else if (count($option_ids)) - { - $sql_where = 'AND ' . $db->sql_in_set('a.auth_option_id', $option_ids); - } - - // Not ideal, due to the filesort, non-use of indexes, etc. - $sql = 'SELECT DISTINCT u.user_id, u.username, u.username_clean, u.user_regdate - FROM ' . USERS_TABLE . ' u, ' . ACL_USERS_TABLE . " a - WHERE u.user_id = a.user_id - $sql_forum_id - $sql_where - ORDER BY u.username_clean, u.user_regdate ASC"; - $result = $db->sql_query($sql); - - $s_defined_user_options = ''; - $defined_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $s_defined_user_options .= ''; - $defined_user_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT DISTINCT g.group_type, g.group_name, g.group_id - FROM ' . GROUPS_TABLE . ' g, ' . ACL_GROUPS_TABLE . " a - WHERE g.group_id = a.group_id - $sql_forum_id - $sql_where - ORDER BY g.group_type DESC, g.group_name ASC"; - $result = $db->sql_query($sql); - - $s_defined_group_options = ''; - $defined_group_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $s_defined_group_options .= '' . $group_helper->get_name($row['group_name']) . ''; - $defined_group_ids[] = $row['group_id']; - } - $db->sql_freeresult($result); - - return array( - 'group_ids' => $defined_group_ids, - 'group_ids_options' => $s_defined_group_options, - 'user_ids' => $defined_user_ids, - 'user_ids_options' => $s_defined_user_options - ); - } -} diff --git a/install/update/new/includes/acp/acp_prune.php b/install/update/new/includes/acp/acp_prune.php deleted file mode 100644 index c5f7789..0000000 --- a/install/update/new/includes/acp/acp_prune.php +++ /dev/null @@ -1,588 +0,0 @@ - -* @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_prune -{ - var $u_action; - - function main($id, $mode) - { - global $user, $phpEx, $phpbb_root_path; - - $user->add_lang('acp/prune'); - - if (!function_exists('user_active_flip')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - switch ($mode) - { - case 'forums': - $this->tpl_name = 'acp_prune_forums'; - $this->page_title = 'ACP_PRUNE_FORUMS'; - $this->prune_forums($id, $mode); - break; - - case 'users': - $this->tpl_name = 'acp_prune_users'; - $this->page_title = 'ACP_PRUNE_USERS'; - $this->prune_users($id, $mode); - break; - } - } - - /** - * Prune forums - */ - function prune_forums($id, $mode) - { - global $db, $user, $auth, $template, $phpbb_log, $request, $phpbb_dispatcher; - - $all_forums = $request->variable('all_forums', 0); - $forum_id = $request->variable('f', array(0)); - $submit = (isset($_POST['submit'])) ? true : false; - - if ($all_forums) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id'; - $result = $db->sql_query($sql); - - $forum_id = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_id[] = $row['forum_id']; - } - $db->sql_freeresult($result); - } - - if ($submit) - { - if (confirm_box(true)) - { - $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->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); - $prunedate_viewed = time() - ($prune_viewed * 86400); - - $template->assign_vars(array( - 'S_PRUNED' => true) - ); - - $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 - FROM ' . FORUMS_TABLE . ' - WHERE forum_type = ' . FORUM_POST . " - $sql_forum - ORDER BY left_id ASC"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $prune_ids = array(); - $p_result['topics'] = 0; - $p_result['posts'] = 0; - $log_data = ''; - - do - { - if (!$auth->acl_get('f_list', $row['forum_id'])) - { - continue; - } - - if ($prune_all) - { - $p_result = prune($row['forum_id'], 'posted', time(), $prune_flags, false); - } - else - { - if ($prune_posted) - { - $return = prune($row['forum_id'], 'posted', $prunedate_posted, $prune_flags, false); - $p_result['topics'] += $return['topics']; - $p_result['posts'] += $return['posts']; - } - - if ($prune_viewed) - { - $return = prune($row['forum_id'], 'viewed', $prunedate_viewed, $prune_flags, false); - $p_result['topics'] += $return['topics']; - $p_result['posts'] += $return['posts']; - } - } - - $prune_ids[] = $row['forum_id']; - - $template->assign_block_vars('pruned', array( - 'FORUM_NAME' => $row['forum_name'], - 'NUM_TOPICS' => $p_result['topics'], - 'NUM_POSTS' => $p_result['posts']) - ); - - $log_data .= (($log_data != '') ? ', ' : '') . $row['forum_name']; - } - while ($row = $db->sql_fetchrow($result)); - - // Sync all pruned forums at once - sync('forum', 'forum_id', $prune_ids, true, true); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PRUNE', false, array($log_data)); - } - $db->sql_freeresult($result); - - return; - } - else - { - $hidden_fields = array( - 'i' => $id, - 'mode' => $mode, - 'submit' => 1, - 'all_forums' => $all_forums, - 'f' => $forum_id, - - '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 (!count($forum_id)) - { - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - 'S_SELECT_FORUM' => true, - 'S_FORUM_OPTIONS' => make_forum_select(false, false, false)) - ); - } - else - { - $sql = 'SELECT forum_id, forum_name - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - - if (!$row) - { - $db->sql_freeresult($result); - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $forum_list = $s_hidden_fields = ''; - do - { - $forum_list .= (($forum_list != '') ? ', ' : '') . '' . $row['forum_name'] . ''; - $s_hidden_fields .= ''; - } - while ($row = $db->sql_fetchrow($result)); - - $db->sql_freeresult($result); - - $l_selected_forums = (count($forum_id) == 1) ? 'SELECTED_FORUM' : 'SELECTED_FORUMS'; - - $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, - ); - - /** - * 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); - } - } - - /** - * Prune users - */ - function prune_users($id, $mode) - { - 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'); - - $prune = (isset($_POST['prune'])) ? true : false; - - if ($prune) - { - $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 (count($user_ids)) - { - if ($action == 'deactivate') - { - user_active_flip('deactivate', $user_ids); - $l_log = 'LOG_PRUNE_USER_DEAC'; - } - else if ($action == 'delete') - { - if ($deleteposts) - { - user_delete('remove', $user_ids); - - $l_log = 'LOG_PRUNE_USER_DEL_DEL'; - } - else - { - user_delete('retain', $user_ids, true); - - $l_log = 'LOG_PRUNE_USER_DEL_ANON'; - } - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $l_log, false, array(implode(', ', $usernames))); - $msg = $user->lang['USER_' . strtoupper($action) . '_SUCCESS']; - } - else - { - $msg = $user->lang['USER_PRUNE_FAILURE']; - } - - trigger_error($msg . adm_back_link($this->u_action)); - } - else - { - // We list the users which will be pruned... - $user_ids = $usernames = array(); - $this->get_prune_users($user_ids, $usernames); - - if (!count($user_ids)) - { - trigger_error($user->lang['USER_PRUNE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Assign to template - foreach ($user_ids as $user_id) - { - $template->assign_block_vars('users', array( - 'USERNAME' => $usernames[$user_id], - 'USER_ID' => $user_id, - 'U_PROFILE' => get_username_string('profile', $user_id, $usernames[$user_id]), - 'U_USER_ADMIN' => ($auth->acl_get('a_user')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview&u=' . $user_id, true, $user->session_id) : '', - )); - } - - $template->assign_vars(array( - 'S_DEACTIVATE' => ($action == 'deactivate') ? true : false, - 'S_DELETE' => ($action == 'delete') ? true : false, - )); - - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'prune' => 1, - - 'deleteposts' => $request->variable('deleteposts', 0), - 'action' => $request->variable('action', ''), - )), 'confirm_body_prune.html'); - } - } - - $find_count = array('lt' => $user->lang['LESS_THAN'], 'eq' => $user->lang['EQUAL_TO'], 'gt' => $user->lang['MORE_THAN']); - $s_find_count = ''; - - foreach ($find_count as $key => $value) - { - $selected = ($key == 'eq') ? ' selected="selected"' : ''; - $s_find_count .= ''; - } - - $find_time = array('lt' => $user->lang['BEFORE'], 'gt' => $user->lang['AFTER']); - $s_find_active_time = ''; - foreach ($find_time as $key => $value) - { - $s_find_active_time .= ''; - } - - $sql = 'SELECT group_id, group_name - FROM ' . GROUPS_TABLE . ' - WHERE group_type <> ' . GROUP_SPECIAL . ' - ORDER BY group_name ASC'; - $result = $db->sql_query($sql); - - $s_group_list = ''; - while ($row = $db->sql_fetchrow($result)) - { - $s_group_list .= ''; - } - $db->sql_freeresult($result); - - if ($s_group_list) - { - // Only prepend the "All groups" option if there are groups, - // otherwise we don't want to display this option at all. - $s_group_list = '' . $s_group_list; - } - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - 'S_ACTIVE_OPTIONS' => $s_find_active_time, - 'S_GROUP_LIST' => $s_group_list, - 'S_COUNT_OPTIONS' => $s_find_count, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=acp_prune&field=users'), - )); - } - - /** - * Get user_ids/usernames from those being pruned - */ - function get_prune_users(&$user_ids, &$usernames) - { - global $user, $db, $request; - - $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) - { - $users = explode("\n", $users_by_name); - $where_sql = ' AND ' . $db->sql_in_set('username_clean', array_map('utf8_clean_string', $users)); - } - else if (!empty($users_by_id)) - { - $user_ids = $users_by_id; - user_get_id_name($user_ids, $usernames); - - $where_sql = ' AND ' . $db->sql_in_set('user_id', $user_ids); - } - else - { - $username = $request->variable('username', '', true); - $email = $request->variable('email', ''); - - $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); - - $active = ($active) ? explode('-', $active) : array(); - $joined_before = ($joined_before) ? explode('-', $joined_before) : array(); - $joined_after = ($joined_after) ? explode('-', $joined_after) : array(); - - // calculate the conditions required by the join time criteria - $joined_sql = ''; - if (!empty($joined_before) && !empty($joined_after)) - { - // if the two entered dates are equal, we need to adjust - // so that our time range is a full day instead of 1 second - if ($joined_after == $joined_before) - { - $joined_after[2] += 1; - } - - $joined_sql = ' AND user_regdate BETWEEN ' . gmmktime(0, 0, 0, (int) $joined_after[1], (int) $joined_after[2], (int) $joined_after[0]) . - ' AND ' . gmmktime(0, 0, 0, (int) $joined_before[1], (int) $joined_before[2], (int) $joined_before[0]); - } - else if (empty($joined_before) && !empty($joined_after)) - { - $joined_sql = ' AND user_regdate > ' . gmmktime(0, 0, 0, (int) $joined_after[1], (int) $joined_after[2], (int) $joined_after[0]); - } - else if (empty($joined_after) && !empty($joined_before)) - { - $joined_sql = ' AND user_regdate < ' . gmmktime(0, 0, 0, (int) $joined_before[1], (int) $joined_before[2], (int) $joined_before[0]); - } - // implicit else when both arrays are empty do nothing - - 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' => '='); - - $where_sql = ''; - $where_sql .= ($username) ? ' AND username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($username))) : ''; - $where_sql .= ($email) ? ' AND user_email ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $email)) . ' ' : ''; - $where_sql .= $joined_sql; - $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 (count($active) && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0) - { - $where_sql .= ' AND user_lastvisit = 0'; - } - 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 (count($active)) - { - $where_sql .= ' AND (user_lastvisit > 0 AND user_lastvisit < ' . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]) . ')'; - } - } - - // If no search criteria were provided, go no further. - if (!$where_sql && !$group_id && $posts_on_queue === false) - { - return; - } - - // Get bot ids - $sql = 'SELECT user_id - FROM ' . BOTS_TABLE; - $result = $db->sql_query($sql); - - $bot_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $bot_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - // Protect the admin, do not prune if no options are given... - if ($where_sql) - { - // Do not prune founder members - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE user_id <> ' . ANONYMOUS . ' - AND user_type <> ' . USER_FOUNDER . " - $where_sql"; - $result = $db->sql_query($sql); - - $user_ids = $usernames = array(); - - while ($row = $db->sql_fetchrow($result)) - { - // Do not prune bots and the user currently pruning. - if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) - { - $user_ids[] = $row['user_id']; - $usernames[$row['user_id']] = $row['username']; - } - } - $db->sql_freeresult($result); - } - - if ($group_id) - { - $sql = 'SELECT u.user_id, u.username - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u - WHERE ug.group_id = ' . (int) $group_id . ' - AND ug.user_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); - - // we're performing an intersection operation, so all the relevant users - // come from this most recent query (which was limited to the results of the - // previous query) - $user_ids = $usernames = array(); - while ($row = $db->sql_fetchrow($result)) - { - // Do not prune bots and the user currently pruning. - if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) - { - $user_ids[] = $row['user_id']; - $usernames[$row['user_id']] = $row['username']; - } - } - $db->sql_freeresult($result); - } - - if ($posts_on_queue !== false) - { - $sql = 'SELECT u.user_id, u.username, COUNT(p.post_id) AS queue_posts - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE u.user_id <> ' . ANONYMOUS . ' - AND u.user_type <> ' . USER_FOUNDER . ' - AND ' . $db->sql_in_set('p.post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)) . ' - AND u.user_id = p.poster_id - ' . (!empty($user_ids) ? ' AND ' . $db->sql_in_set('p.poster_id', $user_ids) : '') . ' - GROUP BY p.poster_id - HAVING queue_posts ' . $key_match[$queue_select] . ' ' . $posts_on_queue; - $result = $db->sql_query($sql); - - // same intersection logic as the above group ID portion - $user_ids = $usernames = array(); - while ($row = $db->sql_fetchrow($result)) - { - // Do not prune bots and the user currently pruning. - if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) - { - $user_ids[] = $row['user_id']; - $usernames[$row['user_id']] = $row['username']; - } - } - $db->sql_freeresult($result); - } - } -} diff --git a/install/update/new/includes/acp/acp_reasons.php b/install/update/new/includes/acp/acp_reasons.php deleted file mode 100644 index f3f82bd..0000000 --- a/install/update/new/includes/acp/acp_reasons.php +++ /dev/null @@ -1,392 +0,0 @@ - -* @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_reasons -{ - var $u_action; - - function main($id, $mode) - { - global $db, $user, $template; - global $request, $phpbb_log; - - $user->add_lang(array('mcp', 'acp/posting')); - - // Set up general vars - $action = $request->variable('action', ''); - $submit = (isset($_POST['submit'])) ? true : false; - $reason_id = $request->variable('id', 0); - - $this->tpl_name = 'acp_reasons'; - $this->page_title = 'ACP_REASONS'; - - $form_name = 'acp_reason'; - add_form_key('acp_reason'); - - $error = array(); - - switch ($action) - { - case 'add': - case 'edit': - - $reason_row = array( - 'reason_title' => $request->variable('reason_title', '', true), - 'reason_description' => $request->variable('reason_description', '', true), - ); - - if ($submit) - { - if (!check_form_key($form_name)) - { - $error[] = $user->lang['FORM_INVALID']; - } - // Reason specified? - if (!$reason_row['reason_title'] || !$reason_row['reason_description']) - { - $error[] = $user->lang['NO_REASON_INFO']; - } - - $check_double = ($action == 'add') ? true : false; - - if ($action == 'edit') - { - $sql = 'SELECT reason_title - FROM ' . REPORTS_REASONS_TABLE . " - WHERE reason_id = $reason_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (strtolower($row['reason_title']) == 'other' || strtolower($reason_row['reason_title']) == 'other') - { - $reason_row['reason_title'] = 'other'; - } - - if ($row['reason_title'] != $reason_row['reason_title']) - { - $check_double = true; - } - } - - // Check for same reason if adding it... - if ($check_double) - { - $sql = 'SELECT reason_id - FROM ' . REPORTS_REASONS_TABLE . " - WHERE reason_title = '" . $db->sql_escape($reason_row['reason_title']) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row || ($action == 'add' && strtolower($reason_row['reason_title']) == 'other')) - { - $error[] = $user->lang['REASON_ALREADY_EXIST']; - } - } - - if (!count($error)) - { - // New reason? - if ($action == 'add') - { - // Get new order... - $sql = 'SELECT MAX(reason_order) as max_reason_order - FROM ' . REPORTS_REASONS_TABLE; - $result = $db->sql_query($sql); - $max_order = (int) $db->sql_fetchfield('max_reason_order'); - $db->sql_freeresult($result); - - $sql_ary = array( - 'reason_title' => (string) $reason_row['reason_title'], - 'reason_description' => (string) $reason_row['reason_description'], - 'reason_order' => $max_order + 1 - ); - - $db->sql_query('INSERT INTO ' . REPORTS_REASONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $log = 'ADDED'; - } - else if ($reason_id) - { - $sql_ary = array( - 'reason_title' => (string) $reason_row['reason_title'], - 'reason_description' => (string) $reason_row['reason_description'], - ); - - $db->sql_query('UPDATE ' . REPORTS_REASONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE reason_id = ' . $reason_id); - - $log = 'UPDATED'; - } - - $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)); - } - } - else if ($reason_id) - { - $sql = 'SELECT * - FROM ' . REPORTS_REASONS_TABLE . ' - WHERE reason_id = ' . $reason_id; - $result = $db->sql_query($sql); - $reason_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$reason_row) - { - trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - $l_title = ($action == 'edit') ? 'EDIT' : 'ADD'; - - $translated = false; - - // 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($reason_row['reason_title'])]) && isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason_row['reason_title'])])) - { - $translated = true; - } - - $template->assign_vars(array( - 'L_TITLE' => $user->lang['REASON_' . $l_title], - 'U_ACTION' => $this->u_action . "&id=$reason_id&action=$action", - 'U_BACK' => $this->u_action, - 'ERROR_MSG' => (count($error)) ? implode('
', $error) : '', - - 'REASON_TITLE' => $reason_row['reason_title'], - 'REASON_DESCRIPTION' => $reason_row['reason_description'], - - 'TRANSLATED_TITLE' => ($translated) ? $user->lang['report_reasons']['TITLE'][strtoupper($reason_row['reason_title'])] : '', - 'TRANSLATED_DESCRIPTION'=> ($translated) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason_row['reason_title'])] : '', - - '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' => (count($error)) ? true : false, - ) - ); - - return; - break; - - case 'delete': - - $sql = 'SELECT * - FROM ' . REPORTS_REASONS_TABLE . ' - WHERE reason_id = ' . $reason_id; - $result = $db->sql_query($sql); - $reason_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$reason_row) - { - trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (strtolower($reason_row['reason_title']) == 'other') - { - trigger_error($user->lang['NO_REMOVE_DEFAULT_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Let the deletion be confirmed... - if (confirm_box(true)) - { - $sql = 'SELECT reason_id - FROM ' . REPORTS_REASONS_TABLE . " - WHERE LOWER(reason_title) = 'other'"; - $result = $db->sql_query($sql); - $other_reason_id = (int) $db->sql_fetchfield('reason_id'); - $db->sql_freeresult($result); - - switch ($db->get_sql_layer()) - { - // The ugly one! - case 'mysqli': - // Change the reports using this reason to 'other' - $sql = 'UPDATE ' . REPORTS_TABLE . ' - SET reason_id = ' . $other_reason_id . ", report_text = CONCAT('" . $db->sql_escape($reason_row['reason_description']) . "\n\n', report_text) - WHERE reason_id = $reason_id"; - break; - - // Standard? What's that? - case 'mssql_odbc': - case 'mssqlnative': - // Change the reports using this reason to 'other' - $sql = "DECLARE @ptrval binary(16) - - SELECT @ptrval = TEXTPTR(report_text) - FROM " . REPORTS_TABLE . " - WHERE reason_id = " . $reason_id . " - - UPDATETEXT " . REPORTS_TABLE . ".report_text @ptrval 0 0 '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' - - UPDATE " . REPORTS_TABLE . ' - SET reason_id = ' . $other_reason_id . " - WHERE reason_id = $reason_id"; - break; - - // Teh standard - case 'postgres': - case 'oracle': - case 'sqlite3': - // Change the reports using this reason to 'other' - $sql = 'UPDATE ' . REPORTS_TABLE . ' - SET reason_id = ' . $other_reason_id . ", report_text = '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' || report_text - WHERE reason_id = $reason_id"; - break; - } - $db->sql_query($sql); - - $db->sql_query('DELETE FROM ' . REPORTS_REASONS_TABLE . ' WHERE reason_id = ' . $reason_id); - - $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 - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'id' => $reason_id)) - ); - } - - break; - - case 'move_up': - case 'move_down': - - if (!check_link_hash($request->variable('hash', ''), 'acp_reasons')) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql = 'SELECT reason_order - FROM ' . REPORTS_REASONS_TABLE . " - WHERE reason_id = $reason_id"; - $result = $db->sql_query($sql); - $order = $db->sql_fetchfield('reason_order'); - $db->sql_freeresult($result); - - if ($order === false || ($order == 0 && $action == 'move_up')) - { - break; - } - $order = (int) $order; - $order_total = $order * 2 + (($action == 'move_up') ? -1 : 1); - - $sql = 'UPDATE ' . REPORTS_REASONS_TABLE . ' - SET reason_order = ' . $order_total . ' - reason_order - WHERE reason_order IN (' . $order . ', ' . (($action == 'move_up') ? $order - 1 : $order + 1) . ')'; - $db->sql_query($sql); - - if ($request->is_ajax()) - { - $json_response = new \phpbb\json_response; - $json_response->send(array( - 'success' => (bool) $db->sql_affectedrows(), - )); - } - break; - } - - // By default, check that order is valid and fix it if necessary - $sql = 'SELECT reason_id, reason_order - FROM ' . REPORTS_REASONS_TABLE . ' - ORDER BY reason_order'; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $order = 0; - do - { - ++$order; - - if ($row['reason_order'] != $order) - { - $sql = 'UPDATE ' . REPORTS_REASONS_TABLE . " - SET reason_order = $order - WHERE reason_id = {$row['reason_id']}"; - $db->sql_query($sql); - } - } - while ($row = $db->sql_fetchrow($result)); - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - ) - ); - - // Reason count - $sql = 'SELECT reason_id, COUNT(reason_id) AS reason_count - FROM ' . REPORTS_TABLE . ' - GROUP BY reason_id'; - $result = $db->sql_query($sql); - - $reason_count = array(); - while ($row = $db->sql_fetchrow($result)) - { - $reason_count[$row['reason_id']] = $row['reason_count']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT * - FROM ' . REPORTS_REASONS_TABLE . ' - ORDER BY reason_order ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $translated = false; - $other_reason = ($row['reason_title'] == 'other') ? true : false; - - // 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'])]; - - $translated = true; - } - - $template->assign_block_vars('reasons', array( - 'REASON_TITLE' => $row['reason_title'], - 'REASON_DESCRIPTION' => $row['reason_description'], - 'REASON_COUNT' => (isset($reason_count[$row['reason_id']])) ? $reason_count[$row['reason_id']] : 0, - - 'S_TRANSLATED' => $translated, - 'S_OTHER_REASON' => $other_reason, - - 'U_EDIT' => $this->u_action . '&action=edit&id=' . $row['reason_id'], - 'U_DELETE' => (!$other_reason) ? $this->u_action . '&action=delete&id=' . $row['reason_id'] : '', - 'U_MOVE_UP' => $this->u_action . '&action=move_up&id=' . $row['reason_id'] . '&hash=' . generate_link_hash('acp_reasons'), - 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&id=' . $row['reason_id'] . '&hash=' . generate_link_hash('acp_reasons')) - ); - } - $db->sql_freeresult($result); - } -} diff --git a/install/update/new/includes/acp/acp_styles.php b/install/update/new/includes/acp/acp_styles.php deleted file mode 100644 index 87c8d88..0000000 --- a/install/update/new/includes/acp/acp_styles.php +++ /dev/null @@ -1,1396 +0,0 @@ - -* @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_styles -{ - public $u_action; - - protected $u_base_action; - protected $s_hidden_fields; - protected $mode; - protected $styles_path; - protected $styles_path_absolute = 'styles'; - protected $default_style = 0; - 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; - - /** @var \phpbb\user */ - protected $user; - - /** @var \phpbb\template\template */ - protected $template; - - /** @var \phpbb\request\request_interface */ - protected $request; - - /** @var \phpbb\cache\driver\driver_interface */ - protected $cache; - - /** @var \phpbb\auth\auth */ - protected $auth; - - /** @var \phpbb\textformatter\cache_interface */ - protected $text_formatter_cache; - - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - - /** @var \phpbb\event\dispatcher_interface */ - protected $dispatcher; - - public function main($id, $mode) - { - 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; - $this->template = $template; - $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; - $this->dispatcher = $phpbb_dispatcher; - - $this->default_style = $config['default_style']; - $this->styles_path = $this->phpbb_root_path . $this->styles_path_absolute . '/'; - - $this->u_base_action = append_sid("{$phpbb_admin_path}index.{$this->php_ext}", "i={$id}"); - $this->s_hidden_fields = array( - 'mode' => $mode, - ); - - $this->user->add_lang('acp/styles'); - - $this->tpl_name = 'acp_styles'; - $this->page_title = 'ACP_CAT_STYLES'; - $this->mode = $mode; - - $action = $this->request->variable('action', ''); - $post_actions = array('install', 'activate', 'deactivate', 'uninstall'); - - foreach ($post_actions as $key) - { - if ($this->request->is_set_post($key)) - { - $action = $key; - } - } - - // The uninstall action uses confirm_box() to verify the validity of the request, - // so there is no need to check for a valid token here. - if (in_array($action, $post_actions) && $action != 'uninstall') - { - $is_valid_request = check_link_hash($request->variable('hash', ''), $action) || check_form_key('styles_management'); - - if (!$is_valid_request) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - if ($action != '') - { - $this->s_hidden_fields['action'] = $action; - } - - $this->template->assign_vars(array( - 'U_ACTION' => $this->u_base_action, - 'S_HIDDEN_FIELDS' => build_hidden_fields($this->s_hidden_fields) - ) - ); - - /** - * Run code before ACP styles action execution - * - * @event core.acp_styles_action_before - * @var int id Module ID - * @var string mode Active module - * @var string action Module that should be run - * @since 3.1.7-RC1 - */ - $vars = array('id', 'mode', 'action'); - extract($this->dispatcher->trigger_event('core.acp_styles_action_before', compact($vars))); - - // Execute actions - switch ($action) - { - case 'install': - $this->action_install(); - return; - case 'uninstall': - $this->action_uninstall(); - return; - case 'activate': - $this->action_activate(); - return; - case 'deactivate': - $this->action_deactivate(); - return; - case 'details': - $this->action_details(); - return; - default: - $this->frontend(); - } - } - - /** - * Main page - */ - protected function frontend() - { - add_form_key('styles_management'); - - // Check mode - switch ($this->mode) - { - case 'style': - $this->welcome_message('ACP_STYLES', 'ACP_STYLES_EXPLAIN'); - $this->show_installed(); - return; - case 'install': - $this->welcome_message('INSTALL_STYLES', 'INSTALL_STYLES_EXPLAIN'); - $this->show_available(); - return; - } - trigger_error($this->user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - /** - * Install style(s) - */ - protected function action_install() - { - // Get list of styles to install - $dirs = $this->request_vars('dir', '', true); - - // Get list of styles that can be installed - $styles = $this->find_available(false); - - // Install each style - $messages = array(); - $installed_names = array(); - $installed_dirs = array(); - foreach ($dirs as $dir) - { - if (in_array($dir, $this->reserved_style_names)) - { - $messages[] = $this->user->lang('STYLE_NAME_RESERVED', htmlspecialchars($dir)); - continue; - } - - $found = false; - foreach ($styles as &$style) - { - // Check if: - // 1. Directory matches directory we are looking for - // 2. Style is not installed yet - // 3. Style with same name or directory hasn't been installed already within this function - if ($style['style_path'] == $dir && empty($style['_installed']) && !in_array($style['style_path'], $installed_dirs) && !in_array($style['style_name'], $installed_names)) - { - // Install style - $style['style_active'] = 1; - $style['style_id'] = $this->install_style($style); - $style['_installed'] = true; - $found = true; - $installed_names[] = $style['style_name']; - $installed_dirs[] = $style['style_path']; - $messages[] = sprintf($this->user->lang['STYLE_INSTALLED'], htmlspecialchars($style['style_name'])); - } - } - if (!$found) - { - $messages[] = sprintf($this->user->lang['STYLE_NOT_INSTALLED'], htmlspecialchars($dir)); - } - } - - // 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)) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - $message = implode('
', $messages); - $message .= '

« ' . $this->user->lang('STYLE_INSTALLED_RETURN_INSTALLED_STYLES') . ''; - $message .= '

» ' . $this->user->lang('STYLE_INSTALLED_RETURN_UNINSTALLED_STYLES') . ''; - trigger_error($message, E_USER_NOTICE); - } - - /** - * Confirm styles removal - */ - protected function action_uninstall() - { - // 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)) - { - // Uninstall - $this->action_uninstall_confirmed($ids, $this->request->variable('confirm_delete_files', false)); - return; - } - - // Confirm box - $s_hidden = build_hidden_fields(array( - 'action' => 'uninstall', - 'ids' => $ids - )); - $this->template->assign_var('S_CONFIRM_DELETE', true); - confirm_box(false, $this->user->lang['CONFIRM_UNINSTALL_STYLES'], $s_hidden, 'acp_styles.html'); - - // Canceled - show styles list - $this->frontend(); - } - - /** - * Uninstall styles(s) - * - * @param array $ids List of style IDs - * @param bool $delete_files If true, script will attempt to remove files for selected styles - */ - protected function action_uninstall_confirmed($ids, $delete_files) - { - global $user, $phpbb_log; - - $default = $this->default_style; - $uninstalled = array(); - $messages = array(); - - // Check styles list - foreach ($ids as $id) - { - if (!$id) - { - trigger_error($this->user->lang['INVALID_STYLE_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - if ($id == $default) - { - trigger_error($this->user->lang['UNINSTALL_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); - } - $uninstalled[$id] = false; - } - - // Order by reversed style_id, so parent styles would be removed after child styles - // This way parent and child styles can be removed in same function call - $sql = 'SELECT * - FROM ' . STYLES_TABLE . ' - WHERE style_id IN (' . implode(', ', $ids) . ') - ORDER BY style_id DESC'; - $result = $this->db->sql_query($sql); - - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - // Uinstall each style - $uninstalled = array(); - foreach ($rows as $style) - { - $result = $this->uninstall_style($style, $delete_files); - - if (is_string($result)) - { - $messages[] = $result; - continue; - } - $messages[] = sprintf($this->user->lang['STYLE_UNINSTALLED'], $style['style_name']); - $uninstalled[] = $style['style_name']; - - // Attempt to delete files - if ($delete_files) - { - $messages[] = sprintf($this->user->lang[$this->delete_style_files($style['style_path']) ? 'DELETE_STYLE_FILES_SUCCESS' : 'DELETE_STYLE_FILES_FAILED'], $style['style_name']); - } - } - - if (empty($messages)) - { - // Nothing to uninstall? - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Log action - if (count($uninstalled)) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_DELETE', false, array(implode(', ', $uninstalled))); - } - - // Clear cache - $this->cache->purge(); - - // Show message - trigger_error(implode('
', $messages) . adm_back_link($this->u_action), E_USER_NOTICE); - } - - /** - * Activate styles - */ - protected function action_activate() - { - // Get list of styles to activate - $ids = $this->request_vars('id', 0, true); - - // Activate styles - $sql = 'UPDATE ' . STYLES_TABLE . ' - SET style_active = 1 - WHERE style_id IN (' . implode(', ', $ids) . ')'; - $this->db->sql_query($sql); - - // Purge cache - $this->cache->destroy('sql', STYLES_TABLE); - - // Show styles list - $this->frontend(); - } - - /** - * Deactivate styles - */ - protected function action_deactivate() - { - // Get list of styles to deactivate - $ids = $this->request_vars('id', 0, true); - - // Check for default style - foreach ($ids as $id) - { - if ($id == $this->default_style) - { - trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - // Reset default style for users who use selected styles - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_style = ' . (int) $this->default_style . ' - WHERE user_style IN (' . implode(', ', $ids) . ')'; - $this->db->sql_query($sql); - - // Deactivate styles - $sql = 'UPDATE ' . STYLES_TABLE . ' - SET style_active = 0 - WHERE style_id IN (' . implode(', ', $ids) . ')'; - $this->db->sql_query($sql); - - // Purge cache - $this->cache->destroy('sql', STYLES_TABLE); - - // Show styles list - $this->frontend(); - } - - /** - * Show style details - */ - protected function action_details() - { - global $user, $phpbb_log; - - $id = $this->request->variable('id', 0); - if (!$id) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Get all styles - $styles = $this->get_styles(); - usort($styles, array($this, 'sort_styles')); - - // Find current style - $style = false; - foreach ($styles as $row) - { - if ($row['style_id'] == $id) - { - $style = $row; - break; - } - } - - if ($style === false) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Read style configuration file - $style_cfg = $this->read_style_cfg($style['style_path']); - - // Find all available parent styles - $list = $this->find_possible_parents($styles, $id); - - // Add form key - $form_key = 'acp_styles'; - add_form_key($form_key); - - // Change data - if ($this->request->variable('update', false)) - { - if (!check_form_key($form_key)) - { - trigger_error($this->user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $update = array( - 'style_name' => trim($this->request->variable('style_name', $style['style_name'])), - 'style_parent_id' => $this->request->variable('style_parent', (int) $style['style_parent_id']), - 'style_active' => $this->request->variable('style_active', (int) $style['style_active']), - ); - $update_action = $this->u_action . '&action=details&id=' . $id; - - // Check style name - if ($update['style_name'] != $style['style_name']) - { - if (!strlen($update['style_name'])) - { - trigger_error($this->user->lang['STYLE_ERR_STYLE_NAME'] . adm_back_link($update_action), E_USER_WARNING); - } - foreach ($styles as $row) - { - if ($row['style_name'] == $update['style_name']) - { - trigger_error($this->user->lang['STYLE_ERR_NAME_EXIST'] . adm_back_link($update_action), E_USER_WARNING); - } - } - } - else - { - unset($update['style_name']); - } - - // Check parent style id - if ($update['style_parent_id'] != $style['style_parent_id']) - { - if ($update['style_parent_id'] != 0) - { - $found = false; - foreach ($list as $row) - { - if ($row['style_id'] == $update['style_parent_id']) - { - $found = true; - $update['style_parent_tree'] = ($row['style_parent_tree'] != '' ? $row['style_parent_tree'] . '/' : '') . $row['style_path']; - break; - } - } - if (!$found) - { - trigger_error($this->user->lang['STYLE_ERR_INVALID_PARENT'] . adm_back_link($update_action), E_USER_WARNING); - } - } - else - { - $update['style_parent_tree'] = ''; - } - } - else - { - unset($update['style_parent_id']); - } - - // Check style_active - if ($update['style_active'] != $style['style_active']) - { - if (!$update['style_active'] && $this->default_style == $style['style_id']) - { - trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($update_action), E_USER_WARNING); - } - } - else - { - unset($update['style_active']); - } - - // Update data - if (count($update)) - { - $sql = 'UPDATE ' . STYLES_TABLE . ' - SET ' . $this->db->sql_build_array('UPDATE', $update) . " - WHERE style_id = $id"; - $this->db->sql_query($sql); - - $style = array_merge($style, $update); - - if (isset($update['style_parent_id'])) - { - // Update styles tree - $styles = $this->get_styles(); - if ($this->update_styles_tree($styles, $style)) - { - // Something was changed in styles tree, purge all cache - $this->cache->purge(); - } - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_EDIT_DETAILS', false, array($style['style_name'])); - } - - // Update default style - $default = $this->request->variable('style_default', 0); - if ($default) - { - if (!$style['style_active']) - { - trigger_error($this->user->lang['STYLE_DEFAULT_CHANGE_INACTIVE'] . adm_back_link($update_action), E_USER_WARNING); - } - $this->config->set('default_style', $id); - $this->cache->purge(); - } - - // Show styles list - $this->frontend(); - return; - } - - // Show page title - $this->welcome_message('ACP_STYLES', null); - - // Show parent styles - foreach ($list as $row) - { - $this->template->assign_block_vars('parent_styles', array( - 'STYLE_ID' => $row['style_id'], - 'STYLE_NAME' => htmlspecialchars($row['style_name']), - 'LEVEL' => $row['level'], - 'SPACER' => str_repeat('  ', $row['level']), - ) - ); - } - - // Show style details - $this->template->assign_vars(array( - 'S_STYLE_DETAILS' => true, - 'STYLE_ID' => $style['style_id'], - 'STYLE_NAME' => htmlspecialchars($style['style_name']), - 'STYLE_PATH' => htmlspecialchars($style['style_path']), - 'STYLE_VERSION' => htmlspecialchars($style_cfg['style_version']), - 'STYLE_COPYRIGHT' => strip_tags($style['style_copyright']), - 'STYLE_PARENT' => $style['style_parent_id'], - 'S_STYLE_ACTIVE' => $style['style_active'], - 'S_STYLE_DEFAULT' => ($style['style_id'] == $this->default_style) - ) - ); - } - - /** - * List installed styles - */ - protected function show_installed() - { - // Get all installed styles - $styles = $this->get_styles(); - - if (!count($styles)) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - usort($styles, array($this, 'sort_styles')); - - // Get users - $users = $this->get_users(); - - // Add users counter to rows - foreach ($styles as &$style) - { - $style['_users'] = isset($users[$style['style_id']]) ? $users[$style['style_id']] : 0; - } - - // Set up styles list variables - // Addons should increase this number and update template variable - $this->styles_list_cols = 4; - $this->template->assign_var('STYLES_LIST_COLS', $this->styles_list_cols); - - // Show styles list - $this->show_styles_list($styles, 0, 0); - - // Show styles with invalid inherits_id - foreach ($styles as $style) - { - if (empty($style['_shown'])) - { - $style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($style['style_parent_tree'])); - $this->list_style($style, 0); - } - } - - // Add buttons - $this->template->assign_block_vars('extra_actions', array( - 'ACTION_NAME' => 'activate', - 'L_ACTION' => $this->user->lang['STYLE_ACTIVATE'], - ) - ); - - $this->template->assign_block_vars('extra_actions', array( - 'ACTION_NAME' => 'deactivate', - 'L_ACTION' => $this->user->lang['STYLE_DEACTIVATE'], - ) - ); - - if (isset($this->style_counters) && $this->style_counters['total'] > 1) - { - $this->template->assign_block_vars('extra_actions', array( - 'ACTION_NAME' => 'uninstall', - 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'], - ) - ); - } - } - - /** - * Show list of styles that can be installed - */ - protected function show_available() - { - // Get list of styles - $styles = $this->find_available(true); - - // Show styles - if (empty($styles)) - { - trigger_error($this->user->lang['NO_UNINSTALLED_STYLE'] . adm_back_link($this->u_base_action), E_USER_NOTICE); - } - - usort($styles, array($this, 'sort_styles')); - - $this->styles_list_cols = 3; - $this->template->assign_vars(array( - 'STYLES_LIST_COLS' => $this->styles_list_cols, - 'STYLES_LIST_HIDE_COUNT' => true - ) - ); - - // Show styles - foreach ($styles as &$style) - { - // Check if style has a parent style in styles list - $has_parent = false; - if ($style['_inherit_name'] != '') - { - foreach ($styles as $parent_style) - { - if ($parent_style['style_name'] == $style['_inherit_name'] && empty($parent_style['_shown'])) - { - // Show parent style first - $has_parent = true; - } - } - } - if (!$has_parent) - { - $this->list_style($style, 0); - $this->show_available_child_styles($styles, $style['style_name'], 1); - } - } - - // Show styles that do not have parent style in styles list - foreach ($styles as $style) - { - if (empty($style['_shown'])) - { - $this->list_style($style, 0); - } - } - - // Add button - if (isset($this->style_counters) && $this->style_counters['caninstall'] > 0) - { - $this->template->assign_block_vars('extra_actions', array( - 'ACTION_NAME' => 'install', - 'L_ACTION' => $this->user->lang['INSTALL_STYLES'], - ) - ); - } - } - - /** - * Find styles available for installation - * - * @param bool $all if true, function will return all installable styles. if false, function will return only styles that can be installed - * @return array List of styles - */ - protected function find_available($all) - { - // Get list of installed styles - $installed = $this->get_styles(); - - $installed_dirs = array(); - $installed_names = array(); - foreach ($installed as $style) - { - $installed_dirs[] = $style['style_path']; - $installed_names[$style['style_name']] = array( - 'path' => $style['style_path'], - 'id' => $style['style_id'], - 'parent' => $style['style_parent_id'], - 'tree' => (strlen($style['style_parent_tree']) ? $style['style_parent_tree'] . '/' : '') . $style['style_path'], - ); - } - - // Get list of directories - $dirs = $this->find_style_dirs(); - - // Find styles that can be installed - $styles = array(); - foreach ($dirs as $dir) - { - if (in_array($dir, $installed_dirs)) - { - // Style is already installed - continue; - } - $cfg = $this->read_style_cfg($dir); - if ($cfg === false) - { - // Invalid style.cfg - continue; - } - - // Style should be available for installation - $parent = $cfg['parent']; - $style = array( - 'style_id' => 0, - 'style_name' => $cfg['name'], - 'style_copyright' => $cfg['copyright'], - 'style_active' => 0, - 'style_path' => $dir, - 'bbcode_bitfield' => $cfg['template_bitfield'], - 'style_parent_id' => 0, - 'style_parent_tree' => '', - // Extra values for styles list - // All extra variable start with _ so they won't be confused with data that can be added to styles table - '_inherit_name' => $parent, - '_available' => true, - '_note' => '', - ); - - // Check style inheritance - if ($parent != '') - { - if (isset($installed_names[$parent])) - { - // Parent style is installed - $row = $installed_names[$parent]; - $style['style_parent_id'] = $row['id']; - $style['style_parent_tree'] = $row['tree']; - } - else - { - // Parent style is not installed yet - $style['_available'] = false; - $style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($parent)); - } - } - - if ($all || $style['_available']) - { - $styles[] = $style; - } - } - - return $styles; - } - - /** - * Show styles list - * - * @param array $styles styles list - * @param int $parent parent style id - * @param int $level style inheritance level - */ - protected function show_styles_list(&$styles, $parent, $level) - { - foreach ($styles as &$style) - { - if (empty($style['_shown']) && $style['style_parent_id'] == $parent) - { - $this->list_style($style, $level); - $this->show_styles_list($styles, $style['style_id'], $level + 1); - } - } - } - - /** - * Show available styles tree - * - * @param array $styles Styles list, passed as reference - * @param string $name Name of parent style - * @param int $level Styles tree level - */ - protected function show_available_child_styles(&$styles, $name, $level) - { - foreach ($styles as &$style) - { - if (empty($style['_shown']) && $style['_inherit_name'] == $name) - { - $this->list_style($style, $level); - $this->show_available_child_styles($styles, $style['style_name'], $level + 1); - } - } - } - - /** - * Update styles tree - * - * @param array $styles Styles list, passed as reference - * @param array|false $style Current style, false if root - * @return bool True if something was updated, false if not - */ - protected function update_styles_tree(&$styles, $style = false) - { - $parent_id = ($style === false) ? 0 : $style['style_id']; - $parent_tree = ($style === false) ? '' : ($style['style_parent_tree'] == '' ? '' : $style['style_parent_tree']) . $style['style_path']; - $update = false; - $updated = false; - foreach ($styles as &$row) - { - if ($row['style_parent_id'] == $parent_id) - { - if ($row['style_parent_tree'] != $parent_tree) - { - $row['style_parent_tree'] = $parent_tree; - $update = true; - } - $updated |= $this->update_styles_tree($styles, $row); - } - } - if ($update) - { - $sql = 'UPDATE ' . STYLES_TABLE . " - SET style_parent_tree = '" . $this->db->sql_escape($parent_tree) . "' - WHERE style_parent_id = {$parent_id}"; - $this->db->sql_query($sql); - $updated = true; - } - return $updated; - } - - /** - * Find all possible parent styles for style - * - * @param array $styles list of styles - * @param int $id id of style - * @param int $parent current parent style id - * @param int $level current tree level - * @return array Style ids, names and levels - */ - protected function find_possible_parents($styles, $id = -1, $parent = 0, $level = 0) - { - $results = array(); - foreach ($styles as $style) - { - if ($style['style_id'] != $id && $style['style_parent_id'] == $parent) - { - $results[] = array( - 'style_id' => $style['style_id'], - 'style_name' => $style['style_name'], - 'style_path' => $style['style_path'], - 'style_parent_id' => $style['style_parent_id'], - 'style_parent_tree' => $style['style_parent_tree'], - 'level' => $level - ); - $results = array_merge($results, $this->find_possible_parents($styles, $id, $style['style_id'], $level + 1)); - } - } - return $results; - } - - /** - * Show item in styles list - * - * @param array $style style row - * @param int $level style inheritance level - */ - protected function list_style(&$style, $level) - { - // Mark row as shown - if (!empty($style['_shown'])) - { - return; - } - - $style['_shown'] = true; - - // Generate template variables - $actions = array(); - $row = array( - // 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'], - - // Additional data - 'DEFAULT' => ($style['style_id'] && $style['style_id'] == $this->default_style), - 'USERS' => (isset($style['_users'])) ? $style['_users'] : '', - 'LEVEL' => $level, - 'PADDING' => (4 + 16 * $level), - 'SHOW_COPYRIGHT' => ($style['style_id']) ? false : true, - 'STYLE_PATH_FULL' => htmlspecialchars($this->styles_path_absolute . '/' . $style['style_path']) . '/', - - // Comment to show below style - 'COMMENT' => (isset($style['_note'])) ? $style['_note'] : '', - - // The following variables should be used by hooks to add custom HTML code - 'EXTRA' => '', - 'EXTRA_OPTIONS' => '' - ); - - // Status specific data - if ($style['style_id']) - { - // Style is installed - - // Details - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=details&id=' . $style['style_id'], - 'L_ACTION' => $this->user->lang['DETAILS'] - ); - - // Activate/Deactive - $action_name = ($style['style_active'] ? 'de' : '') . 'activate'; - - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=' . $action_name . '&hash=' . generate_link_hash($action_name) . '&id=' . $style['style_id'], - 'L_ACTION' => $this->user->lang['STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE'] - ); - -/* // Export - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=export&hash=' . generate_link_hash('export') . '&id=' . $style['style_id'], - 'L_ACTION' => $this->user->lang['EXPORT'] - ); */ - - if ($style['style_name'] !== 'prosilver') - { - // Uninstall - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=uninstall&hash=' . generate_link_hash('uninstall') . '&id=' . $style['style_id'], - 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'] - ); - } - - // Preview - $actions[] = array( - 'U_ACTION' => append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'style=' . $style['style_id']), - 'L_ACTION' => $this->user->lang['PREVIEW'] - ); - } - else - { - // Style is not installed - if (empty($style['_available'])) - { - $actions[] = array( - 'HTML' => $this->user->lang['CANNOT_BE_INSTALLED'] - ); - } - else - { - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=install&hash=' . generate_link_hash('install') . '&dir=' . urlencode($style['style_path']), - 'L_ACTION' => $this->user->lang['INSTALL_STYLE'] - ); - } - } - - // todo: add hook - - // Assign template variables - $this->template->assign_block_vars('styles_list', $row); - foreach ($actions as $action) - { - $this->template->assign_block_vars('styles_list.actions', $action); - } - - // Increase counters - $counter = ($style['style_id']) ? ($style['style_active'] ? 'active' : 'inactive') : (empty($style['_available']) ? 'cannotinstall' : 'caninstall'); - if (!isset($this->style_counters)) - { - $this->style_counters = array( - 'total' => 0, - 'active' => 0, - 'inactive' => 0, - 'caninstall' => 0, - 'cannotinstall' => 0 - ); - } - $this->style_counters[$counter]++; - $this->style_counters['total']++; - } - - /** - * Show welcome message - * - * @param string $title main title - * @param string $description page description - */ - protected function welcome_message($title, $description) - { - $this->template->assign_vars(array( - 'L_TITLE' => $this->user->lang[$title], - 'L_EXPLAIN' => (isset($this->user->lang[$description])) ? $this->user->lang[$description] : '' - ) - ); - } - - /** - * Find all directories that have styles - * - * @return array Directory names - */ - protected function find_style_dirs() - { - $styles = array(); - - $dp = @opendir($this->styles_path); - if ($dp) - { - while (($file = readdir($dp)) !== false) - { - $dir = $this->styles_path . $file; - if ($file[0] == '.' || !is_dir($dir)) - { - continue; - } - - if (file_exists("{$dir}/style.cfg")) - { - $styles[] = $file; - } - } - closedir($dp); - } - - return $styles; - } - - /** - * Sort styles - */ - public function sort_styles($style1, $style2) - { - if ($style1['style_active'] != $style2['style_active']) - { - return ($style1['style_active']) ? -1 : 1; - } - if (isset($style1['_available']) && $style1['_available'] != $style2['_available']) - { - return ($style1['_available']) ? -1 : 1; - } - return strcasecmp(isset($style1['style_name']) ? $style1['style_name'] : $style1['name'], isset($style2['style_name']) ? $style2['style_name'] : $style2['name']); - } - - /** - * Read style configuration file - * - * @param string $dir style directory - * @return array|bool Style data, false on error - */ - 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 - foreach ($required as $key) - { - if (!isset($cfg[$key])) - { - return false; - } - } - - // Check data - if (!isset($cfg['parent']) || !is_string($cfg['parent']) || $cfg['parent'] == $cfg['name']) - { - $cfg['parent'] = ''; - } - if (!isset($cfg['template_bitfield'])) - { - $cfg['template_bitfield'] = $this->default_bitfield(); - } - - return $cfg; - } - - /** - * Install style - * - * @param array $style style data - * @return int Style id - */ - protected function install_style($style) - { - global $user, $phpbb_log; - - // Generate row - $sql_ary = array(); - foreach ($style as $key => $value) - { - if ($key != 'style_id' && substr($key, 0, 1) != '_') - { - $sql_ary[$key] = $value; - } - } - - // Add to database - $this->db->sql_transaction('begin'); - - $sql = 'INSERT INTO ' . STYLES_TABLE . ' - ' . $this->db->sql_build_array('INSERT', $sql_ary); - $this->db->sql_query($sql); - - $id = $this->db->sql_nextid(); - - $this->db->sql_transaction('commit'); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_ADD', false, array($sql_ary['style_name'])); - - return $id; - } - - /** - * Lists all styles - * - * @return array Rows with styles data - */ - protected function get_styles() - { - $sql = 'SELECT * - FROM ' . STYLES_TABLE; - $result = $this->db->sql_query($sql); - - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - return $rows; - } - - /** - * Count users for each style - * - * @return array Styles in following format: [style_id] = number of users - */ - protected function get_users() - { - $sql = 'SELECT user_style, COUNT(user_style) AS style_count - FROM ' . USERS_TABLE . ' - GROUP BY user_style'; - $result = $this->db->sql_query($sql); - - $style_count = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $style_count[$row['user_style']] = $row['style_count']; - } - $this->db->sql_freeresult($result); - - return $style_count; - } - - /** - * Uninstall style - * - * @param array $style Style data - * @return bool|string True on success, error message on error - */ - protected function uninstall_style($style) - { - $id = $style['style_id']; - $path = $style['style_path']; - - // Check if style has child styles - $sql = 'SELECT style_id - FROM ' . STYLES_TABLE . ' - WHERE style_parent_id = ' . (int) $id . " OR style_parent_tree = '" . $this->db->sql_escape($path) . "'"; - $result = $this->db->sql_query($sql); - - $conflict = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($conflict !== false) - { - return sprintf($this->user->lang['STYLE_UNINSTALL_DEPENDENT'], $style['style_name']); - } - - // Change default style for users - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_style = ' . (int) $this->default_style . ' - WHERE user_style = ' . $id; - $this->db->sql_query($sql); - - // Uninstall style - $sql = 'DELETE FROM ' . STYLES_TABLE . ' - WHERE style_id = ' . $id; - $this->db->sql_query($sql); - return true; - } - - /** - * Delete all files in style directory - * - * @param string $path Style directory - * @param string $dir Directory to remove inside style's directory - * @return bool True on success, false on error - */ - protected function delete_style_files($path, $dir = '') - { - $dirname = $this->styles_path . $path . $dir; - $result = true; - - $dp = @opendir($dirname); - - if ($dp) - { - while (($file = readdir($dp)) !== false) - { - if ($file == '.' || $file == '..') - { - continue; - } - $filename = $dirname . '/' . $file; - if (is_dir($filename)) - { - if (!$this->delete_style_files($path, $dir . '/' . $file)) - { - $result = false; - } - } - else - { - if (!@unlink($filename)) - { - $result = false; - } - } - } - closedir($dp); - } - if (!@rmdir($dirname)) - { - return false; - } - - return $result; - } - - /** - * Get list of items from posted data - * - * @param string $name Variable name - * @param string|int $default Default value for array - * @param bool $error If true, error will be triggered if list is empty - * @return array Items - */ - protected function request_vars($name, $default, $error = false) - { - $item = $this->request->variable($name, $default); - $items = $this->request->variable($name . 's', array($default)); - - if (count($items) == 1 && $items[0] == $default) - { - $items = array(); - } - - if ($item != $default && !count($items)) - { - $items[] = $item; - } - - if ($error && !count($items)) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - return $items; - } - - /** - * Generates default bitfield - * - * This bitfield decides which bbcodes are defined in a template. - * - * @return string Bitfield - */ - protected function default_bitfield() - { - static $value; - if (isset($value)) - { - return $value; - } - - // Hardcoded template bitfield to add for new templates - $default_bitfield = '1111111111111'; - - $bitfield = new bitfield(); - for ($i = 0; $i < strlen($default_bitfield); $i++) - { - if ($default_bitfield[$i] == '1') - { - $bitfield->set($i); - } - } - - return $bitfield->get_base64(); - } - -} diff --git a/install/update/new/includes/acp/acp_update.php b/install/update/new/includes/acp/acp_update.php deleted file mode 100644 index fa3afa6..0000000 --- a/install/update/new/includes/acp/acp_update.php +++ /dev/null @@ -1,88 +0,0 @@ - -* @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_update -{ - var $u_action; - - function main($id, $mode) - { - global $config, $user, $template, $request; - global $phpbb_root_path, $phpEx, $phpbb_container; - - $user->add_lang('install'); - - $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 - { - $recheck = $request->variable('versioncheck_force', false); - $updates_available = $version_helper->get_update_on_branch($recheck); - $upgrades_available = $version_helper->get_suggested_updates(); - if (!empty($upgrades_available)) - { - $upgrades_available = array_pop($upgrades_available); - } - } - catch (\RuntimeException $e) - { - $template->assign_var('S_VERSIONCHECK_FAIL', true); - - $updates_available = array(); - } - - if (!empty($updates_available)) - { - $template->assign_block_vars('updates_available', $updates_available); - } - - $update_link = $phpbb_root_path . 'install/app.' . $phpEx; - - $template_ary = [ - 'S_UP_TO_DATE' => empty($updates_available), - 'U_ACTION' => $this->u_action, - 'U_VERSIONCHECK_FORCE' => append_sid($this->u_action . '&versioncheck_force=1'), - - 'CURRENT_VERSION' => $config['version'], - - '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 = $phpbb_root_path . 'install/app.php/update'; - - $template->assign_vars(array( - 'S_UPDATE_INCOMPLETE' => true, - 'FILES_VERSION' => PHPBB_VERSION, - 'INCOMPLETE_INSTRUCTIONS' => $user->lang('UPDATE_INCOMPLETE_EXPLAIN', $database_update_link), - )); - } - } -} diff --git a/install/update/new/includes/acp/acp_users.php b/install/update/new/includes/acp/acp_users.php deleted file mode 100644 index 6993c86..0000000 --- a/install/update/new/includes/acp/acp_users.php +++ /dev/null @@ -1,2689 +0,0 @@ - -* @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_users -{ - var $u_action; - var $p_master; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $config, $db, $user, $auth, $template; - global $phpbb_root_path, $phpbb_admin_path, $phpEx; - global $phpbb_dispatcher, $request; - global $phpbb_container, $phpbb_log; - - $user->add_lang(array('posting', 'ucp', 'acp/users')); - $this->tpl_name = 'acp_users'; - - $error = array(); - $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->variable('redirect', ''); - $redirect_tag = "redirect=$redirect"; - $redirect_url = append_sid("{$phpbb_admin_path}index.$phpEx", "i=$redirect"); - - $submit = (isset($_POST['update']) && !isset($_POST['cancel'])) ? true : false; - - $form_name = 'acp_users'; - add_form_key($form_name); - - // Whois (special case) - if ($action == 'whois') - { - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $this->page_title = 'WHOIS'; - $this->tpl_name = 'simple_body'; - - $user_ip = phpbb_ip_normalise($request->variable('user_ip', '')); - $domain = gethostbyaddr($user_ip); - $ipwhois = user_ipwhois($user_ip); - - $template->assign_vars(array( - 'MESSAGE_TITLE' => sprintf($user->lang['IP_WHOIS_FOR'], $domain), - 'MESSAGE_TEXT' => nl2br($ipwhois)) - ); - - return; - } - - // Show user selection mask - if (!$username && !$user_id) - { - $this->page_title = 'SELECT_USER'; - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - 'ANONYMOUS_USER_ID' => ANONYMOUS, - - 'S_SELECT_USER' => true, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_user&field=username&select_single=true'), - )); - - return; - } - - if (!$user_id) - { - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $db->sql_query($sql); - $user_id = (int) $db->sql_fetchfield('user_id'); - $db->sql_freeresult($result); - - if (!$user_id) - { - trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - // Generate content for all modes - $sql = 'SELECT u.*, s.* - FROM ' . USERS_TABLE . ' u - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) - WHERE u.user_id = ' . $user_id . ' - ORDER BY s.session_time DESC'; - $result = $db->sql_query_limit($sql, 1); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Generate overall "header" for user admin - $s_form_options = ''; - - // Build modes dropdown list - $sql = 'SELECT module_mode, module_auth - FROM ' . MODULES_TABLE . " - WHERE module_basename = 'acp_users' - AND module_enabled = 1 - AND module_class = 'acp' - ORDER BY left_id, module_mode"; - $result = $db->sql_query($sql); - - $dropdown_modes = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (!$this->p_master->module_auth_self($row['module_auth'])) - { - continue; - } - - $dropdown_modes[$row['module_mode']] = true; - } - $db->sql_freeresult($result); - - foreach ($dropdown_modes as $module_mode => $null) - { - $selected = ($mode == $module_mode) ? ' selected="selected"' : ''; - $s_form_options .= ''; - } - - $template->assign_vars(array( - 'U_BACK' => (empty($redirect)) ? $this->u_action : $redirect_url, - 'U_MODE_SELECT' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&u=$user_id"), - 'U_ACTION' => $this->u_action . '&u=' . $user_id . ((empty($redirect)) ? '' : '&' . $redirect_tag), - 'S_FORM_OPTIONS' => $s_form_options, - 'MANAGED_USERNAME' => $user_row['username']) - ); - - // Prevent normal users/admins change/view founders if they are not a founder by themselves - if ($user->data['user_type'] != USER_FOUNDER && $user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['NOT_MANAGE_FOUNDER'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $this->page_title = $user_row['username'] . ' :: ' . $user->lang('ACP_USER_' . strtoupper($mode)); - - switch ($mode) - { - case 'overview': - - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $user->add_lang('acp/ban'); - - $delete = $request->variable('delete', 0); - $delete_type = $request->variable('delete_type', ''); - $ip = $request->variable('ip', 'ip'); - - /** - * Run code at beginning of ACP users overview - * - * @event core.acp_users_overview_before - * @var array user_row Current user data - * @var string mode Active module - * @var string action Module that should be run - * @var bool submit Do we display the form only - * or did the user press submit - * @var array error Array holding error messages - * @since 3.1.3-RC1 - */ - $vars = array('user_row', 'mode', 'action', 'submit', 'error'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_overview_before', compact($vars))); - - if ($submit) - { - if ($delete) - { - if (!$auth->acl_get('a_userdel')) - { - send_status_line(403, 'Forbidden'); - trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // Check if the user wants to remove himself or the guest user account - if ($user_id == ANONYMOUS) - { - trigger_error($user->lang['CANNOT_REMOVE_ANONYMOUS'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // Founders can not be deleted. - if ($user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['CANNOT_REMOVE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_id == $user->data['user_id']) - { - trigger_error($user->lang['CANNOT_REMOVE_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($delete_type) - { - if (confirm_box(true)) - { - user_delete($delete_type, $user_id, $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 - ) - ); - } - else - { - $delete_confirm_hidden_fields = array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true, - 'delete' => 1, - 'delete_type' => $delete_type, - ); - - // Checks if the redirection page is specified - if (!empty($redirect)) - { - $delete_confirm_hidden_fields['redirect'] = $redirect; - } - - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($delete_confirm_hidden_fields)); - } - } - else - { - trigger_error($user->lang['NO_MODE'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - } - - // Handle quicktool actions - switch ($action) - { - case 'banuser': - case 'banemail': - case 'banip': - - if ($user_id == $user->data['user_id']) - { - trigger_error($user->lang['CANNOT_BAN_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_id == ANONYMOUS) - { - trigger_error($user->lang['CANNOT_BAN_ANONYMOUS'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['CANNOT_BAN_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $ban = array(); - - switch ($action) - { - case 'banuser': - $ban[] = $user_row['username']; - $reason = 'USER_ADMIN_BAN_NAME_REASON'; - break; - - case 'banemail': - $ban[] = $user_row['user_email']; - $reason = 'USER_ADMIN_BAN_EMAIL_REASON'; - break; - - case 'banip': - $ban[] = $user_row['user_ip']; - - $sql = 'SELECT DISTINCT poster_ip - FROM ' . POSTS_TABLE . " - WHERE poster_id = $user_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $ban[] = $row['poster_ip']; - } - $db->sql_freeresult($result); - - $reason = 'USER_ADMIN_BAN_IP_REASON'; - break; - } - - $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); - - trigger_error((($result === false) ? $user->lang['BAN_ALREADY_ENTERED'] : $user->lang['BAN_SUCCESSFUL']) . adm_back_link($this->u_action . '&u=' . $user_id)); - - break; - - case 'reactivate': - - if ($user_id == $user->data['user_id']) - { - trigger_error($user->lang['CANNOT_FORCE_REACT_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['CANNOT_FORCE_REACT_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error($user->lang['CANNOT_FORCE_REACT_BOT'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($config['email_enable']) - { - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $server_url = generate_board_url(); - - $user_actkey = gen_rand_string(mt_rand(6, 10)); - $email_template = ($user_row['user_type'] == USER_NORMAL) ? 'user_reactivate_account' : 'user_resend_inactive'; - - if ($user_row['user_type'] == USER_NORMAL) - { - user_active_flip('deactivate', $user_id, INACTIVE_REMIND); - } - else - { - // Grabbing the last confirm key - we only send a reminder - $sql = 'SELECT user_actkey - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - $user_activation_key = (string) $db->sql_fetchfield('user_actkey'); - $db->sql_freeresult($result); - - $user_actkey = empty($user_activation_key) ? $user_actkey : $user_activation_key; - } - - if ($user_row['user_type'] == USER_NORMAL || empty($user_activation_key)) - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_actkey = '" . $db->sql_escape($user_actkey) . "' - WHERE user_id = $user_id"; - $db->sql_query($sql); - } - - $messenger = new messenger(false); - - $messenger->template($email_template, $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey") - ); - - $messenger->send(NOTIFY_EMAIL); - - $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 . '&u=' . $user_id)); - } - - break; - - case 'active': - - if ($user_id == $user->data['user_id']) - { - // It is only deactivation since the user is already activated (else he would not have reached this page) - trigger_error($user->lang['CANNOT_DEACTIVATE_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['CANNOT_DEACTIVATE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error($user->lang['CANNOT_DEACTIVATE_BOT'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - user_active_flip('flip', $user_id); - - if ($user_row['user_type'] == USER_INACTIVE) - { - 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']); - - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $messenger = new messenger(false); - - $messenger->template('admin_welcome_activated', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($user_row['username'])) - ); - - $messenger->send(NOTIFY_EMAIL); - } - } - - $message = ($user_row['user_type'] == USER_INACTIVE) ? 'USER_ADMIN_ACTIVATED' : 'USER_ADMIN_DEACTIVED'; - $log = ($user_row['user_type'] == USER_INACTIVE) ? 'LOG_USER_ACTIVE' : 'LOG_USER_INACTIVE'; - - $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 . '&u=' . $user_id)); - - break; - - case 'delsig': - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $sql_ary = array( - 'user_sig' => '', - 'user_sig_bbcode_uid' => '', - 'user_sig_bbcode_bitfield' => '' - ); - - $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - $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 . '&u=' . $user_id)); - - break; - - case 'delavatar': - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // 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_'); - - $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 . '&u=' . $user_id)); - break; - - case 'delposts': - - if (confirm_box(true)) - { - // Delete posts, attachments, etc. - delete_posts('poster_id', $user_id); - - $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 . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true)) - ); - } - - break; - - case 'delattach': - - if (confirm_box(true)) - { - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $attachment_manager->delete('user', $user_id); - unset($attachment_manager); - - $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 . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true)) - ); - } - - break; - - case 'deloutbox': - - if (confirm_box(true)) - { - $msg_ids = array(); - $lang = 'EMPTY'; - - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE author_id = $user_id - AND folder_id = " . PRIVMSGS_OUTBOX; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - if (!function_exists('delete_pm')) - { - include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - } - - do - { - $msg_ids[] = (int) $row['msg_id']; - } - while ($row = $db->sql_fetchrow($result)); - - $db->sql_freeresult($result); - - delete_pm($user_id, $msg_ids, PRIVMSGS_OUTBOX); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_OUTBOX', false, array($user_row['username'])); - - $lang = 'EMPTIED'; - } - $db->sql_freeresult($result); - - trigger_error($user->lang['USER_OUTBOX_' . $lang] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true)) - ); - } - break; - - case 'moveposts': - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $user->add_lang('acp/forums'); - - $new_forum_id = $request->variable('new_f', 0); - - if (!$new_forum_id) - { - $this->page_title = 'USER_ADMIN_MOVE_POSTS'; - - $template->assign_vars(array( - 'S_SELECT_FORUM' => true, - 'U_ACTION' => $this->u_action . "&action=$action&u=$user_id", - 'U_BACK' => $this->u_action . "&u=$user_id", - 'S_FORUM_OPTIONS' => make_forum_select(false, false, false, true)) - ); - - return; - } - - // Is the new forum postable to? - $sql = 'SELECT forum_name, forum_type - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $new_forum_id"; - $result = $db->sql_query($sql); - $forum_info = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$forum_info) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($forum_info['forum_type'] != FORUM_POST) - { - trigger_error($user->lang['MOVE_POSTS_NO_POSTABLE_FORUM'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // Two stage? - // Move topics comprising only posts from this user - $topic_id_ary = $move_topic_ary = $move_post_ary = $new_topic_id_ary = array(); - $forum_id_ary = array($new_forum_id); - - $sql = 'SELECT topic_id, post_visibility, COUNT(post_id) AS total_posts - FROM ' . POSTS_TABLE . " - WHERE poster_id = $user_id - AND forum_id <> $new_forum_id - GROUP BY topic_id, post_visibility"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id_ary[$row['topic_id']][$row['post_visibility']] = $row['total_posts']; - } - $db->sql_freeresult($result); - - 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 . ' - WHERE ' . $db->sql_in_set('topic_id', array_keys($topic_id_ary)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($topic_id_ary[$row['topic_id']][ITEM_APPROVED] == $row['topic_posts_approved'] - && $topic_id_ary[$row['topic_id']][ITEM_UNAPPROVED] == $row['topic_posts_unapproved'] - && $topic_id_ary[$row['topic_id']][ITEM_REAPPROVE] == $row['topic_posts_unapproved'] - && $topic_id_ary[$row['topic_id']][ITEM_DELETED] == $row['topic_posts_softdeleted']) - { - $move_topic_ary[] = $row['topic_id']; - } - else - { - $move_post_ary[$row['topic_id']]['title'] = $row['topic_title']; - $move_post_ary[$row['topic_id']]['attach'] = ($row['topic_attachment']) ? 1 : 0; - } - - $forum_id_ary[] = $row['forum_id']; - } - $db->sql_freeresult($result); - } - - // Entire topic comprises posts by this user, move these topics - if (count($move_topic_ary)) - { - move_topics($move_topic_ary, $new_forum_id, false); - } - - if (count($move_post_ary)) - { - // Create new topic - // Update post_ids, report_ids, attachment_ids - foreach ($move_post_ary as $topic_id => $post_ary) - { - // Create new topic - $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'topic_poster' => $user_id, - 'topic_time' => time(), - 'forum_id' => $new_forum_id, - 'icon_id' => 0, - 'topic_visibility' => ITEM_APPROVED, - 'topic_title' => $post_ary['title'], - 'topic_first_poster_name' => $user_row['username'], - 'topic_type' => POST_NORMAL, - 'topic_time_limit' => 0, - 'topic_attachment' => $post_ary['attach']) - ); - $db->sql_query($sql); - - $new_topic_id = $db->sql_nextid(); - - // Move posts - $sql = 'UPDATE ' . POSTS_TABLE . " - SET forum_id = $new_forum_id, topic_id = $new_topic_id - WHERE topic_id = $topic_id - AND poster_id = $user_id"; - $db->sql_query($sql); - - if ($post_ary['attach']) - { - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET topic_id = $new_topic_id - WHERE topic_id = $topic_id - AND poster_id = $user_id"; - $db->sql_query($sql); - } - - $new_topic_id_ary[] = $new_topic_id; - } - } - - $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 (count($topic_id_ary)) - { - sync('topic_reported', 'topic_id', $topic_id_ary); - sync('topic', 'topic_id', $topic_id_ary); - } - - if (count($forum_id_ary)) - { - sync('forum', 'forum_id', $forum_id_ary, false, true); - } - - $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 . '&u=' . $user_id)); - - break; - - case 'leave_nr': - - if (confirm_box(true)) - { - remove_newly_registered($user_id, $user_row); - - $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 . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true)) - ); - } - - break; - - default: - $u_action = $this->u_action; - - /** - * Run custom quicktool code - * - * @event core.acp_users_overview_run_quicktool - * @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', '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' => $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), - ); - - // Validation data - we do not check the password complexity setting here - $check_ary = array( - 'new_password' => array( - array('string', true, $config['min_pass_chars'], 0), - array('password')), - 'password_confirm' => array('string', true, $config['min_pass_chars'], 0), - ); - - // Check username if altered - if ($data['username'] != $user_row['username']) - { - $check_ary += array( - 'username' => array( - array('string', false, $config['min_name_chars'], $config['max_name_chars']), - array('username', $user_row['username'], true) - ), - ); - } - - // Check email if altered - if ($data['email'] != $user_row['user_email']) - { - $check_ary += array( - 'email' => array( - array('string', false, 6, 60), - array('user_email', $user_row['user_email']), - ), - ); - } - - $error = validate_data($data, $check_ary); - - if ($data['new_password'] && $data['password_confirm'] != $data['new_password']) - { - $error[] = 'NEW_PASSWORD_ERROR'; - } - - if (!check_form_key($form_name)) - { - $error[] = 'FORM_INVALID'; - } - - // Instantiate passwords manager - /* @var $passwords_manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('passwords.manager'); - - // Which updates do we need to do? - $update_username = ($user_row['username'] != $data['username']) ? $data['username'] : false; - $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 (!count($error)) - { - $sql_ary = array(); - - if ($user_row['user_type'] != USER_FOUNDER || $user->data['user_type'] == USER_FOUNDER) - { - // Only allow founders updating the founder status... - if ($user->data['user_type'] == USER_FOUNDER) - { - // Setting a normal member to be a founder - if ($data['user_founder'] && $user_row['user_type'] != USER_FOUNDER) - { - // Make sure the user is not setting an Inactive or ignored user to be a founder - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error($user->lang['CANNOT_SET_FOUNDER_IGNORED'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_INACTIVE) - { - trigger_error($user->lang['CANNOT_SET_FOUNDER_INACTIVE'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $sql_ary['user_type'] = USER_FOUNDER; - } - else if (!$data['user_founder'] && $user_row['user_type'] == USER_FOUNDER) - { - // Check if at least one founder is present - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_FOUNDER . ' - AND user_id <> ' . $user_id; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $sql_ary['user_type'] = USER_NORMAL; - } - else - { - trigger_error($user->lang['AT_LEAST_ONE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - } - } - } - - /** - * Modify user data before we update it - * - * @event core.acp_users_overview_modify_data - * @var array user_row Current user data - * @var array data Submitted user data - * @var array sql_ary User data we udpate - * @since 3.1.0-a1 - */ - $vars = array('user_row', 'data', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_overview_modify_data', compact($vars))); - - if ($update_username !== false) - { - $sql_ary['username'] = $update_username; - $sql_ary['username_clean'] = utf8_clean_string($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) - { - $sql_ary += ['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) - { - $sql_ary += array( - 'user_password' => $passwords_manager->hash($data['new_password']), - 'user_passchg' => time(), - ); - - $user->reset_login_keys($user_id); - - $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_NEW_PASSWORD', false, array( - 'reportee_id' => $user_id, - $user_row['username'] - )); - } - - if (count($sql_ary)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - } - - if ($update_username) - { - user_update_name($user_row['username'], $update_username); - } - - // Let the users permissions being updated - $auth->acl_clear_prefetch($user_id); - - $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 . '&u=' . $user_id)); - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - if ($user_id == $user->data['user_id']) - { - $quick_tool_ary = array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH', 'deloutbox' => 'DEL_OUTBOX'); - if ($user_row['user_new']) - { - $quick_tool_ary['leave_nr'] = 'LEAVE_NR'; - } - } - else - { - $quick_tool_ary = array(); - - if ($user_row['user_type'] != USER_FOUNDER) - { - $quick_tool_ary += array('banuser' => 'BAN_USER', 'banemail' => 'BAN_EMAIL', 'banip' => 'BAN_IP'); - } - - if ($user_row['user_type'] != USER_FOUNDER && $user_row['user_type'] != USER_IGNORE) - { - $quick_tool_ary += array('active' => (($user_row['user_type'] == USER_INACTIVE) ? 'ACTIVATE' : 'DEACTIVATE')); - } - - $quick_tool_ary += array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH', 'deloutbox' => 'DEL_OUTBOX'); - - if ($config['email_enable'] && ($user_row['user_type'] == USER_NORMAL || $user_row['user_type'] == USER_INACTIVE)) - { - $quick_tool_ary['reactivate'] = 'FORCE'; - } - - if ($user_row['user_new']) - { - $quick_tool_ary['leave_nr'] = 'LEAVE_NR'; - } - } - - if ($config['load_onlinetrack']) - { - $sql = 'SELECT MAX(session_time) AS session_time, MIN(session_viewonline) AS session_viewonline - FROM ' . SESSIONS_TABLE . " - WHERE session_user_id = $user_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $user_row['session_time'] = (isset($row['session_time'])) ? $row['session_time'] : 0; - $user_row['session_viewonline'] = (isset($row['session_viewonline'])) ? $row['session_viewonline'] : 0; - unset($row); - } - - /** - * Add additional quick tool options and overwrite user data - * - * @event core.acp_users_display_overview - * @var array user_row Array with user data - * @var array quick_tool_ary Ouick tool options - * @since 3.1.0-a1 - */ - $vars = array('user_row', 'quick_tool_ary'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_display_overview', compact($vars))); - - $s_action_options = ''; - foreach ($quick_tool_ary as $value => $lang) - { - $s_action_options .= ''; - } - - $last_active = (!empty($user_row['session_time'])) ? $user_row['session_time'] : $user_row['user_lastvisit']; - - $inactive_reason = ''; - if ($user_row['user_type'] == USER_INACTIVE) - { - $inactive_reason = $user->lang['INACTIVE_REASON_UNKNOWN']; - - switch ($user_row['user_inactive_reason']) - { - case INACTIVE_REGISTER: - $inactive_reason = $user->lang['INACTIVE_REASON_REGISTER']; - break; - - case INACTIVE_PROFILE: - $inactive_reason = $user->lang['INACTIVE_REASON_PROFILE']; - break; - - case INACTIVE_MANUAL: - $inactive_reason = $user->lang['INACTIVE_REASON_MANUAL']; - break; - - case INACTIVE_REMIND: - $inactive_reason = $user->lang['INACTIVE_REASON_REMIND']; - break; - } - } - - // Posts in Queue - $sql = 'SELECT COUNT(post_id) as posts_in_queue - FROM ' . POSTS_TABLE . ' - WHERE poster_id = ' . $user_id . ' - AND ' . $db->sql_in_set('post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)); - $result = $db->sql_query($sql); - $user_row['posts_in_queue'] = (int) $db->sql_fetchfield('posts_in_queue'); - $db->sql_freeresult($result); - - $sql = 'SELECT post_id - FROM ' . POSTS_TABLE . ' - WHERE poster_id = '. $user_id; - $result = $db->sql_query_limit($sql, 1); - $user_row['user_has_posts'] = (bool) $db->sql_fetchfield('post_id'); - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'L_NAME_CHARS_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars'])), - 'L_POSTS_IN_QUEUE' => $user->lang('NUM_POSTS_IN_QUEUE', $user_row['posts_in_queue']), - 'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, - - 'S_OVERVIEW' => true, - 'S_USER_IP' => ($user_row['user_ip']) ? true : false, - 'S_USER_FOUNDER' => ($user_row['user_type'] == USER_FOUNDER) ? true : false, - 'S_ACTION_OPTIONS' => $s_action_options, - 'S_OWN_ACCOUNT' => ($user_id == $user->data['user_id']) ? true : false, - 'S_USER_INACTIVE' => ($user_row['user_type'] == USER_INACTIVE) ? true : false, - - 'U_SHOW_IP' => $this->u_action . "&u=$user_id&ip=" . (($ip == 'ip') ? 'hostname' : 'ip'), - 'U_WHOIS' => $this->u_action . "&action=whois&user_ip={$user_row['user_ip']}", - 'U_MCP_QUEUE' => ($auth->acl_getf_global('m_approve')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue', true, $user->session_id) : '', - 'U_SEARCH_USER' => ($config['load_search'] && $auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id={$user_row['user_id']}&sr=posts") : '', - - 'U_SWITCH_PERMISSIONS' => ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_row['user_id']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&u={$user_row['user_id']}&hash=" . generate_link_hash('switchperm')) : '', - - 'POSTS_IN_QUEUE' => $user_row['posts_in_queue'], - 'USER' => $user_row['username'], - 'USER_REGISTERED' => $user->format_date($user_row['user_regdate']), - 'REGISTERED_IP' => ($ip == 'hostname') ? gethostbyaddr($user_row['user_ip']) : $user_row['user_ip'], - 'USER_LASTACTIVE' => ($last_active) ? $user->format_date($last_active) : ' - ', - 'USER_EMAIL' => $user_row['user_email'], - 'USER_WARNINGS' => $user_row['user_warnings'], - 'USER_POSTS' => $user_row['user_posts'], - 'USER_HAS_POSTS' => $user_row['user_has_posts'], - 'USER_INACTIVE_REASON' => $inactive_reason, - )); - - break; - - case 'feedback': - - $user->add_lang('mcp'); - - // Set up general vars - $start = $request->variable('start', 0); - $deletemark = (isset($_POST['delmarked'])) ? true : false; - $deleteall = (isset($_POST['delall'])) ? true : false; - $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->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')) - { - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $where_sql = ''; - if ($deletemark && $marked) - { - $sql_in = array(); - foreach ($marked as $mark) - { - $sql_in[] = $mark; - } - $where_sql = ' AND ' . $db->sql_in_set('log_id', $sql_in); - unset($sql_in); - } - - if ($where_sql || $deleteall) - { - $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE log_type = ' . LOG_USERS . " - AND reportee_id = $user_id - $where_sql"; - $db->sql_query($sql); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CLEAR_USER', false, array($user_row['username'])); - } - } - - if ($submit && $message) - { - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $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 . '&u=' . $user_id)); - } - - // Sorting - $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_text = array('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'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - - // Define where and sort sql for use in displaying logs - $sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0; - $sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); - - // Grab log data - $log_data = array(); - $log_count = 0; - $start = view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort); - - $base_url = $this->u_action . "&u=$user_id&$u_sort_param"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'S_FEEDBACK' => true, - - 'S_LIMIT_DAYS' => $s_limit_days, - 'S_SORT_KEY' => $s_sort_key, - 'S_SORT_DIR' => $s_sort_dir, - 'S_CLEARLOGS' => $auth->acl_get('a_clearlogs')) - ); - - foreach ($log_data as $row) - { - $template->assign_block_vars('log', array( - 'USERNAME' => $row['username_full'], - 'IP' => $row['ip'], - 'DATE' => $user->format_date($row['time']), - 'ACTION' => nl2br($row['action']), - 'ID' => $row['id']) - ); - } - - break; - - case 'warnings': - $user->add_lang('mcp'); - - // Set up general vars - $deletemark = (isset($_POST['delmarked'])) ? true : false; - $deleteall = (isset($_POST['delall'])) ? true : false; - $confirm = (isset($_POST['confirm'])) ? true : false; - $marked = $request->variable('mark', array(0)); - - // Delete entries if requested and able - if ($deletemark || $deleteall || $confirm) - { - if (confirm_box(true)) - { - $where_sql = ''; - $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)); - } - - if ($where_sql || $deleteall) - { - $sql = 'DELETE FROM ' . WARNINGS_TABLE . " - WHERE user_id = $user_id - $where_sql"; - $db->sql_query($sql); - - if ($deleteall) - { - $log_warnings = $deleted_warnings = 0; - } - else - { - $num_warnings = (int) $db->sql_affectedrows(); - $deleted_warnings = ' user_warnings - ' . $num_warnings; - $log_warnings = ($num_warnings > 2) ? 2 : $num_warnings; - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_warnings = $deleted_warnings - WHERE user_id = $user_id"; - $db->sql_query($sql); - - if ($log_warnings) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_WARNINGS_DELETED', false, array($user_row['username'], $num_warnings)); - } - else - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_WARNINGS_DELETED_ALL', false, array($user_row['username'])); - } - } - } - else - { - $s_hidden_fields = array( - 'i' => $id, - 'mode' => $mode, - 'u' => $user_id, - 'mark' => $marked, - ); - if (isset($_POST['delmarked'])) - { - $s_hidden_fields['delmarked'] = 1; - } - if (isset($_POST['delall'])) - { - $s_hidden_fields['delall'] = 1; - } - if (isset($_POST['delall']) || (isset($_POST['delmarked']) && count($marked))) - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); - } - } - } - - $sql = 'SELECT w.warning_id, w.warning_time, w.post_id, l.log_operation, l.log_data, l.user_id AS mod_user_id, m.username AS mod_username, m.user_colour AS mod_user_colour - FROM ' . WARNINGS_TABLE . ' w - LEFT JOIN ' . LOG_TABLE . ' l - ON (w.log_id = l.log_id) - LEFT JOIN ' . USERS_TABLE . ' m - ON (l.user_id = m.user_id) - WHERE w.user_id = ' . $user_id . ' - ORDER BY w.warning_time DESC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$row['log_operation']) - { - // We do not have a log-entry anymore, so there is no data available - $row['action'] = $user->lang['USER_WARNING_LOG_DELETED']; - } - else - { - $row['action'] = (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}'; - if (!empty($row['log_data'])) - { - $log_data_ary = @unserialize($row['log_data']); - $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary; - - if (isset($user->lang[$row['log_operation']])) - { - // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array - // It doesn't matter if we add more arguments than placeholders - if ((substr_count($row['action'], '%') - count($log_data_ary)) > 0) - { - $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'])); - } - else if (!empty($log_data_ary)) - { - $row['action'] .= '
' . implode('', $log_data_ary); - } - } - } - - $template->assign_block_vars('warn', array( - 'ID' => $row['warning_id'], - 'USERNAME' => ($row['log_operation']) ? get_username_string('full', $row['mod_user_id'], $row['mod_username'], $row['mod_user_colour']) : '-', - 'ACTION' => make_clickable($row['action']), - 'DATE' => $user->format_date($row['warning_time']), - )); - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_WARNINGS' => true, - )); - - break; - - case 'profile': - - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - /* @var $cp \phpbb\profilefields\manager */ - $cp = $phpbb_container->get('profilefields.manager'); - - $cp_data = $cp_error = array(); - - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($user->data['user_lang']) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $user_row['iso_lang_id'] = $row['lang_id']; - - $data = array( - 'jabber' => $request->variable('jabber', $user_row['user_jabber'], true), - 'bday_day' => 0, - 'bday_month' => 0, - 'bday_year' => 0, - ); - - if ($user_row['user_birthday']) - { - list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user_row['user_birthday']); - } - - $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']); - - /** - * Modify user data on editing profile in ACP - * - * @event core.acp_users_modify_profile - * @var array data Array with user profile data - * @var bool submit Flag indicating if submit button has been pressed - * @var int user_id The user id - * @var array user_row Array with the full user data - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit', 'user_id', 'user_row'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_modify_profile', compact($vars))); - - if ($submit) - { - $error = validate_data($data, array( - 'jabber' => array( - array('string', true, 5, 255), - array('jabber')), - 'bday_day' => array('num', true, 1, 31), - 'bday_month' => array('num', true, 1, 12), - 'bday_year' => array('num', true, 1901, gmdate('Y', time())), - 'user_birthday' => array('date', true), - )); - - // validate custom profile fields - $cp->submit_cp_field('profile', $user_row['iso_lang_id'], $cp_data, $cp_error); - - if (count($cp_error)) - { - $error = array_merge($error, $cp_error); - } - if (!check_form_key($form_name)) - { - $error[] = 'FORM_INVALID'; - } - - /** - * Validate profile data in ACP before submitting to the database - * - * @event core.acp_users_profile_validate - * @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('data', 'user_id', 'user_row', 'error'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_validate', compact($vars))); - - if (!count($error)) - { - $sql_ary = array( - 'user_jabber' => $data['jabber'], - 'user_birthday' => $data['user_birthday'], - ); - - /** - * Modify profile data in ACP before submitting to the database - * - * @event core.acp_users_profile_modify_sql_ary - * @var array cp_data Array with the user custom profile fields data - * @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 sql_ary Array with sql data - * @since 3.1.4-RC1 - */ - $vars = array('cp_data', 'data', 'user_id', 'user_row', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_modify_sql_ary', compact($vars))); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - // Update Custom Fields - $cp->update_profile_field_data($user_id, $cp_data); - - trigger_error($user->lang['USER_PROFILE_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - $s_birthday_day_options = ''; - for ($i = 1; $i < 32; $i++) - { - $selected = ($i == $data['bday_day']) ? ' selected="selected"' : ''; - $s_birthday_day_options .= ""; - } - - $s_birthday_month_options = ''; - for ($i = 1; $i < 13; $i++) - { - $selected = ($i == $data['bday_month']) ? ' selected="selected"' : ''; - $s_birthday_month_options .= ""; - } - - $now = getdate(); - $s_birthday_year_options = ''; - for ($i = $now['year'] - 100; $i <= $now['year']; $i++) - { - $selected = ($i == $data['bday_year']) ? ' selected="selected"' : ''; - $s_birthday_year_options .= ""; - } - unset($now); - - $template->assign_vars(array( - 'JABBER' => $data['jabber'], - 'S_BIRTHDAY_DAY_OPTIONS' => $s_birthday_day_options, - 'S_BIRTHDAY_MONTH_OPTIONS' => $s_birthday_month_options, - 'S_BIRTHDAY_YEAR_OPTIONS' => $s_birthday_year_options, - - 'S_PROFILE' => true) - ); - - // Get additional profile fields and assign them to the template block var 'profile_fields' - $user->get_profile_fields($user_id); - - $cp->generate_profile_fields('profile', $user_row['iso_lang_id']); - - break; - - case 'prefs': - - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $data = array( - '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']), - ); - - /** - * Modify users preferences data - * - * @event core.acp_users_prefs_modify_data - * @var array data Array with users preferences data - * @var array user_row Array with user data - * @since 3.1.0-b3 - */ - $vars = array('data', 'user_row'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_data', compact($vars))); - - if ($submit) - { - $error = validate_data($data, array( - 'dateformat' => array('string', false, 1, 64), - 'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'), - 'tz' => array('timezone'), - - 'topic_sk' => array('string', false, 1, 1), - 'topic_sd' => array('string', false, 1, 1), - 'post_sk' => array('string', false, 1, 1), - 'post_sd' => array('string', false, 1, 1), - )); - - if (!check_form_key($form_name)) - { - $error[] = 'FORM_INVALID'; - } - - if (!count($error)) - { - $this->optionset($user_row, 'viewimg', $data['view_images']); - $this->optionset($user_row, 'viewflash', $data['view_flash']); - $this->optionset($user_row, 'viewsmilies', $data['view_smilies']); - $this->optionset($user_row, 'viewsigs', $data['view_sigs']); - $this->optionset($user_row, 'viewavatars', $data['view_avatars']); - $this->optionset($user_row, 'viewcensors', $data['view_wordcensor']); - $this->optionset($user_row, 'bbcode', $data['bbcode']); - $this->optionset($user_row, 'smilies', $data['smilies']); - $this->optionset($user_row, 'attachsig', $data['sig']); - - $sql_ary = array( - 'user_options' => $user_row['user_options'], - - 'user_allow_pm' => $data['allowpm'], - 'user_allow_viewemail' => $data['viewemail'], - 'user_allow_massemail' => $data['massemail'], - 'user_allow_viewonline' => !$data['hideonline'], - 'user_notify_type' => $data['notifymethod'], - 'user_notify_pm' => $data['notifypm'], - - 'user_dateformat' => $data['dateformat'], - 'user_lang' => $data['lang'], - 'user_timezone' => $data['tz'], - 'user_style' => $data['style'], - - 'user_topic_sortby_type' => $data['topic_sk'], - 'user_post_sortby_type' => $data['post_sk'], - 'user_topic_sortby_dir' => $data['topic_sd'], - 'user_post_sortby_dir' => $data['post_sd'], - - 'user_topic_show_days' => $data['topic_st'], - 'user_post_show_days' => $data['post_st'], - - 'user_notify' => $data['notify'], - ); - - /** - * Modify SQL query before users preferences are updated - * - * @event core.acp_users_prefs_modify_sql - * @var array data Array with users preferences data - * @var array user_row Array with user data - * @var array sql_ary SQL array with users preferences data to update - * @var array error Array with errors data - * @since 3.1.0-b3 - */ - $vars = array('data', 'user_row', 'sql_ary', 'error'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_sql', compact($vars))); - - if (!count($error)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - // Check if user has an active session - if ($user_row['session_id']) - { - // We'll update the session if user_allow_viewonline has changed and the user is a bot - // Or if it's a regular user and the admin set it to hide the session - if ($user_row['user_allow_viewonline'] != $sql_ary['user_allow_viewonline'] && $user_row['user_type'] == USER_IGNORE - || $user_row['user_allow_viewonline'] && !$sql_ary['user_allow_viewonline']) - { - // We also need to check if the user has the permission to cloak. - $user_auth = new \phpbb\auth\auth(); - $user_auth->acl($user_row); - - $session_sql_ary = array( - 'session_viewonline' => ($user_auth->acl_get('u_hideonline')) ? $sql_ary['user_allow_viewonline'] : true, - ); - - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $session_sql_ary) . " - WHERE session_user_id = $user_id"; - $db->sql_query($sql); - - unset($user_auth); - } - } - - trigger_error($user->lang['USER_PREFS_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - $dateformat_options = ''; - foreach ($user->lang['dateformats'] as $format => $null) - { - $dateformat_options .= ''; - } - - $s_custom = false; - - $dateformat_options .= ''; - - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - // Topic ordering options - $limit_topic_days = array(0 => $user->lang['ALL_TOPICS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_topic_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 'r' => $user->lang['REPLIES'], 's' => $user->lang['SUBJECT'], 'v' => $user->lang['VIEWS']); - - // Post ordering options - $limit_post_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_post_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); - - $_options = array('topic', 'post'); - foreach ($_options as $sort_option) - { - ${'s_limit_' . $sort_option . '_days'} = ''; - - ${'s_sort_' . $sort_option . '_key'} = ''; - - ${'s_sort_' . $sort_option . '_dir'} = ''; - } - - phpbb_timezone_select($template, $user, $data['tz'], true); - $user_prefs_data = array( - 'S_PREFS' => true, - 'S_JABBER_DISABLED' => ($config['jab_enable'] && $user_row['user_jabber'] && @extension_loaded('xml')) ? false : true, - - 'VIEW_EMAIL' => $data['viewemail'], - 'MASS_EMAIL' => $data['massemail'], - 'ALLOW_PM' => $data['allowpm'], - 'HIDE_ONLINE' => $data['hideonline'], - 'NOTIFY_EMAIL' => ($data['notifymethod'] == NOTIFY_EMAIL) ? true : false, - 'NOTIFY_IM' => ($data['notifymethod'] == NOTIFY_IM) ? true : false, - 'NOTIFY_BOTH' => ($data['notifymethod'] == NOTIFY_BOTH) ? true : false, - 'NOTIFY_PM' => $data['notifypm'], - 'BBCODE' => $data['bbcode'], - 'SMILIES' => $data['smilies'], - 'ATTACH_SIG' => $data['sig'], - 'NOTIFY' => $data['notify'], - 'VIEW_IMAGES' => $data['view_images'], - 'VIEW_FLASH' => $data['view_flash'], - 'VIEW_SMILIES' => $data['view_smilies'], - 'VIEW_SIGS' => $data['view_sigs'], - 'VIEW_AVATARS' => $data['view_avatars'], - 'VIEW_WORDCENSOR' => $data['view_wordcensor'], - - 'S_TOPIC_SORT_DAYS' => $s_limit_topic_days, - 'S_TOPIC_SORT_KEY' => $s_sort_topic_key, - 'S_TOPIC_SORT_DIR' => $s_sort_topic_dir, - 'S_POST_SORT_DAYS' => $s_limit_post_days, - 'S_POST_SORT_KEY' => $s_sort_post_key, - 'S_POST_SORT_DIR' => $s_sort_post_dir, - - 'DATE_FORMAT' => $data['dateformat'], - 'S_DATEFORMAT_OPTIONS' => $dateformat_options, - 'S_CUSTOM_DATEFORMAT' => $s_custom, - 'DEFAULT_DATEFORMAT' => $config['default_dateformat'], - 'A_DEFAULT_DATEFORMAT' => addslashes($config['default_dateformat']), - - 'S_LANG_OPTIONS' => language_select($data['lang']), - 'S_STYLE_OPTIONS' => style_select($data['style']), - ); - - /** - * Modify users preferences data before assigning it to the template - * - * @event core.acp_users_prefs_modify_template_data - * @var array data Array with users preferences data - * @var array user_row Array with user data - * @var array user_prefs_data Array with users preferences data to be assigned to the template - * @since 3.1.0-b3 - */ - $vars = array('data', 'user_row', 'user_prefs_data'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_template_data', compact($vars))); - - $template->assign_vars($user_prefs_data); - - break; - - case 'avatar': - - $avatars_enabled = false; - /** @var \phpbb\avatar\manager $phpbb_avatar_manager */ - $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); - - if ($config['allow_avatar']) - { - $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers(); - - // This is normalised data, without the user_ prefix - $avatar_data = \phpbb\avatar\manager::clean_row($user_row, 'user'); - - if ($submit) - { - if (check_form_key($form_name)) - { - $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); - - if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) - { - $driver = $phpbb_avatar_manager->get_driver($driver_name); - $result = $driver->process_form($request, $template, $user, $avatar_data, $error); - - if ($result && empty($error)) - { - // Success! Lets save the result in the database - $result = array( - 'user_avatar_type' => $driver_name, - 'user_avatar' => $result['avatar'], - 'user_avatar_width' => $result['avatar_width'], - 'user_avatar_height' => $result['avatar_height'], - ); - - /** - * 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; - - $db->sql_query($sql); - trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - } - } - else - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - } - - // Handle deletion of avatars - if ($request->is_set_post('avatar_delete')) - { - if (!confirm_box(true)) - { - confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( - 'avatar_delete' => true)) - ); - } - else - { - $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, USERS_TABLE, 'user_'); - - trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - } - - $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user_row['user_avatar_type'])); - - // Assign min and max values before generating avatar driver html - $template->assign_vars(array( - 'AVATAR_MIN_WIDTH' => $config['avatar_min_width'], - 'AVATAR_MAX_WIDTH' => $config['avatar_max_width'], - 'AVATAR_MIN_HEIGHT' => $config['avatar_min_height'], - 'AVATAR_MAX_HEIGHT' => $config['avatar_max_height'], - )); - - foreach ($avatar_drivers as $current_driver) - { - $driver = $phpbb_avatar_manager->get_driver($current_driver); - - $avatars_enabled = true; - $template->set_filenames(array( - 'avatar' => $driver->get_acp_template_name(), - )); - - if ($driver->prepare_form($request, $template, $user, $avatar_data, $error)) - { - $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); - $driver_upper = strtoupper($driver_name); - - $template->assign_block_vars('avatar_drivers', array( - 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), - 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), - - 'DRIVER' => $driver_name, - 'SELECTED' => $current_driver == $selected_driver, - 'OUTPUT' => $template->assign_display('avatar'), - )); - } - } - } - - // Avatar manager is not initialized if avatars are disabled - if (isset($phpbb_avatar_manager)) - { - // Replace "error" strings with their real, localised form - $error = $phpbb_avatar_manager->localize_errors($user, $error); - } - - $avatar = phpbb_get_user_avatar($user_row, 'USER_AVATAR', true); - - $template->assign_vars(array( - 'S_AVATAR' => true, - 'ERROR' => (!empty($error)) ? implode('
', $error) : '', - 'AVATAR' => (empty($avatar) ? '' : $avatar), - - 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', - - 'L_AVATAR_EXPLAIN' => $user->lang(($config['avatar_filesize'] == 0) ? 'AVATAR_EXPLAIN_NO_FILESIZE' : 'AVATAR_EXPLAIN', $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024), - - 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled), - )); - - break; - - case 'rank': - - if ($submit) - { - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $rank_id = $request->variable('user_rank', 0); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_rank = $rank_id - WHERE user_id = $user_id"; - $db->sql_query($sql); - - trigger_error($user->lang['USER_RANK_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - - $sql = 'SELECT * - FROM ' . RANKS_TABLE . ' - WHERE rank_special = 1 - ORDER BY rank_title'; - $result = $db->sql_query($sql); - - $s_rank_options = ''; - - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($user_row['user_rank'] && $row['rank_id'] == $user_row['user_rank']) ? ' selected="selected"' : ''; - $s_rank_options .= ''; - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_RANK' => true, - 'S_RANK_OPTIONS' => $s_rank_options) - ); - - break; - - case 'sig': - - if (!function_exists('display_custom_bbcodes')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $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; - - $bbcode_flags = ($enable_bbcode ? OPTION_FLAG_BBCODE : 0) + ($enable_smilies ? OPTION_FLAG_SMILIES : 0) + ($enable_urls ? OPTION_FLAG_LINKS : 0); - - $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 = ''; - - 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'; - } - } - - $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 (!$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' => $signature, - 'user_options' => $user_row['user_options'], - '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; - $db->sql_query($sql); - - trigger_error($user->lang['USER_SIG_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - - if ($request->is_set_post('preview')) - { - $decoded_message = generate_text_for_edit($signature, $bbcode_uid, $bbcode_flags); - } - - /** @var \phpbb\controller\helper $controller_helper */ - $controller_helper = $phpbb_container->get('controller.helper'); - - $template->assign_vars(array( - 'S_SIGNATURE' => true, - - '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' => $user->lang(($config['allow_sig_bbcode'] ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '', ''), - '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'], - 'URL_STATUS' => ($config['allow_sig_links']) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], - - 'L_SIGNATURE_EXPLAIN' => $user->lang('SIGNATURE_EXPLAIN', (int) $config['max_sig_chars']), - - 'S_BBCODE_ALLOWED' => $config['allow_sig_bbcode'], - 'S_SMILIES_ALLOWED' => $config['allow_sig_smilies'], - 'S_BBCODE_IMG' => ($config['allow_sig_img']) ? true : false, - 'S_BBCODE_FLASH' => ($config['allow_sig_flash']) ? true : false, - 'S_LINKS_ALLOWED' => ($config['allow_sig_links']) ? true : false) - ); - - // Assigning custom bbcodes - display_custom_bbcodes(); - - break; - - case 'attach': - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - - $start = $request->variable('start', 0); - $deletemark = (isset($_POST['delmarked'])) ? true : false; - $marked = $request->variable('mark', array(0)); - - // Sort keys - $sort_key = $request->variable('sk', 'a'); - $sort_dir = $request->variable('sd', 'd'); - - if ($deletemark && count($marked)) - { - $sql = 'SELECT attach_id - FROM ' . ATTACHMENTS_TABLE . ' - WHERE poster_id = ' . $user_id . ' - AND is_orphan = 0 - AND ' . $db->sql_in_set('attach_id', $marked); - $result = $db->sql_query($sql); - - $marked = array(); - while ($row = $db->sql_fetchrow($result)) - { - $marked[] = $row['attach_id']; - } - $db->sql_freeresult($result); - } - - if ($deletemark && count($marked)) - { - if (confirm_box(true)) - { - $sql = 'SELECT real_filename - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', $marked); - $result = $db->sql_query($sql); - - $log_attachments = array(); - while ($row = $db->sql_fetchrow($result)) - { - $log_attachments[] = $row['real_filename']; - } - $db->sql_freeresult($result); - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $attachment_manager->delete('attach', $marked); - unset($attachment_manager); - - $message = (count($log_attachments) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED']; - - $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 . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'delmarked' => true, - 'mark' => $marked)) - ); - } - } - - $sk_text = array('a' => $user->lang['SORT_FILENAME'], 'c' => $user->lang['SORT_EXTENSION'], 'd' => $user->lang['SORT_SIZE'], 'e' => $user->lang['SORT_DOWNLOADS'], 'f' => $user->lang['SORT_POST_TIME'], 'g' => $user->lang['SORT_TOPIC_TITLE']); - $sk_sql = array('a' => 'a.real_filename', 'c' => 'a.extension', 'd' => 'a.filesize', 'e' => 'a.download_count', 'f' => 'a.filetime', 'g' => 't.topic_title'); - - $sd_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - $s_sort_key = ''; - foreach ($sk_text as $key => $value) - { - $selected = ($sort_key == $key) ? ' selected="selected"' : ''; - $s_sort_key .= ''; - } - - $s_sort_dir = ''; - foreach ($sd_text as $key => $value) - { - $selected = ($sort_dir == $key) ? ' selected="selected"' : ''; - $s_sort_dir .= ''; - } - - if (!isset($sk_sql[$sort_key])) - { - $sort_key = 'a'; - } - - $order_by = $sk_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); - - $sql = 'SELECT COUNT(attach_id) as num_attachments - FROM ' . ATTACHMENTS_TABLE . " - WHERE poster_id = $user_id - AND is_orphan = 0"; - $result = $db->sql_query_limit($sql, 1); - $num_attachments = (int) $db->sql_fetchfield('num_attachments'); - $db->sql_freeresult($result); - - $sql = 'SELECT a.*, t.topic_title, p.message_subject as message_title - FROM ' . ATTACHMENTS_TABLE . ' a - 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) - WHERE a.poster_id = ' . $user_id . " - AND a.is_orphan = 0 - ORDER BY $order_by"; - $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['in_message']) - { - $view_topic = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&p={$row['post_msg_id']}"); - } - else - { - $view_topic = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}") . '#p' . $row['post_msg_id']; - } - - $template->assign_block_vars('attach', array( - 'REAL_FILENAME' => $row['real_filename'], - 'COMMENT' => nl2br($row['attach_comment']), - 'EXTENSION' => $row['extension'], - 'SIZE' => get_formatted_filesize($row['filesize']), - 'DOWNLOAD_COUNT' => $row['download_count'], - 'POST_TIME' => $user->format_date($row['filetime']), - 'TOPIC_TITLE' => ($row['in_message']) ? $row['message_title'] : $row['topic_title'], - - 'ATTACH_ID' => $row['attach_id'], - 'POST_ID' => $row['post_msg_id'], - 'TOPIC_ID' => $row['topic_id'], - - 'S_IN_MESSAGE' => $row['in_message'], - - 'U_DOWNLOAD' => append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&id=' . $row['attach_id']), - 'U_VIEW_TOPIC' => $view_topic) - ); - } - $db->sql_freeresult($result); - - $base_url = $this->u_action . "&u=$user_id&sk=$sort_key&sd=$sort_dir"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_attachments, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'S_ATTACHMENTS' => true, - 'S_SORT_KEY' => $s_sort_key, - 'S_SORT_DIR' => $s_sort_dir, - )); - - break; - - case 'groups': - - if (!function_exists('group_user_attributes')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $user->add_lang(array('groups', 'acp/groups')); - $group_id = $request->variable('g', 0); - - if ($group_id) - { - // Check the founder only entry for this group to make sure everything is well - $sql = 'SELECT group_founder_manage - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . $group_id; - $result = $db->sql_query($sql); - $founder_manage = (int) $db->sql_fetchfield('group_founder_manage'); - $db->sql_freeresult($result); - - if ($user->data['user_type'] != USER_FOUNDER && $founder_manage) - { - trigger_error($user->lang['NOT_ALLOWED_MANAGE_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - } - - switch ($action) - { - case 'demote': - case 'promote': - case 'default': - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!check_link_hash($request->variable('hash', ''), 'acp_users')) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - group_user_attributes($action, $group_id, $user_id); - - if ($action == 'default') - { - $user_row['group_id'] = $group_id; - } - break; - - case 'delete': - - if (confirm_box(true)) - { - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($error = group_user_del($group_id, $user_id)) - { - trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $error = array(); - - // The delete action was successful - therefore update the user row... - $sql = 'SELECT u.*, s.* - FROM ' . USERS_TABLE . ' u - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) - WHERE u.user_id = ' . $user_id . ' - ORDER BY s.session_time DESC'; - $result = $db->sql_query_limit($sql, 1); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'g' => $group_id)) - ); - } - - break; - - case 'approve': - - if (confirm_box(true)) - { - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - group_user_attributes($action, $group_id, $user_id); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'g' => $group_id)) - ); - } - - break; - } - - // Add user to group? - if ($submit) - { - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // Add user/s to group - if ($error = group_user_add($group_id, $user_id)) - { - trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $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 - AND g.group_id = ug.group_id - ORDER BY g.group_type DESC, ug.user_pending ASC, g.group_name"; - $result = $db->sql_query($sql); - - $i = 0; - $group_data = $id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $type = ($row['group_type'] == GROUP_SPECIAL) ? 'special' : (($row['user_pending']) ? 'pending' : 'normal'); - - $group_data[$type][$i]['group_id'] = $row['group_id']; - $group_data[$type][$i]['group_name'] = $row['group_name']; - $group_data[$type][$i]['group_leader'] = ($row['group_leader']) ? 1 : 0; - - $id_ary[] = $row['group_id']; - - $i++; - } - $db->sql_freeresult($result); - - // Select box for other groups - $sql = 'SELECT group_id, group_name, group_type, group_founder_manage - FROM ' . GROUPS_TABLE . ' - ' . ((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); - - $s_group_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - if (!$config['coppa_enable'] && $row['group_name'] == 'REGISTERED_COPPA') - { - continue; - } - - // Do not display those groups not allowed to be managed - if ($user->data['user_type'] != USER_FOUNDER && $row['group_founder_manage']) - { - continue; - } - - $s_group_options .= '' . $group_helper->get_name($row['group_name']) . ''; - } - $db->sql_freeresult($result); - - $current_type = ''; - foreach ($group_data as $group_type => $data_ary) - { - if ($current_type != $group_type) - { - $template->assign_block_vars('group', array( - 'S_NEW_GROUP_TYPE' => true, - 'GROUP_TYPE' => $user->lang['USER_GROUP_' . strtoupper($group_type)]) - ); - } - - foreach ($data_ary as $data) - { - $template->assign_block_vars('group', array( - 'U_EDIT_GROUP' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=groups&mode=manage&action=edit&u=$user_id&g={$data['group_id']}&back_link=acp_users_groups"), - 'U_DEFAULT' => $this->u_action . "&action=default&u=$user_id&g=" . $data['group_id'] . '&hash=' . generate_link_hash('acp_users'), - 'U_DEMOTE_PROMOTE' => $this->u_action . '&action=' . (($data['group_leader']) ? 'demote' : 'promote') . "&u=$user_id&g=" . $data['group_id'] . '&hash=' . generate_link_hash('acp_users'), - 'U_DELETE' => $this->u_action . "&action=delete&u=$user_id&g=" . $data['group_id'], - 'U_APPROVE' => ($group_type == 'pending') ? $this->u_action . "&action=approve&u=$user_id&g=" . $data['group_id'] : '', - - 'GROUP_NAME' => $group_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, - 'S_NO_DEFAULT' => ($user_row['group_id'] != $data['group_id']) ? true : false, - 'S_SPECIAL_GROUP' => ($group_type == 'special') ? true : false, - ) - ); - } - } - - $template->assign_vars(array( - 'S_GROUPS' => true, - 'S_GROUP_OPTIONS' => $s_group_options) - ); - - break; - - case 'perm': - - if (!class_exists('auth_admin')) - { - include($phpbb_root_path . 'includes/acp/auth.' . $phpEx); - } - - $auth_admin = new auth_admin(); - - $user->add_lang('acp/permissions'); - add_permission_language(); - - $forum_id = $request->variable('f', 0); - - // Global Permissions - if (!$forum_id) - { - // Select auth options - $sql = 'SELECT auth_option, is_local, is_global - FROM ' . ACL_OPTIONS_TABLE . ' - WHERE auth_option ' . $db->sql_like_expression($db->get_any_char() . '_') . ' - AND is_global = 1 - ORDER BY auth_option'; - $result = $db->sql_query($sql); - - $hold_ary = array(); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary = $auth_admin->get_mask('view', $user_id, false, false, $row['auth_option'], 'global', ACL_NEVER); - $auth_admin->display_mask('view', $row['auth_option'], $hold_ary, 'user', false, false); - } - $db->sql_freeresult($result); - - unset($hold_ary); - } - else - { - $sql = 'SELECT auth_option, is_local, is_global - FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($db->get_any_char() . '_') . " - AND is_local = 1 - ORDER BY is_global DESC, auth_option"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary = $auth_admin->get_mask('view', $user_id, false, $forum_id, $row['auth_option'], 'local', ACL_NEVER); - $auth_admin->display_mask('view', $row['auth_option'], $hold_ary, 'user', true, false); - } - $db->sql_freeresult($result); - } - - $s_forum_options = ''; - $s_forum_options .= make_forum_select($forum_id, false, true, false, false, false); - - $template->assign_vars(array( - 'S_PERMISSIONS' => true, - - 'S_GLOBAL' => (!$forum_id) ? true : false, - 'S_FORUM_OPTIONS' => $s_forum_options, - - 'U_ACTION' => $this->u_action . '&u=' . $user_id, - 'U_USER_PERMISSIONS' => append_sid("{$phpbb_admin_path}index.$phpEx" ,'i=permissions&mode=setting_user_global&user_id[]=' . $user_id), - 'U_USER_FORUM_PERMISSIONS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions&mode=setting_user_local&user_id[]=' . $user_id)) - ); - - 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' => (count($error)) ? true : false, - 'ERROR_MSG' => (count($error)) ? implode('
', $error) : '') - ); - } - - /** - * Set option bit field for user options in a user row array. - * - * Optionset replacement for this module based on $user->optionset. - * - * @param array $user_row Row from the users table. - * @param int $key Option key, as defined in $user->keyoptions property. - * @param bool $value True to set the option, false to clear the option. - * @param int $data Current bit field value, or false to use $user_row['user_options'] - * @return int|bool If $data is false, the bit field is modified and - * written back to $user_row['user_options'], and - * return value is true if the bit field changed and - * false otherwise. If $data is not false, the new - * bitfield value is returned. - */ - function optionset(&$user_row, $key, $value, $data = false) - { - global $user; - - $var = ($data !== false) ? $data : $user_row['user_options']; - - $new_var = phpbb_optionset($user->keyoptions[$key], $value, $var); - - if ($data === false) - { - if ($new_var != $var) - { - $user_row['user_options'] = $new_var; - return true; - } - else - { - return false; - } - } - else - { - return $new_var; - } - } - - /** - * Get option bit field from user options in a user row array. - * - * Optionget replacement for this module based on $user->optionget. - * - * @param array $user_row Row from the users table. - * @param int $key option key, as defined in $user->keyoptions property. - * @param int $data bit field value to use, or false to use $user_row['user_options'] - * @return bool true if the option is set in the bit field, false otherwise - */ - function optionget(&$user_row, $key, $data = false) - { - global $user; - - $var = ($data !== false) ? $data : $user_row['user_options']; - return phpbb_optionget($user->keyoptions[$key], $var); - } -} diff --git a/install/update/new/includes/acp/auth.php b/install/update/new/includes/acp/auth.php deleted file mode 100644 index f203f9d..0000000 --- a/install/update/new/includes/acp/auth.php +++ /dev/null @@ -1,1316 +0,0 @@ - -* @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; -} - -/** -* ACP Permission/Auth class -*/ -class auth_admin extends \phpbb\auth\auth -{ - /** - * Init auth settings - */ - function __construct() - { - global $db, $cache; - - if (($this->acl_options = $cache->get('_acl_options')) === false) - { - $sql = 'SELECT auth_option_id, auth_option, is_global, is_local - FROM ' . ACL_OPTIONS_TABLE . ' - ORDER BY auth_option_id'; - $result = $db->sql_query($sql); - - $global = $local = 0; - $this->acl_options = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['is_global']) - { - $this->acl_options['global'][$row['auth_option']] = $global++; - } - - if ($row['is_local']) - { - $this->acl_options['local'][$row['auth_option']] = $local++; - } - - $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id']; - $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option']; - } - $db->sql_freeresult($result); - - $cache->put('_acl_options', $this->acl_options); - } - } - - /** - * Get permission mask - * This function only supports getting permissions of one type (for example a_) - * - * @param set|view $mode defines the permissions we get, view gets effective permissions (checking user AND group permissions), set only gets the user or group permission set alone - * @param mixed $user_id user ids to search for (a user_id or a group_id has to be specified at least) - * @param mixed $group_id group ids to search for, return group related settings (a user_id or a group_id has to be specified at least) - * @param mixed $forum_id forum_ids to search for. Defining a forum id also means getting local settings - * @param string $auth_option the auth_option defines the permission setting to look for (a_ for example) - * @param local|global $scope the scope defines the permission scope. If local, a forum_id is additionally required - * @param ACL_NEVER|ACL_NO|ACL_YES $acl_fill defines the mode those permissions not set are getting filled with - */ - function get_mask($mode, $user_id = false, $group_id = false, $forum_id = false, $auth_option = false, $scope = false, $acl_fill = ACL_NEVER) - { - global $db, $user; - - $hold_ary = array(); - $view_user_mask = ($mode == 'view' && $group_id === false) ? true : false; - - if ($auth_option === false || $scope === false) - { - return array(); - } - - $acl_user_function = ($mode == 'set') ? 'acl_user_raw_data' : 'acl_raw_data'; - - if (!$view_user_mask) - { - if ($forum_id !== false) - { - $hold_ary = ($group_id !== false) ? $this->acl_group_raw_data($group_id, $auth_option . '%', $forum_id) : $this->$acl_user_function($user_id, $auth_option . '%', $forum_id); - } - else - { - $hold_ary = ($group_id !== false) ? $this->acl_group_raw_data($group_id, $auth_option . '%', ($scope == 'global') ? 0 : false) : $this->$acl_user_function($user_id, $auth_option . '%', ($scope == 'global') ? 0 : false); - } - } - - // Make sure hold_ary is filled with every setting (prevents missing forums/users/groups) - $ug_id = ($group_id !== false) ? ((!is_array($group_id)) ? array($group_id) : $group_id) : ((!is_array($user_id)) ? array($user_id) : $user_id); - $forum_ids = ($forum_id !== false) ? ((!is_array($forum_id)) ? array($forum_id) : $forum_id) : (($scope == 'global') ? array(0) : array()); - - // Only those options we need - $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' && !count($forum_ids)) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql, 120); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = (int) $row['forum_id']; - } - $db->sql_freeresult($result); - } - - if ($view_user_mask) - { - $auth2 = null; - - $sql = 'SELECT user_id, user_permissions, user_type - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $ug_id); - $result = $db->sql_query($sql); - - while ($userdata = $db->sql_fetchrow($result)) - { - if ($user->data['user_id'] != $userdata['user_id']) - { - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($userdata); - } - else - { - global $auth; - $auth2 = &$auth; - } - - $hold_ary[$userdata['user_id']] = array(); - foreach ($forum_ids as $f_id) - { - $hold_ary[$userdata['user_id']][$f_id] = array(); - foreach ($compare_options as $option) - { - $hold_ary[$userdata['user_id']][$f_id][$option] = $auth2->acl_get($option, $f_id); - } - } - } - $db->sql_freeresult($result); - - unset($userdata); - unset($auth2); - } - - foreach ($ug_id as $_id) - { - if (!isset($hold_ary[$_id])) - { - $hold_ary[$_id] = array(); - } - - foreach ($forum_ids as $f_id) - { - if (!isset($hold_ary[$_id][$f_id])) - { - $hold_ary[$_id][$f_id] = array(); - } - } - } - - // Now, we need to fill the gaps with $acl_fill. ;) - - // Now switch back to keys - if (count($compare_options)) - { - $compare_options = array_combine($compare_options, array_fill(1, count($compare_options), $acl_fill)); - } - - // Defining the user-function here to save some memory - $return_acl_fill = function () use ($acl_fill) - { - return $acl_fill; - }; - - // Actually fill the gaps - if (count($hold_ary)) - { - foreach ($hold_ary as $ug_id => $row) - { - foreach ($row as $id => $options) - { - // Do not include the global auth_option - unset($options[$auth_option]); - - // Not a "fine" solution, but at all it's a 1-dimensional - // array_diff_key function filling the resulting array values with zeros - // The differences get merged into $hold_ary (all permissions having $acl_fill set) - $hold_ary[$ug_id][$id] = array_merge($options, - - array_map($return_acl_fill, - array_flip( - array_diff( - array_keys($compare_options), array_keys($options) - ) - ) - ) - ); - } - } - } - else - { - $hold_ary[($group_id !== false) ? $group_id : $user_id][(int) $forum_id] = $compare_options; - } - - return $hold_ary; - } - - /** - * Get permission mask for roles - * This function only supports getting masks for one role - */ - function get_role_mask($role_id) - { - global $db; - - $hold_ary = array(); - - // Get users having this role set... - $sql = 'SELECT user_id, forum_id - FROM ' . ACL_USERS_TABLE . ' - WHERE auth_role_id = ' . $role_id . ' - ORDER BY forum_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary[$row['forum_id']]['users'][] = $row['user_id']; - } - $db->sql_freeresult($result); - - // Now grab groups... - $sql = 'SELECT group_id, forum_id - FROM ' . ACL_GROUPS_TABLE . ' - WHERE auth_role_id = ' . $role_id . ' - ORDER BY forum_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary[$row['forum_id']]['groups'][] = $row['group_id']; - } - $db->sql_freeresult($result); - - return $hold_ary; - } - - /** - * Display permission mask (assign to template) - */ - function display_mask($mode, $permission_type, &$hold_ary, $user_mode = 'user', $local = false, $group_display = true) - { - 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'; - $tpl_category = 'category'; - $tpl_mask = 'mask'; - - $l_acl_type = $phpbb_permissions->get_type_lang($permission_type, (($local) ? 'local' : 'global')); - - // Allow trace for viewing permissions and in user mode - $show_trace = ($mode == 'view' && $user_mode == 'user') ? true : false; - - // Get names - if ($user_mode == 'user') - { - $sql = 'SELECT user_id as ug_id, username as ug_name - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary)) . ' - ORDER BY username_clean ASC'; - } - else - { - $sql = 'SELECT group_id as ug_id, group_name as ug_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', array_keys($hold_ary)) . ' - ORDER BY group_type DESC, group_name ASC'; - } - $result = $db->sql_query($sql); - - $ug_names_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $ug_names_ary[$row['ug_id']] = ($user_mode == 'user') ? $row['ug_name'] : $group_helper->get_name($row['ug_name']); - } - $db->sql_freeresult($result); - - // Get used forums - $forum_ids = array(); - foreach ($hold_ary as $ug_id => $row) - { - $forum_ids = array_merge($forum_ids, array_keys($row)); - } - $forum_ids = array_unique($forum_ids); - - $forum_names_ary = array(); - if ($local) - { - $forum_names_ary = make_forum_select(false, false, true, false, false, false, true); - - // Remove the disabled ones, since we do not create an option field here... - foreach ($forum_names_ary as $key => $value) - { - if (!$value['disabled']) - { - continue; - } - unset($forum_names_ary[$key]); - } - } - else - { - $forum_names_ary[0] = $l_acl_type; - } - - // Get available roles - $sql = 'SELECT * - FROM ' . ACL_ROLES_TABLE . " - WHERE role_type = '" . $db->sql_escape($permission_type) . "' - ORDER BY role_order ASC"; - $result = $db->sql_query($sql); - - $roles = array(); - while ($row = $db->sql_fetchrow($result)) - { - $roles[$row['role_id']] = $row; - } - $db->sql_freeresult($result); - - $cur_roles = $this->acl_role_data($user_mode, $permission_type, array_keys($hold_ary)); - - // Build js roles array (role data assignments) - $s_role_js_array = ''; - - if (count($roles)) - { - $s_role_js_array = array(); - - // Make sure every role (even if empty) has its array defined - foreach ($roles as $_role_id => $null) - { - $s_role_js_array[$_role_id] = "\n" . 'role_options[' . $_role_id . '] = new Array();' . "\n"; - } - - $sql = 'SELECT r.role_id, o.auth_option, r.auth_setting - FROM ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' o - WHERE o.auth_option_id = r.auth_option_id - AND ' . $db->sql_in_set('r.role_id', array_keys($roles)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $flag = substr($row['auth_option'], 0, strpos($row['auth_option'], '_') + 1); - if ($flag == $row['auth_option']) - { - continue; - } - - $s_role_js_array[$row['role_id']] .= 'role_options[' . $row['role_id'] . '][\'' . addslashes($row['auth_option']) . '\'] = ' . $row['auth_setting'] . '; '; - } - $db->sql_freeresult($result); - - $s_role_js_array = implode('', $s_role_js_array); - } - - $template->assign_var('S_ROLE_JS_ARRAY', $s_role_js_array); - unset($s_role_js_array); - - // Now obtain memberships - $user_groups_default = $user_groups_custom = array(); - if ($user_mode == 'user' && $group_display) - { - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE . ' - ORDER BY group_type DESC, group_name ASC'; - $result = $db->sql_query($sql); - - $groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $groups[$row['group_id']] = $row; - } - $db->sql_freeresult($result); - - $memberships = group_memberships(false, array_keys($hold_ary), false); - - // User is not a member of any group? Bad admin, bad bad admin... - if ($memberships) - { - foreach ($memberships as $row) - { - $user_groups_default[$row['user_id']][] = $group_helper->get_name($groups[$row['group_id']]['group_name']); - } - } - unset($memberships, $groups); - } - - // 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 (count($forum_ids) == 1 || ($local && count($ug_names_ary) > 1)) - { - $hold_ary_temp = $hold_ary; - $hold_ary = array(); - foreach ($hold_ary_temp as $ug_id => $row) - { - foreach ($forum_names_ary as $forum_id => $forum_row) - { - if (isset($row[$forum_id])) - { - $hold_ary[$forum_id][$ug_id] = $row[$forum_id]; - } - } - } - unset($hold_ary_temp); - - foreach ($hold_ary as $forum_id => $forum_array) - { - $content_array = $categories = array(); - $this->build_permission_array($hold_ary[$forum_id], $content_array, $categories, array_keys($ug_names_ary)); - - $template->assign_block_vars($tpl_pmask, 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'], - - 'CATEGORIES' => implode('', $categories), - - 'L_ACL_TYPE' => $l_acl_type, - - 'S_LOCAL' => ($local) ? true : false, - 'S_GLOBAL' => (!$local) ? true : false, - 'S_NUM_CATS' => count($categories), - 'S_VIEW' => ($mode == 'view') ? true : false, - 'S_NUM_OBJECTS' => count($content_array), - 'S_USER_MODE' => ($user_mode == 'user') ? true : false, - 'S_GROUP_MODE' => ($user_mode == 'group') ? true : false) - ); - - foreach ($content_array as $ug_id => $ug_array) - { - // 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; - - foreach ($roles as $role_id => $role_row) - { - $role_description = (!empty($user->lang[$role_row['role_description']])) ? $user->lang[$role_row['role_description']] : nl2br($role_row['role_description']); - $role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name']; - - $title = ($role_description) ? ' title="' . $role_description . '"' : ''; - $s_role_options .= ''; - - $role_options[] = array( - 'ID' => $role_id, - 'ROLE_NAME' => $role_name, - 'TITLE' => $role_description, - 'SELECTED' => $role_id == $current_role_id, - ); - } - - if ($s_role_options) - { - $s_role_options = '' . $s_role_options; - } - - if (!$current_role_id && $mode != 'view') - { - $s_custom_permissions = false; - - foreach ($ug_array as $key => $value) - { - if ($value['S_NEVER'] || $value['S_YES']) - { - $s_custom_permissions = true; - break; - } - } - } - else - { - $s_custom_permissions = false; - } - - $template->assign_block_vars($tpl_pmask . '.' . $tpl_fmask, array( - 'NAME' => $ug_names_ary[$ug_id], - 'UG_ID' => $ug_id, - 'S_ROLE_OPTIONS' => $s_role_options, - 'S_CUSTOM' => $s_custom_permissions, - '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); - - unset($content_array[$ug_id]); - } - - unset($hold_ary[$forum_id]); - } - } - else - { - foreach ($ug_names_ary as $ug_id => $ug_name) - { - if (!isset($hold_ary[$ug_id])) - { - continue; - } - - $content_array = $categories = array(); - $this->build_permission_array($hold_ary[$ug_id], $content_array, $categories, array_keys($forum_names_ary)); - - $template->assign_block_vars($tpl_pmask, array( - 'NAME' => $ug_name, - 'CATEGORIES' => implode('', $categories), - - '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' => count($categories), - 'S_VIEW' => ($mode == 'view') ? true : false, - 'S_NUM_OBJECTS' => count($content_array), - 'S_USER_MODE' => ($user_mode == 'user') ? true : false, - 'S_GROUP_MODE' => ($user_mode == 'group') ? true : false) - ); - - foreach ($content_array as $forum_id => $forum_array) - { - // 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 = ''; - - foreach ($roles as $role_id => $role_row) - { - $role_description = (!empty($user->lang[$role_row['role_description']])) ? $user->lang[$role_row['role_description']] : nl2br($role_row['role_description']); - $role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name']; - - $title = ($role_description) ? ' title="' . $role_description . '"' : ''; - $s_role_options .= ''; - - $role_options[] = array( - 'ID' => $role_id, - 'ROLE_NAME' => $role_name, - 'TITLE' => $role_description, - 'SELECTED' => $role_id == $current_role_id, - ); - } - - if ($s_role_options) - { - $s_role_options = '' . $s_role_options; - } - - if (!$current_role_id && $mode != 'view') - { - $s_custom_permissions = false; - - foreach ($forum_array as $key => $value) - { - if ($value['S_NEVER'] || $value['S_YES']) - { - $s_custom_permissions = true; - break; - } - } - } - else - { - $s_custom_permissions = false; - } - - $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_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); - } - - unset($hold_ary[$ug_id], $ug_names_ary[$ug_id]); - } - } - } - - /** - * Display permission mask for roles - */ - function display_role_mask(&$hold_ary) - { - global $db, $template, $user, $phpbb_root_path, $phpEx; - global $phpbb_container; - - 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 . ' - WHERE ' . $db->sql_in_set('forum_id', array_keys($hold_ary)) . ' - ORDER BY left_id'; - $result = $db->sql_query($sql); - - // If the role is used globally, then reflect that - $forum_names = (isset($hold_ary[0])) ? array(0 => '') : array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_names[$row['forum_id']] = $row['forum_name']; - } - $db->sql_freeresult($result); - - foreach ($forum_names as $forum_id => $forum_name) - { - $auth_ary = $hold_ary[$forum_id]; - - $template->assign_block_vars('role_mask', array( - 'NAME' => ($forum_id == 0) ? $user->lang['GLOBAL_MASK'] : $forum_name, - 'FORUM_ID' => $forum_id) - ); - - if (isset($auth_ary['users']) && count($auth_ary['users'])) - { - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $auth_ary['users']) . ' - ORDER BY username_clean ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('role_mask.users', array( - 'USER_ID' => $row['user_id'], - 'USERNAME' => get_username_string('username', $row['user_id'], $row['username']), - 'U_PROFILE' => get_username_string('profile', $row['user_id'], $row['username']), - )); - } - $db->sql_freeresult($result); - } - - if (isset($auth_ary['groups']) && count($auth_ary['groups'])) - { - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', $auth_ary['groups']) . ' - ORDER BY group_type ASC, group_name'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('role_mask.groups', array( - 'GROUP_ID' => $row['group_id'], - 'GROUP_NAME' => $group_helper->get_name($row['group_name']), - 'U_PROFILE' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=group&g={$row['group_id']}")) - ); - } - $db->sql_freeresult($result); - } - } - } - - /** - * NOTE: this function is not in use atm - * Add a new option to the list ... $options is a hash of form -> - * $options = array( - * 'local' => array('option1', 'option2', ...), - * 'global' => array('optionA', 'optionB', ...) - * ); - */ - function acl_add_option($options) - { - global $db, $cache; - - if (!is_array($options)) - { - return false; - } - - $cur_options = array(); - - // Determine current options - $sql = 'SELECT auth_option, is_global, is_local - FROM ' . ACL_OPTIONS_TABLE . ' - ORDER BY auth_option_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $cur_options[$row['auth_option']] = ($row['is_global'] && $row['is_local']) ? 'both' : (($row['is_global']) ? 'global' : 'local'); - } - $db->sql_freeresult($result); - - // Here we need to insert new options ... this requires discovering whether - // an options is global, local or both and whether we need to add an permission - // set flag (x_) - $new_options = array('local' => array(), 'global' => array()); - - foreach ($options as $type => $option_ary) - { - $option_ary = array_unique($option_ary); - - foreach ($option_ary as $option_value) - { - $new_options[$type][] = $option_value; - - $flag = substr($option_value, 0, strpos($option_value, '_') + 1); - - if (!in_array($flag, $new_options[$type])) - { - $new_options[$type][] = $flag; - } - } - } - unset($options); - - $options = array(); - $options['local'] = array_diff($new_options['local'], $new_options['global']); - $options['global'] = array_diff($new_options['global'], $new_options['local']); - $options['both'] = array_intersect($new_options['local'], $new_options['global']); - - // Now check which options to add/update - $add_options = $update_options = array(); - - // First local ones... - foreach ($options as $type => $option_ary) - { - foreach ($option_ary as $option) - { - if (!isset($cur_options[$option])) - { - $add_options[] = array( - 'auth_option' => (string) $option, - 'is_global' => ($type == 'global' || $type == 'both') ? 1 : 0, - 'is_local' => ($type == 'local' || $type == 'both') ? 1 : 0 - ); - - continue; - } - - // Else, update existing entry if it is changed... - if ($type === $cur_options[$option]) - { - continue; - } - - // New type is always both: - // If is now both, we set both. - // If it was global the new one is local and we need to set it to both - // If it was local the new one is global and we need to set it to both - $update_options[] = $option; - } - } - - if (!empty($add_options)) - { - $db->sql_multi_insert(ACL_OPTIONS_TABLE, $add_options); - } - - if (!empty($update_options)) - { - $sql = 'UPDATE ' . ACL_OPTIONS_TABLE . ' - SET is_global = 1, is_local = 1 - WHERE ' . $db->sql_in_set('auth_option', $update_options); - $db->sql_query($sql); - } - - $cache->destroy('_acl_options'); - $this->acl_clear_prefetch(); - - // 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->__construct(); - - return true; - } - - /** - * Set a user or group ACL record - */ - function acl_set($ug_type, $forum_id, $ug_id, $auth, $role_id = 0, $clear_prefetch = true) - { - global $db; - - // One or more forums - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - // One or more users - if (!is_array($ug_id)) - { - $ug_id = array($ug_id); - } - - $ug_id_sql = $db->sql_in_set($ug_type . '_id', array_map('intval', $ug_id)); - $forum_sql = $db->sql_in_set('forum_id', array_map('intval', $forum_id)); - - // Instead of updating, inserting, removing we just remove all current settings and re-set everything... - $table = ($ug_type == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE; - $id_field = $ug_type . '_id'; - - // Get any flags as required - reset($auth); - $flag = key($auth); - $flag = substr($flag, 0, strpos($flag, '_') + 1); - - // This ID (the any-flag) is set if one or more permissions are true... - $any_option_id = (int) $this->acl_options['id'][$flag]; - - // Remove any-flag from auth ary - if (isset($auth[$flag])) - { - unset($auth[$flag]); - } - - // Remove current auth options... - $auth_option_ids = array((int) $any_option_id); - foreach ($auth as $auth_option => $auth_setting) - { - $auth_option_ids[] = (int) $this->acl_options['id'][$auth_option]; - } - - $sql = "DELETE FROM $table - WHERE $forum_sql - AND $ug_id_sql - AND " . $db->sql_in_set('auth_option_id', $auth_option_ids); - $db->sql_query($sql); - - // Remove those having a role assigned... the correct type of course... - $sql = 'SELECT role_id - FROM ' . ACL_ROLES_TABLE . " - WHERE role_type = '" . $db->sql_escape($flag) . "'"; - $result = $db->sql_query($sql); - - $role_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $role_ids[] = $row['role_id']; - } - $db->sql_freeresult($result); - - if (count($role_ids)) - { - $sql = "DELETE FROM $table - WHERE $forum_sql - AND $ug_id_sql - AND auth_option_id = 0 - AND " . $db->sql_in_set('auth_role_id', $role_ids); - $db->sql_query($sql); - } - - // Ok, include the any-flag if one or more auth options are set to yes... - foreach ($auth as $auth_option => $setting) - { - if ($setting == ACL_YES && (!isset($auth[$flag]) || $auth[$flag] == ACL_NEVER)) - { - $auth[$flag] = ACL_YES; - } - } - - $sql_ary = array(); - foreach ($forum_id as $forum) - { - $forum = (int) $forum; - - if ($role_id) - { - foreach ($ug_id as $id) - { - $sql_ary[] = array( - $id_field => (int) $id, - 'forum_id' => (int) $forum, - 'auth_option_id' => 0, - 'auth_setting' => 0, - 'auth_role_id' => (int) $role_id, - ); - } - } - else - { - foreach ($auth as $auth_option => $setting) - { - $auth_option_id = (int) $this->acl_options['id'][$auth_option]; - - if ($setting != ACL_NO) - { - foreach ($ug_id as $id) - { - $sql_ary[] = array( - $id_field => (int) $id, - 'forum_id' => (int) $forum, - 'auth_option_id' => (int) $auth_option_id, - 'auth_setting' => (int) $setting - ); - } - } - } - } - } - - $db->sql_multi_insert($table, $sql_ary); - - if ($clear_prefetch) - { - $this->acl_clear_prefetch(); - } - } - - /** - * Set a role-specific ACL record - */ - function acl_set_role($role_id, $auth) - { - global $db; - - // Get any-flag as required - reset($auth); - $flag = key($auth); - $flag = substr($flag, 0, strpos($flag, '_') + 1); - - // Remove any-flag from auth ary - if (isset($auth[$flag])) - { - unset($auth[$flag]); - } - - // Re-set any flag... - foreach ($auth as $auth_option => $setting) - { - if ($setting == ACL_YES && (!isset($auth[$flag]) || $auth[$flag] == ACL_NEVER)) - { - $auth[$flag] = ACL_YES; - } - } - - $sql_ary = array(); - foreach ($auth as $auth_option => $setting) - { - $auth_option_id = (int) $this->acl_options['id'][$auth_option]; - - if ($setting != ACL_NO) - { - $sql_ary[] = array( - 'role_id' => (int) $role_id, - 'auth_option_id' => (int) $auth_option_id, - 'auth_setting' => (int) $setting - ); - } - } - - // If no data is there, we set the any-flag to ACL_NEVER... - if (!count($sql_ary)) - { - $sql_ary[] = array( - 'role_id' => (int) $role_id, - 'auth_option_id' => (int) $this->acl_options['id'][$flag], - 'auth_setting' => ACL_NEVER - ); - } - - // Remove current auth options... - $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' - WHERE role_id = ' . $role_id; - $db->sql_query($sql); - - // Now insert the new values - $db->sql_multi_insert(ACL_ROLES_DATA_TABLE, $sql_ary); - - $this->acl_clear_prefetch(); - } - - /** - * Remove local permission - */ - function acl_delete($mode, $ug_id = false, $forum_id = false, $permission_type = false) - { - global $db; - - if ($ug_id === false && $forum_id === false) - { - return; - } - - $option_id_ary = array(); - $table = ($mode == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE; - $id_field = $mode . '_id'; - - $where_sql = array(); - - if ($forum_id !== false) - { - $where_sql[] = (!is_array($forum_id)) ? 'forum_id = ' . (int) $forum_id : $db->sql_in_set('forum_id', array_map('intval', $forum_id)); - } - - if ($ug_id !== false) - { - $where_sql[] = (!is_array($ug_id)) ? $id_field . ' = ' . (int) $ug_id : $db->sql_in_set($id_field, array_map('intval', $ug_id)); - } - - // There seem to be auth options involved, therefore we need to go through the list and make sure we capture roles correctly - if ($permission_type !== false) - { - // Get permission type - $sql = 'SELECT auth_option, auth_option_id - FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char()); - $result = $db->sql_query($sql); - - $auth_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $option_id_ary[] = $row['auth_option_id']; - $auth_id_ary[$row['auth_option']] = ACL_NO; - } - $db->sql_freeresult($result); - - // First of all, lets grab the items having roles with the specified auth options assigned - $sql = "SELECT auth_role_id, $id_field, forum_id - FROM $table, " . ACL_ROLES_TABLE . " r - WHERE auth_role_id <> 0 - AND auth_role_id = r.role_id - AND r.role_type = '{$permission_type}' - AND " . implode(' AND ', $where_sql) . ' - ORDER BY auth_role_id'; - $result = $db->sql_query($sql); - - $cur_role_auth = array(); - while ($row = $db->sql_fetchrow($result)) - { - $cur_role_auth[$row['auth_role_id']][$row['forum_id']][] = $row[$id_field]; - } - $db->sql_freeresult($result); - - // Get role data for resetting data - 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 - WHERE ao.auth_option_id = rd.auth_option_id - AND ' . $db->sql_in_set('rd.role_id', array_keys($cur_role_auth)); - $result = $db->sql_query($sql); - - $auth_settings = array(); - while ($row = $db->sql_fetchrow($result)) - { - // We need to fill all auth_options, else setting it will fail... - if (!isset($auth_settings[$row['role_id']])) - { - $auth_settings[$row['role_id']] = $auth_id_ary; - } - $auth_settings[$row['role_id']][$row['auth_option']] = $row['auth_setting']; - } - $db->sql_freeresult($result); - - // Set the options - foreach ($cur_role_auth as $role_id => $auth_row) - { - foreach ($auth_row as $f_id => $ug_row) - { - $this->acl_set($mode, $f_id, $ug_row, $auth_settings[$role_id], 0, false); - } - } - } - } - - // Now, normally remove permissions... - if ($permission_type !== false) - { - $where_sql[] = $db->sql_in_set('auth_option_id', array_map('intval', $option_id_ary)); - } - - $sql = "DELETE FROM $table - WHERE " . implode(' AND ', $where_sql); - $db->sql_query($sql); - - $this->acl_clear_prefetch(); - } - - /** - * Assign category to template - * used by display_mask() - */ - function assign_cat_array(&$category_array, $tpl_cat, $tpl_mask, $ug_id, $forum_id, $s_view, $show_trace = false) - { - global $template, $phpbb_admin_path, $phpEx, $phpbb_container; - - /* @var $phpbb_permissions \phpbb\permissions */ - $phpbb_permissions = $phpbb_container->get('acl.permissions'); - - foreach ($category_array as $cat => $cat_array) - { - if (!$phpbb_permissions->category_defined($cat)) - { - continue; - } - - $template->assign_block_vars($tpl_cat, array( - 'S_YES' => ($cat_array['S_YES'] && !$cat_array['S_NEVER'] && !$cat_array['S_NO']) ? true : false, - 'S_NEVER' => ($cat_array['S_NEVER'] && !$cat_array['S_YES'] && !$cat_array['S_NO']) ? true : false, - 'S_NO' => ($cat_array['S_NO'] && !$cat_array['S_NEVER'] && !$cat_array['S_YES']) ? true : false, - - 'CAT_NAME' => $phpbb_permissions->get_category_lang($cat), - )); - - /* Sort permissions by name (more naturaly and user friendly than sorting by a primary key) - * Commented out due to it's memory consumption and time needed - * - $key_array = array_intersect(array_keys($user->lang), array_map(create_function('$a', 'return "acl_" . $a;'), array_keys($cat_array['permissions']))); - $values_array = $cat_array['permissions']; - - $cat_array['permissions'] = array(); - - foreach ($key_array as $key) - { - $key = str_replace('acl_', '', $key); - $cat_array['permissions'][$key] = $values_array[$key]; - } - unset($key_array, $values_array); -*/ - foreach ($cat_array['permissions'] as $permission => $allowed) - { - if (!$phpbb_permissions->permission_defined($permission)) - { - continue; - } - - if ($s_view) - { - $template->assign_block_vars($tpl_cat . '.' . $tpl_mask, array( - 'S_YES' => ($allowed == ACL_YES) ? true : false, - 'S_NEVER' => ($allowed == ACL_NEVER) ? true : false, - - 'UG_ID' => $ug_id, - 'FORUM_ID' => $forum_id, - 'FIELD_NAME' => $permission, - 'S_FIELD_NAME' => 'setting[' . $ug_id . '][' . $forum_id . '][' . $permission . ']', - - 'U_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission") : '', - 'UA_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '', - - 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission), - )); - } - else - { - $template->assign_block_vars($tpl_cat . '.' . $tpl_mask, array( - 'S_YES' => ($allowed == ACL_YES) ? true : false, - 'S_NEVER' => ($allowed == ACL_NEVER) ? true : false, - 'S_NO' => ($allowed == ACL_NO) ? true : false, - - 'UG_ID' => $ug_id, - 'FORUM_ID' => $forum_id, - 'FIELD_NAME' => $permission, - 'S_FIELD_NAME' => 'setting[' . $ug_id . '][' . $forum_id . '][' . $permission . ']', - - 'U_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission") : '', - 'UA_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '', - - 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission), - )); - } - } - } - } - - /** - * Building content array from permission rows with explicit key ordering - * used by display_mask() - */ - function build_permission_array(&$permission_row, &$content_array, &$categories, $key_sort_array) - { - global $phpbb_container; - - /* @var $phpbb_permissions \phpbb\permissions */ - $phpbb_permissions = $phpbb_container->get('acl.permissions'); - - foreach ($key_sort_array as $forum_id) - { - if (!isset($permission_row[$forum_id])) - { - continue; - } - - $permissions = $permission_row[$forum_id]; - ksort($permissions); - - foreach ($permissions as $permission => $auth_setting) - { - $cat = $phpbb_permissions->get_permission_category($permission); - - // Build our categories array - if (!isset($categories[$cat])) - { - $categories[$cat] = $phpbb_permissions->get_category_lang($cat); - } - - // Build our content array - if (!isset($content_array[$forum_id])) - { - $content_array[$forum_id] = array(); - } - - if (!isset($content_array[$forum_id][$cat])) - { - $content_array[$forum_id][$cat] = array( - 'S_YES' => false, - 'S_NEVER' => false, - 'S_NO' => false, - 'permissions' => array(), - ); - } - - $content_array[$forum_id][$cat]['S_YES'] |= ($auth_setting == ACL_YES) ? true : false; - $content_array[$forum_id][$cat]['S_NEVER'] |= ($auth_setting == ACL_NEVER) ? true : false; - $content_array[$forum_id][$cat]['S_NO'] |= ($auth_setting == ACL_NO) ? true : false; - - $content_array[$forum_id][$cat]['permissions'][$permission] = $auth_setting; - } - } - } - - /** - * Use permissions from another user. This transferes a permission set from one user to another. - * The other user is always able to revert back to his permission set. - * This function does not check for lower/higher permissions, it is possible for the user to gain - * "more" permissions by this. - * Admin permissions will not be copied. - */ - function ghost_permissions($from_user_id, $to_user_id) - { - global $db; - - if ($to_user_id == ANONYMOUS) - { - return false; - } - - $hold_ary = $this->acl_raw_data_single_user($from_user_id); - - // Key 0 in $hold_ary are global options, all others are forum_ids - - // We disallow copying admin permissions - foreach ($this->acl_options['global'] as $opt => $id) - { - if (strpos($opt, 'a_') === 0) - { - $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_NEVER; - } - } - - // Force a_switchperm to be allowed - $hold_ary[0][$this->acl_options['id']['a_switchperm']] = ACL_YES; - - $user_permissions = $this->build_bitstring($hold_ary); - - if (!$user_permissions) - { - return false; - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_permissions = '" . $db->sql_escape($user_permissions) . "', - user_perm_from = $from_user_id - WHERE user_id = " . $to_user_id; - $db->sql_query($sql); - - return true; - } -} diff --git a/install/update/new/includes/bbcode.php b/install/update/new/includes/bbcode.php deleted file mode 100644 index 21c630d..0000000 --- a/install/update/new/includes/bbcode.php +++ /dev/null @@ -1,707 +0,0 @@ - -* @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; -} - -/** -* BBCode class -*/ -class bbcode -{ - var $bbcode_uid = ''; - var $bbcode_bitfield = ''; - var $bbcode_cache = array(); - var $bbcode_template = array(); - - var $bbcodes = array(); - - var $template_bitfield; - - /** - * Constructor - */ - function __construct($bitfield = '') - { - $this->bbcode_set_bitfield($bitfield); - } - - /** - * Init bbcode cache entries if bitfield is specified - * - * @param string $bitfield The bbcode bitfield - */ - function bbcode_set_bitfield($bitfield = '') - { - if ($bitfield) - { - $this->bbcode_bitfield = $bitfield; - $this->bbcode_cache_init(); - } - } - - /** - * Second pass bbcodes - */ - function bbcode_second_pass(&$message, $bbcode_uid = '', $bbcode_bitfield = false) - { - if ($bbcode_uid) - { - $this->bbcode_uid = $bbcode_uid; - } - - if ($bbcode_bitfield !== false) - { - $this->bbcode_bitfield = $bbcode_bitfield; - - // Init those added with a new bbcode_bitfield (already stored codes will not get parsed again) - $this->bbcode_cache_init(); - } - - if (!$this->bbcode_bitfield) - { - // Remove the uid from tags that have not been transformed into HTML - if ($this->bbcode_uid) - { - $message = str_replace(':' . $this->bbcode_uid, '', $message); - } - - return; - } - - $str = array('search' => array(), 'replace' => array()); - $preg = array('search' => array(), 'replace' => array()); - - $bitfield = new bitfield($this->bbcode_bitfield); - $bbcodes_set = $bitfield->get_all_set(); - - $undid_bbcode_specialchars = false; - foreach ($bbcodes_set as $bbcode_id) - { - if (!empty($this->bbcode_cache[$bbcode_id])) - { - foreach ($this->bbcode_cache[$bbcode_id] as $type => $array) - { - foreach ($array as $search => $replace) - { - ${$type}['search'][] = str_replace('$uid', $this->bbcode_uid, $search); - ${$type}['replace'][] = $replace; - } - - if (count($str['search'])) - { - $message = str_replace($str['search'], $str['replace'], $message); - $str = array('search' => array(), 'replace' => array()); - } - - if (count($preg['search'])) - { - // we need to turn the entities back into their original form to allow the - // search patterns to work properly - if (!$undid_bbcode_specialchars) - { - $message = str_replace(array(':', '.'), array(':', '.'), $message); - $undid_bbcode_specialchars = true; - } - - 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()); - } - } - } - } - - // Remove the uid from tags that have not been transformed into HTML - $message = str_replace(':' . $this->bbcode_uid, '', $message); - } - - /** - * Init bbcode cache - * - * requires: $this->bbcode_bitfield - * sets: $this->bbcode_cache with bbcode templates needed for bbcode_bitfield - */ - function bbcode_cache_init() - { - 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_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'); - } - - $bbcode_ids = $rowset = $sql = array(); - - $bitfield = new bitfield($this->bbcode_bitfield); - $bbcodes_set = $bitfield->get_all_set(); - - foreach ($bbcodes_set as $bbcode_id) - { - if (isset($this->bbcode_cache[$bbcode_id])) - { - // do not try to re-cache it if it's already in - continue; - } - $bbcode_ids[] = $bbcode_id; - - if ($bbcode_id > NUM_CORE_BBCODES) - { - $sql[] = $bbcode_id; - } - } - - if (count($sql)) - { - global $db; - - $sql = 'SELECT * - FROM ' . BBCODES_TABLE . ' - WHERE ' . $db->sql_in_set('bbcode_id', $sql); - $result = $db->sql_query($sql, 3600); - - while ($row = $db->sql_fetchrow($result)) - { - // To circumvent replacing newlines with
for the generated html, - // we use carriage returns here. They are later changed back to newlines - $row['bbcode_tpl'] = str_replace("\n", "\r", $row['bbcode_tpl']); - $row['second_pass_replace'] = str_replace("\n", "\r", $row['second_pass_replace']); - - $rowset[$row['bbcode_id']] = $row; - } - $db->sql_freeresult($result); - } - - // To perform custom second pass in extension, use $this->bbcode_second_pass_by_extension() - // method which accepts variable number of parameters - foreach ($bbcode_ids as $bbcode_id) - { - switch ($bbcode_id) - { - case BBCODE_ID_QUOTE: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[/quote:$uid]' => $this->bbcode_tpl('quote_close', $bbcode_id) - ), - 'preg' => array( - '#\[quote(?:="(.*?)")?:$uid\]((?!\[quote(?:=".*?")?:$uid\]).)?#is' => function ($match) { - if (!isset($match[2])) - { - $match[2] = ''; - } - - return $this->bbcode_second_pass_quote($match[1], $match[2]); - }, - ) - ); - break; - - case BBCODE_ID_B: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[b:$uid]' => $this->bbcode_tpl('b_open', $bbcode_id), - '[/b:$uid]' => $this->bbcode_tpl('b_close', $bbcode_id), - ) - ); - break; - - case BBCODE_ID_I: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[i:$uid]' => $this->bbcode_tpl('i_open', $bbcode_id), - '[/i:$uid]' => $this->bbcode_tpl('i_close', $bbcode_id), - ) - ); - break; - - case BBCODE_ID_URL: - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[url:$uid\]((.*?))\[/url:$uid\]#s' => $this->bbcode_tpl('url', $bbcode_id), - '#\[url=([^\[]+?):$uid\](.*?)\[/url:$uid\]#s' => $this->bbcode_tpl('url', $bbcode_id), - ) - ); - break; - - case BBCODE_ID_IMG: - if ($user->optionget('viewimg')) - { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[img:$uid\](.*?)\[/img:$uid\]#s' => $this->bbcode_tpl('img', $bbcode_id), - ) - ); - } - else - { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[img:$uid\](.*?)\[/img:$uid\]#s' => str_replace('$2', '[ img ]', $this->bbcode_tpl('url', $bbcode_id, true)), - ) - ); - } - break; - - case BBCODE_ID_SIZE: - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[size=([\-\+]?\d+):$uid\](.*?)\[/size:$uid\]#s' => $this->bbcode_tpl('size', $bbcode_id), - ) - ); - break; - - 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), - ) - ); - break; - - case BBCODE_ID_U: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[u:$uid]' => $this->bbcode_tpl('u_open', $bbcode_id), - '[/u:$uid]' => $this->bbcode_tpl('u_close', $bbcode_id), - ) - ); - break; - - case BBCODE_ID_CODE: - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[code(?:=([a-z]+))?:$uid\](.*?)\[/code:$uid\]#is' => function ($match) { - return $this->bbcode_second_pass_code($match[1], $match[2]); - }, - ) - ); - break; - - 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\]#' => function ($match) { - return $this->bbcode_list($match[1]); - }, - ), - 'str' => array( - '[list:$uid]' => $this->bbcode_tpl('ulist_open_default', $bbcode_id), - '[/list:u:$uid]' => $this->bbcode_tpl('ulist_close', $bbcode_id), - '[/list:o:$uid]' => $this->bbcode_tpl('olist_close', $bbcode_id), - '[*:$uid]' => $this->bbcode_tpl('listitem', $bbcode_id), - '[/*:$uid]' => $this->bbcode_tpl('listitem_close', $bbcode_id), - '[/*:m:$uid]' => $this->bbcode_tpl('listitem_close', $bbcode_id) - ), - ); - break; - - case BBCODE_ID_EMAIL: - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[email:$uid\]((.*?))\[/email:$uid\]#is' => $this->bbcode_tpl('email', $bbcode_id), - '#\[email=([^\[]+):$uid\](.*?)\[/email:$uid\]#is' => $this->bbcode_tpl('email', $bbcode_id) - ) - ); - break; - - case BBCODE_ID_FLASH: - if ($user->optionget('viewflash')) - { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#' => $this->bbcode_tpl('flash', $bbcode_id), - ) - ); - } - else - { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#' => str_replace('$1', '$3', str_replace('$2', '[ flash ]', $this->bbcode_tpl('url', $bbcode_id, true))) - ) - ); - } - break; - - case BBCODE_ID_ATTACH: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[/attachment:$uid]' => $this->bbcode_tpl('inline_attachment_close', $bbcode_id) - ), - 'preg' => array( - '#\[attachment=([0-9]+):$uid\]#' => $this->bbcode_tpl('inline_attachment_open', $bbcode_id) - ) - ); - break; - - default: - if (isset($rowset[$bbcode_id])) - { - if ($this->template_bitfield->get($bbcode_id)) - { - // The bbcode requires a custom template to be loaded - if (!$bbcode_tpl = $this->bbcode_tpl($rowset[$bbcode_id]['bbcode_tag'], $bbcode_id)) - { - // For some reason, the required template seems not to be available, use the default template - $bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl']; - } - else - { - // In order to use templates with custom bbcodes we need - // to replace all {VARS} to corresponding backreferences - // Note that backreferences are numbered from bbcode_match - if (preg_match_all('/\{(URL|LOCAL_URL|EMAIL|TEXT|SIMPLETEXT|INTTEXT|IDENTIFIER|COLOR|NUMBER)[0-9]*\}/', $rowset[$bbcode_id]['bbcode_match'], $m)) - { - foreach ($m[0] as $i => $tok) - { - $bbcode_tpl = str_replace($tok, '$' . ($i + 1), $bbcode_tpl); - } - } - } - } - else - { - // Default template - $bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl']; - } - - // Replace {L_*} lang strings - $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'])) - { - // The custom BBCode requires second-pass pattern replacements - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl) - ); - } - else - { - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl) - ); - } - } - else - { - $this->bbcode_cache[$bbcode_id] = false; - } - break; - } - } - - $bbcode_cache = $this->bbcode_cache; - $bbcode_bitfield = $this->bbcode_bitfield; - $bbcode_uid = $this->bbcode_uid; - - /** - * Use this event to modify the bbcode_cache - * - * @event core.bbcode_cache_init_end - * @var array bbcode_cache The array of cached search and replace patterns of bbcodes - * @var string bbcode_bitfield The bbcode bitfield - * @var string bbcode_uid The bbcode uid - * @since 3.1.3-RC1 - */ - $vars = array('bbcode_cache', 'bbcode_bitfield', 'bbcode_uid'); - extract($phpbb_dispatcher->trigger_event('core.bbcode_cache_init_end', compact($vars))); - - $this->bbcode_cache = $bbcode_cache; - $this->bbcode_bitfield = $bbcode_bitfield; - $this->bbcode_uid = $bbcode_uid; - } - - /** - * Return bbcode template - */ - function bbcode_tpl($tpl_name, $bbcode_id = -1, $skip_bitfield_check = false) - { - static $bbcode_hardtpl = array(); - if (empty($bbcode_hardtpl)) - { - global $user; - - $bbcode_hardtpl = array( - 'b_open' => '', - 'b_close' => '', - 'i_open' => '', - 'i_close' => '', - 'u_open' => '', - 'u_close' => '', - 'img' => '' . $user->lang['IMAGE'] . '', - 'size' => '$2', - 'color' => '$2', - 'email' => '$2' - ); - } - - if ($bbcode_id != -1 && !$skip_bitfield_check && !$this->template_bitfield->get($bbcode_id)) - { - return (isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false; - } - - if (empty($this->bbcode_template)) - { - if (($tpl = file_get_contents($this->template_filename)) === false) - { - trigger_error('Could not load bbcode template', E_USER_ERROR); - } - - // replace \ with \\ and then ' with \'. - $tpl = str_replace('\\', '\\\\', $tpl); - $tpl = str_replace("'", "\'", $tpl); - - // strip newlines and indent - $tpl = preg_replace("/\n[\n\r\s\t]*/", '', $tpl); - - // Turn template blocks into PHP assignment statements for the values of $bbcode_tpl.. - $this->bbcode_template = array(); - - // Capture the BBCode template matches - // Allow phpBB template or the Twig syntax - $matches = (preg_match_all('#(.*?)#', $tpl, $match)) ?: - preg_match_all('#{% for (.*?) in .*? %}(.*?){% endfor %}#s', $tpl, $match); - - for ($i = 0; $i < $matches; $i++) - { - if (empty($match[1][$i])) - { - continue; - } - - $this->bbcode_template[$match[1][$i]] = $this->bbcode_tpl_replace($match[1][$i], $match[2][$i]); - } - } - - return (isset($this->bbcode_template[$tpl_name])) ? $this->bbcode_template[$tpl_name] : ((isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false); - } - - /** - * Return bbcode template replacement - */ - function bbcode_tpl_replace($tpl_name, $tpl) - { - global $user; - - static $replacements = array( - 'quote_username_open' => array('{USERNAME}' => '$1'), - 'color' => array('{COLOR}' => '$1', '{TEXT}' => '$2'), - 'size' => array('{SIZE}' => '$1', '{TEXT}' => '$2'), - 'img' => array('{URL}' => '$1'), - 'flash' => array('{WIDTH}' => '$1', '{HEIGHT}' => '$2', '{URL}' => '$3'), - 'url' => array('{URL}' => '$1', '{DESCRIPTION}' => '$2'), - 'email' => array('{EMAIL}' => '$1', '{DESCRIPTION}' => '$2') - ); - - $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])) - { - $tpl = strtr($tpl, $replacements[$tpl_name]); - } - - return trim($tpl); - } - - /** - * Second parse list bbcode - */ - function bbcode_list($type) - { - if ($type == '') - { - $tpl = 'ulist_open_default'; - $type = 'default'; - } - else if ($type == 'i') - { - $tpl = 'olist_open'; - $type = 'lower-roman'; - } - else if ($type == 'I') - { - $tpl = 'olist_open'; - $type = 'upper-roman'; - } - else if (preg_match('#^(disc|circle|square)$#i', $type)) - { - $tpl = 'ulist_open'; - $type = strtolower($type); - } - else if (preg_match('#^[a-z]$#', $type)) - { - $tpl = 'olist_open'; - $type = 'lower-alpha'; - } - else if (preg_match('#[A-Z]#', $type)) - { - $tpl = 'olist_open'; - $type = 'upper-alpha'; - } - else if (is_numeric($type)) - { - $tpl = 'olist_open'; - $type = 'decimal'; - } - else - { - $tpl = 'olist_open'; - $type = 'decimal'; - } - - return str_replace('{LIST_TYPE}', $type, $this->bbcode_tpl($tpl)); - } - - /** - * Second parse quote tag - */ - function bbcode_second_pass_quote($username, $quote) - { - // when using the /e modifier, preg_replace slashes double-quotes but does not - // seem to slash anything else - $quote = str_replace('\"', '"', $quote); - $username = str_replace('\"', '"', $username); - - // remove newline at the beginning - if ($quote == "\n") - { - $quote = ''; - } - - $quote = (($username) ? str_replace('$1', $username, $this->bbcode_tpl('quote_username_open')) : $this->bbcode_tpl('quote_open')) . $quote; - - return $quote; - } - - /** - * Second parse code tag - */ - function bbcode_second_pass_code($type, $code) - { - // when using the /e modifier, preg_replace slashes double-quotes but does not - // seem to slash anything else - $code = str_replace('\"', '"', $code); - - switch ($type) - { - case 'php': - // Not the english way, but valid because of hardcoded syntax highlighting - if (strpos($code, '
') === 0) - { - $code = substr($code, 41); - } - - // no break; - - default: - $code = str_replace("\t", '   ', $code); - $code = str_replace(' ', '  ', $code); - $code = str_replace(' ', '  ', $code); - $code = str_replace("\n ", "\n ", $code); - - // keep space at the beginning - if (!empty($code) && $code[0] == ' ') - { - $code = ' ' . substr($code, 1); - } - - // remove newline at the beginning - if (!empty($code) && $code[0] == "\n") - { - $code = substr($code, 1); - } - break; - } - - $code = $this->bbcode_tpl('code_open') . $code . $this->bbcode_tpl('code_close'); - - return $code; - } - - /** - * Function to perform custom bbcode second pass by extensions - * can be used to assign bbcode pattern replacement - * Example: '#\[list=([^\[]+):$uid\]#e' => "\$this->bbcode_second_pass_by_extension('\$1')" - * - * Accepts variable number of parameters - * - * @return mixed Second pass result - */ - function bbcode_second_pass_by_extension() - { - global $phpbb_dispatcher; - - $return = false; - $params_array = func_get_args(); - - /** - * Event to perform bbcode second pass with - * the custom validating methods provided by extensions - * - * @event core.bbcode_second_pass_by_extension - * @var array params_array Array with the function parameters - * @var mixed return Second pass result to return - * - * @since 3.1.5-RC1 - */ - $vars = array('params_array', 'return'); - extract($phpbb_dispatcher->trigger_event('core.bbcode_second_pass_by_extension', compact($vars))); - - return $return; - } -} diff --git a/install/update/new/includes/compatibility_globals.php b/install/update/new/includes/compatibility_globals.php deleted file mode 100644 index 15880d4..0000000 --- a/install/update/new/includes/compatibility_globals.php +++ /dev/null @@ -1,92 +0,0 @@ - -* @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; -} - -// -// Deprecated globals -// -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_QUICKTIME', 6); // Quicktime/Mov files - @deprecated 3.2 -define('ATTACHMENT_CATEGORY_FLASH', 5); // Flash/SWF files - @deprecated 3.3 - -/** - * 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); - - /* @var $user \phpbb\user */ - $user = $phpbb_container->get('user'); - - /* @var \phpbb\language\language $language */ - $language = $phpbb_container->get('language'); - - /* @var $auth \phpbb\auth\auth */ - $auth = $phpbb_container->get('auth'); - - /* @var $db \phpbb\db\driver\driver_interface */ - $db = $phpbb_container->get('dbal.conn'); - - // 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); - - /* @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/install/update/new/includes/constants.php b/install/update/new/includes/constants.php deleted file mode 100644 index 9508ce5..0000000 --- a/install/update/new/includes/constants.php +++ /dev/null @@ -1,312 +0,0 @@ - -* @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; -} - -/** -* valid external constants: -* PHPBB_MSG_HANDLER -* PHPBB_DB_NEW_LINK -* PHPBB_ROOT_PATH -* PHPBB_ADMIN_PATH -*/ - -// phpBB Version -@define('PHPBB_VERSION', '3.3.0'); - -// QA-related -// define('PHPBB_QA', 1); - -// User related -define('ANONYMOUS', 1); - -define('USER_ACTIVATION_NONE', 0); -define('USER_ACTIVATION_SELF', 1); -define('USER_ACTIVATION_ADMIN', 2); -define('USER_ACTIVATION_DISABLE', 3); - -define('AVATAR_UPLOAD', 1); -define('AVATAR_REMOTE', 2); -define('AVATAR_GALLERY', 3); - -define('USER_NORMAL', 0); -define('USER_INACTIVE', 1); -define('USER_IGNORE', 2); -define('USER_FOUNDER', 3); - -define('INACTIVE_REGISTER', 1); // Newly registered account -define('INACTIVE_PROFILE', 2); // Profile details changed -define('INACTIVE_MANUAL', 3); // Account deactivated by administrator -define('INACTIVE_REMIND', 4); // Forced user account reactivation - -// ACL -define('ACL_NEVER', 0); -define('ACL_YES', 1); -define('ACL_NO', -1); - -// Login error codes -define('LOGIN_CONTINUE', 1); -define('LOGIN_BREAK', 2); -define('LOGIN_SUCCESS', 3); -define('LOGIN_SUCCESS_CREATE_PROFILE', 20); -define('LOGIN_SUCCESS_LINK_PROFILE', 21); -define('LOGIN_ERROR_USERNAME', 10); -define('LOGIN_ERROR_PASSWORD', 11); -define('LOGIN_ERROR_ACTIVE', 12); -define('LOGIN_ERROR_ATTEMPTS', 13); -define('LOGIN_ERROR_EXTERNAL_AUTH', 14); -define('LOGIN_ERROR_PASSWORD_CONVERT', 15); - -// Maximum login attempts -// The value is arbitrary, but it has to fit into the user_login_attempts field. -define('LOGIN_ATTEMPTS_MAX', 100); - -// Group settings -define('GROUP_OPEN', 0); -define('GROUP_CLOSED', 1); -define('GROUP_HIDDEN', 2); -define('GROUP_SPECIAL', 3); -define('GROUP_FREE', 4); - -// Forum/Topic states -define('FORUM_CAT', 0); -define('FORUM_POST', 1); -define('FORUM_LINK', 2); -define('ITEM_UNLOCKED', 0); -define('ITEM_LOCKED', 1); -define('ITEM_MOVED', 2); - -define('ITEM_UNAPPROVED', 0); // => has not yet been approved -define('ITEM_APPROVED', 1); // => has been approved, and has not been soft deleted -define('ITEM_DELETED', 2); // => has been soft deleted -define('ITEM_REAPPROVE', 3); // => has been edited and needs to be re-approved - -// Forum Flags -define('FORUM_FLAG_LINK_TRACK', 1); -define('FORUM_FLAG_PRUNE_POLL', 2); -define('FORUM_FLAG_PRUNE_ANNOUNCE', 4); -define('FORUM_FLAG_PRUNE_STICKY', 8); -define('FORUM_FLAG_ACTIVE_TOPICS', 16); -define('FORUM_FLAG_POST_REVIEW', 32); -define('FORUM_FLAG_QUICK_REPLY', 64); - -// Forum Options... sequential order. Modifications should begin at number 10 (number 29 is maximum) -define('FORUM_OPTION_FEED_NEWS', 1); -define('FORUM_OPTION_FEED_EXCLUDE', 2); - -// Optional text flags -define('OPTION_FLAG_BBCODE', 1); -define('OPTION_FLAG_SMILIES', 2); -define('OPTION_FLAG_LINKS', 4); - -// Topic types -define('POST_NORMAL', 0); -define('POST_STICKY', 1); -define('POST_ANNOUNCE', 2); -define('POST_GLOBAL', 3); - -// Lastread types -define('TRACK_NORMAL', 0); -define('TRACK_POSTED', 1); - -// Notify methods -define('NOTIFY_EMAIL', 0); -define('NOTIFY_IM', 1); -define('NOTIFY_BOTH', 2); - -// Notify status -define('NOTIFY_YES', 0); -define('NOTIFY_NO', 1); - -// Email Priority Settings -define('MAIL_LOW_PRIORITY', 4); -define('MAIL_NORMAL_PRIORITY', 3); -define('MAIL_HIGH_PRIORITY', 2); - -// Log types -define('LOG_ADMIN', 0); -define('LOG_MOD', 1); -define('LOG_CRITICAL', 2); -define('LOG_USERS', 3); - -// Private messaging - Do NOT change these values -define('PRIVMSGS_HOLD_BOX', -4); -define('PRIVMSGS_NO_BOX', -3); -define('PRIVMSGS_OUTBOX', -2); -define('PRIVMSGS_SENTBOX', -1); -define('PRIVMSGS_INBOX', 0); - -// Full Folder Actions -define('FULL_FOLDER_NONE', -3); -define('FULL_FOLDER_DELETE', -2); -define('FULL_FOLDER_HOLD', -1); - -// Download Modes - Attachments -define('INLINE_LINK', 1); -// This mode is only used internally to allow modders extending the attachment functionality -define('PHYSICAL_LINK', 2); - -// Confirm types -define('CONFIRM_REG', 1); -define('CONFIRM_LOGIN', 2); -define('CONFIRM_POST', 3); -define('CONFIRM_REPORT', 4); - -// Categories - Attachments -define('ATTACHMENT_CATEGORY_NONE', 0); -define('ATTACHMENT_CATEGORY_IMAGE', 1); // Inline Images -define('ATTACHMENT_CATEGORY_THUMB', 4); // Not used within the database, only while displaying posts - -// 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); - -// Smiley hard limit -define('SMILEY_LIMIT', 1000); - -// Magic url types -define('MAGIC_URL_EMAIL', 1); -define('MAGIC_URL_FULL', 2); -define('MAGIC_URL_LOCAL', 3); -define('MAGIC_URL_WWW', 4); - -// Profile Field Types -define('FIELD_INT', 1); -define('FIELD_STRING', 2); -define('FIELD_TEXT', 3); -define('FIELD_BOOL', 4); -define('FIELD_DROPDOWN', 5); -define('FIELD_DATE', 6); - -// referer validation -define('REFERER_VALIDATE_NONE', 0); -define('REFERER_VALIDATE_HOST', 1); -define('REFERER_VALIDATE_PATH', 2); - -// phpbb_chmod() permissions -@define('CHMOD_ALL', 7); -@define('CHMOD_READ', 4); -@define('CHMOD_WRITE', 2); -@define('CHMOD_EXECUTE', 1); - -// Captcha code length -define('CAPTCHA_MIN_CHARS', 4); -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'); -define('ACL_ROLES_DATA_TABLE', $table_prefix . 'acl_roles_data'); -define('ACL_ROLES_TABLE', $table_prefix . 'acl_roles'); -define('ACL_USERS_TABLE', $table_prefix . 'acl_users'); -define('ATTACHMENTS_TABLE', $table_prefix . 'attachments'); -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_TEXT_TABLE', $table_prefix . 'config_text'); -define('CONFIRM_TABLE', $table_prefix . 'confirm'); -define('DISALLOW_TABLE', $table_prefix . 'disallow'); -define('DRAFTS_TABLE', $table_prefix . 'drafts'); -define('EXT_TABLE', $table_prefix . 'ext'); -define('EXTENSIONS_TABLE', $table_prefix . 'extensions'); -define('EXTENSION_GROUPS_TABLE', $table_prefix . 'extension_groups'); -define('FORUMS_TABLE', $table_prefix . 'forums'); -define('FORUMS_ACCESS_TABLE', $table_prefix . 'forums_access'); -define('FORUMS_TRACK_TABLE', $table_prefix . 'forums_track'); -define('FORUMS_WATCH_TABLE', $table_prefix . 'forums_watch'); -define('GROUPS_TABLE', $table_prefix . 'groups'); -define('ICONS_TABLE', $table_prefix . 'icons'); -define('LANG_TABLE', $table_prefix . 'lang'); -define('LOG_TABLE', $table_prefix . 'log'); -define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts'); -define('MIGRATIONS_TABLE', $table_prefix . 'migrations'); -define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache'); -define('MODULES_TABLE', $table_prefix . 'modules'); -define('NOTIFICATION_TYPES_TABLE', $table_prefix . 'notification_types'); -define('NOTIFICATIONS_TABLE', $table_prefix . 'notifications'); -define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options'); -define('POLL_VOTES_TABLE', $table_prefix . 'poll_votes'); -define('POSTS_TABLE', $table_prefix . 'posts'); -define('PRIVMSGS_TABLE', $table_prefix . 'privmsgs'); -define('PRIVMSGS_FOLDER_TABLE', $table_prefix . 'privmsgs_folder'); -define('PRIVMSGS_RULES_TABLE', $table_prefix . 'privmsgs_rules'); -define('PRIVMSGS_TO_TABLE', $table_prefix . 'privmsgs_to'); -define('PROFILE_FIELDS_TABLE', $table_prefix . 'profile_fields'); -define('PROFILE_FIELDS_DATA_TABLE', $table_prefix . 'profile_fields_data'); -define('PROFILE_FIELDS_LANG_TABLE', $table_prefix . 'profile_fields_lang'); -define('PROFILE_LANG_TABLE', $table_prefix . 'profile_lang'); -define('RANKS_TABLE', $table_prefix . 'ranks'); -define('REPORTS_TABLE', $table_prefix . 'reports'); -define('REPORTS_REASONS_TABLE', $table_prefix . 'reports_reasons'); -define('SEARCH_RESULTS_TABLE', $table_prefix . 'search_results'); -define('SEARCH_WORDLIST_TABLE', $table_prefix . 'search_wordlist'); -define('SEARCH_WORDMATCH_TABLE', $table_prefix . 'search_wordmatch'); -define('SESSIONS_TABLE', $table_prefix . 'sessions'); -define('SESSIONS_KEYS_TABLE', $table_prefix . 'sessions_keys'); -define('SITELIST_TABLE', $table_prefix . 'sitelist'); -define('SMILIES_TABLE', $table_prefix . 'smilies'); -define('SPHINX_TABLE', $table_prefix . 'sphinx'); -define('STYLES_TABLE', $table_prefix . 'styles'); -define('STYLES_TEMPLATE_TABLE', $table_prefix . 'styles_template'); -define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data'); -define('STYLES_THEME_TABLE', $table_prefix . 'styles_theme'); -define('STYLES_IMAGESET_TABLE', $table_prefix . 'styles_imageset'); -define('STYLES_IMAGESET_DATA_TABLE',$table_prefix . 'styles_imageset_data'); -define('TEAMPAGE_TABLE', $table_prefix . 'teampage'); -define('TOPICS_TABLE', $table_prefix . 'topics'); -define('TOPICS_POSTED_TABLE', $table_prefix . 'topics_posted'); -define('TOPICS_TRACK_TABLE', $table_prefix . 'topics_track'); -define('TOPICS_WATCH_TABLE', $table_prefix . 'topics_watch'); -define('USER_GROUP_TABLE', $table_prefix . 'user_group'); -define('USER_NOTIFICATIONS_TABLE', $table_prefix . 'user_notifications'); -define('USERS_TABLE', $table_prefix . 'users'); -define('WARNINGS_TABLE', $table_prefix . 'warnings'); -define('WORDS_TABLE', $table_prefix . 'words'); -define('ZEBRA_TABLE', $table_prefix . 'zebra'); - -// Additional tables diff --git a/install/update/new/includes/diff/engine.php b/install/update/new/includes/diff/engine.php deleted file mode 100644 index 0d73db0..0000000 --- a/install/update/new/includes/diff/engine.php +++ /dev/null @@ -1,557 +0,0 @@ - -* @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; -} - -/** -* Code from pear.php.net, Text_Diff-1.1.0 package -* http://pear.php.net/package/Text_Diff/ (native engine) -* -* Modified by phpBB Limited to meet our coding standards -* and being able to integrate into phpBB -* -* Class used internally by Text_Diff to actually compute the diffs. This -* class is implemented using native PHP code. -* -* The algorithm used here is mostly lifted from the perl module -* Algorithm::Diff (version 1.06) by Ned Konz, which is available at: -* http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip -* -* More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html -* -* Some ideas (and a bit of code) are taken from analyze.c, of GNU -* diffutils-2.7, which can be found at: -* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz -* -* Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from -* Geoffrey T. Dairiki . The original PHP version of this -* code was written by him, and is used/adapted with his permission. -* -* Copyright 2004-2008 The Horde Project (http://www.horde.org/) -* -* @author Geoffrey T. Dairiki -* @package diff -* -* @access private -*/ -class diff_engine -{ - /** - * If set to true we trim all lines before we compare them. This ensures that sole space/tab changes do not trigger diffs. - */ - var $skip_whitespace_changes = true; - - function diff(&$from_lines, &$to_lines, $preserve_cr = true) - { - // Remove empty lines... - // If preserve_cr is true, we basically only change \r\n and bare \r to \n to get the same carriage returns for both files - // If it is false, we try to only use \n once per line and ommit all empty lines to be able to get a proper data diff - - if (is_array($from_lines)) - { - $from_lines = implode("\n", $from_lines); - } - - if (is_array($to_lines)) - { - $to_lines = implode("\n", $to_lines); - } - - if ($preserve_cr) - { - $from_lines = explode("\n", str_replace("\r", "\n", str_replace("\r\n", "\n", $from_lines))); - $to_lines = explode("\n", str_replace("\r", "\n", str_replace("\r\n", "\n", $to_lines))); - } - else - { - $from_lines = explode("\n", preg_replace('#[\n\r]+#', "\n", $from_lines)); - $to_lines = explode("\n", preg_replace('#[\n\r]+#', "\n", $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); - - // Skip leading common lines. - for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) - { - if (trim($from_lines[$skip]) !== trim($to_lines[$skip])) - { - break; - } - $this->xchanged[$skip] = $this->ychanged[$skip] = false; - } - - // Skip trailing common lines. - $xi = $n_from; - $yi = $n_to; - - for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) - { - if (trim($from_lines[$xi]) !== trim($to_lines[$yi])) - { - break; - } - $this->xchanged[$xi] = $this->ychanged[$yi] = false; - } - - // Ignore lines which do not exist in both files. - for ($xi = $skip; $xi < $n_from - $endskip; $xi++) - { - if ($this->skip_whitespace_changes) $xhash[trim($from_lines[$xi])] = 1; else $xhash[$from_lines[$xi]] = 1; - } - - for ($yi = $skip; $yi < $n_to - $endskip; $yi++) - { - $line = ($this->skip_whitespace_changes) ? trim($to_lines[$yi]) : $to_lines[$yi]; - - if (($this->ychanged[$yi] = empty($xhash[$line]))) - { - continue; - } - $yhash[$line] = 1; - $this->yv[] = $line; - $this->yind[] = $yi; - } - - for ($xi = $skip; $xi < $n_from - $endskip; $xi++) - { - $line = ($this->skip_whitespace_changes) ? trim($from_lines[$xi]) : $from_lines[$xi]; - - if (($this->xchanged[$xi] = empty($yhash[$line]))) - { - continue; - } - $this->xv[] = $line; - $this->xind[] = $xi; - } - - // Find the LCS. - $this->_compareseq(0, count($this->xv), 0, count($this->yv)); - - // Merge edits when possible. - if ($this->skip_whitespace_changes) - { - $from_lines_clean = array_map('trim', $from_lines); - $to_lines_clean = array_map('trim', $to_lines); - - $this->_shift_boundaries($from_lines_clean, $this->xchanged, $this->ychanged); - $this->_shift_boundaries($to_lines_clean, $this->ychanged, $this->xchanged); - - unset($from_lines_clean, $to_lines_clean); - } - else - { - $this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged); - $this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged); - } - - // Compute the edit operations. - $edits = array(); - $xi = $yi = 0; - - while ($xi < $n_from || $yi < $n_to) - { - // Skip matching "snake". - $copy = array(); - - while ($xi < $n_from && $yi < $n_to && !$this->xchanged[$xi] && !$this->ychanged[$yi]) - { - $copy[] = $from_lines[$xi++]; - $yi++; - } - - if ($copy) - { - $edits[] = new diff_op_copy($copy); - } - - // Find deletes & adds. - $delete = array(); - while ($xi < $n_from && $this->xchanged[$xi]) - { - $delete[] = $from_lines[$xi++]; - } - - $add = array(); - while ($yi < $n_to && $this->ychanged[$yi]) - { - $add[] = $to_lines[$yi++]; - } - - if ($delete && $add) - { - $edits[] = new diff_op_change($delete, $add); - } - else if ($delete) - { - $edits[] = new diff_op_delete($delete); - } - else if ($add) - { - $edits[] = new diff_op_add($add); - } - } - - return $edits; - } - - /** - * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF, - * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized segments. - * - * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of - * NCHUNKS+1 (X, Y) indexes giving the diving points between sub - * sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1), - * the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) == - * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM). - * - * This function assumes that the first lines of the specified portions of - * the two files do not match, and likewise that the last lines do not - * match. The caller must trim matching lines from the beginning and end - * of the portions it is going to specify. - */ - function _diag($xoff, $xlim, $yoff, $ylim, $nchunks) - { - $flip = false; - - if ($xlim - $xoff > $ylim - $yoff) - { - // Things seems faster (I'm not sure I understand why) when the shortest sequence is in X. - $flip = true; - list($xoff, $xlim, $yoff, $ylim) = array($yoff, $ylim, $xoff, $xlim); - } - - if ($flip) - { - for ($i = $ylim - 1; $i >= $yoff; $i--) - { - $ymatches[$this->xv[$i]][] = $i; - } - } - else - { - for ($i = $ylim - 1; $i >= $yoff; $i--) - { - $ymatches[$this->yv[$i]][] = $i; - } - } - - $this->lcs = 0; - $this->seq[0]= $yoff - 1; - $this->in_seq = array(); - $ymids[0] = array(); - - $numer = $xlim - $xoff + $nchunks - 1; - $x = $xoff; - - for ($chunk = 0; $chunk < $nchunks; $chunk++) - { - if ($chunk > 0) - { - for ($i = 0; $i <= $this->lcs; $i++) - { - $ymids[$i][$chunk - 1] = $this->seq[$i]; - } - } - - $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks); - - for (; $x < $x1; $x++) - { - $line = $flip ? $this->yv[$x] : $this->xv[$x]; - if (empty($ymatches[$line])) - { - continue; - } - $matches = $ymatches[$line]; - - reset($matches); - while ($y = current($matches)) - { - next($matches); - if (empty($this->in_seq[$y])) - { - $k = $this->_lcs_pos($y); - $ymids[$k] = $ymids[$k - 1]; - break; - } - } - - // no reset() here - while ($y = current($matches)) - { - next($matches); - if ($y > $this->seq[$k - 1]) - { - // Optimization: this is a common case: next match is just replacing previous match. - $this->in_seq[$this->seq[$k]] = false; - $this->seq[$k] = $y; - $this->in_seq[$y] = 1; - } - else if (empty($this->in_seq[$y])) - { - $k = $this->_lcs_pos($y); - $ymids[$k] = $ymids[$k - 1]; - } - } - } - } - - $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff); - $ymid = $ymids[$this->lcs]; - - for ($n = 0; $n < $nchunks - 1; $n++) - { - $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks); - $y1 = $ymid[$n] + 1; - $seps[] = $flip ? array($y1, $x1) : array($x1, $y1); - } - $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim); - - return array($this->lcs, $seps); - } - - function _lcs_pos($ypos) - { - $end = $this->lcs; - - if ($end == 0 || $ypos > $this->seq[$end]) - { - $this->seq[++$this->lcs] = $ypos; - $this->in_seq[$ypos] = 1; - return $this->lcs; - } - - $beg = 1; - while ($beg < $end) - { - $mid = (int)(($beg + $end) / 2); - if ($ypos > $this->seq[$mid]) - { - $beg = $mid + 1; - } - else - { - $end = $mid; - } - } - - $this->in_seq[$this->seq[$end]] = false; - $this->seq[$end] = $ypos; - $this->in_seq[$ypos] = 1; - - return $end; - } - - /** - * Finds LCS of two sequences. - * - * The results are recorded in the vectors $this->{x,y}changed[], by - * storing a 1 in the element for each line that is an insertion or - * deletion (ie. is not in the LCS). - * - * The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1. - * - * Note that XLIM, YLIM are exclusive bounds. All line numbers are - * origin-0 and discarded lines are not counted. - */ - function _compareseq($xoff, $xlim, $yoff, $ylim) - { - // Slide down the bottom initial diagonal. - while ($xoff < $xlim && $yoff < $ylim && $this->xv[$xoff] == $this->yv[$yoff]) - { - ++$xoff; - ++$yoff; - } - - // Slide up the top initial diagonal. - while ($xlim > $xoff && $ylim > $yoff && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) - { - --$xlim; - --$ylim; - } - - if ($xoff == $xlim || $yoff == $ylim) - { - $lcs = 0; - } - else - { - // This is ad hoc but seems to work well. - // $nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); - // $nchunks = max(2,min(8,(int)$nchunks)); - $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1; - list($lcs, $seps) = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks); - } - - if ($lcs == 0) - { - // X and Y sequences have no common subsequence: mark all changed. - while ($yoff < $ylim) - { - $this->ychanged[$this->yind[$yoff++]] = 1; - } - - while ($xoff < $xlim) - { - $this->xchanged[$this->xind[$xoff++]] = 1; - } - } - else - { - // Use the partitions to split this problem into subproblems. - reset($seps); - $pt1 = $seps[0]; - - while ($pt2 = next($seps)) - { - $this->_compareseq($pt1[0], $pt2[0], $pt1[1], $pt2[1]); - $pt1 = $pt2; - } - } - } - - /** - * Adjusts inserts/deletes of identical lines to join changes as much as possible. - * - * We do something when a run of changed lines include a line at one end - * and has an excluded, identical line at the other. We are free to - * choose which identical line is included. 'compareseq' usually chooses - * the one at the beginning, but usually it is cleaner to consider the - * following identical line to be the "change". - * - * This is extracted verbatim from analyze.c (GNU diffutils-2.7). - */ - function _shift_boundaries($lines, &$changed, $other_changed) - { - $i = 0; - $j = 0; - - $len = count($lines); - $other_len = count($other_changed); - - while (1) - { - // Scan forward to find the beginning of another run of - // changes. Also keep track of the corresponding point in the other file. - // - // Throughout this code, $i and $j are adjusted together so that - // the first $i elements of $changed and the first $j elements of - // $other_changed both contain the same number of zeros (unchanged lines). - // - // Furthermore, $j is always kept so that $j == $other_len or $other_changed[$j] == false. - while ($j < $other_len && $other_changed[$j]) - { - $j++; - } - - while ($i < $len && ! $changed[$i]) - { - $i++; - $j++; - - while ($j < $other_len && $other_changed[$j]) - { - $j++; - } - } - - if ($i == $len) - { - break; - } - - $start = $i; - - // Find the end of this run of changes. - while (++$i < $len && $changed[$i]) - { - continue; - } - - do - { - // Record the length of this run of changes, so that we can later determine whether the run has grown. - $runlength = $i - $start; - - // Move the changed region back, so long as the previous unchanged line matches the last changed one. - // This merges with previous changed regions. - while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) - { - $changed[--$start] = 1; - $changed[--$i] = false; - - while ($start > 0 && $changed[$start - 1]) - { - $start--; - } - - while ($other_changed[--$j]) - { - continue; - } - } - - // Set CORRESPONDING to the end of the changed run, at the last point where it corresponds to a changed run in the - // other file. CORRESPONDING == LEN means no such point has been found. - $corresponding = $j < $other_len ? $i : $len; - - // Move the changed region forward, so long as the first changed line matches the following unchanged one. - // This merges with following changed regions. - // Do this second, so that if there are no merges, the changed region is moved forward as far as possible. - while ($i < $len && $lines[$start] == $lines[$i]) - { - $changed[$start++] = false; - $changed[$i++] = 1; - - while ($i < $len && $changed[$i]) - { - $i++; - } - - $j++; - if ($j < $other_len && $other_changed[$j]) - { - $corresponding = $i; - while ($j < $other_len && $other_changed[$j]) - { - $j++; - } - } - } - } - while ($runlength != $i - $start); - - // If possible, move the fully-merged run of changes back to a corresponding run in the other file. - while ($corresponding < $i) - { - $changed[--$start] = 1; - $changed[--$i] = 0; - - while ($other_changed[--$j]) - { - continue; - } - } - } - } -} diff --git a/install/update/new/includes/functions.php b/install/update/new/includes/functions.php deleted file mode 100644 index 9759eab..0000000 --- a/install/update/new/includes/functions.php +++ /dev/null @@ -1,4630 +0,0 @@ - -* @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; -} - -// Common global functions -/** -* Load the autoloaders added by the extensions. -* -* @param string $phpbb_root_path Path to the phpbb root directory. -*/ -function phpbb_load_extensions_autoloaders($phpbb_root_path) -{ - $iterator = new \RecursiveIteratorIterator( - new \phpbb\recursive_dot_prefix_filter_iterator( - new \RecursiveDirectoryIterator( - $phpbb_root_path . 'ext/', - \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS - ) - ), - \RecursiveIteratorIterator::SELF_FIRST - ); - $iterator->setMaxDepth(2); - - foreach ($iterator as $file_info) - { - if ($file_info->getFilename() === 'vendor' && $iterator->getDepth() === 2) - { - $filename = $file_info->getRealPath() . '/autoload.php'; - if (file_exists($filename)) - { - require $filename; - } - } - } -} - -/** -* Generates an alphanumeric random string of given length -* -* @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($num_chars = 8) -{ - $range = array_merge(range('A', 'Z'), range(0, 9)); - $size = count($range); - - $output = ''; - for ($i = 0; $i < $num_chars; $i++) - { - $rand = random_int(0, $size-1); - $output .= $range[$rand]; - } - - 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) -{ - $range = array_merge(range('A', 'N'), range('P', 'Z'), range(1, 9)); - $size = count($range); - - $output = ''; - for ($i = 0; $i < $num_chars; $i++) - { - $rand = random_int(0, $size-1); - $output .= $range[$rand]; - } - - return $output; -} - -/** -* Return unique id -*/ -function unique_id() -{ - return strtolower(gen_rand_string(16)); -} - -/** -* Wrapper for mt_rand() which allows swapping $min and $max parameters. -* -* PHP does not allow us to swap the order of the arguments for mt_rand() anymore. -* (since PHP 5.3.4, see http://bugs.php.net/46587) -* -* @param int $min Lowest value to be returned -* @param int $max Highest value to be returned -* -* @return int Random integer between $min and $max (or $max and $min) -*/ -function phpbb_mt_rand($min, $max) -{ - return ($min > $max) ? mt_rand($max, $min) : mt_rand($min, $max); -} - -/** -* Wrapper for getdate() which returns the equivalent array for UTC timestamps. -* -* @param int $time Unix timestamp (optional) -* -* @return array Returns an associative array of information related to the timestamp. -* See http://www.php.net/manual/en/function.getdate.php -*/ -function phpbb_gmgetdate($time = false) -{ - if ($time === false) - { - $time = time(); - } - - // getdate() interprets timestamps in local time. - // What follows uses the fact that getdate() and - // date('Z') balance each other out. - return getdate($time - date('Z')); -} - -/** -* Return formatted string for filesizes -* -* @param mixed $value filesize in bytes -* (non-negative number; int, float or string) -* @param bool $string_only true if language string should be returned -* @param array $allowed_units only allow these units (data array indexes) -* -* @return mixed data array if $string_only is false -*/ -function get_formatted_filesize($value, $string_only = true, $allowed_units = false) -{ - global $user; - - $available_units = array( - 'tb' => array( - 'min' => 1099511627776, // pow(2, 40) - 'index' => 4, - 'si_unit' => 'TB', - 'iec_unit' => 'TIB', - ), - 'gb' => array( - 'min' => 1073741824, // pow(2, 30) - 'index' => 3, - 'si_unit' => 'GB', - 'iec_unit' => 'GIB', - ), - 'mb' => array( - 'min' => 1048576, // pow(2, 20) - 'index' => 2, - 'si_unit' => 'MB', - 'iec_unit' => 'MIB', - ), - 'kb' => array( - 'min' => 1024, // pow(2, 10) - 'index' => 1, - 'si_unit' => 'KB', - 'iec_unit' => 'KIB', - ), - 'b' => array( - 'min' => 0, - 'index' => 0, - 'si_unit' => 'BYTES', // Language index - 'iec_unit' => 'BYTES', // Language index - ), - ); - - foreach ($available_units as $si_identifier => $unit_info) - { - if (!empty($allowed_units) && $si_identifier != 'b' && !in_array($si_identifier, $allowed_units)) - { - continue; - } - - if ($value >= $unit_info['min']) - { - $unit_info['si_identifier'] = $si_identifier; - - break; - } - } - unset($available_units); - - for ($i = 0; $i < $unit_info['index']; $i++) - { - $value /= 1024; - } - $value = round($value, 2); - - // Lookup units in language dictionary - $unit_info['si_unit'] = (isset($user->lang[$unit_info['si_unit']])) ? $user->lang[$unit_info['si_unit']] : $unit_info['si_unit']; - $unit_info['iec_unit'] = (isset($user->lang[$unit_info['iec_unit']])) ? $user->lang[$unit_info['iec_unit']] : $unit_info['iec_unit']; - - // Default to IEC - $unit_info['unit'] = $unit_info['iec_unit']; - - if (!$string_only) - { - $unit_info['value'] = $value; - - return $unit_info; - } - - return $value . ' ' . $unit_info['unit']; -} - -/** -* Determine whether we are approaching the maximum execution time. Should be called once -* at the beginning of the script in which it's used. -* @return bool Either true if the maximum execution time is nearly reached, or false -* if some time is still left. -*/ -function still_on_time($extra_time = 15) -{ - static $max_execution_time, $start_time; - - $current_time = microtime(true); - - if (empty($max_execution_time)) - { - $max_execution_time = (function_exists('ini_get')) ? (int) @ini_get('max_execution_time') : (int) @get_cfg_var('max_execution_time'); - - // If zero, then set to something higher to not let the user catch the ten seconds barrier. - if ($max_execution_time === 0) - { - $max_execution_time = 50 + $extra_time; - } - - $max_execution_time = min(max(10, ($max_execution_time - $extra_time)), 50); - - // For debugging purposes - // $max_execution_time = 10; - - global $starttime; - $start_time = (empty($starttime)) ? $current_time : $starttime; - } - - return (ceil($current_time - $start_time) < $max_execution_time) ? true : false; -} - -/** -* Wrapper for version_compare() that allows using uppercase A and B -* for alpha and beta releases. -* -* See http://www.php.net/manual/en/function.version-compare.php -* -* @param string $version1 First version number -* @param string $version2 Second version number -* @param string $operator Comparison operator (optional) -* -* @return mixed Boolean (true, false) if comparison operator is specified. -* Integer (-1, 0, 1) otherwise. -*/ -function phpbb_version_compare($version1, $version2, $operator = null) -{ - $version1 = strtolower($version1); - $version2 = strtolower($version2); - - if (is_null($operator)) - { - return version_compare($version1, $version2); - } - else - { - return version_compare($version1, $version2, $operator); - } -} - -// functions used for building option fields - -/** -* Pick a language, any language ... -*/ -function language_select($default = '') -{ - global $db; - - $sql = 'SELECT lang_iso, lang_local_name - FROM ' . LANG_TABLE . ' - ORDER BY lang_english_name'; - $result = $db->sql_query($sql); - - $lang_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($row['lang_iso'] == $default) ? ' selected="selected"' : ''; - $lang_options .= ''; - } - $db->sql_freeresult($result); - - return $lang_options; -} - -/** -* Pick a template/theme combo, -*/ -function style_select($default = '', $all = false) -{ - global $db; - - $sql_where = (!$all) ? 'WHERE style_active = 1 ' : ''; - $sql = 'SELECT style_id, style_name - FROM ' . STYLES_TABLE . " - $sql_where - ORDER BY style_name"; - $result = $db->sql_query($sql); - - $style_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($row['style_id'] == $default) ? ' selected="selected"' : ''; - $style_options .= ''; - } - $db->sql_freeresult($result); - - return $style_options; -} - -/** -* Format the timezone offset with hours and minutes -* -* @param int $tz_offset Timezone offset in seconds -* @param bool $show_null Whether null offsets should be shown -* @return string Normalized offset string: -7200 => -02:00 -* 16200 => +04:30 -*/ -function phpbb_format_timezone_offset($tz_offset, $show_null = false) -{ - $sign = ($tz_offset < 0) ? '-' : '+'; - $time_offset = abs($tz_offset); - - if ($time_offset == 0 && $show_null == false) - { - return ''; - } - - $offset_seconds = $time_offset % 3600; - $offset_minutes = $offset_seconds / 60; - $offset_hours = ($time_offset - $offset_seconds) / 3600; - - $offset_string = sprintf("%s%02d:%02d", $sign, $offset_hours, $offset_minutes); - return $offset_string; -} - -/** -* Compares two time zone labels. -* Arranges them in increasing order by timezone offset. -* Places UTC before other timezones in the same offset. -*/ -function phpbb_tz_select_compare($a, $b) -{ - $a_sign = $a[3]; - $b_sign = $b[3]; - if ($a_sign != $b_sign) - { - return $a_sign == '-' ? -1 : 1; - } - - $a_offset = substr($a, 4, 5); - $b_offset = substr($b, 4, 5); - if ($a_offset == $b_offset) - { - $a_name = substr($a, 12); - $b_name = substr($b, 12); - if ($a_name == $b_name) - { - return 0; - } - else if ($a_name == 'UTC') - { - return -1; - } - else if ($b_name == 'UTC') - { - return 1; - } - else - { - return $a_name < $b_name ? -1 : 1; - } - } - else - { - if ($a_sign == '-') - { - return $a_offset > $b_offset ? -1 : 1; - } - else - { - return $a_offset < $b_offset ? -1 : 1; - } - } -} - -/** -* Return list of timezone identifiers -* We also add the selected timezone if we can create an object with it. -* DateTimeZone::listIdentifiers seems to not add all identifiers to the list, -* because some are only kept for backward compatible reasons. If the user has -* a deprecated value, we add it here, so it can still be kept. Once the user -* changed his value, there is no way back to deprecated values. -* -* @param string $selected_timezone Additional timezone that shall -* be added to the list of identiers -* @return array DateTimeZone::listIdentifiers and additional -* selected_timezone if it is a valid timezone. -*/ -function phpbb_get_timezone_identifiers($selected_timezone) -{ - $timezones = DateTimeZone::listIdentifiers(); - - if (!in_array($selected_timezone, $timezones)) - { - try - { - // Add valid timezones that are currently selected but not returned - // by DateTimeZone::listIdentifiers - $validate_timezone = new DateTimeZone($selected_timezone); - $timezones[] = $selected_timezone; - } - catch (\Exception $e) - { - } - } - - return $timezones; -} - -/** -* Options to pick a timezone and date/time -* -* @param \phpbb\template\template $template phpBB template object -* @param \phpbb\user $user Object of the current user -* @param string $default A timezone to select -* @param boolean $truncate Shall we truncate the options text -* -* @return array Returns an array containing the options for the time selector. -*/ -function phpbb_timezone_select($template, $user, $default = '', $truncate = false) -{ - static $timezones; - - $default_offset = ''; - if (!isset($timezones)) - { - $unsorted_timezones = phpbb_get_timezone_identifiers($default); - - $timezones = array(); - foreach ($unsorted_timezones as $timezone) - { - $tz = new DateTimeZone($timezone); - $dt = $user->create_datetime('now', $tz); - $offset = $dt->getOffset(); - $current_time = $dt->format($user->lang['DATETIME_FORMAT'], true); - $offset_string = phpbb_format_timezone_offset($offset, true); - $timezones['UTC' . $offset_string . ' - ' . $timezone] = array( - 'tz' => $timezone, - 'offset' => $offset_string, - 'current' => $current_time, - ); - if ($timezone === $default) - { - $default_offset = 'UTC' . $offset_string; - } - } - unset($unsorted_timezones); - - uksort($timezones, 'phpbb_tz_select_compare'); - } - - $tz_select = $opt_group = ''; - - foreach ($timezones as $key => $timezone) - { - if ($opt_group != $timezone['offset']) - { - // Generate tz_select for backwards compatibility - $tz_select .= ($opt_group) ? '' : ''; - $tz_select .= ''; - $opt_group = $timezone['offset']; - $template->assign_block_vars('timezone_select', array( - 'LABEL' => $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $timezone['current']), - 'VALUE' => $key . ' - ' . $timezone['current'], - )); - - $selected = (!empty($default_offset) && strpos($key, $default_offset) !== false) ? ' selected="selected"' : ''; - $template->assign_block_vars('timezone_date', array( - 'VALUE' => $key . ' - ' . $timezone['current'], - 'SELECTED' => !empty($selected), - 'TITLE' => $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $timezone['current']), - )); - } - - $label = $timezone['tz']; - if (isset($user->lang['timezones'][$label])) - { - $label = $user->lang['timezones'][$label]; - } - $title = $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $label); - - if ($truncate) - { - $label = truncate_string($label, 50, 255, false, '...'); - } - - // Also generate timezone_select for backwards compatibility - $selected = ($timezone['tz'] === $default) ? ' selected="selected"' : ''; - $tz_select .= ''; - $template->assign_block_vars('timezone_select.timezone_options', array( - 'TITLE' => $title, - 'VALUE' => $timezone['tz'], - 'SELECTED' => !empty($selected), - 'LABEL' => $label, - )); - } - $tz_select .= ''; - - return $tz_select; -} - -// Functions handling topic/post tracking/marking - -/** -* Marks a topic/forum as read -* Marks a topic as posted to -* -* @param string $mode (all, topics, topic, post) -* @param int|bool $forum_id Used in all, topics, and topic mode -* @param int|bool $topic_id Used in topic and post mode -* @param int $post_time 0 means current time(), otherwise to set a specific mark time -* @param int $user_id can only be used with $mode == 'post' -*/ -function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0) -{ - global $db, $user, $config; - global $request, $phpbb_container, $phpbb_dispatcher; - - $post_time = ($post_time === 0 || $post_time > time()) ? time() : (int) $post_time; - - $should_markread = true; - - /** - * This event is used for performing actions directly before marking forums, - * topics or posts as read. - * - * It is also possible to prevent the marking. For that, the $should_markread parameter - * should be set to FALSE. - * - * @event core.markread_before - * @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 - * @var bool should_markread Flag indicating if the markread should be done or not. - * @since 3.1.4-RC1 - */ - $vars = array( - 'mode', - 'forum_id', - 'topic_id', - 'post_time', - 'user_id', - 'should_markread', - ); - extract($phpbb_dispatcher->trigger_event('core.markread_before', compact($vars))); - - if (!$should_markread) - { - return; - } - - if ($mode == 'all') - { - 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(array( - 'notification.type.topic', - 'notification.type.quote', - 'notification.type.bookmark', - 'notification.type.post', - 'notification.type.approve_topic', - 'notification.type.approve_post', - ), false, $user->data['user_id'], $post_time); - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - // Mark all forums read (index page) - $tables = array(TOPICS_TRACK_TABLE, FORUMS_TRACK_TABLE); - foreach ($tables as $table) - { - $sql = 'DELETE FROM ' . $table . " - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time"; - $db->sql_query($sql); - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastmark = $post_time - WHERE user_id = {$user->data['user_id']} - AND user_lastmark < $post_time"; - $db->sql_query($sql); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - - unset($tracking_topics['tf']); - unset($tracking_topics['t']); - unset($tracking_topics['f']); - $tracking_topics['l'] = base_convert($post_time - $config['board_startdate'], 10, 36); - - $user->set_cookie('track', tracking_serialize($tracking_topics), $post_time + 31536000); - $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking_topics), \phpbb\request\request_interface::COOKIE); - - unset($tracking_topics); - - if ($user->data['is_registered']) - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastmark = $post_time - WHERE user_id = {$user->data['user_id']} - AND user_lastmark < $post_time"; - $db->sql_query($sql); - } - } - } - } - else if ($mode == 'topics') - { - // Mark all topics in forums read - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - else - { - $forum_id = array_unique($forum_id); - } - - /* @var $phpbb_notifications \phpbb\notification\manager */ - $phpbb_notifications = $phpbb_container->get('notification_manager'); - - $phpbb_notifications->mark_notifications_by_parent(array( - 'notification.type.topic', - 'notification.type.approve_topic', - ), $forum_id, $user->data['user_id'], $post_time); - - // Mark all post/quote notifications read for this user in this forum - $topic_ids = array(); - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id); - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - $phpbb_notifications->mark_notifications_by_parent(array( - 'notification.type.quote', - 'notification.type.bookmark', - 'notification.type.post', - 'notification.type.approve_post', - ), $topic_ids, $user->data['user_id'], $post_time); - - // Add 0 to forums array to mark global announcements correctly - // $forum_id[] = 0; - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql = 'DELETE FROM ' . TOPICS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time - AND " . $db->sql_in_set('forum_id', $forum_id); - $db->sql_query($sql); - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND " . $db->sql_in_set('forum_id', $forum_id); - $result = $db->sql_query($sql); - - $sql_update = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_update[] = (int) $row['forum_id']; - } - $db->sql_freeresult($result); - - if (count($sql_update)) - { - $sql = 'UPDATE ' . FORUMS_TRACK_TABLE . " - SET mark_time = $post_time - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time - AND " . $db->sql_in_set('forum_id', $sql_update); - $db->sql_query($sql); - } - - if ($sql_insert = array_diff($forum_id, $sql_update)) - { - $sql_ary = array(); - foreach ($sql_insert as $f_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user->data['user_id'], - 'forum_id' => (int) $f_id, - 'mark_time' => $post_time, - ); - } - - $db->sql_multi_insert(FORUMS_TRACK_TABLE, $sql_ary); - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking = ($tracking) ? tracking_unserialize($tracking) : array(); - - foreach ($forum_id as $f_id) - { - $topic_ids36 = (isset($tracking['tf'][$f_id])) ? $tracking['tf'][$f_id] : array(); - - if (isset($tracking['tf'][$f_id])) - { - unset($tracking['tf'][$f_id]); - } - - foreach ($topic_ids36 as $topic_id36) - { - unset($tracking['t'][$topic_id36]); - } - - if (isset($tracking['f'][$f_id])) - { - unset($tracking['f'][$f_id]); - } - - $tracking['f'][$f_id] = base_convert($post_time - $config['board_startdate'], 10, 36); - } - - if (isset($tracking['tf']) && empty($tracking['tf'])) - { - unset($tracking['tf']); - } - - $user->set_cookie('track', tracking_serialize($tracking), $post_time + 31536000); - $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking), \phpbb\request\request_interface::COOKIE); - - unset($tracking); - } - } - else if ($mode == 'topic') - { - if ($topic_id === false || $forum_id === false) - { - 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(array( - 'notification.type.topic', - 'notification.type.approve_topic', - ), $topic_id, $user->data['user_id'], $post_time); - - $phpbb_notifications->mark_notifications_by_parent(array( - 'notification.type.quote', - 'notification.type.bookmark', - 'notification.type.post', - 'notification.type.approve_post', - ), $topic_id, $user->data['user_id'], $post_time); - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql = 'UPDATE ' . TOPICS_TRACK_TABLE . " - SET mark_time = $post_time - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time - AND topic_id = $topic_id"; - $db->sql_query($sql); - - // insert row - if (!$db->sql_affectedrows()) - { - $db->sql_return_on_error(true); - - $sql_ary = array( - 'user_id' => (int) $user->data['user_id'], - 'topic_id' => (int) $topic_id, - 'forum_id' => (int) $forum_id, - 'mark_time' => $post_time, - ); - - $db->sql_query('INSERT INTO ' . TOPICS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $db->sql_return_on_error(false); - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking = ($tracking) ? tracking_unserialize($tracking) : array(); - - $topic_id36 = base_convert($topic_id, 10, 36); - - if (!isset($tracking['t'][$topic_id36])) - { - $tracking['tf'][$forum_id][$topic_id36] = true; - } - - $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... - if (strlen($request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE)) > 10000) - { - //echo 'Cookie grown too large' . print_r($tracking, true); - - // We get the ten most minimum stored time offsets and its associated topic ids - $time_keys = array(); - for ($i = 0; $i < 10 && count($tracking['t']); $i++) - { - $min_value = min($tracking['t']); - $m_tkey = array_search($min_value, $tracking['t']); - unset($tracking['t'][$m_tkey]); - - $time_keys[$m_tkey] = $min_value; - } - - // Now remove the topic ids from the array... - foreach ($tracking['tf'] as $f_id => $topic_id_ary) - { - foreach ($time_keys as $m_tkey => $min_value) - { - if (isset($topic_id_ary[$m_tkey])) - { - $tracking['f'][$f_id] = $min_value; - unset($tracking['tf'][$f_id][$m_tkey]); - } - } - } - - if ($user->data['is_registered']) - { - $user->data['user_lastmark'] = intval(base_convert(max($time_keys) + $config['board_startdate'], 36, 10)); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastmark = $post_time - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time"; - $db->sql_query($sql); - } - else - { - $tracking['l'] = max($time_keys); - } - } - - $user->set_cookie('track', tracking_serialize($tracking), $post_time + 31536000); - $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking), \phpbb\request\request_interface::COOKIE); - } - } - else if ($mode == 'post') - { - if ($topic_id === false) - { - return; - } - - $use_user_id = (!$user_id) ? $user->data['user_id'] : $user_id; - - if ($config['load_db_track'] && $use_user_id != ANONYMOUS) - { - $db->sql_return_on_error(true); - - $sql_ary = array( - 'user_id' => (int) $use_user_id, - 'topic_id' => (int) $topic_id, - 'topic_posted' => 1, - ); - - $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $db->sql_return_on_error(false); - } - } - - /** - * 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))); -} - -/** -* Get topic tracking info by using already fetched info -*/ -function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $global_announce_list = false) -{ - global $user; - - $last_read = array(); - - if (!is_array($topic_ids)) - { - $topic_ids = array($topic_ids); - } - - foreach ($topic_ids as $topic_id) - { - if (!empty($rowset[$topic_id]['mark_time'])) - { - $last_read[$topic_id] = $rowset[$topic_id]['mark_time']; - } - } - - $topic_ids = array_diff($topic_ids, array_keys($last_read)); - - if (count($topic_ids)) - { - $mark_time = array(); - - if (!empty($forum_mark_time[$forum_id]) && $forum_mark_time[$forum_id] !== false) - { - $mark_time[$forum_id] = $forum_mark_time[$forum_id]; - } - - $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user->data['user_lastmark']; - - foreach ($topic_ids as $topic_id) - { - $last_read[$topic_id] = $user_lastmark; - } - } - - return $last_read; -} - -/** -* Get topic tracking info from db (for cookie based tracking only this function is used) -*/ -function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_list = false) -{ - global $config, $user, $request; - - $last_read = array(); - - if (!is_array($topic_ids)) - { - $topic_ids = array($topic_ids); - } - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - global $db; - - $sql = 'SELECT topic_id, mark_time - FROM ' . TOPICS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND " . $db->sql_in_set('topic_id', $topic_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $last_read[$row['topic_id']] = $row['mark_time']; - } - $db->sql_freeresult($result); - - $topic_ids = array_diff($topic_ids, array_keys($last_read)); - - if (count($topic_ids)) - { - $sql = 'SELECT forum_id, mark_time - FROM ' . FORUMS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND forum_id = $forum_id"; - $result = $db->sql_query($sql); - - $mark_time = array(); - while ($row = $db->sql_fetchrow($result)) - { - $mark_time[$row['forum_id']] = $row['mark_time']; - } - $db->sql_freeresult($result); - - $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user->data['user_lastmark']; - - foreach ($topic_ids as $topic_id) - { - $last_read[$topic_id] = $user_lastmark; - } - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - global $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(); - } - - if (!$user->data['is_registered']) - { - $user_lastmark = (isset($tracking_topics['l'])) ? base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate'] : 0; - } - else - { - $user_lastmark = $user->data['user_lastmark']; - } - - foreach ($topic_ids as $topic_id) - { - $topic_id36 = base_convert($topic_id, 10, 36); - - if (isset($tracking_topics['t'][$topic_id36])) - { - $last_read[$topic_id] = base_convert($tracking_topics['t'][$topic_id36], 36, 10) + $config['board_startdate']; - } - } - - $topic_ids = array_diff($topic_ids, array_keys($last_read)); - - if (count($topic_ids)) - { - $mark_time = array(); - - if (isset($tracking_topics['f'][$forum_id])) - { - $mark_time[$forum_id] = base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']; - } - - $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user_lastmark; - - foreach ($topic_ids as $topic_id) - { - $last_read[$topic_id] = $user_lastmark; - } - } - } - - return $last_read; -} - -/** -* Get list of unread topics -* -* @param int $user_id User ID (or false for current user) -* @param string $sql_extra Extra WHERE SQL statement -* @param string $sql_sort ORDER BY SQL sorting statement -* @param string $sql_limit Limits the size of unread topics list, 0 for unlimited query -* @param string $sql_limit_offset Sets the offset of the first row to search, 0 to search from the start -* -* @return array[int][int] Topic ids as keys, mark_time of topic as value -*/ -function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $sql_limit = 1001, $sql_limit_offset = 0) -{ - global $config, $db, $user, $request; - global $phpbb_dispatcher; - - $user_id = ($user_id === false) ? (int) $user->data['user_id'] : (int) $user_id; - - // Data array we're going to return - $unread_topics = array(); - - if (empty($sql_sort)) - { - $sql_sort = 'ORDER BY t.topic_last_post_time DESC, t.topic_last_post_id DESC'; - } - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - // Get list of the unread topics - $last_mark = (int) $user->data['user_lastmark']; - - $sql_array = array( - 'SELECT' => 't.topic_id, t.topic_last_post_time, tt.mark_time as topic_mark_time, ft.mark_time as forum_mark_time', - - 'FROM' => array(TOPICS_TABLE => 't'), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(TOPICS_TRACK_TABLE => 'tt'), - 'ON' => "tt.user_id = $user_id AND t.topic_id = tt.topic_id", - ), - array( - 'FROM' => array(FORUMS_TRACK_TABLE => 'ft'), - 'ON' => "ft.user_id = $user_id AND t.forum_id = ft.forum_id", - ), - ), - - 'WHERE' => " - t.topic_last_post_time > $last_mark AND - ( - (tt.mark_time IS NOT NULL AND t.topic_last_post_time > tt.mark_time) OR - (tt.mark_time IS NULL AND ft.mark_time IS NOT NULL AND t.topic_last_post_time > ft.mark_time) OR - (tt.mark_time IS NULL AND ft.mark_time IS NULL) - ) - $sql_extra - $sql_sort", - ); - - /** - * Change SQL query for fetching unread topics data - * - * @event core.get_unread_topics_modify_sql - * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, LEFT_JOIN, WHERE - * @var int last_mark User's last_mark time - * @var string sql_extra Extra WHERE SQL statement - * @var string sql_sort ORDER BY SQL sorting statement - * @since 3.1.4-RC1 - */ - $vars = array( - 'sql_array', - 'last_mark', - 'sql_extra', - 'sql_sort', - ); - extract($phpbb_dispatcher->trigger_event('core.get_unread_topics_modify_sql', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query_limit($sql, $sql_limit, $sql_limit_offset); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id = (int) $row['topic_id']; - $unread_topics[$topic_id] = ($row['topic_mark_time']) ? (int) $row['topic_mark_time'] : (($row['forum_mark_time']) ? (int) $row['forum_mark_time'] : $last_mark); - } - $db->sql_freeresult($result); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - global $tracking_topics; - - if (empty($tracking_topics)) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', false, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - } - - if (!$user->data['is_registered']) - { - $user_lastmark = (isset($tracking_topics['l'])) ? base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate'] : 0; - } - else - { - $user_lastmark = (int) $user->data['user_lastmark']; - } - - $sql = 'SELECT t.topic_id, t.forum_id, t.topic_last_post_time - FROM ' . TOPICS_TABLE . ' t - WHERE t.topic_last_post_time > ' . $user_lastmark . " - $sql_extra - $sql_sort"; - $result = $db->sql_query_limit($sql, $sql_limit, $sql_limit_offset); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_id = (int) $row['forum_id']; - $topic_id = (int) $row['topic_id']; - $topic_id36 = base_convert($topic_id, 10, 36); - - if (isset($tracking_topics['t'][$topic_id36])) - { - $last_read = base_convert($tracking_topics['t'][$topic_id36], 36, 10) + $config['board_startdate']; - - if ($row['topic_last_post_time'] > $last_read) - { - $unread_topics[$topic_id] = $last_read; - } - } - else if (isset($tracking_topics['f'][$forum_id])) - { - $mark_time = base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']; - - if ($row['topic_last_post_time'] > $mark_time) - { - $unread_topics[$topic_id] = $mark_time; - } - } - else - { - $unread_topics[$topic_id] = $user_lastmark; - } - } - $db->sql_freeresult($result); - } - - return $unread_topics; -} - -/** -* Check for read forums and update topic tracking info accordingly -* -* @param int $forum_id the forum id to check -* @param int $forum_last_post_time the forums last post time -* @param int $f_mark_time the forums last mark time if user is registered and load_db_lastread enabled -* @param int $mark_time_forum false if the mark time needs to be obtained, else the last users forum mark time -* -* @return true if complete forum got marked read, else false. -*/ -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, $request, $phpbb_container; - - // Determine the users last forum mark time if not given. - if ($mark_time_forum === false) - { - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $mark_time_forum = (!empty($f_mark_time)) ? $f_mark_time : $user->data['user_lastmark']; - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - - $mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark']; - } - } - - // 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. - // If there are none, we mark the forum as read. - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - if ($mark_time_forum >= $forum_last_post_time) - { - // We do not need to mark read, this happened before. Therefore setting this to true - $row = true; - } - else - { - $sql = 'SELECT t.forum_id - FROM ' . TOPICS_TABLE . ' t - LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt - ON (tt.topic_id = t.topic_id - AND tt.user_id = ' . $user->data['user_id'] . ') - WHERE t.forum_id = ' . $forum_id . ' - AND t.topic_last_post_time > ' . $mark_time_forum . ' - AND t.topic_moved_id = 0 - AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.') . ' - AND (tt.topic_id IS NULL - OR tt.mark_time < t.topic_last_post_time)'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - // Get information from cookie - if (!isset($tracking_topics['tf'][$forum_id])) - { - // We do not need to mark read, this happened before. Therefore setting this to true - $row = true; - } - else - { - $sql = 'SELECT t.topic_id - FROM ' . TOPICS_TABLE . ' t - WHERE t.forum_id = ' . $forum_id . ' - AND t.topic_last_post_time > ' . $mark_time_forum . ' - AND t.topic_moved_id = 0 - AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'); - $result = $db->sql_query($sql); - - $check_forum = $tracking_topics['tf'][$forum_id]; - $unread = false; - - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($check_forum[base_convert($row['topic_id'], 10, 36)])) - { - $unread = true; - break; - } - } - $db->sql_freeresult($result); - - $row = $unread; - } - } - else - { - $row = true; - } - - if (!$row) - { - markread('topics', $forum_id); - return true; - } - - return false; -} - -/** -* Transform an array into a serialized format -*/ -function tracking_serialize($input) -{ - $out = ''; - foreach ($input as $key => $value) - { - if (is_array($value)) - { - $out .= $key . ':(' . tracking_serialize($value) . ');'; - } - else - { - $out .= $key . ':' . $value . ';'; - } - } - return $out; -} - -/** -* Transform a serialized array into an actual array -*/ -function tracking_unserialize($string, $max_depth = 3) -{ - $n = strlen($string); - if ($n > 10010) - { - die('Invalid data supplied'); - } - $data = $stack = array(); - $key = ''; - $mode = 0; - $level = &$data; - for ($i = 0; $i < $n; ++$i) - { - switch ($mode) - { - case 0: - switch ($string[$i]) - { - case ':': - $level[$key] = 0; - $mode = 1; - break; - case ')': - unset($level); - $level = array_pop($stack); - $mode = 3; - break; - default: - $key .= $string[$i]; - } - break; - - case 1: - switch ($string[$i]) - { - case '(': - if (count($stack) >= $max_depth) - { - die('Invalid data supplied'); - } - $stack[] = &$level; - $level[$key] = array(); - $level = &$level[$key]; - $key = ''; - $mode = 0; - break; - default: - $level[$key] = $string[$i]; - $mode = 2; - break; - } - break; - - case 2: - switch ($string[$i]) - { - case ')': - unset($level); - $level = array_pop($stack); - $mode = 3; - break; - case ';': - $key = ''; - $mode = 0; - break; - default: - $level[$key] .= $string[$i]; - break; - } - break; - - case 3: - switch ($string[$i]) - { - case ')': - unset($level); - $level = array_pop($stack); - break; - case ';': - $key = ''; - $mode = 0; - break; - default: - die('Invalid data supplied'); - break; - } - break; - } - } - - if (count($stack) != 0 || ($mode != 0 && $mode != 3)) - { - die('Invalid data supplied'); - } - - return $level; -} - -// Server functions (building urls, redirecting...) - -/** -* Append session id to url. -* This function supports hooks. -* -* @param string $url The url the session id needs to be appended to (can have params) -* @param mixed $params String or array of additional url parameters -* @param bool $is_amp Is url using & (true) or & (false) -* @param string $session_id Possibility to use a custom session id instead of the global one -* @param bool $is_route Is url generated by a route. -* -* @return string The corrected url. -* -* Examples: -* -* append_sid("{$phpbb_root_path}viewtopic.$phpEx?t=1&f=2"); -* append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2'); -* append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2', false); -* append_sid("{$phpbb_root_path}viewtopic.$phpEx", array('t' => 1, 'f' => 2)); -* -* -*/ -function append_sid($url, $params = false, $is_amp = true, $session_id = false, $is_route = false) -{ - global $_SID, $_EXTRA_URL, $phpbb_hook, $phpbb_path_helper; - global $phpbb_dispatcher; - - if ($params === '' || (is_array($params) && empty($params))) - { - // Do not append the ? if the param-list is empty anyway. - $params = false; - } - - // Update the root path with the correct relative web path - if (!$is_route && $phpbb_path_helper instanceof \phpbb\path_helper) - { - $url = $phpbb_path_helper->update_web_root_path($url); - } - - $append_sid_overwrite = false; - - /** - * This event can either supplement or override the append_sid() function - * - * To override this function, the event must set $append_sid_overwrite to - * the new URL value, which will be returned following the event - * - * @event core.append_sid - * @var string url The url the session id needs - * to be appended to (can have - * params) - * @var mixed params String or array of additional - * url parameters - * @var bool is_amp Is url using & (true) or - * & (false) - * @var bool|string session_id Possibility to use a custom - * session id (string) instead of - * the global one (false) - * @var bool|string append_sid_overwrite Overwrite function (string - * URL) or not (false) - * @var bool is_route Is url generated by a route. - * @since 3.1.0-a1 - */ - $vars = array('url', 'params', 'is_amp', 'session_id', 'append_sid_overwrite', 'is_route'); - extract($phpbb_dispatcher->trigger_event('core.append_sid', compact($vars))); - - if ($append_sid_overwrite) - { - return $append_sid_overwrite; - } - - // The following hook remains for backwards compatibility, though use of - // the event above is preferred. - // Developers using the hook function need to globalise the $_SID and $_EXTRA_URL on their own and also handle it appropriately. - // They could mimic most of what is within this function - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id)) - { - if ($phpbb_hook->hook_return(__FUNCTION__)) - { - return $phpbb_hook->hook_return_result(__FUNCTION__); - } - } - - $params_is_array = is_array($params); - - // Get anchor - $anchor = ''; - if (strpos($url, '#') !== false) - { - list($url, $anchor) = explode('#', $url, 2); - $anchor = '#' . $anchor; - } - else if (!$params_is_array && strpos($params, '#') !== false) - { - list($params, $anchor) = explode('#', $params, 2); - $anchor = '#' . $anchor; - } - - // Handle really simple cases quickly - if ($_SID == '' && $session_id === false && empty($_EXTRA_URL) && !$params_is_array && !$anchor) - { - if ($params === false) - { - return $url; - } - - $url_delim = (strpos($url, '?') === false) ? '?' : (($is_amp) ? '&' : '&'); - return $url . ($params !== false ? $url_delim. $params : ''); - } - - // Assign sid if session id is not specified - if ($session_id === false) - { - $session_id = $_SID; - } - - $amp_delim = ($is_amp) ? '&' : '&'; - $url_delim = (strpos($url, '?') === false) ? '?' : $amp_delim; - - // Appending custom url parameter? - $append_url = (!empty($_EXTRA_URL)) ? implode($amp_delim, $_EXTRA_URL) : ''; - - // Use the short variant if possible ;) - if ($params === false) - { - // Append session id - if (!$session_id) - { - return $url . (($append_url) ? $url_delim . $append_url : '') . $anchor; - } - else - { - return $url . (($append_url) ? $url_delim . $append_url . $amp_delim : $url_delim) . 'sid=' . $session_id . $anchor; - } - } - - // Build string if parameters are specified as array - if (is_array($params)) - { - $output = array(); - - foreach ($params as $key => $item) - { - if ($item === NULL) - { - continue; - } - - if ($key == '#') - { - $anchor = '#' . $item; - continue; - } - - $output[] = $key . '=' . $item; - } - - $params = implode($amp_delim, $output); - } - - // Append session id and parameters (even if they are empty) - // If parameters are empty, the developer can still append his/her parameters without caring about the delimiter - return $url . (($append_url) ? $url_delim . $append_url . $amp_delim : $url_delim) . $params . ((!$session_id) ? '' : $amp_delim . 'sid=' . $session_id) . $anchor; -} - -/** -* Generate board url (example: http://www.example.com/phpBB) -* -* @param bool $without_script_path if set to true the script path gets not appended (example: http://www.example.com) -* -* @return string the generated board url -*/ -function generate_board_url($without_script_path = false) -{ - global $config, $user, $request, $symfony_request; - - $server_name = $user->host; - - // Forcing server vars is the only way to specify/override the protocol - if ($config['force_server_vars'] || !$server_name) - { - $server_protocol = ($config['server_protocol']) ? $config['server_protocol'] : (($config['cookie_secure']) ? 'https://' : 'http://'); - $server_name = $config['server_name']; - $server_port = (int) $config['server_port']; - $script_path = $config['script_path']; - - $url = $server_protocol . $server_name; - $cookie_secure = $config['cookie_secure']; - } - else - { - $server_port = (int) $symfony_request->getPort(); - - $forwarded_proto = $request->server('HTTP_X_FORWARDED_PROTO'); - - if (!empty($forwarded_proto) && $forwarded_proto === 'https') - { - $server_port = 443; - } - // Do not rely on cookie_secure, users seem to think that it means a secured cookie instead of an encrypted connection - $cookie_secure = $request->is_secure() ? 1 : 0; - $url = (($cookie_secure) ? 'https://' : 'http://') . $server_name; - - $script_path = $user->page['root_script_path']; - } - - if ($server_port && (($cookie_secure && $server_port <> 443) || (!$cookie_secure && $server_port <> 80))) - { - // HTTP HOST can carry a port number (we fetch $user->host, but for old versions this may be true) - if (strpos($server_name, ':') === false) - { - $url .= ':' . $server_port; - } - } - - if (!$without_script_path) - { - $url .= $script_path; - } - - // Strip / from the end - if (substr($url, -1, 1) == '/') - { - $url = substr($url, 0, -1); - } - - return $url; -} - -/** -* Redirects the user to another page then exits the script nicely -* This function is intended for urls within the board. It's not meant to redirect to cross-domains. -* -* @param string $url The url to redirect to -* @param bool $return If true, do not redirect but return the sanitized URL. Default is no return. -* @param bool $disable_cd_check If true, redirect() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. Default is false. -*/ -function redirect($url, $return = false, $disable_cd_check = false) -{ - global $user, $phpbb_path_helper, $phpbb_dispatcher; - - if (!$user->is_setup()) - { - $user->add_lang('common'); - } - - // Make sure no &'s are in, this will break the redirect - $url = str_replace('&', '&', $url); - - // Determine which type of redirect we need to handle... - $url_parts = @parse_url($url); - - if ($url_parts === false) - { - // 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_WARNING); - } - } - else if ($url[0] == '/') - { - // Absolute uri, prepend direct url... - $url = generate_board_url(true) . $url; - } - else - { - // Relative uri - $pathinfo = pathinfo($url); - - // Is the uri pointing to the current directory? - if ($pathinfo['dirname'] == '.') - { - $url = str_replace('./', '', $url); - - // Strip / from the beginning - if ($url && substr($url, 0, 1) == '/') - { - $url = substr($url, 1); - } - } - - $url = $phpbb_path_helper->remove_web_root_path($url); - - if ($user->page['page_dir']) - { - $url = $user->page['page_dir'] . '/' . $url; - } - - $url = generate_board_url() . '/' . $url; - } - - // Clean URL and check if we go outside the forum directory - $url = $phpbb_path_helper->clean_url($url); - - if (!$disable_cd_check && strpos($url, generate_board_url(true) . '/') !== 0) - { - 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_WARNING); - } - - // Now, also check the protocol and for a valid url the last time... - $allowed_protocols = array('http', 'https', 'ftp', 'ftps'); - $url_parts = parse_url($url); - - if ($url_parts === false || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], $allowed_protocols)) - { - trigger_error('INSECURE_REDIRECT', E_USER_WARNING); - } - - /** - * Execute code and/or overwrite redirect() - * - * @event core.functions.redirect - * @var string url The url - * @var bool return If true, do not redirect but return the sanitized URL. - * @var bool disable_cd_check If true, redirect() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. - * @since 3.1.0-RC3 - */ - $vars = array('url', 'return', 'disable_cd_check'); - extract($phpbb_dispatcher->trigger_event('core.functions.redirect', compact($vars))); - - if ($return) - { - return $url; - } - else - { - garbage_collection(); - } - - // Behave as per HTTP/1.1 spec for others - header('Location: ' . $url); - exit; -} - -/** -* Re-Apply session id after page reloads -*/ -function reapply_sid($url, $is_route = false) -{ - global $phpEx, $phpbb_root_path; - - if ($url === "index.$phpEx") - { - return append_sid("index.$phpEx"); - } - else if ($url === "{$phpbb_root_path}index.$phpEx") - { - return append_sid("{$phpbb_root_path}index.$phpEx"); - } - - // Remove previously added sid - if (strpos($url, 'sid=') !== false) - { - // All kind of links - $url = preg_replace('/(\?)?(&|&)?sid=[a-z0-9]+/', '', $url); - // if the sid was the first param, make the old second as first ones - $url = preg_replace("/$phpEx(&|&)+?/", "$phpEx?", $url); - } - - return append_sid($url, false, true, false, $is_route); -} - -/** -* Returns url from the session/current page with an re-appended SID with optionally stripping vars from the url -*/ -function build_url($strip_vars = false) -{ - global $config, $user, $phpbb_path_helper; - - $page = $phpbb_path_helper->get_valid_page($user->page['page'], $config['enable_mod_rewrite']); - - // Append SID - $redirect = append_sid($page, false, false); - - if ($strip_vars !== false) - { - $redirect = $phpbb_path_helper->strip_url_params($redirect, $strip_vars, false); - } - else - { - $redirect = str_replace('&', '&', $redirect); - } - - return $redirect . ((strpos($redirect, '?') === false) ? '?' : ''); -} - -/** -* Meta refresh assignment -* Adds META template variable with meta http tag. -* -* @param int $time Time in seconds for meta refresh tag -* @param string $url URL to redirect to. The url will go through redirect() first before the template variable is assigned -* @param bool $disable_cd_check If true, meta_refresh() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. Default is false. -*/ -function meta_refresh($time, $url, $disable_cd_check = false) -{ - global $template, $refresh_data, $request; - - $url = redirect($url, true, $disable_cd_check); - if ($request->is_ajax()) - { - $refresh_data = array( - 'time' => $time, - 'url' => $url, - ); - } - else - { - // For XHTML compatibility we change back & to & - $url = str_replace('&', '&', $url); - - $template->assign_vars(array( - 'META' => '') - ); - } - - return $url; -} - -/** -* Outputs correct status line header. -* -* Depending on php sapi one of the two following forms is used: -* -* Status: 404 Not Found -* -* HTTP/1.x 404 Not Found -* -* HTTP version is taken from HTTP_VERSION environment variable, -* and defaults to 1.0. -* -* Sample usage: -* -* send_status_line(404, 'Not Found'); -* -* @param int $code HTTP status code -* @param string $message Message for the status code -* @return null -*/ -function send_status_line($code, $message) -{ - if (substr(strtolower(@php_sapi_name()), 0, 3) === 'cgi') - { - // in theory, we shouldn't need that due to php doing it. Reality offers a differing opinion, though - header("Status: $code $message", true, $code); - } - else - { - $version = phpbb_request_http_version(); - header("$version $code $message", true, $code); - } -} - -/** -* Returns the HTTP version used in the current request. -* -* Handles the case of being called before $request is present, -* in which case it falls back to the $_SERVER superglobal. -* -* @return string HTTP version -*/ -function phpbb_request_http_version() -{ - global $request; - - $version = ''; - if ($request && $request->server('SERVER_PROTOCOL')) - { - $version = $request->server('SERVER_PROTOCOL'); - } - else if (isset($_SERVER['SERVER_PROTOCOL'])) - { - $version = $_SERVER['SERVER_PROTOCOL']; - } - - if (!empty($version) && is_string($version) && preg_match('#^HTTP/[0-9]\.[0-9]$#', $version)) - { - return $version; - } - - return 'HTTP/1.0'; -} - -//Form validation - - -/** -* Add a secret hash for use in links/GET requests -* @param string $link_name The name of the link; has to match the name used in check_link_hash, otherwise no restrictions apply -* @return string the hash - -*/ -function generate_link_hash($link_name) -{ - global $user; - - if (!isset($user->data["hash_$link_name"])) - { - $user->data["hash_$link_name"] = substr(sha1($user->data['user_form_salt'] . $link_name), 0, 8); - } - - return $user->data["hash_$link_name"]; -} - - -/** -* checks a link hash - for GET requests -* @param string $token the submitted token -* @param string $link_name The name of the link -* @return boolean true if all is fine -*/ -function check_link_hash($token, $link_name) -{ - return $token === generate_link_hash($link_name); -} - -/** -* Add a secret token to the form (requires the S_FORM_TOKEN template variable) -* @param string $form_name The name of the form; has to match the name used in check_form_key, otherwise no restrictions apply -* @param string $template_variable_suffix A string that is appended to the name of the template variable to which the form elements are assigned -*/ -function add_form_key($form_name, $template_variable_suffix = '') -{ - global $config, $template, $user, $phpbb_dispatcher; - - $now = time(); - $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : ''; - $token = sha1($now . $user->data['user_form_salt'] . $form_name . $token_sid); - - $s_fields = build_hidden_fields(array( - 'creation_time' => $now, - 'form_token' => $token, - )); - - /** - * Perform additional actions on creation of the form token - * - * @event core.add_form_key - * @var string form_name The form name - * @var int now Current time timestamp - * @var string s_fields Generated hidden fields - * @var string token Form token - * @var string token_sid User session ID - * @var string template_variable_suffix The string that is appended to template variable name - * - * @since 3.1.0-RC3 - * @changed 3.1.11-RC1 Added template_variable_suffix - */ - $vars = array( - 'form_name', - 'now', - 's_fields', - 'token', - 'token_sid', - 'template_variable_suffix', - ); - extract($phpbb_dispatcher->trigger_event('core.add_form_key', compact($vars))); - - $template->assign_var('S_FORM_TOKEN' . $template_variable_suffix, $s_fields); -} - -/** - * Check the form key. Required for all altering actions not secured by confirm_box - * - * @param string $form_name The name of the form; has to match the name used - * in add_form_key, otherwise no restrictions apply - * @param int $timespan The maximum acceptable age for a submitted form - * in seconds. Defaults to the config setting. - * @return bool True, if the form key was valid, false otherwise - */ -function check_form_key($form_name, $timespan = false) -{ - global $config, $request, $user; - - if ($timespan === false) - { - // we enforce a minimum value of half a minute here. - $timespan = ($config['form_token_lifetime'] == -1) ? -1 : max(30, $config['form_token_lifetime']); - } - - if ($request->is_set_post('creation_time') && $request->is_set_post('form_token')) - { - $creation_time = abs($request->variable('creation_time', 0)); - $token = $request->variable('form_token', ''); - - $diff = time() - $creation_time; - - // If creation_time and the time() now is zero we can assume it was not a human doing this (the check for if ($diff)... - if (defined('DEBUG_TEST') || $diff && ($diff <= $timespan || $timespan === -1)) - { - $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : ''; - $key = sha1($creation_time . $user->data['user_form_salt'] . $form_name . $token_sid); - - if ($key === $token) - { - return true; - } - } - } - - return false; -} - -// Message/Login boxes - -/** -* Build Confirm box -* @param boolean $check True for checking if confirmed (without any additional parameters) and false for displaying the 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, $language, $phpbb_path_helper, $phpbb_dispatcher; - - if (isset($_POST['cancel'])) - { - return false; - } - - $confirm = ($language->lang('YES') === $request->variable('confirm', '', true, \phpbb\request\request_interface::POST)); - - if ($check && $confirm) - { - $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']) - { - return false; - } - - // Reset user_last_confirm_key - $sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '' - WHERE user_id = " . $user->data['user_id']; - $db->sql_query($sql); - - return true; - } - else if ($check) - { - return false; - } - - $s_hidden_fields = build_hidden_fields(array( - 'confirm_uid' => $user->data['user_id'], - 'sess' => $user->session_id, - 'sid' => $user->session_id, - )); - - // 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($confirm_title); - } - else - { - page_header($confirm_title); - } - - $template->set_filenames(array( - 'body' => $html_body) - ); - - // If activation key already exist, we better do not re-use the key (something very strange is going on...) - if ($request->variable('confirm_key', '')) - { - // This should not occur, therefore we cancel the operation to safe the user - return false; - } - - // re-add sid / transform & to & for user->page (user->page is always using &) - $use_page = ($u_action) ? $u_action : str_replace('&', '&', $user->page['page']); - $u_action = reapply_sid($phpbb_path_helper->get_valid_page($use_page, $config['enable_mod_rewrite'])); - $u_action .= ((strpos($u_action, '?') === false) ? '?' : '&') . 'confirm_key=' . $confirm_key; - - $template->assign_vars(array( - 'MESSAGE_TITLE' => $confirm_title, - 'MESSAGE_TEXT' => $confirm_text, - - 'YES_VALUE' => $language->lang('YES'), - 'S_CONFIRM_ACTION' => $u_action, - 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields, - 'S_AJAX_REQUEST' => $request->is_ajax(), - )); - - $sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "' - WHERE user_id = " . $user->data['user_id']; - $db->sql_query($sql); - - if ($request->is_ajax()) - { - $u_action .= '&confirm_uid=' . $user->data['user_id'] . '&sess=' . $user->session_id . '&sid=' . $user->session_id; - $data = array( - 'MESSAGE_BODY' => $template->assign_display('body'), - 'MESSAGE_TITLE' => $confirm_title, - 'MESSAGE_TEXT' => $confirm_text, - - 'YES_VALUE' => $language->lang('YES'), - 'S_CONFIRM_ACTION' => str_replace('&', '&', $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']) - { - adm_page_footer(); - } - else - { - page_footer(); - } - - exit; // unreachable, page_footer() above will call exit() -} - -/** -* Generate login box or verify password -*/ -function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true) -{ - global $user, $template, $auth, $phpEx, $phpbb_root_path, $config; - global $request, $phpbb_container, $phpbb_dispatcher, $phpbb_log; - - $err = ''; - $form_name = 'login'; - $username = $autologin = false; - - // Make sure user->setup() has been called - if (!$user->is_setup()) - { - $user->setup(); - } - - /** - * This event allows an extension to modify the login process - * - * @event core.login_box_before - * @var string redirect Redirect string - * @var string l_explain Explain language string - * @var string l_success Success language string - * @var bool admin Is admin? - * @var bool s_display Display full login form? - * @var string err Error string - * @since 3.1.9-RC1 - */ - $vars = array('redirect', 'l_explain', 'l_success', 'admin', 's_display', 'err'); - extract($phpbb_dispatcher->trigger_event('core.login_box_before', compact($vars))); - - // Print out error if user tries to authenticate as an administrator without having the privileges... - if ($admin && !$auth->acl_get('a_')) - { - // Not authd - // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions - if ($user->data['is_registered']) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL'); - } - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_ADMIN'); - } - - if (empty($err) && ($request->is_set_post('login') || ($request->is_set('login') && $request->variable('login', '') == 'external'))) - { - // Get credential - if ($admin) - { - $credential = $request->variable('credential', ''); - - if (strspn($credential, 'abcdef0123456789') !== strlen($credential) || strlen($credential) != 32) - { - if ($user->data['is_registered']) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL'); - } - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_ADMIN'); - } - - $password = $request->untrimmed_variable('password_' . $credential, '', true); - } - else - { - $password = $request->untrimmed_variable('password', '', true); - } - - $username = $request->variable('username', '', true); - $autologin = $request->is_set_post('autologin'); - $viewonline = (int) !$request->is_set_post('viewonline'); - $admin = ($admin) ? 1 : 0; - $viewonline = ($admin) ? $user->data['session_viewonline'] : $viewonline; - - // Check if the supplied username is equal to the one stored within the database if re-authenticating - if ($admin && utf8_clean_string($username) != utf8_clean_string($user->data['username'])) - { - // We log the attempt to use a different username... - $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'); - } - - // 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 - if ($admin) - { - if ($result['status'] == LOGIN_SUCCESS) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_SUCCESS'); - } - else - { - // Only log the failed attempt if a real user tried to. - // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions - if ($user->data['is_registered']) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL'); - } - } - } - - // The result parameter is always an array, holding the relevant information... - if ($result['status'] == LOGIN_SUCCESS) - { - $redirect = $request->variable('redirect', "{$phpbb_root_path}index.$phpEx"); - - /** - * This event allows an extension to modify the redirection when a user successfully logs in - * - * @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', 'result'); - extract($phpbb_dispatcher->trigger_event('core.login_box_redirect', compact($vars))); - - // append/replace SID (may change during the session for AOL users) - $redirect = reapply_sid($redirect); - - // Special case... the user is effectively banned, but we allow founders to login - if (defined('IN_CHECK_BAN') && $result['user_row']['user_type'] != USER_FOUNDER) - { - return; - } - - redirect($redirect); - } - - // Something failed, determine what... - if ($result['status'] == LOGIN_BREAK) - { - trigger_error($result['error_msg']); - } - - // Special cases... determine - switch ($result['status']) - { - case LOGIN_ERROR_PASSWORD_CONVERT: - $err = sprintf( - $user->lang[$result['error_msg']], - ($config['email_enable']) ? '' : '', - ($config['email_enable']) ? '' : '', - '', - '' - ); - break; - - case LOGIN_ERROR_ATTEMPTS: - - $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); - $captcha->init(CONFIRM_LOGIN); - // $captcha->reset(); - - $template->assign_vars(array( - 'CAPTCHA_TEMPLATE' => $captcha->get_template(), - )); - // no break; - - // Username, password, etc... - default: - $err = $user->lang[$result['error_msg']]; - - // Assign admin contact to some error messages - if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' || $result['error_msg'] == 'LOGIN_ERROR_PASSWORD') - { - $err = sprintf($user->lang[$result['error_msg']], '', ''); - } - - break; - } - - /** - * This event allows an extension to process when a user fails a login attempt - * - * @event core.login_box_failed - * @var array result Login result data - * @var string username User name used to login - * @var string password Password used to login - * @var string err Error message - * @since 3.1.3-RC1 - */ - $vars = array('result', 'username', 'password', 'err'); - extract($phpbb_dispatcher->trigger_event('core.login_box_failed', compact($vars))); - } - - // Assign credential for username/password pair - $credential = ($admin) ? md5(unique_id()) : false; - - $s_hidden_fields = array( - 'sid' => $user->session_id, - ); - - if ($redirect) - { - $s_hidden_fields['redirect'] = $redirect; - } - - if ($admin) - { - $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(); - - $auth_provider_data = $auth_provider->get_login_data(); - if ($auth_provider_data) - { - if (isset($auth_provider_data['VARS'])) - { - $template->assign_vars($auth_provider_data['VARS']); - } - - if (isset($auth_provider_data['BLOCK_VAR_NAME'])) - { - foreach ($auth_provider_data['BLOCK_VARS'] as $block_vars) - { - $template->assign_block_vars($auth_provider_data['BLOCK_VAR_NAME'], $block_vars); - } - } - - $template->assign_vars(array( - 'PROVIDER_TEMPLATE_FILE' => $auth_provider_data['TEMPLATE_FILE'], - )); - } - - $s_hidden_fields = build_hidden_fields($s_hidden_fields); - - /** @var \phpbb\controller\helper $controller_helper */ - $controller_helper = $phpbb_container->get('controller.helper'); - - $login_box_template_data = array( - 'LOGIN_ERROR' => $err, - 'LOGIN_EXPLAIN' => $l_explain, - - 'U_SEND_PASSWORD' => ($config['email_enable']) ? $controller_helper->route('phpbb_ucp_forgot_password_controller') : '', - '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, - - 'S_ADMIN_AUTH' => $admin, - 'USERNAME' => ($admin) ? $user->data['username'] : '', - - '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']); - - $template->set_filenames(array( - 'body' => 'login_body.html') - ); - make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - - page_footer(); -} - -/** -* Generate forum login box -*/ -function login_forum_box($forum_data) -{ - global $db, $phpbb_container, $request, $template, $user, $phpbb_dispatcher, $phpbb_root_path, $phpEx; - - $password = $request->variable('password', '', true); - - $sql = 'SELECT forum_id - FROM ' . FORUMS_ACCESS_TABLE . ' - WHERE forum_id = ' . $forum_data['forum_id'] . ' - AND user_id = ' . $user->data['user_id'] . " - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return true; - } - - if ($password) - { - // Remove expired authorised sessions - $sql = 'SELECT f.session_id - FROM ' . FORUMS_ACCESS_TABLE . ' f - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (f.session_id = s.session_id) - WHERE s.session_id IS NULL'; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - do - { - $sql_in[] = (string) $row['session_id']; - } - while ($row = $db->sql_fetchrow($result)); - - // Remove expired sessions - $sql = 'DELETE FROM ' . FORUMS_ACCESS_TABLE . ' - WHERE ' . $db->sql_in_set('session_id', $sql_in); - $db->sql_query($sql); - } - $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'])) - { - $sql_ary = array( - 'forum_id' => (int) $forum_data['forum_id'], - 'user_id' => (int) $user->data['user_id'], - 'session_id' => (string) $user->session_id, - ); - - $db->sql_query('INSERT INTO ' . FORUMS_ACCESS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - return true; - } - - $template->assign_var('LOGIN_ERROR', $user->lang['WRONG_PASSWORD']); - } - - /** - * Performing additional actions, load additional data on forum login - * - * @event core.login_forum_box - * @var array forum_data Array with forum data - * @var string password Password entered - * @since 3.1.0-RC3 - */ - $vars = array('forum_data', 'password'); - extract($phpbb_dispatcher->trigger_event('core.login_forum_box', compact($vars))); - - page_header($user->lang['LOGIN']); - - $template->assign_vars(array( - 'FORUM_NAME' => isset($forum_data['forum_name']) ? $forum_data['forum_name'] : '', - 'S_LOGIN_ACTION' => build_url(array('f')), - 'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id']))) - ); - - $template->set_filenames(array( - 'body' => 'login_forum.html') - ); - - make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_data['forum_id']); - - page_footer(); -} - -// Little helpers - -/** -* Little helper for the build_hidden_fields function -*/ -function _build_hidden_fields($key, $value, $specialchar, $stripslashes) -{ - $hidden_fields = ''; - - if (!is_array($value)) - { - $value = ($stripslashes) ? stripslashes($value) : $value; - $value = ($specialchar) ? htmlspecialchars($value, ENT_COMPAT, 'UTF-8') : $value; - - $hidden_fields .= '' . "\n"; - } - else - { - foreach ($value as $_key => $_value) - { - $_key = ($stripslashes) ? stripslashes($_key) : $_key; - $_key = ($specialchar) ? htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') : $_key; - - $hidden_fields .= _build_hidden_fields($key . '[' . $_key . ']', $_value, $specialchar, $stripslashes); - } - } - - return $hidden_fields; -} - -/** -* Build simple hidden fields from array -* -* @param array $field_ary an array of values to build the hidden field from -* @param bool $specialchar if true, keys and values get specialchared -* @param bool $stripslashes if true, keys and values get stripslashed -* -* @return string the hidden fields -*/ -function build_hidden_fields($field_ary, $specialchar = false, $stripslashes = false) -{ - $s_hidden_fields = ''; - - foreach ($field_ary as $name => $vars) - { - $name = ($stripslashes) ? stripslashes($name) : $name; - $name = ($specialchar) ? htmlspecialchars($name, ENT_COMPAT, 'UTF-8') : $name; - - $s_hidden_fields .= _build_hidden_fields($name, $vars, $specialchar, $stripslashes); - } - - return $s_hidden_fields; -} - -/** -* Parse cfg file -*/ -function parse_cfg_file($filename, $lines = false) -{ - $parsed_items = array(); - - if ($lines === false) - { - $lines = file($filename); - } - - foreach ($lines as $line) - { - $line = trim($line); - - if (!$line || $line[0] == '#' || ($delim_pos = strpos($line, '=')) === false) - { - continue; - } - - // Determine first occurrence, since in values the equal sign is allowed - $key = htmlspecialchars(strtolower(trim(substr($line, 0, $delim_pos)))); - $value = trim(substr($line, $delim_pos + 1)); - - if (in_array($value, array('off', 'false', '0'))) - { - $value = false; - } - else if (in_array($value, array('on', 'true', '1'))) - { - $value = true; - } - else if (!trim($value)) - { - $value = ''; - } - else if (($value[0] == "'" && $value[strlen($value) - 1] == "'") || ($value[0] == '"' && $value[strlen($value) - 1] == '"')) - { - $value = htmlspecialchars(substr($value, 1, strlen($value)-2)); - } - else - { - $value = htmlspecialchars($value); - } - - $parsed_items[$key] = $value; - } - - if (isset($parsed_items['parent']) && isset($parsed_items['name']) && $parsed_items['parent'] == $parsed_items['name']) - { - unset($parsed_items['parent']); - } - - return $parsed_items; -} - -/** -* Return a nicely formatted backtrace. -* -* Turns the array returned by debug_backtrace() into HTML markup. -* Also filters out absolute paths to phpBB root. -* -* @return string HTML markup -*/ -function get_backtrace() -{ - $output = '
'; - $backtrace = debug_backtrace(); - - // We skip the first one, because it only shows this file/function - unset($backtrace[0]); - - foreach ($backtrace as $trace) - { - // Strip the current directory from path - $trace['file'] = (empty($trace['file'])) ? '(not given by php)' : htmlspecialchars(phpbb_filter_root_path($trace['file'])); - $trace['line'] = (empty($trace['line'])) ? '(not given by php)' : $trace['line']; - - // Only show function arguments for include etc. - // Other parameters may contain sensible information - $argument = ''; - if (!empty($trace['args'][0]) && in_array($trace['function'], array('include', 'require', 'include_once', 'require_once'))) - { - $argument = htmlspecialchars(phpbb_filter_root_path($trace['args'][0])); - } - - $trace['class'] = (!isset($trace['class'])) ? '' : $trace['class']; - $trace['type'] = (!isset($trace['type'])) ? '' : $trace['type']; - - $output .= '
'; - $output .= 'FILE: ' . $trace['file'] . '
'; - $output .= 'LINE: ' . ((!empty($trace['line'])) ? $trace['line'] : '') . '
'; - - $output .= 'CALL: ' . htmlspecialchars($trace['class'] . $trace['type'] . $trace['function']); - $output .= '(' . (($argument !== '') ? "'$argument'" : '') . ')
'; - } - $output .= '
'; - return $output; -} - -/** -* This function returns a regular expression pattern for commonly used expressions -* Use with / as delimiter for email mode and # for url modes -* mode can be: email|bbcode_htm|url|url_inline|www_url|www_url_inline|relative_url|relative_url_inline|ipv4|ipv6 -*/ -function get_preg_expression($mode) -{ - switch ($mode) - { - case 'email': - // Regex written by James Watts and Francisco Jose Martin Moreno - // http://fightingforalostcause.net/misc/2006/compare-email-regex.php - return '((?:[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+)@((((([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})?)'; - break; - - case 'bbcode_htm': - return array( - '#.*?#', - '#.*?#', - '#\2#', - '#.*?#', - '#(?:0|[1-9](?:(?:0|[1-9])+)*))[.](?(?:0|[1-9](?:(?:0|[1-9])+)*))[.](?(?:0|[1-9](?:(?:0|[1-9])+)*))(?:-(?(?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:0|[1-9](?:(?:0|[1-9])+)*))(?:[.](?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:0|[1-9](?:(?:0|[1-9])+)*)))*))?(?:[+](?(?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:(?:0|[1-9])+))(?:[.](?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:(?:0|[1-9])+)))*))?)$/'; - break; - } - - return ''; -} - -/** -* Generate regexp for naughty words censoring -* Depends on whether installed PHP version supports unicode properties -* -* @param string $word word template to be replaced -* -* @return string $preg_expr regex to use with word censor -*/ -function get_censor_preg_expression($word) -{ - // Unescape the asterisk to simplify further conversions - $word = str_replace('\*', '*', preg_quote($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 = '#(?getParameter('debug.show_errors') ? E_ALL : error_reporting())) == 0) - { - return; - } - - if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false) - { - $errfile = phpbb_filter_root_path($errfile); - $msg_text = phpbb_filter_root_path($msg_text); - $error_name = ($errno === E_WARNING) ? 'PHP Warning' : 'PHP Notice'; - echo '[phpBB Debug] ' . $error_name . ': in file ' . $errfile . ' on line ' . $errline . ': ' . $msg_text . '
' . "\n"; - - // we are writing an image - the user won't see the debug, so let's place it in the log - if (defined('IMAGE_OUTPUT') || defined('IN_CRON')) - { - $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_IMAGE_GENERATION_ERROR', false, array($errfile, $errline, $msg_text)); - } - // echo '

BACKTRACE
' . get_backtrace() . '
' . "\n"; - } - - return; - - break; - - case E_USER_ERROR: - - 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); - - $l_return_index = sprintf($user->lang['RETURN_INDEX'], '', ''); - $l_notify = ''; - - if (!empty($config['board_contact'])) - { - $l_notify = '

' . sprintf($user->lang['NOTIFY_ADMIN_EMAIL'], $config['board_contact']) . '

'; - } - } - else - { - $msg_title = 'General Error'; - $l_return_index = 'Return to index page'; - $l_notify = ''; - - if (!empty($config['board_contact'])) - { - $l_notify = '

Please notify the board administrator or webmaster: ' . $config['board_contact'] . '

'; - } - } - - $log_text = $msg_text; - $backtrace = get_backtrace(); - if ($backtrace) - { - $log_text .= '

BACKTRACE
' . $backtrace; - } - - if (defined('IN_INSTALL') || ($phpbb_container != null && $phpbb_container->getParameter('debug.show_errors')) || isset($auth) && $auth->acl_get('a_')) - { - $msg_text = $log_text; - - // If this is defined there already was some output - // So let's not break it - if (defined('IN_DB_UPDATE')) - { - echo '
' . $msg_text . '
'; - - $db->sql_return_on_error(true); - phpbb_end_update($cache, $config); - } - } - - if ((defined('IN_CRON') || defined('IMAGE_OUTPUT')) && isset($db)) - { - // let's avoid loops - $db->sql_return_on_error(true); - $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); - } - - // Do not send 200 OK, but service unavailable on errors - send_status_line(503, 'Service Unavailable'); - - garbage_collection(); - - // Try to not call the adm page data... - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '' . $msg_title . ''; - echo ''; - echo ''; - echo ''; - echo '
'; - echo ' '; - echo '
'; - echo '
'; - echo '
'; - echo '

' . $msg_title . '

'; - - echo '
' . $msg_text . '
'; - - echo $l_notify; - - echo '
'; - echo '
'; - echo '
'; - echo ' '; - echo '
'; - echo ''; - echo ''; - - exit_handler(); - - // On a fatal error (and E_USER_ERROR *is* fatal) we never want other scripts to continue and force an exit here. - exit; - break; - - case E_USER_WARNING: - case E_USER_NOTICE: - - define('IN_ERROR_HANDLER', true); - - if (empty($user->data)) - { - $user->session_begin(); - } - - // We re-init the auth array to get correct results on login/logout - $auth->acl($user->data); - - if (!$user->is_setup()) - { - $user->setup(); - } - - if ($msg_text == 'ERROR_NO_ATTACHMENT' || $msg_text == 'NO_FORUM' || $msg_text == 'NO_TOPIC' || $msg_text == 'NO_USER') - { - send_status_line(404, 'Not Found'); - } - - $msg_text = (!empty($user->lang[$msg_text])) ? $user->lang[$msg_text] : $msg_text; - $msg_title = (!isset($msg_title)) ? $user->lang['INFORMATION'] : ((!empty($user->lang[$msg_title])) ? $user->lang[$msg_title] : $msg_title); - - if (!defined('HEADER_INC')) - { - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_header($msg_title); - } - else - { - page_header($msg_title); - } - } - - $template->set_filenames(array( - 'body' => 'message_body.html') - ); - - $template->assign_vars(array( - 'MESSAGE_TITLE' => $msg_title, - 'MESSAGE_TEXT' => $msg_text, - 'S_USER_WARNING' => ($errno == E_USER_WARNING) ? true : false, - 'S_USER_NOTICE' => ($errno == E_USER_NOTICE) ? true : false) - ); - - if ($request->is_ajax()) - { - global $refresh_data; - - $json_response = new \phpbb\json_response; - $json_response->send(array( - 'MESSAGE_TITLE' => $msg_title, - 'MESSAGE_TEXT' => $msg_text, - 'S_USER_WARNING' => ($errno == E_USER_WARNING) ? true : false, - 'S_USER_NOTICE' => ($errno == E_USER_NOTICE) ? true : false, - 'REFRESH_DATA' => (!empty($refresh_data)) ? $refresh_data : null - )); - } - - // We do not want the cron script to be called on error messages - define('IN_CRON', true); - - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_footer(); - } - else - { - page_footer(); - } - - exit_handler(); - break; - - // PHP4 compatibility - case E_DEPRECATED: - return true; - break; - } - - // If we notice an error not handled here we pass this back to PHP by returning false - // This may not work for all php versions - return false; -} - -/** -* Removes absolute path to phpBB root directory from error messages -* and converts backslashes to forward slashes. -* -* @param string $errfile Absolute file path -* (e.g. /var/www/phpbb3/phpBB/includes/functions.php) -* Please note that if $errfile is outside of the phpBB root, -* the root path will not be found and can not be filtered. -* @return string Relative file path -* (e.g. /includes/functions.php) -*/ -function phpbb_filter_root_path($errfile) -{ - global $phpbb_filesystem; - - static $root_path; - - if (empty($root_path)) - { - 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); -} - -/** -* Queries the session table to get information about online guests -* @param int $item_id Limits the search to the item with this id -* @param string $item The name of the item which is stored in the session table as session_{$item}_id -* @return int The number of active distinct guest sessions -*/ -function obtain_guest_count($item_id = 0, $item = 'forum') -{ - global $db, $config; - - if ($item_id) - { - $reading_sql = ' AND s.session_' . $item . '_id = ' . (int) $item_id; - } - else - { - $reading_sql = ''; - } - $time = (time() - (intval($config['load_online_time']) * 60)); - - // Get number of online guests - - if ($db->get_sql_layer() === 'sqlite3') - { - $sql = 'SELECT COUNT(session_ip) as num_guests - FROM ( - SELECT DISTINCT s.session_ip - FROM ' . SESSIONS_TABLE . ' s - WHERE s.session_user_id = ' . ANONYMOUS . ' - AND s.session_time >= ' . ($time - ((int) ($time % 60))) . - $reading_sql . - ')'; - } - else - { - $sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests - FROM ' . SESSIONS_TABLE . ' s - WHERE s.session_user_id = ' . ANONYMOUS . ' - AND s.session_time >= ' . ($time - ((int) ($time % 60))) . - $reading_sql; - } - $result = $db->sql_query($sql); - $guests_online = (int) $db->sql_fetchfield('num_guests'); - $db->sql_freeresult($result); - - return $guests_online; -} - -/** -* Queries the session table to get information about online users -* @param int $item_id Limits the search to the item with this id -* @param string $item The name of the item which is stored in the session table as session_{$item}_id -* @return array An array containing the ids of online, hidden and visible users, as well as statistical info -*/ -function obtain_users_online($item_id = 0, $item = 'forum') -{ - global $db, $config; - - $reading_sql = ''; - if ($item_id !== 0) - { - $reading_sql = ' AND s.session_' . $item . '_id = ' . (int) $item_id; - } - - $online_users = array( - 'online_users' => array(), - 'hidden_users' => array(), - 'total_online' => 0, - 'visible_online' => 0, - 'hidden_online' => 0, - 'guests_online' => 0, - ); - - if ($config['load_online_guests']) - { - $online_users['guests_online'] = obtain_guest_count($item_id, $item); - } - - // a little discrete magic to cache this for 30 seconds - $time = (time() - (intval($config['load_online_time']) * 60)); - - $sql = 'SELECT s.session_user_id, s.session_ip, s.session_viewonline - FROM ' . SESSIONS_TABLE . ' s - WHERE s.session_time >= ' . ($time - ((int) ($time % 30))) . - $reading_sql . - ' AND s.session_user_id <> ' . ANONYMOUS; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - // Skip multiple sessions for one user - if (!isset($online_users['online_users'][$row['session_user_id']])) - { - $online_users['online_users'][$row['session_user_id']] = (int) $row['session_user_id']; - if ($row['session_viewonline']) - { - $online_users['visible_online']++; - } - else - { - $online_users['hidden_users'][$row['session_user_id']] = (int) $row['session_user_id']; - $online_users['hidden_online']++; - } - } - } - $online_users['total_online'] = $online_users['guests_online'] + $online_users['visible_online'] + $online_users['hidden_online']; - $db->sql_freeresult($result); - - return $online_users; -} - -/** -* Uses the result of obtain_users_online to generate a localized, readable representation. -* @param mixed $online_users result of obtain_users_online - array with user_id lists for total, hidden and visible users, and statistics -* @param int $item_id Indicate that the data is limited to one item and not global -* @param string $item The name of the item which is stored in the session table as session_{$item}_id -* @return array An array containing the string for output to the template -*/ -function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum') -{ - global $config, $db, $user, $auth, $phpbb_dispatcher; - - $user_online_link = $rowset = array(); - // Need caps version of $item for language-strings - $item_caps = strtoupper($item); - - 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', - 'FROM' => array( - USERS_TABLE => 'u', - ), - 'WHERE' => $db->sql_in_set('u.user_id', $online_users['online_users']), - 'ORDER_BY' => 'u.username_clean ASC', - ); - - /** - * Modify SQL query to obtain online users data - * - * @event core.obtain_users_online_string_sql - * @var array online_users Array with online users data - * from obtain_users_online() - * @var int item_id Restrict online users to item id - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var array sql_ary SQL query array to obtain users online data - * @since 3.1.4-RC1 - * @changed 3.1.7-RC1 Change sql query into array and adjust var accordingly. Allows extension authors the ability to adjust the sql_ary. - */ - $vars = array('online_users', 'item_id', 'item', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_sql', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - $rowset = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - foreach ($rowset as $row) - { - // User is logged in and therefore not a guest - if ($row['user_id'] != ANONYMOUS) - { - if (isset($online_users['hidden_users'][$row['user_id']])) - { - $row['username'] = '' . $row['username'] . ''; - } - - if (!isset($online_users['hidden_users'][$row['user_id']]) || $auth->acl_get('u_viewonline') || $row['user_id'] === $user->data['user_id']) - { - $user_online_link[$row['user_id']] = get_username_string(($row['user_type'] <> USER_IGNORE) ? 'full' : 'no_profile', $row['user_id'], $row['username'], $row['user_colour']); - } - } - } - } - - /** - * Modify online userlist data - * - * @event core.obtain_users_online_string_before_modify - * @var array online_users Array with online users data - * from obtain_users_online() - * @var int item_id Restrict online users to item id - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var array rowset Array with online users data - * @var array user_online_link Array with online users items (usernames) - * @since 3.1.10-RC1 - */ - $vars = array( - 'online_users', - 'item_id', - 'item', - 'rowset', - 'user_online_link', - ); - extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_before_modify', compact($vars))); - - $online_userlist = implode(', ', $user_online_link); - - if (!$online_userlist) - { - $online_userlist = $user->lang['NO_ONLINE_USERS']; - } - - if ($item_id === 0) - { - $online_userlist = $user->lang['REGISTERED_USERS'] . ' ' . $online_userlist; - } - else if ($config['load_online_guests']) - { - $online_userlist = $user->lang('BROWSING_' . $item_caps . '_GUESTS', $online_users['guests_online'], $online_userlist); - } - else - { - $online_userlist = sprintf($user->lang['BROWSING_' . $item_caps], $online_userlist); - } - // Build online listing - $visible_online = $user->lang('REG_USERS_TOTAL', (int) $online_users['visible_online']); - $hidden_online = $user->lang('HIDDEN_USERS_TOTAL', (int) $online_users['hidden_online']); - - if ($config['load_online_guests']) - { - $guests_online = $user->lang('GUEST_USERS_TOTAL', (int) $online_users['guests_online']); - $l_online_users = $user->lang('ONLINE_USERS_TOTAL_GUESTS', (int) $online_users['total_online'], $visible_online, $hidden_online, $guests_online); - } - else - { - $l_online_users = $user->lang('ONLINE_USERS_TOTAL', (int) $online_users['total_online'], $visible_online, $hidden_online); - } - - /** - * Modify online userlist data - * - * @event core.obtain_users_online_string_modify - * @var array online_users Array with online users data - * from obtain_users_online() - * @var int item_id Restrict online users to item id - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var array rowset Array with online users data - * @var array user_online_link Array with online users items (usernames) - * @var string online_userlist String containing users online list - * @var string l_online_users String with total online users count info - * @since 3.1.4-RC1 - */ - $vars = array( - 'online_users', - 'item_id', - 'item', - 'rowset', - 'user_online_link', - 'online_userlist', - 'l_online_users', - ); - extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_modify', compact($vars))); - - return array( - 'online_userlist' => $online_userlist, - 'l_online_users' => $l_online_users, - ); -} - -/** -* Get option bitfield from custom data -* -* @param int $bit The bit/value to get -* @param int $data Current bitfield to check -* @return bool Returns true if value of constant is set in bitfield, else false -*/ -function phpbb_optionget($bit, $data) -{ - return ($data & 1 << (int) $bit) ? true : false; -} - -/** -* Set option bitfield -* -* @param int $bit The bit/value to set/unset -* @param bool $set True if option should be set, false if option should be unset. -* @param int $data Current bitfield to change -* -* @return int The new bitfield -*/ -function phpbb_optionset($bit, $set, $data) -{ - if ($set && !($data & 1 << $bit)) - { - $data += 1 << $bit; - } - else if (!$set && ($data & 1 << $bit)) - { - $data -= 1 << $bit; - } - - return $data; -} - -/** -* Login using http authenticate. -* -* @param array $param Parameter array, see $param_defaults array. -* -* @return null -*/ -function phpbb_http_login($param) -{ - global $auth, $user, $request; - global $config; - - $param_defaults = array( - 'auth_message' => '', - - 'autologin' => false, - 'viewonline' => true, - 'admin' => false, - ); - - // Overwrite default values with passed values - $param = array_merge($param_defaults, $param); - - // User is already logged in - // We will not overwrite his session - if (!empty($user->data['is_registered'])) - { - return; - } - - // $_SERVER keys to check - $username_keys = array( - 'PHP_AUTH_USER', - 'Authorization', - 'REMOTE_USER', 'REDIRECT_REMOTE_USER', - 'HTTP_AUTHORIZATION', 'REDIRECT_HTTP_AUTHORIZATION', - 'REMOTE_AUTHORIZATION', 'REDIRECT_REMOTE_AUTHORIZATION', - 'AUTH_USER', - ); - - $password_keys = array( - 'PHP_AUTH_PW', - 'REMOTE_PASSWORD', - 'AUTH_PASSWORD', - ); - - $username = null; - foreach ($username_keys as $k) - { - if ($request->is_set($k, \phpbb\request\request_interface::SERVER)) - { - $username = htmlspecialchars_decode($request->server($k)); - break; - } - } - - $password = null; - foreach ($password_keys as $k) - { - if ($request->is_set($k, \phpbb\request\request_interface::SERVER)) - { - $password = htmlspecialchars_decode($request->server($k)); - break; - } - } - - // Decode encoded information (IIS, CGI, FastCGI etc.) - if (!is_null($username) && is_null($password) && strpos($username, 'Basic ') === 0) - { - list($username, $password) = explode(':', base64_decode(substr($username, 6)), 2); - } - - if (!is_null($username) && !is_null($password)) - { - set_var($username, $username, 'string', true); - set_var($password, $password, 'string', true); - - $auth_result = $auth->login($username, $password, $param['autologin'], $param['viewonline'], $param['admin']); - - if ($auth_result['status'] == LOGIN_SUCCESS) - { - return; - } - else if ($auth_result['status'] == LOGIN_ERROR_ATTEMPTS) - { - send_status_line(401, 'Unauthorized'); - - trigger_error('NOT_AUTHORISED'); - } - } - - // Prepend sitename to auth_message - $param['auth_message'] = ($param['auth_message'] === '') ? $config['sitename'] : $config['sitename'] . ' - ' . $param['auth_message']; - - // We should probably filter out non-ASCII characters - RFC2616 - $param['auth_message'] = preg_replace('/[\x80-\xFF]/', '?', $param['auth_message']); - - header('WWW-Authenticate: Basic realm="' . $param['auth_message'] . '"'); - send_status_line(401, 'Unauthorized'); - - trigger_error('NOT_AUTHORISED'); -} - -/** -* Escapes and quotes a string for use as an HTML/XML attribute value. -* -* This is a port of Python xml.sax.saxutils quoteattr. -* -* The function will attempt to choose a quote character in such a way as to -* avoid escaping quotes in the string. If this is not possible the string will -* be wrapped in double quotes and double quotes will be escaped. -* -* @param string $data The string to be escaped -* @param array $entities Associative array of additional entities to be escaped -* @return string Escaped and quoted string -*/ -function phpbb_quoteattr($data, $entities = null) -{ - $data = str_replace('&', '&', $data); - $data = str_replace('>', '>', $data); - $data = str_replace('<', '<', $data); - - $data = str_replace("\n", ' ', $data); - $data = str_replace("\r", ' ', $data); - $data = str_replace("\t", ' ', $data); - - if (!empty($entities)) - { - $data = str_replace(array_keys($entities), array_values($entities), $data); - } - - if (strpos($data, '"') !== false) - { - if (strpos($data, "'") !== false) - { - $data = '"' . str_replace('"', '"', $data) . '"'; - } - else - { - $data = "'" . $data . "'"; - } - } - else - { - $data = '"' . $data . '"'; - } - - return $data; -} - -/** -* Converts query string (GET) parameters in request into hidden fields. -* -* Useful for forwarding GET parameters when submitting forms with GET method. -* -* It is possible to omit some of the GET parameters, which is useful if -* they are specified in the form being submitted. -* -* sid is always omitted. -* -* @param \phpbb\request\request $request Request object -* @param array $exclude A list of variable names that should not be forwarded -* @return string HTML with hidden fields -*/ -function phpbb_build_hidden_fields_for_query_params($request, $exclude = null) -{ - $names = $request->variable_names(\phpbb\request\request_interface::GET); - $hidden = ''; - foreach ($names as $name) - { - // Sessions are dealt with elsewhere, omit sid always - if ($name == 'sid') - { - continue; - } - - // Omit any additional parameters requested - if (!empty($exclude) && in_array($name, $exclude)) - { - continue; - } - - $escaped_name = phpbb_quoteattr($name); - - // Note: we might retrieve the variable from POST or cookies - // here. To avoid exposing cookies, skip variables that are - // overwritten somewhere other than GET entirely. - $value = $request->variable($name, '', true); - $get_value = $request->variable($name, '', true, \phpbb\request\request_interface::GET); - if ($value === $get_value) - { - $escaped_value = phpbb_quoteattr($value); - $hidden .= ""; - } - } - return $hidden; -} - -/** -* Get user avatar -* -* @param array $user_row Row from the users table -* @param string $alt Optional language string for alt tag within image, can be a language key or text -* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP -* @param bool $lazy If true, will be lazy loaded (requires JS) -* -* @return string Avatar html -*/ -function phpbb_get_user_avatar($user_row, $alt = 'USER_AVATAR', $ignore_config = false, $lazy = false) -{ - $row = \phpbb\avatar\manager::clean_row($user_row, 'user'); - return phpbb_get_avatar($row, $alt, $ignore_config, $lazy); -} - -/** -* 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 phpbb_get_group_avatar($group_row, $alt = 'GROUP_AVATAR', $ignore_config = false, $lazy = false) -{ - $row = \phpbb\avatar\manager::clean_row($group_row, 'group'); - return phpbb_get_avatar($row, $alt, $ignore_config, $lazy); -} - -/** -* Get avatar -* -* @param array $row Row cleaned by \phpbb\avatar\manager::clean_row -* @param string $alt Optional language string for alt tag within image, can be a language key or text -* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP -* @param bool $lazy If true, will be lazy loaded (requires JS) -* -* @return string Avatar html -*/ -function phpbb_get_avatar($row, $alt, $ignore_config = false, $lazy = false) -{ - global $user, $config; - global $phpbb_container, $phpbb_dispatcher; - - if (!$config['allow_avatar'] && !$ignore_config) - { - return ''; - } - - $avatar_data = array( - 'src' => $row['avatar'], - 'width' => $row['avatar_width'], - '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 = ''; - - if ($driver) - { - $html = $driver->get_custom_html($user, $row, $alt); - $avatar_data = $driver->get_data($row); - } - else - { - $avatar_data['src'] = ''; - } - - if (empty($html) && !empty($avatar_data['src'])) - { - if ($lazy) - { - // Determine board url - we may need it later - $board_url = generate_board_url() . '/'; - // 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. - $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; - - $theme = "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme'; - - $src = 'src="' . $theme . '/images/no_avatar.gif" data-src="' . $avatar_data['src'] . '"'; - } - else - { - $src = 'src="' . $avatar_data['src'] . '"'; - } - - $html = ''; - } - - /** - * Event to modify HTML tag of avatar - * - * @event core.get_avatar_after - * @var array row Row cleaned by \phpbb\avatar\manager::clean_row - * @var string alt Optional language string for alt tag within image, can be a language key or text - * @var bool ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP - * @var array avatar_data The HTML attributes for avatar tag - * @var string html The HTML tag of generated avatar - * @since 3.1.6-RC1 - */ - $vars = array('row', 'alt', 'ignore_config', 'avatar_data', 'html'); - extract($phpbb_dispatcher->trigger_event('core.get_avatar_after', compact($vars))); - - return $html; -} - -/** -* Generate page header -*/ -function page_header($page_title = '', $display_online_list = false, $item_id = 0, $item = 'forum', $send_headers = true) -{ - global $db, $config, $template, $SID, $_SID, $_EXTRA_URL, $user, $auth, $phpEx, $phpbb_root_path; - global $phpbb_dispatcher, $request, $phpbb_container, $phpbb_admin_path; - - if (defined('HEADER_INC')) - { - return; - } - - define('HEADER_INC', true); - - // A listener can set this variable to `true` when it overrides this function - $page_header_override = false; - - /** - * Execute code and/or overwrite page_header() - * - * @event core.page_header - * @var string page_title Page title - * @var bool display_online_list Do we display online users list - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var int item_id Restrict online users to item id - * @var bool page_header_override Shall we return instead of running - * the rest of page_header() - * @since 3.1.0-a1 - */ - $vars = array('page_title', 'display_online_list', 'item_id', 'item', 'page_header_override'); - extract($phpbb_dispatcher->trigger_event('core.page_header', compact($vars))); - - if ($page_header_override) - { - return; - } - - // gzip_compression - if ($config['gzip_compress']) - { - // to avoid partially compressed output resulting in blank pages in - // the browser or error messages, compression is disabled in a few cases: - // - // 1) if headers have already been sent, this indicates plaintext output - // has been started so further content must not be compressed - // 2) the length of the current output buffer is non-zero. This means - // there is already some uncompressed content in this output buffer - // so further output must not be compressed - // 3) if more than one level of output buffering is used because we - // cannot test all output buffer level content lengths. One level - // could be caused by php.ini output_buffering. Anything - // beyond that is manual, so the code wrapping phpBB in output buffering - // can easily compress the output itself. - // - if (@extension_loaded('zlib') && !headers_sent() && ob_get_level() <= 1 && ob_get_length() == 0) - { - ob_start('ob_gzhandler'); - } - } - - $user->update_session_infos(); - - // Generate logged in/logged out status - if ($user->data['user_id'] != ANONYMOUS) - { - $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout', true, $user->session_id); - $l_login_logout = $user->lang['LOGOUT']; - } - else - { - $redirect = $request->variable('redirect', rawurlencode($user->page['page'])); - $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login&redirect=' . $redirect); - $l_login_logout = $user->lang['LOGIN']; - } - - // Last visit date/time - $s_last_visit = ($user->data['user_id'] != ANONYMOUS) ? $user->format_date($user->data['session_last_visit']) : ''; - - // Get users online list ... if required - $l_online_users = $online_userlist = $l_online_record = $l_online_time = ''; - - if ($config['load_online'] && $config['load_online_time'] && $display_online_list) - { - /** - * Load online data: - * For obtaining another session column use $item and $item_id in the function-parameter, whereby the column is session_{$item}_id. - */ - $item_id = max($item_id, 0); - - $online_users = obtain_users_online($item_id, $item); - $user_online_strings = obtain_users_online_string($online_users, $item_id, $item); - - $l_online_users = $user_online_strings['l_online_users']; - $online_userlist = $user_online_strings['online_userlist']; - $total_online_users = $online_users['total_online']; - - if ($total_online_users > $config['record_online_users']) - { - $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)); - - $l_online_time = $user->lang('VIEW_ONLINE_TIMES', (int) $config['load_online_time']); - } - - $s_privmsg_new = false; - - // Check for new private messages if user is logged in - if (!empty($user->data['is_registered'])) - { - if ($user->data['user_new_privmsg']) - { - if (!$user->data['user_last_privmsg'] || $user->data['user_last_privmsg'] > $user->data['session_last_visit']) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_last_privmsg = ' . $user->data['session_last_visit'] . ' - WHERE user_id = ' . $user->data['user_id']; - $db->sql_query($sql); - - $s_privmsg_new = true; - } - else - { - $s_privmsg_new = false; - } - } - else - { - $s_privmsg_new = false; - } - } - - $forum_id = $request->variable('f', 0); - $topic_id = $request->variable('t', 0); - - $s_feed_news = false; - - // Get option for news - if ($config['feed_enable']) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0'); - $result = $db->sql_query_limit($sql, 1, 0, 600); - $s_feed_news = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - } - - // Determine board url - we may need it later - $board_url = generate_board_url() . '/'; - // 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; - - // Send a proper content-language to the output - $user_lang = $user->lang['USER_LANG']; - if (strpos($user_lang, '-x-') !== false) - { - $user_lang = substr($user_lang, 0, strpos($user_lang, '-x-')); - } - - $s_search_hidden_fields = array(); - if ($_SID) - { - $s_search_hidden_fields['sid'] = $_SID; - } - - if (!empty($_EXTRA_URL)) - { - foreach ($_EXTRA_URL as $url_param) - { - $url_param = explode('=', $url_param, 2); - $s_search_hidden_fields[$url_param[0]] = $url_param[1]; - } - } - - $dt = $user->create_datetime(); - $timezone_offset = $user->lang(array('timezones', 'UTC_OFFSET'), phpbb_format_timezone_offset($dt->getOffset())); - $timezone_name = $user->timezone->getName(); - if (isset($user->lang['timezones'][$timezone_name])) - { - $timezone_name = $user->lang['timezones'][$timezone_name]; - } - - // Output the notifications - $notifications = false; - 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('notification.method.board', array( - 'all_unread' => true, - 'limit' => 5, - )); - - foreach ($notifications['notifications'] as $notification) - { - $template->assign_block_vars('notifications', $notification->prepare_for_display()); - } - } - - /** @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: 4.0.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'], - 'SITE_DESCRIPTION' => $config['site_desc'], - 'PAGE_TITLE' => $page_title, - 'SCRIPT_NAME' => str_replace('.' . $phpEx, '', $user->page['page_name']), - 'LAST_VISIT_DATE' => sprintf($user->lang['YOU_LAST_VISIT'], $s_last_visit), - 'LAST_VISIT_YOU' => $s_last_visit, - 'CURRENT_TIME' => sprintf($user->lang['CURRENT_TIME'], $user->format_date(time(), false, true)), - 'TOTAL_USERS_ONLINE' => $l_online_users, - 'LOGGED_IN_USER_LIST' => $online_userlist, - 'RECORD_USERS' => $l_online_record, - - 'PRIVATE_MESSAGE_COUNT' => (!empty($user->data['user_unread_privmsg'])) ? $user->data['user_unread_privmsg'] : 0, - 'CURRENT_USER_AVATAR' => phpbb_get_user_avatar($user->data), - 'CURRENT_USERNAME_SIMPLE' => get_username_string('no_profile', $user->data['user_id'], $user->data['username'], $user->data['user_colour']), - 'CURRENT_USERNAME_FULL' => get_username_string('full', $user->data['user_id'], $user->data['username'], $user->data['user_colour']), - 'UNREAD_NOTIFICATIONS_COUNT' => ($notifications !== false) ? $notifications['unread_count'] : '', - 'NOTIFICATIONS_COUNT' => ($notifications !== false) ? $notifications['unread_count'] : '', - '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&mode=notification_list&mark=all&token=' . $notification_mark_hash), - 'U_NOTIFICATION_SETTINGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications&mode=notification_options'), - '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'], - 'S_USER_NEW' => $user->data['user_new'], - - 'SID' => $SID, - '_SID' => $_SID, - 'SESSION_ID' => $user->session_id, - 'ROOT_PATH' => $web_path, - 'BOARD_URL' => $board_url, - - 'L_LOGIN_LOGOUT' => $l_login_logout, - 'L_INDEX' => ($config['board_index_text'] !== '') ? $config['board_index_text'] : $user->lang['FORUM_INDEX'], - 'L_SITE_HOME' => ($config['site_home_text'] !== '') ? $config['site_home_text'] : $user->lang['HOME'], - 'L_ONLINE_EXPLAIN' => $l_online_time, - - 'U_PRIVATEMSGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'), - 'U_RETURN_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'), - 'U_MEMBERLIST' => append_sid("{$phpbb_root_path}memberlist.$phpEx"), - 'U_VIEWONLINE' => ($auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel')) ? append_sid("{$phpbb_root_path}viewonline.$phpEx") : '', - 'U_LOGIN_LOGOUT' => $u_login_logout, - 'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"), - 'U_SEARCH' => append_sid("{$phpbb_root_path}search.$phpEx"), - 'U_SITE_HOME' => $config['site_home_url'], - 'U_REGISTER' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), - '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' => $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'), - 'U_SEARCH_UNREAD' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unreadposts'), - 'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'), - 'U_DELETE_COOKIES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'), - 'U_CONTACT_US' => ($config['contact_admin_form_enable'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin') : '', - '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' => $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, - 'S_BOARD_DISABLED' => ($config['board_disable']) ? true : false, - 'S_REGISTERED_USER' => (!empty($user->data['is_registered'])) ? true : false, - 'S_IS_BOT' => (!empty($user->data['is_bot'])) ? true : false, - 'S_USER_LANG' => $user_lang, - 'S_USER_BROWSER' => (isset($user->data['session_browser'])) ? $user->data['session_browser'] : $user->lang['UNKNOWN_BROWSER'], - 'S_USERNAME' => $user->data['username'], - 'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'], - 'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right', - 'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left', - 'S_CONTENT_ENCODING' => 'UTF-8', - 'S_TIMEZONE' => sprintf($user->lang['ALL_TIMES'], $timezone_offset, $timezone_name), - 'S_DISPLAY_ONLINE_LIST' => ($l_online_time) ? 1 : 0, - 'S_DISPLAY_SEARCH' => (!$config['load_search']) ? 0 : (isset($auth) ? ($auth->acl_get('u_search') && $auth->acl_getf_global('f_search')) : 1), - 'S_DISPLAY_PM' => ($config['allow_privmsg'] && !empty($user->data['is_registered']) && ($auth->acl_get('u_readpm') || $auth->acl_get('u_sendpm'))) ? true : false, - 'S_DISPLAY_MEMBERLIST' => (isset($auth)) ? $auth->acl_get('u_viewprofile') : 0, - 'S_NEW_PM' => ($s_privmsg_new) ? 1 : 0, - 'S_REGISTER_ENABLED' => ($config['require_activation'] != USER_ACTIVATION_DISABLE) ? true : false, - 'S_FORUM_ID' => $forum_id, - 'S_TOPIC_ID' => $topic_id, - - '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' => $s_login_redirect, - - 'S_ENABLE_FEEDS' => ($config['feed_enable']) ? true : false, - 'S_ENABLE_FEEDS_OVERALL' => ($config['feed_overall']) ? true : false, - 'S_ENABLE_FEEDS_FORUMS' => ($config['feed_overall_forums']) ? true : false, - 'S_ENABLE_FEEDS_TOPICS' => ($config['feed_topics_new']) ? true : false, - 'S_ENABLE_FEEDS_TOPICS_ACTIVE' => ($config['feed_topics_active']) ? true : false, - 'S_ENABLE_FEEDS_NEWS' => ($s_feed_news) ? true : false, - - 'S_LOAD_UNREADS' => ($config['load_unreads_search'] && ($config['load_anon_lastread'] || $user->data['is_registered'])) ? true : false, - - 'S_SEARCH_HIDDEN_FIELDS' => build_hidden_fields($s_search_hidden_fields), - - 'T_ASSETS_VERSION' => $config['assets_version'], - 'T_ASSETS_PATH' => "{$web_path}assets", - 'T_THEME_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme', - 'T_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/template', - 'T_SUPER_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/template', - 'T_IMAGES_PATH' => "{$web_path}images/", - 'T_SMILIES_PATH' => "{$web_path}{$config['smilies_path']}/", - 'T_AVATAR_PATH' => "{$web_path}{$config['avatar_path']}/", - 'T_AVATAR_GALLERY_PATH' => "{$web_path}{$config['avatar_gallery_path']}/", - 'T_ICONS_PATH' => "{$web_path}{$config['icons_path']}/", - 'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/", - 'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/", - 'T_STYLESHEET_LINK' => "{$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_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-3.4.1.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->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', - 'T_SMILIES' => $config['smilies_path'], - 'T_AVATAR' => $config['avatar_path'], - 'T_AVATAR_GALLERY' => $config['avatar_gallery_path'], - 'T_ICONS' => $config['icons_path'], - 'T_RANKS' => $config['ranks_path'], - 'T_UPLOAD' => $config['upload_path'], - - 'SITE_LOGO_IMG' => $user->img('site_logo'), - )); - - $http_headers = array(); - - if ($send_headers) - { - // 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'])) - { - // Let reverse proxies know we detected a bot. - $http_headers['X-PHPBB-IS-BOT'] = 'yes'; - } - } - - /** - * Execute code and/or overwrite _common_ template variables after they have been assigned. - * - * @event core.page_header_after - * @var string page_title Page title - * @var bool display_online_list Do we display online users list - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var int item_id Restrict online users to item id - * @var array http_headers HTTP headers that should be set by phpbb - * - * @since 3.1.0-b3 - */ - $vars = array('page_title', 'display_online_list', 'item_id', 'item', 'http_headers'); - extract($phpbb_dispatcher->trigger_event('core.page_header_after', compact($vars))); - - foreach ($http_headers as $hname => $hval) - { - header((string) $hname . ': ' . (string) $hval); - } - - return; -} - -/** -* Check and display the SQL report if requested. -* -* @param \phpbb\request\request_interface $request Request object -* @param \phpbb\auth\auth $auth Auth object -* @param \phpbb\db\driver\driver_interface $db Database connection -*/ -function phpbb_check_and_display_sql_report(\phpbb\request\request_interface $request, \phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db) -{ - global $phpbb_container; - - if ($phpbb_container->getParameter('debug.sql_explain') && $request->variable('explain', false) && $auth->acl_get('a_')) - { - $db->sql_report('display'); - } -} - -/** -* Generate the debug output string -* -* @param \phpbb\db\driver\driver_interface $db Database connection -* @param \phpbb\config\config $config Config object -* @param \phpbb\auth\auth $auth Auth object -* @param \phpbb\user $user User object -* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher -* @return string -*/ -function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\auth\auth $auth, \phpbb\user $user, \phpbb\event\dispatcher_interface $phpbb_dispatcher) -{ - global $phpbb_container; - - $debug_info = array(); - - // Output page creation time - if ($phpbb_container->getParameter('debug.load_time')) - { - if (isset($GLOBALS['starttime'])) - { - $totaltime = microtime(true) - $GLOBALS['starttime']; - $debug_info[] = sprintf('Time: %.3fs', $db->get_sql_time(), ($totaltime - $db->get_sql_time()), $totaltime); - } - } - - if ($phpbb_container->getParameter('debug.memory')) - { - $memory_usage = memory_get_peak_usage(); - if ($memory_usage) - { - $memory_usage = get_formatted_filesize($memory_usage); - - $debug_info[] = 'Peak Memory Usage: ' . $memory_usage; - } - - $debug_info[] = 'GZIP: ' . (($config['gzip_compress'] && @extension_loaded('zlib')) ? 'On' : 'Off'); - - if ($user->load) - { - $debug_info[] = 'Load: ' . $user->load; - } - } - - if ($phpbb_container->getParameter('debug.sql_explain')) - { - $debug_info[] = sprintf('Queries: %d', $db->sql_num_queries(true), $db->sql_num_queries()); - - if ($auth->acl_get('a_')) - { - $debug_info[] = 'SQL Explain'; - } - } - - /** - * Modify debug output information - * - * @event core.phpbb_generate_debug_output - * @var array debug_info Array of strings with debug information - * - * @since 3.1.0-RC3 - */ - $vars = array('debug_info'); - extract($phpbb_dispatcher->trigger_event('core.phpbb_generate_debug_output', compact($vars))); - - return implode(' | ', $debug_info); -} - -/** -* Generate page footer -* -* @param bool $run_cron Whether or not to run the cron -* @param bool $display_template Whether or not to display the template -* @param bool $exit_handler Whether or not to run the exit_handler() -*/ -function page_footer($run_cron = true, $display_template = true, $exit_handler = true) -{ - 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 - $page_footer_override = false; - - /** - * Execute code and/or overwrite page_footer() - * - * @event core.page_footer - * @var bool run_cron Shall we run cron tasks - * @var bool page_footer_override Shall we return instead of running - * the rest of page_footer() - * @since 3.1.0-a1 - */ - $vars = array('run_cron', 'page_footer_override'); - extract($phpbb_dispatcher->trigger_event('core.page_footer', compact($vars))); - - if ($page_footer_override) - { - return; - } - - phpbb_check_and_display_sql_report($request, $auth, $db); - - $template->assign_vars(array( - 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher), - 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', - 'CREDIT_LINE' => $user->lang('POWERED_BY', 'phpBB® Forum Software © phpBB Limited'), - - 'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_admin_path}index.$phpEx", false, true, $user->session_id) : '') - ); - - // Call cron-type script - $call_cron = false; - if (!defined('IN_CRON') && !$config['use_system_cron'] && $run_cron && !$config['board_disable'] && !$user->data['is_bot'] && !$cache->get('_cron.lock_check')) - { - $call_cron = true; - $time_now = (!empty($user->time_now) && is_int($user->time_now)) ? $user->time_now : time(); - - // Any old lock present? - if (!empty($config['cron_lock'])) - { - $cron_time = explode(' ', $config['cron_lock']); - - // If 1 hour lock is present we do not call cron.php - if ($cron_time[0] + 3600 >= $time_now) - { - $call_cron = false; - } - } - } - - // Call cron job? - if ($call_cron) - { - global $phpbb_container; - - /* @var $cron \phpbb\cron\manager */ - $cron = $phpbb_container->get('cron.manager'); - $task = $cron->find_one_ready_task(); - - if ($task) - { - $url = $task->get_url(); - $template->assign_var('RUN_CRON_TASK', 'cron'); - } - else - { - $cache->put('_cron.lock_check', true, 60); - } - } - - /** - * Execute code and/or modify output before displaying the template. - * - * @event core.page_footer_after - * @var bool display_template Whether or not to display the template - * @var bool exit_handler Whether or not to run the exit_handler() - * - * @since 3.1.0-RC5 - */ - $vars = array('display_template', 'exit_handler'); - extract($phpbb_dispatcher->trigger_event('core.page_footer_after', compact($vars))); - - if ($display_template) - { - $template->display('body'); - } - - garbage_collection(); - - if ($exit_handler) - { - exit_handler(); - } -} - -/** -* Closing the cache object and the database -* Cool function name, eh? We might want to add operations to it later -*/ -function garbage_collection() -{ - global $cache, $db; - global $phpbb_dispatcher; - - if (!empty($phpbb_dispatcher)) - { - /** - * Unload some objects, to free some memory, before we finish our task - * - * @event core.garbage_collection - * @since 3.1.0-a1 - */ - $phpbb_dispatcher->dispatch('core.garbage_collection'); - } - - // Unload cache, must be done before the DB connection if closed - if (!empty($cache)) - { - $cache->unload(); - } - - // Close our DB connection. - if (!empty($db)) - { - $db->sql_close(); - } -} - -/** -* Handler for exit calls in phpBB. -* This function supports hooks. -* -* Note: This function is called after the template has been outputted. -*/ -function exit_handler() -{ - global $phpbb_hook; - - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__)) - { - if ($phpbb_hook->hook_return(__FUNCTION__)) - { - return $phpbb_hook->hook_return_result(__FUNCTION__); - } - } - - // As a pre-caution... some setups display a blank page if the flush() is not there. - (ob_get_level() > 0) ? @ob_flush() : @flush(); - - exit; -} - -/** -* Handler for init calls in phpBB. This function is called in \phpbb\user::setup(); -* This function supports hooks. -*/ -function phpbb_user_session_handler() -{ - global $phpbb_hook; - - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__)) - { - if ($phpbb_hook->hook_return(__FUNCTION__)) - { - return $phpbb_hook->hook_return_result(__FUNCTION__); - } - } - - return; -} - -/** -* Casts a numeric string $input to an appropriate numeric type (i.e. integer or float) -* -* @param string $input A numeric string. -* -* @return int|float Integer $input if $input fits integer, -* float $input otherwise. -*/ -function phpbb_to_numeric($input) -{ - return ($input > PHP_INT_MAX) ? (float) $input : (int) $input; -} - -/** -* Get the board contact details (e.g. for emails) -* -* @param \phpbb\config\config $config -* @param string $phpEx -* @return string -*/ -function phpbb_get_board_contact(\phpbb\config\config $config, $phpEx) -{ - if ($config['contact_admin_form_enable']) - { - return generate_board_url() . '/memberlist.' . $phpEx . '?mode=contactadmin'; - } - else - { - return $config['board_contact']; - } -} - -/** -* Get a clickable board contact details link -* -* @param \phpbb\config\config $config -* @param string $phpbb_root_path -* @param string $phpEx -* @return string -*/ -function phpbb_get_board_contact_link(\phpbb\config\config $config, $phpbb_root_path, $phpEx) -{ - if ($config['contact_admin_form_enable'] && $config['email_enable']) - { - return append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin'); - } - else - { - return 'mailto:' . htmlspecialchars($config['board_contact']); - } -} diff --git a/install/update/new/includes/functions_acp.php b/install/update/new/includes/functions_acp.php deleted file mode 100644 index 4926351..0000000 --- a/install/update/new/includes/functions_acp.php +++ /dev/null @@ -1,727 +0,0 @@ - -* @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; -} - -/** -* Header for acp pages -*/ -function adm_page_header($page_title) -{ - global $config, $user, $template; - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $SID, $_SID; - global $phpbb_dispatcher, $phpbb_container; - - if (defined('HEADER_INC')) - { - return; - } - - define('HEADER_INC', true); - - // A listener can set this variable to `true` when it overrides this function - $adm_page_header_override = false; - - /** - * Execute code and/or overwrite adm_page_header() - * - * @event core.adm_page_header - * @var string page_title Page title - * @var bool adm_page_header_override Shall we return instead of - * running the rest of adm_page_header() - * @since 3.1.0-a1 - */ - $vars = array('page_title', 'adm_page_header_override'); - extract($phpbb_dispatcher->trigger_event('core.adm_page_header', compact($vars))); - - if ($adm_page_header_override) - { - return; - } - - $user->update_session_infos(); - - // gzip_compression - if ($config['gzip_compress']) - { - if (@extension_loaded('zlib') && !headers_sent()) - { - ob_start('ob_gzhandler'); - } - } - - $template->assign_vars(array( - 'PAGE_TITLE' => $page_title, - 'USERNAME' => $user->data['username'], - - 'SID' => $SID, - '_SID' => $_SID, - 'SESSION_ID' => $user->session_id, - 'ROOT_PATH' => $phpbb_root_path, - 'ADMIN_ROOT_PATH' => $phpbb_admin_path, - - 'U_LOGOUT' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout'), - 'U_ADM_LOGOUT' => append_sid("{$phpbb_admin_path}index.$phpEx", 'action=admlogout'), - 'U_ADM_INDEX' => append_sid("{$phpbb_admin_path}index.$phpEx"), - 'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"), - - 'T_IMAGES_PATH' => "{$phpbb_root_path}images/", - 'T_SMILIES_PATH' => "{$phpbb_root_path}{$config['smilies_path']}/", - 'T_AVATAR_PATH' => "{$phpbb_root_path}{$config['avatar_path']}/", - 'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/", - 'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/", - 'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/", - 'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/", - 'T_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'], - - 'ICON_MOVE_UP' => '' . $user->lang['MOVE_UP'] . '', - 'ICON_MOVE_UP_DISABLED' => '' . $user->lang['MOVE_UP'] . '', - 'ICON_MOVE_DOWN' => '' . $user->lang['MOVE_DOWN'] . '', - 'ICON_MOVE_DOWN_DISABLED' => '' . $user->lang['MOVE_DOWN'] . '', - 'ICON_EDIT' => '' . $user->lang['EDIT'] . '', - 'ICON_EDIT_DISABLED' => '' . $user->lang['EDIT'] . '', - 'ICON_DELETE' => '' . $user->lang['DELETE'] . '', - 'ICON_DELETE_DISABLED' => '' . $user->lang['DELETE'] . '', - 'ICON_SYNC' => '' . $user->lang['RESYNC'] . '', - 'ICON_SYNC_DISABLED' => '' . $user->lang['RESYNC'] . '', - - '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', - - '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. - $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', - ); - - /** - * Execute code and/or overwrite _common_ template variables after they have been assigned. - * - * @event core.adm_page_header_after - * @var string page_title Page title - * @var array http_headers HTTP headers that should be set by phpbb - * - * @since 3.1.0-RC3 - */ - $vars = array('page_title', 'http_headers'); - extract($phpbb_dispatcher->trigger_event('core.adm_page_header_after', compact($vars))); - - foreach ($http_headers as $hname => $hval) - { - header((string) $hname . ': ' . (string) $hval); - } - - return; -} - -/** -* Page footer for acp pages -*/ -function adm_page_footer($copyright_html = true) -{ - 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 - $adm_page_footer_override = false; - - /** - * Execute code and/or overwrite adm_page_footer() - * - * @event core.adm_page_footer - * @var bool copyright_html Shall we display the copyright? - * @var bool adm_page_footer_override Shall we return instead of - * running the rest of adm_page_footer() - * @since 3.1.0-a1 - */ - $vars = array('copyright_html', 'adm_page_footer_override'); - extract($phpbb_dispatcher->trigger_event('core.adm_page_footer', compact($vars))); - - if ($adm_page_footer_override) - { - return; - } - - phpbb_check_and_display_sql_report($request, $auth, $db); - - $template->assign_vars(array( - 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher), - 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', - 'S_COPYRIGHT_HTML' => $copyright_html, - 'CREDIT_LINE' => $user->lang('POWERED_BY', 'phpBB® Forum Software © phpBB Limited'), - 'T_JQUERY_LINK' => !empty($config['allow_cdn']) && !empty($config['load_jquery_url']) ? $config['load_jquery_url'] : "{$phpbb_root_path}assets/javascript/jquery-3.4.1.min.js", - 'S_ALLOW_CDN' => !empty($config['allow_cdn']), - 'VERSION' => $config['version']) - ); - - $template->display('body'); - - garbage_collection(); - exit_handler(); -} - -/** -* Generate back link for acp pages -*/ -function adm_back_link($u_action) -{ - global $user; - return '

« ' . $user->lang['BACK_TO_PREV'] . ''; -} - -/** -* Build select field options in acp pages -*/ -function build_select($option_ary, $option_default = false) -{ - global $user; - - $html = ''; - foreach ($option_ary as $value => $title) - { - $selected = ($option_default !== false && $value == $option_default) ? ' selected="selected"' : ''; - $html .= ''; - } - - return $html; -} - -/** -* Build radio fields in acp pages -*/ -function h_radio($name, $input_ary, $input_default = false, $id = false, $key = false, $separator = '') -{ - global $user; - - $html = ''; - $id_assigned = false; - foreach ($input_ary as $value => $title) - { - $selected = ($input_default !== false && $value == $input_default) ? ' checked="checked"' : ''; - $html .= '' . $separator; - $id_assigned = true; - } - - return $html; -} - -/** -* Build configuration template for acp configuration pages -*/ -function build_cfg_template($tpl_type, $key, &$new_ary, $config_key, $vars) -{ - global $user, $module, $phpbb_dispatcher; - - $tpl = ''; - $name = 'config[' . $config_key . ']'; - - // Make sure there is no notice printed out for non-existent config options (we simply set them) - if (!isset($new_ary[$config_key])) - { - $new_ary[$config_key] = ''; - } - - switch ($tpl_type[0]) - { - case 'password': - if ($new_ary[$config_key] !== '') - { - // replace passwords with asterixes - $new_ary[$config_key] = '********'; - } - case 'text': - case 'url': - case 'email': - case 'tel': - case 'search': - // maxlength and size are only valid for these types and will be - // ignored for other input types. - $size = (int) $tpl_type[1]; - $maxlength = (int) $tpl_type[2]; - - $tpl = ''; - break; - - case 'color': - case 'datetime': - case 'datetime-local': - case 'month': - case 'week': - $tpl = ''; - break; - - case 'date': - case 'time': - case 'number': - case 'range': - $max = ''; - $min = ( isset($tpl_type[1]) ) ? (int) $tpl_type[1] : false; - if ( isset($tpl_type[2]) ) - { - $max = (int) $tpl_type[2]; - } - - $tpl = ''; - break; - - case 'dimension': - $max = ''; - - $min = (int) $tpl_type[1]; - - if ( isset($tpl_type[2]) ) - { - $max = (int) $tpl_type[2]; - } - - $tpl = ' x '; - break; - - case 'textarea': - $rows = (int) $tpl_type[1]; - $cols = (int) $tpl_type[2]; - - $tpl = ''; - break; - - case 'radio': - $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; - - $tpl_no = ''; - $tpl_yes = ''; - - $tpl = ($tpl_type_cond[0] == 'yes' || $tpl_type_cond[0] == 'enabled') ? $tpl_yes . $tpl_no : $tpl_no . $tpl_yes; - break; - - case 'select': - case 'custom': - - if (isset($vars['method'])) - { - $call = array($module->module, $vars['method']); - } - else if (isset($vars['function'])) - { - $call = $vars['function']; - } - else - { - break; - } - - if (isset($vars['params'])) - { - $args = array(); - foreach ($vars['params'] as $value) - { - switch ($value) - { - case '{CONFIG_VALUE}': - $value = $new_ary[$config_key]; - break; - - case '{KEY}': - $value = $key; - break; - } - - $args[] = $value; - } - } - else - { - $args = array($new_ary[$config_key], $key); - } - - $return = call_user_func_array($call, $args); - - if ($tpl_type[0] == 'select') - { - $size = (isset($tpl_type[1])) ? (int) $tpl_type[1] : 1; - $data_toggle = (!empty($tpl_type[2])) ? ' data-togglable-settings="true"' : ''; - - $tpl = ''; - } - else - { - $tpl = $return; - } - - break; - - default: - break; - } - - if (isset($vars['append'])) - { - $tpl .= $vars['append']; - } - - $new = $new_ary; - /** - * Overwrite the html code we display for the config value - * - * @event core.build_config_template - * @var array tpl_type Config type array: - * 0 => data type - * 1 [optional] => string: size, int: minimum - * 2 [optional] => string: max. length, int: maximum - * @var string key Should be used for the id attribute in html - * @var array new Array with the config values we display - * @var string name Should be used for the name attribute - * @var array vars Array with the options for the config - * @var string tpl The resulting html code we display - * @since 3.1.0-a1 - */ - $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; -} - -/** -* Going through a config array and validate values, writing errors to $error. The validation method accepts parameters separated by ':' for string and int. -* The first parameter defines the type to be used, the second the lower bound and the third the upper bound. Only the type is required. -*/ -function validate_config_vars($config_vars, &$cfg_array, &$error) -{ - global $phpbb_root_path, $user, $phpbb_dispatcher, $phpbb_filesystem, $language; - - $type = 0; - $min = 1; - $max = 2; - - foreach ($config_vars as $config_name => $config_definition) - { - if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false) - { - continue; - } - - if (!isset($config_definition['validate'])) - { - continue; - } - - $validator = explode(':', $config_definition['validate']); - - // 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]); - - // the column is a VARCHAR - $validator[$max] = (isset($validator[$max])) ? min(255, $validator[$max]) : 255; - - if (isset($validator[$min]) && $length < $validator[$min]) - { - $error[] = sprintf($user->lang['SETTING_TOO_SHORT'], $user->lang[$config_definition['lang']], $validator[$min]); - } - else if (isset($validator[$max]) && $length > $validator[2]) - { - $error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$config_definition['lang']], $validator[$max]); - } - break; - - case 'bool': - $cfg_array[$config_name] = ($cfg_array[$config_name]) ? 1 : 0; - break; - - case 'int': - $cfg_array[$config_name] = (int) $cfg_array[$config_name]; - - if (isset($validator[$min]) && $cfg_array[$config_name] < $validator[$min]) - { - $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], $validator[$min]); - } - else if (isset($validator[$max]) && $cfg_array[$config_name] > $validator[$max]) - { - $error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$config_definition['lang']], $validator[$max]); - } - - if (strpos($config_name, '_max') !== false) - { - // Min/max pairs of settings should ensure that min <= max - // Replace _max with _min to find the name of the minimum - // corresponding configuration variable - $min_name = str_replace('_max', '_min', $config_name); - - if (isset($cfg_array[$min_name]) && is_numeric($cfg_array[$min_name]) && $cfg_array[$config_name] < $cfg_array[$min_name]) - { - // A minimum value exists and the maximum value is less than it - $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], (int) $cfg_array[$min_name]); - } - } - break; - - case 'email': - if (!preg_match('/^' . get_preg_expression('email') . '$/i', $cfg_array[$config_name])) - { - $error[] = $user->lang['EMAIL_INVALID_EMAIL']; - } - break; - - // Absolute path - case 'script_path': - if (!$cfg_array[$config_name]) - { - break; - } - - $destination = str_replace('\\', '/', $cfg_array[$config_name]); - - if ($destination !== '/') - { - // Adjust destination path (no trailing slash) - if (substr($destination, -1, 1) == '/') - { - $destination = substr($destination, 0, -1); - } - - $destination = str_replace(array('../', './'), '', $destination); - - if ($destination[0] != '/') - { - $destination = '/' . $destination; - } - } - - $cfg_array[$config_name] = trim($destination); - - break; - - // Absolute path - case 'lang': - if (!$cfg_array[$config_name]) - { - break; - } - - $cfg_array[$config_name] = basename($cfg_array[$config_name]); - - if (!file_exists($phpbb_root_path . 'language/' . $cfg_array[$config_name] . '/')) - { - $error[] = $user->lang['WRONG_DATA_LANG']; - } - break; - - // Relative path (appended $phpbb_root_path) - case 'rpath': - case 'rwpath': - if (!$cfg_array[$config_name]) - { - break; - } - - $destination = $cfg_array[$config_name]; - - // Adjust destination path (no trailing slash) - if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\') - { - $destination = substr($destination, 0, -1); - } - - $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination); - if ($destination && ($destination[0] == '/' || $destination[0] == "\\")) - { - $destination = ''; - } - - $cfg_array[$config_name] = trim($destination); - - // Path being relative (still prefixed by phpbb_root_path), but with the ability to escape the root dir... - case 'path': - case 'wpath': - - if (!$cfg_array[$config_name]) - { - break; - } - - $cfg_array[$config_name] = trim($cfg_array[$config_name]); - - // Make sure no NUL byte is present... - if (strpos($cfg_array[$config_name], "\0") !== false || strpos($cfg_array[$config_name], '%00') !== false) - { - $cfg_array[$config_name] = ''; - break; - } - - $path = $phpbb_root_path . $cfg_array[$config_name]; - - if (!file_exists($path)) - { - $error[] = sprintf($user->lang['DIRECTORY_DOES_NOT_EXIST'], $cfg_array[$config_name]); - } - - if (file_exists($path) && !is_dir($path)) - { - $error[] = sprintf($user->lang['DIRECTORY_NOT_DIR'], $cfg_array[$config_name]); - } - - // Check if the path is writable - if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath') - { - if (file_exists($path) && !$phpbb_filesystem->is_writable($path)) - { - $error[] = sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $cfg_array[$config_name]); - } - } - - break; - - default: - /** - * Validate a config value - * - * @event core.validate_config_variable - * @var array cfg_array Array with config values - * @var string config_name Name of the config we validate - * @var array config_definition Array with the options for - * this config - * @var array error Array of errors, the errors should - * be strings only, language keys are - * not replaced afterwards - * @since 3.1.0-a1 - */ - $vars = array('cfg_array', 'config_name', 'config_definition', 'error'); - extract($phpbb_dispatcher->trigger_event('core.validate_config_variable', compact($vars))); - break; - } - } - - return; -} - -/** -* Checks whatever or not a variable is OK for use in the Database -* param mixed $value_ary An array of the form array(array('lang' => ..., 'value' => ..., 'column_type' =>))' -* param mixed $error The error array -*/ -function validate_range($value_ary, &$error) -{ - global $user; - - $column_types = array( - 'BOOL' => array('php_type' => 'int', 'min' => 0, 'max' => 1), - 'USINT' => array('php_type' => 'int', 'min' => 0, 'max' => 65535), - 'UINT' => array('php_type' => 'int', 'min' => 0, 'max' => (int) 0x7fffffff), - // Do not use (int) 0x80000000 - it evaluates to different - // values on 32-bit and 64-bit systems. - // Apparently -2147483648 is a float on 32-bit systems, - // despite fitting in an int, thus explicit cast is needed. - 'INT' => array('php_type' => 'int', 'min' => (int) -2147483648, 'max' => (int) 0x7fffffff), - 'TINT' => array('php_type' => 'int', 'min' => -128, 'max' => 127), - - 'VCHAR' => array('php_type' => 'string', 'min' => 0, 'max' => 255), - ); - foreach ($value_ary as $value) - { - $column = explode(':', $value['column_type']); - if (!isset($column_types[$column[0]])) - { - continue; - } - else - { - $type = $column_types[$column[0]]; - } - - switch ($type['php_type']) - { - case 'string' : - $max = (isset($column[1])) ? min($column[1],$type['max']) : $type['max']; - if (utf8_strlen($value['value']) > $max) - { - $error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$value['lang']], $max); - } - break; - - case 'int': - $min = (isset($column[1])) ? max($column[1],$type['min']) : $type['min']; - $max = (isset($column[2])) ? min($column[2],$type['max']) : $type['max']; - if ($value['value'] < $min) - { - $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$value['lang']], $min); - } - else if ($value['value'] > $max) - { - $error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$value['lang']], $max); - } - break; - } - } -} - -/** -* Inserts new config display_vars into an exisiting display_vars array -* at the given position. -* -* @param array $display_vars An array of existing config display vars -* @param array $add_config_vars An array of new config display vars -* @param array $where Where to place the new config vars, -* before or after an exisiting config, as an array -* of the form: array('after' => 'config_name') or -* array('before' => 'config_name'). -* @return array The array of config display vars -*/ -function phpbb_insert_config_array($display_vars, $add_config_vars, $where) -{ - if (is_array($where) && array_key_exists(current($where), $display_vars)) - { - $position = array_search(current($where), array_keys($display_vars)) + ((key($where) == 'before') ? 0 : 1); - $display_vars = array_merge( - array_slice($display_vars, 0, $position), - $add_config_vars, - array_slice($display_vars, $position) - ); - } - - return $display_vars; -} diff --git a/install/update/new/includes/functions_admin.php b/install/update/new/includes/functions_admin.php deleted file mode 100644 index 4629706..0000000 --- a/install/update/new/includes/functions_admin.php +++ /dev/null @@ -1,3096 +0,0 @@ - -* @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; -} - -/** -* Recalculate Nested Sets -* -* @param int $new_id first left_id (should start with 1) -* @param string $pkey primary key-column (containing the id for the parent_id of the children) -* @param string $table constant or fullname of the table -* @param int $parent_id parent_id of the current set (default = 0) -* @param array $where contains strings to compare closer on the where statement (additional) -*/ -function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = array()) -{ - global $db; - - $sql = 'SELECT * - FROM ' . $table . ' - WHERE parent_id = ' . (int) $parent_id . - ((!empty($where)) ? ' AND ' . implode(' AND ', $where) : '') . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - // First we update the left_id for this module - if ($row['left_id'] != $new_id) - { - $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('left_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}"); - } - $new_id++; - - // Then we go through any children and update their left/right id's - recalc_nested_sets($new_id, $pkey, $table, $row[$pkey], $where); - - // Then we come back and update the right_id for this module - if ($row['right_id'] != $new_id) - { - $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('right_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}"); - } - $new_id++; - } - $db->sql_freeresult($result); -} - -/** -* Simple version of jumpbox, just lists authed forums -*/ -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, $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 - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql, 600); - - $rowset = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[(int) $row['forum_id']] = $row; - } - $db->sql_freeresult($result); - - $right = 0; - $padding_store = array('0' => ''); - $padding = ''; - $forum_list = ($return_array) ? array() : ''; - - /** - * Modify the forum list data - * - * @event core.make_forum_select_modify_forum_list - * @var array rowset Array with the forums list data - * @since 3.1.10-RC1 - */ - $vars = array('rowset'); - extract($phpbb_dispatcher->trigger_event('core.make_forum_select_modify_forum_list', compact($vars))); - - // Sometimes it could happen that forums will be displayed here not be displayed within the index page - // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions. - // If this happens, the padding could be "broken" - - foreach ($rowset as $row) - { - if ($row['left_id'] < $right) - { - $padding .= '   '; - $padding_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : ''; - } - - $right = $row['right_id']; - $disabled = false; - - if (!$ignore_acl && $auth->acl_gets(array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'), $row['forum_id'])) - { - if ($only_acl_post && !$auth->acl_get('f_post', $row['forum_id']) || (!$auth->acl_get('m_approve', $row['forum_id']) && !$auth->acl_get('f_noapprove', $row['forum_id']))) - { - $disabled = true; - } - } - else if (!$ignore_acl) - { - continue; - } - - if ( - ((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id) - || - // Non-postable forum with no subforums, don't display - ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat) - || - ($row['forum_type'] != FORUM_POST && $ignore_nonpost) - ) - { - $disabled = true; - } - - if ($return_array) - { - // Include some more information... - $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? true : false) : (($row['forum_id'] == $select_id) ? true : false); - $forum_list[$row['forum_id']] = array_merge(array('padding' => $padding, 'selected' => ($selected && !$disabled), 'disabled' => $disabled), $row); - } - else - { - $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? ' selected="selected"' : '') : (($row['forum_id'] == $select_id) ? ' selected="selected"' : ''); - $forum_list .= ''; - } - } - unset($padding_store, $rowset); - - return $forum_list; -} - -/** -* Generate size select options -*/ -function size_select_options($size_compare) -{ - global $user; - - $size_types_text = array($user->lang['BYTES'], $user->lang['KIB'], $user->lang['MIB']); - $size_types = array('b', 'kb', 'mb'); - - $s_size_options = ''; - - for ($i = 0, $size = count($size_types_text); $i < $size; $i++) - { - $selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : ''; - $s_size_options .= ''; - } - - return $s_size_options; -} - -/** -* Generate list of groups (option fields without select) -* -* @param int $group_id The default group id to mark as selected -* @param array $exclude_ids The group ids to exclude from the list, false (default) if you whish to exclude no id -* @param int $manage_founder If set to false (default) all groups are returned, if 0 only those groups returned not being managed by founders only, if 1 only those groups returned managed by founders only. -* -* @return string The list of options. -*/ -function group_select_options($group_id, $exclude_ids = false, $manage_founder = false) -{ - global $db, $config, $phpbb_container; - - /** @var \phpbb\group\helper $group_helper */ - $group_helper = $phpbb_container->get('group_helper'); - - $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 : ''; - - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE . " - $exclude_sql - $sql_and - $sql_founder - ORDER BY group_type DESC, group_name ASC"; - $result = $db->sql_query($sql); - - $s_group_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : ''; - $s_group_options .= '' . $group_helper->get_name($row['group_name']) . ''; - } - $db->sql_freeresult($result); - - return $s_group_options; -} - -/** -* Obtain authed forums list -*/ -function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false) -{ - global $db, $auth, $phpbb_dispatcher; - static $forum_rows; - - if (!isset($forum_rows)) - { - // This query is identical to the jumpbox one - $expire_time = ($no_cache) ? 0 : 600; - - $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql, $expire_time); - - $forum_rows = array(); - - $right = $padding = 0; - $padding_store = array('0' => 0); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['left_id'] < $right) - { - $padding++; - $padding_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it. - // @todo digging deep to find out "how" this can happen. - $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding; - } - - $right = $row['right_id']; - $row['padding'] = $padding; - - $forum_rows[] = $row; - } - $db->sql_freeresult($result); - unset($padding_store); - } - - $rowset = array(); - foreach ($forum_rows as $row) - { - if ($postable_only && $row['forum_type'] != FORUM_POST) - { - continue; - } - - if ($acl_list == '' || ($acl_list != '' && $auth->acl_gets($acl_list, $row['forum_id']))) - { - $rowset[] = ($id_only) ? (int) $row['forum_id'] : $row; - } - } - - /** - * Modify the forum list data - * - * @event core.get_forum_list_modify_data - * @var array rowset Array with the forum list data - * @since 3.1.10-RC1 - */ - $vars = array('rowset'); - extract($phpbb_dispatcher->trigger_event('core.get_forum_list_modify_data', compact($vars))); - - return $rowset; -} - -/** -* Get forum branch -*/ -function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $include_forum = true) -{ - global $db; - - switch ($type) - { - case 'parents': - $condition = 'f1.left_id BETWEEN f2.left_id AND f2.right_id'; - break; - - case 'children': - $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id'; - break; - - default: - $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id OR f1.left_id BETWEEN f2.left_id AND f2.right_id'; - break; - } - - $rows = array(); - - $sql = 'SELECT f2.* - FROM ' . FORUMS_TABLE . ' f1 - LEFT JOIN ' . FORUMS_TABLE . " f2 ON ($condition) - WHERE f1.forum_id = $forum_id - ORDER BY f2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC'); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$include_forum && $row['forum_id'] == $forum_id) - { - continue; - } - - $rows[] = $row; - } - $db->sql_freeresult($result); - - return $rows; -} - -/** -* Copies permissions from one forum to others -* -* @param int $src_forum_id The source forum we want to copy permissions from -* @param array $dest_forum_ids The destination forum(s) we want to copy to -* @param bool $clear_dest_perms True if destination permissions should be deleted -* @param bool $add_log True if log entry should be added -* -* @return bool False on error -*/ -function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perms = true, $add_log = true) -{ - global $db, $user, $phpbb_log; - - // Only one forum id specified - if (!is_array($dest_forum_ids)) - { - $dest_forum_ids = array($dest_forum_ids); - } - - // Make sure forum ids are integers - $src_forum_id = (int) $src_forum_id; - $dest_forum_ids = array_map('intval', $dest_forum_ids); - - // No source forum or no destination forums specified - if (empty($src_forum_id) || empty($dest_forum_ids)) - { - return false; - } - - // Check if source forum exists - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $src_forum_id; - $result = $db->sql_query($sql); - $src_forum_name = $db->sql_fetchfield('forum_name'); - $db->sql_freeresult($result); - - // Source forum doesn't exist - if (empty($src_forum_name)) - { - return false; - } - - // Check if destination forums exists - $sql = 'SELECT forum_id, forum_name - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); - $result = $db->sql_query($sql); - - $dest_forum_ids = $dest_forum_names = array(); - while ($row = $db->sql_fetchrow($result)) - { - $dest_forum_ids[] = (int) $row['forum_id']; - $dest_forum_names[] = $row['forum_name']; - } - $db->sql_freeresult($result); - - // No destination forum exists - if (empty($dest_forum_ids)) - { - return false; - } - - // From the mysql documentation: - // Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear - // in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14. - // Due to this we stay on the safe side if we do the insertion "the manual way" - - // Rowsets we're going to insert - $users_sql_ary = $groups_sql_ary = array(); - - // Query acl users table for source forum data - $sql = 'SELECT user_id, auth_option_id, auth_role_id, auth_setting - FROM ' . ACL_USERS_TABLE . ' - WHERE forum_id = ' . $src_forum_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $row = array( - 'user_id' => (int) $row['user_id'], - 'auth_option_id' => (int) $row['auth_option_id'], - 'auth_role_id' => (int) $row['auth_role_id'], - 'auth_setting' => (int) $row['auth_setting'], - ); - - foreach ($dest_forum_ids as $dest_forum_id) - { - $users_sql_ary[] = $row + array('forum_id' => $dest_forum_id); - } - } - $db->sql_freeresult($result); - - // Query acl groups table for source forum data - $sql = 'SELECT group_id, auth_option_id, auth_role_id, auth_setting - FROM ' . ACL_GROUPS_TABLE . ' - WHERE forum_id = ' . $src_forum_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $row = array( - 'group_id' => (int) $row['group_id'], - 'auth_option_id' => (int) $row['auth_option_id'], - 'auth_role_id' => (int) $row['auth_role_id'], - 'auth_setting' => (int) $row['auth_setting'], - ); - - foreach ($dest_forum_ids as $dest_forum_id) - { - $groups_sql_ary[] = $row + array('forum_id' => $dest_forum_id); - } - } - $db->sql_freeresult($result); - - $db->sql_transaction('begin'); - - // Clear current permissions of destination forums - if ($clear_dest_perms) - { - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); - $db->sql_query($sql); - } - - $db->sql_multi_insert(ACL_USERS_TABLE, $users_sql_ary); - $db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary); - - if ($add_log) - { - $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'); - - return true; -} - -/** -* Get physical file listing -*/ -function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png') -{ - $matches = array($dir => array()); - - // Remove initial / if present - $rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir; - // Add closing / if not present - $rootdir = ($rootdir && substr($rootdir, -1) != '/') ? $rootdir . '/' : $rootdir; - - // Remove initial / if present - $dir = (substr($dir, 0, 1) == '/') ? substr($dir, 1) : $dir; - // Add closing / if not present - $dir = ($dir && substr($dir, -1) != '/') ? $dir . '/' : $dir; - - if (!is_dir($rootdir . $dir)) - { - return $matches; - } - - $dh = @opendir($rootdir . $dir); - - if (!$dh) - { - return $matches; - } - - while (($fname = readdir($dh)) !== false) - { - if (is_file("$rootdir$dir$fname")) - { - if (filesize("$rootdir$dir$fname") && preg_match('#\.' . $type . '$#i', $fname)) - { - $matches[$dir][] = $fname; - } - } - else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname")) - { - $matches += filelist($rootdir, "$dir$fname", $type); - } - } - closedir($dh); - - return $matches; -} - -/** -* Move topic(s) -*/ -function move_topics($topic_ids, $forum_id, $auto_sync = true) -{ - global $db, $phpbb_dispatcher; - - if (empty($topic_ids)) - { - return; - } - - $forum_ids = array($forum_id); - - if (!is_array($topic_ids)) - { - $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; - $db->sql_query($sql); - - if ($auto_sync) - { - $sql = 'SELECT DISTINCT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $db->sql_freeresult($result); - } - - $table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE); - - /** - * Perform additional actions before topics move - * - * @event core.move_topics_before_query - * @var array table_ary Array of tables from which forum_id will be updated for all rows that hold the moved topics - * @var array topic_ids Array of the moved topic ids - * @var string forum_id The forum id from where the topics are moved - * @var array forum_ids Array of the forums where the topics are moving (includes also forum_id) - * @var bool auto_sync Whether or not to perform auto sync - * @since 3.1.5-RC1 - */ - $vars = array( - 'table_ary', - 'topic_ids', - 'forum_id', - 'forum_ids', - 'auto_sync', - ); - extract($phpbb_dispatcher->trigger_event('core.move_topics_before_query', compact($vars))); - - foreach ($table_ary as $table) - { - $sql = "UPDATE $table - SET forum_id = $forum_id - WHERE " . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - 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); - unset($forum_ids); - } -} - -/** -* Move post(s) -*/ -function move_posts($post_ids, $topic_id, $auto_sync = true) -{ - global $db, $phpbb_dispatcher; - - if (!is_array($post_ids)) - { - $post_ids = array($post_ids); - } - - $forum_ids = array(); - $topic_ids = array($topic_id); - - $sql = 'SELECT DISTINCT topic_id, forum_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = (int) $row['forum_id']; - $topic_ids[] = (int) $row['topic_id']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $forum_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$forum_row) - { - trigger_error('NO_TOPIC'); - } - - /** - * Perform additional actions before moving posts - * - * @event core.move_posts_before - * @var array post_ids Array of post ids to move - * @var int topic_id The topic id the posts are moved to - * @var bool auto_sync Whether or not to perform auto sync - * @var array forum_ids Array of the forum ids the posts are moved from - * @var array topic_ids Array of the topic ids the posts are moved from - * @var array forum_row Array with the forum id of the topic the posts are moved to - * @since 3.1.7-RC1 - */ - $vars = array( - 'post_ids', - 'topic_id', - 'auto_sync', - 'forum_ids', - 'topic_ids', - 'forum_row', - ); - extract($phpbb_dispatcher->trigger_event('core.move_posts_before', compact($vars))); - - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET forum_id = ' . (int) $forum_row['forum_id'] . ", topic_id = $topic_id - WHERE " . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET topic_id = $topic_id, in_message = 0 - WHERE " . $db->sql_in_set('post_msg_id', $post_ids); - $db->sql_query($sql); - - /** - * Perform additional actions after moving posts - * - * @event core.move_posts_after - * @var array post_ids Array of the moved post ids - * @var int topic_id The topic id the posts are moved to - * @var bool auto_sync Whether or not to perform auto sync - * @var array forum_ids Array of the forum ids the posts are moved from - * @var array topic_ids Array of the topic ids the posts are moved from - * @var array forum_row Array with the forum id of the topic the posts are moved to - * @since 3.1.7-RC1 - */ - $vars = array( - 'post_ids', - 'topic_id', - 'auto_sync', - 'forum_ids', - 'topic_ids', - 'forum_row', - ); - extract($phpbb_dispatcher->trigger_event('core.move_posts_after', compact($vars))); - - if ($auto_sync) - { - $forum_ids[] = (int) $forum_row['forum_id']; - - sync('topic_reported', 'topic_id', $topic_ids); - sync('topic_attachment', 'topic_id', $topic_ids); - sync('topic', 'topic_id', $topic_ids, true); - sync('forum', 'forum_id', $forum_ids, true, true); - - /** - * Perform additional actions after move post sync - * - * @event core.move_posts_sync_after - * @var array post_ids Array of the moved post ids - * @var int topic_id The topic id the posts are moved to - * @var bool auto_sync Whether or not to perform auto sync - * @var array forum_ids Array of the forum ids the posts are moved from - * @var array topic_ids Array of the topic ids the posts are moved from - * @var array forum_row Array with the forum id of the topic the posts are moved to - * @since 3.1.11-RC1 - */ - $vars = array( - 'post_ids', - 'topic_id', - 'auto_sync', - 'forum_ids', - 'topic_ids', - 'forum_row', - ); - extract($phpbb_dispatcher->trigger_event('core.move_posts_sync_after', compact($vars))); - } - - // Update posted information - update_posted_info($topic_ids); -} - -/** -* Remove topic(s) -*/ -function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true) -{ - global $db, $config, $phpbb_container, $phpbb_dispatcher; - - $approved_topics = 0; - $forum_ids = $topic_ids = array(); - - if ($where_type === 'range') - { - $where_clause = $where_ids; - } - else - { - $where_ids = (is_array($where_ids)) ? array_unique($where_ids) : array($where_ids); - - if (!count($where_ids)) - { - return array('topics' => 0, 'posts' => 0); - } - - $where_clause = $db->sql_in_set($where_type, $where_ids); - } - - // Making sure that delete_posts does not call delete_topics again... - $return = array( - 'posts' => ($call_delete_posts) ? delete_posts($where_type, $where_ids, false, true, $post_count_sync, false) : 0, - ); - - $sql = 'SELECT topic_id, forum_id, topic_visibility, topic_moved_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $where_clause; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - $topic_ids[] = $row['topic_id']; - - if ($row['topic_visibility'] == ITEM_APPROVED && !$row['topic_moved_id']) - { - $approved_topics++; - } - } - $db->sql_freeresult($result); - - $return['topics'] = count($topic_ids); - - if (!count($topic_ids)) - { - return $return; - } - - $db->sql_transaction('begin'); - - $table_ary = array(BOOKMARKS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE); - - /** - * Perform additional actions before topic(s) deletion - * - * @event core.delete_topics_before_query - * @var array table_ary Array of tables from which all rows will be deleted that hold a topic_id occuring in topic_ids - * @var array topic_ids Array of topic ids to delete - * @since 3.1.4-RC1 - */ - $vars = array( - 'table_ary', - 'topic_ids', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_topics_before_query', compact($vars))); - - foreach ($table_ary as $table) - { - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - unset($table_ary); - - /** - * Perform additional actions after topic(s) deletion - * - * @event core.delete_topics_after_query - * @var array topic_ids Array of topic ids that were deleted - * @since 3.1.4-RC1 - */ - $vars = array( - 'topic_ids', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_topics_after_query', compact($vars))); - - $moved_topic_ids = array(); - - // update the other forums - $sql = 'SELECT topic_id, forum_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - $moved_topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (count($moved_topic_ids)) - { - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $moved_topic_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - if ($auto_sync) - { - sync('forum', 'forum_id', array_unique($forum_ids), true, true); - sync('topic_reported', $where_type, $where_ids); - } - - if ($approved_topics) - { - $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( - 'notification.type.topic', - 'notification.type.approve_topic', - 'notification.type.topic_in_queue', - ), $topic_ids); - - return $return; -} - -/** -* Remove post(s) -*/ -function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true) -{ - global $db, $config, $phpbb_root_path, $phpEx, $auth, $user, $phpbb_container, $phpbb_dispatcher; - - // Notifications types to delete - $delete_notifications_types = array( - 'notification.type.quote', - 'notification.type.approve_post', - 'notification.type.post_in_queue', - 'notification.type.report_post', - ); - - /** - * Perform additional actions before post(s) deletion - * - * @event core.delete_posts_before - * @var string where_type Variable containing posts deletion mode - * @var mixed where_ids Array or comma separated list of posts ids to delete - * @var bool auto_sync Flag indicating if topics/forums should be synchronized - * @var bool posted_sync Flag indicating if topics_posted table should be resynchronized - * @var bool post_count_sync Flag indicating if posts count should be resynchronized - * @var bool call_delete_topics Flag indicating if topics having no posts should be deleted - * @var array delete_notifications_types Array with notifications types to delete - * @since 3.1.0-a4 - */ - $vars = array( - 'where_type', - 'where_ids', - 'auto_sync', - 'posted_sync', - 'post_count_sync', - 'call_delete_topics', - 'delete_notifications_types', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_posts_before', compact($vars))); - - if ($where_type === 'range') - { - $where_clause = $where_ids; - } - else - { - if (is_array($where_ids)) - { - $where_ids = array_unique($where_ids); - } - else - { - $where_ids = array($where_ids); - } - - if (!count($where_ids)) - { - return false; - } - - $where_ids = array_map('intval', $where_ids); - -/* Possible code for splitting post deletion - if (count($where_ids) >= 1001) - { - // Split into chunks of 1000 - $chunks = array_chunk($where_ids, 1000); - - foreach ($chunks as $_where_ids) - { - delete_posts($where_type, $_where_ids, $auto_sync, $posted_sync, $post_count_sync, $call_delete_topics); - } - - return; - }*/ - - $where_clause = $db->sql_in_set($where_type, $where_ids); - } - - $approved_posts = 0; - $post_ids = $topic_ids = $forum_ids = $post_counts = $remove_topics = array(); - - $sql = 'SELECT post_id, poster_id, post_visibility, post_postcount, topic_id, forum_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $where_clause; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_ids[] = (int) $row['post_id']; - $poster_ids[] = (int) $row['poster_id']; - $topic_ids[] = (int) $row['topic_id']; - $forum_ids[] = (int) $row['forum_id']; - - if ($row['post_postcount'] && $post_count_sync && $row['post_visibility'] == ITEM_APPROVED) - { - $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1; - } - - if ($row['post_visibility'] == ITEM_APPROVED) - { - $approved_posts++; - } - } - $db->sql_freeresult($result); - - if (!count($post_ids)) - { - return false; - } - - $db->sql_transaction('begin'); - - $table_ary = array(POSTS_TABLE, REPORTS_TABLE); - - /** - * Perform additional actions during post(s) deletion before running the queries - * - * @event core.delete_posts_in_transaction_before - * @var array post_ids Array with deleted posts' ids - * @var array poster_ids Array with deleted posts' author ids - * @var array topic_ids Array with deleted posts' topic ids - * @var array forum_ids Array with deleted posts' forum ids - * @var string where_type Variable containing posts deletion mode - * @var mixed where_ids Array or comma separated list of post ids to delete - * @var array delete_notifications_types Array with notifications types to delete - * @var array table_ary Array with table names to delete data from - * @since 3.1.7-RC1 - */ - $vars = array( - 'post_ids', - 'poster_ids', - 'topic_ids', - 'forum_ids', - 'where_type', - 'where_ids', - 'delete_notifications_types', - 'table_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_posts_in_transaction_before', compact($vars))); - - foreach ($table_ary as $table) - { - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - } - unset($table_ary); - - // Adjust users post counts - if (count($post_counts) && $post_count_sync) - { - foreach ($post_counts as $poster_id => $substract) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = 0 - WHERE user_id = ' . $poster_id . ' - AND user_posts < ' . $substract; - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts - ' . $substract . ' - WHERE user_id = ' . $poster_id . ' - AND user_posts >= ' . $substract; - $db->sql_query($sql); - } - } - - // Remove topics now having no posts? - if (count($topic_ids)) - { - $sql = 'SELECT topic_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - GROUP BY topic_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $remove_topics[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - // Actually, those not within remove_topics should be removed. ;) - $remove_topics = array_diff($topic_ids, $remove_topics); - } - - // Remove the message from the search index - $search_type = $config['search_type']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if ($error) - { - trigger_error($error); - } - - $search->index_remove($post_ids, $poster_ids, $forum_ids); - - /** @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 - * - * @event core.delete_posts_in_transaction - * @var array post_ids Array with deleted posts' ids - * @var array poster_ids Array with deleted posts' author ids - * @var array topic_ids Array with deleted posts' topic ids - * @var array forum_ids Array with deleted posts' forum ids - * @var string where_type Variable containing posts deletion mode - * @var mixed where_ids Array or comma separated list of posts ids to delete - * @var array delete_notifications_types Array with notifications types to delete - * @since 3.1.0-a4 - */ - $vars = array( - 'post_ids', - 'poster_ids', - 'topic_ids', - 'forum_ids', - 'where_type', - 'where_ids', - 'delete_notifications_types', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_posts_in_transaction', compact($vars))); - - $db->sql_transaction('commit'); - - /** - * Perform additional actions after post(s) deletion - * - * @event core.delete_posts_after - * @var array post_ids Array with deleted posts' ids - * @var array poster_ids Array with deleted posts' author ids - * @var array topic_ids Array with deleted posts' topic ids - * @var array forum_ids Array with deleted posts' forum ids - * @var string where_type Variable containing posts deletion mode - * @var mixed where_ids Array or comma separated list of posts ids to delete - * @var array delete_notifications_types Array with notifications types to delete - * @since 3.1.0-a4 - */ - $vars = array( - 'post_ids', - 'poster_ids', - 'topic_ids', - 'forum_ids', - 'where_type', - 'where_ids', - 'delete_notifications_types', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_posts_after', compact($vars))); - - // Resync topics_posted table - if ($posted_sync) - { - update_posted_info($topic_ids); - } - - if ($auto_sync) - { - sync('topic_reported', 'topic_id', $topic_ids); - sync('topic', 'topic_id', $topic_ids, true); - sync('forum', 'forum_id', $forum_ids, true, true); - } - - if ($approved_posts && $post_count_sync) - { - $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 (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 count($post_ids); -} - -/** -* Deletes shadow topics pointing to a specified forum. -* -* @param int $forum_id The forum id -* @param string $sql_more Additional WHERE statement, e.g. t.topic_time < (time() - 1234) -* @param bool $auto_sync Will call sync() if this is true -* -* @return array Array with affected forums -*/ -function delete_topic_shadows($forum_id, $sql_more = '', $auto_sync = true) -{ - global $db; - - if (!$forum_id) - { - // Nothing to do. - return; - } - - // Set of affected forums we have to resync - $sync_forum_ids = array(); - - // Amount of topics we select and delete at once. - $batch_size = 500; - - do - { - $sql = 'SELECT t2.forum_id, t2.topic_id - FROM ' . TOPICS_TABLE . ' t2, ' . TOPICS_TABLE . ' t - WHERE t2.topic_moved_id = t.topic_id - AND t.forum_id = ' . (int) $forum_id . ' - ' . (($sql_more) ? 'AND ' . $sql_more : ''); - $result = $db->sql_query_limit($sql, $batch_size); - - $topic_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = (int) $row['topic_id']; - - $sync_forum_ids[(int) $row['forum_id']] = (int) $row['forum_id']; - } - $db->sql_freeresult($result); - - if (!empty($topic_ids)) - { - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - } - while (count($topic_ids) == $batch_size); - - if ($auto_sync) - { - sync('forum', 'forum_id', $sync_forum_ids, true, true); - } - - return $sync_forum_ids; -} - -/** -* Update/Sync posted information for topics -*/ -function update_posted_info(&$topic_ids) -{ - global $db, $config; - - if (empty($topic_ids) || !$config['load_db_track']) - { - return; - } - - // First of all, let us remove any posted information for these topics - $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - - // Now, let us collect the user/topic combos for rebuilding the information - $sql = 'SELECT poster_id, topic_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - AND poster_id <> ' . ANONYMOUS . ' - GROUP BY poster_id, topic_id'; - $result = $db->sql_query($sql); - - $posted = array(); - while ($row = $db->sql_fetchrow($result)) - { - // Add as key to make them unique (grouping by) and circumvent empty keys on array_unique - $posted[$row['poster_id']][] = $row['topic_id']; - } - $db->sql_freeresult($result); - - // Now add the information... - $sql_ary = array(); - foreach ($posted as $user_id => $topic_row) - { - foreach ($topic_row as $topic_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user_id, - 'topic_id' => (int) $topic_id, - 'topic_posted' => 1, - ); - } - } - unset($posted); - - $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); -} - -/** -* All-encompasing sync function -* -* Exaples: -* -* sync('topic', 'topic_id', 123); // resync topic #123 -* sync('topic', 'forum_id', array(2, 3)); // resync topics from forum #2 and #3 -* sync('topic'); // resync all topics -* sync('topic', 'range', 'topic_id BETWEEN 1 AND 60'); // resync a range of topics/forums (only available for 'topic' and 'forum' modes) -* -* -* Modes: -* - forum Resync complete forum -* - topic Resync topics -* - topic_moved Removes topic shadows that would be in the same forum as the topic they link to -* - topic_visibility Resyncs the topic_visibility flag according to the status of the first post -* - post_reported Resyncs the post_reported flag, relying on actual reports -* - topic_reported Resyncs the topic_reported flag, relying on post_reported flags -* - post_attachement Same as post_reported, but with attachment flags -* - topic_attachement Same as topic_reported, but with attachment flags -*/ -function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sync_extra = false) -{ - global $db; - - if (is_array($where_ids)) - { - $where_ids = array_unique($where_ids); - $where_ids = array_map('intval', $where_ids); - } - else if ($where_type != 'range') - { - $where_ids = ($where_ids) ? array((int) $where_ids) : array(); - } - - if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_visibility' || $mode == 'topic_reported' || $mode == 'post_reported') - { - if (!$where_type) - { - $where_sql = ''; - $where_sql_and = 'WHERE'; - } - else if ($where_type == 'range') - { - // Only check a range of topics/forums. For instance: 'topic_id BETWEEN 1 AND 60' - $where_sql = 'WHERE (' . $mode[0] . ".$where_ids)"; - $where_sql_and = $where_sql . "\n\tAND"; - } - else - { - // Do not sync the "global forum" - $where_ids = array_diff($where_ids, array(0)); - - if (!count($where_ids)) - { - // Empty array with IDs. This means that we don't have any work to do. Just return. - return; - } - - // Limit the topics/forums we are syncing, use specific topic/forum IDs. - // $where_type contains the field for the where clause (forum_id, topic_id) - $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids); - $where_sql_and = $where_sql . "\n\tAND"; - } - } - else - { - if (!count($where_ids)) - { - return; - } - - // $where_type contains the field for the where clause (forum_id, topic_id) - $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids); - $where_sql_and = $where_sql . "\n\tAND"; - } - - switch ($mode) - { - case 'topic_moved': - $db->sql_transaction('begin'); - switch ($db->get_sql_layer()) - { - case 'mysqli': - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - USING ' . TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2 - WHERE t1.topic_moved_id = t2.topic_id - AND t1.forum_id = t2.forum_id"; - $db->sql_query($sql); - break; - - default: - $sql = 'SELECT t1.topic_id - FROM ' .TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2 - WHERE t1.topic_moved_id = t2.topic_id - AND t1.forum_id = t2.forum_id"; - $result = $db->sql_query($sql); - - $topic_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_id_ary[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (!count($topic_id_ary)) - { - return; - } - - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_id_ary); - $db->sql_query($sql); - - break; - } - - $db->sql_transaction('commit'); - break; - - case 'topic_visibility': - - $db->sql_transaction('begin'); - - $sql = 'SELECT t.topic_id, p.post_visibility - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and p.topic_id = t.topic_id - AND p.post_visibility = " . ITEM_APPROVED; - $result = $db->sql_query($sql); - - $topics_approved = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topics_approved[] = (int) $row['topic_id']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT t.topic_id, p.post_visibility - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and " . $db->sql_in_set('t.topic_id', $topics_approved, true, true) . ' - AND p.topic_id = t.topic_id - AND p.post_visibility = ' . ITEM_DELETED; - $result = $db->sql_query($sql); - - $topics_softdeleted = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topics_softdeleted[] = (int) $row['topic_id']; - } - $db->sql_freeresult($result); - - $topics_softdeleted = array_diff($topics_softdeleted, $topics_approved); - $topics_not_unapproved = array_merge($topics_softdeleted, $topics_approved); - - $update_ary = array( - ITEM_UNAPPROVED => (!empty($topics_not_unapproved)) ? $where_sql_and . ' ' . $db->sql_in_set('topic_id', $topics_not_unapproved, true) : '', - ITEM_APPROVED => (!empty($topics_approved)) ? ' WHERE ' . $db->sql_in_set('topic_id', $topics_approved) : '', - ITEM_DELETED => (!empty($topics_softdeleted)) ? ' WHERE ' . $db->sql_in_set('topic_id', $topics_softdeleted) : '', - ); - - foreach ($update_ary as $visibility => $sql_where) - { - if ($sql_where) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_visibility = ' . $visibility . ' - ' . $sql_where; - $db->sql_query($sql); - } - } - - $db->sql_transaction('commit'); - break; - - case 'post_reported': - $post_ids = $post_reported = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT p.post_id, p.post_reported - FROM ' . POSTS_TABLE . " p - $where_sql - GROUP BY p.post_id, p.post_reported"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_ids[$row['post_id']] = $row['post_id']; - if ($row['post_reported']) - { - $post_reported[$row['post_id']] = 1; - } - } - $db->sql_freeresult($result); - - $sql = 'SELECT DISTINCT(post_id) - FROM ' . REPORTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids) . ' - AND report_closed = 0'; - $result = $db->sql_query($sql); - - $post_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($post_reported[$row['post_id']])) - { - $post_ids[] = $row['post_id']; - } - else - { - unset($post_reported[$row['post_id']]); - } - } - $db->sql_freeresult($result); - - // $post_reported should be empty by now, if it's not it contains - // posts that are falsely flagged as reported - foreach ($post_reported as $post_id => $void) - { - $post_ids[] = $post_id; - } - - if (count($post_ids)) - { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_reported = 1 - post_reported - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - break; - - case 'topic_reported': - if ($sync_extra) - { - sync('post_reported', $where_type, $where_ids); - } - - $topic_ids = $topic_reported = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT DISTINCT(t.topic_id) - FROM ' . POSTS_TABLE . " t - $where_sql_and t.post_reported = 1"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_reported[$row['topic_id']] = 1; - } - $db->sql_freeresult($result); - - $sql = 'SELECT t.topic_id, t.topic_reported - FROM ' . TOPICS_TABLE . " t - $where_sql"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_reported'] ^ isset($topic_reported[$row['topic_id']])) - { - $topic_ids[] = $row['topic_id']; - } - } - $db->sql_freeresult($result); - - if (count($topic_ids)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_reported = 1 - topic_reported - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - break; - - case 'post_attachment': - $post_ids = $post_attachment = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT p.post_id, p.post_attachment - FROM ' . POSTS_TABLE . " p - $where_sql - GROUP BY p.post_id, p.post_attachment"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_ids[$row['post_id']] = $row['post_id']; - if ($row['post_attachment']) - { - $post_attachment[$row['post_id']] = 1; - } - } - $db->sql_freeresult($result); - - $sql = 'SELECT DISTINCT(post_msg_id) - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . ' - AND in_message = 0'; - $result = $db->sql_query($sql); - - $post_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($post_attachment[$row['post_msg_id']])) - { - $post_ids[] = $row['post_msg_id']; - } - else - { - unset($post_attachment[$row['post_msg_id']]); - } - } - $db->sql_freeresult($result); - - // $post_attachment should be empty by now, if it's not it contains - // posts that are falsely flagged as having attachments - foreach ($post_attachment as $post_id => $void) - { - $post_ids[] = $post_id; - } - - if (count($post_ids)) - { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_attachment = 1 - post_attachment - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - break; - - case 'topic_attachment': - if ($sync_extra) - { - sync('post_attachment', $where_type, $where_ids); - } - - $topic_ids = $topic_attachment = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT DISTINCT(t.topic_id) - FROM ' . POSTS_TABLE . " t - $where_sql_and t.post_attachment = 1"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_attachment[$row['topic_id']] = 1; - } - $db->sql_freeresult($result); - - $sql = 'SELECT t.topic_id, t.topic_attachment - FROM ' . TOPICS_TABLE . " t - $where_sql"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_attachment'] ^ isset($topic_attachment[$row['topic_id']])) - { - $topic_ids[] = $row['topic_id']; - } - } - $db->sql_freeresult($result); - - if (count($topic_ids)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_attachment = 1 - topic_attachment - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - break; - - case 'forum': - - $db->sql_transaction('begin'); - - // 1: Get the list of all forums - $sql = 'SELECT f.* - FROM ' . FORUMS_TABLE . " f - $where_sql"; - $result = $db->sql_query($sql); - - $forum_data = $forum_ids = $post_ids = $last_post_id = $post_info = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['forum_type'] == FORUM_LINK) - { - continue; - } - - $forum_id = (int) $row['forum_id']; - $forum_ids[$forum_id] = $forum_id; - - $forum_data[$forum_id] = $row; - if ($sync_extra) - { - $forum_data[$forum_id]['posts_approved'] = 0; - $forum_data[$forum_id]['posts_unapproved'] = 0; - $forum_data[$forum_id]['posts_softdeleted'] = 0; - $forum_data[$forum_id]['topics_approved'] = 0; - $forum_data[$forum_id]['topics_unapproved'] = 0; - $forum_data[$forum_id]['topics_softdeleted'] = 0; - } - $forum_data[$forum_id]['last_post_id'] = 0; - $forum_data[$forum_id]['last_post_subject'] = ''; - $forum_data[$forum_id]['last_post_time'] = 0; - $forum_data[$forum_id]['last_poster_id'] = 0; - $forum_data[$forum_id]['last_poster_name'] = ''; - $forum_data[$forum_id]['last_poster_colour'] = ''; - } - $db->sql_freeresult($result); - - if (!count($forum_ids)) - { - break; - } - - $forum_ids = array_values($forum_ids); - - // 2: Get topic counts for each forum (optional) - if ($sync_extra) - { - $sql = 'SELECT forum_id, topic_visibility, COUNT(topic_id) AS total_topics - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . ' - GROUP BY forum_id, topic_visibility'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_id = (int) $row['forum_id']; - - if ($row['topic_visibility'] == ITEM_APPROVED) - { - $forum_data[$forum_id]['topics_approved'] = $row['total_topics']; - } - else if ($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) - { - $forum_data[$forum_id]['topics_unapproved'] = $row['total_topics']; - } - else if ($row['topic_visibility'] == ITEM_DELETED) - { - $forum_data[$forum_id]['topics_softdeleted'] = $row['total_topics']; - } - } - $db->sql_freeresult($result); - } - - // 3: Get post count for each forum (optional) - if ($sync_extra) - { - 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 - WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_status <> ' . ITEM_MOVED; - } - else - { - $sql = 'SELECT t.forum_id, SUM(t.topic_posts_approved) AS forum_posts_approved, SUM(t.topic_posts_unapproved) AS forum_posts_unapproved, SUM(t.topic_posts_softdeleted) AS forum_posts_softdeleted - FROM ' . TOPICS_TABLE . ' t - WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_status <> ' . ITEM_MOVED . ' - GROUP BY t.forum_id'; - } - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $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']; - $forum_data[$forum_id]['posts_softdeleted'] = (int) $row['forum_posts_softdeleted']; - } - $db->sql_freeresult($result); - } - - // 4: Get last_post_id for each forum - if (count($forum_ids) == 1) - { - $sql = 'SELECT MAX(t.topic_last_post_id) as last_post_id - FROM ' . TOPICS_TABLE . ' t - WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_visibility = ' . ITEM_APPROVED; - } - else - { - $sql = 'SELECT t.forum_id, MAX(t.topic_last_post_id) as last_post_id - FROM ' . TOPICS_TABLE . ' t - WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_visibility = ' . ITEM_APPROVED . ' - GROUP BY t.forum_id'; - } - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $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']; - - $post_ids[] = $row['last_post_id']; - } - $db->sql_freeresult($result); - - // 5: Retrieve last_post infos - 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 - WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' - AND p.poster_id = u.user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_info[$row['post_id']] = $row; - } - $db->sql_freeresult($result); - - foreach ($forum_data as $forum_id => $data) - { - if ($data['last_post_id']) - { - if (isset($post_info[$data['last_post_id']])) - { - $forum_data[$forum_id]['last_post_subject'] = $post_info[$data['last_post_id']]['post_subject']; - $forum_data[$forum_id]['last_post_time'] = $post_info[$data['last_post_id']]['post_time']; - $forum_data[$forum_id]['last_poster_id'] = $post_info[$data['last_post_id']]['poster_id']; - $forum_data[$forum_id]['last_poster_name'] = ($post_info[$data['last_post_id']]['poster_id'] != ANONYMOUS) ? $post_info[$data['last_post_id']]['username'] : $post_info[$data['last_post_id']]['post_username']; - $forum_data[$forum_id]['last_poster_colour'] = $post_info[$data['last_post_id']]['user_colour']; - } - else - { - // For some reason we did not find the post in the db - $forum_data[$forum_id]['last_post_id'] = 0; - $forum_data[$forum_id]['last_post_subject'] = ''; - $forum_data[$forum_id]['last_post_time'] = 0; - $forum_data[$forum_id]['last_poster_id'] = 0; - $forum_data[$forum_id]['last_poster_name'] = ''; - $forum_data[$forum_id]['last_poster_colour'] = ''; - } - } - } - unset($post_info); - } - - // 6: Now do that thing - $fieldnames = array('last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); - - if ($sync_extra) - { - array_push($fieldnames, 'posts_approved', 'posts_unapproved', 'posts_softdeleted', 'topics_approved', 'topics_unapproved', 'topics_softdeleted'); - } - - foreach ($forum_data as $forum_id => $row) - { - $sql_ary = array(); - - foreach ($fieldnames as $fieldname) - { - if ($row['forum_' . $fieldname] != $row[$fieldname]) - { - if (preg_match('#(name|colour|subject)$#', $fieldname)) - { - $sql_ary['forum_' . $fieldname] = (string) $row[$fieldname]; - } - else - { - $sql_ary['forum_' . $fieldname] = (int) $row[$fieldname]; - } - } - } - - if (count($sql_ary)) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE forum_id = ' . $forum_id; - $db->sql_query($sql); - } - } - - $db->sql_transaction('commit'); - break; - - case 'topic': - $topic_data = $post_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_visibility, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_first_post_id, t.topic_first_poster_name, t.topic_first_poster_colour, t.topic_last_post_id, t.topic_last_post_subject, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_poster_colour, t.topic_last_post_time - FROM ' . TOPICS_TABLE . " t - $where_sql"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_moved_id']) - { - $moved_topics[] = $row['topic_id']; - continue; - } - - $topic_id = (int) $row['topic_id']; - $topic_data[$topic_id] = $row; - $topic_data[$topic_id]['visibility'] = ITEM_UNAPPROVED; - $topic_data[$topic_id]['posts_approved'] = 0; - $topic_data[$topic_id]['posts_unapproved'] = 0; - $topic_data[$topic_id]['posts_softdeleted'] = 0; - $topic_data[$topic_id]['first_post_id'] = 0; - $topic_data[$topic_id]['last_post_id'] = 0; - unset($topic_data[$topic_id]['topic_id']); - - // This array holds all topic_ids - $delete_topics[$topic_id] = ''; - - if ($sync_extra) - { - $topic_data[$topic_id]['reported'] = 0; - $topic_data[$topic_id]['attachment'] = 0; - } - } - $db->sql_freeresult($result); - - // Use "t" as table alias because of the $where_sql clause - // NOTE: 't.post_visibility' in the GROUP BY is causing a major slowdown. - $sql = 'SELECT t.topic_id, t.post_visibility, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id - FROM ' . POSTS_TABLE . " t - $where_sql - GROUP BY t.topic_id, t.post_visibility"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id = (int) $row['topic_id']; - - $row['first_post_id'] = (int) $row['first_post_id']; - $row['last_post_id'] = (int) $row['last_post_id']; - - if (!isset($topic_data[$topic_id])) - { - // Hey, these posts come from a topic that does not exist - $delete_posts[$topic_id] = ''; - } - else - { - // Unset the corresponding entry in $delete_topics - // When we'll be done, only topics with no posts will remain - unset($delete_topics[$topic_id]); - - if ($row['post_visibility'] == ITEM_APPROVED) - { - $topic_data[$topic_id]['posts_approved'] = $row['total_posts']; - } - else if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) - { - $topic_data[$topic_id]['posts_unapproved'] = $row['total_posts']; - } - else if ($row['post_visibility'] == ITEM_DELETED) - { - $topic_data[$topic_id]['posts_softdeleted'] = $row['total_posts']; - } - - if ($row['post_visibility'] == ITEM_APPROVED) - { - $topic_data[$topic_id]['visibility'] = ITEM_APPROVED; - $topic_data[$topic_id]['first_post_id'] = $row['first_post_id']; - $topic_data[$topic_id]['last_post_id'] = $row['last_post_id']; - } - else if ($topic_data[$topic_id]['visibility'] != ITEM_APPROVED) - { - // If there is no approved post, we take the min/max of the other visibilities - // for the last and first post info, because it is only visible to moderators anyway - $topic_data[$topic_id]['first_post_id'] = (!empty($topic_data[$topic_id]['first_post_id'])) ? min($topic_data[$topic_id]['first_post_id'], $row['first_post_id']) : $row['first_post_id']; - $topic_data[$topic_id]['last_post_id'] = max($topic_data[$topic_id]['last_post_id'], $row['last_post_id']); - - if ($topic_data[$topic_id]['visibility'] == ITEM_UNAPPROVED || $topic_data[$topic_id]['visibility'] == ITEM_REAPPROVE) - { - // Soft delete status is stronger than unapproved. - $topic_data[$topic_id]['visibility'] = $row['post_visibility']; - } - } - } - } - $db->sql_freeresult($result); - - foreach ($topic_data as $topic_id => $row) - { - $post_ids[] = $row['first_post_id']; - if ($row['first_post_id'] != $row['last_post_id']) - { - $post_ids[] = $row['last_post_id']; - } - } - - // Now we delete empty topics and orphan posts - if (count($delete_posts)) - { - delete_posts('topic_id', array_keys($delete_posts), false); - unset($delete_posts); - } - - 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 (count($delete_topics)) - { - $delete_topic_ids = array(); - foreach ($delete_topics as $topic_id => $void) - { - unset($topic_data[$topic_id]); - $delete_topic_ids[] = $topic_id; - } - - delete_topics('topic_id', $delete_topic_ids, false); - unset($delete_topics, $delete_topic_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 - WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' - AND u.user_id = p.poster_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id = intval($row['topic_id']); - - if ($row['post_id'] == $topic_data[$topic_id]['first_post_id']) - { - $topic_data[$topic_id]['time'] = $row['post_time']; - $topic_data[$topic_id]['poster'] = $row['poster_id']; - $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; - $topic_data[$topic_id]['first_poster_colour'] = $row['user_colour']; - } - - if ($row['post_id'] == $topic_data[$topic_id]['last_post_id']) - { - $topic_data[$topic_id]['last_poster_id'] = $row['poster_id']; - $topic_data[$topic_id]['last_post_subject'] = $row['post_subject']; - $topic_data[$topic_id]['last_post_time'] = $row['post_time']; - $topic_data[$topic_id]['last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; - $topic_data[$topic_id]['last_poster_colour'] = $row['user_colour']; - } - } - $db->sql_freeresult($result); - - // Make sure shadow topics do link to existing topics - if (count($moved_topics)) - { - $delete_topics = array(); - - $sql = 'SELECT t1.topic_id, t1.topic_moved_id - FROM ' . TOPICS_TABLE . ' t1 - LEFT JOIN ' . TOPICS_TABLE . ' t2 ON (t2.topic_id = t1.topic_moved_id) - WHERE ' . $db->sql_in_set('t1.topic_id', $moved_topics) . ' - AND t2.topic_id IS NULL'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $delete_topics[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (count($delete_topics)) - { - delete_topics('topic_id', $delete_topics, false); - } - unset($delete_topics); - - // Make sure shadow topics having no last post data being updated (this only rarely happens...) - $sql = 'SELECT topic_id, topic_moved_id, topic_last_post_id, topic_first_post_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $moved_topics) . ' - AND topic_last_post_time = 0'; - $result = $db->sql_query($sql); - - $shadow_topic_data = $post_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $shadow_topic_data[$row['topic_moved_id']] = $row; - $post_ids[] = $row['topic_last_post_id']; - $post_ids[] = $row['topic_first_post_id']; - } - $db->sql_freeresult($result); - - $sync_shadow_topics = array(); - 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 - WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' - AND u.user_id = p.poster_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id = (int) $row['topic_id']; - - // Ok, there should be a shadow topic. If there isn't, then there's something wrong with the db. - // However, there's not much we can do about it. - if (!empty($shadow_topic_data[$topic_id])) - { - if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_first_post_id']) - { - $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id']; - - if (!isset($sync_shadow_topics[$orig_topic_id])) - { - $sync_shadow_topics[$orig_topic_id] = array(); - } - - $sync_shadow_topics[$orig_topic_id]['topic_time'] = $row['post_time']; - $sync_shadow_topics[$orig_topic_id]['topic_poster'] = $row['poster_id']; - $sync_shadow_topics[$orig_topic_id]['topic_first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; - $sync_shadow_topics[$orig_topic_id]['topic_first_poster_colour'] = $row['user_colour']; - } - - if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_last_post_id']) - { - $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id']; - - if (!isset($sync_shadow_topics[$orig_topic_id])) - { - $sync_shadow_topics[$orig_topic_id] = array(); - } - - $sync_shadow_topics[$orig_topic_id]['topic_last_poster_id'] = $row['poster_id']; - $sync_shadow_topics[$orig_topic_id]['topic_last_post_subject'] = $row['post_subject']; - $sync_shadow_topics[$orig_topic_id]['topic_last_post_time'] = $row['post_time']; - $sync_shadow_topics[$orig_topic_id]['topic_last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; - $sync_shadow_topics[$orig_topic_id]['topic_last_poster_colour'] = $row['user_colour']; - } - } - } - $db->sql_freeresult($result); - - $shadow_topic_data = array(); - - // Update the information we collected - if (count($sync_shadow_topics)) - { - foreach ($sync_shadow_topics as $sync_topic_id => $sql_ary) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE topic_id = ' . $sync_topic_id; - $db->sql_query($sql); - } - } - } - - unset($sync_shadow_topics, $shadow_topic_data); - } - - // These are fields that will be synchronised - $fieldnames = array('time', 'visibility', 'posts_approved', 'posts_unapproved', 'posts_softdeleted', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); - - if ($sync_extra) - { - // This routine assumes that post_reported values are correct - // if they are not, use sync('post_reported') first - $sql = 'SELECT t.topic_id, p.post_id - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and p.topic_id = t.topic_id - AND p.post_reported = 1 - GROUP BY t.topic_id, p.post_id"; - $result = $db->sql_query($sql); - - $fieldnames[] = 'reported'; - while ($row = $db->sql_fetchrow($result)) - { - $topic_data[intval($row['topic_id'])]['reported'] = 1; - } - $db->sql_freeresult($result); - - // This routine assumes that post_attachment values are correct - // if they are not, use sync('post_attachment') first - $sql = 'SELECT t.topic_id, p.post_id - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and p.topic_id = t.topic_id - AND p.post_attachment = 1 - GROUP BY t.topic_id, p.post_id"; - $result = $db->sql_query($sql); - - $fieldnames[] = 'attachment'; - while ($row = $db->sql_fetchrow($result)) - { - $topic_data[intval($row['topic_id'])]['attachment'] = 1; - } - $db->sql_freeresult($result); - } - - foreach ($topic_data as $topic_id => $row) - { - $sql_ary = array(); - - foreach ($fieldnames as $fieldname) - { - if (isset($row[$fieldname]) && isset($row['topic_' . $fieldname]) && $row['topic_' . $fieldname] != $row[$fieldname]) - { - $sql_ary['topic_' . $fieldname] = $row[$fieldname]; - } - } - - if (count($sql_ary)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE topic_id = ' . $topic_id; - $db->sql_query($sql); - - $resync_forums[$row['forum_id']] = $row['forum_id']; - } - } - unset($topic_data); - - $db->sql_transaction('commit'); - - // if some topics have been resync'ed then resync parent forums - // except when we're only syncing a range, we don't want to sync forums during - // batch processing. - if ($resync_parents && count($resync_forums) && $where_type != 'range') - { - sync('forum', 'forum_id', array_values($resync_forums), true, true); - } - break; - } - - return; -} - -/** -* Prune function -*/ -function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true, $prune_limit = 0) -{ - global $db, $phpbb_dispatcher; - - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - if (!count($forum_id)) - { - return; - } - - $sql_and = ''; - - if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE)) - { - $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE; - $sql_and .= ' AND topic_type <> ' . POST_GLOBAL; - } - - if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY)) - { - $sql_and .= ' AND topic_type <> ' . POST_STICKY; - } - - if ($prune_mode == 'posted') - { - $sql_and .= " AND topic_last_post_time < $prune_date"; - } - - if ($prune_mode == 'viewed') - { - $sql_and .= " AND topic_last_view_time < $prune_date"; - } - - if ($prune_mode == 'shadow') - { - $sql_and .= ' AND topic_status = ' . ITEM_MOVED . " AND topic_last_post_time < $prune_date"; - } - - /** - * Use this event to modify the SQL that selects topics to be pruned - * - * @event core.prune_sql - * @var string forum_id The forum id - * @var string prune_mode The prune mode - * @var string prune_date The prune date - * @var int prune_flags The prune flags - * @var bool auto_sync Whether or not to perform auto sync - * @var string sql_and SQL text appended to where clause - * @var int prune_limit The prune limit - * @since 3.1.3-RC1 - * @changed 3.1.10-RC1 Added prune_limit - */ - $vars = array( - 'forum_id', - 'prune_mode', - 'prune_date', - 'prune_flags', - 'auto_sync', - 'sql_and', - 'prune_limit', - ); - extract($phpbb_dispatcher->trigger_event('core.prune_sql', compact($vars))); - - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id) . " - AND poll_start = 0 - $sql_and"; - $result = $db->sql_query_limit($sql, $prune_limit); - - $topic_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_list[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if ($prune_flags & FORUM_FLAG_PRUNE_POLL) - { - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id) . " - AND poll_start > 0 - AND poll_last_vote < $prune_date - $sql_and"; - $result = $db->sql_query_limit($sql, $prune_limit); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_list[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - $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); -} - -/** -* Function auto_prune(), this function now relies on passed vars -*/ -function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_freq) -{ - global $db, $user, $phpbb_log; - - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql, 3600); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $prune_date = time() - ($prune_days * 86400); - $next_prune = time() + ($prune_freq * 86400); - - $result = prune($forum_id, $prune_mode, $prune_date, $prune_flags, true, 300); - - if ($result['topics'] == 0 && $result['posts'] == 0) - { - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET prune_next = $next_prune - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_AUTO_PRUNE', false, array($row['forum_name'])); - } - - return; -} - -/** -* Cache moderators. Called whenever permissions are changed -* via admin_permissions. Changes of usernames and group names -* must be carried through for the moderators table. -* -* @param \phpbb\db\driver\driver_interface $db Database connection -* @param \phpbb\cache\driver\driver_interface Cache driver -* @param \phpbb\auth\auth $auth Authentication object -* @return null -*/ -function phpbb_cache_moderators($db, $cache, $auth) -{ - // Remove cached sql results - $cache->destroy('sql', MODERATOR_CACHE_TABLE); - - // Clear table - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE); - break; - - default: - $db->sql_query('TRUNCATE TABLE ' . MODERATOR_CACHE_TABLE); - break; - } - - // We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting - $sql_ary = array(); - - // Grab all users having moderative options... - $hold_ary = $auth->acl_user_raw_data(false, 'm_%', false); - - // Add users? - if (!empty($hold_ary)) - { - // At least one moderative option warrants a display - $ug_id_ary = array_keys($hold_ary); - - // Remove users who have group memberships with DENY moderator permissions - $sql_ary_deny = array( - 'SELECT' => 'a.forum_id, ug.user_id, g.group_id', - - 'FROM' => array( - ACL_OPTIONS_TABLE => 'o', - USER_GROUP_TABLE => 'ug', - GROUPS_TABLE => 'g', - ACL_GROUPS_TABLE => 'a', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id', - ), - ), - - 'WHERE' => '(o.auth_option_id = a.auth_option_id OR o.auth_option_id = r.auth_option_id) - AND ((a.auth_setting = ' . ACL_NEVER . ' AND r.auth_setting IS NULL) - OR r.auth_setting = ' . ACL_NEVER . ') - AND a.group_id = ug.group_id - AND g.group_id = ug.group_id - AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) - AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . " - AND ug.user_pending = 0 - AND o.auth_option " . $db->sql_like_expression('m_' . $db->get_any_char()), - ); - $sql = $db->sql_build_query('SELECT', $sql_ary_deny); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (isset($hold_ary[$row['user_id']][$row['forum_id']])) - { - unset($hold_ary[$row['user_id']][$row['forum_id']]); - } - } - $db->sql_freeresult($result); - - if (count($hold_ary)) - { - // Get usernames... - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary)); - $result = $db->sql_query($sql); - - $usernames_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $usernames_ary[$row['user_id']] = $row['username']; - } - $db->sql_freeresult($result); - - foreach ($hold_ary as $user_id => $forum_id_ary) - { - // Do not continue if user does not exist - if (!isset($usernames_ary[$user_id])) - { - continue; - } - - foreach ($forum_id_ary as $forum_id => $auth_ary) - { - $sql_ary[] = array( - 'forum_id' => (int) $forum_id, - 'user_id' => (int) $user_id, - 'username' => (string) $usernames_ary[$user_id], - 'group_id' => 0, - 'group_name' => '' - ); - } - } - } - } - - // Now to the groups... - $hold_ary = $auth->acl_group_raw_data(false, 'm_%', false); - - if (!empty($hold_ary)) - { - $ug_id_ary = array_keys($hold_ary); - - // Make sure not hidden or special groups are involved... - $sql = 'SELECT group_name, group_id, group_type - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', $ug_id_ary); - $result = $db->sql_query($sql); - - $groupnames_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['group_type'] == GROUP_HIDDEN || $row['group_type'] == GROUP_SPECIAL) - { - unset($hold_ary[$row['group_id']]); - } - - $groupnames_ary[$row['group_id']] = $row['group_name']; - } - $db->sql_freeresult($result); - - foreach ($hold_ary as $group_id => $forum_id_ary) - { - // If there is no group, we do not assign it... - if (!isset($groupnames_ary[$group_id])) - { - continue; - } - - foreach ($forum_id_ary as $forum_id => $auth_ary) - { - $flag = false; - foreach ($auth_ary as $auth_option => $setting) - { - // Make sure at least one ACL_YES option is set... - if ($setting == ACL_YES) - { - $flag = true; - break; - } - } - - if (!$flag) - { - continue; - } - - $sql_ary[] = array( - 'forum_id' => (int) $forum_id, - 'user_id' => 0, - 'username' => '', - 'group_id' => (int) $group_id, - 'group_name' => (string) $groupnames_ary[$group_id] - ); - } - } - } - - $db->sql_multi_insert(MODERATOR_CACHE_TABLE, $sql_ary); -} - -/** -* View log -* -* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved -* @param array &$log The result array with the logs -* @param mixed &$log_count If $log_count is set to false, we will skip counting all entries in the database. -* Otherwise an integer with the number of total matching entries is returned. -* @param int $limit Limit the number of entries that are returned -* @param int $offset Offset when fetching the log entries, f.e. when paginating -* @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids) -* @param int $topic_id Restrict the log entries to the given topic_id -* @param int $user_id Restrict the log entries to the given user_id -* @param int $log_time Only get log entries newer than the given timestamp -* @param string $sort_by SQL order option, e.g. 'l.log_time DESC' -* @param string $keywords Will only return log entries that have the keywords in log_operation or log_data -* -* @return int Returns the offset of the last valid page, if the specified offset was invalid (too high) -*/ -function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '') -{ - global $phpbb_log; - - $count_logs = ($log_count !== false); - - $log = $phpbb_log->get_logs($mode, $count_logs, $limit, $offset, $forum_id, $topic_id, $user_id, $limit_days, $sort_by, $keywords); - $log_count = $phpbb_log->get_log_count(); - - return $phpbb_log->get_valid_offset(); -} - -/** -* Removes moderators and administrators from foe lists. -* -* @param \phpbb\db\driver\driver_interface $db Database connection -* @param \phpbb\auth\auth $auth Authentication object -* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore -* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore -* @return null -*/ -function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false) -{ - // update foes for some user - if (is_array($user_id) && count($user_id)) - { - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $db->sql_in_set('zebra_id', $user_id) . ' - AND foe = 1'; - $db->sql_query($sql); - return; - } - - // update foes for some group - if (is_array($group_id) && count($group_id)) - { - // Grab group settings... - $sql_ary = array( - 'SELECT' => 'a.group_id', - - 'FROM' => array( - ACL_OPTIONS_TABLE => 'ao', - ACL_GROUPS_TABLE => 'a', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id', - ), - ), - - 'WHERE' => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id) - AND ' . $db->sql_in_set('a.group_id', $group_id) . " - AND ao.auth_option IN ('a_', 'm_')", - - 'GROUP_BY' => 'a.group_id', - ); - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - - $groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $groups[] = (int) $row['group_id']; - } - $db->sql_freeresult($result); - - if (!count($groups)) - { - return; - } - - switch ($db->get_sql_layer()) - { - case 'mysqli': - $sql = 'DELETE z.* - FROM ' . ZEBRA_TABLE . ' z, ' . USER_GROUP_TABLE . ' ug - WHERE z.zebra_id = ug.user_id - AND z.foe = 1 - AND ' . $db->sql_in_set('ug.group_id', $groups); - $db->sql_query($sql); - break; - - default: - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', $groups); - $result = $db->sql_query($sql); - - $users = array(); - while ($row = $db->sql_fetchrow($result)) - { - $users[] = (int) $row['user_id']; - } - $db->sql_freeresult($result); - - if (count($users)) - { - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $db->sql_in_set('zebra_id', $users) . ' - AND foe = 1'; - $db->sql_query($sql); - } - break; - } - - return; - } - - // update foes for everyone - $perms = array(); - foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary) - { - foreach ($forum_ary as $auth_option => $user_ary) - { - $perms = array_merge($perms, $user_ary); - } - } - - if (count($perms)) - { - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . ' - AND foe = 1'; - $db->sql_query($sql); - } - unset($perms); -} - -/** -* Lists inactive users -*/ -function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC') -{ - global $db, $user; - - $sql = 'SELECT COUNT(user_id) AS user_count - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_INACTIVE . - (($limit_days) ? " AND user_inactive_time >= $limit_days" : ''); - $result = $db->sql_query($sql); - $user_count = (int) $db->sql_fetchfield('user_count'); - $db->sql_freeresult($result); - - if ($user_count == 0) - { - // Save the queries, because there are no users to display - return 0; - } - - if ($offset >= $user_count) - { - $offset = ($offset - $limit < 0) ? 0 : $offset - $limit; - } - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_INACTIVE . - (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . " - ORDER BY $sort_by"; - $result = $db->sql_query_limit($sql, $limit, $offset); - - while ($row = $db->sql_fetchrow($result)) - { - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_UNKNOWN']; - switch ($row['user_inactive_reason']) - { - case INACTIVE_REGISTER: - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REGISTER']; - break; - - case INACTIVE_PROFILE: - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_PROFILE']; - break; - - case INACTIVE_MANUAL: - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_MANUAL']; - break; - - case INACTIVE_REMIND: - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REMIND']; - break; - } - - $users[] = $row; - } - $db->sql_freeresult($result); - - return $offset; -} - -/** -* Lists warned users -*/ -function view_warned_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_warnings DESC') -{ - global $db; - - $sql = 'SELECT user_id, username, user_colour, user_warnings, user_last_warning - FROM ' . USERS_TABLE . ' - WHERE user_warnings > 0 - ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '') . " - ORDER BY $sort_by"; - $result = $db->sql_query_limit($sql, $limit, $offset); - $users = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - $sql = 'SELECT count(user_id) AS user_count - FROM ' . USERS_TABLE . ' - WHERE user_warnings > 0 - ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : ''); - $result = $db->sql_query($sql); - $user_count = (int) $db->sql_fetchfield('user_count'); - $db->sql_freeresult($result); - - return; -} - -/** -* Get database size -* Currently only mysql and mssql are supported -*/ -function get_database_size() -{ - global $db, $user, $table_prefix; - - $database_size = false; - - // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0 - switch ($db->get_sql_layer()) - { - case 'mysqli': - $sql = 'SELECT VERSION() AS mysql_version'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $version = $row['mysql_version']; - - if (preg_match('#(3\.23|[45]\.|10\.[0-9]\.[0-9]{1,2}-+Maria)#', $version)) - { - $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.|10\.[0-9]\.[0-9]{1,2}-+Maria#', $version)) ? "`{$db->get_db_name()}`" : $db->get_db_name(); - - $sql = 'SHOW TABLE STATUS - FROM ' . $db_name; - $result = $db->sql_query($sql, 7200); - - $database_size = 0; - while ($row = $db->sql_fetchrow($result)) - { - if ((isset($row['Type']) && $row['Type'] != 'MRG_MyISAM') || (isset($row['Engine']) && ($row['Engine'] == 'MyISAM' || $row['Engine'] == 'InnoDB' || $row['Engine'] == 'Aria'))) - { - if ($table_prefix != '') - { - if (strpos($row['Name'], $table_prefix) !== false) - { - $database_size += $row['Data_length'] + $row['Index_length']; - } - } - else - { - $database_size += $row['Data_length'] + $row['Index_length']; - } - } - } - $db->sql_freeresult($result); - } - } - break; - - case 'sqlite3': - global $dbhost; - - if (file_exists($dbhost)) - { - $database_size = filesize($dbhost); - } - - break; - - case 'mssql_odbc': - case 'mssqlnative': - $sql = 'SELECT @@VERSION AS mssql_version'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize - FROM sysfiles'; - - if ($row) - { - // Azure stats are stored elsewhere - if (strpos($row['mssql_version'], 'SQL Azure') !== false) - { - $sql = 'SELECT ((SUM(reserved_page_count) * 8.0) * 1024.0) as dbsize - FROM sys.dm_db_partition_stats'; - } - } - - $result = $db->sql_query($sql, 7200); - $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false; - $db->sql_freeresult($result); - break; - - case 'postgres': - $sql = "SELECT proname - FROM pg_proc - WHERE proname = 'pg_database_size'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row['proname'] == 'pg_database_size') - { - $database = $db->get_db_name(); - if (strpos($database, '.') !== false) - { - list($database, ) = explode('.', $database); - } - - $sql = "SELECT oid - FROM pg_database - WHERE datname = '$database'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $oid = $row['oid']; - - $sql = 'SELECT pg_database_size(' . $oid . ') as size'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $database_size = $row['size']; - } - break; - - case 'oracle': - $sql = 'SELECT SUM(bytes) as dbsize - FROM user_segments'; - $result = $db->sql_query($sql, 7200); - $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false; - $db->sql_freeresult($result); - break; - } - - $database_size = ($database_size !== false) ? get_formatted_filesize($database_size) : $user->lang['NOT_AVAILABLE']; - - return $database_size; -} - -/* -* Tidy Warnings -* Remove all warnings which have now expired from the database -* The duration of a warning can be defined by the administrator -* This only removes the warning and reduces the associated count, -* it does not remove the user note recording the contents of the warning -*/ -function tidy_warnings() -{ - global $db, $config; - - $expire_date = time() - ($config['warnings_expire_days'] * 86400); - $warning_list = $user_list = array(); - - $sql = 'SELECT * FROM ' . WARNINGS_TABLE . " - WHERE warning_time < $expire_date"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $warning_list[] = $row['warning_id']; - $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? ++$user_list[$row['user_id']] : 1; - } - $db->sql_freeresult($result); - - if (count($warning_list)) - { - $db->sql_transaction('begin'); - - $sql = 'DELETE FROM ' . WARNINGS_TABLE . ' - WHERE ' . $db->sql_in_set('warning_id', $warning_list); - $db->sql_query($sql); - - foreach ($user_list as $user_id => $value) - { - $sql = 'UPDATE ' . USERS_TABLE . " SET user_warnings = user_warnings - $value - WHERE user_id = $user_id"; - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - } - - $config->set('warnings_last_gc', time(), false); -} - -/** -* Tidy database, doing some maintanance tasks -*/ -function tidy_database() -{ - global $config, $db; - - // Here we check permission consistency - - // Sometimes, it can happen permission tables having forums listed which do not exist - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - - $forum_ids = array(0); - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $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); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - $config->set('database_last_gc', time(), false); -} - -/** -* Add permission language - this will make sure custom files will be included -*/ -function add_permission_language() -{ - global $user, $phpEx, $phpbb_extension_manager; - - // add permission language files from extensions - $finder = $phpbb_extension_manager->get_finder(); - - $lang_files = $finder - ->prefix('permissions_') - ->suffix(".$phpEx") - ->core_path('language/') - ->extension_directory('/language') - ->find(); - - foreach ($lang_files as $lang_file => $ext_name) - { - if ($ext_name === '/') - { - $user->add_lang($lang_file); - } - else - { - $user->add_lang_ext($ext_name, $lang_file); - } - } -} - -/** - * Enables a particular flag in a bitfield column of a given table. - * - * @param string $table_name The table to update - * @param string $column_name The column containing a bitfield to update - * @param int $flag The binary flag which is OR-ed with the current column value - * @param string $sql_more This string is attached to the sql query generated to update the table. - * - * @return null - */ -function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '') -{ - global $db; - - $sql = 'UPDATE ' . $table_name . ' - SET ' . $column_name . ' = ' . $db->sql_bit_or($column_name, $flag) . ' - ' . $sql_more; - $db->sql_query($sql); -} diff --git a/install/update/new/includes/functions_compatibility.php b/install/update/new/includes/functions_compatibility.php deleted file mode 100644 index 92e24c0..0000000 --- a/install/update/new/includes/functions_compatibility.php +++ /dev/null @@ -1,675 +0,0 @@ - -* @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; -} - -/** -* Get user avatar -* -* @deprecated 3.1.0-a1 (To be removed: 4.0.0) -* -* @param string $avatar Users assigned avatar name -* @param int $avatar_type Type of avatar -* @param string $avatar_width Width of users avatar -* @param string $avatar_height Height of users avatar -* @param string $alt Optional language string for alt tag within image, can be a language key or text -* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP -* @param bool $lazy If true, will be lazy loaded (requires JS) -* -* @return string Avatar image -*/ -function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false, $lazy = false) -{ - // map arguments to new function phpbb_get_avatar() - $row = array( - 'avatar' => $avatar, - 'avatar_type' => $avatar_type, - 'avatar_width' => $avatar_width, - 'avatar_height' => $avatar_height, - ); - - return phpbb_get_avatar($row, $alt, $ignore_config, $lazy); -} - -/** -* Hash the password -* -* @deprecated 3.1.0-a2 (To be removed: 4.0.0) -* -* @param string $password Password to be hashed -* -* @return string|bool Password hash or false if something went wrong during hashing -*/ -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); -} - -/** -* Check for correct password -* -* @deprecated 3.1.0-a2 (To be removed: 4.0.0) -* -* @param string $password The password in plain text -* @param string $hash The stored password hash -* -* @return bool Returns true if the password is correct, false if not. -*/ -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); -} - -/** -* Eliminates useless . and .. components from specified path. -* -* Deprecated, use filesystem class instead -* -* @param string $path Path to clean -* @return string Cleaned path -* -* @deprecated 3.1.0 (To be removed: 4.0.0) -*/ -function phpbb_clean_path($path) -{ - global $phpbb_path_helper, $phpbb_container; - - 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) - { - global $phpbb_root_path, $phpEx; - - // The container is not yet loaded, use a new instance - if (!class_exists('\phpbb\path_helper')) - { - require($phpbb_root_path . 'phpbb/path_helper.' . $phpEx); - } - - $request = new phpbb\request\request(); - $phpbb_path_helper = new phpbb\path_helper( - new phpbb\symfony_request( - $request - ), - new phpbb\filesystem\filesystem(), - $request, - $phpbb_root_path, - $phpEx - ); - } - - return $phpbb_path_helper->clean_path($path); -} - -/** -* Pick a timezone -* -* @param string $default A timezone to select -* @param boolean $truncate Shall we truncate the options text -* -* @return string Returns the options for timezone selector only -* -* @deprecated 3.1.0 (To be removed: 4.0.0) -*/ -function tz_select($default = '', $truncate = false) -{ - global $template, $user; - - return phpbb_timezone_select($template, $user, $default, $truncate); -} - -/** -* Cache moderators. Called whenever permissions are changed -* via admin_permissions. Changes of usernames and group names -* must be carried through for the moderators table. -* -* @deprecated 3.1.0 (To be removed: 4.0.0) -* @return null -*/ -function cache_moderators() -{ - global $db, $cache, $auth; - return phpbb_cache_moderators($db, $cache, $auth); -} - -/** -* Removes moderators and administrators from foe lists. -* -* @deprecated 3.1.0 (To be removed: 4.0.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 -*/ -function update_foes($group_id = false, $user_id = false) -{ - global $db, $auth; - return phpbb_update_foes($db, $auth, $group_id, $user_id); -} - -/** -* Get user rank title and image -* -* @param int $user_rank the current stored users rank id -* @param int $user_posts the users number of posts -* @param string &$rank_title the rank title will be stored here after execution -* @param string &$rank_img the rank image as full img tag is stored here after execution -* @param string &$rank_img_src the rank image source is stored here after execution -* -* @deprecated 3.1.0-RC5 (To be removed: 4.0.0) -* -* Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false -*/ -function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank_img_src) -{ - global $phpbb_root_path, $phpEx; - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $rank_data = phpbb_get_user_rank(array('user_rank' => $user_rank), $user_posts); - $rank_title = $rank_data['title']; - $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: 4.0.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: 4.0.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: 4.0.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: 4.0.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: 4.0.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: 4.0.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; -} - -/** - * Casts a variable to the given type. - * - * @deprecated 3.1 (To be removed 4.0.0) - */ -function set_var(&$result, $var, $type, $multibyte = false) -{ - // no need for dependency injection here, if you have the object, call the method yourself! - $type_cast_helper = new \phpbb\request\type_cast_helper(); - $type_cast_helper->set_var($result, $var, $type, $multibyte); -} - -/** - * Delete Attachments - * - * @deprecated 3.2.0-a1 (To be removed: 4.0.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 $phpbb_container; - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $num_deleted = $attachment_manager->delete($mode, $ids, $resync); - - unset($attachment_manager); - - return $num_deleted; -} - -/** - * Delete attached file - * - * @deprecated 3.2.0-a1 (To be removed: 4.0.0) - */ -function phpbb_unlink($filename, $mode = 'file', $entry_removed = false) -{ - global $phpbb_container; - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $unlink = $attachment_manager->unlink($filename, $mode, $entry_removed); - unset($attachment_manager); - - return $unlink; -} - -/** - * Display reasons - * - * @deprecated 3.2.0-dev (To be removed: 4.0.0) - */ -function display_reasons($reason_id = 0) -{ - global $phpbb_container; - - $phpbb_container->get('phpbb.report.report_reason_list_provider')->display_reasons($reason_id); -} - -/** - * Upload Attachment - filedata is generated here - * Uses upload class - * - * @deprecated 3.2.0-a1 (To be removed: 4.0.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 array $local_filedata A filespec object created for the local file - * - * @return array File data array - */ -function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false) -{ - global $phpbb_container; - - /** @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 $file; -} - -/** -* Wrapper for php's checkdnsrr function. -* -* @param string $host Fully-Qualified Domain Name -* @param string $type Resource record type to lookup -* Supported types are: MX (default), A, AAAA, NS, TXT, CNAME -* Other types may work or may not work -* -* @return mixed true if entry found, -* false if entry not found, -* null if this function is not supported by this environment -* -* Since null can also be returned, you probably want to compare the result -* with === true or === false, -* -* @deprecated 3.3.0-b2 (To be removed: 4.0.0) -*/ -function phpbb_checkdnsrr($host, $type = 'MX') -{ - return checkdnsrr($host, $type); -} - -/* - * Wrapper for inet_ntop() - * - * Converts a packed internet address to a human readable representation - * inet_ntop() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. - * - * @param string $in_addr A 32bit IPv4, or 128bit IPv6 address. - * - * @return mixed false on failure, - * string otherwise - * - * @deprecated 3.3.0-b2 (To be removed: 4.0.0) - */ -function phpbb_inet_ntop($in_addr) -{ - return inet_ntop($in_addr); -} - -/** - * Wrapper for inet_pton() - * - * Converts a human readable IP address to its packed in_addr representation - * inet_pton() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. - * - * @param string $address A human readable IPv4 or IPv6 address. - * - * @return mixed false if address is invalid, - * in_addr representation of the given address otherwise (string) - * - * @deprecated 3.3.0-b2 (To be removed: 4.0.0) - */ -function phpbb_inet_pton($address) -{ - return inet_pton($address); -} - -/** - * Hashes an email address to a big integer - * - * @param string $email Email address - * - * @return string Unsigned Big Integer - * - * @deprecated 3.3.0-b2 (To be removed: 4.0.0) - */ -function phpbb_email_hash($email) -{ - return sprintf('%u', crc32(strtolower($email))) . strlen($email); -} diff --git a/install/update/new/includes/functions_compress.php b/install/update/new/includes/functions_compress.php deleted file mode 100644 index 56d64d3..0000000 --- a/install/update/new/includes/functions_compress.php +++ /dev/null @@ -1,830 +0,0 @@ - -* @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 for handling archives (compression/decompression) -*/ -class compress -{ - var $fp = 0; - - /** - * @var array - */ - protected $filelist = array(); - - /** - * Add file to archive - */ - function add_file($src, $src_rm_prefix = '', $src_add_prefix = '', $skip_files = '') - { - global $phpbb_root_path; - - $skip_files = explode(',', $skip_files); - - // Remove rm prefix from src path - $src_path = ($src_rm_prefix) ? preg_replace('#^(' . preg_quote($src_rm_prefix, '#') . ')#', '', $src) : $src; - // Add src prefix - $src_path = ($src_add_prefix) ? ($src_add_prefix . ((substr($src_add_prefix, -1) != '/') ? '/' : '') . $src_path) : $src_path; - // Remove initial "/" if present - $src_path = (substr($src_path, 0, 1) == '/') ? substr($src_path, 1) : $src_path; - - if (is_file($phpbb_root_path . $src)) - { - $this->data($src_path, file_get_contents("$phpbb_root_path$src"), stat("$phpbb_root_path$src"), false); - } - else if (is_dir($phpbb_root_path . $src)) - { - // Clean up path, add closing / if not present - $src_path = ($src_path && substr($src_path, -1) != '/') ? $src_path . '/' : $src_path; - - $filelist = filelist("$phpbb_root_path$src", '', '*'); - krsort($filelist); - - /** - * Commented out, as adding the folders produces corrupted archives - if ($src_path) - { - $this->data($src_path, '', true, stat("$phpbb_root_path$src")); - } - */ - - foreach ($filelist as $path => $file_ary) - { - /** - * Commented out, as adding the folders produces corrupted archives - if ($path) - { - // Same as for src_path - $path = (substr($path, 0, 1) == '/') ? substr($path, 1) : $path; - $path = ($path && substr($path, -1) != '/') ? $path . '/' : $path; - - $this->data("$src_path$path", '', true, stat("$phpbb_root_path$src$path")); - } - */ - - foreach ($file_ary as $file) - { - if (in_array($path . $file, $skip_files)) - { - continue; - } - - $this->data("$src_path$path$file", file_get_contents("$phpbb_root_path$src$path$file"), stat("$phpbb_root_path$src$path$file"), false); - } - } - } - else - { - // $src does not exist - return false; - } - - return true; - } - - /** - * Add custom file (the filepath will not be adjusted) - */ - function add_custom_file($src, $filename) - { - if (!file_exists($src)) - { - return false; - } - - $this->data($filename, file_get_contents($src), stat($src), false); - return true; - } - - /** - * Add file data - */ - function add_data($src, $name) - { - $stat = array(); - $stat[2] = 436; //384 - $stat[4] = $stat[5] = 0; - $stat[7] = strlen($src); - $stat[9] = time(); - $this->data($name, $src, $stat, false); - return true; - } - - /** - * Checks if a file by that name as already been added and, if it has, - * returns a new, unique name. - * - * @param string $name The filename - * @return string A unique filename - */ - protected function unique_filename($name) - { - if (isset($this->filelist[$name])) - { - $start = $name; - $ext = ''; - $this->filelist[$name]++; - - // Separate the extension off the end of the filename to preserve it - $pos = strrpos($name, '.'); - if ($pos !== false) - { - $start = substr($name, 0, $pos); - $ext = substr($name, $pos); - } - - return $start . '_' . $this->filelist[$name] . $ext; - } - - $this->filelist[$name] = 0; - return $name; - } - - /** - * Return available methods - * - * @return array Array of strings of available compression methods (.tar, .tar.gz, .zip, etc.) - */ - static public function methods() - { - $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; - } - - return $methods; - } -} - -/** -* 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 -* -* Modified extensively by psoTFX and DavidMJ, (c) phpBB Limited, 2003 -* -* Based on work by Eric Mueller and Denis125 -* Official ZIP file format: http://www.pkware.com/appnote.txt -*/ -class compress_zip extends compress -{ - var $datasec = array(); - var $ctrl_dir = array(); - var $eof_cdh = "\x50\x4b\x05\x06\x00\x00\x00\x00"; - - var $old_offset = 0; - var $datasec_len = 0; - - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * Constructor - */ - 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) - { - trigger_error('Unable to open file ' . $file . ' [' . $mode . 'b]'); - } - } - - /** - * Convert unix to dos time - */ - function unix_to_dos_time($time) - { - $timearray = (!$time) ? getdate() : getdate($time); - - if ($timearray['year'] < 1980) - { - $timearray['year'] = 1980; - $timearray['mon'] = $timearray['mday'] = 1; - $timearray['hours'] = $timearray['minutes'] = $timearray['seconds'] = 0; - } - - return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1); - } - - /** - * Extract archive - */ - function extract($dst) - { - // Loop the file, looking for files and folders - $dd_try = false; - rewind($this->fp); - - while (!feof($this->fp)) - { - // Check if the signature is valid... - $signature = fread($this->fp, 4); - - switch ($signature) - { - // 'Local File Header' - case "\x50\x4b\x03\x04": - // Lets get everything we need. - // We don't store the version needed to extract, the general purpose bit flag or the date and time fields - $data = unpack("@4/vc_method/@10/Vcrc/Vc_size/Vuc_size/vname_len/vextra_field", fread($this->fp, 26)); - $file_name = fread($this->fp, $data['name_len']); // filename - - if ($data['extra_field']) - { - fread($this->fp, $data['extra_field']); // extra field - } - - $target_filename = "$dst$file_name"; - - if (!$data['uc_size'] && !$data['crc'] && substr($file_name, -1, 1) == '/') - { - if (!is_dir($target_filename)) - { - $str = ''; - $folders = explode('/', $target_filename); - - // Create and folders and subfolders if they do not exist - foreach ($folders as $folder) - { - $folder = trim($folder); - if (!$folder) - { - continue; - } - - $str = (!empty($str)) ? $str . '/' . $folder : $folder; - if (!is_dir($str)) - { - if (!@mkdir($str, 0777)) - { - trigger_error("Could not create directory $folder"); - } - - try - { - $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - } - // This is a directory, we are not writing files - continue 2; - } - else - { - // Some archivers are punks, they don't include folders in their archives! - $str = ''; - $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME)); - - // Create and folders and subfolders if they do not exist - foreach ($folders as $folder) - { - $folder = trim($folder); - if (!$folder) - { - continue; - } - - $str = (!empty($str)) ? $str . '/' . $folder : $folder; - if (!is_dir($str)) - { - if (!@mkdir($str, 0777)) - { - trigger_error("Could not create directory $folder"); - } - - try - { - $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - } - - if (!$data['uc_size']) - { - $content = ''; - } - else - { - $content = fread($this->fp, $data['c_size']); - } - - $fp = fopen($target_filename, "w"); - - switch ($data['c_method']) - { - case 0: - // Not compressed - fwrite($fp, $content); - break; - - case 8: - // Deflate - fwrite($fp, gzinflate($content, $data['uc_size'])); - break; - - case 12: - // Bzip2 - fwrite($fp, bzdecompress($content)); - break; - } - - fclose($fp); - break; - - // We hit the 'Central Directory Header', we can stop because nothing else in here requires our attention - // or we hit the end of the central directory record, we can safely end the loop as we are totally finished with looking for files and folders - case "\x50\x4b\x01\x02": - // This case should simply never happen.. but it does exist.. - case "\x50\x4b\x05\x06": - break 2; - - // 'Packed to Removable Disk', ignore it and look for the next signature... - case 'PK00': - continue 2; - - // We have encountered a header that is weird. Lets look for better data... - default: - if (!$dd_try) - { - // Unexpected header. Trying to detect wrong placed 'Data Descriptor'; - $dd_try = true; - fseek($this->fp, 8, SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4) - continue 2; - } - trigger_error("Unexpected header, ending loop"); - break 2; - } - - $dd_try = false; - } - } - - /** - * Close archive - */ - function close() - { - // Write out central file directory and footer ... if it exists - if (count($this->ctrl_dir)) - { - fwrite($this->fp, $this->file()); - } - fclose($this->fp); - } - - /** - * Create the structures ... note we assume version made by is MSDOS - */ - function data($name, $data, $stat, $is_dir = false) - { - $name = str_replace('\\', '/', $name); - $name = $this->unique_filename($name); - - $hexdtime = pack('V', $this->unix_to_dos_time($stat[9])); - - if ($is_dir) - { - $unc_len = $c_len = $crc = 0; - $zdata = ''; - $var_ext = 10; - } - else - { - $unc_len = strlen($data); - $crc = crc32($data); - $zdata = gzdeflate($data); - $c_len = strlen($zdata); - $var_ext = 20; - - // Did we compress? No, then use data as is - if ($c_len >= $unc_len) - { - $zdata = $data; - $c_len = $unc_len; - $var_ext = 10; - } - } - unset($data); - - // If we didn't compress set method to store, else deflate - $c_method = ($c_len == $unc_len) ? "\x00\x00" : "\x08\x00"; - - // Are we a file or a directory? Set archive for file - $attrib = ($is_dir) ? 16 : 32; - - // File Record Header - $fr = "\x50\x4b\x03\x04"; // Local file header 4bytes - $fr .= pack('v', $var_ext); // ver needed to extract 2bytes - $fr .= "\x00\x00"; // gen purpose bit flag 2bytes - $fr .= $c_method; // compression method 2bytes - $fr .= $hexdtime; // last mod time and date 2+2bytes - $fr .= pack('V', $crc); // crc32 4bytes - $fr .= pack('V', $c_len); // compressed filesize 4bytes - $fr .= pack('V', $unc_len); // uncompressed filesize 4bytes - $fr .= pack('v', strlen($name));// length of filename 2bytes - - $fr .= pack('v', 0); // extra field length 2bytes - $fr .= $name; - $fr .= $zdata; - unset($zdata); - - $this->datasec_len += strlen($fr); - - // Add data to file ... by writing data out incrementally we save some memory - fwrite($this->fp, $fr); - unset($fr); - - // Central Directory Header - $cdrec = "\x50\x4b\x01\x02"; // header 4bytes - $cdrec .= "\x00\x00"; // version made by - $cdrec .= pack('v', $var_ext); // version needed to extract - $cdrec .= "\x00\x00"; // gen purpose bit flag - $cdrec .= $c_method; // compression method - $cdrec .= $hexdtime; // last mod time & date - $cdrec .= pack('V', $crc); // crc32 - $cdrec .= pack('V', $c_len); // compressed filesize - $cdrec .= pack('V', $unc_len); // uncompressed filesize - $cdrec .= pack('v', strlen($name)); // length of filename - $cdrec .= pack('v', 0); // extra field length - $cdrec .= pack('v', 0); // file comment length - $cdrec .= pack('v', 0); // disk number start - $cdrec .= pack('v', 0); // internal file attributes - $cdrec .= pack('V', $attrib); // external file attributes - $cdrec .= pack('V', $this->old_offset); // relative offset of local header - $cdrec .= $name; - - // Save to central directory - $this->ctrl_dir[] = $cdrec; - - $this->old_offset = $this->datasec_len; - } - - /** - * file - */ - function file() - { - $ctrldir = implode('', $this->ctrl_dir); - - return $ctrldir . $this->eof_cdh . - 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 - } - - /** - * Download archive - */ - function download($filename, $download_name = false) - { - global $phpbb_root_path; - - if ($download_name === false) - { - $download_name = $filename; - } - - $mimetype = 'application/zip'; - - header('Cache-Control: private, no-cache'); - header("Content-Type: $mimetype; name=\"$download_name.zip\""); - header("Content-disposition: attachment; filename=$download_name.zip"); - - $fp = @fopen("{$phpbb_root_path}store/$filename.zip", 'rb'); - if ($fp) - { - while ($buffer = fread($fp, 1024)) - { - echo $buffer; - } - fclose($fp); - } - } -} - -/** -* Tar/tar.gz compression routine -* Header/checksum creation derived from tarfile.pl, (c) Tom Horsley, 1994 -*/ -class compress_tar extends compress -{ - var $isgz = false; - var $isbz = false; - var $filename = ''; - var $mode = ''; - var $type = ''; - var $wrote = false; - - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * Constructor - */ - 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); - - $this->mode = &$mode; - $this->file = &$file; - $this->type = &$type; - $this->open(); - - $this->filesystem = ($phpbb_filesystem instanceof \phpbb\filesystem\filesystem_interface) ? $phpbb_filesystem : new \phpbb\filesystem\filesystem(); - } - - /** - * Extract archive - */ - function extract($dst) - { - $fzread = ($this->isbz && function_exists('bzread')) ? 'bzread' : (($this->isgz && @extension_loaded('zlib')) ? 'gzread' : 'fread'); - - // Run through the file and grab directory entries - while ($buffer = $fzread($this->fp, 512)) - { - $tmp = unpack('A6magic', substr($buffer, 257, 6)); - - if (trim($tmp['magic']) == 'ustar') - { - $tmp = unpack('A100name', $buffer); - $filename = trim($tmp['name']); - - $tmp = unpack('Atype', substr($buffer, 156, 1)); - $filetype = (int) trim($tmp['type']); - - $tmp = unpack('A12size', substr($buffer, 124, 12)); - $filesize = octdec((int) trim($tmp['size'])); - - $target_filename = "$dst$filename"; - - if ($filetype == 5) - { - if (!is_dir($target_filename)) - { - $str = ''; - $folders = explode('/', $target_filename); - - // Create and folders and subfolders if they do not exist - foreach ($folders as $folder) - { - $folder = trim($folder); - if (!$folder) - { - continue; - } - - $str = (!empty($str)) ? $str . '/' . $folder : $folder; - if (!is_dir($str)) - { - if (!@mkdir($str, 0777)) - { - trigger_error("Could not create directory $folder"); - } - - try - { - $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - } - } - else if ($filesize >= 0 && ($filetype == 0 || $filetype == "\0")) - { - // Some archivers are punks, they don't properly order the folders in their archives! - $str = ''; - $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME)); - - // Create and folders and subfolders if they do not exist - foreach ($folders as $folder) - { - $folder = trim($folder); - if (!$folder) - { - continue; - } - - $str = (!empty($str)) ? $str . '/' . $folder : $folder; - if (!is_dir($str)) - { - if (!@mkdir($str, 0777)) - { - trigger_error("Could not create directory $folder"); - } - - try - { - $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - - // Write out the files - if (!($fp = fopen($target_filename, 'wb'))) - { - trigger_error("Couldn't create file $filename"); - } - - 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); - fclose($fp); - } - } - } - } - - /** - * Close archive - */ - function close() - { - $fzclose = ($this->isbz && function_exists('bzclose')) ? 'bzclose' : (($this->isgz && @extension_loaded('zlib')) ? 'gzclose' : 'fclose'); - - if ($this->wrote) - { - $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite'); - - // The end of a tar archive ends in two records of all NULLs (1024 bytes of \0) - $fzwrite($this->fp, str_repeat("\0", 1024)); - } - - $fzclose($this->fp); - } - - /** - * Create the structures - */ - function data($name, $data, $stat, $is_dir = false) - { - $name = $this->unique_filename($name); - $this->wrote = true; - $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite'); - - $typeflag = ($is_dir) ? '5' : ''; - - // This is the header data, it contains all the info we know about the file or folder that we are about to archive - $header = ''; - $header .= pack('a100', $name); // file name - $header .= pack('a8', sprintf("%07o", $stat[2])); // file mode - $header .= pack('a8', sprintf("%07o", $stat[4])); // owner id - $header .= pack('a8', sprintf("%07o", $stat[5])); // group id - $header .= pack('a12', sprintf("%011o", $stat[7])); // file size - $header .= pack('a12', sprintf("%011o", $stat[9])); // last mod time - - // Checksum - $checksum = 0; - for ($i = 0; $i < 148; $i++) - { - $checksum += ord($header[$i]); - } - - // We precompute the rest of the hash, this saves us time in the loop and allows us to insert our hash without resorting to string functions - $checksum += 2415 + (($is_dir) ? 53 : 0); - - $header .= pack('a8', sprintf("%07o", $checksum)); // checksum - $header .= pack('a1', $typeflag); // link indicator - $header .= pack('a100', ''); // name of linked file - $header .= pack('a6', 'ustar'); // ustar indicator - $header .= pack('a2', '00'); // ustar version - $header .= pack('a32', 'Unknown'); // owner name - $header .= pack('a32', 'Unknown'); // group name - $header .= pack('a8', ''); // device major number - $header .= pack('a8', ''); // device minor number - $header .= pack('a155', ''); // filename prefix - $header .= pack('a12', ''); // end - - // This writes the entire file in one shot. Header, followed by data and then null padded to a multiple of 512 - $fzwrite($this->fp, $header . (($stat[7] !== 0 && !$is_dir) ? $data . str_repeat("\0", (($stat[7] + 511) &~ 511) - $stat[7]) : '')); - unset($data); - } - - /** - * Open archive - */ - function open() - { - $fzopen = ($this->isbz && function_exists('bzopen')) ? 'bzopen' : (($this->isgz && @extension_loaded('zlib')) ? 'gzopen' : 'fopen'); - $this->fp = @$fzopen($this->file, $this->mode . (($fzopen == 'bzopen') ? '' : 'b') . (($fzopen == 'gzopen') ? '9' : '')); - - if (!$this->fp) - { - trigger_error('Unable to open file ' . $this->file . ' [' . $fzopen . ' - ' . $this->mode . 'b]'); - } - } - - /** - * Download archive - */ - function download($filename, $download_name = false) - { - global $phpbb_root_path; - - if ($download_name === false) - { - $download_name = $filename; - } - - switch ($this->type) - { - case '.tar': - $mimetype = 'application/x-tar'; - break; - - case '.tar.gz': - $mimetype = 'application/x-gzip'; - break; - - case '.tar.bz2': - $mimetype = 'application/x-bzip2'; - break; - - default: - $mimetype = 'application/octet-stream'; - break; - } - - header('Cache-Control: private, no-cache'); - header("Content-Type: $mimetype; name=\"$download_name$this->type\""); - header("Content-disposition: attachment; filename=$download_name$this->type"); - - $fp = @fopen("{$phpbb_root_path}store/$filename$this->type", 'rb'); - if ($fp) - { - while ($buffer = fread($fp, 1024)) - { - echo $buffer; - } - fclose($fp); - } - } -} diff --git a/install/update/new/includes/functions_content.php b/install/update/new/includes/functions_content.php deleted file mode 100644 index fd014c7..0000000 --- a/install/update/new/includes/functions_content.php +++ /dev/null @@ -1,1788 +0,0 @@ - -* @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; -} - -/** -* gen_sort_selects() -* make_jumpbox() -* bump_topic_allowed() -* get_context() -* phpbb_clean_search_string() -* decode_message() -* strip_bbcode() -* generate_text_for_display() -* generate_text_for_storage() -* generate_text_for_edit() -* make_clickable_callback() -* make_clickable() -* censor_text() -* bbcode_nl2br() -* smiley_text() -* parse_attachments() -* extension_allowed() -* truncate_string() -* get_username_string() -* class bitfield -*/ - -/** -* Generate sort selection fields -*/ -function 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, $def_st = false, $def_sk = false, $def_sd = false) -{ - global $user, $phpbb_dispatcher; - - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - $sorts = array( - 'st' => array( - 'key' => 'sort_days', - 'default' => $def_st, - 'options' => $limit_days, - 'output' => &$s_limit_days, - ), - - 'sk' => array( - 'key' => 'sort_key', - 'default' => $def_sk, - 'options' => $sort_by_text, - 'output' => &$s_sort_key, - ), - - 'sd' => array( - 'key' => 'sort_dir', - 'default' => $def_sd, - 'options' => $sort_dir_text, - 'output' => &$s_sort_dir, - ), - ); - $u_sort_param = ''; - - foreach ($sorts as $name => $sort_ary) - { - $key = $sort_ary['key']; - $selected = ${$sort_ary['key']}; - - // Check if the key is selectable. If not, we reset to the default or first key found. - // This ensures the values are always valid. We also set $sort_dir/sort_key/etc. to the - // correct value, else the protection is void. ;) - if (!isset($sort_ary['options'][$selected])) - { - if ($sort_ary['default'] !== false) - { - $selected = ${$key} = $sort_ary['default']; - } - else - { - @reset($sort_ary['options']); - $selected = ${$key} = key($sort_ary['options']); - } - } - - $sort_ary['output'] = ''; - - $u_sort_param .= ($selected !== $sort_ary['default']) ? ((strlen($u_sort_param)) ? '&' : '') . "{$name}={$selected}" : ''; - } - - /** - * Run code before generated sort selects are returned - * - * @event core.gen_sort_selects_after - * @var int limit_days Days limit - * @var array sort_by_text Sort by text options - * @var int sort_days Sort by days flag - * @var string sort_key Sort key - * @var string sort_dir Sort dir - * @var string s_limit_days String of days limit - * @var string s_sort_key String of sort key - * @var string s_sort_dir String of sort dir - * @var string u_sort_param Sort URL params - * @var bool def_st Default sort days - * @var bool def_sk Default sort key - * @var bool def_sd Default sort dir - * @var array sorts Sorts - * @since 3.1.9-RC1 - */ - $vars = array( - 'limit_days', - 'sort_by_text', - 'sort_days', - 'sort_key', - 'sort_dir', - 's_limit_days', - 's_sort_key', - 's_sort_dir', - 'u_sort_param', - 'def_st', - 'def_sk', - 'def_sd', - 'sorts', - ); - extract($phpbb_dispatcher->trigger_event('core.gen_sort_selects_after', compact($vars))); - - return; -} - -/** -* Generate Jumpbox -*/ -function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list = false, $force_display = false) -{ - global $config, $auth, $template, $user, $db, $phpbb_path_helper, $phpbb_dispatcher; - - // We only return if the jumpbox is not forced to be displayed (in case it is needed for functionality) - if (!$config['load_jumpbox'] && $force_display === false) - { - return; - } - - $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql, 600); - - $rowset = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[(int) $row['forum_id']] = $row; - } - $db->sql_freeresult($result); - - $right = $padding = 0; - $padding_store = array('0' => 0); - $display_jumpbox = false; - $iteration = 0; - - /** - * Modify the jumpbox forum list data - * - * @event core.make_jumpbox_modify_forum_list - * @var array rowset Array with the forums list data - * @since 3.1.10-RC1 - */ - $vars = array('rowset'); - extract($phpbb_dispatcher->trigger_event('core.make_jumpbox_modify_forum_list', compact($vars))); - - // Sometimes it could happen that forums will be displayed here not be displayed within the index page - // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions. - // If this happens, the padding could be "broken" - - foreach ($rowset as $row) - { - if ($row['left_id'] < $right) - { - $padding++; - $padding_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it. - // @todo digging deep to find out "how" this can happen. - $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding; - } - - $right = $row['right_id']; - - if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) - { - // Non-postable forum with no subforums, don't display - continue; - } - - if (!$auth->acl_get('f_list', $row['forum_id'])) - { - // if the user does not have permissions to list this forum skip - continue; - } - - if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id'])) - { - continue; - } - - $tpl_ary = array(); - if (!$display_jumpbox) - { - $tpl_ary[] = array( - 'FORUM_ID' => ($select_all) ? 0 : -1, - 'FORUM_NAME' => ($select_all) ? $user->lang['ALL_FORUMS'] : $user->lang['SELECT_FORUM'], - 'S_FORUM_COUNT' => $iteration, - 'LINK' => $phpbb_path_helper->append_url_params($action, array('f' => $forum_id)), - ); - - $iteration++; - $display_jumpbox = true; - } - - $tpl_ary[] = array( - 'FORUM_ID' => $row['forum_id'], - 'FORUM_NAME' => $row['forum_name'], - 'SELECTED' => ($row['forum_id'] == $forum_id) ? ' selected="selected"' : '', - 'S_FORUM_COUNT' => $iteration, - 'S_IS_CAT' => ($row['forum_type'] == FORUM_CAT) ? true : false, - 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK) ? true : false, - 'S_IS_POST' => ($row['forum_type'] == FORUM_POST) ? true : false, - 'LINK' => $phpbb_path_helper->append_url_params($action, array('f' => $row['forum_id'])), - ); - - /** - * Modify the jumpbox before it is assigned to the template - * - * @event core.make_jumpbox_modify_tpl_ary - * @var array row The data of the forum - * @var array tpl_ary Template data of the forum - * @since 3.1.10-RC1 - */ - $vars = array( - 'row', - 'tpl_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.make_jumpbox_modify_tpl_ary', compact($vars))); - - $template->assign_block_vars_array('jumpbox_forums', $tpl_ary); - - unset($tpl_ary); - - for ($i = 0; $i < $padding; $i++) - { - $template->assign_block_vars('jumpbox_forums.level', array()); - } - $iteration++; - } - unset($padding_store, $rowset); - - $url_parts = $phpbb_path_helper->get_url_parts($action); - - $template->assign_vars(array( - 'S_DISPLAY_JUMPBOX' => $display_jumpbox, - 'S_JUMPBOX_ACTION' => $action, - 'HIDDEN_FIELDS_FOR_JUMPBOX' => build_hidden_fields($url_parts['params']), - )); - - return; -} - -/** -* Bump Topic Check - used by posting and viewtopic -*/ -function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_poster, $last_topic_poster) -{ - global $config, $auth, $user; - - // Check permission and make sure the last post was not already bumped - if (!$auth->acl_get('f_bump', $forum_id) || $topic_bumped) - { - return false; - } - - // Check bump time range, is the user really allowed to bump the topic at this time? - $bump_time = ($config['bump_type'] == 'm') ? $config['bump_interval'] * 60 : (($config['bump_type'] == 'h') ? $config['bump_interval'] * 3600 : $config['bump_interval'] * 86400); - - // Check bump time - if ($last_post_time + $bump_time > time()) - { - return false; - } - - // Check bumper, only topic poster and last poster are allowed to bump - if ($topic_poster != $user->data['user_id'] && $last_topic_poster != $user->data['user_id']) - { - return false; - } - - // A bump time of 0 will completely disable the bump feature... not intended but might be useful. - return $bump_time; -} - -/** -* Generates a text with approx. the specified length which contains the specified words and their context -* -* @param string $text The full text from which context shall be extracted -* @param string $words An array of words which should be contained in the result, has to be a valid part of a PCRE pattern (escape with preg_quote!) -* @param int $length The desired length of the resulting text, however the result might be shorter or longer than this value -* -* @return string Context of the specified words separated by "..." -*/ -function get_context($text, $words, $length = 400) -{ - // first replace all whitespaces with single spaces - $text = preg_replace('/ +/', ' ', strtr($text, "\t\n\r\x0C ", ' ')); - - // we need to turn the entities back into their original form, to not cut the message in between them - $entities = array('<', '>', '[', ']', '.', ':', ':'); - $characters = array('<', '>', '[', ']', '.', ':', ':'); - $text = str_replace($entities, $characters, $text); - - $word_indizes = array(); - if (count($words)) - { - $match = ''; - // find the starting indizes of all words - foreach ($words as $word) - { - if ($word) - { - if (preg_match('#(?:[^\w]|^)(' . $word . ')(?:[^\w]|$)#i', $text, $match)) - { - if (empty($match[1])) - { - continue; - } - - $pos = utf8_strpos($text, $match[1]); - if ($pos !== false) - { - $word_indizes[] = $pos; - } - } - } - } - unset($match); - - if (count($word_indizes)) - { - $word_indizes = array_unique($word_indizes); - sort($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 = ''; - $word = $j = 0; - $final_text_index = -1; - - // cycle through every character in the original text - for ($i = $word_indizes[$word], $n = utf8_strlen($text); $i < $n; $i++) - { - // if the current position is the start of one of the words then append $sequence_length characters to the final text - if (isset($word_indizes[$word]) && ($i == $word_indizes[$word])) - { - if ($final_text_index < $i - $sequence_length - 1) - { - $final_text .= '... ' . preg_replace('#^([^ ]*)#', '', utf8_substr($text, $i - $sequence_length, $sequence_length)); - } - else - { - // if the final text is already nearer to the current word than $sequence_length we only append the text - // from its current index on and distribute the unused length to all other sequenes - $sequence_length += (int) (($final_text_index - $i + $sequence_length + 1) / (2 * $wordnum)); - $final_text .= utf8_substr($text, $final_text_index + 1, $i - $final_text_index - 1); - } - $final_text_index = $i - 1; - - // add the following characters to the final text (see below) - $word++; - $j = 1; - } - - if ($j > 0) - { - // add the character to the final text and increment the sequence counter - $final_text .= utf8_substr($text, $i, 1); - $final_text_index++; - $j++; - - // if this is a whitespace then check whether we are done with this sequence - if (utf8_substr($text, $i, 1) == ' ') - { - // only check whether we have to exit the context generation completely if we haven't already reached the end anyway - if ($i + 4 < $n) - { - if (($j > $sequence_length && $word >= $wordnum) || utf8_strlen($final_text) > $length) - { - $final_text .= ' ...'; - break; - } - } - else - { - // make sure the text really reaches the end - $j -= 4; - } - - // stop context generation and wait for the next word - if ($j > $sequence_length) - { - $j = 0; - } - } - } - } - return str_replace($characters, $entities, $final_text); - } - } - - if (!count($words) || !count($word_indizes)) - { - return str_replace($characters, $entities, ((utf8_strlen($text) >= $length + 3) ? utf8_substr($text, 0, $length) . '...' : $text)); - } -} - -/** -* Cleans a search string by removing single wildcards from it and replacing multiple spaces with a single one. -* -* @param string $search_string The full search string which should be cleaned. -* -* @return string The cleaned search string without any wildcards and multiple spaces. -*/ -function phpbb_clean_search_string($search_string) -{ - // This regular expressions matches every single wildcard. - // That means one after a whitespace or the beginning of the string or one before a whitespace or the end of the string. - $search_string = preg_replace('#(?<=^|\s)\*+(?=\s|$)#', '', $search_string); - $search_string = trim($search_string); - $search_string = preg_replace(array('#\s+#u', '#\*+#u'), array(' ', '*'), $search_string); - return $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 $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 - */ - $message_text = $message; - $vars = array('message_text', 'bbcode_uid'); - extract($phpbb_dispatcher->trigger_event('core.decode_message_before', compact($vars))); - $message = $message_text; - - if (preg_match('#^<[rt][ >]#', $message)) - { - $message = htmlspecialchars($phpbb_container->get('text_formatter.utils')->unparse($message), ENT_COMPAT); - } - else - { - if ($bbcode_uid) - { - $match = array('
', "[/*:m:$bbcode_uid]", ":u:$bbcode_uid", ":o:$bbcode_uid", ":$bbcode_uid"); - $replace = array("\n", '', '', '', ''); - } - else - { - $match = array('
'); - $replace = array("\n"); - } - - $message = str_replace($match, $replace, $message); - - $match = get_preg_expression('bbcode_htm'); - $replace = array('\1', '\1', '\2', '\2', '\1', '', ''); - - $message = preg_replace($match, $replace, $message); - } - - /** - * Use this event to modify the message after it is decoded - * - * @event core.decode_message_after - * @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_after', compact($vars))); - $message = $message_text; -} - -/** -* Strips all bbcode from a text in place -*/ -function strip_bbcode(&$text, $uid = '') -{ - global $phpbb_container; - - if (preg_match('#^<[rt][ >]#', $text)) - { - $text = $phpbb_container->get('text_formatter.utils')->clean_formatting($text); - } - else - { - if (!$uid) - { - $uid = '[0-9a-z]{5,}'; - } - - $text = preg_replace("#\[\/?[a-z0-9\*\+\-]+(?:=(?:".*"|[^\]]*))?(?::[a-z])?(\:$uid)\]#", ' ', $text); - - $match = get_preg_expression('bbcode_htm'); - $replace = array('\1', '\1', '\2', '\1', '', ''); - - $text = preg_replace($match, $replace, $text); - } -} - -/** -* For display of custom parsed text on user-facing pages -* Expects $text to be the value directly from the database (stored value) -*/ -function generate_text_for_display($text, $uid, $bitfield, $flags, $censor_text = true) -{ - static $bbcode; - global $auth, $config, $user; - global $phpbb_dispatcher, $phpbb_container; - - if ($text === '') - { - return ''; - } - - /** - * Use this event to modify the text before it is parsed - * - * @event core.modify_text_for_display_before - * @var string text The text to parse - * @var string uid The BBCode UID - * @var string bitfield The BBCode Bitfield - * @var int flags The BBCode Flags - * @var bool censor_text Whether or not to apply word censors - * @since 3.1.0-a1 - */ - $vars = array('text', 'uid', 'bitfield', 'flags', 'censor_text'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_display_before', compact($vars))); - - if (preg_match('#^<[rt][ >]#', $text)) - { - $renderer = $phpbb_container->get('text_formatter.renderer'); - - // 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')) - { - $censor_text = false; - } - - if ($old_censor !== $censor_text) - { - $renderer->set_viewcensors($censor_text); - } - - $text = $renderer->render($text); - - // Restore the previous value - if ($old_censor !== $censor_text) - { - $renderer->set_viewcensors($old_censor); - } - } - 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); - } - - $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 - * - * @event core.modify_text_for_display_after - * @var string text The text to parse - * @var string uid The BBCode UID - * @var string bitfield The BBCode Bitfield - * @var int flags The BBCode Flags - * @since 3.1.0-a1 - */ - $vars = array('text', 'uid', 'bitfield', 'flags'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_display_after', compact($vars))); - - return $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->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 -* @param string $bitfield The BBCode bitfield for this parse -* @param int $flags The allow_bbcode, allow_urls and allow_smilies compiled into a single integer. -* @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, $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; - - /** - * Use this event to modify the text before it is prepared for storage - * - * @event core.modify_text_for_storage_before - * @var string text The text to parse - * @var string uid The BBCode UID - * @var string bitfield The BBCode Bitfield - * @var int flags The BBCode Flags - * @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', - 'uid', - 'bitfield', - 'flags', - '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 (!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, $allow_img_bbcode, $allow_flash_bbcode, $allow_quote_bbcode, $allow_url_bbcode, true, $mode); - - $text = $message_parser->message; - $uid = $message_parser->bbcode_uid; - - // If the bbcode_bitfield is empty, there is no need for the uid to be stored. - if (!$message_parser->bbcode_bitfield) - { - $uid = ''; - } - - $bitfield = $message_parser->bbcode_bitfield; - - /** - * Use this event to modify the text after it is prepared for storage - * - * @event core.modify_text_for_storage_after - * @var string text The text to parse - * @var string uid The BBCode UID - * @var string bitfield The BBCode Bitfield - * @var int flags The BBCode Flags - * @var string message_parser The message_parser object - * @since 3.1.0-a1 - * @changed 3.1.11-RC1 Added message_parser to vars - */ - $vars = array('text', 'uid', 'bitfield', 'flags', 'message_parser'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_storage_after', compact($vars))); - - return $message_parser->warn_msg; -} - -/** -* For decoding custom parsed text for edits as well as extracting the flags -* Expects $text to be the value directly from the database (pre-parsed content) -*/ -function generate_text_for_edit($text, $uid, $flags) -{ - global $phpbb_dispatcher; - - /** - * Use this event to modify the text before it is decoded for editing - * - * @event core.modify_text_for_edit_before - * @var string text The text to parse - * @var string uid The BBCode UID - * @var int flags The BBCode Flags - * @since 3.1.0-a1 - */ - $vars = array('text', 'uid', 'flags'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_edit_before', compact($vars))); - - decode_message($text, $uid); - - /** - * Use this event to modify the text after it is decoded for editing - * - * @event core.modify_text_for_edit_after - * @var string text The text to parse - * @var int flags The BBCode Flags - * @since 3.1.0-a1 - */ - $vars = array('text', 'flags'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_edit_after', compact($vars))); - - return array( - 'allow_bbcode' => ($flags & OPTION_FLAG_BBCODE) ? 1 : 0, - 'allow_smilies' => ($flags & OPTION_FLAG_SMILIES) ? 1 : 0, - 'allow_urls' => ($flags & OPTION_FLAG_LINKS) ? 1 : 0, - 'text' => $text - ); -} - -/** -* A subroutine of make_clickable used with preg_replace -* It places correct HTML around an url, shortens the displayed text -* and makes sure no entities are inside URLs -*/ -function make_clickable_callback($type, $whitespace, $url, $relative_url, $class) -{ - $orig_url = $url; - $orig_relative = $relative_url; - $append = ''; - $url = htmlspecialchars_decode($url); - $relative_url = htmlspecialchars_decode($relative_url); - - // make sure no HTML entities were matched - $chars = array('<', '>', '"'); - $split = false; - - foreach ($chars as $char) - { - $next_split = strpos($url, $char); - if ($next_split !== false) - { - $split = ($split !== false) ? min($split, $next_split) : $next_split; - } - } - - if ($split !== false) - { - // an HTML entity was found, so the URL has to end before it - $append = substr($url, $split) . $relative_url; - $url = substr($url, 0, $split); - $relative_url = ''; - } - else if ($relative_url) - { - // same for $relative_url - $split = false; - foreach ($chars as $char) - { - $next_split = strpos($relative_url, $char); - if ($next_split !== false) - { - $split = ($split !== false) ? min($split, $next_split) : $next_split; - } - } - - if ($split !== false) - { - $append = substr($relative_url, $split); - $relative_url = substr($relative_url, 0, $split); - } - } - - // if the last character of the url is a punctuation mark, exclude it from the url - $last_char = ($relative_url) ? $relative_url[strlen($relative_url) - 1] : $url[strlen($url) - 1]; - - switch ($last_char) - { - case '.': - case '?': - case '!': - case ':': - case ',': - $append = $last_char; - if ($relative_url) - { - $relative_url = substr($relative_url, 0, -1); - } - else - { - $url = substr($url, 0, -1); - } - break; - - // set last_char to empty here, so the variable can be used later to - // check whether a character was removed - default: - $last_char = ''; - break; - } - - $short_url = (utf8_strlen($url) > 55) ? utf8_substr($url, 0, 39) . ' ... ' . utf8_substr($url, -10) : $url; - - switch ($type) - { - case MAGIC_URL_LOCAL: - $tag = 'l'; - $relative_url = preg_replace('/[&?]sid=[0-9a-f]{32}$/', '', preg_replace('/([&?])sid=[0-9a-f]{32}&/', '$1', $relative_url)); - $url = $url . '/' . $relative_url; - $text = $relative_url; - - // this url goes to http://domain.tld/path/to/board/ which - // would result in an empty link if treated as local so - // don't touch it and let MAGIC_URL_FULL take care of it. - if (!$relative_url) - { - return $whitespace . $orig_url . '/' . $orig_relative; // slash is taken away by relative url pattern - } - break; - - case MAGIC_URL_FULL: - $tag = 'm'; - $text = $short_url; - break; - - case MAGIC_URL_WWW: - $tag = 'w'; - $url = 'http://' . $url; - $text = $short_url; - break; - - case MAGIC_URL_EMAIL: - $tag = 'e'; - $text = $short_url; - $url = 'mailto:' . $url; - break; - } - - $url = htmlspecialchars($url); - $text = htmlspecialchars($text); - $append = htmlspecialchars($append); - - $html = "$whitespace$text$append"; - - return $html; -} - -/** -* make_clickable function -* -* Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx. -* Cuts down displayed size of link if over 50 chars, turns absolute links -* into relative versions when the server/script path matches the link -*/ -function make_clickable($text, $server_url = false, $class = 'postlink') -{ - if ($server_url === false) - { - $server_url = generate_board_url(); - } - - static $static_class; - static $magic_url_match_args; - - if (!isset($magic_url_match_args[$server_url]) || $static_class != $class) - { - $static_class = $class; - $class = ($static_class) ? ' class="' . $static_class . '"' : ''; - $local_class = ($static_class) ? ' class="' . $static_class . '-local"' : ''; - - if (!is_array($magic_url_match_args)) - { - $magic_url_match_args = array(); - } - - // relative urls for this board - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>.])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#iu', - MAGIC_URL_LOCAL, - $local_class, - ); - - // matches a xxxx://aaaaa.bbb.cccc. ... - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>.])(' . get_preg_expression('url_inline') . ')#iu', - MAGIC_URL_FULL, - $class, - ); - - // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>])(' . get_preg_expression('www_url_inline') . ')#iu', - MAGIC_URL_WWW, - $class, - ); - - // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode. - $magic_url_match_args[$server_url][] = array( - '/(^|[\n\t (>])(' . get_preg_expression('email') . ')/iu', - MAGIC_URL_EMAIL, - '', - ); - } - - foreach ($magic_url_match_args[$server_url] as $magic_args) - { - if (preg_match($magic_args[0], $text, $matches)) - { - $text = preg_replace_callback($magic_args[0], function($matches) use ($magic_args) - { - $relative_url = isset($matches[3]) ? $matches[3] : ''; - return make_clickable_callback($magic_args[1], $matches[1], $matches[2], $relative_url, $magic_args[2]); - }, $text); - } - } - - return $text; -} - -/** -* Censoring -*/ -function censor_text($text) -{ - static $censors; - - // Nothing to do? - if ($text === '') - { - return ''; - } - - // We moved the word censor checks in here because we call this function quite often - and then only need to do the check once - if (!isset($censors) || !is_array($censors)) - { - global $config, $user, $auth, $cache; - - // We 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')) - { - $censors = array(); - } - else - { - $censors = $cache->obtain_word_list(); - } - } - - if (count($censors)) - { - return preg_replace($censors['match'], $censors['replace'], $text); - } - - return $text; -} - -/** -* custom version of nl2br which takes custom BBCodes into account -*/ -function bbcode_nl2br($text) -{ - // custom BBCodes might contain carriage returns so they - // are not converted into
so now revert that - $text = str_replace(array("\n", "\r"), array('
', "\n"), $text); - return $text; -} - -/** -* Smiley processing -*/ -function smiley_text($text, $force_option = false) -{ - global $config, $user, $phpbb_path_helper, $phpbb_dispatcher; - - if ($force_option || !$config['allow_smilies'] || !$user->optionget('viewsmilies')) - { - return preg_replace('##', ''; - } - } - - $filesize = get_formatted_filesize($attachment['filesize'], false); - - $comment = bbcode_nl2br(censor_text($attachment['attach_comment'])); - - $block_array += array( - 'UPLOAD_ICON' => $upload_icon, - 'FILESIZE' => $filesize['value'], - 'SIZE_LANG' => $filesize['unit'], - 'DOWNLOAD_NAME' => utf8_basename($attachment['real_filename']), - 'COMMENT' => $comment, - ); - - $denied = false; - - if (!extension_allowed($forum_id, $attachment['extension'], $extensions)) - { - $denied = true; - - $block_array += array( - 'S_DENIED' => true, - 'DENIED_MESSAGE' => sprintf($user->lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachment['extension']) - ); - } - - if (!$denied) - { - $display_cat = $extensions[$attachment['extension']]['display_cat']; - - if ($display_cat == ATTACHMENT_CATEGORY_IMAGE) - { - if ($attachment['thumbnail']) - { - $display_cat = ATTACHMENT_CATEGORY_THUMB; - } - else - { - if ($config['img_display_inlined']) - { - if ($config['img_link_width'] || $config['img_link_height']) - { - $dimension = @getimagesize($filename); - - // If the dimensions could not be determined or the image being 0x0 we display it as a link for safety purposes - if ($dimension === false || empty($dimension[0]) || empty($dimension[1])) - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - else - { - $display_cat = ($dimension[0] <= $config['img_link_width'] && $dimension[1] <= $config['img_link_height']) ? ATTACHMENT_CATEGORY_IMAGE : ATTACHMENT_CATEGORY_NONE; - } - } - } - else - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - } - } - - // Make some descisions based on user options being set. - if (($display_cat == ATTACHMENT_CATEGORY_IMAGE || $display_cat == ATTACHMENT_CATEGORY_THUMB) && !$user->optionget('viewimg')) - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - - $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id']); - $l_downloaded_viewed = 'VIEWED_COUNTS'; - - switch ($display_cat) - { - // Images - case ATTACHMENT_CATEGORY_IMAGE: - $inline_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id']); - $download_link .= '&mode=view'; - - $block_array += array( - 'S_IMAGE' => true, - 'U_INLINE_LINK' => $inline_link, - ); - - $update_count_ary[] = $attachment['attach_id']; - break; - - // Images, but display Thumbnail - case ATTACHMENT_CATEGORY_THUMB: - $thumbnail_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id'] . '&t=1'); - $download_link .= '&mode=view'; - - $block_array += array( - 'S_THUMBNAIL' => true, - 'THUMB_IMAGE' => $thumbnail_link, - ); - - $update_count_ary[] = $attachment['attach_id']; - break; - - default: - $l_downloaded_viewed = 'DOWNLOAD_COUNTS'; - - $block_array += array( - 'S_FILE' => true, - ); - break; - } - - if (!isset($attachment['download_count'])) - { - $attachment['download_count'] = 0; - } - - $block_array += array( - 'U_DOWNLOAD_LINK' => $download_link, - 'L_DOWNLOAD_COUNT' => $user->lang($l_downloaded_viewed, (int) $attachment['download_count']), - ); - } - - $update_count = $update_count_ary; - /** - * Use this event to modify the attachment template data. - * - * This event is triggered once per attachment. - * - * @event core.parse_attachments_modify_template_data - * @var array attachment Array with attachment data - * @var array block_array Template data of the attachment - * @var int display_cat Attachment category data - * @var string download_link Attachment download link - * @var array extensions Array with attachment extensions data - * @var mixed forum_id The forum id the attachments are displayed in (false if in private message) - * @var bool preview Flag indicating if we are in post preview mode - * @var array update_count Array with attachment ids to update download count - * @since 3.1.0-RC5 - */ - $vars = array( - 'attachment', - 'block_array', - 'display_cat', - 'download_link', - 'extensions', - 'forum_id', - 'preview', - '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); - - $compiled_attachments[] = $template->assign_display('attachment_tpl'); - } - - $attachments = $compiled_attachments; - unset($compiled_attachments); - - $unset_tpl = array(); - - preg_match_all('#(.*?)#', $message, $matches, PREG_PATTERN_ORDER); - - $replace = array(); - foreach ($matches[0] as $num => $capture) - { - $index = $matches[1][$num]; - - $replace['from'][] = $matches[0][$num]; - $replace['to'][] = (isset($attachments[$index])) ? $attachments[$index] : sprintf($user->lang['MISSING_INLINE_ATTACHMENT'], $matches[2][array_search($index, $matches[1])]); - - $unset_tpl[] = $index; - } - - if (isset($replace['from'])) - { - $message = str_replace($replace['from'], $replace['to'], $message); - } - - $unset_tpl = array_unique($unset_tpl); - - // Sort correctly - if ($config['display_order']) - { - // Ascending sort - krsort($attachments); - } - else - { - // Descending sort - ksort($attachments); - } - - // Needed to let not display the inlined attachments at the end of the post again - foreach ($unset_tpl as $index) - { - unset($attachments[$index]); - } -} - -/** -* Check if extension is allowed to be posted. -* -* @param mixed $forum_id The forum id to check or false if private message -* @param string $extension The extension to check, for example zip. -* @param array &$extensions The extension array holding the information from the cache (will be obtained if empty) -* -* @return bool False if the extension is not allowed to be posted, else true. -*/ -function extension_allowed($forum_id, $extension, &$extensions) -{ - if (empty($extensions)) - { - global $cache; - $extensions = $cache->obtain_attach_extensions($forum_id); - } - - return (!isset($extensions['_allowed_'][$extension])) ? false : true; -} - -/** -* Truncates string while retaining special characters if going over the max length -* The default max length is 60 at the moment -* The maximum storage length is there to fit the string within the given length. The string may be further truncated due to html entities. -* For example: string given is 'a "quote"' (length: 9), would be a stored as 'a "quote"' (length: 19) -* -* @param string $string The text to truncate to the given length. String is specialchared. -* @param int $max_length Maximum length of string (multibyte character count as 1 char / Html entity count as 1 char) -* @param int $max_store_length Maximum character length of string (multibyte character count as 1 char / Html entity count as entity chars). -* @param bool $allow_reply Allow Re: in front of string -* NOTE: This parameter can cause undesired behavior (returning strings longer than $max_store_length) and is deprecated. -* @param string $append String to be appended -*/ -function truncate_string($string, $max_length = 60, $max_store_length = 255, $allow_reply = false, $append = '') -{ - $strip_reply = false; - $stripped = false; - if ($allow_reply && strpos($string, 'Re: ') === 0) - { - $strip_reply = true; - $string = substr($string, 4); - } - - $_chars = utf8_str_split(htmlspecialchars_decode($string)); - $chars = array_map('utf8_htmlspecialchars', $_chars); - - // Now check the 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))); - $stripped = true; - } - - // Due to specialchars, we may not be able to store the string... - if (utf8_strlen($string) > $max_store_length) - { - // let's split again, we do not want half-baked strings where entities are split - $_chars = utf8_str_split(htmlspecialchars_decode($string)); - $chars = array_map('utf8_htmlspecialchars', $_chars); - - do - { - array_pop($chars); - $string = implode('', $chars); - } - while (!empty($chars) && utf8_strlen($string) > $max_store_length); - } - - if ($strip_reply) - { - $string = 'Re: ' . $string; - } - - if ($append != '' && $stripped) - { - $string = $string . $append; - } - - return $string; -} - -/** -* 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 -* @param string $username_colour The users colour -* @param string $guest_username optional parameter to specify the guest username. It will be used in favor of the GUEST language variable then. -* @param string $custom_profile_url optional parameter to specify a profile url. The user id get appended to this url as &u={user_id} -* -* @return string A string consisting of what is wanted based on $mode. -*/ -function get_username_string($mode, $user_id, $username, $username_colour = '', $guest_username = false, $custom_profile_url = false) -{ - static $_profile_cache; - global $phpbb_dispatcher; - - // We cache some common variables we need within this function - if (empty($_profile_cache)) - { - 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&u={USER_ID}'); - $_profile_cache['tpl_noprofile'] = '{USERNAME}'; - $_profile_cache['tpl_noprofile_colour'] = '{USERNAME}'; - $_profile_cache['tpl_profile'] = '{USERNAME}'; - $_profile_cache['tpl_profile_colour'] = '{USERNAME}'; - } - - global $user, $auth; - - // This switch makes sure we only run code required for the mode - switch ($mode) - { - case 'full': - case 'no_profile': - case 'colour': - - // Build correct username colour - $username_colour = ($username_colour) ? '#' . $username_colour : ''; - - // Return colour - if ($mode == 'colour') - { - $username_string = $username_colour; - break; - } - - // no break; - - case 'username': - - // Build correct username - if ($guest_username === false) - { - $username = ($username) ? $username : $user->lang['GUEST']; - } - else - { - $username = ($user_id && $user_id != ANONYMOUS) ? $username : ((!empty($guest_username)) ? $guest_username : $user->lang['GUEST']); - } - - // Return username - if ($mode == 'username') - { - $username_string = $username; - 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 ($user_id && $user_id != ANONYMOUS && ($user->data['user_id'] == ANONYMOUS || $auth->acl_get('u_viewprofile'))) - { - $profile_url = ($custom_profile_url !== false) ? $custom_profile_url . '&u=' . (int) $user_id : str_replace(array('={USER_ID}', '=%7BUSER_ID%7D'), '=' . (int) $user_id, $_profile_cache['base_url']); - } - else - { - $profile_url = ''; - } - - // Return profile - if ($mode == 'profile') - { - $username_string = $profile_url; - break; - } - - // no break; - } - - if (!isset($username_string)) - { - if (($mode == 'full' && !$profile_url) || $mode == 'no_profile') - { - $username_string = str_replace(array('{USERNAME_COLOUR}', '{USERNAME}'), array($username_colour, $username), (!$username_colour) ? $_profile_cache['tpl_noprofile'] : $_profile_cache['tpl_noprofile_colour']); - } - else - { - $username_string = str_replace(array('{PROFILE_URL}', '{USERNAME_COLOUR}', '{USERNAME}'), array($profile_url, $username_colour, $username), (!$username_colour) ? $_profile_cache['tpl_profile'] : $_profile_cache['tpl_profile_colour']); - } - } - - /** - * Use this event to change the output of get_username_string() - * - * @event core.modify_username_string - * @var string mode profile|username|colour|full|no_profile - * @var int user_id String or array of additional url - * parameters - * @var string username The user's username - * @var string username_colour The user's colour - * @var string guest_username Optional parameter to specify the - * guest username. - * @var string custom_profile_url Optional parameter to specify a - * profile url. - * @var string username_string The string that has been generated - * @var array _profile_cache Array of original return templates - * @since 3.1.0-a1 - */ - $vars = array( - 'mode', - 'user_id', - 'username', - 'username_colour', - 'guest_username', - 'custom_profile_url', - 'username_string', - '_profile_cache', - ); - extract($phpbb_dispatcher->trigger_event('core.modify_username_string', compact($vars))); - - return $username_string; -} - -/** - * Add an option to the quick-mod tools. - * - * @param string $url The recepting URL for the quickmod actions. - * @param string $option The language key for the value of the option. - * @param string $lang_string The language string to use. - */ -function phpbb_add_quickmod_option($url, $option, $lang_string) -{ - global $template, $user, $phpbb_path_helper; - - $lang_string = $user->lang($lang_string); - $template->assign_block_vars('quickmod', array( - 'VALUE' => $option, - 'TITLE' => $lang_string, - 'LINK' => $phpbb_path_helper->append_url_params($url, array('action' => $option)), - )); -} - -/** -* Concatenate an array into a string list. -* -* @param array $items Array of items to concatenate -* @param object $user The phpBB $user object. -* -* @return string String list. Examples: "A"; "A and B"; "A, B, and C" -*/ -function phpbb_generate_string_list($items, $user) -{ - if (empty($items)) - { - return ''; - } - - $count = count($items); - $last_item = array_pop($items); - $lang_key = 'STRING_LIST_MULTI'; - - if ($count == 1) - { - return $last_item; - } - else if ($count == 2) - { - $lang_key = 'STRING_LIST_SIMPLE'; - } - $list = implode($user->lang['COMMA_SEPARATOR'], $items); - - return $user->lang($lang_key, $list, $last_item); -} - -class bitfield -{ - var $data; - - function __construct($bitfield = '') - { - $this->data = base64_decode($bitfield); - } - - /** - */ - function get($n) - { - // Get the ($n / 8)th char - $byte = $n >> 3; - - if (strlen($this->data) >= $byte + 1) - { - $c = $this->data[$byte]; - - // Lookup the ($n % 8)th bit of the byte - $bit = 7 - ($n & 7); - return (bool) (ord($c) & (1 << $bit)); - } - else - { - return false; - } - } - - function set($n) - { - $byte = $n >> 3; - $bit = 7 - ($n & 7); - - if (strlen($this->data) >= $byte + 1) - { - $this->data[$byte] = $this->data[$byte] | chr(1 << $bit); - } - else - { - $this->data .= str_repeat("\0", $byte - strlen($this->data)); - $this->data .= chr(1 << $bit); - } - } - - function clear($n) - { - $byte = $n >> 3; - - if (strlen($this->data) >= $byte + 1) - { - $bit = 7 - ($n & 7); - $this->data[$byte] = $this->data[$byte] &~ chr(1 << $bit); - } - } - - function get_blob() - { - return $this->data; - } - - function get_base64() - { - return base64_encode($this->data); - } - - function get_bin() - { - $bin = ''; - $len = strlen($this->data); - - for ($i = 0; $i < $len; ++$i) - { - $bin .= str_pad(decbin(ord($this->data[$i])), 8, '0', STR_PAD_LEFT); - } - - return $bin; - } - - function get_all_set() - { - return array_keys(array_filter(str_split($this->get_bin()))); - } - - function merge($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 = "> "; - $message = censor_text(trim($message_parser->message)); - // see if we are nesting. It's easily tricked but should work for one level of nesting - if (strpos($message, ">") !== false) - { - $offset = 10; - } - $message = utf8_wordwrap($message, 75 + $offset, "\n"); - - $message = $quote_string . $message; - $message = str_replace("\n", "\n" . $quote_string, $message); - - $message_parser->message = $quote_attributes['author'] . " " . $language->lang('WROTE') . ":\n" . $message . "\n"; - } - - if ($message_link) - { - $message_parser->message = $message_link . $message_parser->message; - } -} diff --git a/install/update/new/includes/functions_convert.php b/install/update/new/includes/functions_convert.php deleted file mode 100644 index 96e1087..0000000 --- a/install/update/new/includes/functions_convert.php +++ /dev/null @@ -1,2500 +0,0 @@ - -* @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; -} - -/** -* Default avatar width/height -* @ignore -*/ -define('DEFAULT_AVATAR_X', 80); -define('DEFAULT_AVATAR_Y', 80); - -// Global functions - all functions can be used by convertors - -// SIMPLE FUNCTIONS - -/** -* Return the preceding value -*/ -function dec($var) -{ - return --$var; -} - -/** -* Return the next value -*/ -function inc($var) -{ - return ++$var; -} - -/** -* Return whether the value is positive -*/ -function is_positive($n) -{ - return ($n > 0) ? 1 : 0; -} - -/** -* Boolean inverse of the value -*/ -function not($var) -{ - return ($var) ? 0 : 1; -} - -/** -* Convert a textual value to it's equivalent boolean value -* -* @param string $str String to convert (converts yes, on, y, 1 and true to boolean true) -* @return boolean The equivalent value -*/ -function str_to_bool($str) -{ - $str = strtolower($str); - return ($str == 'yes' || $str == 'on' || $str == 'y' || $str == 'true' || $str == '1') ? true : false; -} - -/** -* Function to mimic php's empty() function (it is the same) -*/ -function is_empty($mixed) -{ - return empty($mixed); -} - -/** -* Convert the name of a user's primary group to the appropriate equivalent phpBB group id -* -* @param string $status The name of the group -* @return int The group_id corresponding to the equivalent group -*/ -function str_to_primary_group($status) -{ - switch (ucfirst(strtolower($status))) - { - case 'Administrator': - return get_group_id('administrators'); - break; - - case 'Super moderator': - case 'Global moderator': - case 'Moderator': - return get_group_id('global_moderators'); - break; - - case 'Guest': - case 'Anonymous': - return get_group_id('guests'); - break; - - default: - return get_group_id('registered'); - break; - } -} - -/** -* Convert a boolean into the appropriate phpBB constant indicating whether the item is locked -*/ -function is_item_locked($bool) -{ - return ($bool) ? ITEM_LOCKED : ITEM_UNLOCKED; -} - -/** -* Convert a value from days to seconds -*/ -function days_to_seconds($days) -{ - return ($days * 86400); -} - -/** -* Determine whether a user is anonymous and return the appropriate new user_id -*/ -function is_user_anonymous($user_id) -{ - return ($user_id > ANONYMOUS) ? $user_id : ANONYMOUS; -} - -/** -* Generate a key value based on existing values -* -* @param int $pad Amount to add to the maximum value -* @return int Key value -*/ -function auto_id($pad = 0) -{ - global $auto_id, $convert_row; - - if (!empty($convert_row['max_id'])) - { - return $convert_row['max_id'] + $pad; - } - - return $auto_id + $pad; -} - -/** -* Convert a boolean into the appropriate phpBB constant indicating whether the user is active -*/ -function set_user_type($user_active) -{ - return ($user_active) ? USER_NORMAL : USER_INACTIVE; -} - -/** -* Convert a value from minutes to hours -*/ -function minutes_to_hours($minutes) -{ - return ($minutes / 3600); -} - -/** -* Return the group_id for a given group name -*/ -function get_group_id($group_name) -{ - global $db, $group_mapping; - - if (empty($group_mapping)) - { - $sql = 'SELECT group_name, group_id - FROM ' . GROUPS_TABLE; - $result = $db->sql_query($sql); - - $group_mapping = array(); - while ($row = $db->sql_fetchrow($result)) - { - $group_mapping[strtoupper($row['group_name'])] = (int) $row['group_id']; - } - $db->sql_freeresult($result); - } - - if (!count($group_mapping)) - { - add_default_groups(); - return get_group_id($group_name); - } - - if (isset($group_mapping[strtoupper($group_name)])) - { - return $group_mapping[strtoupper($group_name)]; - } - - return $group_mapping['REGISTERED']; -} - -/** -* Convert a boolean into the appropriate phpBB constant indicating whether the topic is locked -*/ -function is_topic_locked($bool) -{ - return (!empty($bool)) ? ITEM_LOCKED : ITEM_UNLOCKED; -} - -/** -* Generate a bbcode_uid value -*/ -function make_uid($timestamp) -{ - static $last_timestamp, $last_uid; - - if (empty($last_timestamp) || $timestamp != $last_timestamp) - { - $last_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN); - } - $last_timestamp = $timestamp; - return $last_uid; -} - - -/** -* Validate a website address -*/ -function validate_website($url) -{ - if ($url === 'http://') - { - return ''; - } - else if (!preg_match('#^http[s]?://#i', $url) && strlen($url) > 0) - { - return 'http://' . $url; - } - return $url; -} - -/** -* Convert nulls to zeros for fields which allowed a NULL value in the source but not the destination -*/ -function null_to_zero($value) -{ - return ($value === NULL) ? 0 : $value; -} - -/** -* Convert nulls to empty strings for fields which allowed a NULL value in the source but not the destination -*/ -function null_to_str($value) -{ - return ($value === NULL) ? '' : $value; -} - -// EXTENDED FUNCTIONS - -/** -* Get old config value -*/ -function get_config_value($config_name) -{ - static $convert_config; - - if (!isset($convert_config)) - { - $convert_config = get_config(); - } - - if (!isset($convert_config[$config_name])) - { - return false; - } - - return (empty($convert_config[$config_name])) ? '' : $convert_config[$config_name]; -} - -/** -* Convert an IP address from the hexadecimal notation to normal dotted-quad notation -*/ -function decode_ip($int_ip) -{ - if (!$int_ip) - { - return $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 (count($hexipbang) < 4) - { - return $int_ip; - } - - return hexdec($hexipbang[0]) . '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]); -} - -/** -* Reverse the encoding of wild-carded bans -*/ -function decode_ban_ip($int_ip) -{ - return str_replace('255', '*', decode_ip($int_ip)); -} - -/** -* Determine the MIME-type of a specified filename -* This does not actually inspect the file, but simply uses the file extension -*/ -function mimetype($filename) -{ - if (!preg_match('/\.([a-z0-9]+)$/i', $filename, $m)) - { - return 'application/octet-stream'; - } - - switch (strtolower($m[1])) - { - case 'zip': return 'application/zip'; - case 'jpeg': return 'image/jpeg'; - case 'jpg': return 'image/jpeg'; - case 'jpe': return 'image/jpeg'; - case 'png': return 'image/png'; - case 'gif': return 'image/gif'; - case 'htm': - case 'html': return 'text/html'; - case 'tif': return 'image/tiff'; - case 'tiff': return 'image/tiff'; - case 'ras': return 'image/x-cmu-raster'; - case 'pnm': return 'image/x-portable-anymap'; - case 'pbm': return 'image/x-portable-bitmap'; - case 'pgm': return 'image/x-portable-graymap'; - case 'ppm': return 'image/x-portable-pixmap'; - case 'rgb': return 'image/x-rgb'; - case 'xbm': return 'image/x-xbitmap'; - case 'xpm': return 'image/x-xpixmap'; - case 'xwd': return 'image/x-xwindowdump'; - case 'z': return 'application/x-compress'; - case 'gtar': return 'application/x-gtar'; - case 'tgz': return 'application/x-gtar'; - case 'gz': return 'application/x-gzip'; - case 'tar': return 'application/x-tar'; - case 'xls': return 'application/excel'; - case 'pdf': return 'application/pdf'; - case 'ppt': return 'application/powerpoint'; - case 'rm': return 'application/vnd.rn-realmedia'; - case 'wma': return 'audio/x-ms-wma'; - case 'swf': return 'application/x-shockwave-flash'; - case 'ief': return 'image/ief'; - case 'doc': - case 'dot': - case 'wrd': return 'application/msword'; - case 'ai': - case 'eps': - case 'ps': return 'application/postscript'; - case 'asc': - case 'txt': - case 'c': - case 'cc': - case 'h': - case 'hh': - case 'cpp': - case 'hpp': - case 'php': - case 'php3': return 'text/plain'; - default: return 'application/octet-stream'; - } -} - -/** -* Obtain the dimensions of all remotely hosted avatars -* This should only be called from execute_last -* There can be significant network overhead if there are a large number of remote avatars -* @todo Look at the option of allowing the user to decide whether this is called or to force the dimensions -*/ -function remote_avatar_dims() -{ - global $db; - - $sql = 'SELECT user_id, user_avatar - FROM ' . USERS_TABLE . ' - WHERE user_avatar_type = ' . AVATAR_REMOTE; - $result = $db->sql_query($sql); - - $remote_avatars = array(); - while ($row = $db->sql_fetchrow($result)) - { - $remote_avatars[(int) $row['user_id']] = $row['user_avatar']; - } - $db->sql_freeresult($result); - - foreach ($remote_avatars as $user_id => $avatar) - { - $width = (int) get_remote_avatar_dim($avatar, 0); - $height = (int) get_remote_avatar_dim($avatar, 1); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_avatar_width = ' . (int) $width . ', user_avatar_height = ' . (int) $height . ' - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - } -} - -function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false) -{ - global $config, $convert, $user; - - $relative_path = empty($convert->convertor['source_path_absolute']); - - // check for trailing slash - if (rtrim($convert->convertor['avatar_gallery_path'], '/') === '') - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'import_avatar_gallery()'), __LINE__, __FILE__); - } - - $src_path = relative_base(path($convert->convertor['avatar_gallery_path'], $relative_path), $relative_path); - - if (is_dir($src_path)) - { - // Do not die on failure... safe mode restrictions may be in effect. - copy_dir($convert->convertor['avatar_gallery_path'], path($config['avatar_gallery_path']) . $gallery_name, !$subdirs_as_galleries, false, false, $relative_path); - - // only doing 1 level deep. (ibf 1.x) - // notes: ibf has 2 tiers: directly in the avatar directory for base gallery (handled in the above statement), plus subdirs(handled below). - // recursive subdirs ignored. -- i don't know if other forums support recursive galleries. if they do, this following code could be upgraded to be recursive. - if ($subdirs_as_galleries) - { - $dirlist = array(); - if ($handle = @opendir($src_path)) - { - while ($entry = readdir($handle)) - { - if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm') - { - continue; - } - - if (is_dir($src_path . $entry)) - { - $dirlist[] = $entry; - } - } - closedir($handle); - } - else if ($dir = @dir($src_path)) - { - while ($entry = $dir->read()) - { - if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm') - { - continue; - } - - if (is_dir($src_path . $entry)) - { - $dirlist[] = $entry; - } - } - $dir->close(); - } - - for ($i = 0, $end = count($dirlist); $i < $end; ++$i) - { - $dir = $dirlist[$i]; - - // Do not die on failure... safe mode restrictions may be in effect. - copy_dir(path($convert->convertor['avatar_gallery_path'], $relative_path) . $dir, path($config['avatar_gallery_path']) . $dir, true, false, false, $relative_path); - } - } - } -} - -function import_attachment_files($category_name = '') -{ - global $config, $convert, $db, $user; - - $sql = 'SELECT config_value AS upload_path - FROM ' . CONFIG_TABLE . " - WHERE config_name = 'upload_path'"; - $result = $db->sql_query($sql); - $config['upload_path'] = $db->sql_fetchfield('upload_path'); - $db->sql_freeresult($result); - - $relative_path = empty($convert->convertor['source_path_absolute']); - - if (empty($convert->convertor['upload_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment_files()'), __LINE__, __FILE__); - } - - if (is_dir(relative_base(path($convert->convertor['upload_path'], $relative_path), $relative_path))) - { - copy_dir($convert->convertor['upload_path'], path($config['upload_path']) . $category_name, true, false, true, $relative_path); - } -} - -function attachment_forum_perms($forum_id) -{ - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - return serialize($forum_id); -} - -// base64todec function -// -> from php manual? -function base64_unpack($string) -{ - $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-'; - $base = strlen($chars); - - $length = strlen($string); - $number = 0; - - for ($i = 1; $i <= $length; $i++) - { - $pos = $length - $i; - $operand = strpos($chars, substr($string, $pos, 1)); - $exponent = pow($base, $i-1); - $dec_value = $operand * $exponent; - $number += $dec_value; - } - - return $number; -} - -function _import_check($config_var, $source, $use_target) -{ - global $convert, $config; - - $result = array( - 'orig_source' => $source, - 'copied' => false, - 'relative_path' => (empty($convert->convertor['source_path_absolute'])) ? true : false, - ); - - // copy file will prepend $phpBB_root_path - $target = $config[$config_var] . '/' . utf8_basename(($use_target === false) ? $source : $use_target); - - if (!empty($convert->convertor[$config_var]) && strpos($source, $convert->convertor[$config_var]) !== 0) - { - $source = $convert->convertor[$config_var] . $source; - } - - $result['source'] = $source; - - if (file_exists(relative_base($source, $result['relative_path'], __LINE__, __FILE__))) - { - $result['copied'] = copy_file($source, $target, false, false, $result['relative_path']); - } - - if ($result['copied']) - { - $result['target'] = utf8_basename($target); - } - else - { - $result['target'] = ($use_target !== false) ? $result['orig_source'] : utf8_basename($target); - } - - return $result; -} - -function import_attachment($source, $use_target = false) -{ - if (empty($source)) - { - return ''; - } - - global $convert, $config, $user; - - // check for trailing slash - if (rtrim($convert->convertor['upload_path'], '/') === '') - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment()'), __LINE__, __FILE__); - } - - $result = _import_check('upload_path', $source, $use_target); - - if ($result['copied']) - { - // Thumbnails? - if (is_array($convert->convertor['thumbnails'])) - { - $thumb_dir = $convert->convertor['thumbnails'][0]; - $thumb_prefix = $convert->convertor['thumbnails'][1]; - $thumb_source = $thumb_dir . $thumb_prefix . utf8_basename($result['source']); - - if (strpos($thumb_source, $convert->convertor['upload_path']) !== 0) - { - $thumb_source = $convert->convertor['upload_path'] . $thumb_source; - } - $thumb_target = $config['upload_path'] . '/thumb_' . $result['target']; - - if (file_exists(relative_base($thumb_source, $result['relative_path'], __LINE__, __FILE__))) - { - copy_file($thumb_source, $thumb_target, false, false, $result['relative_path']); - } - } - } - - return $result['target']; -} - -function import_rank($source, $use_target = false) -{ - if (empty($source)) - { - return ''; - } - - global $convert, $user; - - if (!isset($convert->convertor['ranks_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_RANKS_PATH'], 'import_rank()'), __LINE__, __FILE__); - } - - $result = _import_check('ranks_path', $source, $use_target); - return $result['target']; -} - -function import_smiley($source, $use_target = false) -{ - if (empty($source)) - { - return ''; - } - - global $convert, $user; - - // check for trailing slash - if (rtrim($convert->convertor['smilies_path'], '/') === '') - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'import_smiley()'), __LINE__, __FILE__); - } - - $result = _import_check('smilies_path', $source, $use_target); - return $result['target']; -} - -/* -*/ -function import_avatar($source, $use_target = false, $user_id = false) -{ - if (empty($source) || preg_match('#^https?:#i', $source) || preg_match('#blank\.(gif|png)$#i', $source)) - { - return; - } - - global $convert, $config, $user; - - // check for trailing slash - if (rtrim($convert->convertor['avatar_path'], '/') === '') - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'import_avatar()'), __LINE__, __FILE__); - } - - if ($use_target === false && $user_id !== false) - { - $use_target = $config['avatar_salt'] . '_' . $user_id . '.' . substr(strrchr($source, '.'), 1); - } - - _import_check('avatar_path', $source, $use_target); - - return ((!empty($user_id)) ? $user_id : $use_target) . '.' . substr(strrchr($source, '.'), 1); -} - -/** -* @todo all image dimension functions below (there are a *lot*) should get revisited and converted to one or two functions (no more needed, really). -*/ - -/** -* Calculate the size of the specified image -* Called from the following functions for calculating the size of specific image types -*/ -function get_image_dim($source) -{ - if (empty($source)) - { - return array(0, 0); - } - - global $convert; - - $relative_path = empty($convert->convertor['source_path_absolute']); - - if (file_exists(relative_base($source, $relative_path))) - { - $image = relative_base($source, $relative_path); - return @getimagesize($image); - } - - return false; -} - -/** -* Obtain the width of the specified smilie -*/ -function get_smiley_width($src) -{ - return get_smiley_dim($src, 0); -} - -/** -* Obtain the height of the specified smilie -*/ -function get_smiley_height($src) -{ - return get_smiley_dim($src, 1); -} - -/** -* Obtain the size of the specified smilie (using the cache if possible) and cache the value -*/ -function get_smiley_dim($source, $axis) -{ - if (empty($source)) - { - return 15; - } - - static $smiley_cache = array(); - - if (isset($smiley_cache[$source])) - { - return $smiley_cache[$source][$axis]; - } - - global $convert, $user; - - $orig_source = $source; - - if (!isset($convert->convertor['smilies_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'get_smiley_dim()'), __LINE__, __FILE__); - } - - if (!empty($convert->convertor['smilies_path']) && strpos($source, $convert->convertor['smilies_path']) !== 0) - { - $source = $convert->convertor['smilies_path'] . $source; - } - - $smiley_cache[$orig_source] = get_image_dim($source); - - if (empty($smiley_cache[$orig_source]) || empty($smiley_cache[$orig_source][0]) || empty($smiley_cache[$orig_source][1])) - { - $smiley_cache[$orig_source] = array(15, 15); - return 15; - } - - return $smiley_cache[$orig_source][$axis]; -} - -/** -* Obtain the width of the specified avatar -*/ -function get_avatar_width($src, $func = false, $arg1 = false, $arg2 = false) -{ - return get_avatar_dim($src, 0, $func, $arg1, $arg2); -} - -/** -* Obtain the height of the specified avatar -*/ -function get_avatar_height($src, $func = false, $arg1 = false, $arg2 = false) -{ - return get_avatar_dim($src, 1, $func, $arg1, $arg2); -} - -/** -*/ -function get_avatar_dim($src, $axis, $func = false, $arg1 = false, $arg2 = false) -{ - $avatar_type = AVATAR_UPLOAD; - - if ($func) - { - if ($arg1 || $arg2) - { - $ary = array($arg1); - - if ($arg2) - { - $ary[] = $arg2; - } - - $avatar_type = call_user_func_array($func, $ary); - } - else - { - $avatar_type = call_user_func($func); - } - } - - switch ($avatar_type) - { - case AVATAR_UPLOAD: - return get_upload_avatar_dim($src, $axis); - break; - - case AVATAR_GALLERY: - return get_gallery_avatar_dim($src, $axis); - break; - - case AVATAR_REMOTE: - // see notes on this functions usage and (hopefully) model $func to avoid this accordingly - return get_remote_avatar_dim($src, $axis); - break; - - default: - $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X; - $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y; - - return $axis ? $default_y : $default_x; - break; - } -} - -/** -* Obtain the size of the specified uploaded avatar (using the cache if possible) and cache the value -*/ -function get_upload_avatar_dim($source, $axis) -{ - static $cachedims = false; - static $cachekey = false; - - if (empty($source)) - { - return 0; - } - - if ($cachekey == $source) - { - return $cachedims[$axis]; - } - - if (substr($source, 0, 7) == 'upload:') - { - $source = substr($source, 7); - } - - global $convert, $user; - - if (!isset($convert->convertor['avatar_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'get_upload_avatar_dim()'), __LINE__, __FILE__); - } - - if (!empty($convert->convertor['avatar_path']) && strpos($source, $convert->convertor['avatar_path']) !== 0) - { - $source = path($convert->convertor['avatar_path'], empty($convert->convertor['source_path_absolute'])) . $source; - } - - $cachedims = get_image_dim($source); - - if (empty($cachedims) || empty($cachedims[0]) || empty($cachedims[1])) - { - $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X; - $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y; - - $cachedims = array($default_x, $default_y); - } - - return $cachedims[$axis]; -} - -/** -* Obtain the size of the specified gallery avatar (using the cache if possible) and cache the value -*/ -function get_gallery_avatar_dim($source, $axis) -{ - if (empty($source)) - { - return 0; - } - - static $avatar_cache = array(); - - if (isset($avatar_cache[$source])) - { - return $avatar_cache[$source][$axis]; - } - - global $convert, $user; - - $orig_source = $source; - - if (!isset($convert->convertor['avatar_gallery_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'get_gallery_avatar_dim()'), __LINE__, __FILE__); - } - - if (!empty($convert->convertor['avatar_gallery_path']) && strpos($source, $convert->convertor['avatar_gallery_path']) !== 0) - { - $source = path($convert->convertor['avatar_gallery_path'], empty($convert->convertor['source_path_absolute'])) . $source; - } - - $avatar_cache[$orig_source] = get_image_dim($source); - - if (empty($avatar_cache[$orig_source]) || empty($avatar_cache[$orig_source][0]) || empty($avatar_cache[$orig_source][1])) - { - $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X; - $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y; - - $avatar_cache[$orig_source] = array($default_x, $default_y); - } - - return $avatar_cache[$orig_source][$axis]; -} - -/** -* Obtain the size of the specified remote avatar (using the cache if possible) and cache the value -* Whilst it's unlikely that remote avatars will be duplicated, it is possible so caching seems the best option -* This should only be called from a post processing step due to the possibility of network timeouts -*/ -function get_remote_avatar_dim($src, $axis) -{ - if (empty($src)) - { - return 0; - } - - static $remote_avatar_cache = array(); - - // an ugly hack: we assume that the dimensions of each remote avatar are accessed exactly twice (x and y) - if (isset($remote_avatar_cache[$src])) - { - $retval = $remote_avatar_cache[$src][$axis]; - unset($remote_avatar_cache); - return $retval; - } - - $url_info = @parse_url($src); - if (empty($url_info['host'])) - { - return 0; - } - $host = $url_info['host']; - $port = (isset($url_info['port'])) ? $url_info['port'] : 0; - $protocol = (isset($url_info['scheme'])) ? $url_info['scheme'] : 'http'; - if (empty($port)) - { - switch (strtolower($protocol)) - { - case 'ftp': - $port = 21; - break; - - case 'https': - $port = 443; - break; - - default: - $port = 80; - } - } - - $timeout = @ini_get('default_socket_timeout'); - @ini_set('default_socket_timeout', 2); - - // We're just trying to reach the server to avoid timeouts - $fp = @fsockopen($host, $port, $errno, $errstr, 1); - if ($fp) - { - $remote_avatar_cache[$src] = @getimagesize($src); - fclose($fp); - } - - $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X; - $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y; - $default = array($default_x, $default_y); - - if (empty($remote_avatar_cache[$src]) || empty($remote_avatar_cache[$src][0]) || empty($remote_avatar_cache[$src][1])) - { - $remote_avatar_cache[$src] = $default; - } - else - { - // We trust gallery and uploaded avatars to conform to the size settings; we might have to adjust here - if ($remote_avatar_cache[$src][0] > $default_x || $remote_avatar_cache[$src][1] > $default_y) - { - $bigger = ($remote_avatar_cache[$src][0] > $remote_avatar_cache[$src][1]) ? 0 : 1; - $ratio = $default[$bigger] / $remote_avatar_cache[$src][$bigger]; - $remote_avatar_cache[$src][0] = (int) ($remote_avatar_cache[$src][0] * $ratio); - $remote_avatar_cache[$src][1] = (int) ($remote_avatar_cache[$src][1] * $ratio); - } - } - - @ini_set('default_socket_timeout', $timeout); - return $remote_avatar_cache[$src][$axis]; -} - -function set_user_options() -{ - global $convert_row; - - // Key need to be set in row, else default value is chosen - $keyoptions = array( - 'viewimg' => array('bit' => 0, 'default' => 1), - 'viewflash' => array('bit' => 1, 'default' => 1), - 'viewsmilies' => array('bit' => 2, 'default' => 1), - 'viewsigs' => array('bit' => 3, 'default' => 1), - 'viewavatars' => array('bit' => 4, 'default' => 1), - 'viewcensors' => array('bit' => 5, 'default' => 1), - 'attachsig' => array('bit' => 6, 'default' => 0), - 'bbcode' => array('bit' => 8, 'default' => 1), - 'smilies' => array('bit' => 9, 'default' => 1), - 'sig_bbcode' => array('bit' => 15, 'default' => 1), - 'sig_smilies' => array('bit' => 16, 'default' => 1), - 'sig_links' => array('bit' => 17, 'default' => 1), - ); - - $option_field = 0; - - foreach ($keyoptions as $key => $key_ary) - { - $value = (isset($convert_row[$key])) ? (int) $convert_row[$key] : $key_ary['default']; - - if ($value && !($option_field & 1 << $key_ary['bit'])) - { - $option_field += 1 << $key_ary['bit']; - } - } - - return $option_field; -} - -/** -* Index messages on the fly as we convert them -* @todo naderman, can you check that this works with the new search plugins as it's use is currently disabled (and thus untested) -function search_indexing($message = '') -{ - global $fulltext_search, $convert_row; - - if (!isset($convert_row['post_id'])) - { - return; - } - - if (!$message) - { - if (!isset($convert_row['message'])) - { - return; - } - - $message = $convert_row['message']; - } - - $title = (isset($convert_row['title'])) ? $convert_row['title'] : ''; - - $fulltext_search->index('post', $convert_row['post_id'], $message, $title, $convert_row['poster_id'], $convert_row['forum_id']); -} -*/ - -function make_unique_filename($filename) -{ - if (!strlen($filename)) - { - $filename = md5(unique_id()) . '.dat'; - } - else if ($filename[0] == '.') - { - $filename = md5(unique_id()) . $filename; - } - else if (preg_match('/\.([a-z]+)$/i', $filename, $m)) - { - $filename = preg_replace('/\.([a-z]+)$/i', '_' . md5(unique_id()) . '.\1', $filename); - } - else - { - $filename .= '_' . md5(unique_id()) . '.dat'; - } - - return $filename; -} - -function words_unique(&$words) -{ - reset($words); - $return_array = array(); - - $word = current($words); - do - { - $return_array[$word] = $word; - } - while ($word = next($words)); - - return $return_array; -} - -/** -* Adds a user to the specified group and optionally makes them a group leader -* This function does not create the group if it does not exist and so should only be called after the groups have been created -*/ -function add_user_group($group_id, $user_id, $group_leader = false) -{ - global $db; - - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'group_id' => $group_id, - 'user_id' => $user_id, - 'group_leader' => ($group_leader) ? 1 : 0, - 'user_pending' => 0)); - $db->sql_query($sql); -} - -// STANDALONE FUNCTIONS - -/** -* Add users to the pre-defined "special" groups -* -* @param string $group The name of the special group to add to -* @param string $select_query An SQL query to retrieve the user(s) to add to the group -*/ -function user_group_auth($group, $select_query, $use_src_db) -{ - global $convert, $user, $db, $src_db, $same_db; - - if (!in_array($group, array('guests', 'registered', 'registered_coppa', 'global_moderators', 'administrators', 'bots'))) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_WRONG_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true); - return; - } - - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $db->sql_escape(strtoupper($group)) . "'"; - $result = $db->sql_query($sql); - $group_id = (int) $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - - if (!$group_id) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true); - return; - } - - if ($same_db || !$use_src_db) - { - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' (user_id, group_id, user_pending) - ' . str_replace('{' . strtoupper($group) . '}', $group_id . ', 0', $select_query); - $db->sql_query($sql); - } - else - { - $result = $src_db->sql_query(str_replace('{' . strtoupper($group) . '}', $group_id . ' ', $select_query)); - while ($row = $src_db->sql_fetchrow($result)) - { - // this might become quite a lot of INSERTS unfortunately - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . " (user_id, group_id, user_pending) - VALUES ({$row['user_id']}, $group_id, 0)"; - $db->sql_query($sql); - } - $src_db->sql_freeresult($result); - } -} - -/** -* Retrieves configuration information from the source forum and caches it as an array -* Both database and file driven configuration formats can be handled -* (the type used is specified in $config_schema, see convert_phpbb20.php for more details) -*/ -function get_config() -{ - static $convert_config; - global $user; - - if (isset($convert_config)) - { - return $convert_config; - } - - global $src_db, $same_db; - global $convert; - - if ($convert->config_schema['table_format'] != 'file') - { - if ($convert->mysql_convert && $same_db) - { - $src_db->sql_query("SET NAMES 'binary'"); - } - - $sql = 'SELECT * FROM ' . $convert->src_table_prefix . $convert->config_schema['table_name']; - $result = $src_db->sql_query($sql); - $row = $src_db->sql_fetchrow($result); - - if (!$row) - { - $convert->p_master->error($user->lang['CONV_ERROR_GET_CONFIG'], __LINE__, __FILE__); - } - } - - if (is_array($convert->config_schema['table_format'])) - { - $convert_config = array(); - $key = key($convert->config_schema['table_format']); - $val = current($convert->config_schema['table_format']); - - do - { - $convert_config[$row[$key]] = $row[$val]; - } - while ($row = $src_db->sql_fetchrow($result)); - $src_db->sql_freeresult($result); - - if ($convert->mysql_convert && $same_db) - { - $src_db->sql_query("SET NAMES 'utf8'"); - } - } - else if ($convert->config_schema['table_format'] == 'file') - { - $filename = $convert->options['forum_path'] . '/' . $convert->config_schema['filename']; - if (!file_exists($filename)) - { - $convert->p_master->error($user->lang('FILE_NOT_FOUND', $filename), __LINE__, __FILE__); - } - - if (isset($convert->config_schema['array_name'])) - { - unset($convert->config_schema['array_name']); - } - - $convert_config = extract_variables_from_file($filename); - if (!empty($convert->config_schema['array_name'])) - { - $convert_config = $convert_config[$convert->config_schema['array_name']]; - } - } - else - { - $convert_config = $row; - if ($convert->mysql_convert && $same_db) - { - $src_db->sql_query("SET NAMES 'utf8'"); - } - } - - if (!count($convert_config)) - { - $convert->p_master->error($user->lang['CONV_ERROR_CONFIG_EMPTY'], __LINE__, __FILE__); - } - - return $convert_config; -} - -/** -* Transfers the relevant configuration information from the source forum -* The mapping of fields is specified in $config_schema, see convert_phpbb20.php for more details -*/ -function restore_config($schema) -{ - global $config; - - $convert_config = get_config(); - - foreach ($schema['settings'] as $config_name => $src) - { - if (preg_match('/(.*)\((.*)\)/', $src, $m)) - { - $var = (empty($m[2]) || empty($convert_config[$m[2]])) ? "''" : "'" . addslashes($convert_config[$m[2]]) . "'"; - $exec = '$config_value = ' . $m[1] . '(' . $var . ');'; - // @codingStandardsIgnoreStart - eval($exec); - // @codingStandardsIgnoreEnd - } - else - { - if ($schema['table_format'] != 'file' || empty($schema['array_name'])) - { - $config_value = (isset($convert_config[$src])) ? $convert_config[$src] : ''; - } - else if (!empty($schema['array_name'])) - { - $src_ary = $schema['array_name']; - $config_value = (isset($convert_config[$src_ary][$src])) ? $convert_config[$src_ary][$src] : ''; - } - } - - if ($config_value !== '') - { - // Most are... - if (is_string($config_value)) - { - $config_value = truncate_string(utf8_htmlspecialchars($config_value), 255, 255, false); - } - - $config->set($config_name, $config_value); - } - } -} - -/** -* Update the count of PM's in custom folders for all users -*/ -function update_folder_pm_count() -{ - global $db; - - $sql = 'SELECT user_id, folder_id, COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ', ' . PRIVMSGS_INBOX . ', ' . PRIVMSGS_OUTBOX . ', ' . PRIVMSGS_SENTBOX . ') - GROUP BY folder_id, user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . PRIVMSGS_FOLDER_TABLE . ' SET pm_count = ' . $row['num_messages'] . ' - WHERE user_id = ' . $row['user_id'] . ' AND folder_id = ' . $row['folder_id']); - } - $db->sql_freeresult($result); -} - -// Functions mainly used by the main convertor script - -function path($path, $path_relative = true) -{ - if ($path === false) - { - return ''; - } - - if (substr($path, -1) != '/') - { - $path .= '/'; - } - - if (!$path_relative) - { - return $path; - } - - if (substr($path, 0, 1) == '/') - { - $path = substr($path, 1); - } - - return $path; -} - -/** -* Extract the variables defined in a configuration file -* @todo As noted by Xore we need to look at this from a security perspective -*/ -function extract_variables_from_file($_filename) -{ - include($_filename); - - $vars = get_defined_vars(); - unset($vars['_filename']); - - return $vars; -} - -function get_path($src_path, $src_url, $test_file) -{ - global $phpbb_root_path, $phpEx; - - $board_config = get_config(); - - $test_file = preg_replace('/\.php$/i', ".$phpEx", $test_file); - $src_path = path($src_path); - - if (@file_exists($phpbb_root_path . $src_path . $test_file)) - { - return $src_path; - } - - if (!empty($src_url) && !empty($board_config['server_name'])) - { - if (!preg_match('#https?://([^/]+)(.*)#i', $src_url, $m)) - { - return false; - } - - if ($m[1] != $board_config['server_name']) - { - return false; - } - - $url_parts = explode('/', $m[2]); - if (substr($src_url, -1) != '/') - { - if (preg_match('/.*\.([a-z0-9]{3,4})$/i', $url_parts[count($url_parts) - 1])) - { - $url_parts[count($url_parts) - 1] = ''; - } - else - { - $url_parts[] = ''; - } - } - - $script_path = $board_config['script_path']; - if (substr($script_path, -1) == '/') - { - $script_path = substr($script_path, 0, -1); - } - - $path_array = array(); - - $phpbb_parts = explode('/', $script_path); - for ($i = 0, $end = count($url_parts); $i < $end; ++$i) - { - if ($i < count($phpbb_parts[$i]) && $url_parts[$i] == $phpbb_parts[$i]) - { - $path_array[] = $url_parts[$i]; - unset($url_parts[$i]); - } - else - { - $path = ''; - for ($j = $i, $end2 = count($phpbb_parts); $j < $end2; ++$j) - { - $path .= '../'; - } - $path .= implode('/', $url_parts); - break; - } - } - - if (!empty($path)) - { - if (@file_exists($phpbb_root_path . $path . $test_file)) - { - return $path; - } - } - } - - return false; -} - -function compare_table($tables, $tablename, &$prefixes) -{ - for ($i = 0, $table_size = count($tables); $i < $table_size; ++$i) - { - if (preg_match('/(.*)' . $tables[$i] . '$/', $tablename, $m)) - { - if (empty($m[1])) - { - $m[1] = '*'; - } - - if (isset($prefixes[$m[1]])) - { - $prefixes[$m[1]]++; - } - else - { - $prefixes[$m[1]] = 1; - } - } - } -} - -/** -* Grant permissions to a specified user or group -* -* @param string $ug_type user|group|user_role|group_role -* @param mixed $forum_id forum ids (array|int|0) -> 0 == all forums -* @param mixed $ug_id [int] user_id|group_id : [string] usergroup name -* @param mixed $acl_list [string] acl entry : [array] acl entries : [string] role entry -* @param int $setting ACL_YES|ACL_NO|ACL_NEVER -*/ -function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO) -{ - global $db; - static $acl_option_ids, $group_ids; - - if (($ug_type == 'group' || $ug_type == 'group_role') && is_string($ug_id)) - { - if (!isset($group_ids[$ug_id])) - { - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $db->sql_escape(strtoupper($ug_id)) . "'"; - $result = $db->sql_query_limit($sql, 1); - $id = (int) $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - - if (!$id) - { - return; - } - - $group_ids[$ug_id] = $id; - } - - $ug_id = (int) $group_ids[$ug_id]; - } - - $table = ($ug_type == 'user' || $ug_type == 'user_role') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE; - $id_field = ($ug_type == 'user' || $ug_type == 'user_role') ? 'user_id' : 'group_id'; - - // Role based permissions are the simplest to handle so check for them first - if ($ug_type == 'user_role' || $ug_type == 'group_role') - { - if (is_numeric($forum_id)) - { - $sql = 'SELECT role_id - FROM ' . ACL_ROLES_TABLE . " - WHERE role_name = 'ROLE_" . $db->sql_escape($acl_list) . "'"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // If we have no role id there is something wrong here - if ($row) - { - $sql = "INSERT INTO $table ($id_field, forum_id, auth_role_id) VALUES ($ug_id, $forum_id, " . $row['role_id'] . ')'; - $db->sql_query($sql); - } - } - - return; - } - - // Build correct parameters - $auth = array(); - - if (!is_array($acl_list)) - { - $auth = array($acl_list => $setting); - } - else - { - foreach ($acl_list as $auth_option) - { - $auth[$auth_option] = $setting; - } - } - unset($acl_list); - - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - // Set any flags as required - foreach ($auth as $auth_option => $acl_setting) - { - $flag = substr($auth_option, 0, strpos($auth_option, '_') + 1); - if (empty($auth[$flag])) - { - $auth[$flag] = $acl_setting; - } - } - - if (!is_array($acl_option_ids) || empty($acl_option_ids)) - { - $sql = 'SELECT auth_option_id, auth_option - FROM ' . ACL_OPTIONS_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $acl_option_ids[$row['auth_option']] = $row['auth_option_id']; - } - $db->sql_freeresult($result); - } - - $sql_forum = 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id), false, true); - - $sql = ($ug_type == 'user') ? 'SELECT o.auth_option_id, o.auth_option, a.forum_id, a.auth_setting FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " o WHERE a.auth_option_id = o.auth_option_id $sql_forum AND a.user_id = $ug_id" : 'SELECT o.auth_option_id, o.auth_option, a.forum_id, a.auth_setting FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " o WHERE a.auth_option_id = o.auth_option_id $sql_forum AND a.group_id = $ug_id"; - $result = $db->sql_query($sql); - - $cur_auth = array(); - while ($row = $db->sql_fetchrow($result)) - { - $cur_auth[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting']; - } - $db->sql_freeresult($result); - - $sql_ary = array(); - foreach ($forum_id as $forum) - { - foreach ($auth as $auth_option => $setting) - { - $auth_option_id = $acl_option_ids[$auth_option]; - - if (!$auth_option_id) - { - continue; - } - - switch ($setting) - { - case ACL_NO: - if (isset($cur_auth[$forum][$auth_option_id])) - { - $sql_ary['delete'][] = "DELETE FROM $table - WHERE forum_id = $forum - AND auth_option_id = $auth_option_id - AND $id_field = $ug_id"; - } - break; - - default: - if (!isset($cur_auth[$forum][$auth_option_id])) - { - $sql_ary['insert'][] = "$ug_id, $forum, $auth_option_id, $setting"; - } - else if ($cur_auth[$forum][$auth_option_id] != $setting) - { - $sql_ary['update'][] = "UPDATE " . $table . " - SET auth_setting = $setting - WHERE $id_field = $ug_id - AND forum_id = $forum - AND auth_option_id = $auth_option_id"; - } - } - } - } - unset($cur_auth); - - $sql = ''; - foreach ($sql_ary as $sql_type => $sql_subary) - { - switch ($sql_type) - { - case 'insert': - switch ($db->get_sql_layer()) - { - case 'sqlite3': - case 'mssqlnative': - $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); - break; - - default: - foreach ($sql_subary as $sql) - { - $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) VALUES ($sql)"; - $db->sql_query($sql); - $sql = ''; - } - } - - if ($sql != '') - { - $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) $sql"; - $db->sql_query($sql); - } - break; - - case 'update': - case 'delete': - foreach ($sql_subary as $sql) - { - $db->sql_query($sql); - $sql = ''; - } - break; - } - unset($sql_ary[$sql_type]); - } - unset($sql_ary); - -} - -/** -* Update the count of unread private messages for all users -*/ -function update_unread_count() -{ - global $db; - - $sql = 'SELECT user_id, COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE pm_unread = 1 - AND folder_id <> ' . PRIVMSGS_OUTBOX . ' - GROUP BY user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_unread_privmsg = ' . $row['num_messages'] . ' - WHERE user_id = ' . $row['user_id']); - } - $db->sql_freeresult($result); -} - -/** -* Add any of the pre-defined "special" groups which are missing from the database -*/ -function add_default_groups() -{ - global $db; - - $default_groups = array( - 'GUESTS' => array('', 0, 0), - 'REGISTERED' => array('', 0, 0), - 'REGISTERED_COPPA' => array('', 0, 0), - 'GLOBAL_MODERATORS' => array('00AA00', 2, 0), - 'ADMINISTRATORS' => array('AA0000', 1, 1), - 'BOTS' => array('9E8DA7', 0, 0), - 'NEWLY_REGISTERED' => array('', 0, 0), - ); - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_name', array_keys($default_groups)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - unset($default_groups[strtoupper($row['group_name'])]); - } - $db->sql_freeresult($result); - - $sql_ary = array(); - - foreach ($default_groups as $name => $data) - { - $sql_ary[] = array( - 'group_name' => (string) $name, - 'group_desc' => '', - 'group_desc_uid' => '', - 'group_desc_bitfield' => '', - 'group_type' => GROUP_SPECIAL, - 'group_colour' => (string) $data[0], - 'group_legend' => (int) $data[1], - 'group_founder_manage' => (int) $data[2], - ); - } - - if (count($sql_ary)) - { - $db->sql_multi_insert(GROUPS_TABLE, $sql_ary); - } -} - -function add_groups_to_teampage() -{ - global $db; - - $teampage_groups = array( - 'ADMINISTRATORS' => 1, - 'GLOBAL_MODERATORS' => 2, - ); - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_name', array_keys($teampage_groups)); - $result = $db->sql_query($sql); - - $teampage_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $teampage_ary[] = array( - 'group_id' => (int) $row['group_id'], - 'teampage_name' => '', - 'teampage_position' => (int) $teampage_groups[$row['group_name']], - 'teampage_parent' => 0, - ); - } - $db->sql_freeresult($result); - - if (count($teampage_ary)) - { - $db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_ary); - } -} - - -/** -* Sync post count. We might need to do this in batches. -*/ -function sync_post_count($offset, $limit) -{ - global $db; - $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id - FROM ' . POSTS_TABLE . ' - WHERE post_postcount = 1 - AND post_visibility = ' . ITEM_APPROVED . ' - GROUP BY poster_id - ORDER BY poster_id'; - $result = $db->sql_query_limit($sql, $limit, $offset); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}"); - } - $db->sql_freeresult($result); -} - -/** -* Add the search bots into the database -* This code should be used in execute_last if the source database did not have bots -* If you are converting bots this function should not be called -* @todo We might want to look at sharing the bot list between the install code and this code for consistancy -*/ -function add_bots() -{ - global $db, $convert, $user, $config, $phpbb_root_path, $phpEx; - - $db->sql_query($convert->truncate_statement . BOTS_TABLE); - - $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'"; - $result = $db->sql_query($sql); - $group_id = (int) $db->sql_fetchfield('group_id', false, $result); - $db->sql_freeresult($result); - - if (!$group_id) - { - add_default_groups(); - - $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'"; - $result = $db->sql_query($sql); - $group_id = (int) $db->sql_fetchfield('group_id', false, $result); - $db->sql_freeresult($result); - - if (!$group_id) - { - global $install; - $install->error($user->lang['CONV_ERROR_INCONSISTENT_GROUPS'], __LINE__, __FILE__); - } - } - - $bots = 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/2', ''), - 'Majestic-12 [Bot]' => array('MJ12bot/', ''), - 'Metager [Bot]' => array('MetagerBot/', ''), - 'MSN NewsBlogs' => array('msnbot-NewsBlogs/', ''), - 'MSN [Bot]' => array('msnbot/', ''), - 'MSNbot Media' => array('msnbot-media/', ''), - 'NG-Search [Bot]' => array('NG-Search/', ''), - 'Nutch [Bot]' => array('http://lucene.apache.org/nutch/', ''), - 'Nutch/CVS [Bot]' => array('NutchCVS/', ''), - 'OmniExplorer [Bot]' => array('OmniExplorer_Bot/', ''), - 'Online link [Validator]' => array('online link validator', ''), - 'psbot [Picsearch]' => array('psbot/0', ''), - 'Seekport [Bot]' => array('Seekbot/', ''), - '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/', ''), - 'Synoo [Bot]' => array('SynooBot/', ''), - 'Telekom [Bot]' => array('crawleradmin.t-info@telekom.de', ''), - 'TurnitinBot [Bot]' => array('TurnitinBot/', ''), - 'Voyager [Bot]' => array('voyager/1.0', ''), - 'W3 [Sitesearch]' => array('W3 SiteSearch Crawler', ''), - 'W3C [Linkcheck]' => array('W3C-checklink/', ''), - 'W3C [Validator]' => array('W3C_*Validator', ''), - 'WiseNut [Bot]' => array('http://www.WISEnutbot.com', ''), - '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/', ''), - ); - - if (!function_exists('user_add')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - foreach ($bots 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' => $config['default_lang'], - 'user_style' => 1, - 'user_timezone' => 'UTC', - 'user_allow_massemail' => 0, - ); - - $user_id = user_add($user_row); - - if ($user_id) - { - $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'bot_active' => 1, - 'bot_name' => $bot_name, - 'user_id' => $user_id, - 'bot_agent' => $bot_ary[0], - 'bot_ip' => $bot_ary[1]) - ); - $db->sql_query($sql); - } - } -} - -/** -* Update any dynamic configuration variables after the conversion is finished -* @todo Confirm that this updates all relevant values since it has not necessarily been kept in sync with all changes -*/ -function update_dynamic_config() -{ - global $db, $config; - - // Get latest username - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; - - if (!empty($config['increment_user_id'])) - { - $sql .= ' AND user_id <> ' . $config['increment_user_id']; - } - - $sql .= ' ORDER BY user_id DESC'; - - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $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. -// set_config('record_online_users', 1, true); -// set_config('record_online_date', time(), true); - - $sql = 'SELECT COUNT(post_id) AS stat - FROM ' . POSTS_TABLE . ' - WHERE post_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_posts', (int) $row['stat'], false); - - $sql = 'SELECT COUNT(topic_id) AS stat - FROM ' . TOPICS_TABLE . ' - WHERE topic_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_topics', (int) $row['stat'], false); - - $sql = 'SELECT COUNT(user_id) AS stat - FROM ' . USERS_TABLE . ' - WHERE user_type IN (' . USER_NORMAL . ',' . USER_FOUNDER . ')'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $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); - $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); - $config->set('upload_dir_size', (float) $db->sql_fetchfield('stat'), false); - $db->sql_freeresult($result); - - /** - * We do not resync users post counts - this can be done by the admin after conversion if wanted. - $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id - FROM ' . POSTS_TABLE . ' - WHERE post_postcount = 1 - GROUP BY poster_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}"); - } - $db->sql_freeresult($result); - */ -} - -/** -* Updates topics_posted entries -*/ -function update_topics_posted() -{ - global $db; - - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); - break; - - default: - $db->sql_query('TRUNCATE TABLE ' . TOPICS_POSTED_TABLE); - break; - } - - // This can get really nasty... therefore we only do the last six months - $get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60); - - // Select forum ids, do not include categories - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type <> ' . FORUM_CAT; - $result = $db->sql_query($sql); - - $forum_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $db->sql_freeresult($result); - - // Any global announcements? ;) - $forum_ids[] = 0; - - // Now go through the forums and get us some topics... - foreach ($forum_ids as $forum_id) - { - $sql = 'SELECT p.poster_id, p.topic_id - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t - WHERE t.forum_id = ' . $forum_id . ' - AND t.topic_moved_id = 0 - AND t.topic_last_post_time > ' . $get_from_time . ' - AND t.topic_id = p.topic_id - AND p.poster_id <> ' . ANONYMOUS . ' - GROUP BY p.poster_id, p.topic_id'; - $result = $db->sql_query($sql); - - $posted = array(); - while ($row = $db->sql_fetchrow($result)) - { - $posted[$row['poster_id']][] = $row['topic_id']; - } - $db->sql_freeresult($result); - - $sql_ary = array(); - foreach ($posted as $user_id => $topic_row) - { - foreach ($topic_row as $topic_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user_id, - 'topic_id' => (int) $topic_id, - 'topic_posted' => 1, - ); - } - } - unset($posted); - - if (count($sql_ary)) - { - $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); - } - } -} - -/** -* Ensure that all users have a default group specified and update related information such as their colour -*/ -function fix_empty_primary_groups() -{ - global $db; - - // Set group ids for users not already having it - $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . ' - WHERE group_id = 0 AND user_type = ' . USER_INACTIVE; - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . ' - WHERE group_id = 0 AND user_type = ' . USER_NORMAL; - $db->sql_query($sql); - - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('guests') . ' WHERE user_id = ' . ANONYMOUS); - - $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('administrators'); - $result = $db->sql_query($sql); - - $user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - 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)); - } - - $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('global_moderators'); - $result = $db->sql_query($sql); - - $user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - 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)); - } - - // Set user colour - $sql = 'SELECT group_id, group_colour FROM ' . GROUPS_TABLE . " - WHERE group_colour <> ''"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_colour = '{$row['group_colour']}' WHERE group_id = {$row['group_id']}"); - } - $db->sql_freeresult($result); -} - -/** -* Cleanly remove invalid user entries after converting the users table... -*/ -function remove_invalid_users() -{ - global $db, $phpEx, $phpbb_root_path; - - // username_clean is UNIQUE - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE username_clean = ''"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - if (!function_exists('user_delete')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - user_delete('remove', $row['user_id']); - } -} - -function convert_bbcode($message, $convert_size = true, $extended_bbcodes = false) -{ - static $orig, $repl, $origx, $replx, $str_from, $str_to; - - if (empty($orig)) - { - $orig = $repl = array(); - - $orig[] = '#\[(php|sql)\](.*?)\[/(php|sql)\]#is'; - $repl[] = '[code]\2[/code]'; - - $orig[] = '#\[font=[^\]]+\](.*?)\[/font\]#is'; - $repl[] = '\1'; - - $orig[] = '#\[align=[a-z]+\](.*?)\[/align\]#is'; - $repl[] = '\1'; - - $orig[] = '#\[/list=.*?\]#is'; - $repl[] = '[/list]'; - - $origx = array( - '#\[glow[^\]]+\](.*?)\[/glow\]#is', - '#\[shadow[^\]]+\](.*?)\[/shadow\]#is', - '#\[flash[^\]]+\](.*?)\[/flash\]#is' - ); - - $replx = array( - '\1', - '\1', - '[url=\1]Flash[/url]' - ); - - $str_from = array( - '[ftp]', '[/ftp]', - '[ftp=', '[/ftp]', - '[pre]', '[/pre]', - '[table]', '[/table]', - '[td]', '[/td]', - '[tr]', '[/tr]', - '[s]', '[/s]', - '[left]', '[/left]', - '[right]', '[/right]', - '[center]', '[/center]', - '[sub]', '[/sub]', - '[sup]', '[/sup]', - '[tt]', '[/tt]', - '[move]', '[/move]', - '[hr]' - ); - - $str_to = array( - '[url]', '[/url]', - '[url=', '[/url]', - '[code]', '[/code]', - "\n", '', - '', '', - "\n", '', - '', '', - '', '', - '', '', - '', '', - '', '', - '', '', - '', '', - '', '', - "\n\n" - ); - - for ($i = 0, $end = count($str_from); $i < $end; ++$i) - { - $origx[] = '#\\' . str_replace(']', '\\]', $str_from[$i]) . '#is'; - $replx[] = $str_to[$i]; - } - } - - if (preg_match_all('#\[email=([^\]]+)\](.*?)\[/email\]#i', $message, $m)) - { - for ($i = 0, $end = count($m[1]); $i < $end; ++$i) - { - if ($m[1][$i] == $m[2][$i]) - { - $message = str_replace($m[0][$i], '[email]' . $m[1][$i] . '[/email]', $message); - } - else - { - $message = str_replace($m[0][$i], $m[2][$i] . ' ([email]' . $m[1][$i] . '[/email])', $message); - } - } - } - - if ($convert_size && preg_match('#\[size=[0-9]+\].*?\[/size\]#i', $message)) - { - $size = array(9, 9, 12, 15, 18, 24, 29, 29, 29, 29); - $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 = count($size); $i;) - { - $i--; - $message = str_replace('[size=' . $i . ']', '[size=' . $size[$i] . ']', $message); - } - } - - if ($extended_bbcodes) - { - $message = preg_replace($origx, $replx, $message); - } - - $message = preg_replace($orig, $repl, $message); - return $message; -} - - -function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $source_relative_path = true) -{ - global $convert, $phpbb_root_path, $user, $phpbb_filesystem; - - /** @var \phpbb\filesystem\filesystem_interface $filesystem */ - $filesystem = $phpbb_filesystem; - - if (substr($trg, -1) == '/') - { - $trg .= utf8_basename($src); - } - $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__); - $trg_path = $trg; - - if (!$overwrite && @file_exists($trg_path)) - { - return true; - } - - if (!@file_exists($src_path)) - { - return; - } - - $path = $phpbb_root_path; - $parts = explode('/', $trg); - unset($parts[count($parts) - 1]); - - for ($i = 0, $end = count($parts); $i < $end; ++$i) - { - $path .= $parts[$i] . '/'; - - if (!is_dir($path)) - { - @mkdir($path, 0777); - } - } - - if (!$filesystem->is_writable($path)) - { - @chmod($path, 0777); - } - - if (!@copy($src_path, $phpbb_root_path . $trg_path)) - { - $convert->p_master->error(sprintf($user->lang['COULD_NOT_COPY'], $src_path, $phpbb_root_path . $trg_path), __LINE__, __FILE__, !$die_on_failure); - return; - } - - if ($perm = @fileperms($src_path)) - { - @chmod($phpbb_root_path . $trg_path, $perm); - } - - return true; -} - -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, $phpbb_filesystem; - - /** @var \phpbb\filesystem\filesystem_interface $filesystem */ - $filesystem = $phpbb_filesystem; - - $dirlist = $filelist = $bad_dirs = array(); - $src = path($src, $source_relative_path); - $trg = path($trg); - $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__); - $trg_path = $phpbb_root_path . $trg; - - if (!is_dir($trg_path)) - { - @mkdir($trg_path, 0777); - @chmod($trg_path, 0777); - } - - if (!$filesystem->is_writable($trg_path)) - { - $bad_dirs[] = path($config['script_path']) . $trg; - } - - if ($handle = @opendir($src_path)) - { - while ($entry = readdir($handle)) - { - if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm') - { - continue; - } - - if (is_dir($src_path . $entry)) - { - $dirlist[] = $entry; - } - else - { - $filelist[] = $entry; - } - } - closedir($handle); - } - else if ($dir = @dir($src_path)) - { - while ($entry = $dir->read()) - { - if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm') - { - continue; - } - - if (is_dir($src_path . $entry)) - { - $dirlist[] = $entry; - } - else - { - $filelist[] = $entry; - } - } - $dir->close(); - } - else - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_COULD_NOT_READ'], relative_base($src, $source_relative_path)), __LINE__, __FILE__); - } - - if ($copy_subdirs) - { - for ($i = 0, $end = count($dirlist); $i < $end; ++$i) - { - $dir = $dirlist[$i]; - - if ($dir == 'CVS') - { - continue; - } - - if (!is_dir($trg_path . $dir)) - { - @mkdir($trg_path . $dir, 0777); - @chmod($trg_path . $dir, 0777); - } - - if (!$filesystem->is_writable($trg_path . $dir)) - { - $bad_dirs[] = $trg . $dir; - $bad_dirs[] = $trg_path . $dir; - } - - if (!count($bad_dirs)) - { - copy_dir($src . $dir, $trg . $dir, true, $overwrite, $die_on_failure, $source_relative_path); - } - } - } - - if (count($bad_dirs)) - { - $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('
', $bad_dirs)), __LINE__, __FILE__); - } - - for ($i = 0, $end = count($filelist); $i < $end; ++$i) - { - copy_file($src . $filelist[$i], $trg . $filelist[$i], $overwrite, $die_on_failure, $source_relative_path); - } -} - -function relative_base($path, $is_relative = true, $line = false, $file = false) -{ - global $convert, $user; - - if (!$is_relative) - { - return $path; - } - - if (empty($convert->options['forum_path']) && $is_relative) - { - $line = $line ? $line : __LINE__; - $file = $file ? $file : __FILE__; - - $convert->p_master->error($user->lang['CONV_ERROR_NO_FORUM_PATH'], $line, $file); - } - - return $convert->options['forum_path'] . '/' . $path; -} - -function get_smiley_display() -{ - static $smiley_count = 0; - $smiley_count++; - return ($smiley_count < 50) ? 1 : 0; -} - - -function fill_dateformat($user_dateformat) -{ - global $config; - - return ((empty($user_dateformat)) ? $config['default_dateformat'] : $user_dateformat); -} diff --git a/install/update/new/includes/functions_display.php b/install/update/new/includes/functions_display.php deleted file mode 100644 index 44478db..0000000 --- a/install/update/new/includes/functions_display.php +++ /dev/null @@ -1,1725 +0,0 @@ - -* @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; -} - -/** -* Display Forums -*/ -function display_forums($root_data = '', $display_moderators = true, $return_moderators = false) -{ - global $db, $auth, $user, $template; - global $phpbb_root_path, $phpEx, $config; - global $request, $phpbb_dispatcher, $phpbb_container; - - $forum_rows = $subforums = $forum_ids = $forum_ids_moderator = $forum_moderators = $active_forum_ary = array(); - $parent_id = $visible_forums = 0; - $parent_subforum_limit = false; - - // Mark forums read? - $mark_read = $request->variable('mark', ''); - - if ($mark_read == 'all') - { - $mark_read = ''; - } - - if (!$root_data) - { - if ($mark_read == 'forums') - { - $mark_read = 'all'; - } - - $root_data = array('forum_id' => 0); - $sql_where = ''; - } - else - { - $sql_where = 'left_id > ' . $root_data['left_id'] . ' AND left_id < ' . $root_data['right_id']; - } - - // Handle marking everything read - if ($mark_read == 'all') - { - $redirect = build_url(array('mark', 'hash', 'mark_time')); - meta_refresh(3, $redirect); - - if (check_link_hash($request->variable('hash', ''), 'global')) - { - markread('all', false, false, $request->variable('mark_time', 0)); - - if ($request->is_ajax()) - { - // Tell the ajax script what language vars and URL need to be replaced - $data = array( - 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'], - 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'], - 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}index.$phpEx", 'hash=' . generate_link_hash('global') . '&mark=forums&mark_time=' . time(), false) : '', - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED'] - ); - $json_response = new \phpbb\json_response(); - $json_response->send($data); - } - - trigger_error( - $user->lang['FORUMS_MARKED'] . '

' . - sprintf($user->lang['RETURN_INDEX'], '', '') - ); - } - else - { - trigger_error(sprintf($user->lang['RETURN_PAGE'], '', '')); - } - } - - // Display list of active topics for this category? - $show_active = (isset($root_data['forum_flags']) && ($root_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) ? true : false; - - $sql_array = array( - 'SELECT' => 'f.*', - 'FROM' => array( - FORUMS_TABLE => 'f' - ), - 'LEFT_JOIN' => array(), - ); - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql_array['LEFT_JOIN'][] = array('FROM' => array(FORUMS_TRACK_TABLE => 'ft'), 'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND ft.forum_id = f.forum_id'); - $sql_array['SELECT'] .= ', ft.mark_time'; - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - } - - if ($show_active) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(FORUMS_ACCESS_TABLE => 'fa'), - 'ON' => "fa.forum_id = f.forum_id AND fa.session_id = '" . $db->sql_escape($user->session_id) . "'" - ); - - $sql_array['SELECT'] .= ', fa.user_id'; - } - - $sql_ary = array( - 'SELECT' => $sql_array['SELECT'], - 'FROM' => $sql_array['FROM'], - 'LEFT_JOIN' => $sql_array['LEFT_JOIN'], - - 'WHERE' => $sql_where, - - 'ORDER_BY' => 'f.left_id', - ); - - /** - * Event to modify the SQL query before the forum data is queried - * - * @event core.display_forums_modify_sql - * @var array sql_ary The SQL array to get the data of the forums - * @since 3.1.0-a1 - */ - $vars = array('sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_sql', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - - $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)) - { - /** - * Event to modify the data set of a forum - * - * This event is triggered once per forum - * - * @event core.display_forums_modify_row - * @var int branch_root_id Last top-level forum - * @var array row The data of the forum - * @since 3.1.0-a1 - */ - $vars = array('branch_root_id', 'row'); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_row', compact($vars))); - - $forum_id = $row['forum_id']; - - // Mark forums read? - if ($mark_read == 'forums') - { - if ($auth->acl_get('f_list', $forum_id)) - { - $forum_ids[] = $forum_id; - } - - continue; - } - - // Category with no members - if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) - { - continue; - } - - // Skip branch - if (isset($right_id)) - { - if ($row['left_id'] < $right_id) - { - continue; - } - unset($right_id); - } - - if (!$auth->acl_get('f_list', $forum_id)) - { - // if the user does not have permissions to list this forum, skip everything until next branch - $right_id = $row['right_id']; - continue; - } - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $forum_tracking_info[$forum_id] = (!empty($row['mark_time'])) ? $row['mark_time'] : $user->data['user_lastmark']; - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - $forum_tracking_info[$forum_id] = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark']; - } - - // Lets check whether there are unapproved topics/posts, so we can display an information to moderators - $row['forum_id_unapproved_topics'] = ($auth->acl_get('m_approve', $forum_id) && $row['forum_topics_unapproved']) ? $forum_id : 0; - $row['forum_id_unapproved_posts'] = ($auth->acl_get('m_approve', $forum_id) && $row['forum_posts_unapproved']) ? $forum_id : 0; - $row['forum_posts'] = $phpbb_content_visibility->get_count('forum_posts', $row, $forum_id); - $row['forum_topics'] = $phpbb_content_visibility->get_count('forum_topics', $row, $forum_id); - - // Display active topics from this forum? - if ($show_active && $row['forum_type'] == FORUM_POST && $auth->acl_get('f_read', $forum_id) && ($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) - { - if (!isset($active_forum_ary['forum_topics'])) - { - $active_forum_ary['forum_topics'] = 0; - } - - if (!isset($active_forum_ary['forum_posts'])) - { - $active_forum_ary['forum_posts'] = 0; - } - - $active_forum_ary['forum_id'][] = $forum_id; - $active_forum_ary['enable_icons'][] = $row['enable_icons']; - $active_forum_ary['forum_topics'] += $row['forum_topics']; - $active_forum_ary['forum_posts'] += $row['forum_posts']; - - // If this is a passworded forum we do not show active topics from it if the user is not authorised to view it... - if ($row['forum_password'] && $row['user_id'] != $user->data['user_id']) - { - $active_forum_ary['exclude_forum_id'][] = $forum_id; - } - } - - // Fill list of categories with forums - if (isset($forum_rows[$row['parent_id']])) - { - $valid_categories[$row['parent_id']] = true; - } - - // - if ($row['parent_id'] == $root_data['forum_id'] || $row['parent_id'] == $branch_root_id) - { - if ($row['forum_type'] != FORUM_CAT) - { - $forum_ids_moderator[] = (int) $forum_id; - } - - // Direct child of current branch - $parent_id = $forum_id; - $parent_subforum_limit = $row['display_subforum_limit']; - $forum_rows[$forum_id] = $row; - - if ($row['forum_type'] == FORUM_CAT && $row['parent_id'] == $root_data['forum_id']) - { - $branch_root_id = $forum_id; - } - $forum_rows[$parent_id]['forum_id_last_post'] = $row['forum_id']; - $forum_rows[$parent_id]['forum_password_last_post'] = $row['forum_password']; - $forum_rows[$parent_id]['orig_forum_last_post_time'] = $row['forum_last_post_time']; - } - else if ($row['forum_type'] != FORUM_CAT) - { - $subforums[$parent_id][$forum_id]['display'] = ($row['display_on_index'] && (!$parent_subforum_limit || $parent_id == $row['parent_id'])); - $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']) - { - $subforums[$parent_id][$row['parent_id']]['children'][] = $forum_id; - } - - if (!$forum_rows[$parent_id]['forum_id_unapproved_topics'] && $row['forum_id_unapproved_topics']) - { - $forum_rows[$parent_id]['forum_id_unapproved_topics'] = $forum_id; - } - - if (!$forum_rows[$parent_id]['forum_id_unapproved_posts'] && $row['forum_id_unapproved_posts']) - { - $forum_rows[$parent_id]['forum_id_unapproved_posts'] = $forum_id; - } - - $forum_rows[$parent_id]['forum_topics'] += $row['forum_topics']; - - // Do not list redirects in LINK Forums as Posts. - if ($row['forum_type'] != FORUM_LINK) - { - $forum_rows[$parent_id]['forum_posts'] += $row['forum_posts']; - } - - if ($row['forum_last_post_time'] > $forum_rows[$parent_id]['forum_last_post_time']) - { - $forum_rows[$parent_id]['forum_last_post_id'] = $row['forum_last_post_id']; - $forum_rows[$parent_id]['forum_last_post_subject'] = $row['forum_last_post_subject']; - $forum_rows[$parent_id]['forum_last_post_time'] = $row['forum_last_post_time']; - $forum_rows[$parent_id]['forum_last_poster_id'] = $row['forum_last_poster_id']; - $forum_rows[$parent_id]['forum_last_poster_name'] = $row['forum_last_poster_name']; - $forum_rows[$parent_id]['forum_last_poster_colour'] = $row['forum_last_poster_colour']; - $forum_rows[$parent_id]['forum_id_last_post'] = $forum_id; - $forum_rows[$parent_id]['forum_password_last_post'] = $row['forum_password']; - } - } - - /** - * Event to modify the forum rows data set - * - * This event is triggered once per forum - * - * @event core.display_forums_modify_forum_rows - * @var array forum_rows Data array of all forums we display - * @var array subforums Data array of all subforums we display - * @var int branch_root_id Current top-level forum - * @var int parent_id Current parent forum - * @var array row The data of the forum - * @since 3.1.0-a1 - */ - $vars = array('forum_rows', 'subforums', 'branch_root_id', 'parent_id', 'row'); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_forum_rows', compact($vars))); - } - $db->sql_freeresult($result); - - // Handle marking posts - if ($mark_read == 'forums') - { - $redirect = build_url(array('mark', 'hash', 'mark_time')); - $token = $request->variable('hash', ''); - if (check_link_hash($token, 'global')) - { - markread('topics', $forum_ids, false, $request->variable('mark_time', 0)); - $message = sprintf($user->lang['RETURN_FORUM'], '', ''); - meta_refresh(3, $redirect); - - if ($request->is_ajax()) - { - // Tell the ajax script what language vars and URL need to be replaced - $data = array( - 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'], - 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'], - 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . '&f=' . $root_data['forum_id'] . '&mark=forums&mark_time=' . time(), false) : '', - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED'] - ); - $json_response = new \phpbb\json_response(); - $json_response->send($data); - } - - trigger_error($user->lang['FORUMS_MARKED'] . '

' . $message); - } - else - { - $message = sprintf($user->lang['RETURN_PAGE'], '', ''); - meta_refresh(3, $redirect); - trigger_error($message); - } - - } - - // Grab moderators ... if necessary - if ($display_moderators) - { - if ($return_moderators) - { - $forum_ids_moderator[] = $root_data['forum_id']; - } - get_moderators($forum_moderators, $forum_ids_moderator); - } - - /** - * Event to perform additional actions before the forum list is being generated - * - * @event core.display_forums_before - * @var array active_forum_ary Array with forum data to display active topics - * @var bool display_moderators Flag indicating if we display forum moderators - * @var array forum_moderators Array with forum moderators list - * @var array forum_rows Data array of all forums we display - * @var bool return_moderators Flag indicating if moderators list should be returned - * @var array root_data Array with the root forum data - * @since 3.1.4-RC1 - */ - $vars = array( - 'active_forum_ary', - 'display_moderators', - 'forum_moderators', - 'forum_rows', - 'return_moderators', - 'root_data', - ); - extract($phpbb_dispatcher->trigger_event('core.display_forums_before', compact($vars))); - - // Used to tell whatever we have to create a dummy category or not. - $last_catless = true; - foreach ($forum_rows as $row) - { - // Category - if ($row['parent_id'] == $root_data['forum_id'] && $row['forum_type'] == FORUM_CAT) - { - // Do not display categories without any forums to display - if (!isset($valid_categories[$row['forum_id']])) - { - continue; - } - - $cat_row = array( - 'S_IS_CAT' => true, - 'FORUM_ID' => $row['forum_id'], - 'FORUM_NAME' => $row['forum_name'], - 'FORUM_DESC' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), - 'FORUM_FOLDER_IMG' => '', - 'FORUM_FOLDER_IMG_SRC' => '', - 'FORUM_IMAGE' => ($row['forum_image']) ? '' . $user->lang['FORUM_CAT'] . '' : '', - 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', - 'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), - ); - - /** - * Modify the template data block of the 'category' - * - * This event is triggered once per 'category' - * - * @event core.display_forums_modify_category_template_vars - * @var array cat_row Template data of the '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', - 'last_catless', - 'root_data', - 'row', - ); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_category_template_vars', compact($vars))); - - $template->assign_block_vars('forumrow', $cat_row); - - continue; - } - - $visible_forums++; - $forum_id = $row['forum_id']; - - $forum_unread = (isset($forum_tracking_info[$forum_id]) && $row['orig_forum_last_post_time'] > $forum_tracking_info[$forum_id]) ? true : false; - - $folder_image = $folder_alt = $l_subforums = ''; - $subforums_list = array(); - - // Generate list of subforums if we need to - if (isset($subforums[$forum_id])) - { - foreach ($subforums[$forum_id] as $subforum_id => $subforum_row) - { - $subforum_unread = (isset($forum_tracking_info[$subforum_id]) && $subforum_row['orig_forum_last_post_time'] > $forum_tracking_info[$subforum_id]) ? true : false; - - if (!$subforum_unread && !empty($subforum_row['children'])) - { - foreach ($subforum_row['children'] as $child_id) - { - if (isset($forum_tracking_info[$child_id]) && $subforums[$forum_id][$child_id]['orig_forum_last_post_time'] > $forum_tracking_info[$child_id]) - { - // Once we found an unread child forum, we can drop out of this loop - $subforum_unread = true; - break; - } - } - } - - if ($subforum_row['display'] && $subforum_row['name']) - { - $subforums_list[] = array( - 'link' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $subforum_id), - 'name' => $subforum_row['name'], - 'unread' => $subforum_unread, - 'type' => $subforum_row['type'], - ); - } - else - { - unset($subforums[$forum_id][$subforum_id]); - } - - // If one subforum is unread the forum gets unread too... - if ($subforum_unread) - { - $forum_unread = true; - } - } - - $l_subforums = (count($subforums[$forum_id]) == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS']; - $folder_image = ($forum_unread) ? 'forum_unread_subforum' : 'forum_read_subforum'; - } - else - { - switch ($row['forum_type']) - { - case FORUM_POST: - $folder_image = ($forum_unread) ? 'forum_unread' : 'forum_read'; - break; - - case FORUM_LINK: - $folder_image = 'forum_link'; - break; - } - } - - // Which folder should we display? - if ($row['forum_status'] == ITEM_LOCKED) - { - $folder_image = ($forum_unread) ? 'forum_unread_locked' : 'forum_read_locked'; - $folder_alt = 'FORUM_LOCKED'; - } - else - { - $folder_alt = ($forum_unread) ? 'UNREAD_POSTS' : 'NO_UNREAD_POSTS'; - } - - // Create last post link information, if appropriate - if ($row['forum_last_post_id']) - { - if ($row['forum_password_last_post'] === '' && $auth->acl_gets('f_read', 'f_list_topics', $row['forum_id_last_post'])) - { - $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 - { - $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'] . '&p=' . $row['forum_last_post_id']) . '#p' . $row['forum_last_post_id']; - } - else - { - $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 = (count($forum_moderators[$forum_id]) == 1) ? $user->lang['MODERATOR'] : $user->lang['MODERATORS']; - $moderators_list = implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]); - } - - $l_post_click_count = ($row['forum_type'] == FORUM_LINK) ? 'CLICKS' : 'POSTS'; - $post_click_count = ($row['forum_type'] != FORUM_LINK || $row['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? $row['forum_posts'] : ''; - - $s_subforums_list = $subforums_row = array(); - foreach ($subforums_list as $subforum) - { - $s_subforums_list[] = '' . $subforum['name'] . ''; - $subforums_row[] = array( - '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); - $catless = ($row['parent_id'] == $root_data['forum_id']) ? true : false; - - if ($row['forum_type'] != FORUM_LINK) - { - $u_viewforum = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']); - } - else - { - // If the forum is a link and we count redirects we need to visit it - // If the forum is having a password or no read access we do not expose the link, but instead handle it in viewforum - if (($row['forum_flags'] & FORUM_FLAG_LINK_TRACK) || $row['forum_password'] || !$auth->acl_get('f_read', $forum_id)) - { - $u_viewforum = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']); - } - else - { - $u_viewforum = $row['forum_link']; - } - } - - $forum_row = array( - 'S_IS_CAT' => false, - 'S_NO_CAT' => $catless && !$last_catless, - 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK) ? true : false, - 'S_UNREAD_FORUM' => $forum_unread, - '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' => (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, - - 'FORUM_ID' => $row['forum_id'], - 'FORUM_NAME' => $row['forum_name'], - 'FORUM_DESC' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), - 'TOPICS' => $row['forum_topics'], - $l_post_click_count => $post_click_count, - 'FORUM_IMG_STYLE' => $folder_image, - 'FORUM_FOLDER_IMG' => $user->img($folder_image, $folder_alt), - 'FORUM_FOLDER_IMG_ALT' => isset($user->lang[$folder_alt]) ? $user->lang[$folder_alt] : '', - 'FORUM_IMAGE' => ($row['forum_image']) ? '' . $user->lang[$folder_alt] . '' : '', - 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', - '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']), - 'MODERATORS' => $moderators_list, - 'SUBFORUMS' => $s_subforums_list, - - 'L_SUBFORUM_STR' => $l_subforums, - 'L_MODERATOR_STR' => $l_moderator, - - 'U_UNAPPROVED_TOPICS' => ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_topics&f=' . $row['forum_id_unapproved_topics']) : '', - 'U_UNAPPROVED_POSTS' => ($row['forum_id_unapproved_posts']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_posts&f=' . $row['forum_id_unapproved_posts']) : '', - 'U_VIEWFORUM' => $u_viewforum, - 'U_LAST_POSTER' => get_username_string('profile', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']), - 'U_LAST_POST' => $last_post_url, - ); - - /** - * Modify the template data block of the forum - * - * This event is triggered once per forum - * - * @event core.display_forums_modify_template_vars - * @var array forum_row Template data of the forum - * @var array row The data of the forum - * @var array subforums_row Template data of subforums - * @since 3.1.0-a1 - * @changed 3.1.0-b5 Added var subforums_row - */ - $vars = array('forum_row', 'row', 'subforums_row'); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_template_vars', compact($vars))); - - $template->assign_block_vars('forumrow', $forum_row); - - // Assign subforums loop for style authors - $template->assign_block_vars_array('forumrow.subforum', $subforums_row); - - /** - * Modify and/or assign additional template data for the forum - * after forumrow loop has been assigned. This can be used - * to create additional forumrow subloops in extensions. - * - * This event is triggered once per forum - * - * @event core.display_forums_add_template_data - * @var array forum_row Template data of the forum - * @var array row The data of the forum - * @var array subforums_list The data of subforums - * @var array subforums_row Template data of subforums - * @var bool catless The flag indicating whether a forum has a parent category - * @since 3.1.0-b5 - */ - $vars = array( - 'forum_row', - 'row', - 'subforums_list', - 'subforums_row', - 'catless', - ); - extract($phpbb_dispatcher->trigger_event('core.display_forums_add_template_data', compact($vars))); - - $last_catless = $catless; - } - - $template->assign_vars(array( - '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()) : '', - 'S_HAS_SUBFORUM' => ($visible_forums) ? true : false, - 'L_SUBFORUM' => ($visible_forums == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS'], - 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPICS_UNAPPROVED'), - 'UNAPPROVED_POST_IMG' => $user->img('icon_topic_unapproved', 'POSTS_UNAPPROVED_FORUM'), - )); - - /** - * Event to perform additional actions after the forum list has been generated - * - * @event core.display_forums_after - * @var array active_forum_ary Array with forum data to display active topics - * @var bool display_moderators Flag indicating if we display forum moderators - * @var array forum_moderators Array with forum moderators list - * @var array forum_rows Data array of all forums we display - * @var bool return_moderators Flag indicating if moderators list should be returned - * @var array root_data Array with the root forum data - * @since 3.1.0-RC5 - */ - $vars = array( - 'active_forum_ary', - 'display_moderators', - 'forum_moderators', - 'forum_rows', - 'return_moderators', - 'root_data', - ); - extract($phpbb_dispatcher->trigger_event('core.display_forums_after', compact($vars))); - - if ($return_moderators) - { - return array($active_forum_ary, $forum_moderators); - } - - return array($active_forum_ary, array()); -} - -/** -* Create forum rules for given forum -*/ -function generate_forum_rules(&$forum_data) -{ - if ($forum_data['forum_rules']) - { - $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']); - } - - if (!$forum_data['forum_rules'] && !$forum_data['forum_rules_link']) - { - return; - } - - global $template; - - $template->assign_vars(array( - 'S_FORUM_RULES' => true, - 'U_FORUM_RULES' => $forum_data['forum_rules_link'], - 'FORUM_RULES' => $forum_data['forum_rules']) - ); -} - -/** -* 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_ary) -{ - global $template, $auth, $config; - global $phpEx, $phpbb_root_path, $phpbb_dispatcher; - - if (!$auth->acl_get('f_list', $forum_data_ary['forum_id'])) - { - return; - } - - $navlinks_parents = $forum_template_data = array(); - - // Get forum parents - $forum_parents = get_forum_parents($forum_data_ary); - - $microdata_attr = 'data-forum-id'; - - // Build navigation links - if (!empty($forum_parents)) - { - foreach ($forum_parents as $parent_forum_id => $parent_data) - { - list($parent_name, $parent_type) = array_values($parent_data); - - // Skip this parent if the user does not have the permission to view it - if (!$auth->acl_get('f_list', $parent_forum_id)) - { - continue; - } - - $navlinks_parents[] = array( - 'S_IS_CAT' => ($parent_type == FORUM_CAT) ? true : false, - 'S_IS_LINK' => ($parent_type == FORUM_LINK) ? true : false, - 'S_IS_POST' => ($parent_type == FORUM_POST) ? true : false, - 'BREADCRUMB_NAME' => $parent_name, - 'FORUM_ID' => $parent_forum_id, - 'MICRODATA' => $microdata_attr . '="' . $parent_forum_id . '"', - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $parent_forum_id), - ); - } - } - - $navlinks = array( - '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, - 'BREADCRUMB_NAME' => $forum_data_ary['forum_name'], - 'FORUM_ID' => $forum_data_ary['forum_id'], - 'MICRODATA' => $microdata_attr . '="' . $forum_data_ary['forum_id'] . '"', - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_data_ary['forum_id']), - ); - - $forum_template_data = array( - '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_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 - * - * @event core.generate_forum_nav - * @var array forum_data Array with the forum data - * @var array forum_template_data Array with generic forum template data - * @var string microdata_attr The microdata attribute - * @var array navlinks_parents Array with the forum parents navlinks data - * @var array navlinks Array with the forum navlinks data - * @since 3.1.5-RC1 - */ - $vars = array( - 'forum_data', - 'forum_template_data', - 'microdata_attr', - 'navlinks_parents', - '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); - $template->assign_vars($forum_template_data); - - return; -} - -/** -* Returns forum parents as an array. Get them from forum_data if available, or update the database otherwise -*/ -function get_forum_parents(&$forum_data) -{ - global $db; - - $forum_parents = array(); - - if ($forum_data['parent_id'] > 0) - { - if ($forum_data['forum_parents'] == '') - { - $sql = 'SELECT forum_id, forum_name, forum_type - FROM ' . FORUMS_TABLE . ' - WHERE left_id < ' . $forum_data['left_id'] . ' - AND right_id > ' . $forum_data['right_id'] . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_parents[$row['forum_id']] = array($row['forum_name'], (int) $row['forum_type']); - } - $db->sql_freeresult($result); - - $forum_data['forum_parents'] = serialize($forum_parents); - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_parents = '" . $db->sql_escape($forum_data['forum_parents']) . "' - WHERE parent_id = " . $forum_data['parent_id']; - $db->sql_query($sql); - } - else - { - $forum_parents = unserialize($forum_data['forum_parents']); - } - } - - return $forum_parents; -} - -/** -* Obtain list of moderators of each forum -*/ -function get_moderators(&$forum_moderators, $forum_id = false) -{ - global $db, $phpbb_root_path, $phpEx, $user, $auth; - global $phpbb_container; - - $forum_id_ary = array(); - - if ($forum_id !== false) - { - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - // Exchange key/value pair to be able to faster check for the forum id existence - $forum_id_ary = array_flip($forum_id); - } - - $sql_array = array( - 'SELECT' => 'm.*, u.user_colour, g.group_colour, g.group_type', - - 'FROM' => array( - MODERATOR_CACHE_TABLE => 'm', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(USERS_TABLE => 'u'), - 'ON' => 'm.user_id = u.user_id', - ), - array( - 'FROM' => array(GROUPS_TABLE => 'g'), - 'ON' => 'm.group_id = g.group_id', - ), - ), - - '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); - - while ($row = $db->sql_fetchrow($result)) - { - $f_id = (int) $row['forum_id']; - - if (!isset($forum_id_ary[$f_id])) - { - continue; - } - - if (!empty($row['user_id'])) - { - $forum_moderators[$f_id][] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']); - } - else - { - $group_name = $group_helper->get_name($row['group_name']); - - if ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')) - { - $forum_moderators[$f_id][] = '' . $group_name . ''; - } - else - { - $forum_moderators[$f_id][] = '' . $group_name . ''; - } - } - } - $db->sql_freeresult($result); - - return; -} - -/** -* User authorisation levels output -* -* @param string $mode Can be forum or topic. Not in use at the moment. -* @param int $forum_id The current forum the user is in. -* @param int $forum_status The forums status bit. -*/ -function gen_forum_auth_level($mode, $forum_id, $forum_status) -{ - global $template, $auth, $user, $config; - - $locked = ($forum_status == ITEM_LOCKED && !$auth->acl_get('m_edit', $forum_id)) ? true : false; - - $rules = array( - ($auth->acl_get('f_post', $forum_id) && !$locked) ? $user->lang['RULES_POST_CAN'] : $user->lang['RULES_POST_CANNOT'], - ($auth->acl_get('f_reply', $forum_id) && !$locked) ? $user->lang['RULES_REPLY_CAN'] : $user->lang['RULES_REPLY_CANNOT'], - ($user->data['is_registered'] && $auth->acl_gets('f_edit', 'm_edit', $forum_id) && !$locked) ? $user->lang['RULES_EDIT_CAN'] : $user->lang['RULES_EDIT_CANNOT'], - ($user->data['is_registered'] && ($auth->acl_gets('f_delete', 'm_delete', $forum_id) || $auth->acl_gets('f_softdelete', 'm_softdelete', $forum_id)) && !$locked) ? $user->lang['RULES_DELETE_CAN'] : $user->lang['RULES_DELETE_CANNOT'], - ); - - if ($config['allow_attachments']) - { - $rules[] = ($auth->acl_get('f_attach', $forum_id) && $auth->acl_get('u_attach') && !$locked) ? $user->lang['RULES_ATTACH_CAN'] : $user->lang['RULES_ATTACH_CANNOT']; - } - - foreach ($rules as $rule) - { - $template->assign_block_vars('rules', array('RULE' => $rule)); - } - - return; -} - -/** -* Generate topic status -*/ -function topic_status(&$topic_row, $replies, $unread_topic, &$folder_img, &$folder_alt, &$topic_type) -{ - global $user, $config; - - if ($topic_row['topic_status'] == ITEM_MOVED) - { - $topic_type = $user->lang['VIEW_TOPIC_MOVED']; - $folder_img = 'topic_moved'; - $folder_alt = 'TOPIC_MOVED'; - } - else - { - switch ($topic_row['topic_type']) - { - case POST_GLOBAL: - $topic_type = $user->lang['VIEW_TOPIC_GLOBAL']; - $folder = 'global_read'; - $folder_new = 'global_unread'; - break; - - case POST_ANNOUNCE: - $topic_type = $user->lang['VIEW_TOPIC_ANNOUNCEMENT']; - $folder = 'announce_read'; - $folder_new = 'announce_unread'; - break; - - case POST_STICKY: - $topic_type = $user->lang['VIEW_TOPIC_STICKY']; - $folder = 'sticky_read'; - $folder_new = 'sticky_unread'; - break; - - default: - $topic_type = ''; - $folder = 'topic_read'; - $folder_new = 'topic_unread'; - - // Hot topic threshold is for posts in a topic, which is replies + the first post. ;) - if ($config['hot_threshold'] && ($replies + 1) >= $config['hot_threshold'] && $topic_row['topic_status'] != ITEM_LOCKED) - { - $folder .= '_hot'; - $folder_new .= '_hot'; - } - break; - } - - if ($topic_row['topic_status'] == ITEM_LOCKED) - { - $topic_type = $user->lang['VIEW_TOPIC_LOCKED']; - $folder .= '_locked'; - $folder_new .= '_locked'; - } - - $folder_img = ($unread_topic) ? $folder_new : $folder; - $folder_alt = ($unread_topic) ? 'UNREAD_POSTS' : (($topic_row['topic_status'] == ITEM_LOCKED) ? 'TOPIC_LOCKED' : 'NO_UNREAD_POSTS'); - - // Posted image? - if (!empty($topic_row['topic_posted']) && $topic_row['topic_posted']) - { - $folder_img .= '_mine'; - } - } - - if ($topic_row['poll_start'] && $topic_row['topic_status'] != ITEM_MOVED) - { - $topic_type = $user->lang['VIEW_TOPIC_POLL']; - } -} - -/** -* Assign/Build custom bbcodes for display in screens supporting using of bbcodes -* The custom bbcodes buttons will be placed within the template block 'custom_tags' -*/ -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 = NUM_PREDEFINED_BBCODES; - - $sql_ary = array( - 'SELECT' => 'b.bbcode_id, b.bbcode_tag, b.bbcode_helpline', - 'FROM' => array(BBCODES_TABLE => 'b'), - 'WHERE' => 'b.display_on_posting = 1', - 'ORDER_BY' => 'b.bbcode_tag', - ); - - /** - * Event to modify the SQL query before custom bbcode data is queried - * - * @event core.display_custom_bbcodes_modify_sql - * @var array sql_ary The SQL array to get the bbcode data - * @var int num_predefined_bbcodes The number of predefined core bbcodes - * (multiplied by factor of 2) - * @since 3.1.0-a3 - */ - $vars = array('sql_ary', 'num_predefined_bbcodes'); - extract($phpbb_dispatcher->trigger_event('core.display_custom_bbcodes_modify_sql', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - - $i = 0; - while ($row = $db->sql_fetchrow($result)) - { - // If the helpline is defined within the language file, we will use the localised version, else just use the database entry... - if (isset($user->lang[strtoupper($row['bbcode_helpline'])])) - { - $row['bbcode_helpline'] = $user->lang[strtoupper($row['bbcode_helpline'])]; - } - - $custom_tags = array( - 'BBCODE_NAME' => "'[{$row['bbcode_tag']}]', '[/" . str_replace('=', '', $row['bbcode_tag']) . "]'", - 'BBCODE_ID' => $num_predefined_bbcodes + ($i * 2), - 'BBCODE_TAG' => $row['bbcode_tag'], - 'BBCODE_TAG_CLEAN' => str_replace('=', '-', $row['bbcode_tag']), - 'BBCODE_HELPLINE' => $row['bbcode_helpline'], - ); - - /** - * Event to modify the template data block of a custom bbcode - * - * This event is triggered once per bbcode - * - * @event core.display_custom_bbcodes_modify_row - * @var array custom_tags Template data of the bbcode - * @var array row The data of the bbcode - * @since 3.1.0-a1 - */ - $vars = array('custom_tags', 'row'); - extract($phpbb_dispatcher->trigger_event('core.display_custom_bbcodes_modify_row', compact($vars))); - - $template->assign_block_vars('custom_tags', $custom_tags); - - $i++; - } - $db->sql_freeresult($result); - - /** - * Display custom bbcodes - * - * @event core.display_custom_bbcodes - * @since 3.1.0-a1 - */ - $phpbb_dispatcher->dispatch('core.display_custom_bbcodes'); -} - -/** -* Display user activity (action forum/topic) -*/ -function display_user_activity(&$userdata_ary) -{ - global $auth, $template, $db, $user, $config; - global $phpbb_root_path, $phpEx; - global $phpbb_container, $phpbb_dispatcher; - - // 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; - } - - $forum_ary = array(); - - $forum_read_ary = $auth->acl_getf('f_read'); - foreach ($forum_read_ary as $forum_id => $allowed) - { - if ($allowed['f_read']) - { - $forum_ary[] = (int) $forum_id; - } - } - - $forum_ary = array_diff($forum_ary, $user->get_passworded_forums()); - - $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_ary['user_id'] . ' - AND post_postcount = 1 - AND ' . $phpbb_content_visibility->get_forums_visibility_sql('post', $forum_ary) . ' - GROUP BY forum_id - ORDER BY num_posts DESC'; - $result = $db->sql_query_limit($sql, 1); - $active_f_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!empty($active_f_row)) - { - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $active_f_row['forum_id']; - $result = $db->sql_query($sql, 3600); - $active_f_row['forum_name'] = (string) $db->sql_fetchfield('forum_name'); - $db->sql_freeresult($result); - } - - // Obtain active topic - $sql = 'SELECT topic_id, COUNT(post_id) AS num_posts - FROM ' . POSTS_TABLE . ' - 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 - ORDER BY num_posts DESC'; - $result = $db->sql_query_limit($sql, 1); - $active_t_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!empty($active_t_row)) - { - $sql = 'SELECT topic_title - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $active_t_row['topic_id']; - $result = $db->sql_query($sql); - $active_t_row['topic_title'] = (string) $db->sql_fetchfield('topic_title'); - $db->sql_freeresult($result); - } - } - - $userdata = $userdata_ary; - $show_user_activity = true; - /** - * Alter list of forums and topics to display as active - * - * @event core.display_user_activity_modify_actives - * @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', 'show_user_activity'); - extract($phpbb_dispatcher->trigger_event('core.display_user_activity_modify_actives', compact($vars))); - $userdata_ary = $userdata; - unset($userdata); - - $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'])) - { - $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_ary['user_posts']) ? ($active_f_count / $userdata_ary['user_posts']) * 100 : 0; - } - - $active_t_name = $active_t_id = $active_t_count = $active_t_pct = ''; - if (!empty($active_t_row['num_posts'])) - { - $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_ary['user_posts']) ? ($active_t_count / $userdata_ary['user_posts']) * 100 : 0; - } - - $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, - 'ACTIVE_FORUM_POSTS' => $user->lang('USER_POSTS', (int) $active_f_count), - 'ACTIVE_FORUM_PCT' => sprintf($l_active_pct, $active_f_pct), - 'ACTIVE_TOPIC' => censor_text($active_t_name), - 'ACTIVE_TOPIC_POSTS' => $user->lang('USER_POSTS', (int) $active_t_count), - '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' => $show_user_activity) - ); -} - -/** -* Topic and forum watching common code -*/ -function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $notify_status = 'unset', $start = 0, $item_title = '') -{ - global $db, $user, $phpEx, $start, $phpbb_root_path; - global $request; - - $table_sql = ($mode == 'forum') ? FORUMS_WATCH_TABLE : TOPICS_WATCH_TABLE; - $where_sql = ($mode == 'forum') ? 'forum_id' : 'topic_id'; - $match_id = ($mode == 'forum') ? $forum_id : $topic_id; - $u_url = "uid={$user->data['user_id']}"; - $u_url .= ($mode == 'forum') ? '&f' : '&f=' . $forum_id . '&t'; - $is_watching = 0; - - // Is user watching this topic? - if ($user_id != ANONYMOUS) - { - $can_watch = true; - - if ($notify_status == 'unset') - { - $sql = "SELECT notify_status - FROM $table_sql - WHERE $where_sql = $match_id - AND user_id = $user_id"; - $result = $db->sql_query($sql); - - $notify_status = ($row = $db->sql_fetchrow($result)) ? $row['notify_status'] : NULL; - $db->sql_freeresult($result); - } - - if (!is_null($notify_status) && $notify_status !== '') - { - if (isset($_GET['unwatch'])) - { - $uid = $request->variable('uid', 0); - $token = $request->variable('hash', ''); - - if ($token && check_link_hash($token, "{$mode}_$match_id") || confirm_box(true)) - { - if ($uid != $user_id || $request->variable('unwatch', '', false, \phpbb\request\request_interface::GET) != $mode) - { - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ERR_UNWATCHING']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_' . strtoupper($mode), '', ''); - } - trigger_error($message); - } - - $sql = 'DELETE FROM ' . $table_sql . " - WHERE $where_sql = $match_id - AND user_id = $user_id"; - $db->sql_query($sql); - - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['NOT_WATCHING_' . strtoupper($mode)]; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_' . strtoupper($mode), '', ''); - } - meta_refresh(3, $redirect_url); - trigger_error($message); - } - else - { - $s_hidden_fields = array( - 'uid' => $user->data['user_id'], - 'unwatch' => $mode, - 'start' => $start, - 'f' => $forum_id, - ); - if ($mode != 'forum') - { - $s_hidden_fields['t'] = $topic_id; - } - - if ($item_title == '') - { - $confirm_box_message = 'UNWATCH_' . strtoupper($mode); - } - else - { - $confirm_box_message = $user->lang('UNWATCH_' . strtoupper($mode) . '_DETAILED', $item_title); - } - confirm_box(false, $confirm_box_message, build_hidden_fields($s_hidden_fields)); - } - } - else - { - $is_watching = true; - - if ($notify_status != NOTIFY_YES) - { - $sql = 'UPDATE ' . $table_sql . " - SET notify_status = " . NOTIFY_YES . " - WHERE $where_sql = $match_id - AND user_id = $user_id"; - $db->sql_query($sql); - } - } - } - else - { - if (isset($_GET['watch'])) - { - $uid = $request->variable('uid', 0); - $token = $request->variable('hash', ''); - - if ($token && check_link_hash($token, "{$mode}_$match_id") || confirm_box(true)) - { - if ($uid != $user_id || $request->variable('watch', '', false, \phpbb\request\request_interface::GET) != $mode) - { - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ERR_WATCHING']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_' . strtoupper($mode), '', ''); - } - trigger_error($message); - } - - $is_watching = true; - - $sql = 'INSERT INTO ' . $table_sql . " (user_id, $where_sql, notify_status) - VALUES ($user_id, $match_id, " . NOTIFY_YES . ')'; - $db->sql_query($sql); - - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ARE_WATCHING_' . strtoupper($mode)]; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_' . strtoupper($mode), '', ''); - } - meta_refresh(3, $redirect_url); - trigger_error($message); - } - else - { - $s_hidden_fields = array( - 'uid' => $user->data['user_id'], - 'watch' => $mode, - 'start' => $start, - 'f' => $forum_id, - ); - if ($mode != 'forum') - { - $s_hidden_fields['t'] = $topic_id; - } - - $confirm_box_message = (($item_title == '') ? 'WATCH_' . strtoupper($mode) : $user->lang('WATCH_' . strtoupper($mode) . '_DETAILED', $item_title)); - confirm_box(false, $confirm_box_message, build_hidden_fields($s_hidden_fields)); - } - } - else - { - $is_watching = 0; - } - } - } - else - { - if ((isset($_GET['unwatch']) && $request->variable('unwatch', '', false, \phpbb\request\request_interface::GET) == $mode) || - (isset($_GET['watch']) && $request->variable('watch', '', false, \phpbb\request\request_interface::GET) == $mode)) - { - login_box(); - } - else - { - $can_watch = 0; - $is_watching = 0; - } - } - - if ($can_watch) - { - $s_watching['link'] = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&" . (($is_watching) ? 'unwatch' : 'watch') . "=$mode&start=$start&hash=" . generate_link_hash("{$mode}_$match_id")); - $s_watching['link_toggle'] = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&" . ((!$is_watching) ? 'unwatch' : 'watch') . "=$mode&start=$start&hash=" . generate_link_hash("{$mode}_$match_id")); - $s_watching['title'] = $user->lang[(($is_watching) ? 'STOP' : 'START') . '_WATCHING_' . strtoupper($mode)]; - $s_watching['title_toggle'] = $user->lang[((!$is_watching) ? 'STOP' : 'START') . '_WATCHING_' . strtoupper($mode)]; - $s_watching['is_watching'] = $is_watching; - } - - return; -} - -/** -* Get user rank title and image -* -* @param array $user_data the current stored users data -* @param int $user_posts the users number of posts -* -* @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) -* -* Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false -*/ -function phpbb_get_user_rank($user_data, $user_posts) -{ - global $ranks, $config, $phpbb_root_path, $phpbb_path_helper, $phpbb_dispatcher; - - $user_rank_data = array( - 'title' => null, - 'img' => null, - 'img_src' => null, - ); - - /** - * Preparing a user's rank before displaying - * - * @event core.modify_user_rank - * @var array user_data Array with user's data - * @var int user_posts User_posts to change - * @since 3.1.0-RC4 - */ - - $vars = array('user_data', 'user_posts'); - extract($phpbb_dispatcher->trigger_event('core.modify_user_rank', compact($vars))); - - if (empty($ranks)) - { - global $cache; - $ranks = $cache->obtain_ranks(); - } - - if (!empty($user_data['user_rank'])) - { - - $user_rank_data['title'] = (isset($ranks['special'][$user_data['user_rank']]['rank_title'])) ? $ranks['special'][$user_data['user_rank']]['rank_title'] : ''; - - $user_rank_data['img_src'] = (!empty($ranks['special'][$user_data['user_rank']]['rank_image'])) ? $phpbb_path_helper->update_web_root_path($phpbb_root_path . $config['ranks_path'] . '/' . $ranks['special'][$user_data['user_rank']]['rank_image']) : ''; - - $user_rank_data['img'] = (!empty($ranks['special'][$user_data['user_rank']]['rank_image'])) ? '' . $ranks['special'][$user_data['user_rank']]['rank_title'] . '' : ''; - } - else if ($user_posts !== false) - { - if (!empty($ranks['normal'])) - { - foreach ($ranks['normal'] as $rank) - { - if ($user_posts >= $rank['rank_min']) - { - $user_rank_data['title'] = $rank['rank_title']; - $user_rank_data['img_src'] = (!empty($rank['rank_image'])) ? $phpbb_path_helper->update_web_root_path($phpbb_root_path . $config['ranks_path'] . '/' . $rank['rank_image']) : ''; - $user_rank_data['img'] = (!empty($rank['rank_image'])) ? '' . $rank['rank_title'] . '' : ''; - break; - } - } - } - } - - /** - * Modify a user's rank before displaying - * - * @event core.get_user_rank_after - * @var array user_data Array with user's data - * @var int user_posts User_posts to change - * @var array user_rank_data User rank data - * @since 3.1.11-RC1 - */ - - $vars = array( - 'user_data', - 'user_posts', - 'user_rank_data', - ); - extract($phpbb_dispatcher->trigger_event('core.get_user_rank_after', compact($vars))); - - return $user_rank_data; -} - -/** -* Prepare profile data -*/ -function phpbb_show_profile($data, $user_notes_enabled = false, $warn_user_enabled = false, $check_can_receive_pm = true) -{ - global $config, $auth, $user, $phpEx, $phpbb_root_path, $phpbb_dispatcher; - - $username = $data['username']; - $user_id = $data['user_id']; - - $user_rank_data = phpbb_get_user_rank($data, (($user_id == ANONYMOUS) ? false : $data['user_posts'])); - - if ((!empty($data['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_user')) - { - $email = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=email&u=' . $user_id) : (($config['board_hide_emails'] && !$auth->acl_get('a_user')) ? '' : 'mailto:' . $data['user_email']); - } - else - { - $email = ''; - } - - if ($config['load_onlinetrack']) - { - $update_time = $config['load_online_time'] * 60; - $online = (time() - $update_time < $data['session_time'] && ((isset($data['session_viewonline']) && $data['session_viewonline']) || $auth->acl_get('u_viewonline'))) ? true : false; - } - else - { - $online = false; - } - - if ($data['user_allow_viewonline'] || $auth->acl_get('u_viewonline')) - { - $last_active = (!empty($data['session_time'])) ? $data['session_time'] : $data['user_lastvisit']; - } - else - { - $last_active = ''; - } - - $age = ''; - - if ($config['allow_birthdays'] && $data['user_birthday']) - { - list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $data['user_birthday'])); - - if ($bday_year) - { - $now = $user->create_datetime(); - $now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset()); - - $diff = $now['mon'] - $bday_month; - if ($diff == 0) - { - $diff = ($now['mday'] - $bday_day < 0) ? 1 : 0; - } - else - { - $diff = ($diff < 0) ? 1 : 0; - } - - $age = max(0, (int) ($now['year'] - $bday_year - $diff)); - } - } - - if (!function_exists('phpbb_get_banned_user_ids')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - // Can this user receive a Private Message? - $can_receive_pm = $check_can_receive_pm && ( - // They must be a "normal" user - $data['user_type'] != USER_IGNORE && - - // They must not be deactivated by the administrator - ($data['user_type'] != USER_INACTIVE || $data['user_inactive_reason'] != INACTIVE_MANUAL) && - - // They must be able to read PMs - count($auth->acl_get_list($user_id, 'u_readpm')) && - - // They must not be permanently banned - !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']) - ); - - // Dump it out to the template - $template_data = array( - 'AGE' => $age, - 'RANK_TITLE' => $user_rank_data['title'], - 'JOINED' => $user->format_date($data['user_regdate']), - 'LAST_ACTIVE' => (empty($last_active)) ? ' - ' : $user->format_date($last_active), - 'POSTS' => ($data['user_posts']) ? $data['user_posts'] : 0, - 'WARNINGS' => isset($data['user_warnings']) ? $data['user_warnings'] : 0, - - 'USERNAME_FULL' => get_username_string('full', $user_id, $username, $data['user_colour']), - 'USERNAME' => get_username_string('username', $user_id, $username, $data['user_colour']), - 'USER_COLOR' => get_username_string('colour', $user_id, $username, $data['user_colour']), - 'U_VIEW_PROFILE' => get_username_string('profile', $user_id, $username, $data['user_colour']), - - 'A_USERNAME' => addslashes(get_username_string('username', $user_id, $username, $data['user_colour'])), - - 'AVATAR_IMG' => phpbb_get_user_avatar($data), - 'ONLINE_IMG' => (!$config['load_onlinetrack']) ? '' : (($online) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')), - 'S_ONLINE' => ($config['load_onlinetrack'] && $online) ? true : false, - 'RANK_IMG' => $user_rank_data['img'], - 'RANK_IMG_SRC' => $user_rank_data['img_src'], - 'S_JABBER_ENABLED' => ($config['jab_enable']) ? true : false, - - 'S_WARNINGS' => ($auth->acl_getf_global('m_') || $auth->acl_get('m_warn')) ? true : false, - - 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$user_id&sr=posts") : '', - 'U_NOTES' => ($user_notes_enabled && $auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $user_id, true, $user->session_id) : '', - 'U_WARN' => ($warn_user_enabled && $auth->acl_get('m_warn')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $user_id, true, $user->session_id) : '', - 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $user_id) : '', - 'U_EMAIL' => $email, - 'U_JABBER' => ($data['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=jabber&u=' . $user_id) : '', - - 'USER_JABBER' => ($config['jab_enable']) ? $data['user_jabber'] : '', - 'USER_JABBER_IMG' => ($config['jab_enable'] && $data['user_jabber']) ? $user->img('icon_contact_jabber', $data['user_jabber']) : '', - - 'L_SEND_EMAIL_USER' => $user->lang('SEND_EMAIL_USER', $username), - 'L_CONTACT_USER' => $user->lang('CONTACT_USER', $username), - 'L_VIEWING_PROFILE' => $user->lang('VIEWING_PROFILE', $username), - ); - - /** - * Preparing a user's data before displaying it in profile and memberlist - * - * @event core.memberlist_prepare_profile_data - * @var array data Array with user's data - * @var array template_data Template array with user's data - * @since 3.1.0-a1 - */ - $vars = array('data', 'template_data'); - extract($phpbb_dispatcher->trigger_event('core.memberlist_prepare_profile_data', compact($vars))); - - return $template_data; -} - -function phpbb_sort_last_active($first, $second) -{ - global $id_cache, $sort_dir; - - $lesser_than = ($sort_dir === 'd') ? -1 : 1; - - if (isset($id_cache[$first]['group_leader']) && $id_cache[$first]['group_leader'] && (!isset($id_cache[$second]['group_leader']) || !$id_cache[$second]['group_leader'])) - { - return -1; - } - else if (isset($id_cache[$second]['group_leader']) && (!isset($id_cache[$first]['group_leader']) || !$id_cache[$first]['group_leader']) && $id_cache[$second]['group_leader']) - { - return 1; - } - else - { - return $lesser_than * (int) ($id_cache[$first]['last_visit'] - $id_cache[$second]['last_visit']); - } -} diff --git a/install/update/new/includes/functions_download.php b/install/update/new/includes/functions_download.php deleted file mode 100644 index d2d3924..0000000 --- a/install/update/new/includes/functions_download.php +++ /dev/null @@ -1,782 +0,0 @@ - -* @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 simplified function to deliver avatars -* The argument needs to be checked before calling this function. -*/ -function send_avatar_to_browser($file, $browser) -{ - global $config, $phpbb_root_path; - - $prefix = $config['avatar_salt'] . '_'; - $image_dir = $config['avatar_path']; - - // Adjust image_dir path (no trailing slash) - if (substr($image_dir, -1, 1) == '/' || substr($image_dir, -1, 1) == '\\') - { - $image_dir = substr($image_dir, 0, -1) . '/'; - } - $image_dir = str_replace(array('../', '..\\', './', '.\\'), '', $image_dir); - - if ($image_dir && ($image_dir[0] == '/' || $image_dir[0] == '\\')) - { - $image_dir = ''; - } - $file_path = $phpbb_root_path . $image_dir . '/' . $prefix . $file; - - if ((@file_exists($file_path) && @is_readable($file_path)) && !headers_sent()) - { - header('Cache-Control: public'); - - $image_data = @getimagesize($file_path); - header('Content-Type: ' . image_type_to_mime_type($image_data[2])); - - if ((strpos(strtolower($browser), 'msie') !== false) && !phpbb_is_greater_ie_version($browser, 7)) - { - header('Content-Disposition: attachment; ' . header_filename($file)); - - if (strpos(strtolower($browser), 'msie 6.0') !== false) - { - header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); - } - else - { - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); - } - } - else - { - header('Content-Disposition: inline; ' . header_filename($file)); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); - } - - $size = @filesize($file_path); - if ($size) - { - header("Content-Length: $size"); - } - - if (@readfile($file_path) == false) - { - $fp = @fopen($file_path, 'rb'); - - if ($fp !== false) - { - while (!feof($fp)) - { - echo fread($fp, 8192); - } - fclose($fp); - } - } - - flush(); - } - else - { - header('HTTP/1.0 404 Not Found'); - } -} - -/** -* Wraps an url into a simple html page. Used to display attachments in IE. -* this is a workaround for now; might be moved to template system later -* direct any complaints to 1 Microsoft Way, Redmond -*/ -function wrap_img_in_html($src, $title) -{ - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '' . $title . ''; - echo ''; - echo ''; - echo '
'; - echo '' . $title . ''; - echo '
'; - echo ''; - echo ''; -} - -/** -* Send file to browser -*/ -function send_file_to_browser($attachment, $upload_dir, $category) -{ - global $user, $db, $phpbb_dispatcher, $phpbb_root_path, $request; - - $filename = $phpbb_root_path . $upload_dir . '/' . $attachment['physical_filename']; - - if (!@file_exists($filename)) - { - send_status_line(404, 'Not Found'); - trigger_error('ERROR_NO_ATTACHMENT'); - } - - // Correct the mime type - we force application/octetstream for all files, except images - // Please do not change this, it is a security precaution - if ($category != ATTACHMENT_CATEGORY_IMAGE || strpos($attachment['mimetype'], 'image') !== 0) - { - $attachment['mimetype'] = (strpos(strtolower($user->browser), 'msie') !== false || strpos(strtolower($user->browser), 'opera') !== false) ? 'application/octetstream' : 'application/octet-stream'; - } - - if (@ob_get_length()) - { - @ob_end_clean(); - } - - // Now send the File Contents to the Browser - $size = @filesize($filename); - - /** - * Event to alter attachment before it is sent to browser. - * - * @event core.send_file_to_browser_before - * @var array attachment Attachment data - * @var string upload_dir Relative path of upload directory - * @var int category Attachment category - * @var string filename Path to file, including filename - * @var int size File size - * @since 3.1.11-RC1 - */ - $vars = array( - 'attachment', - 'upload_dir', - 'category', - 'filename', - 'size', - ); - extract($phpbb_dispatcher->trigger_event('core.send_file_to_browser_before', compact($vars))); - - // To correctly display further errors we need to make sure we are using the correct headers for both (unsetting content-length may not work) - - // Check if headers already sent or not able to get the file contents. - if (headers_sent() || !@file_exists($filename) || !@is_readable($filename)) - { - // PHP track_errors setting On? - if (!empty($php_errormsg)) - { - send_status_line(500, 'Internal Server Error'); - trigger_error($user->lang['UNABLE_TO_DELIVER_FILE'] . '
' . sprintf($user->lang['TRACKED_PHP_ERROR'], $php_errormsg)); - } - - send_status_line(500, 'Internal Server Error'); - trigger_error('UNABLE_TO_DELIVER_FILE'); - } - - // Make sure the database record for the filesize is correct - if ($size > 0 && $size != $attachment['filesize'] && strpos($attachment['physical_filename'], 'thumb_') === false) - { - // Update database record - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET filesize = ' . (int) $size . ' - WHERE attach_id = ' . (int) $attachment['attach_id']; - $db->sql_query($sql); - } - - // Now the tricky part... let's dance - 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']); - - if (phpbb_is_greater_ie_version($user->browser, 7)) - { - header('X-Content-Type-Options: nosniff'); - } - - if (empty($user->browser) || ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7))) - { - header('Content-Disposition: attachment; ' . header_filename(htmlspecialchars_decode($attachment['real_filename']))); - if (empty($user->browser) || (strpos(strtolower($user->browser), 'msie 6.0') !== false)) - { - header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); - } - } - else - { - header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(htmlspecialchars_decode($attachment['real_filename']))); - if (phpbb_is_greater_ie_version($user->browser, 7) && (strpos($attachment['mimetype'], 'image') !== 0)) - { - header('X-Download-Options: noopen'); - } - } - - // Close the db connection before sending the file etc. - file_gc(false); - - if (!set_modified_headers($attachment['filetime'], $user->browser)) - { - // We make sure those have to be enabled manually by defining a constant - // because of the potential disclosure of full attachment path - // in case support for features is absent in the webserver software. - if (defined('PHPBB_ENABLE_X_ACCEL_REDIRECT') && PHPBB_ENABLE_X_ACCEL_REDIRECT) - { - // X-Accel-Redirect - http://wiki.nginx.org/XSendfile - header('X-Accel-Redirect: ' . $user->page['root_script_path'] . $upload_dir . '/' . $attachment['physical_filename']); - exit; - } - else if (defined('PHPBB_ENABLE_X_SENDFILE') && PHPBB_ENABLE_X_SENDFILE && !phpbb_http_byte_range($size)) - { - // X-Sendfile - http://blog.lighttpd.net/articles/2006/07/02/x-sendfile - // Lighttpd's X-Sendfile does not support range requests as of 1.4.26 - // and always requires an absolute path. - header('X-Sendfile: ' . dirname(__FILE__) . "/../$upload_dir/{$attachment['physical_filename']}"); - exit; - } - - if ($size) - { - header("Content-Length: $size"); - } - - // Try to deliver in chunks - @set_time_limit(0); - - $fp = @fopen($filename, 'rb'); - - if ($fp !== false) - { - // Deliver file partially if requested - if ($range = phpbb_http_byte_range($size)) - { - fseek($fp, $range['byte_pos_start']); - - 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']); - - // 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 - { - while (!feof($fp)) - { - echo fread($fp, 8192); - } - } - fclose($fp); - } - else - { - @readfile($filename); - } - - flush(); - } - - exit; -} - -/** -* Get a browser friendly UTF-8 encoded filename -*/ -function header_filename($file) -{ - global $request; - - $user_agent = $request->header('User-Agent'); - - // There be dragons here. - // Not many follows the RFC... - if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Konqueror') !== false) - { - return "filename=" . rawurlencode($file); - } - - // follow the RFC for extended filename for the rest - return "filename*=UTF-8''" . rawurlencode($file); -} - -/** -* Check if downloading item is allowed -*/ -function download_allowed() -{ - global $config, $user, $db, $request; - - if (!$config['secure_downloads']) - { - return true; - } - - $url = htmlspecialchars_decode($request->header('Referer')); - - if (!$url) - { - return ($config['secure_allow_empty_referer']) ? true : false; - } - - // Split URL into domain and script part - $url = @parse_url($url); - - if ($url === false) - { - return ($config['secure_allow_empty_referer']) ? true : false; - } - - $hostname = $url['host']; - unset($url); - - $allowed = ($config['secure_allow_deny']) ? false : true; - $iplist = array(); - - if (($ip_ary = @gethostbynamel($hostname)) !== false) - { - foreach ($ip_ary as $ip) - { - if ($ip) - { - $iplist[] = $ip; - } - } - } - - // Check for own server... - $server_name = $user->host; - - // Forcing server vars is the only way to specify/override the protocol - if ($config['force_server_vars'] || !$server_name) - { - $server_name = $config['server_name']; - } - - if (preg_match('#^.*?' . preg_quote($server_name, '#') . '.*?$#i', $hostname)) - { - $allowed = true; - } - - // Get IP's and Hostnames - if (!$allowed) - { - $sql = 'SELECT site_ip, site_hostname, ip_exclude - FROM ' . SITELIST_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $site_ip = trim($row['site_ip']); - $site_hostname = trim($row['site_hostname']); - - if ($site_ip) - { - foreach ($iplist as $ip) - { - if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_ip, '#')) . '$#i', $ip)) - { - if ($row['ip_exclude']) - { - $allowed = ($config['secure_allow_deny']) ? false : true; - break 2; - } - else - { - $allowed = ($config['secure_allow_deny']) ? true : false; - } - } - } - } - - if ($site_hostname) - { - if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_hostname, '#')) . '$#i', $hostname)) - { - if ($row['ip_exclude']) - { - $allowed = ($config['secure_allow_deny']) ? false : true; - break; - } - else - { - $allowed = ($config['secure_allow_deny']) ? true : false; - } - } - } - } - $db->sql_freeresult($result); - } - - return $allowed; -} - -/** -* Check if the browser has the file already and set the appropriate headers- -* @returns false if a resend is in order. -*/ -function set_modified_headers($stamp, $browser) -{ - global $request; - - // let's see if we have to send the file at all - $last_load = $request->header('If-Modified-Since') ? strtotime(trim($request->header('If-Modified-Since'))) : false; - - if (strpos(strtolower($browser), 'msie 6.0') === false && !phpbb_is_greater_ie_version($browser, 7)) - { - if ($last_load !== false && $last_load >= $stamp) - { - send_status_line(304, 'Not Modified'); - // seems that we need those too ... browsers - header('Cache-Control: private'); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); - return true; - } - else - { - header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT'); - } - } - return false; -} - -/** -* Garbage Collection -* -* @param bool $exit Whether to die or not. -* -* @return null -*/ -function file_gc($exit = true) -{ - global $cache, $db; - - if (!empty($cache)) - { - $cache->unload(); - } - - $db->sql_close(); - - if ($exit) - { - exit; - } -} - -/** -* HTTP range support (RFC 2616 Section 14.35) -* -* Allows browsers to request partial file content -* in case a download has been interrupted. -* -* @param int $filesize the size of the file in bytes we are about to deliver -* -* @return mixed false if the whole file has to be delivered -* associative array on success -*/ -function phpbb_http_byte_range($filesize) -{ - // Only call find_range_request() once. - static $request_array; - - if (!$filesize) - { - return false; - } - - if (!isset($request_array)) - { - $request_array = phpbb_find_range_request(); - } - - return (empty($request_array)) ? false : phpbb_parse_range_request($request_array, $filesize); -} - -/** -* Searches for HTTP range request in request headers. -* -* @return mixed false if no request found -* array of strings containing the requested ranges otherwise -* e.g. array(0 => '0-0', 1 => '123-125') -*/ -function phpbb_find_range_request() -{ - global $request; - - $value = $request->header('Range'); - - // Make sure range request starts with "bytes=" - if (strpos($value, 'bytes=') === 0) - { - // Strip leading 'bytes=' - // Multiple ranges can be separated by a comma - return explode(',', substr($value, 6)); - } - - return false; -} - -/** -* Analyses a range request array. -* -* A range request can contain multiple ranges, -* we however only handle the first request and -* only support requests from a given byte to the end of the file. -* -* @param array $request_array array of strings containing the requested ranges -* @param int $filesize the full size of the file in bytes that has been requested -* -* @return mixed false if the whole file has to be delivered -* associative array on success -* byte_pos_start the first byte position, can be passed to fseek() -* byte_pos_end the last byte position -* bytes_requested the number of bytes requested -* bytes_total the full size of the file -*/ -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 (count($range) != 2 || $range[0] === '' && $range[1] === '') - { - continue; - } - - // Substitute defaults - if ($range[0] === '') - { - $range[0] = 0; - } - - if ($range[1] === '') - { - $range[1] = $filesize - 1; - } - - if ($last_byte_pos >= 0 && $last_byte_pos + 1 != $range[0]) - { - // We only support contiguous ranges, no multipart stuff :( - return false; - } - - if ($range[1] && $range[1] < $range[0]) - { - // 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 ($first_byte_pos >= $filesize) - { - // Requested range not satisfiable - return false; - } - - // 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 < 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, - ); -} - -/** -* Increments the download count of all provided attachments -* -* @param \phpbb\db\driver\driver_interface $db The database object -* @param array|int $ids The attach_id of each attachment -* -* @return null -*/ -function phpbb_increment_downloads($db, $ids) -{ - if (!is_array($ids)) - { - $ids = array($ids); - } - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET download_count = download_count + 1 - WHERE ' . $db->sql_in_set('attach_id', $ids); - $db->sql_query($sql); -} - -/** -* Handles authentication when downloading attachments from a post or topic -* -* @param \phpbb\db\driver\driver_interface $db The database object -* @param \phpbb\auth\auth $auth The authentication object -* @param int $topic_id The id of the topic that we are downloading from -* -* @return null -*/ -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( - TOPICS_TABLE => 't', - FORUMS_TABLE => 'f', - ), - 'WHERE' => 't.topic_id = ' . (int) $topic_id . ' - AND t.forum_id = f.forum_id', - ); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $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'); - } - else if ($row && $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id'])) - { - if ($row['forum_password']) - { - // Do something else ... ? - login_forum_box($row); - } - } - else - { - send_status_line(403, 'Forbidden'); - trigger_error('SORRY_AUTH_VIEW_ATTACH'); - } -} - -/** -* Handles authentication when downloading attachments from PMs -* -* @param \phpbb\db\driver\driver_interface $db The database object -* @param \phpbb\auth\auth $auth The authentication object -* @param int $user_id The user id -* @param int $msg_id The id of the PM that we are downloading from -* -* @return null -*/ -function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id) -{ - global $phpbb_dispatcher; - - if (!$auth->acl_get('u_pm_download')) - { - send_status_line(403, 'Forbidden'); - trigger_error('SORRY_AUTH_VIEW_ATTACH'); - } - - $allowed = phpbb_download_check_pm_auth($db, $user_id, $msg_id); - - /** - * Event to modify PM attachments download auth - * - * @event core.modify_pm_attach_download_auth - * @var bool allowed Whether the user is allowed to download from that PM or not - * @var int msg_id The id of the PM to download from - * @var int user_id The user id for auth check - * @since 3.1.11-RC1 - */ - $vars = array('allowed', 'msg_id', 'user_id'); - extract($phpbb_dispatcher->trigger_event('core.modify_pm_attach_download_auth', compact($vars))); - - if (!$allowed) - { - send_status_line(403, 'Forbidden'); - trigger_error('ERROR_NO_ATTACHMENT'); - } -} - -/** -* Checks whether a user can download from a particular PM -* -* @param \phpbb\db\driver\driver_interface $db The database object -* @param int $user_id The user id -* @param int $msg_id The id of the PM that we are downloading from -* -* @return bool Whether the user is allowed to download from that PM or not -*/ -function phpbb_download_check_pm_auth($db, $user_id, $msg_id) -{ - // Check if the attachment is within the users scope... - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE msg_id = ' . (int) $msg_id . ' - AND ( - user_id = ' . (int) $user_id . ' - OR author_id = ' . (int) $user_id . ' - )'; - $result = $db->sql_query_limit($sql, 1); - $allowed = (bool) $db->sql_fetchfield('msg_id'); - $db->sql_freeresult($result); - - return $allowed; -} - -/** -* Check if the browser is internet explorer version 7+ -* -* @param string $user_agent User agent HTTP header -* @param int $version IE version to check against -* -* @return bool true if internet explorer version is greater than $version -*/ -function phpbb_is_greater_ie_version($user_agent, $version) -{ - if (preg_match('/msie (\d+)/', strtolower($user_agent), $matches)) - { - $ie_version = (int) $matches[1]; - return ($ie_version > $version); - } - else - { - return false; - } -} diff --git a/install/update/new/includes/functions_messenger.php b/install/update/new/includes/functions_messenger.php deleted file mode 100644 index ec297b5..0000000 --- a/install/update/new/includes/functions_messenger.php +++ /dev/null @@ -1,1935 +0,0 @@ - -* @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; -} - -/** -* Messenger -*/ -class messenger -{ - var $msg, $replyto, $from, $subject; - var $addresses = array(); - var $extra_headers = array(); - - var $mail_priority = MAIL_NORMAL_PRIORITY; - var $use_queue = true; - - /** @var \phpbb\template\template */ - protected $template; - - /** - * Constructor - */ - function __construct($use_queue = true) - { - global $config; - - $this->use_queue = (!$config['email_package_size']) ? false : $use_queue; - $this->subject = ''; - } - - /** - * Resets all the data (address, template file, etc etc) to default - */ - function reset() - { - $this->addresses = $this->extra_headers = array(); - $this->msg = $this->replyto = $this->from = ''; - $this->mail_priority = MAIL_NORMAL_PRIORITY; - } - - /** - * Set addresses for to/im as available - * - * @param array $user User row - */ - function set_addresses($user) - { - if (isset($user['user_email']) && $user['user_email']) - { - $this->to($user['user_email'], (isset($user['username']) ? $user['username'] : '')); - } - - if (isset($user['user_jabber']) && $user['user_jabber']) - { - $this->im($user['user_jabber'], (isset($user['username']) ? $user['username'] : '')); - } - } - - /** - * Sets an email address to send to - */ - function to($address, $realname = '') - { - global $config; - - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['to']) ? count($this->addresses['to']) : 0; - - $this->addresses['to'][$pos]['email'] = trim($address); - - // If empty sendmail_path on windows, PHP changes the to line - if (!$config['smtp_delivery'] && DIRECTORY_SEPARATOR == '\\') - { - $this->addresses['to'][$pos]['name'] = ''; - } - else - { - $this->addresses['to'][$pos]['name'] = trim($realname); - } - } - - /** - * Sets an cc address to send to - */ - function cc($address, $realname = '') - { - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['cc']) ? count($this->addresses['cc']) : 0; - $this->addresses['cc'][$pos]['email'] = trim($address); - $this->addresses['cc'][$pos]['name'] = trim($realname); - } - - /** - * Sets an bcc address to send to - */ - function bcc($address, $realname = '') - { - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['bcc']) ? count($this->addresses['bcc']) : 0; - $this->addresses['bcc'][$pos]['email'] = trim($address); - $this->addresses['bcc'][$pos]['name'] = trim($realname); - } - - /** - * Sets a im contact to send to - */ - function im($address, $realname = '') - { - // IM-Addresses could be empty - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['im']) ? count($this->addresses['im']) : 0; - $this->addresses['im'][$pos]['uid'] = trim($address); - $this->addresses['im'][$pos]['name'] = trim($realname); - } - - /** - * Set the reply to address - */ - function replyto($address) - { - $this->replyto = trim($address); - } - - /** - * Set the from address - */ - function from($address) - { - $this->from = trim($address); - } - - /** - * set up subject for mail - */ - function subject($subject = '') - { - $this->subject = trim($subject); - } - - /** - * set up extra mail headers - */ - function headers($headers) - { - $this->extra_headers[] = trim($headers); - } - - /** - * Adds X-AntiAbuse headers - * - * @param \phpbb\config\config $config Config object - * @param \phpbb\user $user User object - * @return void - */ - function anti_abuse_headers($config, $user) - { - $this->headers('X-AntiAbuse: Board servername - ' . mail_encode($config['server_name'])); - $this->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']); - $this->headers('X-AntiAbuse: Username - ' . mail_encode($user->data['username'])); - $this->headers('X-AntiAbuse: User IP - ' . $user->ip); - } - - /** - * Set the email priority - */ - function set_mail_priority($priority = MAIL_NORMAL_PRIORITY) - { - $this->mail_priority = $priority; - } - - /** - * Set email template to use - */ - function template($template_file, $template_lang = '', $template_path = '', $template_dir_prefix = '') - { - global $config, $phpbb_root_path, $user; - - $template_dir_prefix = (!$template_dir_prefix || $template_dir_prefix[0] === '/') ? $template_dir_prefix : '/' . $template_dir_prefix; - - $this->setup_template(); - - if (!trim($template_file)) - { - trigger_error('No template file for emailing set.', E_USER_ERROR); - } - - if (!trim($template_lang)) - { - // fall back to board default language if the user's language is - // missing $template_file. If this does not exist either, - // $this->template->set_filenames will do a trigger_error - $template_lang = basename($config['default_lang']); - } - - $ext_template_paths = array( - array( - 'name' => $template_lang . '_email', - 'ext_path' => 'language/' . $template_lang . '/email' . $template_dir_prefix, - ), - ); - - if ($template_path) - { - $template_paths = array( - $template_path . $template_dir_prefix, - ); - } - else - { - $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $template_path .= $template_lang . '/email'; - - $template_paths = array( - $template_path . $template_dir_prefix, - ); - - $board_language = basename($config['default_lang']); - - // we can only specify default language fallback when the path is not a custom one for which we - // do not know the default language alternative - if ($template_lang !== $board_language) - { - $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $fallback_template_path .= $board_language . '/email'; - - $template_paths[] = $fallback_template_path . $template_dir_prefix; - - $ext_template_paths[] = array( - 'name' => $board_language . '_email', - 'ext_path' => 'language/' . $board_language . '/email' . $template_dir_prefix, - ); - } - // If everything fails just fall back to en template - if ($template_lang !== 'en' && $board_language !== 'en') - { - $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $fallback_template_path .= 'en/email'; - - $template_paths[] = $fallback_template_path . $template_dir_prefix; - - $ext_template_paths[] = array( - 'name' => 'en_email', - 'ext_path' => 'language/en/email' . $template_dir_prefix, - ); - } - } - - $this->set_template_paths($ext_template_paths, $template_paths); - - $this->template->set_filenames(array( - 'body' => $template_file . '.txt', - )); - - return true; - } - - /** - * assign variables to email template - */ - function assign_vars($vars) - { - $this->setup_template(); - - $this->template->assign_vars($vars); - } - - function assign_block_vars($blockname, $vars) - { - $this->setup_template(); - - $this->template->assign_block_vars($blockname, $vars); - } - - /** - * Send the mail out to the recipients set previously in var $this->addresses - * - * @param int $method User notification method NOTIFY_EMAIL|NOTIFY_IM|NOTIFY_BOTH - * @param bool $break Flag indicating if the function only formats the subject - * and the message without sending it - * - * @return bool - */ - function send($method = NOTIFY_EMAIL, $break = false) - { - global $config, $user, $phpbb_dispatcher; - - // We add some standard variables we always use, no need to specify them always - $this->assign_vars(array( - 'U_BOARD' => generate_board_url(), - 'EMAIL_SIG' => str_replace('
', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])), - 'SITENAME' => htmlspecialchars_decode($config['sitename']), - )); - - $subject = $this->subject; - $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 after parsing - * - * @event core.modify_notification_message - * @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 string message The message text - * @since 3.1.11-RC1 - */ - $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, $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); - - // We now try and pull a subject from the email body ... if it exists, - // do this here because the subject may contain a variable - $drop_header = ''; - $match = array(); - if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match)) - { - $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']); - $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#'); - } - else - { - $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)); - } - - if ($break) - { - return true; - } - - switch ($method) - { - case NOTIFY_EMAIL: - $result = $this->msg_email(); - break; - - case NOTIFY_IM: - $result = $this->msg_jabber(); - break; - - case NOTIFY_BOTH: - $result = $this->msg_email(); - $this->msg_jabber(); - break; - } - - $this->reset(); - return $result; - } - - /** - * Add error message to log - */ - function error($type, $msg) - { - global $user, $config, $request, $phpbb_log; - - // Session doesn't exist, create it - if (!isset($user->session_id) || $user->session_id === '') - { - $user->session_begin(); - } - - $calling_page = htmlspecialchars_decode($request->server('PHP_SELF')); - - switch ($type) - { - case 'EMAIL': - $message = 'EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/mail()') . ''; - break; - - default: - $message = "$type"; - break; - } - - $message .= '
' . htmlspecialchars($calling_page) . '

' . $msg . '
'; - $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_' . $type, false, array($message)); - } - - /** - * Save to queue - */ - function save_queue() - { - global $config; - - if ($config['email_package_size'] && $this->use_queue && !empty($this->queue)) - { - $this->queue->save(); - return; - } - } - - /** - * Generates a valid message id to be used in emails - * - * @return string message id - */ - function generate_message_id() - { - global $config, $request; - - $domain = ($config['server_name']) ?: $request->server('SERVER_NAME', 'phpbb.generated'); - - return md5(unique_id(time())) . '@' . $domain; - } - - /** - * Return email header - */ - function build_header($to, $cc, $bcc) - { - global $config, $phpbb_dispatcher; - - // We could use keys here, but we won't do this for 3.0.x to retain backwards compatibility - $headers = array(); - - $headers[] = 'From: ' . $this->from; - - if ($cc) - { - $headers[] = 'Cc: ' . $cc; - } - - if ($bcc) - { - $headers[] = 'Bcc: ' . $bcc; - } - - $headers[] = 'Reply-To: ' . $this->replyto; - $headers[] = 'Return-Path: <' . $config['board_email'] . '>'; - $headers[] = 'Sender: <' . $config['board_email'] . '>'; - $headers[] = 'MIME-Version: 1.0'; - $headers[] = 'Message-ID: <' . $this->generate_message_id() . '>'; - $headers[] = 'Date: ' . date('r', time()); - $headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed - $headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit - - $headers[] = 'X-Priority: ' . $this->mail_priority; - $headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High')); - $headers[] = 'X-Mailer: phpBB3'; - $headers[] = 'X-MimeOLE: phpBB3'; - $headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url()); - - /** - * Event to modify email header entries - * - * @event core.modify_email_headers - * @var array headers Array containing email header entries - * @since 3.1.11-RC1 - */ - $vars = array('headers'); - extract($phpbb_dispatcher->trigger_event('core.modify_email_headers', compact($vars))); - - if (count($this->extra_headers)) - { - $headers = array_merge($headers, $this->extra_headers); - } - - return $headers; - } - - /** - * Send out emails - */ - function msg_email() - { - global $config, $phpbb_dispatcher; - - if (empty($config['email_enable'])) - { - return false; - } - - // Addresses to send to? - if (empty($this->addresses) || (empty($this->addresses['to']) && empty($this->addresses['cc']) && empty($this->addresses['bcc']))) - { - // Send was successful. ;) - return true; - } - - $use_queue = false; - if ($config['email_package_size'] && $this->use_queue) - { - if (empty($this->queue)) - { - $this->queue = new queue(); - $this->queue->init('email', $config['email_package_size']); - } - $use_queue = true; - } - - $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; - } - - if (empty($this->from)) - { - $this->from = $board_contact; - } - - $encode_eol = ($config['smtp_delivery']) ? "\r\n" : PHP_EOL; - - // Build to, cc and bcc strings - $to = $cc = $bcc = ''; - foreach ($this->addresses as $type => $address_ary) - { - if ($type == 'im') - { - continue; - } - - foreach ($address_ary as $which_ary) - { - ${$type} .= ((${$type} != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']); - } - } - - // Build header - $headers = $this->build_header($to, $cc, $bcc); - - // Send message ... - if (!$use_queue) - { - $mail_to = ($to == '') ? 'undisclosed-recipients:;' : $to; - $err_msg = ''; - - if ($config['smtp_delivery']) - { - $result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $err_msg, $headers); - } - else - { - $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, PHP_EOL, $err_msg); - } - - if (!$result) - { - $this->error('EMAIL', $err_msg); - return false; - } - } - else - { - $this->queue->put('email', array( - 'to' => $to, - 'addresses' => $this->addresses, - 'subject' => $this->subject, - 'msg' => $this->msg, - 'headers' => $headers) - ); - } - - return true; - } - - /** - * Send jabber message out - */ - function msg_jabber() - { - global $config, $user, $phpbb_root_path, $phpEx; - - if (empty($config['jab_enable']) || empty($config['jab_host']) || empty($config['jab_username']) || empty($config['jab_password'])) - { - return false; - } - - if (empty($this->addresses['im'])) - { - // Send was successful. ;) - return true; - } - - $use_queue = false; - if ($config['jab_package_size'] && $this->use_queue) - { - if (empty($this->queue)) - { - $this->queue = new queue(); - $this->queue->init('jabber', $config['jab_package_size']); - } - $use_queue = true; - } - - $addresses = array(); - foreach ($this->addresses['im'] as $type => $uid_ary) - { - $addresses[] = $uid_ary['uid']; - } - $addresses = array_unique($addresses); - - if (!$use_queue) - { - include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx); - $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl'], $config['jab_verify_peer'], $config['jab_verify_peer_name'], $config['jab_allow_self_signed']); - - if (!$this->jabber->connect()) - { - $this->error('JABBER', $user->lang['ERR_JAB_CONNECT'] . '
' . $this->jabber->get_log()); - return false; - } - - if (!$this->jabber->login()) - { - $this->error('JABBER', $user->lang['ERR_JAB_AUTH'] . '
' . $this->jabber->get_log()); - return false; - } - - foreach ($addresses as $address) - { - $this->jabber->send_message($address, $this->msg, $this->subject); - } - - $this->jabber->disconnect(); - } - else - { - $this->queue->put('jabber', array( - 'addresses' => $addresses, - 'subject' => $this->subject, - 'msg' => $this->msg) - ); - } - unset($addresses); - return true; - } - - /** - * Setup template engine - */ - protected function setup_template() - { - global $phpbb_container, $phpbb_dispatcher; - - if ($this->template instanceof \phpbb\template\template) - { - return; - } - - $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') - ); - } - - /** - * Set template paths to load - */ - protected function set_template_paths($path_name, $paths) - { - $this->setup_template(); - - $this->template->set_custom_style($path_name, $paths); - } -} - -/** -* handling email and jabber queue -*/ -class queue -{ - var $data = array(); - var $queue_data = array(); - var $package_size = 0; - var $cache_file = ''; - var $eol = "\n"; - - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * constructor - */ - function __construct() - { - global $phpEx, $phpbb_root_path, $phpbb_filesystem, $phpbb_container; - - $this->data = array(); - $this->cache_file = $phpbb_container->getParameter('core.cache_dir') . "queue.$phpEx"; - $this->filesystem = $phpbb_filesystem; - } - - /** - * Init a queue object - */ - function init($object, $package_size) - { - $this->data[$object] = array(); - $this->data[$object]['package_size'] = $package_size; - $this->data[$object]['data'] = array(); - } - - /** - * Put object in queue - */ - function put($object, $scope) - { - $this->data[$object]['data'][] = $scope; - } - - /** - * Process queue - * Using lock file - */ - function process() - { - global $config, $phpEx, $phpbb_root_path, $user, $phpbb_dispatcher; - - $lock = new \phpbb\lock\flock($this->cache_file); - $lock->acquire(); - - // avoid races, check file existence once - $have_cache_file = file_exists($this->cache_file); - if (!$have_cache_file || $config['last_queue_run'] > time() - $config['queue_interval']) - { - if (!$have_cache_file) - { - $config->set('last_queue_run', time(), false); - } - - $lock->release(); - return; - } - - $config->set('last_queue_run', time(), false); - - include($this->cache_file); - - foreach ($this->queue_data as $object => $data_ary) - { - @set_time_limit(0); - - if (!isset($data_ary['package_size'])) - { - $data_ary['package_size'] = 0; - } - - $package_size = $data_ary['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. - * The core problem is rather restrictive email sending limits. - * This code is nly useful if you have no such restrictions from the - * 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 (count($data_ary['data']) > $package_size * 2.5) - { - $num_items = count($data_ary['data']); - } - */ - - switch ($object) - { - case 'email': - // Delete the email queued objects if mailing is disabled - if (!$config['email_enable']) - { - unset($this->queue_data['email']); - continue 2; - } - break; - - case 'jabber': - if (!$config['jab_enable']) - { - unset($this->queue_data['jabber']); - continue 2; - } - - include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx); - $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl'], $config['jab_verify_peer'], $config['jab_verify_peer_name'], $config['jab_allow_self_signed']); - - if (!$this->jabber->connect()) - { - $messenger = new messenger(); - $messenger->error('JABBER', $user->lang['ERR_JAB_CONNECT']); - continue 2; - } - - if (!$this->jabber->login()) - { - $messenger = new messenger(); - $messenger->error('JABBER', $user->lang['ERR_JAB_AUTH']); - continue 2; - } - - break; - - default: - $lock->release(); - return; - } - - for ($i = 0; $i < $num_items; $i++) - { - // Make variables available... - extract(array_shift($this->queue_data[$object]['data'])); - - switch ($object) - { - case 'email': - $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) - { - $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 - { - $result = phpbb_mail($to, $subject, $msg, $headers, PHP_EOL, $err_msg); - } - - if (!$result) - { - $messenger = new messenger(); - $messenger->error('EMAIL', $err_msg); - continue 2; - } - } - break; - - case 'jabber': - foreach ($addresses as $address) - { - if ($this->jabber->send_message($address, $msg, $subject) === false) - { - $messenger = new messenger(); - $messenger->error('JABBER', $this->jabber->get_log()); - continue 3; - } - } - break; - } - } - - // No more data for this object? Unset it - if (!count($this->queue_data[$object]['data'])) - { - unset($this->queue_data[$object]); - } - - // Post-object processing - switch ($object) - { - case 'jabber': - // Hang about a couple of secs to ensure the messages are - // handled, then disconnect - $this->jabber->disconnect(); - break; - } - } - - if (!count($this->queue_data)) - { - @unlink($this->cache_file); - } - else - { - if ($fp = @fopen($this->cache_file, 'wb')) - { - fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>"); - fclose($fp); - - if (function_exists('opcache_invalidate')) - { - @opcache_invalidate($this->cache_file); - } - - try - { - $this->filesystem->phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - - $lock->release(); - } - - /** - * Save queue - */ - function save() - { - if (!count($this->data)) - { - return; - } - - $lock = new \phpbb\lock\flock($this->cache_file); - $lock->acquire(); - - if (file_exists($this->cache_file)) - { - include($this->cache_file); - - foreach ($this->queue_data as $object => $data_ary) - { - if (isset($this->data[$object]) && count($this->data[$object])) - { - $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']); - } - else - { - $this->data[$object]['data'] = $data_ary['data']; - } - } - } - - if ($fp = @fopen($this->cache_file, 'w')) - { - fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>"); - fclose($fp); - - if (function_exists('opcache_invalidate')) - { - @opcache_invalidate($this->cache_file); - } - - try - { - $this->filesystem->phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - - $this->data = array(); - } - - $lock->release(); - } -} - -/** -* Replacement or substitute for PHP's mail command -*/ -function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false) -{ - global $config, $user; - - // Fix any bare linefeeds in the message to make it RFC821 Compliant. - $message = preg_replace("#(?lang['NO_EMAIL_SUBJECT'])) ? $user->lang['NO_EMAIL_SUBJECT'] : 'No email subject specified'; - return false; - } - - if (trim($message) == '') - { - $err_msg = (isset($user->lang['NO_EMAIL_MESSAGE'])) ? $user->lang['NO_EMAIL_MESSAGE'] : 'Email message was blank'; - return 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']) && count($addresses['to'])) - { - foreach ($addresses['to'] as $which_ary) - { - $mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; - $mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - if (isset($addresses['bcc']) && count($addresses['bcc'])) - { - foreach ($addresses['bcc'] as $which_ary) - { - $mail_rcpt['bcc'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - if (isset($addresses['cc']) && count($addresses['cc'])) - { - foreach ($addresses['cc'] as $which_ary) - { - $mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; - $mail_rcpt['cc'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - $smtp = new smtp_class(); - - $errno = 0; - $errstr = ''; - - $smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']); - - // Ok we have error checked as much as we can to this point let's get on it already. - if (!class_exists('\phpbb\error_collector')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/error_collector.' . $phpEx); - } - $collector = new \phpbb\error_collector; - $collector->install(); - - $options = array(); - $verify_peer = (bool) $config['smtp_verify_peer']; - $verify_peer_name = (bool) $config['smtp_verify_peer_name']; - $allow_self_signed = (bool) $config['smtp_allow_self_signed']; - $remote_socket = $config['smtp_host'] . ':' . $config['smtp_port']; - - // Set ssl context options, see http://php.net/manual/en/context.ssl.php - $options['ssl'] = array('verify_peer' => $verify_peer, 'verify_peer_name' => $verify_peer_name, 'allow_self_signed' => $allow_self_signed); - $socket_context = stream_context_create($options); - - $smtp->socket = @stream_socket_client($remote_socket, $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $socket_context); - $collector->uninstall(); - $error_contents = $collector->format_errors(); - - if (!$smtp->socket) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - $err_msg .= ($error_contents) ? '

' . htmlspecialchars($error_contents) : ''; - return false; - } - - // Wait for reply - if ($err_msg = $smtp->server_parse('220', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Let me in. This function handles the complete authentication process - if ($err_msg = $smtp->log_into_server($config['smtp_host'], $config['smtp_username'], htmlspecialchars_decode($config['smtp_password']), $config['smtp_auth_method'])) - { - $smtp->close_session($err_msg); - return false; - } - - // From this point onward most server response codes should be 250 - // Specify who the mail is from.... - $smtp->server_send('MAIL FROM:<' . $config['board_email'] . '>'); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Specify each user to send to and build to header. - $to_header = implode(', ', $mail_to); - $cc_header = implode(', ', $mail_cc); - - // Now tell the MTA to send the Message to the following people... [TO, BCC, CC] - $rcpt = false; - foreach ($mail_rcpt as $type => $mail_to_addresses) - { - foreach ($mail_to_addresses as $mail_to_address) - { - // Add an additional bit of error checking to the To field. - if (preg_match('#[^ ]+\@[^ ]+#', $mail_to_address)) - { - $smtp->server_send("RCPT TO:$mail_to_address"); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - // We continue... if users are not resolved we do not care - if ($smtp->numeric_response_code != 550) - { - $smtp->close_session($err_msg); - return false; - } - } - else - { - $rcpt = true; - } - } - } - } - - // We try to send messages even if a few people do not seem to have valid email addresses, but if no one has, we have to exit here. - if (!$rcpt) - { - $user->session_begin(); - $err_msg .= '

'; - $err_msg .= (isset($user->lang['INVALID_EMAIL_LOG'])) ? sprintf($user->lang['INVALID_EMAIL_LOG'], htmlspecialchars($mail_to_address)) : '' . htmlspecialchars($mail_to_address) . ' possibly an invalid email address?'; - $smtp->close_session($err_msg); - return false; - } - - // Ok now we tell the server we are ready to start sending data - $smtp->server_send('DATA'); - - // This is the last response code we look for until the end of the message. - if ($err_msg = $smtp->server_parse('354', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Send the Subject Line... - $smtp->server_send("Subject: $subject"); - - // Now the To Header. - $to_header = ($to_header == '') ? 'undisclosed-recipients:;' : $to_header; - $smtp->server_send("To: $to_header"); - - // Now the CC Header. - if ($cc_header != '') - { - $smtp->server_send("CC: $cc_header"); - } - - // Now any custom headers.... - if ($headers !== false) - { - $smtp->server_send("$headers\r\n"); - } - - // Ok now we are ready for the message... - $smtp->server_send($message); - - // Ok the all the ingredients are mixed in let's cook this puppy... - $smtp->server_send('.'); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Now tell the server we are done and close the socket... - $smtp->server_send('QUIT'); - $smtp->close_session($err_msg); - - return true; -} - -/** -* SMTP Class -* Auth Mechanisms originally taken from the AUTH Modules found within the PHP Extension and Application Repository (PEAR) -* See docs/AUTHORS for more details -*/ -class smtp_class -{ - var $server_response = ''; - var $socket = 0; - protected $socket_tls = false; - var $responses = array(); - var $commands = array(); - var $numeric_response_code = 0; - - var $backtrace = false; - var $backtrace_log = array(); - - function __construct() - { - // Always create a backtrace for admins to identify SMTP problems - $this->backtrace = true; - $this->backtrace_log = array(); - } - - /** - * Add backtrace message for debugging - */ - function add_backtrace($message) - { - if ($this->backtrace) - { - $this->backtrace_log[] = utf8_htmlspecialchars($message); - } - } - - /** - * Send command to smtp server - */ - function server_send($command, $private_info = false) - { - fputs($this->socket, $command . "\r\n"); - - (!$private_info) ? $this->add_backtrace("# $command") : $this->add_backtrace('# Omitting sensitive information'); - - // We could put additional code here - } - - /** - * We use the line to give the support people an indication at which command the error occurred - */ - function server_parse($response, $line) - { - global $user; - - $this->server_response = ''; - $this->responses = array(); - $this->numeric_response_code = 0; - - while (substr($this->server_response, 3, 1) != ' ') - { - if (!($this->server_response = fgets($this->socket, 256))) - { - return (isset($user->lang['NO_EMAIL_RESPONSE_CODE'])) ? $user->lang['NO_EMAIL_RESPONSE_CODE'] : 'Could not get mail server response codes'; - } - $this->responses[] = substr(rtrim($this->server_response), 4); - $this->numeric_response_code = (int) substr($this->server_response, 0, 3); - - $this->add_backtrace("LINE: $line <- {$this->server_response}"); - } - - if (!(substr($this->server_response, 0, 3) == $response)) - { - $this->numeric_response_code = (int) substr($this->server_response, 0, 3); - return (isset($user->lang['EMAIL_SMTP_ERROR_RESPONSE'])) ? sprintf($user->lang['EMAIL_SMTP_ERROR_RESPONSE'], $line, $this->server_response) : "Ran into problems sending Mail at Line $line. Response: $this->server_response"; - } - - return 0; - } - - /** - * Close session - */ - function close_session(&$err_msg) - { - fclose($this->socket); - - if ($this->backtrace) - { - $message = '

Backtrace

' . implode('
', $this->backtrace_log) . '

'; - $err_msg .= $message; - } - } - - /** - * Log into server and get possible auth codes if neccessary - */ - function log_into_server($hostname, $username, $password, $default_auth_method) - { - global $user; - - // Here we try to determine the *real* hostname (reverse DNS entry preferrably) - $local_host = $user->host; - - if (function_exists('php_uname')) - { - $local_host = php_uname('n'); - - // Able to resolve name to IP - if (($addr = @gethostbyname($local_host)) !== $local_host) - { - // Able to resolve IP back to name - if (($name = @gethostbyaddr($addr)) !== $addr) - { - $local_host = $name; - } - } - } - - // If we are authenticating through pop-before-smtp, we - // have to login ones before we get authenticated - // NOTE: on some configurations the time between an update of the auth database takes so - // long that the first email send does not work. This is not a biggie on a live board (only - // the install mail will most likely fail) - but on a dynamic ip connection this might produce - // severe problems and is not fixable! - if ($default_auth_method == 'POP-BEFORE-SMTP' && $username && $password) - { - global $config; - - $errno = 0; - $errstr = ''; - - $this->server_send("QUIT"); - fclose($this->socket); - - $this->pop_before_smtp($hostname, $username, $password); - $username = $password = $default_auth_method = ''; - - // We need to close the previous session, else the server is not - // able to get our ip for matching... - if (!$this->socket = @fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 10)) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - return $err_msg; - } - - // Wait for reply - if ($err_msg = $this->server_parse('220', __LINE__)) - { - $this->close_session($err_msg); - return $err_msg; - } - } - - $hello_result = $this->hello($local_host); - if (!is_null($hello_result)) - { - return $hello_result; - } - - // SMTP STARTTLS (RFC 3207) - if (!$this->socket_tls) - { - $this->socket_tls = $this->starttls(); - - if ($this->socket_tls) - { - // Switched to TLS - // RFC 3207: "The client MUST discard any knowledge obtained from the server, [...]" - // So say hello again - $hello_result = $this->hello($local_host); - - if (!is_null($hello_result)) - { - return $hello_result; - } - } - } - - // If we are not authenticated yet, something might be wrong if no username and passwd passed - if (!$username || !$password) - { - return false; - } - - if (!isset($this->commands['AUTH'])) - { - return (isset($user->lang['SMTP_NO_AUTH_SUPPORT'])) ? $user->lang['SMTP_NO_AUTH_SUPPORT'] : 'SMTP server does not support authentication'; - } - - // Get best authentication method - $available_methods = explode(' ', $this->commands['AUTH']); - - // Define the auth ordering if the default auth method was not found - $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5'); - $method = ''; - - if (in_array($default_auth_method, $available_methods)) - { - $method = $default_auth_method; - } - else - { - foreach ($auth_methods as $_method) - { - if (in_array($_method, $available_methods)) - { - $method = $_method; - break; - } - } - } - - if (!$method) - { - return (isset($user->lang['NO_SUPPORTED_AUTH_METHODS'])) ? $user->lang['NO_SUPPORTED_AUTH_METHODS'] : 'No supported authentication methods'; - } - - $method = strtolower(str_replace('-', '_', $method)); - return $this->$method($username, $password); - } - - /** - * SMTP EHLO/HELO - * - * @return mixed Null if the authentication process is supposed to continue - * False if already authenticated - * Error message (string) otherwise - */ - protected function hello($hostname) - { - // Try EHLO first - $this->server_send("EHLO $hostname"); - if ($err_msg = $this->server_parse('250', __LINE__)) - { - // a 503 response code means that we're already authenticated - if ($this->numeric_response_code == 503) - { - return false; - } - - // If EHLO fails, we try HELO - $this->server_send("HELO $hostname"); - if ($err_msg = $this->server_parse('250', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - } - - foreach ($this->responses as $response) - { - $response = explode(' ', $response); - $response_code = $response[0]; - unset($response[0]); - $this->commands[$response_code] = implode(' ', $response); - } - } - - /** - * SMTP STARTTLS (RFC 3207) - * - * @return bool Returns true if TLS was started - * Otherwise false - */ - 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; - } - - if (!isset($this->commands['STARTTLS'])) - { - return false; - } - - $this->server_send('STARTTLS'); - - if ($err_msg = $this->server_parse('220', __LINE__)) - { - return false; - } - - $result = false; - $stream_meta = stream_get_meta_data($this->socket); - - if (socket_set_blocking($this->socket, 1)) - { - // 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']); - } - - return $result; - } - - /** - * Pop before smtp authentication - */ - function pop_before_smtp($hostname, $username, $password) - { - global $user; - - if (!$this->socket = @fsockopen($hostname, 110, $errno, $errstr, 10)) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - return (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - } - - $this->server_send("USER $username", true); - if ($err_msg = $this->server_parse('+OK', __LINE__)) - { - return $err_msg; - } - - $this->server_send("PASS $password", true); - if ($err_msg = $this->server_parse('+OK', __LINE__)) - { - return $err_msg; - } - - $this->server_send('QUIT'); - fclose($this->socket); - - return false; - } - - /** - * Plain authentication method - */ - function plain($username, $password) - { - $this->server_send('AUTH PLAIN'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $base64_method_plain = base64_encode("\0" . $username . "\0" . $password); - $this->server_send($base64_method_plain, true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * Login authentication method - */ - function login($username, $password) - { - $this->server_send('AUTH LOGIN'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $this->server_send(base64_encode($username), true); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return $err_msg; - } - - $this->server_send(base64_encode($password), true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * cram_md5 authentication method - */ - function cram_md5($username, $password) - { - $this->server_send('AUTH CRAM-MD5'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $md5_challenge = base64_decode($this->responses[0]); - $password = (strlen($password) > 64) ? pack('H32', md5($password)) : ((strlen($password) < 64) ? str_pad($password, 64, chr(0)) : $password); - $md5_digest = md5((substr($password, 0, 64) ^ str_repeat(chr(0x5C), 64)) . (pack('H32', md5((substr($password, 0, 64) ^ str_repeat(chr(0x36), 64)) . $md5_challenge)))); - - $base64_method_cram_md5 = base64_encode($username . ' ' . $md5_digest); - - $this->server_send($base64_method_cram_md5, true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * digest_md5 authentication method - * A real pain in the *** - */ - function digest_md5($username, $password) - { - global $config, $user; - - $this->server_send('AUTH DIGEST-MD5'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $md5_challenge = base64_decode($this->responses[0]); - - // Parse the md5 challenge - from AUTH_SASL (PEAR) - $tokens = array(); - while (preg_match('/^([a-z-]+)=("[^"]+(?host; - } - - // Maxbuf - if (empty($tokens['maxbuf'])) - { - $tokens['maxbuf'] = 65536; - } - - // Required: nonce, algorithm - if (empty($tokens['nonce']) || empty($tokens['algorithm'])) - { - $tokens = array(); - } - $md5_challenge = $tokens; - - if (!empty($md5_challenge)) - { - $str = ''; - for ($i = 0; $i < 32; $i++) - { - $str .= chr(mt_rand(0, 255)); - } - $cnonce = base64_encode($str); - - $digest_uri = 'smtp/' . $config['smtp_host']; - - $auth_1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $username, $md5_challenge['realm'], $password))), $md5_challenge['nonce'], $cnonce); - $auth_2 = 'AUTHENTICATE:' . $digest_uri; - $response_value = md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($auth_1), $md5_challenge['nonce'], $cnonce, md5($auth_2))); - - $input_string = sprintf('username="%s",realm="%s",nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $username, $md5_challenge['realm'], $md5_challenge['nonce'], $cnonce, $digest_uri, $response_value, $md5_challenge['maxbuf']); - } - else - { - return (isset($user->lang['INVALID_DIGEST_CHALLENGE'])) ? $user->lang['INVALID_DIGEST_CHALLENGE'] : 'Invalid digest challenge'; - } - - $base64_method_digest_md5 = base64_encode($input_string); - $this->server_send($base64_method_digest_md5, true); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return $err_msg; - } - - $this->server_send(' '); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } -} - -/** -* Encodes the given string for proper display in UTF-8. -* -* This version is using base64 encoded data. The downside of this -* is if the mail client does not understand this encoding the user -* is basically doomed with an unreadable subject. -* -* Please note that this version fully supports RFC 2045 section 6.8. -* -* @param string $eol End of line we are using (optional to be backwards compatible) -*/ -function mail_encode($str, $eol = "\r\n") -{ - // define start delimimter, end delimiter and spacer - $start = "=?UTF-8?B?"; - $end = "?="; - $delimiter = "$eol "; - - // Maximum length is 75. $split_length *must* be a multiple of 4, but <= 75 - strlen($start . $delimiter . $end)!!! - $split_length = 60; - $encoded_str = base64_encode($str); - - // If encoded string meets the limits, we just return with the correct data. - if (strlen($encoded_str) <= $split_length) - { - return $start . $encoded_str . $end; - } - - // If there is only ASCII data, we just return what we want, correctly splitting the lines. - if (strlen($str) === utf8_strlen($str)) - { - return $start . implode($end . $delimiter . $start, str_split($encoded_str, $split_length)) . $end; - } - - // UTF-8 data, compose encoded lines - $array = utf8_str_split($str); - $str = ''; - - while (count($array)) - { - $text = ''; - - while (count($array) && intval((strlen($text . $array[0]) + 2) / 3) << 2 <= $split_length) - { - $text .= array_shift($array); - } - - $str .= $start . base64_encode($text) . $end . $delimiter; - } - - return substr($str, 0, -strlen($delimiter)); -} - -/** - * Wrapper for sending out emails with the PHP's mail function - */ -function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg) -{ - global $config, $phpbb_root_path, $phpEx; - - // 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')) - { - include($phpbb_root_path . 'includes/error_collector.' . $phpEx); - } - - $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) - */ - $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(); - - return $result; -} diff --git a/install/update/new/includes/functions_module.php b/install/update/new/includes/functions_module.php deleted file mode 100644 index e90c11f..0000000 --- a/install/update/new/includes/functions_module.php +++ /dev/null @@ -1,1153 +0,0 @@ - -* @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 handling all types of 'plugins' (a future term) -*/ -class p_master -{ - var $p_id; - var $p_class; - var $p_name; - var $p_mode; - var $p_parent; - - var $include_path = false; - var $active_module = false; - var $active_module_row_id = false; - var $acl_forum_id = false; - var $module_ary = array(); - - /** - * Constuctor - * Set module include path - */ - function __construct($include_path = false) - { - global $phpbb_root_path; - - $this->include_path = ($include_path !== false) ? $include_path : $phpbb_root_path . 'includes/'; - - // Make sure the path ends with / - if (substr($this->include_path, -1) !== '/') - { - $this->include_path .= '/'; - } - } - - /** - * Set custom include path for modules - * Schema for inclusion is include_path . modulebase - * - * @param string $include_path include path to be used. - * @access public - */ - function set_custom_include_path($include_path) - { - $this->include_path = $include_path; - - // Make sure the path ends with / - if (substr($this->include_path, -1) !== '/') - { - $this->include_path .= '/'; - } - } - - /** - * List modules - * - * This creates a list, stored in $this->module_ary of all available - * modules for the given class (ucp, mcp and acp). Additionally - * $this->module_y_ary is created with indentation information for - * displaying the module list appropriately. Only modules for which - * the user has access rights are included in these lists. - */ - function list_modules($p_class) - { - 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)); - - // Get cached modules - if (($this->module_cache = $cache->get('_modules_' . $this->p_class)) === false) - { - // Get modules - $sql = 'SELECT * - FROM ' . MODULES_TABLE . " - WHERE module_class = '" . $db->sql_escape($this->p_class) . "' - ORDER BY left_id ASC"; - $result = $db->sql_query($sql); - - $rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rows[$row['module_id']] = $row; - } - $db->sql_freeresult($result); - - $this->module_cache = array(); - foreach ($rows as $module_id => $row) - { - $this->module_cache['modules'][] = $row; - $this->module_cache['parents'][$row['module_id']] = $this->get_parents($row['parent_id'], $row['left_id'], $row['right_id'], $rows); - } - unset($rows); - - $cache->put('_modules_' . $this->p_class, $this->module_cache); - } - - if (empty($this->module_cache)) - { - $this->module_cache = array('modules' => array(), 'parents' => array()); - } - - // We "could" build a true tree with this function - maybe mod authors want to use this... - // Functions for traversing and manipulating the tree are not available though - // We might re-structure the module system to use true trees in 4.0 - // $tree = $this->build_tree($this->module_cache['modules'], $this->module_cache['parents']); - - // Clean up module cache array to only let survive modules the user can access - $right_id = false; - - $hide_categories = array(); - foreach ($this->module_cache['modules'] as $key => $row) - { - // When the module has no mode (category) we check whether it has visible children - // before listing it as well. - if (!$row['module_mode']) - { - $hide_categories[(int) $row['module_id']] = $key; - } - - // Not allowed to view module? - if (!$this->module_auth_self($row['module_auth'])) - { - unset($this->module_cache['modules'][$key]); - continue; - } - - // Category with no members, ignore - if (!$row['module_basename'] && ($row['left_id'] + 1 == $row['right_id'])) - { - unset($this->module_cache['modules'][$key]); - continue; - } - - // Skip branch - if ($right_id !== false) - { - if ($row['left_id'] < $right_id) - { - unset($this->module_cache['modules'][$key]); - continue; - } - - $right_id = false; - } - - // Not enabled? - if (!$row['module_enabled']) - { - // If category is disabled then disable every child too - unset($this->module_cache['modules'][$key]); - $right_id = $row['right_id']; - continue; - } - - if ($row['module_mode']) - { - // The parent category has a visible child - // So remove it and all its parents from the hide array - unset($hide_categories[(int) $row['parent_id']]); - foreach ($this->module_cache['parents'][$row['module_id']] as $module_id => $row_id) - { - unset($hide_categories[$module_id]); - } - } - } - - foreach ($hide_categories as $module_id => $row_id) - { - unset($this->module_cache['modules'][$row_id]); - } - - // Re-index (this is needed, else we are not able to array_slice later) - $this->module_cache['modules'] = array_merge($this->module_cache['modules']); - - // Include MOD _info files for populating language entries within the menus - $this->add_mod_info($this->p_class); - - // Now build the module array, but exclude completely empty categories... - $right_id = false; - $names = array(); - - foreach ($this->module_cache['modules'] as $key => $row) - { - // Skip branch - if ($right_id !== false) - { - if ($row['left_id'] < $right_id) - { - continue; - } - - $right_id = false; - } - - // Category with no members on their way down (we have to check every level) - if (!$row['module_basename']) - { - $empty_category = true; - - // We go through the branch and look for an activated module - foreach (array_slice($this->module_cache['modules'], $key + 1) as $temp_row) - { - if ($temp_row['left_id'] > $row['left_id'] && $temp_row['left_id'] < $row['right_id']) - { - // Module there - if ($temp_row['module_basename'] && $temp_row['module_enabled']) - { - $empty_category = false; - break; - } - continue; - } - break; - } - - // Skip the branch - if ($empty_category) - { - $right_id = $row['right_id']; - continue; - } - } - - $depth = count($this->module_cache['parents'][$row['module_id']]); - - // We need to prefix the functions to not create a naming conflict - - // Function for building 'url_extra' - $short_name = $this->get_short_name($row['module_basename']); - - $url_func = 'phpbb_module_' . $short_name . '_url'; - if (!function_exists($url_func)) - { - $url_func = '_module_' . $short_name . '_url'; - } - - // Function for building the language name - $lang_func = 'phpbb_module_' . $short_name . '_lang'; - if (!function_exists($lang_func)) - { - $lang_func = '_module_' . $short_name . '_lang'; - } - - // Custom function for calling parameters on module init (for example assigning template variables) - $custom_func = 'phpbb_module_' . $short_name; - if (!function_exists($custom_func)) - { - $custom_func = '_module_' . $short_name; - } - - $names[$row['module_basename'] . '_' . $row['module_mode']][] = true; - - $module_row = array( - 'depth' => $depth, - - 'id' => (int) $row['module_id'], - 'parent' => (int) $row['parent_id'], - 'cat' => ($row['right_id'] > $row['left_id'] + 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'], - 'display' => (int) $row['module_display'], - - 'url_extra' => (function_exists($url_func)) ? $url_func($row['module_mode'], $row) : '', - - 'lang' => ($row['module_basename'] && function_exists($lang_func)) ? $lang_func($row['module_mode'], $row['module_langname']) : ((!empty($user->lang[$row['module_langname']])) ? $user->lang[$row['module_langname']] : $row['module_langname']), - 'langname' => $row['module_langname'], - - 'left' => $row['left_id'], - 'right' => $row['right_id'], - ); - - if (function_exists($custom_func)) - { - $custom_func($row['module_mode'], $module_row); - } - - /** - * This event allows to modify parameters for building modules list - * - * @event core.modify_module_row - * @var string url_func Function for building 'url_extra' - * @var string lang_func Function for building the language name - * @var string custom_func Custom function for calling parameters on module init - * @var array row Array holding the basic module data - * @var array module_row Array holding the module display parameters - * @since 3.1.0-b3 - */ - $vars = array('url_func', 'lang_func', 'custom_func', 'row', 'module_row'); - extract($phpbb_dispatcher->trigger_event('core.modify_module_row', compact($vars))); - - $this->module_ary[] = $module_row; - } - - unset($this->module_cache['modules'], $names); - } - - /** - * Check if a certain main module is accessible/loaded - * By giving the module mode you are able to additionally check for only one mode within the main module - * - * @param string $module_basename The module base name, for example logs, reports, main (for the mcp). - * @param mixed $module_mode The module mode to check. If provided the mode will be checked in addition for presence. - * - * @return bool Returns true if module is loaded and accessible, else returns false - */ - function loaded($module_basename, $module_mode = false) - { - if (!$this->is_full_class($module_basename)) - { - $module_basename = $this->p_class . '_' . $module_basename; - } - - if (empty($this->loaded_cache)) - { - $this->loaded_cache = array(); - - foreach ($this->module_ary as $row) - { - if (!$row['name']) - { - continue; - } - - if (!isset($this->loaded_cache[$row['name']])) - { - $this->loaded_cache[$row['name']] = array(); - } - - if (!$row['mode']) - { - continue; - } - - $this->loaded_cache[$row['name']][$row['mode']] = true; - } - } - - if ($module_mode === false) - { - return (isset($this->loaded_cache[$module_basename])) ? true : false; - } - - return (!empty($this->loaded_cache[$module_basename][$module_mode])) ? true : false; - } - - /** - * Check module authorisation. - * - * This is a non-static version that uses $this->acl_forum_id - * for the forum id. - */ - function module_auth_self($module_auth) - { - return self::module_auth($module_auth, $this->acl_forum_id); - } - - /** - * Check module authorisation. - * - * This is a static version, it must be given $forum_id. - * See also module_auth_self. - */ - static function module_auth($module_auth, $forum_id) - { - global $auth, $config; - global $request, $phpbb_extension_manager, $phpbb_dispatcher; - - $module_auth = trim($module_auth); - - // Generally allowed to access module if module_auth is empty - if (!$module_auth) - { - return true; - } - - // With the code below we make sure only those elements get eval'd we really want to be checked - preg_match_all('/(?: - "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | - \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | - [(),] | - [^\s(),]+)/x', $module_auth, $match); - - // Valid tokens for auth and their replacements - $valid_tokens = array( - 'acl_([a-z0-9_]+)(,\$id)?' => '(int) $auth->acl_get(\'\\1\'\\2)', - '\$id' => '(int) $forum_id', - 'aclf_([a-z0-9_]+)' => '(int) $auth->acl_getf_global(\'\\1\')', - 'cfg_([a-z0-9_]+)' => '(int) $config[\'\\1\']', - 'request_([a-zA-Z0-9_]+)' => '$request->variable(\'\\1\', false)', - 'ext_([a-zA-Z0-9_/]+)' => 'array_key_exists(\'\\1\', $phpbb_extension_manager->all_enabled())', - 'authmethod_([a-z0-9_\\\\]+)' => '($config[\'auth_method\'] === \'\\1\')', - ); - - /** - * Alter tokens for module authorisation check - * - * @event core.module_auth - * @var array valid_tokens Valid tokens and their auth check - * replacements - * @var string module_auth The module_auth of the current - * module - * @var int forum_id The current forum_id - * @since 3.1.0-a3 - */ - $vars = array('valid_tokens', 'module_auth', 'forum_id'); - extract($phpbb_dispatcher->trigger_event('core.module_auth', compact($vars))); - - $tokens = $match[0]; - for ($i = 0, $size = count($tokens); $i < $size; $i++) - { - $token = &$tokens[$i]; - - switch ($token) - { - case ')': - case '(': - case '&&': - case '||': - case ',': - break; - - default: - if (!preg_match('#(?:' . implode(')|(?:', array_keys($valid_tokens)) . ')#', $token)) - { - $token = ''; - } - break; - } - } - - $module_auth = implode(' ', $tokens); - - // Make sure $id separation is working fine - $module_auth = str_replace(' , ', ',', $module_auth); - - $module_auth = preg_replace( - // Array keys with # prepended/appended - array_map(function($value) { - return '#' . $value . '#'; - }, array_keys($valid_tokens)), - array_values($valid_tokens), - $module_auth - ); - - $is_auth = false; - // @codingStandardsIgnoreStart - eval('$is_auth = (int) (' . $module_auth . ');'); - // @codingStandardsIgnoreEnd - - return $is_auth; - } - - /** - * Set active module - */ - function set_active($id = false, $mode = false) - { - global $request; - - $icat = false; - $this->active_module = false; - - if ($request->variable('icat', '')) - { - $icat = $id; - $id = $request->variable('icat', ''); - } - - // Restore the backslashes in class names - if (strpos($id, '-') !== false) - { - $id = str_replace('-', '\\', $id); - } - - if ($id && !is_numeric($id) && !$this->is_full_class($id)) - { - $id = $this->p_class . '_' . $id; - } - - $category = false; - foreach ($this->module_ary as $row_id => $item_ary) - { - // If this is a module and it's selected, active - // If this is a category and the module is the first within it, active - // If this is a module and no mode selected, select first mode - // If no category or module selected, go active for first module in first category - if ( - (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (($item_ary['mode'] == $mode && !$item_ary['cat']) || ($icat && $item_ary['cat']))) || - ($item_ary['parent'] === $category && !$item_ary['cat'] && !$icat && $item_ary['display']) || - (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) || - (!$id && !$mode && !$item_ary['cat'] && $item_ary['display']) - ) - { - if ($item_ary['cat']) - { - $id = $icat; - $icat = false; - - continue; - } - - $this->p_id = $item_ary['id']; - $this->p_parent = $item_ary['parent']; - $this->p_name = $item_ary['name']; - $this->p_mode = $item_ary['mode']; - $this->p_left = $item_ary['left']; - $this->p_right = $item_ary['right']; - - $this->module_cache['parents'] = $this->module_cache['parents'][$this->p_id]; - $this->active_module = $item_ary['id']; - $this->active_module_row_id = $row_id; - - break; - } - else if (($item_ary['cat'] && $item_ary['id'] === (int) $id) || ($item_ary['parent'] === $category && $item_ary['cat'])) - { - $category = $item_ary['id']; - } - } - } - - /** - * Loads currently active module - * - * This method loads a given module, passing it the relevant id and mode. - * - * @param string|false $mode mode, as passed through to the module - * @param string|false $module_url If supplied, we use this module url - * @param bool $execute_module If true, at the end we execute the main method for the new instance - */ - function load_active($mode = false, $module_url = false, $execute_module = true) - { - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template, $request; - - $module_path = $this->include_path . $this->p_class; - $icat = $request->variable('icat', ''); - - if ($this->active_module === false) - { - trigger_error('MODULE_NOT_ACCESS', E_USER_ERROR); - } - - // new modules use the full class names, old ones are always called _, e.g. acp_board - if (!class_exists($this->p_name)) - { - if (!file_exists("$module_path/{$this->p_name}.$phpEx")) - { - trigger_error($user->lang('MODULE_NOT_FIND', "$module_path/{$this->p_name}.$phpEx"), E_USER_ERROR); - } - - include("$module_path/{$this->p_name}.$phpEx"); - - if (!class_exists($this->p_name)) - { - trigger_error($user->lang('MODULE_FILE_INCORRECT_CLASS', "$module_path/{$this->p_name}.$phpEx", $this->p_name), E_USER_ERROR); - } - } - - if (!empty($mode)) - { - $this->p_mode = $mode; - } - - // Create a new instance of the desired module ... - $class_name = $this->p_name; - - $this->module = new $class_name($this); - - // We pre-define the action parameter we are using all over the place - if (defined('IN_ADMIN')) - { - /* - * If this is an extension module, we'll try to automatically set - * the style paths for the extension (the ext author can change them - * if necessary). - */ - $module_dir = explode('\\', get_class($this->module)); - - // 0 vendor, 1 extension name, ... - if (isset($module_dir[1])) - { - $module_style_dir = $phpbb_root_path . 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/adm/style'; - - if (is_dir($module_style_dir)) - { - $template->set_custom_style(array( - array( - 'name' => 'adm', - 'ext_path' => 'adm/style/', - ), - ), array($module_style_dir, $phpbb_admin_path . 'style')); - } - } - - // Is first module automatically enabled a duplicate and the category not passed yet? - if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate']) - { - $icat = $this->module_ary[$this->active_module_row_id]['parent']; - } - - // Not being able to overwrite ;) - $this->module->u_action = append_sid("{$phpbb_admin_path}index.$phpEx", 'i=' . $this->get_module_identifier($this->p_name)) . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; - } - else - { - /* - * If this is an extension module, we'll try to automatically set - * the style paths for the extension (the ext author can change them - * if necessary). - */ - $module_dir = explode('\\', get_class($this->module)); - - // 0 vendor, 1 extension name, ... - if (isset($module_dir[1])) - { - $module_style_dir = 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/styles'; - - if (is_dir($phpbb_root_path . $module_style_dir)) - { - $template->set_style(array($module_style_dir, 'styles')); - } - } - - // If user specified the module url we will use it... - if ($module_url !== false) - { - $this->module->u_action = $module_url; - } - else - { - $this->module->u_action = $phpbb_root_path . (($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '') . $user->page['page_name']; - } - - $this->module->u_action = append_sid($this->module->u_action, 'i=' . $this->get_module_identifier($this->p_name)) . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; - } - - // Add url_extra parameter to u_action url - if (!empty($this->module_ary) && $this->active_module !== false && $this->module_ary[$this->active_module_row_id]['url_extra']) - { - $this->module->u_action .= $this->module_ary[$this->active_module_row_id]['url_extra']; - } - - // Assign the module path for re-usage - $this->module->module_path = $module_path . '/'; - - // Execute the main method for the new instance, we send the module id and mode as parameters - // Users are able to call the main method after this function to be able to assign additional parameters manually - if ($execute_module) - { - $short_name = preg_replace("#^{$this->p_class}_#", '', $this->p_name); - $this->module->main($short_name, $this->p_mode); - } - } - - /** - * Appending url parameter to the currently active module. - * - * This function is called for adding specific url parameters while executing the current module. - * It is doing the same as the _module_{name}_url() function, apart from being able to be called after - * having dynamically parsed specific parameters. This allows more freedom in choosing additional parameters. - * One example can be seen in /includes/mcp/mcp_notes.php - $this->p_master->adjust_url() call. - * - * @param string $url_extra Extra url parameters, e.g.: &u=$user_id - * - */ - function adjust_url($url_extra) - { - if (empty($this->module_ary[$this->active_module_row_id])) - { - return; - } - - $row = &$this->module_ary[$this->active_module_row_id]; - - // We check for the same url_extra in $row['url_extra'] to overcome doubled additions... - if (strpos($row['url_extra'], $url_extra) === false) - { - $row['url_extra'] .= $url_extra; - } - } - - /** - * Check if a module is active - */ - function is_active($id, $mode = false) - { - // If we find a name by this id and being enabled we have our active one... - foreach ($this->module_ary as $row_id => $item_ary) - { - if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && $item_ary['display'] || $item_ary['name'] === $this->p_class . '_' . $id) - { - if ($mode === false || $mode === $item_ary['mode']) - { - return true; - } - } - } - - return false; - } - - /** - * Get parents - */ - function get_parents($parent_id, $left_id, $right_id, &$all_parents) - { - $parents = array(); - - if ($parent_id > 0) - { - foreach ($all_parents as $module_id => $row) - { - if ($row['left_id'] < $left_id && $row['right_id'] > $right_id) - { - $parents[$module_id] = $row['parent_id']; - } - - if ($row['left_id'] > $left_id) - { - break; - } - } - } - - return $parents; - } - - /** - * Get tree branch - */ - function get_branch($left_id, $right_id, $remaining) - { - $branch = array(); - - foreach ($remaining as $key => $row) - { - if ($row['left_id'] > $left_id && $row['left_id'] < $right_id) - { - $branch[] = $row; - continue; - } - break; - } - - return $branch; - } - - /** - * Build true binary tree from given array - * Not in use - */ - function build_tree(&$modules, &$parents) - { - $tree = array(); - - foreach ($modules as $row) - { - $branch = &$tree; - - if ($row['parent_id']) - { - // Go through the tree to find our branch - $parent_tree = $parents[$row['module_id']]; - - foreach ($parent_tree as $id => $value) - { - if (!isset($branch[$id]) && isset($branch['child'])) - { - $branch = &$branch['child']; - } - $branch = &$branch[$id]; - } - $branch = &$branch['child']; - } - - $branch[$row['module_id']] = $row; - if (!isset($branch[$row['module_id']]['child'])) - { - $branch[$row['module_id']]['child'] = array(); - } - } - - return $tree; - } - - /** - * Build navigation structure - */ - function assign_tpl_vars($module_url) - { - global $template; - - $current_id = $right_id = false; - - // Make sure the module_url has a question mark set, effectively determining the delimiter to use - $delim = (strpos($module_url, '?') === false) ? '?' : '&'; - - $current_depth = 0; - $linear_offset = 'l_block1'; - $tabular_offset = 't_block2'; - - // Generate the list of modules, we'll do this in two ways ... - // 1) In a linear fashion - // 2) In a combined tabbed + linear fashion ... tabs for the categories - // and a linear list for subcategories/items - foreach ($this->module_ary as $row_id => $item_ary) - { - // Skip hidden modules - if (!$item_ary['display']) - { - continue; - } - - // Skip branch - if ($right_id !== false) - { - if ($item_ary['left'] < $right_id) - { - continue; - } - - $right_id = false; - } - - // Category with no members on their way down (we have to check every level) - if (!$item_ary['name']) - { - $empty_category = true; - - // We go through the branch and look for an activated module - foreach (array_slice($this->module_ary, $row_id + 1) as $temp_row) - { - if ($temp_row['left'] > $item_ary['left'] && $temp_row['left'] < $item_ary['right']) - { - // Module there and displayed? - if ($temp_row['name'] && $temp_row['display']) - { - $empty_category = false; - break; - } - continue; - } - break; - } - - // Skip the branch - if ($empty_category) - { - $right_id = $item_ary['right']; - continue; - } - } - - // Select first id we can get - if (!$current_id && (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id)) - { - $current_id = $item_ary['id']; - } - - $depth = $item_ary['depth']; - - if ($depth > $current_depth) - { - $linear_offset = $linear_offset . '.l_block' . ($depth + 1); - $tabular_offset = ($depth + 1 > 2) ? $tabular_offset . '.t_block' . ($depth + 1) : $tabular_offset; - } - else if ($depth < $current_depth) - { - for ($i = $current_depth - $depth; $i > 0; $i--) - { - $linear_offset = substr($linear_offset, 0, strrpos($linear_offset, '.')); - $tabular_offset = ($i + $depth > 1) ? substr($tabular_offset, 0, strrpos($tabular_offset, '.')) : $tabular_offset; - } - } - - $u_title = $module_url . $delim . 'i='; - // if the item has a name use it, else use its id - if (empty($item_ary['name'])) - { - $u_title .= $item_ary['id']; - } - else - { - // if the category has a name, then use it. - $u_title .= $this->get_module_identifier($item_ary['name']); - } - // If the item is not a category append the mode - if (!$item_ary['cat']) - { - if ($item_ary['is_duplicate']) - { - $u_title .= '&icat=' . $current_id; - } - $u_title .= '&mode=' . $item_ary['mode']; - } - - // Was not allowed in categories before - /*!$item_ary['cat'] && */ - $u_title .= (isset($item_ary['url_extra'])) ? $item_ary['url_extra'] : ''; - - // Only output a categories items if it's currently selected - if (!$depth || ($depth && (in_array($item_ary['parent'], array_values($this->module_cache['parents'])) || $item_ary['parent'] == $this->p_parent))) - { - $use_tabular_offset = (!$depth) ? 't_block1' : $tabular_offset; - - $tpl_ary = array( - 'L_TITLE' => $item_ary['lang'], - 'S_SELECTED' => (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) ? true : false, - 'U_TITLE' => $u_title - ); - - if (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) - { - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $item_ary['lang'], - 'U_BREADCRUMB' => $u_title, - )); - } - - $template->assign_block_vars($use_tabular_offset, array_merge($tpl_ary, array_change_key_case($item_ary, CASE_UPPER))); - } - - $tpl_ary = array( - 'L_TITLE' => $item_ary['lang'], - 'S_SELECTED' => (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) ? true : false, - 'U_TITLE' => $u_title - ); - - $template->assign_block_vars($linear_offset, array_merge($tpl_ary, array_change_key_case($item_ary, CASE_UPPER))); - - $current_depth = $depth; - } - } - - /** - * Returns desired template name - */ - function get_tpl_name() - { - return $this->module->tpl_name . '.html'; - } - - /** - * Returns the desired page title - */ - function get_page_title() - { - global $user; - - if (!isset($this->module->page_title)) - { - return ''; - } - - return (isset($user->lang[$this->module->page_title])) ? $user->lang[$this->module->page_title] : $this->module->page_title; - } - - /** - * Load module as the current active one without the need for registering it - * - * @param string $class module class (acp/mcp/ucp) - * @param string $name module name (class name of the module, or its basename - * phpbb_ext_foo_acp_bar_module, ucp_zebra or zebra) - * @param string $mode mode, as passed through to the module - * - */ - function load($class, $name, $mode = false) - { - // new modules use the full class names, old ones are always called _, e.g. acp_board - // in the latter case this function may be called as load('acp', 'board') - if (!class_exists($name) && substr($name, 0, strlen($class) + 1) !== $class . '_') - { - $name = $class . '_' . $name; - } - - $this->p_class = $class; - $this->p_name = $name; - - // Set active module to true instead of using the id - $this->active_module = true; - - $this->load_active($mode); - } - - /** - * Display module - */ - function display($page_title, $display_online_list = false) - { - global $template, $user; - - // Generate the page - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_header($page_title); - } - else - { - page_header($page_title, $display_online_list); - } - - $template->set_filenames(array( - 'body' => $this->get_tpl_name()) - ); - - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_footer(); - } - else - { - page_footer(); - } - } - - /** - * Toggle whether this module will be displayed or not - */ - function set_display($id, $mode = false, $display = true) - { - foreach ($this->module_ary as $row_id => $item_ary) - { - if (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (!$mode || $item_ary['mode'] === $mode)) - { - $this->module_ary[$row_id]['display'] = (int) $display; - } - } - } - - /** - * Add custom MOD info language file - */ - function add_mod_info($module_class) - { - global $config, $user, $phpEx, $phpbb_extension_manager; - - $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('info_' . strtolower($module_class) . '_') - ->suffix(".$phpEx") - ->extension_directory('/language/' . basename($config['default_lang'])) - ->core_path('language/' . basename($config['default_lang']) . '/mods/') - ->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('info_' . strtolower($module_class) . '_') - ->suffix(".$phpEx") - ->extension_directory('/language/en') - ->core_path('language/en/mods/') - ->find(); - } - - // Find files in the user's language - $user_lang_files = $finder - ->prefix('info_' . strtolower($module_class) . '_') - ->suffix(".$phpEx") - ->extension_directory('/language/' . $user->lang_name) - ->core_path('language/' . $user->lang_name . '/mods/') - ->find(); - - $lang_files = array_merge($english_lang_files, $default_lang_files, $user_lang_files); - foreach ($lang_files as $lang_file => $ext_name) - { - $user->add_lang_ext($ext_name, $lang_file); - } - } - - /** - * Retrieve shortened module basename for legacy basenames (with xcp_ prefix) - * - * @param string $basename A module basename - * @return string The basename if it starts with phpbb_ or the basename with - * the current p_class (e.g. acp_) stripped. - */ - protected function get_short_name($basename) - { - if (substr($basename, 0, 6) === 'phpbb\\' || strpos($basename, '\\') !== false) - { - return $basename; - } - - // strip xcp_ prefix from old classes - return substr($basename, strlen($this->p_class) + 1); - } - - /** - * If the basename contains a \ we don't use that for the URL. - * - * Firefox is currently unable to correctly copy a urlencoded \ - * so users will be unable to post links to modules. - * However we can replace them with dashes and re-replace them later - * - * @param string $basename Basename of the module - * @return string Identifier that should be used for - * module link creation - */ - protected function get_module_identifier($basename) - { - if (strpos($basename, '\\') === false) - { - return $basename; - } - - return str_replace('\\', '-', $basename); - } - - /** - * Checks whether the given module basename is a correct class name - * - * @param string $basename A module basename - * @return bool True if the basename starts with phpbb_ or (x)cp_, false otherwise - */ - protected function is_full_class($basename) - { - return (strpos($basename, '\\') !== false || preg_match('/^(ucp|mcp|acp)_/', $basename)); - } -} diff --git a/install/update/new/includes/functions_posting.php b/install/update/new/includes/functions_posting.php deleted file mode 100644 index 45eda4b..0000000 --- a/install/update/new/includes/functions_posting.php +++ /dev/null @@ -1,2804 +0,0 @@ - -* @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; -} - -/** -* Fill smiley templates (or just the variables) with smilies, either in a window or inline -*/ -function generate_smilies($mode, $forum_id) -{ - global $db, $user, $config, $template, $phpbb_dispatcher, $request; - global $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_path_helper; - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id); - $start = $request->variable('start', 0); - - if ($mode == 'window') - { - if ($forum_id) - { - $sql = 'SELECT forum_style - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $user->setup('posting', (int) $row['forum_style']); - } - else - { - $user->setup('posting'); - } - - page_header($user->lang['SMILIES']); - - $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; - while ($row = $db->sql_fetchrow($result)) - { - ++$smiley_count; - } - $db->sql_freeresult($result); - - $template->set_filenames(array( - 'body' => 'posting_smilies.html') - ); - - $start = $pagination->validate_start($start, $config['smilies_per_page'], $smiley_count); - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $smiley_count, $config['smilies_per_page'], $start); - } - - $display_link = false; - if ($mode == 'inline') - { - $sql = 'SELECT smiley_id - FROM ' . SMILIES_TABLE . ' - WHERE display_on_posting = 0'; - $result = $db->sql_query_limit($sql, 1, 0, 3600); - - if ($row = $db->sql_fetchrow($result)) - { - $display_link = true; - } - $db->sql_freeresult($result); - } - - if ($mode == 'window') - { - $sql = 'SELECT smiley_url, MIN(emotion) as emotion, MIN(code) AS code, smiley_width, smiley_height, MIN(smiley_order) AS min_smiley_order - FROM ' . SMILIES_TABLE . ' - GROUP BY smiley_url, smiley_width, smiley_height - ORDER BY min_smiley_order'; - $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $start, 3600); - } - else - { - $sql = 'SELECT * - FROM ' . SMILIES_TABLE . ' - WHERE display_on_posting = 1 - ORDER BY smiley_order'; - $result = $db->sql_query($sql, 3600); - } - - $smilies = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (empty($smilies[$row['smiley_url']])) - { - $smilies[$row['smiley_url']] = $row; - } - } - $db->sql_freeresult($result); - - /** - * 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(); - - foreach ($smilies as $row) - { - /** - * Modify smiley root path before populating smiley list - * - * @event core.generate_smilies_before - * @var string root_path root_path for smilies - * @since 3.1.11-RC1 - */ - $vars = array('root_path'); - extract($phpbb_dispatcher->trigger_event('core.generate_smilies_before', compact($vars))); - $template->assign_block_vars('smiley', array( - 'SMILEY_CODE' => $row['code'], - 'A_SMILEY_CODE' => addslashes($row['code']), - 'SMILEY_IMG' => $root_path . $config['smilies_path'] . '/' . $row['smiley_url'], - 'SMILEY_WIDTH' => $row['smiley_width'], - 'SMILEY_HEIGHT' => $row['smiley_height'], - 'SMILEY_DESC' => $row['emotion']) - ); - } - } - - /** - * This event is called after the smilies are populated - * - * @event core.generate_smilies_after - * @var string mode Mode of the smilies: window|inline - * @var int forum_id The forum ID we are currently in - * @var bool display_link Shall we display the "more smilies" link? - * @since 3.1.0-a1 - */ - $vars = array('mode', 'forum_id', 'display_link'); - extract($phpbb_dispatcher->trigger_event('core.generate_smilies_after', compact($vars))); - - if ($mode == 'inline' && $display_link) - { - $template->assign_vars(array( - 'S_SHOW_SMILEY_LINK' => true, - 'U_MORE_SMILIES' => $base_url, - )); - } - - if ($mode == 'window') - { - page_footer(); - } -} - -/** -* Update last post information -* Should be used instead of sync() if only the last post information are out of sync... faster -* -* @param string $type Can be forum|topic -* @param mixed $ids topic/forum ids -* @param bool $return_update_sql true: SQL query shall be returned, false: execute SQL -*/ -function update_post_information($type, $ids, $return_update_sql = false) -{ - global $db; - - if (empty($ids)) - { - return; - } - if (!is_array($ids)) - { - $ids = array($ids); - } - - $update_sql = $empty_forums = $not_empty_forums = array(); - - if ($type != 'topic') - { - $topic_join = ', ' . TOPICS_TABLE . ' t'; - $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_visibility = ' . ITEM_APPROVED; - } - else - { - $topic_join = ''; - $topic_condition = ''; - } - - if (count($ids) == 1) - { - $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 . " - ORDER BY p.post_id DESC"; - $result = $db->sql_query_limit($sql, 1); - } - else - { - $sql = 'SELECT p.' . $type . '_id, MAX(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 . " - GROUP BY p.{$type}_id"; - $result = $db->sql_query($sql); - } - - $last_post_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (count($ids) == 1) - { - $row[$type . '_id'] = $ids[0]; - } - - if ($type == 'forum') - { - $not_empty_forums[] = $row['forum_id']; - - if (empty($row['last_post_id'])) - { - $empty_forums[] = $row['forum_id']; - } - } - - $last_post_ids[] = $row['last_post_id']; - } - $db->sql_freeresult($result); - - if ($type == 'forum') - { - $empty_forums = array_merge($empty_forums, array_diff($ids, $not_empty_forums)); - - foreach ($empty_forums as $void => $forum_id) - { - $update_sql[$forum_id][] = 'forum_last_post_id = 0'; - $update_sql[$forum_id][] = "forum_last_post_subject = ''"; - $update_sql[$forum_id][] = 'forum_last_post_time = 0'; - $update_sql[$forum_id][] = 'forum_last_poster_id = 0'; - $update_sql[$forum_id][] = "forum_last_poster_name = ''"; - $update_sql[$forum_id][] = "forum_last_poster_colour = ''"; - } - } - - 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 - WHERE p.poster_id = u.user_id - AND ' . $db->sql_in_set('p.post_id', $last_post_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $update_sql[$row["{$type}_id"]][] = $type . '_last_post_id = ' . (int) $row['post_id']; - $update_sql[$row["{$type}_id"]][] = "{$type}_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'"; - $update_sql[$row["{$type}_id"]][] = $type . '_last_post_time = ' . (int) $row['post_time']; - $update_sql[$row["{$type}_id"]][] = $type . '_last_poster_id = ' . (int) $row['poster_id']; - $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'"; - $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'"; - } - $db->sql_freeresult($result); - } - unset($empty_forums, $ids, $last_post_ids); - - if ($return_update_sql || !count($update_sql)) - { - return $update_sql; - } - - $table = ($type == 'forum') ? FORUMS_TABLE : TOPICS_TABLE; - - foreach ($update_sql as $update_id => $update_sql_ary) - { - $sql = "UPDATE $table - SET " . implode(', ', $update_sql_ary) . " - WHERE {$type}_id = $update_id"; - $db->sql_query($sql); - } - - return; -} - -/** -* Generate Topic Icons for display -*/ -function posting_gen_topic_icons($mode, $icon_id) -{ - global $phpbb_root_path, $config, $template, $cache; - - // Grab icons - $icons = $cache->obtain_icons(); - - if (!$icon_id) - { - $template->assign_var('S_NO_ICON_CHECKED', ' checked="checked"'); - } - - if (count($icons)) - { - $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; - - foreach ($icons as $id => $data) - { - if ($data['display']) - { - $template->assign_block_vars('topic_icon', array( - 'ICON_ID' => $id, - '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"' : '') - ); - } - } - - return true; - } - - return false; -} - -/** -* Build topic types able to be selected -*/ -function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL) -{ - 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'), - 'announce_global' => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL') - ); - - $topic_type_array = array(); - - foreach ($topic_types as $auth_key => $topic_value) - { - if ($auth->acl_get('f_' . $auth_key, $forum_id)) - { - $toggle = true; - - $topic_type_array[] = array( - 'VALUE' => $topic_value['const'], - 'S_CHECKED' => ($cur_topic_type == $topic_value['const']) ? ' checked="checked"' : '', - 'L_TOPIC_TYPE' => $user->lang[$topic_value['lang']] - ); - } - } - - if ($toggle) - { - $topic_type_array = array_merge(array(0 => array( - 'VALUE' => POST_NORMAL, - 'S_CHECKED' => ($cur_topic_type == POST_NORMAL) ? ' checked="checked"' : '', - 'L_TOPIC_TYPE' => $user->lang['POST_NORMAL'])), - - $topic_type_array - ); - - foreach ($topic_type_array as $array) - { - $template->assign_block_vars('topic_type', $array); - } - - $template->assign_vars(array( - 'S_TOPIC_TYPE_STICKY' => ($auth->acl_get('f_sticky', $forum_id)), - 'S_TOPIC_TYPE_ANNOUNCE' => ($auth->acl_gets('f_announce', 'f_announce_global', $forum_id)), - )); - } - - return $toggle; -} - -// -// Attachment related functions -// -/** -* Calculate the needed size for Thumbnail -*/ -function get_img_size_format($width, $height) -{ - global $config; - - // Maximum Width the Image can take - $max_width = ($config['img_max_thumb_width']) ? $config['img_max_thumb_width'] : 400; - - if ($width > $height) - { - return array( - round($width * ($max_width / $width)), - round($height * ($max_width / $width)) - ); - } - else - { - return array( - round($width * ($max_width / $height)), - round($height * ($max_width / $height)) - ); - } -} - -/** -* Return supported image types -*/ -function get_supported_image_types($type = false) -{ - if (@extension_loaded('gd')) - { - $format = imagetypes(); - $new_type = 0; - - if ($type !== false) - { - // Type is one of the IMAGETYPE constants - it is fetched from getimagesize() - switch ($type) - { - // GIF - case IMAGETYPE_GIF: - $new_type = ($format & IMG_GIF) ? IMG_GIF : false; - break; - - // JPG, JPC, JP2 - case IMAGETYPE_JPEG: - case IMAGETYPE_JPC: - case IMAGETYPE_JPEG2000: - case IMAGETYPE_JP2: - case IMAGETYPE_JPX: - case IMAGETYPE_JB2: - $new_type = ($format & IMG_JPG) ? IMG_JPG : false; - break; - - // PNG - case IMAGETYPE_PNG: - $new_type = ($format & IMG_PNG) ? IMG_PNG : false; - break; - - // WBMP - case IMAGETYPE_WBMP: - $new_type = ($format & IMG_WBMP) ? IMG_WBMP : false; - break; - } - } - else - { - $new_type = array(); - $go_through_types = array(IMG_GIF, IMG_JPG, IMG_PNG, IMG_WBMP); - - foreach ($go_through_types as $check_type) - { - if ($format & $check_type) - { - $new_type[] = $check_type; - } - } - } - - return array( - 'gd' => ($new_type) ? true : false, - 'format' => $new_type, - 'version' => (function_exists('imagecreatetruecolor')) ? 2 : 1 - ); - } - - return array('gd' => false); -} - -/** -* Create Thumbnail -*/ -function create_thumbnail($source, $destination, $mimetype) -{ - global $config, $phpbb_filesystem, $phpbb_dispatcher; - - $min_filesize = (int) $config['img_min_thumb_filesize']; - $img_filesize = (file_exists($source)) ? @filesize($source) : false; - - if (!$img_filesize || $img_filesize <= $min_filesize) - { - return false; - } - - $dimension = @getimagesize($source); - - if ($dimension === false) - { - return false; - } - - list($width, $height, $type, ) = $dimension; - - if (empty($width) || empty($height)) - { - return false; - } - - list($new_width, $new_height) = get_img_size_format($width, $height); - - // Do not create a thumbnail if the resulting width/height is bigger than the original one - if ($new_width >= $width && $new_height >= $height) - { - return false; - } - - $thumbnail_created = false; - - /** - * 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 (!$thumbnail_created) - { - $type = get_supported_image_types($type); - - if ($type['gd']) - { - // If the type is not supported, we are not able to create a thumbnail - if ($type['format'] === false) - { - return false; - } - - switch ($type['format']) - { - case IMG_GIF: - $image = @imagecreatefromgif($source); - break; - - case IMG_JPG: - @ini_set('gd.jpeg_ignore_warning', 1); - $image = @imagecreatefromjpeg($source); - break; - - case IMG_PNG: - $image = @imagecreatefrompng($source); - break; - - case IMG_WBMP: - $image = @imagecreatefromwbmp($source); - break; - } - - if (empty($image)) - { - return false; - } - - if ($type['version'] == 1) - { - $new_image = imagecreate($new_width, $new_height); - - if ($new_image === false) - { - return false; - } - - imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); - } - else - { - $new_image = imagecreatetruecolor($new_width, $new_height); - - if ($new_image === false) - { - return false; - } - - // Preserve alpha transparency (png for example) - @imagealphablending($new_image, false); - @imagesavealpha($new_image, true); - - imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); - } - - switch ($type['format']) - { - case IMG_GIF: - imagegif($new_image, $destination); - break; - - case IMG_JPG: - imagejpeg($new_image, $destination, 90); - break; - - case IMG_PNG: - imagepng($new_image, $destination); - break; - - case IMG_WBMP: - imagewbmp($new_image, $destination); - break; - } - - imagedestroy($new_image); - } - else - { - return false; - } - } - - if (!file_exists($destination)) - { - return false; - } - - try - { - $phpbb_filesystem->phpbb_chmod($destination, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - - return true; -} - -/** -* Assign Inline attachments (build option fields) -*/ -function posting_gen_inline_attachments(&$attachment_data) -{ - global $template; - - if (count($attachment_data)) - { - $s_inline_attachment_options = ''; - - foreach ($attachment_data as $i => $attachment) - { - $s_inline_attachment_options .= ''; - } - - $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options); - - return true; - } - - return false; -} - -/** -* Generate inline attachment entry -*/ -function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true) -{ - 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' => count($attachment_data), - 'FILESIZE' => $config['max_filesize'], - 'FILE_COMMENT' => (isset($filename_data['filecomment'])) ? $filename_data['filecomment'] : '', - )); - - 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 = ''; - $attach_row['real_filename'] = utf8_basename($attach_row['real_filename']); - - foreach ($attach_row as $key => $value) - { - $hidden .= ''; - } - - $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&id=' . (int) $attach_row['attach_id'], true, ($attach_row['is_orphan']) ? $user->session_id : false); - - $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'], - 'ATTACH_ID' => $attach_row['attach_id'], - 'S_IS_ORPHAN' => $attach_row['is_orphan'], - 'ASSOC_INDEX' => $count, - 'FILESIZE' => get_formatted_filesize($attach_row['filesize']), - - 'U_VIEW_ATTACHMENT' => $download_link, - '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 count($attachment_data); -} - -// -// General Post functions -// - -/** -* Load Drafts -*/ -function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $msg_id = 0) -{ - global $user, $db, $template, $auth; - global $phpbb_root_path, $phpbb_dispatcher, $phpEx; - - $topic_ids = $forum_ids = $draft_rows = array(); - - // Load those drafts not connected to forums/topics - // If forum_id == 0 AND topic_id == 0 then this is a PM draft - if (!$topic_id && !$forum_id) - { - $sql_and = ' AND d.forum_id = 0 AND d.topic_id = 0'; - } - else - { - $sql_and = ''; - $sql_and .= ($forum_id) ? ' AND d.forum_id = ' . (int) $forum_id : ''; - $sql_and .= ($topic_id) ? ' AND d.topic_id = ' . (int) $topic_id : ''; - } - - $sql = 'SELECT d.*, f.forum_id, f.forum_name - FROM ' . DRAFTS_TABLE . ' d - LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = d.forum_id) - WHERE d.user_id = ' . $user->data['user_id'] . " - $sql_and - ORDER BY d.save_time DESC"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_id']) - { - $topic_ids[] = (int) $row['topic_id']; - } - $draft_rows[] = $row; - } - $db->sql_freeresult($result); - - if (!count($draft_rows)) - { - return; - } - - $topic_rows = array(); - if (count($topic_ids)) - { - $sql = 'SELECT topic_id, forum_id, topic_title, topic_poster - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', array_unique($topic_ids)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_rows[$row['topic_id']] = $row; - } - $db->sql_freeresult($result); - } - - /** - * Drafts found and their topics - * Edit $draft_rows in order to add or remove drafts loaded - * - * @event core.load_drafts_draft_list_result - * @var array draft_rows The drafts query result. Includes its forum id and everything about the draft - * @var array topic_ids The list of topics got from the topics table - * @var array topic_rows The topics that draft_rows references - * @since 3.1.0-RC3 - */ - $vars = array('draft_rows', 'topic_ids', 'topic_rows'); - extract($phpbb_dispatcher->trigger_event('core.load_drafts_draft_list_result', compact($vars))); - - unset($topic_ids); - - $template->assign_var('S_SHOW_DRAFTS', true); - - foreach ($draft_rows as $draft) - { - $link_topic = $link_forum = $link_pm = false; - $view_url = $title = ''; - - if (isset($topic_rows[$draft['topic_id']]) - && ( - ($topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_get('f_read', $topic_rows[$draft['topic_id']]['forum_id'])) - || - (!$topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_getf_global('f_read')) - )) - { - $topic_forum_id = ($topic_rows[$draft['topic_id']]['forum_id']) ? $topic_rows[$draft['topic_id']]['forum_id'] : $forum_id; - - $link_topic = true; - $view_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_forum_id . '&t=' . $draft['topic_id']); - $title = $topic_rows[$draft['topic_id']]['topic_title']; - - $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $topic_forum_id . '&t=' . $draft['topic_id'] . '&mode=reply&d=' . $draft['draft_id']); - } - else if ($draft['forum_id'] && $auth->acl_get('f_read', $draft['forum_id'])) - { - $link_forum = true; - $view_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $draft['forum_id']); - $title = $draft['forum_name']; - - $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $draft['forum_id'] . '&mode=post&d=' . $draft['draft_id']); - } - else - { - // Either display as PM draft if forum_id and topic_id are empty or if access to the forums has been denied afterwards... - $link_pm = true; - $insert_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=compose&d={$draft['draft_id']}" . (($pm_action) ? "&action=$pm_action" : '') . (($msg_id) ? "&p=$msg_id" : '')); - } - - $template->assign_block_vars('draftrow', array( - 'DRAFT_ID' => $draft['draft_id'], - 'DATE' => $user->format_date($draft['save_time']), - 'DRAFT_SUBJECT' => $draft['draft_subject'], - - 'TITLE' => $title, - 'U_VIEW' => $view_url, - 'U_INSERT' => $insert_url, - - 'S_LINK_PM' => $link_pm, - 'S_LINK_TOPIC' => $link_topic, - 'S_LINK_FORUM' => $link_forum) - ); - } -} - -/** -* Topic Review -*/ -function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true) -{ - 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'; - - // Go ahead and pull all data for this topic - $sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p' . " - WHERE p.topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . ' - ' . (($mode == 'post_review') ? " AND p.post_id > $cur_post_id" : '') . ' - ' . (($mode == 'post_review_edit') ? " AND p.post_id = $cur_post_id" : '') . ' - ORDER BY p.post_time ' . $sql_sort . ', p.post_id ' . $sql_sort; - $result = $db->sql_query_limit($sql, $config['posts_per_page']); - - $post_list = array(); - - while ($row = $db->sql_fetchrow($result)) - { - $post_list[] = $row['post_id']; - } - - $db->sql_freeresult($result); - - if (!count($post_list)) - { - return false; - } - - // Handle 'post_review_edit' like 'post_review' from now on - if ($mode == 'post_review_edit') - { - $mode = 'post_review'; - } - - $sql_ary = array( - 'SELECT' => 'u.username, u.user_id, u.user_colour, p.*, z.friend, z.foe, uu.username as post_delete_username, uu.user_colour as post_delete_user_colour', - - 'FROM' => array( - USERS_TABLE => 'u', - POSTS_TABLE => 'p', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ZEBRA_TABLE => 'z'), - 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id', - ), - array( - 'FROM' => array(USERS_TABLE => 'uu'), - 'ON' => 'uu.user_id = p.post_delete_user', - ), - ), - - 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . ' - 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); - - $rowset = array(); - $has_attachments = false; - while ($row = $db->sql_fetchrow($result)) - { - $rowset[$row['post_id']] = $row; - - if ($row['post_attachment']) - { - $has_attachments = true; - } - } - $db->sql_freeresult($result); - - // Grab extensions - $attachments = array(); - if ($has_attachments && $auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id)) - { - // Get attachments... - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $post_list) . ' - AND in_message = 0 - ORDER BY filetime DESC, post_msg_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $attachments[$row['post_msg_id']][] = $row; - } - $db->sql_freeresult($result); - } - - /** - * Event to modify the posts list for topic reviews - * - * @event core.topic_review_modify_post_list - * @var array attachments Array with the post attachments data - * @var int cur_post_id Post offset ID - * @var int forum_id The topic's forum ID - * @var string mode The topic review mode - * @var array post_list Array with the post IDs - * @var array rowset Array with the posts data - * @var bool show_quote_button Flag indicating if the quote button should be displayed - * @var int topic_id The topic ID that is being reviewed - * @since 3.1.9-RC1 - */ - $vars = array( - 'attachments', - 'cur_post_id', - 'forum_id', - 'mode', - 'post_list', - 'rowset', - 'show_quote_button', - 'topic_id', - ); - extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_post_list', compact($vars))); - - 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. - if (!isset($rowset[$post_list[$i]])) - { - continue; - } - - $row = $rowset[$post_list[$i]]; - - $poster_id = $row['user_id']; - $post_subject = $row['post_subject']; - - $decoded_message = false; - - if ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) - { - $decoded_message = censor_text($row['post_text']); - decode_message($decoded_message, $row['bbcode_uid']); - - $decoded_message = bbcode_nl2br($decoded_message); - } - - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); - $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0); - $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true); - - if (!empty($attachments[$row['post_id']])) - { - $update_count = array(); - parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count); - } - - $post_subject = censor_text($post_subject); - - $post_anchor = ($mode == 'post_review') ? 'ppr' . $row['post_id'] : 'pr' . $row['post_id']; - $u_show_post = append_sid($phpbb_root_path . 'viewtopic.' . $phpEx, "f=$forum_id&t=$topic_id&p={$row['post_id']}&view=show#p{$row['post_id']}"); - - $l_deleted_message = ''; - if ($row['post_visibility'] == ITEM_DELETED) - { - $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); - - // User having deleted the post also being the post author? - if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id) - { - $display_username = $display_postername; - } - else - { - $display_username = get_username_string('full', $row['post_delete_user'], $row['post_delete_username'], $row['post_delete_user_colour']); - } - - if ($row['post_delete_reason']) - { - $l_deleted_message = $user->lang('POST_DELETED_BY_REASON', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true), $row['post_delete_reason']); - } - else - { - $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true)); - } - } - - $post_row = array( - 'POST_AUTHOR_FULL' => get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - - 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false, - 'S_FRIEND' => ($row['friend']) ? 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']), "", '') : '', - 'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED) ? true : false, - 'L_DELETE_POST' => $l_deleted_message, - - 'POST_SUBJECT' => $post_subject, - 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['POST']), - 'POST_DATE' => $user->format_date($row['post_time']), - '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&mode=post_details&f=' . $forum_id . '&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'])) : '', - ); - - $current_row_number = $i; - - /** - * Event to modify the template data block for topic reviews - * - * @event core.topic_review_modify_row - * @var string mode The review mode - * @var int topic_id The topic that is being reviewed - * @var int forum_id The topic's forum - * @var int cur_post_id Post offset id - * @var int current_row_number Number of the current row being iterated - * @var array post_row Template block array of the current post - * @var array row Array with original post and user data - * @since 3.1.4-RC1 - */ - $vars = array( - 'mode', - 'topic_id', - 'forum_id', - 'cur_post_id', - 'current_row_number', - 'post_row', - 'row', - ); - extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_row', compact($vars))); - - $template->assign_block_vars($mode . '_row', $post_row); - - // Display not already displayed Attachments for this post, we already parsed them. ;) - if (!empty($attachments[$row['post_id']])) - { - foreach ($attachments[$row['post_id']] as $attachment) - { - $template->assign_block_vars($mode . '_row.attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - } - - unset($rowset[$post_list[$i]]); - } - - if ($mode == 'topic_review') - { - $template->assign_var('QUOTE_IMG', $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE'])); - } - - return true; -} - -// -// Post handling functions -// - -/** -* Delete Post -*/ -function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '') -{ - global $db, $user, $phpbb_container, $phpbb_dispatcher; - global $config, $phpEx, $phpbb_root_path; - - // Specify our post mode - $post_mode = 'delete'; - if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1)) - { - $post_mode = 'delete_topic'; - } - else if ($data['topic_first_post_id'] == $post_id) - { - $post_mode = 'delete_first_post'; - } - else if ($data['topic_last_post_id'] == $post_id) - { - $post_mode = 'delete_last_post'; - } - $sql_data = array(); - $next_post_id = false; - - include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - - $db->sql_transaction('begin'); - - // we must make sure to update forums that contain the shadow'd topic - if ($post_mode == 'delete_topic') - { - $shadow_forum_ids = array(); - - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_moved_id', $topic_id); - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($shadow_forum_ids[(int) $row['forum_id']])) - { - $shadow_forum_ids[(int) $row['forum_id']] = 1; - } - else - { - $shadow_forum_ids[(int) $row['forum_id']]++; - } - } - $db->sql_freeresult($result); - } - - /* @var $phpbb_content_visibility \phpbb\content_visibility */ - $phpbb_content_visibility = $phpbb_container->get('content.visibility'); - - // (Soft) delete the post - if ($is_soft && ($post_mode != 'delete_topic')) - { - $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $post_id, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason, ($data['topic_first_post_id'] == $post_id), ($data['topic_last_post_id'] == $post_id)); - } - else if (!$is_soft) - { - if (!delete_posts('post_id', array($post_id), false, false, false)) - { - // Try to delete topic, we may had an previous error causing inconsistency - if ($post_mode == 'delete_topic') - { - delete_topics('topic_id', array($topic_id), false); - } - trigger_error('ALREADY_DELETED'); - } - } - - $db->sql_transaction('commit'); - - // Collect the necessary information for updating the tables - $sql_data[FORUMS_TABLE] = $sql_data[TOPICS_TABLE] = ''; - switch ($post_mode) - { - case 'delete_topic': - - foreach ($shadow_forum_ids as $updated_forum => $topic_count) - { - // 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 . ' - WHERE forum_id = ' . $updated_forum; - $db->sql_query($sql); - update_post_information('forum', $updated_forum); - } - - if ($is_soft) - { - $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason); - } - else - { - delete_topics('topic_id', array($topic_id), false); - - $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 (count($update_sql)) - { - $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : ''; - $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]); - } - } - - break; - - case 'delete_first_post': - $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE p.topic_id = $topic_id - AND p.poster_id = u.user_id - AND p.post_visibility = " . ITEM_APPROVED . ' - ORDER BY p.post_time ASC, p.post_id ASC'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - // No approved post, so the first is a not-approved post (unapproved or soft deleted) - $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE p.topic_id = $topic_id - AND p.poster_id = u.user_id - ORDER BY p.post_time ASC, p.post_id ASC"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - $next_post_id = (int) $row['post_id']; - - $sql_data[TOPICS_TABLE] = $db->sql_build_array('UPDATE', array( - 'topic_poster' => (int) $row['poster_id'], - 'topic_first_post_id' => (int) $row['post_id'], - 'topic_first_poster_colour' => $row['user_colour'], - 'topic_first_poster_name' => ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'], - 'topic_time' => (int) $row['post_time'], - )); - break; - - case 'delete_last_post': - if (!$is_soft) - { - // Update last post information when hard deleting. Soft delete already did that by itself. - $update_sql = update_post_information('forum', $forum_id, true); - if (count($update_sql)) - { - $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . implode(', ', $update_sql[$forum_id]); - } - - $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_bumped = 0, topic_bumper = 0'; - - $update_sql = update_post_information('topic', $topic_id, true); - if (!empty($update_sql)) - { - $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]); - $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]); - } - } - - if (!$next_post_id) - { - $sql = 'SELECT MAX(post_id) as last_post_id - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id); - $result = $db->sql_query($sql); - $next_post_id = (int) $db->sql_fetchfield('last_post_id'); - $db->sql_freeresult($result); - } - break; - - case 'delete': - $sql = 'SELECT post_id - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . ' - AND post_time > ' . $data['post_time'] . ' - ORDER BY post_time ASC, post_id ASC'; - $result = $db->sql_query_limit($sql, 1); - $next_post_id = (int) $db->sql_fetchfield('post_id'); - $db->sql_freeresult($result); - break; - } - - if (($post_mode == 'delete') || ($post_mode == 'delete_last_post') || ($post_mode == 'delete_first_post')) - { - if (!$is_soft) - { - $phpbb_content_visibility->remove_post_from_statistic($data, $sql_data); - } - - $sql = 'SELECT 1 AS has_attachments - FROM ' . ATTACHMENTS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query_limit($sql, 1); - $has_attachments = (int) $db->sql_fetchfield('has_attachments'); - $db->sql_freeresult($result); - - if (!$has_attachments) - { - $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_attachment = 0'; - } - } - - $db->sql_transaction('begin'); - - $where_sql = array( - FORUMS_TABLE => "forum_id = $forum_id", - TOPICS_TABLE => "topic_id = $topic_id", - USERS_TABLE => 'user_id = ' . $data['poster_id'], - ); - - foreach ($sql_data as $table => $update_sql) - { - if ($update_sql) - { - $db->sql_query("UPDATE $table SET $update_sql WHERE " . $where_sql[$table]); - } - } - - // Adjust posted info for this user by looking for a post by him/her within this topic... - if ($post_mode != 'delete_topic' && $config['load_db_track'] && $data['poster_id'] != ANONYMOUS) - { - $sql = 'SELECT poster_id - FROM ' . POSTS_TABLE . ' - WHERE topic_id = ' . $topic_id . ' - AND poster_id = ' . $data['poster_id']; - $result = $db->sql_query_limit($sql, 1); - $poster_id = (int) $db->sql_fetchfield('poster_id'); - $db->sql_freeresult($result); - - // The user is not having any more posts within this topic - if (!$poster_id) - { - $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . ' - WHERE topic_id = ' . $topic_id . ' - AND user_id = ' . $data['poster_id']; - $db->sql_query($sql); - } - } - - $db->sql_transaction('commit'); - - if ($data['post_reported'] && ($post_mode != 'delete_topic')) - { - sync('topic_reported', 'topic_id', array($topic_id)); - } - - /** - * This event is used for performing actions directly after a post or topic - * has been deleted. - * - * @event core.delete_post_after - * @var int forum_id Post forum ID - * @var int topic_id Post topic ID - * @var int post_id Post ID - * @var array data Post data - * @var bool is_soft Soft delete flag - * @var string softdelete_reason Soft delete reason - * @var string post_mode delete_topic, delete_first_post, delete_last_post or delete - * @var mixed next_post_id Next post ID in the topic (post ID or false) - * - * @since 3.1.11-RC1 - */ - $vars = array( - 'forum_id', - 'topic_id', - 'post_id', - 'data', - 'is_soft', - 'softdelete_reason', - 'post_mode', - 'next_post_id', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_post_after', compact($vars))); - - return $next_post_id; -} - -/** -* Submit Post -* @todo Split up and create lightweight, simple API for this. -*/ -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, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $phpbb_log, $request; - - $poll = $poll_ary; - $data = $data_ary; - /** - * Modify the data for post submitting - * - * @event core.modify_submit_post_data - * @var string mode Variable containing posting mode value - * @var string subject Variable containing post subject value - * @var string username Variable containing post author name - * @var int topic_type Variable containing topic type value - * @var array poll Array with the poll data for the post - * @var array data Array with the data for the post - * @var bool update_message Flag indicating if the post will be updated - * @var bool update_search_index Flag indicating if the search index will be updated - * @since 3.1.0-a4 - */ - $vars = array( - 'mode', - 'subject', - 'username', - 'topic_type', - 'poll', - 'data', - 'update_message', - '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') - { - return false; - } - - if (!empty($data_ary['post_time'])) - { - $current_time = $data_ary['post_time']; - } - else - { - $current_time = time(); - } - - if ($mode == 'post') - { - $post_mode = 'post'; - $update_message = true; - } - else if ($mode != 'edit') - { - $post_mode = 'reply'; - $update_message = true; - } - else if ($mode == '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_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_ary['poster_id'] : (int) $user->data['user_id']; - - // Retrieve some additional information if not present - 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_ary['post_id']; - $result = $db->sql_query($sql); - $topic_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $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 - $post_visibility = ITEM_APPROVED; - - // Check the permissions for post approval. - // Moderators must go through post approval like ordinary users. - if (!$auth->acl_get('f_noapprove', $data_ary['forum_id'])) - { - // Post not approved, but in queue - $post_visibility = ITEM_UNAPPROVED; - switch ($post_mode) - { - case 'edit_first_post': - case 'edit': - case 'edit_last_post': - case 'edit_topic': - $post_visibility = ITEM_REAPPROVE; - break; - } - } - else if (isset($data_ary['post_visibility']) && $data_ary['post_visibility'] !== false) - { - $post_visibility = $data_ary['post_visibility']; - } - - // MODs/Extensions are able to force any visibility on posts - if (isset($data_ary['force_approved_state'])) - { - $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_ary['force_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 - $db->sql_transaction('begin'); - - // Collect Information - switch ($post_mode) - { - case 'post': - case 'reply': - $sql_data[POSTS_TABLE]['sql'] = array( - 'forum_id' => $data_ary['forum_id'], - 'poster_id' => (int) $user->data['user_id'], - 'icon_id' => $data_ary['icon_id'], - 'poster_ip' => $user->ip, - 'post_time' => $current_time, - 'post_visibility' => $post_visibility, - '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_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; - - case 'edit_first_post': - case 'edit': - - case 'edit_last_post': - case 'edit_topic': - - // If edit reason is given always display edit info - - // If editing last post then display no edit info - // If m_edit permission then display no edit info - // 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_ary['post_edit_reason'] || (!$auth->acl_get('m_edit', $data_ary['forum_id']) && ($post_mode == 'edit' || $post_mode == 'edit_first_post'))) - { - $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_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_ary['post_edit_reason'] && $mode == 'edit' && $auth->acl_get('m_edit', $data_ary['forum_id'])) - { - $sql_data[POSTS_TABLE]['sql'] = array( - 'post_edit_reason' => '', - ); - } - - // If the person editing this post is different to the one having posted then we will add a log entry stating the edit - // 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_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'])) - { - $sql_data[POSTS_TABLE]['sql'] = array(); - } - - $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array( - '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_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_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_ary['message']; - } - - break; - } - - // And the topic ladies and gentlemen - switch ($post_mode) - { - case 'post': - $sql_data[TOPICS_TABLE]['sql'] = array( - 'topic_poster' => (int) $user->data['user_id'], - 'topic_time' => $current_time, - 'topic_last_view_time' => $current_time, - '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, - 'topic_visibility' => $post_visibility, - 'topic_delete_user' => ($post_visibility != ITEM_APPROVED) ? (int) $user->data['user_id'] : 0, - 'topic_title' => $subject, - 'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''), - 'topic_first_poster_colour' => $user->data['user_colour'], - 'topic_type' => $topic_type, - '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_ary['poll_options']) && !empty($poll_ary['poll_options'])) - { - $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; - if ($poll_start < 0) - { - $poll_start = 0; - } - $poll_length = 1; - } - - $sql_data[TOPICS_TABLE]['sql'] = array_merge($sql_data[TOPICS_TABLE]['sql'], array( - 'poll_title' => $poll_ary['poll_title'], - 'poll_start' => $poll_start, - 'poll_max_options' => $poll_ary['poll_max_options'], - 'poll_length' => $poll_length, - 'poll_vote_change' => $poll_ary['poll_vote_change']) - ); - } - - $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) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_approved = forum_topics_approved + 1'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1'; - } - else if ($post_visibility == ITEM_UNAPPROVED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_unapproved = forum_topics_unapproved + 1'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1'; - } - else if ($post_visibility == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_softdeleted = forum_topics_softdeleted + 1'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1'; - } - break; - - case 'reply': - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_view_time = ' . $current_time . ', - topic_bumped = 0, - topic_bumper = 0' . - (($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_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_ary['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : ''); - - if ($post_visibility == ITEM_APPROVED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1'; - } - else if ($post_visibility == ITEM_UNAPPROVED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1'; - } - else if ($post_visibility == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1'; - } - break; - - case 'edit_topic': - case 'edit_first_post': - if (isset($poll_ary['poll_options'])) - { - $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; - if ($poll_start < 0) - { - $poll_start = 0; - } - $poll_length = 1; - } - } - - $sql_data[TOPICS_TABLE]['sql'] = array( - '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_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_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 - * - * @event core.submit_post_modify_sql_data - * @var array data Array with the data for the post - * @var array poll Array with the poll data for the post - * @var string post_mode Variable containing posting mode value - * @var bool sql_data Array with the data for the posting SQL query - * @var string subject Variable containing post subject value - * @var int topic_type Variable containing topic type value - * @var string username Variable containing post author name - * @since 3.1.3-RC1 - */ - $vars = array( - 'data', - 'poll', - 'post_mode', - 'sql_data', - 'subject', - 'topic_type', - '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') - { - $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . - $db->sql_build_array('INSERT', $sql_data[TOPICS_TABLE]['sql']); - $db->sql_query($sql); - - $data_ary['topic_id'] = $db->sql_nextid(); - - $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array( - 'topic_id' => $data_ary['topic_id']) - ); - unset($sql_data[TOPICS_TABLE]['sql']); - } - - // Submit new post - if ($post_mode == 'post' || $post_mode == 'reply') - { - if ($post_mode == 'reply') - { - $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array( - '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_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_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'], - 'topic_last_poster_colour' => $user->data['user_colour'], - 'topic_last_post_subject' => (string) $subject, - ); - } - - if ($post_mode == 'post') - { - $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data_ary['post_id']; - } - - // Update total post count and forum information - if ($post_visibility == ITEM_APPROVED) - { - if ($post_mode == 'post') - { - $config->increment('num_topics', 1, false); - } - $config->increment('num_posts', 1, false); - - $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']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'"; - } - - unset($sql_data[POSTS_TABLE]['sql']); - } - - // Update the topics table - if (isset($sql_data[TOPICS_TABLE]['sql'])) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . ' - WHERE topic_id = ' . $data_ary['topic_id']; - $db->sql_query($sql); - - unset($sql_data[TOPICS_TABLE]['sql']); - } - - // Update the posts table - if (isset($sql_data[POSTS_TABLE]['sql'])) - { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . ' - WHERE post_id = ' . $data_ary['post_id']; - $db->sql_query($sql); - - unset($sql_data[POSTS_TABLE]['sql']); - } - - // Update Poll Tables - if (isset($poll_ary['poll_options'])) - { - $cur_poll_options = array(); - - if ($mode == 'edit') - { - $sql = 'SELECT * - FROM ' . POLL_OPTIONS_TABLE . ' - WHERE topic_id = ' . $data_ary['topic_id'] . ' - ORDER BY poll_option_id'; - $result = $db->sql_query($sql); - - $cur_poll_options = array(); - while ($row = $db->sql_fetchrow($result)) - { - $cur_poll_options[] = $row; - } - $db->sql_freeresult($result); - } - - $sql_insert_ary = array(); - - for ($i = 0, $size = count($poll_ary['poll_options']); $i < $size; $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) 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_ary['poll_options'][$i] != $cur_poll_options[$i]) - { - $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . " - 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_ary['topic_id']; - $db->sql_query($sql); - } - } - } - - $db->sql_multi_insert(POLL_OPTIONS_TABLE, $sql_insert_ary); - - if (count($poll_ary['poll_options']) < count($cur_poll_options)) - { - $sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . ' - 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' && count($poll_ary['poll_options']) != count($cur_poll_options)) - { - $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_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_ary['attachment_data'] as $pos => $attach_row) - { - $orphan_rows[(int) $attach_row['attach_id']] = array(); - } - - if (count($orphan_rows)) - { - $sql = 'SELECT attach_id, filesize, physical_filename - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . ' - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - $orphan_rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $orphan_rows[$row['attach_id']] = $row; - } - $db->sql_freeresult($result); - } - - 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 - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "' - WHERE attach_id = " . (int) $attach_row['attach_id'] . ' - AND is_orphan = 0'; - $db->sql_query($sql); - } - else - { - // insert attachment into db - if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) - { - continue; - } - - $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize']; - $files_added++; - - $attach_sql = array( - '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'], - ); - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . ' - WHERE attach_id = ' . $attach_row['attach_id'] . ' - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $db->sql_query($sql); - } - } - - if ($space_taken && $files_added) - { - $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_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_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_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_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_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_ary['poster_id'] == ANONYMOUS) - { - $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'"; - } - - if ($post_visibility == ITEM_APPROVED) - { - // this does not _necessarily_ mean that we must update the info again, - // it just means that we might have to - $sql = 'SELECT forum_last_post_id, forum_last_post_subject - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . (int) $data_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_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) - { - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'"; - } - - // Update the user name if poster is anonymous... just in case a moderator changed it - if ($data_ary['poster_id'] == ANONYMOUS) - { - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'"; - } - } - } - } - } - - // Update forum stats - $where_sql = array( - POSTS_TABLE => 'post_id = ' . $data_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 - ); - - foreach ($sql_data as $table => $update_ary) - { - if (isset($update_ary['stat']) && implode('', $update_ary['stat'])) - { - $sql = "UPDATE $table SET " . implode(', ', $update_ary['stat']) . ' WHERE ' . $where_sql[$table]; - $db->sql_query($sql); - } - } - - // Delete topic shadows (if any exist). We do not need a shadow topic for an global announcement - if ($topic_type == POST_GLOBAL) - { - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE topic_moved_id = ' . $data_ary['topic_id']; - $db->sql_query($sql); - } - - // Committing the transaction before updating search index - $db->sql_transaction('commit'); - - // Delete draft if post was loaded... - $draft_id = $request->variable('draft_loaded', 0); - if ($draft_id) - { - $sql = 'DELETE FROM ' . DRAFTS_TABLE . " - WHERE draft_id = $draft_id - AND user_id = {$user->data['user_id']}"; - $db->sql_query($sql); - } - - // Index message contents - 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']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if ($error) - { - trigger_error($error); - } - - $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_ary['notify_set'] && $data_ary['notify']) - { - $sql = 'INSERT INTO ' . TOPICS_WATCH_TABLE . ' (user_id, topic_id) - VALUES (' . $user->data['user_id'] . ', ' . $data_ary['topic_id'] . ')'; - $db->sql_query($sql); - } - 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_ary['topic_id']; - $db->sql_query($sql); - } - } - - if ($mode == 'post' || $mode == 'reply' || $mode == 'quote') - { - // Mark this topic as posted to - 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_ary['forum_id'], $data_ary['topic_id'], time()); - - // - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql = 'SELECT mark_time - FROM ' . FORUMS_TRACK_TABLE . ' - WHERE user_id = ' . $user->data['user_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); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $f_mark_time = false; - } - - if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) - { - // Update forum info - $sql = 'SELECT forum_last_post_time - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $data_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_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. - // Doing it this way we can use "...post by guest-username..." in notifications when - // "guest-username" is supplied or ommit the username if it is not. - $username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username']; - - // Send Notifications - $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_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) - { - switch ($mode) - { - case 'post': - $phpbb_notifications->add_notifications(array( - 'notification.type.quote', - 'notification.type.topic', - ), $notification_data); - break; - - case 'reply': - case 'quote': - $phpbb_notifications->add_notifications(array( - 'notification.type.quote', - 'notification.type.bookmark', - 'notification.type.post', - ), $notification_data); - break; - - case 'edit_topic': - 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.bookmark', - 'notification.type.topic', - 'notification.type.post', - ), $notification_data); - break; - } - } - else if ($post_visibility == ITEM_UNAPPROVED) - { - switch ($mode) - { - case 'post': - $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data); - break; - - case 'reply': - case 'quote': - $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data); - break; - - case 'edit_topic': - case 'edit_first_post': - case 'edit': - case 'edit_last_post': - // Nothing to do here - break; - } - } - else if ($post_visibility == ITEM_REAPPROVE) - { - switch ($mode) - { - case 'edit_topic': - case 'edit_first_post': - $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data); - - // Delete the approve_post notification so we can notify the user again, - // when his post got reapproved - $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']); - break; - - case 'edit': - case 'edit_last_post': - $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data); - - // Delete the approve_post notification so we can notify the user again, - // when his post got reapproved - $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']); - break; - - case 'post': - case 'reply': - case 'quote': - // Nothing to do here - break; - } - } - else if ($post_visibility == ITEM_DELETED) - { - switch ($mode) - { - case 'post': - case 'reply': - case 'quote': - case 'edit_topic': - case 'edit_first_post': - case 'edit': - case 'edit_last_post': - // Nothing to do here - break; - } - } - - $params = $add_anchor = ''; - - if ($post_visibility == ITEM_APPROVED || - ($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 .= '&t=' . $data_ary['topic_id']; - - if ($mode != 'post') - { - $params .= '&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 .= '&t=' . $data_ary['topic_id']; - } - - $url = (!$params) ? "{$phpbb_root_path}viewforum.$phpEx" : "{$phpbb_root_path}viewtopic.$phpEx"; - $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 - * available in the $data array. - * - * The only action that can be done by altering data made available to this - * event is to modify the return URL ($url). - * - * @event core.submit_post_end - * @var string mode Variable containing posting mode value - * @var string subject Variable containing post subject value - * @var string username Variable containing post author name - * @var int topic_type Variable containing topic type value - * @var array poll Array with the poll data for the post - * @var array data Array with the data for the post - * @var int post_visibility Variable containing up to date post visibility - * @var bool update_message Flag indicating if the post will be updated - * @var bool update_search_index Flag indicating if the search index will be updated - * @var string url The "Return to topic" URL - * - * @since 3.1.0-a3 - * @changed 3.1.0-RC3 Added vars mode, subject, username, topic_type, - * poll, update_message, update_search_index - */ - $vars = array( - 'mode', - 'subject', - 'username', - 'topic_type', - 'poll', - 'data', - 'post_visibility', - 'update_message', - 'update_search_index', - 'url', - ); - extract($phpbb_dispatcher->trigger_event('core.submit_post_end', compact($vars))); - $data_ary = $data; - $poll_ary = $poll; - unset($data); - unset($poll); - - return $url; -} - -/** -* Handle topic bumping -* @param int $forum_id The ID of the forum the topic is being bumped belongs to -* @param int $topic_id The ID of the topic is being bumping -* @param array $post_data Passes some topic parameters: -* - 'topic_title' -* - 'topic_last_post_id' -* - 'topic_last_poster_id' -* - 'topic_last_post_subject' -* - 'topic_last_poster_name' -* - 'topic_last_poster_colour' -* @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time(). -* @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&topic_id=2&p=3#p3 -*/ -function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false) -{ - global $config, $db, $user, $phpEx, $phpbb_root_path, $phpbb_log; - - if ($bump_time === false) - { - $bump_time = time(); - } - - // Begin bumping - $db->sql_transaction('begin'); - - // Update the topic's last post post_time - $sql = 'UPDATE ' . POSTS_TABLE . " - SET post_time = $bump_time - WHERE post_id = {$post_data['topic_last_post_id']} - AND topic_id = $topic_id"; - $db->sql_query($sql); - - // Sync the topic's last post time, the rest of the topic's last post data isn't changed - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_last_post_time = $bump_time, - topic_bumped = 1, - topic_bumper = " . $user->data['user_id'] . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - // Update the forum's last post info - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ", - forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ", - forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "', - forum_last_post_time = $bump_time, - forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "', - forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "' - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - // Update bumper's time of the last posting to prevent flood - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastpost_time = $bump_time - WHERE user_id = " . $user->data['user_id']; - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - // Mark this topic as posted to - markread('post', $forum_id, $topic_id, $bump_time); - - // Mark this topic as read - markread('topic', $forum_id, $topic_id, $bump_time); - - // Update forum tracking info - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql = 'SELECT mark_time - FROM ' . FORUMS_TRACK_TABLE . ' - WHERE user_id = ' . $user->data['user_id'] . ' - AND forum_id = ' . $forum_id; - $result = $db->sql_query($sql); - $f_mark_time = (int) $db->sql_fetchfield('mark_time'); - $db->sql_freeresult($result); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $f_mark_time = false; - } - - if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) - { - // Update forum info - $sql = 'SELECT forum_last_post_time - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $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($forum_id, $forum_last_post_time, $f_mark_time, false); - } - - $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&t=$topic_id&p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}"; - - return $url; -} - -/** -* Show upload popup (progress bar) -*/ -function phpbb_upload_popup($forum_style = 0) -{ - global $template, $user; - - ($forum_style) ? $user->setup('posting', $forum_style) : $user->setup('posting'); - - page_header($user->lang['PROGRESS_BAR']); - - $template->set_filenames(array( - 'popup' => 'posting_progress_bar.html') - ); - - $template->assign_vars(array( - 'PROGRESS_BAR' => $user->img('upload_bar', $user->lang['UPLOAD_IN_PROGRESS'])) - ); - - $template->display('popup'); - - garbage_collection(); - exit_handler(); -} - -/** -* Do the various checks required for removing posts as well as removing it -* -* @param int $forum_id The id of the forum -* @param int $topic_id The id of the topic -* @param int $post_id The id of the post -* @param array $post_data Array with the post data -* @param bool $is_soft The flag indicating whether it is the soft delete mode -* @param string $delete_reason Description for the post deletion reason -* -* @return null -*/ -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_log, $phpbb_dispatcher; - - $force_delete_allowed = $force_softdelete_allowed = false; - $perm_check = ($is_soft) ? 'softdelete' : 'delete'; - - /** - * This event allows to modify the conditions for the post deletion - * - * @event core.handle_post_delete_conditions - * @var int forum_id The id of the forum - * @var int topic_id The id of the topic - * @var int post_id The id of the post - * @var array post_data Array with the post data - * @var bool is_soft The flag indicating whether it is the soft delete mode - * @var string delete_reason Description for the post deletion reason - * @var bool force_delete_allowed Allow the user to delete the post (all permissions and conditions are ignored) - * @var bool force_softdelete_allowed Allow the user to softdelete the post (all permissions and conditions are ignored) - * @var string perm_check The deletion mode softdelete|delete - * @since 3.1.11-RC1 - */ - $vars = array( - 'forum_id', - 'topic_id', - 'post_id', - 'post_data', - 'is_soft', - 'delete_reason', - 'force_delete_allowed', - 'force_softdelete_allowed', - 'perm_check', - ); - extract($phpbb_dispatcher->trigger_event('core.handle_post_delete_conditions', compact($vars))); - - // If moderator removing post or user itself removing post, present a confirmation screen - if ($force_delete_allowed || ($is_soft && $force_softdelete_allowed) || $auth->acl_get("m_$perm_check", $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get("f_$perm_check", $forum_id) && $post_id == $post_data['topic_last_post_id'] && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time']))) - { - $s_hidden_fields = array( - 'p' => $post_id, - 'f' => $forum_id, - 'mode' => ($is_soft) ? 'soft_delete' : 'delete', - ); - - if (confirm_box(true)) - { - $data = array( - 'topic_first_post_id' => $post_data['topic_first_post_id'], - 'topic_last_post_id' => $post_data['topic_last_post_id'], - 'topic_posts_approved' => $post_data['topic_posts_approved'], - 'topic_posts_unapproved' => $post_data['topic_posts_unapproved'], - 'topic_posts_softdeleted' => $post_data['topic_posts_softdeleted'], - 'topic_visibility' => $post_data['topic_visibility'], - 'topic_type' => $post_data['topic_type'], - 'post_visibility' => $post_data['post_visibility'], - 'post_reported' => $post_data['post_reported'], - 'post_time' => $post_data['post_time'], - 'poster_id' => $post_data['poster_id'], - 'post_postcount' => $post_data['post_postcount'], - ); - - $next_post_id = delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $delete_reason); - $post_username = ($post_data['poster_id'] == ANONYMOUS && !empty($post_data['post_username'])) ? $post_data['post_username'] : $post_data['username']; - - if ($next_post_id === false) - { - $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 - { - $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&t=$topic_id&p=$next_post_id") . "#p$next_post_id"; - $message = $user->lang['POST_DELETED']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_TOPIC', '', ''); - } - } - - meta_refresh(3, $meta_info); - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_FORUM', '', ''); - } - trigger_error($message); - } - else - { - global $template; - - $can_delete = $force_delete_allowed || ($auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_delete', $forum_id))); - $can_softdelete = $force_softdelete_allowed || ($auth->acl_get('m_softdelete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_softdelete', $forum_id))); - - $template->assign_vars(array( - 'S_SOFTDELETED' => $post_data['post_visibility'] == ITEM_DELETED, - 'S_CHECKED_PERMANENT' => $request->is_set_post('delete_permanent') ? ' checked="checked"' : '', - 'S_ALLOWED_DELETE' => $can_delete, - 'S_ALLOWED_SOFTDELETE' => $can_softdelete, - )); - - $l_confirm = 'DELETE_POST'; - if ($post_data['post_visibility'] == ITEM_DELETED) - { - $l_confirm .= '_PERMANENTLY'; - $s_hidden_fields['delete_permanent'] = '1'; - } - else if (!$can_softdelete) - { - $s_hidden_fields['delete_permanent'] = '1'; - } - - confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); - } - } - - // If we are here the user is not able to delete - present the correct error message - if ($post_data['poster_id'] != $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id)) - { - trigger_error('DELETE_OWN_POSTS'); - } - - if ($post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && $post_id != $post_data['topic_last_post_id']) - { - trigger_error('CANNOT_DELETE_REPLIED'); - } - - trigger_error('USER_CANNOT_DELETE'); -} diff --git a/install/update/new/includes/functions_privmsgs.php b/install/update/new/includes/functions_privmsgs.php deleted file mode 100644 index f07512d..0000000 --- a/install/update/new/includes/functions_privmsgs.php +++ /dev/null @@ -1,2303 +0,0 @@ - -* @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; -} - -/* - Ability to simply add own rules by doing three things: - 1) Add an appropriate constant - 2) Add a new check array to the global_privmsgs_rules variable and the condition array (if one is required) - 3) Implement the rule logic in the check_rule() function - 4) Add a new language variable to ucp.php - - The user is then able to select the new rule. It will be checked against and handled as specified. - To add new actions (yes, checks can be added here too) to the rule management, the core code has to be modified. -*/ - -define('RULE_IS_LIKE', 1); // Is Like -define('RULE_IS_NOT_LIKE', 2); // Is Not Like -define('RULE_IS', 3); // Is -define('RULE_IS_NOT', 4); // Is Not -define('RULE_BEGINS_WITH', 5); // Begins with -define('RULE_ENDS_WITH', 6); // Ends with -define('RULE_IS_FRIEND', 7); // Is Friend -define('RULE_IS_FOE', 8); // Is Foe -define('RULE_IS_USER', 9); // Is User -define('RULE_IS_GROUP', 10); // Is In Usergroup -define('RULE_ANSWERED', 11); // Answered -define('RULE_FORWARDED', 12); // Forwarded -define('RULE_TO_GROUP', 14); // Usergroup -define('RULE_TO_ME', 15); // Me - -define('ACTION_PLACE_INTO_FOLDER', 1); -define('ACTION_MARK_AS_READ', 2); -define('ACTION_MARK_AS_IMPORTANT', 3); -define('ACTION_DELETE_MESSAGE', 4); - -define('CHECK_SUBJECT', 1); -define('CHECK_SENDER', 2); -define('CHECK_MESSAGE', 3); -define('CHECK_STATUS', 4); -define('CHECK_TO', 5); - -/** -* Global private message rules -* These rules define what to do if a rule is hit -*/ -$global_privmsgs_rules = array( - CHECK_SUBJECT => array( - RULE_IS_LIKE => array('check0' => 'message_subject'), - RULE_IS_NOT_LIKE => array('check0' => 'message_subject'), - RULE_IS => array('check0' => 'message_subject'), - RULE_IS_NOT => array('check0' => 'message_subject'), - RULE_BEGINS_WITH => array('check0' => 'message_subject'), - RULE_ENDS_WITH => array('check0' => 'message_subject'), - ), - - CHECK_SENDER => array( - RULE_IS_LIKE => array('check0' => 'username'), - RULE_IS_NOT_LIKE => array('check0' => 'username'), - RULE_IS => array('check0' => 'username'), - RULE_IS_NOT => array('check0' => 'username'), - RULE_BEGINS_WITH => array('check0' => 'username'), - RULE_ENDS_WITH => array('check0' => 'username'), - RULE_IS_FRIEND => array('check0' => 'friend'), - RULE_IS_FOE => array('check0' => 'foe'), - RULE_IS_USER => array('check0' => 'author_id'), - RULE_IS_GROUP => array('check0' => 'author_in_group'), - ), - - CHECK_MESSAGE => array( - RULE_IS_LIKE => array('check0' => 'message_text'), - RULE_IS_NOT_LIKE => array('check0' => 'message_text'), - RULE_IS => array('check0' => 'message_text'), - RULE_IS_NOT => array('check0' => 'message_text'), - ), - - CHECK_STATUS => array( - RULE_ANSWERED => array('check0' => 'pm_replied'), - RULE_FORWARDED => array('check0' => 'pm_forwarded'), - ), - - CHECK_TO => array( - RULE_TO_GROUP => array('check0' => 'to', 'check1' => 'bcc', 'check2' => 'user_in_group'), - RULE_TO_ME => array('check0' => 'to', 'check1' => 'bcc'), - ) -); - -/** -* This is for defining which condition fields to show for which Rule -*/ -$global_rule_conditions = array( - RULE_IS_LIKE => 'text', - RULE_IS_NOT_LIKE => 'text', - RULE_IS => 'text', - RULE_IS_NOT => 'text', - RULE_BEGINS_WITH => 'text', - RULE_ENDS_WITH => 'text', - RULE_IS_USER => 'user', - RULE_IS_GROUP => 'group' -); - -/** -* Get all folder -*/ -function get_folder($user_id, $folder_id = false) -{ - global $db, $user, $template; - global $phpbb_root_path, $phpEx; - - $folder = array(); - - // Get folder information - $sql = 'SELECT folder_id, COUNT(msg_id) as num_messages, SUM(pm_unread) as num_unread - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id <> " . PRIVMSGS_NO_BOX . ' - GROUP BY folder_id'; - $result = $db->sql_query($sql); - - $num_messages = $num_unread = array(); - while ($row = $db->sql_fetchrow($result)) - { - $num_messages[(int) $row['folder_id']] = $row['num_messages']; - $num_unread[(int) $row['folder_id']] = $row['num_unread']; - } - $db->sql_freeresult($result); - - // Make sure the default boxes are defined - $available_folder = array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX); - - foreach ($available_folder as $default_folder) - { - if (!isset($num_messages[$default_folder])) - { - $num_messages[$default_folder] = 0; - } - - if (!isset($num_unread[$default_folder])) - { - $num_unread[$default_folder] = 0; - } - } - - // Adjust unread status for outbox - $num_unread[PRIVMSGS_OUTBOX] = $num_messages[PRIVMSGS_OUTBOX]; - - $folder[PRIVMSGS_INBOX] = array( - 'folder_name' => $user->lang['PM_INBOX'], - 'num_messages' => $num_messages[PRIVMSGS_INBOX], - 'unread_messages' => $num_unread[PRIVMSGS_INBOX] - ); - - // Custom Folder - $sql = 'SELECT folder_id, folder_name, pm_count - FROM ' . PRIVMSGS_FOLDER_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $folder[$row['folder_id']] = array( - 'folder_name' => $row['folder_name'], - 'num_messages' => $row['pm_count'], - 'unread_messages' => ((isset($num_unread[$row['folder_id']])) ? $num_unread[$row['folder_id']] : 0) - ); - } - $db->sql_freeresult($result); - - $folder[PRIVMSGS_OUTBOX] = array( - 'folder_name' => $user->lang['PM_OUTBOX'], - 'num_messages' => $num_messages[PRIVMSGS_OUTBOX], - 'unread_messages' => $num_unread[PRIVMSGS_OUTBOX] - ); - - $folder[PRIVMSGS_SENTBOX] = array( - 'folder_name' => $user->lang['PM_SENTBOX'], - 'num_messages' => $num_messages[PRIVMSGS_SENTBOX], - 'unread_messages' => $num_unread[PRIVMSGS_SENTBOX] - ); - - // Define Folder Array for template designers (and for making custom folders usable by the template too) - foreach ($folder as $f_id => $folder_ary) - { - $folder_id_name = ($f_id == PRIVMSGS_INBOX) ? 'inbox' : (($f_id == PRIVMSGS_OUTBOX) ? 'outbox' : 'sentbox'); - - $template->assign_block_vars('folder', array( - 'FOLDER_ID' => $f_id, - 'FOLDER_NAME' => $folder_ary['folder_name'], - 'NUM_MESSAGES' => $folder_ary['num_messages'], - 'UNREAD_MESSAGES' => $folder_ary['unread_messages'], - - 'U_FOLDER' => ($f_id > 0) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $f_id) : append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id_name), - - 'S_CUR_FOLDER' => ($f_id === $folder_id) ? true : false, - 'S_UNREAD_MESSAGES' => ($folder_ary['unread_messages']) ? true : false, - 'S_CUSTOM_FOLDER' => ($f_id > 0) ? true : false) - ); - } - - if ($folder_id !== false && $folder_id !== PRIVMSGS_HOLD_BOX && !isset($folder[$folder_id])) - { - trigger_error('UNKNOWN_FOLDER'); - } - - return $folder; -} - -/** -* Delete Messages From Sentbox -* we are doing this here because this saves us a bunch of checks and queries -*/ -function clean_sentbox($num_sentbox_messages) -{ - global $db, $user; - - // Check Message Limit - if ($user->data['message_limit'] && $num_sentbox_messages > $user->data['message_limit']) - { - // Delete old messages - $sql = 'SELECT t.msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p - WHERE t.msg_id = p.msg_id - AND t.user_id = ' . $user->data['user_id'] . ' - AND t.folder_id = ' . PRIVMSGS_SENTBOX . ' - ORDER BY p.message_time ASC'; - $result = $db->sql_query_limit($sql, ($num_sentbox_messages - $user->data['message_limit'])); - - $delete_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $delete_ids[] = $row['msg_id']; - } - $db->sql_freeresult($result); - delete_pm($user->data['user_id'], $delete_ids, PRIVMSGS_SENTBOX); - } -} - -/** -* Check Rule against Message Information -*/ -function check_rule(&$rules, &$rule_row, &$message_row, $user_id) -{ - if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']])) - { - return false; - } - - $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']]; - - $result = false; - - $check0 = $message_row[$check_ary['check0']]; - - switch ($rule_row['rule_connection']) - { - case RULE_IS_LIKE: - $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); - break; - - case RULE_IS_NOT_LIKE: - $result = !preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); - break; - - case RULE_IS: - $result = ($check0 == $rule_row['rule_string']); - break; - - case RULE_IS_NOT: - $result = ($check0 != $rule_row['rule_string']); - break; - - case RULE_BEGINS_WITH: - $result = preg_match("/^" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); - break; - - case RULE_ENDS_WITH: - $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '$/i', $check0); - break; - - case RULE_IS_FRIEND: - case RULE_IS_FOE: - case RULE_ANSWERED: - case RULE_FORWARDED: - $result = ($check0 == 1); - break; - - case RULE_IS_USER: - $result = ($check0 == $rule_row['rule_user_id']); - break; - - case RULE_IS_GROUP: - $result = in_array($rule_row['rule_group_id'], $check0); - break; - - case RULE_TO_GROUP: - $result = (in_array('g_' . $message_row[$check_ary['check2']], $check0) || in_array('g_' . $message_row[$check_ary['check2']], $message_row[$check_ary['check1']])); - break; - - case RULE_TO_ME: - $result = (in_array('u_' . $user_id, $check0) || in_array('u_' . $user_id, $message_row[$check_ary['check1']])); - break; - } - - if (!$result) - { - return false; - } - - switch ($rule_row['rule_action']) - { - case ACTION_PLACE_INTO_FOLDER: - return array('action' => $rule_row['rule_action'], 'folder_id' => $rule_row['rule_folder_id']); - break; - - case ACTION_MARK_AS_READ: - case ACTION_MARK_AS_IMPORTANT: - return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']); - break; - - case ACTION_DELETE_MESSAGE: - 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 - $sql = 'SELECT user_id, user_type, user_permissions - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $message_row['author_id']; - $result = $db->sql_query($sql); - $userdata = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($userdata); - - if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_')) - { - return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']); - } - - return false; - break; - - default: - return false; - } - - return false; -} - -/** -* Update user PM count -*/ -function update_pm_counts() -{ - global $user, $db; - - // Update unread count - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE pm_unread = 1 - AND folder_id <> ' . PRIVMSGS_OUTBOX . ' - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $user->data['user_unread_privmsg'] = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - - // Update new pm count - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE pm_new = 1 - AND folder_id IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ') - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $user->data['user_new_privmsg'] = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( - 'user_unread_privmsg' => (int) $user->data['user_unread_privmsg'], - 'user_new_privmsg' => (int) $user->data['user_new_privmsg'], - )) . ' WHERE user_id = ' . $user->data['user_id']); - - // Ok, here we need to repair something, other boxes than privmsgs_no_box and privmsgs_hold_box should not carry the pm_new flag. - if (!$user->data['user_new_privmsg']) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET pm_new = 0 - WHERE pm_new = 1 - AND folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ') - AND user_id = ' . $user->data['user_id']; - $db->sql_query($sql); - } -} - -/** -* Place new messages into appropriate folder -*/ -function place_pm_into_folder(&$global_privmsgs_rules, $release = false) -{ - global $db, $user, $config; - - if (!$user->data['user_new_privmsg']) - { - return array('not_moved' => 0, 'removed' => 0); - } - - $user_message_rules = (int) $user->data['user_message_rules']; - $user_id = (int) $user->data['user_id']; - - $action_ary = $move_into_folder = array(); - $num_removed = 0; - - // Newly processing on-hold messages - if ($release) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET folder_id = ' . PRIVMSGS_NO_BOX . ' - WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . " - AND user_id = $user_id"; - $db->sql_query($sql); - } - - // Get those messages not yet placed into any box - $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE t.user_id = $user_id - AND p.author_id = u.user_id - AND t.folder_id = " . PRIVMSGS_NO_BOX . ' - AND t.msg_id = p.msg_id'; - - // Just place into the appropriate arrays if no rules need to be checked - if (!$user_message_rules) - { - $result = $db->sql_query($retrieve_sql); - - while ($row = $db->sql_fetchrow($result)) - { - $action_ary[$row['msg_id']][] = array('action' => false); - } - $db->sql_freeresult($result); - } - else - { - $user_rules = $zebra = $check_rows = array(); - $user_ids = $memberships = array(); - - // First of all, grab all rules and retrieve friends/foes - $sql = 'SELECT * - FROM ' . PRIVMSGS_RULES_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query($sql); - $user_rules = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - if (count($user_rules)) - { - $sql = 'SELECT zebra_id, friend, foe - FROM ' . ZEBRA_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $zebra[$row['zebra_id']] = $row; - } - $db->sql_freeresult($result); - } - - // Now build a bare-bone check_row array - $result = $db->sql_query($retrieve_sql); - - while ($row = $db->sql_fetchrow($result)) - { - $check_rows[] = array_merge($row, array( - 'to' => explode(':', $row['to_address']), - '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' => $user->data['group_id'], - 'author_in_group' => array()) - ); - - $user_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - // Retrieve user memberships - if (count($user_ids)) - { - $sql = 'SELECT * - FROM ' . USER_GROUP_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_ids) . ' - AND user_pending = 0'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $memberships[$row['user_id']][] = $row['group_id']; - } - $db->sql_freeresult($result); - } - - // Now place into the appropriate folder - foreach ($check_rows as $row) - { - // Add membership if set - if (isset($memberships[$row['author_id']])) - { - $row['author_in_group'] = $memberships[$row['user_id']]; - } - - // Check Rule - this should be very quick since we have all information we need - $is_match = false; - foreach ($user_rules as $rule_row) - { - if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false) - { - $is_match = true; - $action_ary[$row['msg_id']][] = $action; - } - } - - if (!$is_match) - { - $action_ary[$row['msg_id']][] = array('action' => false); - } - } - - unset($user_rules, $zebra, $check_rows, $user_ids, $memberships); - } - - // We place actions into arrays, to save queries. - $unread_ids = $delete_ids = $important_ids = array(); - - foreach ($action_ary as $msg_id => $msg_ary) - { - // It is allowed to execute actions more than once, except placing messages into folder - $folder_action = $message_removed = false; - - foreach ($msg_ary as $pos => $rule_ary) - { - if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER) - { - continue; - } - - switch ($rule_ary['action']) - { - case ACTION_PLACE_INTO_FOLDER: - // Folder actions have precedence, so we will remove any other ones - $folder_action = true; - $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id; - break; - - case ACTION_MARK_AS_READ: - if ($rule_ary['pm_unread']) - { - $unread_ids[] = $msg_id; - } - break; - - case ACTION_DELETE_MESSAGE: - $delete_ids[] = $msg_id; - $message_removed = true; - break; - - case ACTION_MARK_AS_IMPORTANT: - if (!$rule_ary['pm_marked']) - { - $important_ids[] = $msg_id; - } - break; - } - } - - // We place this here because it could happen that the messages are doubled if a rule marks a message and then moves it into a specific - // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder. - if (!$folder_action && !$message_removed) - { - $move_into_folder[PRIVMSGS_INBOX][] = $msg_id; - } - } - - // Do not change the order of processing - // The number of queries needed to be executed here highly depends on the defined rules and are - // only gone through if new messages arrive. - - // Delete messages - if (count($delete_ids)) - { - $num_removed += count($delete_ids); - delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX); - } - - // Set messages to Unread - if (count($unread_ids)) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET pm_unread = 0 - WHERE ' . $db->sql_in_set('msg_id', $unread_ids) . " - AND user_id = $user_id - AND folder_id = " . PRIVMSGS_NO_BOX; - $db->sql_query($sql); - } - - // mark messages as important - if (count($important_ids)) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET pm_marked = 1 - pm_marked - WHERE folder_id = ' . PRIVMSGS_NO_BOX . " - AND user_id = $user_id - AND " . $db->sql_in_set('msg_id', $important_ids); - $db->sql_query($sql); - } - - // Move into folder - $folder = array(); - - 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']; - - $sql_folder = array_keys($move_into_folder); - if ($full_folder_action >= 0) - { - $sql_folder[] = $full_folder_action; - } - - $sql = 'SELECT folder_id, pm_count - FROM ' . PRIVMSGS_FOLDER_TABLE . ' - WHERE ' . $db->sql_in_set('folder_id', $sql_folder) . " - AND user_id = $user_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $folder[(int) $row['folder_id']] = (int) $row['pm_count']; - } - $db->sql_freeresult($result); - - unset($sql_folder); - - if (isset($move_into_folder[PRIVMSGS_INBOX])) - { - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id = " . PRIVMSGS_INBOX; - $result = $db->sql_query($sql); - $folder[PRIVMSGS_INBOX] = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - } - } - - // Here we have ideally only one folder to move into - foreach ($move_into_folder as $folder_id => $msg_ary) - { - $dest_folder = $folder_id; - $full_folder_action = FULL_FOLDER_NONE; - - // 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] + 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] + count($msg_ary)) > $user->data['message_limit']) - { - $full_folder_action = $config['full_folder_action'] - (FULL_FOLDER_NONE*(-1)); - } - - // If Full Folder Action is to move to another folder, we simply adjust the destination folder - if ($full_folder_action >= 0) - { - $dest_folder = $full_folder_action; - } - else if ($full_folder_action == FULL_FOLDER_DELETE) - { - // Delete some messages. NOTE: Ordered by msg_id here instead of message_time! - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id = $dest_folder - ORDER BY msg_id ASC"; - $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)) - { - $delete_ids[] = $row['msg_id']; - } - $db->sql_freeresult($result); - - $num_removed += count($delete_ids); - delete_pm($user_id, $delete_ids, $dest_folder); - } - } - - // - if ($full_folder_action == FULL_FOLDER_HOLD) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET folder_id = ' . PRIVMSGS_HOLD_BOX . ' - WHERE folder_id = ' . PRIVMSGS_NO_BOX . " - AND user_id = $user_id - AND " . $db->sql_in_set('msg_id', $msg_ary); - $db->sql_query($sql); - } - else - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " - SET folder_id = $dest_folder, pm_new = 0 - WHERE folder_id = " . PRIVMSGS_NO_BOX . " - AND user_id = $user_id - AND pm_new = 1 - AND " . $db->sql_in_set('msg_id', $msg_ary); - $db->sql_query($sql); - - if ($dest_folder != PRIVMSGS_INBOX) - { - $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . ' - SET pm_count = pm_count + ' . (int) $db->sql_affectedrows() . " - WHERE folder_id = $dest_folder - AND user_id = $user_id"; - $db->sql_query($sql); - } - } - } - - 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) - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET folder_id = ' . PRIVMSGS_SENTBOX . ' - WHERE folder_id = ' . PRIVMSGS_OUTBOX . ' - AND ' . $db->sql_in_set('msg_id', array_keys($action_ary)); - $db->sql_query($sql); - } - - // Update new/unread count - update_pm_counts(); - - // Now check how many messages got not moved... - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id = " . PRIVMSGS_HOLD_BOX; - $result = $db->sql_query($sql); - $num_not_moved = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - - return array('not_moved' => $num_not_moved, 'removed' => $num_removed); -} - -/** -* Move PM from one to another folder -*/ -function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_folder_id) -{ - global $db, $user; - global $phpbb_root_path, $phpEx; - - $num_moved = 0; - - if (!is_array($move_msg_ids)) - { - $move_msg_ids = array($move_msg_ids); - } - - 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 ;) - if ($dest_folder != PRIVMSGS_INBOX) - { - $sql = 'SELECT folder_id, folder_name, pm_count - FROM ' . PRIVMSGS_FOLDER_TABLE . " - WHERE folder_id = $dest_folder - AND user_id = $user_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } - - if ($message_limit && $row['pm_count'] + count($move_msg_ids) > $message_limit) - { - $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '

'; - $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $row['folder_name']); - trigger_error($message); - } - } - else - { - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE folder_id = ' . PRIVMSGS_INBOX . " - AND user_id = $user_id"; - $result = $db->sql_query($sql); - $num_messages = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - - if ($message_limit && $num_messages + count($move_msg_ids) > $message_limit) - { - $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $user->lang['PM_INBOX']) . '

'; - $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_INBOX']); - trigger_error($message); - } - } - - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " - SET folder_id = $dest_folder - WHERE folder_id = $cur_folder_id - AND user_id = $user_id - AND " . $db->sql_in_set('msg_id', $move_msg_ids); - $db->sql_query($sql); - $num_moved = $db->sql_affectedrows(); - - // Update pm counts - if ($num_moved) - { - if (!in_array($cur_folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX))) - { - $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . " - SET pm_count = pm_count - $num_moved - WHERE folder_id = $cur_folder_id - AND user_id = $user_id"; - $db->sql_query($sql); - } - - if ($dest_folder != PRIVMSGS_INBOX) - { - $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . " - SET pm_count = pm_count + $num_moved - WHERE folder_id = $dest_folder - AND user_id = $user_id"; - $db->sql_query($sql); - } - } - } - else if (in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX))) - { - trigger_error('CANNOT_MOVE_SPECIAL'); - } - - return $num_moved; -} - -/** -* Update unread message status -*/ -function update_unread_status($unread, $msg_id, $user_id, $folder_id) -{ - if (!$unread) - { - return; - } - - global $db, $user, $phpbb_container; - - /* @var $phpbb_notifications \phpbb\notification\manager */ - $phpbb_notifications = $phpbb_container->get('notification_manager'); - - $phpbb_notifications->mark_notifications('notification.type.pm', $msg_id, $user_id); - - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " - SET pm_unread = 0 - WHERE msg_id = $msg_id - AND user_id = $user_id - AND folder_id = $folder_id - AND pm_unread = 1"; - $db->sql_query($sql); - - // If the message is already marked as read, we just skip the rest to avoid negative PM count - if (!$db->sql_affectedrows()) - { - return; - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_unread_privmsg = user_unread_privmsg - 1 - WHERE user_id = $user_id"; - $db->sql_query($sql); - - if ($user->data['user_id'] == $user_id) - { - $user->data['user_unread_privmsg']--; - - // Try to cope with previous wrong conversions... - if ($user->data['user_unread_privmsg'] < 0) - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_unread_privmsg = 0 - WHERE user_id = $user_id"; - $db->sql_query($sql); - - $user->data['user_unread_privmsg'] = 0; - } - } -} - -function mark_folder_read($user_id, $folder_id) -{ - global $db; - - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE folder_id = ' . ((int) $folder_id) . ' - AND user_id = ' . ((int) $user_id) . ' - AND pm_unread = 1'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - update_unread_status(true, $row['msg_id'], $user_id, $folder_id); - } - $db->sql_freeresult($result); -} - -/** -* Handle all actions possible with marked messages -*/ -function handle_mark_actions($user_id, $mark_action) -{ - global $db, $user, $phpbb_root_path, $phpEx, $request; - - $msg_ids = $request->variable('marked_msg_id', array(0)); - $cur_folder_id = $request->variable('cur_folder_id', PRIVMSGS_NO_BOX); - - if (!count($msg_ids)) - { - return false; - } - - switch ($mark_action) - { - case 'mark_important': - - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " - SET pm_marked = 1 - pm_marked - WHERE folder_id = $cur_folder_id - AND user_id = $user_id - AND " . $db->sql_in_set('msg_id', $msg_ids); - $db->sql_query($sql); - - break; - - case 'delete_marked': - - global $auth; - - if (!$auth->acl_get('u_pm_delete')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_DELETE_MESSAGE'); - } - - if (confirm_box(true)) - { - delete_pm($user_id, $msg_ids, $cur_folder_id); - - $success_msg = (count($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED'; - $redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $cur_folder_id); - - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . sprintf($user->lang['RETURN_FOLDER'], '', '')); - } - else - { - $s_hidden_fields = array( - 'cur_folder_id' => $cur_folder_id, - 'mark_option' => 'delete_marked', - 'submit_mark' => true, - 'marked_msg_id' => $msg_ids - ); - - confirm_box(false, 'DELETE_MARKED_PM', build_hidden_fields($s_hidden_fields)); - } - - break; - - default: - return false; - } - - return true; -} - -/** -* Delete PM(s) -*/ -function delete_pm($user_id, $msg_ids, $folder_id) -{ - global $db, $user, $phpbb_container, $phpbb_dispatcher; - - $user_id = (int) $user_id; - $folder_id = (int) $folder_id; - - if (!$user_id) - { - return false; - } - - if (!is_array($msg_ids)) - { - if (!$msg_ids) - { - return false; - } - $msg_ids = array($msg_ids); - } - - if (!count($msg_ids)) - { - return false; - } - - /** - * Get all info for PM(s) before they are deleted - * - * @event core.delete_pm_before - * @var int user_id ID of the user requested the message delete - * @var array msg_ids array of all messages to be deleted - * @var int folder_id ID of the user folder where the messages are stored - * @since 3.1.0-b5 - */ - $vars = array('user_id', 'msg_ids', 'folder_id'); - extract($phpbb_dispatcher->trigger_event('core.delete_pm_before', compact($vars))); - - // Get PM Information for later deleting - $sql = 'SELECT msg_id, pm_unread, pm_new - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', array_map('intval', $msg_ids)) . " - AND folder_id = $folder_id - AND user_id = $user_id"; - $result = $db->sql_query($sql); - - $delete_rows = array(); - $num_unread = $num_new = $num_deleted = 0; - while ($row = $db->sql_fetchrow($result)) - { - $num_unread += (int) $row['pm_unread']; - $num_new += (int) $row['pm_new']; - - $delete_rows[$row['msg_id']] = 1; - } - $db->sql_freeresult($result); - unset($msg_ids); - - if (!count($delete_rows)) - { - return false; - } - - $db->sql_transaction('begin'); - - // if no one has read the message yet (meaning it is in users outbox) - // then mark the message as deleted... - if ($folder_id == PRIVMSGS_OUTBOX) - { - // Remove PM from Outbox - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id AND folder_id = " . PRIVMSGS_OUTBOX . ' - AND ' . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $db->sql_query($sql); - - // Update PM Information for safety - $sql = 'UPDATE ' . PRIVMSGS_TABLE . " SET message_text = '' - WHERE " . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $db->sql_query($sql); - - // Set delete flag for those intended to receive the PM - // We do not remove the message actually, to retain some basic information (sent time for example) - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET pm_deleted = 1 - WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $db->sql_query($sql); - - $num_deleted = $db->sql_affectedrows(); - } - else - { - // Delete private message data - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id = $folder_id - AND " . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $db->sql_query($sql); - $num_deleted = $db->sql_affectedrows(); - } - - // if folder id is user defined folder then decrease pm_count - if (!in_array($folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX, PRIVMSGS_NO_BOX))) - { - $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . " - SET pm_count = pm_count - $num_deleted - WHERE folder_id = $folder_id"; - $db->sql_query($sql); - } - - // Update unread and new status field - if ($num_unread || $num_new) - { - $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : ''; - - if ($num_new) - { - $set_sql .= ($set_sql != '') ? ', ' : ''; - $set_sql .= 'user_new_privmsg = user_new_privmsg - ' . $num_new; - } - - $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id"); - - $user->data['user_new_privmsg'] -= $num_new; - $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)); - - // Now we have to check which messages we can delete completely - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - unset($delete_rows[$row['msg_id']]); - } - $db->sql_freeresult($result); - - $delete_ids = array_keys($delete_rows); - - if (count($delete_ids)) - { - // Check if there are any attachments we need to remove - /** @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); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - return true; -} - -/** -* Delete all PM(s) for a given user and delete the ones without references -* -* @param int $user_id ID of the user whose private messages we want to delete -* -* @return boolean False if there were no pms found, true otherwise. -*/ -function phpbb_delete_user_pms($user_id) -{ - $user_id = (int) $user_id; - - if (!$user_id) - { - return false; - } - - return phpbb_delete_users_pms(array($user_id)); -} - -/** -* Delete all PM(s) for given users and delete the ones without references -* -* @param array $user_ids IDs of the users whose private messages we want to delete -* -* @return boolean False if there were no pms found, true otherwise. -*/ -function phpbb_delete_users_pms($user_ids) -{ - 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); - - // Get PM Information for later deleting - // The two queries where split, so we can use our indexes - $undelivered_msg = $delete_ids = array(); - - // Part 1: get PMs the user received - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $user_id_sql; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $msg_id = (int) $row['msg_id']; - $delete_ids[$msg_id] = $msg_id; - } - $db->sql_freeresult($result); - - // Part 2: get PMs the users sent, but are yet to be received. - // We cannot simply delete them. First we have to check - // whether another user already received and read the message. - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $author_id_sql . ' - AND folder_id = ' . PRIVMSGS_NO_BOX; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $msg_id = (int) $row['msg_id']; - $undelivered_msg[$msg_id] = $msg_id; - } - $db->sql_freeresult($result); - - if (empty($delete_ids) && empty($undelivered_msg)) - { - return false; - } - - $db->sql_transaction('begin'); - - /* @var $phpbb_notifications \phpbb\notification\manager */ - $phpbb_notifications = $phpbb_container->get('notification_manager'); - - if (!empty($undelivered_msg)) - { - // A pm is delivered, if for any recipient the message was moved - // from their NO_BOX to another folder. We do not delete such - // messages, but only delete them for users, who have not yet - // received them. - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $author_id_sql . ' - AND folder_id <> ' . PRIVMSGS_NO_BOX . ' - AND folder_id <> ' . PRIVMSGS_OUTBOX . ' - AND folder_id <> ' . PRIVMSGS_SENTBOX; - $result = $db->sql_query($sql); - - $delivered_msg = array(); - while ($row = $db->sql_fetchrow($result)) - { - $msg_id = (int) $row['msg_id']; - $delivered_msg[$msg_id] = $msg_id; - unset($undelivered_msg[$msg_id]); - } - $db->sql_freeresult($result); - - $undelivered_user = array(); - - // Count the messages we delete, so we can correct the user pm data - $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $author_id_sql . ' - AND folder_id = ' . PRIVMSGS_NO_BOX . ' - AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . ' - GROUP BY user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $num_pms = (int) $row['num_undelivered_privmsgs']; - $undelivered_user[$num_pms][] = (int) $row['user_id']; - - 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. - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ', - user_unread_privmsg = user_unread_privmsg - ' . $num_pms . ' - WHERE ' . $db->sql_in_set('user_id', $undelivered_user[$num_pms]); - $db->sql_query($sql); - unset($undelivered_user[$num_pms]); - } - } - $db->sql_freeresult($result); - - foreach ($undelivered_user as $num_pms => $undelivered_user_set) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ', - user_unread_privmsg = user_unread_privmsg - ' . $num_pms . ' - WHERE ' . $db->sql_in_set('user_id', $undelivered_user_set); - $db->sql_query($sql); - } - - if (!empty($delivered_msg)) - { - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE folder_id = ' . PRIVMSGS_NO_BOX . ' - AND ' . $db->sql_in_set('msg_id', $delivered_msg); - $db->sql_query($sql); - - $phpbb_notifications->delete_notifications('notification.type.pm', $delivered_msg); - } - - if (!empty($undelivered_msg)) - { - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); - $db->sql_query($sql); - - $phpbb_notifications->delete_notifications('notification.type.pm', $undelivered_msg); - } - } - - // Reset the user's pm count to 0 - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = 0, - user_unread_privmsg = 0 - WHERE ' . $user_id_sql; - $db->sql_query($sql); - - // Delete private message data of the user - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $user_id_sql; - $db->sql_query($sql); - - if (!empty($delete_ids)) - { - // Now we have to check which messages we can delete completely - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', $delete_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - unset($delete_ids[$row['msg_id']]); - } - $db->sql_freeresult($result); - - if (!empty($delete_ids)) - { - // Check if there are any attachments we need to remove - /** @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); - $db->sql_query($sql); - - $phpbb_notifications->delete_notifications('notification.type.pm', $delete_ids); - } - } - - // Set the remaining author id to anonymous - // This way users are still able to read messages from users being removed - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET author_id = ' . ANONYMOUS . ' - WHERE ' . $author_id_sql; - $db->sql_query($sql); - - $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' - SET author_id = ' . ANONYMOUS . ' - WHERE ' . $author_id_sql; - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - return true; -} - -/** -* Rebuild message header -*/ -function rebuild_header($check_ary) -{ - $address = array(); - - foreach ($check_ary as $check_type => $address_field) - { - // Split Addresses into users and groups - preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match); - - $u = $g = array(); - foreach ($match[1] as $id => $type) - { - ${$type}[] = (int) $match[2][$id]; - } - - $_types = array('u', 'g'); - foreach ($_types as $type) - { - if (count(${$type})) - { - foreach (${$type} as $id) - { - $address[$type][$id] = $check_type; - } - } - } - } - - return $address; -} - -/** -* Print out/assign recipient information -*/ -function write_pm_addresses($check_ary, $author_id, $plaintext = false) -{ - 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(); - - foreach ($check_ary as $check_type => $address_field) - { - if (!is_array($address_field)) - { - // Split Addresses into users and groups - preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match); - - $u = $g = array(); - foreach ($match[1] as $id => $type) - { - ${$type}[] = (int) $match[2][$id]; - } - } - else - { - $u = $address_field['u']; - $g = $address_field['g']; - } - - $address = array(); - if (count($u)) - { - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $u); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id']) - { - if ($plaintext) - { - $address[] = $row['username']; - } - else - { - $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']); - } - } - } - $db->sql_freeresult($result); - } - - if (count($g)) - { - if ($plaintext) - { - $sql = 'SELECT group_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', $g); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id']) - { - $address[] = $group_helper->get_name($row['group_name']); - } - } - $db->sql_freeresult($result); - } - else - { - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id - FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug - WHERE ' . $db->sql_in_set('g.group_id', $g) . ' - AND g.group_id = ug.group_id - AND ug.user_pending = 0'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($address['group'][$row['group_id']])) - { - if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id']) - { - $row['group_name'] = $group_helper->get_name($row['group_name']); - $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']); - } - } - - if (isset($address['user'][$row['user_id']])) - { - $address['user'][$row['user_id']]['in_group'] = $row['group_id']; - } - } - $db->sql_freeresult($result); - } - } - - if (count($address) && !$plaintext) - { - $template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true); - - foreach ($address as $type => $adr_ary) - { - foreach ($adr_ary as $id => $row) - { - $tpl_ary = array( - 'IS_GROUP' => ($type == 'group') ? true : false, - 'IS_USER' => ($type == 'user') ? true : false, - 'UG_ID' => $id, - 'NAME' => $row['name'], - 'COLOUR' => ($row['colour']) ? '#' . $row['colour'] : '', - 'TYPE' => $type, - ); - - if ($type == 'user') - { - $tpl_ary = array_merge($tpl_ary, array( - 'U_VIEW' => get_username_string('profile', $id, $row['name'], $row['colour']), - 'NAME_FULL' => get_username_string('full', $id, $row['name'], $row['colour']), - )); - } - else - { - $tpl_ary = array_merge($tpl_ary, array( - 'U_VIEW' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $id), - )); - } - - $template->assign_block_vars($check_type . '_recipient', $tpl_ary); - } - } - } - - $addresses[$check_type] = $address; - } - - return $addresses; -} - -/** -* Get folder status -*/ -function get_folder_status($folder_id, $folder) -{ - global $user; - - if (isset($folder[$folder_id])) - { - $folder = $folder[$folder_id]; - } - else - { - return false; - } - - $return = array( - 'folder_name' => $folder['folder_name'], - 'cur' => $folder['num_messages'], - 'remaining' => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0, - 'max' => $user->data['message_limit'], - 'percent' => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? floor(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0, - ); - - $return['message'] = $user->lang('FOLDER_STATUS_MSG', $user->lang('MESSAGES_COUNT', (int) $return['max']), (int) $return['cur'], $return['percent']); - - return $return; -} - -// -// COMPOSE MESSAGES -// - -/** -* Submit PM -*/ -function submit_pm($mode, $subject, &$data_ary, $put_in_outbox = true) -{ - global $db, $auth, $config, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $request; - - // We do not handle erasing pms here - if ($mode == 'delete') - { - return false; - } - - $current_time = time(); - - $data = $data_ary; - /** - * Get all parts of the PM that are to be submited to the DB. - * - * @event core.submit_pm_before - * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit - * @var string subject Subject of the private message - * @var array data The whole row data of the PM. - * @since 3.1.0-b3 - */ - $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(); - $root_level = 0; - - // Recipient Information - $recipients = $to = $bcc = array(); - - if ($mode != 'edit') - { - // Build Recipient List - // u|g => array($user_id => 'to'|'bcc') - $_types = array('u', 'g'); - foreach ($_types as $ug_type) - { - if (isset($data_ary['address_list'][$ug_type]) && count($data_ary['address_list'][$ug_type])) - { - foreach ($data_ary['address_list'][$ug_type] as $id => $field) - { - $id = (int) $id; - - // Do not rely on the address list being "valid" - if (!$id || ($ug_type == 'u' && $id == ANONYMOUS)) - { - continue; - } - - $field = ($field == 'to') ? 'to' : 'bcc'; - if ($ug_type == 'u') - { - $recipients[$id] = $field; - } - ${$field}[] = $ug_type . '_' . $id; - } - } - } - - 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 - $sql_allow_pm = (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) ? ' AND u.user_allow_pm = 1' : ''; - - $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_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 . ')' . - $sql_allow_pm; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $field = ($data_ary['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc'; - $recipients[$row['user_id']] = $field; - } - $db->sql_freeresult($result); - } - - if (!count($recipients)) - { - trigger_error('NO_RECIPIENT'); - } - } - - // First of all make sure the subject are having the correct length. - $subject = truncate_string($subject); - - $db->sql_transaction('begin'); - - $sql = ''; - - switch ($mode) - { - case 'reply': - case 'quote': - $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_ary['from_user_id'] . ' - AND msg_id = ' . $data_ary['reply_from_msg_id']; - - // no break - - case 'forward': - case 'post': - case 'quotepost': - $sql_data = array( - 'root_level' => $root_level, - '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_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_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, - ); - break; - - case 'edit': - $sql_data = array( - 'icon_id' => $data_ary['icon_id'], - 'message_edit_time' => $current_time, - '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_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 (count($sql_data)) - { - 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_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_ary['msg_id']; - $db->sql_query($sql); - } - } - - if ($mode != 'edit') - { - if ($sql) - { - $db->sql_query($sql); - } - unset($sql); - - $sql_ary = array(); - foreach ($recipients as $user_id => $type) - { - $sql_ary[] = array( - 'msg_id' => (int) $data_ary['msg_id'], - 'user_id' => (int) $user_id, - 'author_id' => (int) $data_ary['from_user_id'], - 'folder_id' => PRIVMSGS_NO_BOX, - 'pm_new' => 1, - 'pm_unread' => 1, - 'pm_forwarded' => ($mode == 'forward') ? 1 : 0 - ); - } - - $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($recipients)); - $db->sql_query($sql); - - // Put PM into outbox - if ($put_in_outbox) - { - $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array( - '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, - 'pm_forwarded' => ($mode == 'forward') ? 1 : 0)) - ); - } - } - - // Set user last post time - if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post') - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastpost_time = $current_time - WHERE user_id = " . $data_ary['from_user_id']; - $db->sql_query($sql); - } - - // Submit Attachments - 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_ary['attachment_data'] as $pos => $attach_row) - { - $orphan_rows[(int) $attach_row['attach_id']] = array(); - } - - if (count($orphan_rows)) - { - $sql = 'SELECT attach_id, filesize, physical_filename - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . ' - AND in_message = 1 - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - $orphan_rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $orphan_rows[$row['attach_id']] = $row; - } - $db->sql_freeresult($result); - } - - foreach ($data_ary['attachment_data'] as $pos => $attach_row) - { - if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']])) - { - continue; - } - - if (!$attach_row['is_orphan']) - { - // update entry in db if attachment already stored in db and filespace - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "' - WHERE attach_id = " . (int) $attach_row['attach_id'] . ' - AND is_orphan = 0'; - $db->sql_query($sql); - } - else - { - // insert attachment into db - if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) - { - continue; - } - - $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize']; - $files_added++; - - $attach_sql = array( - 'post_msg_id' => $data_ary['msg_id'], - 'topic_id' => 0, - 'is_orphan' => 0, - 'poster_id' => $data_ary['from_user_id'], - 'attach_comment' => $attach_row['attach_comment'], - ); - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . ' - WHERE attach_id = ' . $attach_row['attach_id'] . ' - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $db->sql_query($sql); - } - } - - if ($space_taken && $files_added) - { - $config->increment('upload_dir_size', $space_taken, false); - $config->increment('num_files', $files_added, false); - } - } - - // Delete draft if post was loaded... - $draft_id = $request->variable('draft_loaded', 0); - if ($draft_id) - { - $sql = 'DELETE FROM ' . DRAFTS_TABLE . " - WHERE draft_id = $draft_id - AND user_id = " . $data_ary['from_user_id']; - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - // Send Notifications - $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') - { - $phpbb_notifications->update_notifications('notification.type.pm', $pm_data); - } - else - { - $phpbb_notifications->add_notifications('notification.type.pm', $pm_data); - } - - $data = $data_ary; - /** - * Get PM message ID after submission to DB - * - * @event core.submit_pm_after - * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit - * @var string subject Subject of the private message - * @var array data The whole row data of the PM. - * @var array pm_data The data sent to notification class - * @since 3.1.0-b5 - */ - $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_ary['msg_id']; -} - -/** -* Display Message History -*/ -function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false) -{ - 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 - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE msg_id = $msg_id - AND folder_id <> " . PRIVMSGS_HOLD_BOX; - $result = $db->sql_query($sql); - - $recipients = array(); - while ($row = $db->sql_fetchrow($result)) - { - $recipients[] = (int) $row['user_id']; - $recipients[] = (int) $row['author_id']; - } - $db->sql_freeresult($result); - $recipients = array_unique($recipients); - - // Get History Messages (could be newer) - $sql_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) . " - AND t.user_id = $user_id"; - - // We no longer need those. - unset($recipients); - - if (!$message_row['root_level']) - { - $sql_where .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))"; - } - else - { - $sql_where .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')'; - } - - $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); - - if (!$row) - { - $db->sql_freeresult($result); - return false; - } - - $title = $row['message_subject']; - - $rowset = array(); - $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&folder='; - - do - { - $folder_id = (int) $row['folder_id']; - - $row['folder'][] = (isset($folder[$folder_id])) ? '' . $folder[$folder_id]['folder_name'] . '' : $user->lang['UNKNOWN_FOLDER']; - - if (isset($rowset[$row['msg_id']])) - { - $rowset[$row['msg_id']]['folder'][] = (isset($folder[$folder_id])) ? '' . $folder[$folder_id]['folder_name'] . '' : $user->lang['UNKNOWN_FOLDER']; - } - else - { - $rowset[$row['msg_id']] = $row; - } - } - while ($row = $db->sql_fetchrow($result)); - $db->sql_freeresult($result); - - if (count($rowset) == 1 && !$in_post_mode) - { - return false; - } - - $title = censor_text($title); - - $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm'); - $next_history_pm = $previous_history_pm = $prev_id = 0; - - // Re-order rowset to be able to get the next/prev message rows... - $rowset = array_values($rowset); - - for ($i = 0, $size = count($rowset); $i < $size; $i++) - { - $row = &$rowset[$i]; - $id = (int) $row['msg_id']; - - $author_id = $row['author_id']; - $folder_id = (int) $row['folder_id']; - - $subject = $row['message_subject']; - $message = $row['message_text']; - - $message = censor_text($message); - - $decoded_message = false; - - if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) - { - $decoded_message = $message; - decode_message($decoded_message, $row['bbcode_uid']); - - $decoded_message = bbcode_nl2br($decoded_message); - } - - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); - $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0); - - $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); - - $subject = censor_text($subject); - - if ($id == $msg_id) - { - $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0; - $previous_history_pm = $prev_id; - } - - $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']), - 'MESSAGE_AUTHOR' => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']), - 'U_MESSAGE_AUTHOR' => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']), - - 'SUBJECT' => $subject, - 'SENT_DATE' => $user->format_date($row['message_time']), - 'MESSAGE' => $message, - 'FOLDER' => implode($user->lang['COMMA_SEPARATOR'], $row['folder']), - 'DECODED_MESSAGE' => $decoded_message, - - 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id), - 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false, - '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&f=$folder_id&p=" . $row['msg_id'], - 'U_QUOTE' => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=quote&f=" . $folder_id . "&p=" . $row['msg_id'] : '', - 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $row['msg_id'] : '' - ); - - /** - * 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; - } - - $template->assign_vars(array( - 'QUOTE_IMG' => $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']), - 'HISTORY_TITLE' => $title, - - 'U_VIEW_NEXT_HISTORY' => ($next_history_pm) ? "$url&p=" . $next_history_pm : '', - 'U_VIEW_PREVIOUS_HISTORY' => ($previous_history_pm) ? "$url&p=" . $previous_history_pm : '', - )); - - return true; -} - -/** -* Set correct users max messages in PM folder. -* If several group memberships define different amount of messages, the highest will be chosen. -*/ -function set_user_message_limit() -{ - global $user, $db, $config; - - // 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 = ' . (int) $user_id . ' - AND ug.user_pending = 0 - AND ug.group_id = g.group_id'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - $max_setting = (int) $row['max_setting']; - - return $max_setting; -} - -/** -* Generates an array of coloured recipient names from a list of PMs - (groups & users) -* -* @param array $pm_by_id An array of rows from PRIVMSGS_TABLE, keys are the msg_ids. -* -* @return array 2D Array: array(msg_id => array('username or group string', ...), ...) -* Usernames are generated with {@link get_username_string get_username_string} -* Groups are coloured and have a link to the membership page -*/ -function get_recipient_strings($pm_by_id) -{ - global $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(); - - $_types = array('u', 'g'); - - foreach ($pm_by_id as $message_id => $row) - { - $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address'])); - - foreach ($_types as $ug_type) - { - if (isset($address[$message_id][$ug_type]) && count($address[$message_id][$ug_type])) - { - foreach ($address[$message_id][$ug_type] as $ug_id => $in_to) - { - $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => ''); - } - } - } - } - - foreach ($_types as $ug_type) - { - if (!empty($recipient_list[$ug_type])) - { - if ($ug_type == 'u') - { - $sql = 'SELECT user_id as id, username as name, user_colour as colour - FROM ' . USERS_TABLE . ' - WHERE '; - } - else - { - $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type - FROM ' . GROUPS_TABLE . ' - WHERE '; - } - $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type]))); - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($ug_type == 'g') - { - $row['name'] = $group_helper->get_name($row['name']); - } - - $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']); - } - $db->sql_freeresult($result); - } - } - - foreach ($address as $message_id => $adr_ary) - { - foreach ($adr_ary as $type => $id_ary) - { - foreach ($id_ary as $ug_id => $_id) - { - if ($type == 'u') - { - $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']); - } - else - { - $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : ''; - $link = ''; - $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '' : ''); - } - } - } - } - - return $address_list; -} diff --git a/install/update/new/includes/functions_transfer.php b/install/update/new/includes/functions_transfer.php deleted file mode 100644 index f0070b4..0000000 --- a/install/update/new/includes/functions_transfer.php +++ /dev/null @@ -1,899 +0,0 @@ - -* @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; -} - -/** -* Transfer class, wrapper for ftp/sftp/ssh -*/ -class transfer -{ - var $connection; - var $host; - var $port; - var $username; - var $password; - var $timeout; - var $root_path; - var $tmp_path; - var $file_perms; - var $dir_perms; - - /** - * Constructor - init some basic values - */ - function __construct() - { - global $phpbb_root_path; - - $this->file_perms = 0644; - $this->dir_perms = 0777; - - // We use the store directory as temporary path to circumvent open basedir restrictions - $this->tmp_path = $phpbb_root_path . 'store/'; - } - - /** - * Write file to location - */ - function write_file($destination_file = '', $contents = '') - { - global $phpbb_root_path; - - $destination_file = $this->root_path . str_replace($phpbb_root_path, '', $destination_file); - - // need to create a temp file and then move that temp file. - // ftp functions can only move files around and can't create. - // This means that the users will need to have access to write - // temporary files or have write access on a folder within phpBB - // like the cache folder. If the user can't do either, then - // he/she needs to use the fsock ftp method - $temp_name = tempnam($this->tmp_path, 'transfer_'); - @unlink($temp_name); - - $fp = @fopen($temp_name, 'w'); - - if (!$fp) - { - trigger_error('Unable to create temporary file ' . $temp_name, E_USER_ERROR); - } - - @fwrite($fp, $contents); - @fclose($fp); - - $result = $this->overwrite_file($temp_name, $destination_file); - - // remove temporary file now - @unlink($temp_name); - - return $result; - } - - /** - * Moving file into location. If the destination file already exists it gets overwritten - */ - function overwrite_file($source_file, $destination_file) - { - /** - * @todo generally think about overwriting files in another way, by creating a temporary file and then renaming it - * @todo check for the destination file existance too - */ - $this->_delete($destination_file); - $result = $this->_put($source_file, $destination_file); - $this->_chmod($destination_file, $this->file_perms); - - return $result; - } - - /** - * Create directory structure - */ - function make_dir($dir) - { - global $phpbb_root_path; - - $dir = str_replace($phpbb_root_path, '', $dir); - $dir = explode('/', $dir); - $dirs = ''; - - for ($i = 0, $total = count($dir); $i < $total; $i++) - { - $result = true; - - if (strpos($dir[$i], '.') === 0) - { - continue; - } - $cur_dir = $dir[$i] . '/'; - - if (!file_exists($phpbb_root_path . $dirs . $cur_dir)) - { - // create the directory - $result = $this->_mkdir($dir[$i]); - $this->_chmod($dir[$i], $this->dir_perms); - } - - $this->_chdir($this->root_path . $dirs . $dir[$i]); - $dirs .= $cur_dir; - } - - $this->_chdir($this->root_path); - - /** - * @todo stack result into array to make sure every path creation has been taken care of - */ - return $result; - } - - /** - * Copy file from source location to destination location - */ - function copy_file($from_loc, $to_loc) - { - global $phpbb_root_path; - - $from_loc = ((strpos($from_loc, $phpbb_root_path) !== 0) ? $phpbb_root_path : '') . $from_loc; - $to_loc = $this->root_path . str_replace($phpbb_root_path, '', $to_loc); - - if (!file_exists($from_loc)) - { - return false; - } - - $result = $this->overwrite_file($from_loc, $to_loc); - - return $result; - } - - /** - * Remove file - */ - function delete_file($file) - { - global $phpbb_root_path; - - $file = $this->root_path . str_replace($phpbb_root_path, '', $file); - - return $this->_delete($file); - } - - /** - * Remove directory - * @todo remove child directories? - */ - function remove_dir($dir) - { - global $phpbb_root_path; - - $dir = $this->root_path . str_replace($phpbb_root_path, '', $dir); - - return $this->_rmdir($dir); - } - - /** - * Rename a file or folder - */ - function rename($old_handle, $new_handle) - { - global $phpbb_root_path; - - $old_handle = $this->root_path . str_replace($phpbb_root_path, '', $old_handle); - - return $this->_rename($old_handle, $new_handle); - } - - /** - * Check if a specified file exist... - */ - function file_exists($directory, $filename) - { - global $phpbb_root_path; - - $directory = $this->root_path . str_replace($phpbb_root_path, '', $directory); - - $this->_chdir($directory); - $result = $this->_ls(); - - if ($result !== false && is_array($result)) - { - return (in_array($filename, $result)) ? true : false; - } - - return false; - } - - /** - * Open session - */ - function open_session() - { - return $this->_init(); - } - - /** - * Close current session - */ - function close_session() - { - return $this->_close(); - } - - /** - * Determine methods able to be used - */ - static public function methods() - { - $methods = array(); - $disabled_functions = explode(',', @ini_get('disable_functions')); - - if (@extension_loaded('ftp')) - { - $methods[] = 'ftp'; - } - - if (!in_array('fsockopen', $disabled_functions)) - { - $methods[] = 'ftp_fsock'; - } - - return $methods; - } -} - -/** -* FTP transfer class -*/ -class ftp extends transfer -{ - /** - * Standard parameters for FTP session - */ - function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10) - { - $this->host = $host; - $this->port = $port; - $this->username = $username; - $this->password = $password; - $this->timeout = $timeout; - - // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end) - $this->root_path = str_replace('\\', '/', $this->root_path); - - if (!empty($root_path)) - { - $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/'); - } - - // Init some needed values - $this->transfer(); - - return; - } - - /** - * Requests data - */ - static public function data() - { - global $user; - - return array( - 'host' => 'localhost', - 'username' => 'anonymous', - 'password' => '', - 'root_path' => $user->page['root_script_path'], - 'port' => 21, - 'timeout' => 10 - ); - } - - /** - * Init FTP Session - * @access private - */ - function _init() - { - // connect to the server - $this->connection = @ftp_connect($this->host, $this->port, $this->timeout); - - if (!$this->connection) - { - return 'ERR_CONNECTING_SERVER'; - } - - // login to the server - if (!@ftp_login($this->connection, $this->username, $this->password)) - { - return 'ERR_UNABLE_TO_LOGIN'; - } - - // attempt to turn pasv mode on - @ftp_pasv($this->connection, true); - - // change to the root directory - if (!$this->_chdir($this->root_path)) - { - return 'ERR_CHANGING_DIRECTORY'; - } - - return true; - } - - /** - * Create Directory (MKDIR) - * @access private - */ - function _mkdir($dir) - { - return @ftp_mkdir($this->connection, $dir); - } - - /** - * Remove directory (RMDIR) - * @access private - */ - function _rmdir($dir) - { - return @ftp_rmdir($this->connection, $dir); - } - - /** - * Rename file - * @access private - */ - function _rename($old_handle, $new_handle) - { - return @ftp_rename($this->connection, $old_handle, $new_handle); - } - - /** - * Change current working directory (CHDIR) - * @access private - */ - function _chdir($dir = '') - { - if ($dir && $dir !== '/') - { - if (substr($dir, -1, 1) == '/') - { - $dir = substr($dir, 0, -1); - } - } - - return @ftp_chdir($this->connection, $dir); - } - - /** - * change file permissions (CHMOD) - * @access private - */ - function _chmod($file, $perms) - { - if (function_exists('ftp_chmod')) - { - $err = @ftp_chmod($this->connection, $perms, $file); - } - else - { - // Unfortunatly CHMOD is not expecting an octal value... - // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;) - $chmod_cmd = 'CHMOD ' . base_convert($perms, 10, 8) . ' ' . $file; - $err = $this->_site($chmod_cmd); - } - - return $err; - } - - /** - * Upload file to location (PUT) - * @access private - */ - function _put($from_file, $to_file) - { - // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced) - $mode = FTP_BINARY; - - $to_dir = dirname($to_file); - $to_file = basename($to_file); - $this->_chdir($to_dir); - - $result = @ftp_put($this->connection, $to_file, $from_file, $mode); - $this->_chdir($this->root_path); - - return $result; - } - - /** - * Delete file (DELETE) - * @access private - */ - function _delete($file) - { - return @ftp_delete($this->connection, $file); - } - - /** - * Close ftp session (CLOSE) - * @access private - */ - function _close() - { - if (!$this->connection) - { - return false; - } - - return @ftp_quit($this->connection); - } - - /** - * Return current working directory (CWD) - * At the moment not used by parent class - * @access private - */ - function _cwd() - { - return @ftp_pwd($this->connection); - } - - /** - * Return list of files in a given directory (LS) - * @access private - */ - function _ls($dir = './') - { - $list = @ftp_nlist($this->connection, $dir); - - // See bug #46295 - Some FTP daemons don't like './' - if ($dir === './') - { - // Let's try some alternatives - $list = (empty($list)) ? @ftp_nlist($this->connection, '.') : $list; - $list = (empty($list)) ? @ftp_nlist($this->connection, '') : $list; - } - - // Return on error - if ($list === false) - { - return false; - } - - // Remove path if prepended - foreach ($list as $key => $item) - { - // Use same separator for item and dir - $item = str_replace('\\', '/', $item); - $dir = str_replace('\\', '/', $dir); - - if (!empty($dir) && strpos($item, $dir) === 0) - { - $item = substr($item, strlen($dir)); - } - - $list[$key] = $item; - } - - return $list; - } - - /** - * FTP SITE command (ftp-only function) - * @access private - */ - function _site($command) - { - return @ftp_site($this->connection, $command); - } -} - -/** -* FTP fsock transfer class -*/ -class ftp_fsock extends transfer -{ - var $data_connection; - - /** - * Standard parameters for FTP session - */ - function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10) - { - $this->host = $host; - $this->port = $port; - $this->username = $username; - $this->password = $password; - $this->timeout = $timeout; - - // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end) - $this->root_path = str_replace('\\', '/', $this->root_path); - - if (!empty($root_path)) - { - $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/'); - } - - // Init some needed values - parent::__construct(); - - return; - } - - /** - * Requests data - */ - static public function data() - { - global $user; - - return array( - 'host' => 'localhost', - 'username' => 'anonymous', - 'password' => '', - 'root_path' => $user->page['root_script_path'], - 'port' => 21, - 'timeout' => 10 - ); - } - - /** - * Init FTP Session - * @access private - */ - function _init() - { - $errno = 0; - $errstr = ''; - - // connect to the server - $this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout); - - if (!$this->connection || !$this->_check_command()) - { - return 'ERR_CONNECTING_SERVER'; - } - - @stream_set_timeout($this->connection, $this->timeout); - - // login - if (!$this->_send_command('USER', $this->username)) - { - return 'ERR_UNABLE_TO_LOGIN'; - } - - if (!$this->_send_command('PASS', $this->password)) - { - return 'ERR_UNABLE_TO_LOGIN'; - } - - // change to the root directory - if (!$this->_chdir($this->root_path)) - { - return 'ERR_CHANGING_DIRECTORY'; - } - - return true; - } - - /** - * Create Directory (MKDIR) - * @access private - */ - function _mkdir($dir) - { - return $this->_send_command('MKD', $dir); - } - - /** - * Remove directory (RMDIR) - * @access private - */ - function _rmdir($dir) - { - return $this->_send_command('RMD', $dir); - } - - /** - * Rename File - * @access private - */ - function _rename($old_handle, $new_handle) - { - $this->_send_command('RNFR', $old_handle); - return $this->_send_command('RNTO', $new_handle); - } - - /** - * Change current working directory (CHDIR) - * @access private - */ - function _chdir($dir = '') - { - if ($dir && $dir !== '/') - { - if (substr($dir, -1, 1) == '/') - { - $dir = substr($dir, 0, -1); - } - } - - return $this->_send_command('CWD', $dir); - } - - /** - * change file permissions (CHMOD) - * @access private - */ - function _chmod($file, $perms) - { - // Unfortunatly CHMOD is not expecting an octal value... - // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;) - return $this->_send_command('SITE CHMOD', base_convert($perms, 10, 8) . ' ' . $file); - } - - /** - * Upload file to location (PUT) - * @access private - */ - function _put($from_file, $to_file) - { - // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced) - // 'I' == BINARY - // 'A' == ASCII - if (!$this->_send_command('TYPE', 'I')) - { - return false; - } - - // open the connection to send file over - if (!$this->_open_data_connection()) - { - return false; - } - - $this->_send_command('STOR', $to_file, false); - - // send the file - $fp = @fopen($from_file, 'rb'); - while (!@feof($fp)) - { - @fwrite($this->data_connection, @fread($fp, 4096)); - } - @fclose($fp); - - // close connection - $this->_close_data_connection(); - - return $this->_check_command(); - } - - /** - * Delete file (DELETE) - * @access private - */ - function _delete($file) - { - return $this->_send_command('DELE', $file); - } - - /** - * Close ftp session (CLOSE) - * @access private - */ - function _close() - { - if (!$this->connection) - { - return false; - } - - return $this->_send_command('QUIT'); - } - - /** - * Return current working directory (CWD) - * At the moment not used by parent class - * @access private - */ - function _cwd() - { - $this->_send_command('PWD', '', false); - return preg_replace('#^[0-9]{3} "(.+)" .+\r\n#', '\\1', $this->_check_command(true)); - } - - /** - * Return list of files in a given directory (LS) - * @access private - */ - function _ls($dir = './') - { - if (!$this->_open_data_connection()) - { - return false; - } - - $this->_send_command('NLST', $dir); - - $list = array(); - while (!@feof($this->data_connection)) - { - $filename = preg_replace('#[\r\n]#', '', @fgets($this->data_connection, 512)); - - if ($filename !== '') - { - $list[] = $filename; - } - } - $this->_close_data_connection(); - - // Clear buffer - $this->_check_command(); - - // See bug #46295 - Some FTP daemons don't like './' - if ($dir === './' && empty($list)) - { - // Let's try some alternatives - $list = $this->_ls('.'); - - if (empty($list)) - { - $list = $this->_ls(''); - } - - return $list; - } - - // Remove path if prepended - foreach ($list as $key => $item) - { - // Use same separator for item and dir - $item = str_replace('\\', '/', $item); - $dir = str_replace('\\', '/', $dir); - - if (!empty($dir) && strpos($item, $dir) === 0) - { - $item = substr($item, strlen($dir)); - } - - $list[$key] = $item; - } - - return $list; - } - - /** - * Send a command to server (FTP fsock only function) - * @access private - */ - function _send_command($command, $args = '', $check = true) - { - if (!empty($args)) - { - $command = "$command $args"; - } - - fwrite($this->connection, $command . "\r\n"); - - if ($check === true && !$this->_check_command()) - { - return false; - } - - return true; - } - - /** - * Opens a connection to send data (FTP fosck only function) - * @access private - */ - function _open_data_connection() - { - // Try to find out whether we have a IPv4 or IPv6 (control) connection - if (function_exists('stream_socket_get_name')) - { - $socket_name = stream_socket_get_name($this->connection, true); - $server_ip = substr($socket_name, 0, strrpos($socket_name, ':')); - } - - if (isset($server_ip) && filter_var($server_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) // ipv4 - { - // Passive mode - $this->_send_command('PASV', '', false); - - if (!$ip_port = $this->_check_command(true)) - { - return false; - } - - // open the connection to start sending the file - if (!preg_match('#[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+#', $ip_port, $temp)) - { - // bad ip and port - return false; - } - - $temp = explode(',', $temp[0]); - $server_ip = $temp[0] . '.' . $temp[1] . '.' . $temp[2] . '.' . $temp[3]; - $server_port = $temp[4] * 256 + $temp[5]; - } - else // ipv6 - { - // Extended Passive Mode - RFC2428 - $this->_send_command('EPSV', '', false); - - if (!$epsv_response = $this->_check_command(true)) - { - return false; - } - - // Response looks like "229 Entering Extended Passive Mode (|||12345|)" - // where 12345 is the tcp port for the data connection - if (!preg_match('#\(\|\|\|([0-9]+)\|\)#', $epsv_response, $match)) - { - return false; - } - $server_port = (int) $match[1]; - - // fsockopen expects IPv6 address in square brackets - $server_ip = "[$server_ip]"; - } - - $errno = 0; - $errstr = ''; - - if (!$this->data_connection = @fsockopen($server_ip, $server_port, $errno, $errstr, $this->timeout)) - { - return false; - } - @stream_set_timeout($this->data_connection, $this->timeout); - - return true; - } - - /** - * Closes a connection used to send data - * @access private - */ - function _close_data_connection() - { - return @fclose($this->data_connection); - } - - /** - * Check to make sure command was successful (FTP fsock only function) - * @access private - */ - function _check_command($return = false) - { - $response = ''; - - do - { - $result = @fgets($this->connection, 512); - $response .= $result; - } - while (substr($result, 3, 1) !== ' '); - - if (!preg_match('#^[123]#', $response)) - { - return false; - } - - return ($return) ? $response : true; - } -} diff --git a/install/update/new/includes/functions_user.php b/install/update/new/includes/functions_user.php deleted file mode 100644 index dc6e092..0000000 --- a/install/update/new/includes/functions_user.php +++ /dev/null @@ -1,3757 +0,0 @@ - -* @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; -} - -/** -* Obtain user_ids from usernames or vice versa. Returns false on -* success else the error string -* -* @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, $update_references = false) -{ - global $db; - - // Are both arrays already filled? Yep, return else - // are neither array filled? - if ($user_id_ary && $username_ary) - { - return false; - } - else if (!$user_id_ary && !$username_ary) - { - return 'NO_USERS'; - } - - $which_ary = ($user_id_ary) ? 'user_id_ary' : 'username_ary'; - - if (${$which_ary} && !is_array(${$which_ary})) - { - ${$which_ary} = array(${$which_ary}); - } - - $sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', ${$which_ary}) : array_map('utf8_clean_string', ${$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(); - - // Grab the user id/username records - $sql_where = ($which_ary == 'user_id_ary') ? 'user_id' : 'username_clean'; - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set($sql_where, $sql_in); - - if ($user_type !== false && !empty($user_type)) - { - $sql .= ' AND ' . $db->sql_in_set('user_type', $user_type); - } - - $result = $db->sql_query($sql); - - if (!($row = $db->sql_fetchrow($result))) - { - $db->sql_freeresult($result); - return 'NO_USERS'; - } - - do - { - $username_ary[$row['user_id']] = $row['username']; - $user_id_ary[] = $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); - $db->sql_freeresult($result); - - return false; -} - -/** -* Get latest registered username and update database to reflect it -*/ -function update_last_username() -{ - global $config, $db; - - // Get latest username - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') - ORDER BY user_id DESC'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $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); - } -} - -/** -* Updates a username across all relevant tables/fields -* -* @param string $old_name the old/current username -* @param string $new_name the new username -*/ -function user_update_name($old_name, $new_name) -{ - global $config, $db, $cache, $phpbb_dispatcher; - - $update_ary = array( - FORUMS_TABLE => array( - 'forum_last_poster_id' => 'forum_last_poster_name', - ), - MODERATOR_CACHE_TABLE => array( - 'user_id' => 'username', - ), - POSTS_TABLE => array( - 'poster_id' => 'post_username', - ), - TOPICS_TABLE => array( - 'topic_poster' => 'topic_first_poster_name', - 'topic_last_poster_id' => 'topic_last_poster_name', - ), - ); - - foreach ($update_ary as $table => $field_ary) - { - foreach ($field_ary as $id_field => $name_field) - { - $sql = "UPDATE $table - SET $name_field = '" . $db->sql_escape($new_name) . "' - WHERE $name_field = '" . $db->sql_escape($old_name) . "' - AND $id_field <> " . ANONYMOUS; - $db->sql_query($sql); - } - } - - if ($config['newest_username'] == $old_name) - { - $config->set('newest_username', $new_name, false); - } - - /** - * Update a username when it is changed - * - * @event core.update_username - * @var string old_name The old username that is replaced - * @var string new_name The new username - * @since 3.1.0-a1 - */ - $vars = array('old_name', 'new_name'); - extract($phpbb_dispatcher->trigger_event('core.update_username', compact($vars))); - - // Because some tables/caches use username-specific data we need to purge this here. - $cache->destroy('sql', MODERATOR_CACHE_TABLE); -} - -/** -* 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 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, $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'])) - { - return false; - } - - $username_clean = utf8_clean_string($user_row['username']); - - if (empty($username_clean)) - { - return false; - } - - $sql_ary = array( - 'username' => $user_row['username'], - 'username_clean' => $username_clean, - 'user_password' => (isset($user_row['user_password'])) ? $user_row['user_password'] : '', - 'user_email' => strtolower($user_row['user_email']), - 'group_id' => $user_row['group_id'], - 'user_type' => $user_row['user_type'], - ); - - // These are the additional vars able to be specified - $additional_vars = array( - 'user_permissions' => '', - 'user_timezone' => $config['board_timezone'], - 'user_dateformat' => $config['default_dateformat'], - 'user_lang' => $config['default_lang'], - 'user_style' => (int) $config['default_style'], - 'user_actkey' => '', - 'user_ip' => '', - 'user_regdate' => time(), - 'user_passchg' => time(), - 'user_options' => 230271, - // We do not set the new flag here - registration scripts need to specify it - 'user_new' => 0, - - 'user_inactive_reason' => 0, - 'user_inactive_time' => 0, - 'user_lastmark' => time(), - 'user_lastvisit' => 0, - 'user_lastpost_time' => 0, - 'user_lastpage' => '', - 'user_posts' => 0, - 'user_colour' => '', - 'user_avatar' => '', - 'user_avatar_type' => '', - 'user_avatar_width' => 0, - 'user_avatar_height' => 0, - 'user_new_privmsg' => 0, - 'user_unread_privmsg' => 0, - 'user_last_privmsg' => 0, - 'user_message_rules' => 0, - 'user_full_folder' => PRIVMSGS_NO_BOX, - 'user_emailtime' => 0, - - 'user_notify' => 0, - 'user_notify_pm' => 1, - 'user_notify_type' => NOTIFY_EMAIL, - 'user_allow_pm' => 1, - 'user_allow_viewonline' => 1, - 'user_allow_viewemail' => 1, - 'user_allow_massemail' => 1, - - 'user_sig' => '', - 'user_sig_bbcode_uid' => '', - 'user_sig_bbcode_bitfield' => '', - - 'user_form_salt' => unique_id(), - ); - - // Now fill the sql array with not required variables - foreach ($additional_vars as $key => $default_value) - { - $sql_ary[$key] = (isset($user_row[$key])) ? $user_row[$key] : $default_value; - } - - // Any additional variables in $user_row not covered above? - $remaining_vars = array_diff(array_keys($user_row), array_keys($sql_ary)); - - // Now fill our sql array with the remaining vars - if (count($remaining_vars)) - { - foreach ($remaining_vars as $key) - { - $sql_ary[$key] = $user_row[$key]; - } - } - - /** - * 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 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 - * @changed 3.1.0-b5 Added user_row and cp_data - * @changed 3.1.11-RC1 Added notifications_data - */ - $vars = array('user_row', 'cp_data', 'sql_ary', 'notifications_data'); - extract($phpbb_dispatcher->trigger_event('core.user_add_modify_data', compact($vars))); - - $sql = 'INSERT INTO ' . USERS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $user_id = $db->sql_nextid(); - - // Insert Custom Profile Fields - 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)); - $db->sql_query($sql); - } - - // Place into appropriate group... - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'user_id' => (int) $user_id, - 'group_id' => (int) $user_row['group_id'], - 'user_pending' => 0) - ); - $db->sql_query($sql); - - // Now make it the users default group... - group_set_user_default($user_row['group_id'], array($user_id), false); - - // Add to newly registered users group if user_new is 1 - if ($config['new_member_post_limit'] && $sql_ary['user_new']) - { - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = 'NEWLY_REGISTERED' - AND group_type = " . GROUP_SPECIAL; - $result = $db->sql_query($sql); - $add_group_id = (int) $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - - if ($add_group_id) - { - global $phpbb_log; - - // 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. - if ($config['new_member_group_default']) - { - group_user_add($add_group_id, $user_id, false, false, true); - $user_row['group_id'] = $add_group_id; - } - else - { - group_user_add($add_group_id, $user_id); - } - - $phpbb_log->enable('admin'); - } - } - - // 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) - { - $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 . ' - WHERE group_id = ' . (int) $user_row['group_id']; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('newest_user_colour', $row['group_colour'], false); - } - - // Use default notifications settings if notifications_data is not set - if ($notifications_data === null) - { - $notifications_data = array( - array( - 'item_type' => 'notification.type.post', - 'method' => 'notification.method.email', - ), - array( - 'item_type' => 'notification.type.topic', - 'method' => 'notification.method.email', - ), - ); - } - - /** - * 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) - { - $phpbb_notifications->add_subscription($subscription['item_type'], 0, $subscription['method'], $user_id); - } - } - - /** - * 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 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'); - extract($phpbb_dispatcher->trigger_event('core.user_add_after', compact($vars))); - - return $user_id; -} - -/** - * Remove User - * - * @param string $mode Either 'retain' or 'remove' - * @param mixed $user_ids Either an array of integers or an integer - * @param bool $retain_username - * @return bool - */ -function user_delete($mode, $user_ids, $retain_username = true) -{ - global $cache, $config, $db, $user, $phpbb_dispatcher, $phpbb_container; - global $phpbb_root_path, $phpEx; - - $db->sql_transaction('begin'); - - $user_rows = array(); - if (!is_array($user_ids)) - { - $user_ids = array($user_ids); - } - - $user_id_sql = $db->sql_in_set('user_id', $user_ids); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE ' . $user_id_sql; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $user_rows[(int) $row['user_id']] = $row; - } - $db->sql_freeresult($result); - - if (empty($user_rows)) - { - return false; - } - - /** - * Event before a user is deleted - * - * @event core.delete_user_before - * @var string mode Mode of deletion (retain/delete posts) - * @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', 'user_rows'); - extract($phpbb_dispatcher->trigger_event('core.delete_user_before', compact($vars))); - - // Before we begin, we will remove the reports the user issued. - $sql = 'SELECT r.post_id, p.topic_id - FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . ' p - WHERE ' . $db->sql_in_set('r.user_id', $user_ids) . ' - AND p.post_id = r.post_id'; - $result = $db->sql_query($sql); - - $report_posts = $report_topics = array(); - while ($row = $db->sql_fetchrow($result)) - { - $report_posts[] = $row['post_id']; - $report_topics[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (count($report_posts)) - { - $report_posts = array_unique($report_posts); - $report_topics = array_unique($report_topics); - - // Get a list of topics that still contain reported posts - $sql = 'SELECT DISTINCT topic_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $report_topics) . ' - AND post_reported = 1 - AND ' . $db->sql_in_set('post_id', $report_posts, true); - $result = $db->sql_query($sql); - - $keep_report_topics = array(); - while ($row = $db->sql_fetchrow($result)) - { - $keep_report_topics[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (count($keep_report_topics)) - { - $report_topics = array_diff($report_topics, $keep_report_topics); - } - unset($keep_report_topics); - - // Now set the flags back - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_reported = 0 - WHERE ' . $db->sql_in_set('post_id', $report_posts); - $db->sql_query($sql); - - if (count($report_topics)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_reported = 0 - WHERE ' . $db->sql_in_set('topic_id', $report_topics); - $db->sql_query($sql); - } - } - - // Remove reports - $db->sql_query('DELETE FROM ' . REPORTS_TABLE . ' WHERE ' . $user_id_sql); - - $num_users_delta = 0; - - // Get auth provider collection in case accounts might need to be unlinked - $provider_collection = $phpbb_container->get('auth.provider_collection'); - - // Some things need to be done in the loop (if the query changes based - // on which user is currently being deleted) - $added_guest_posts = 0; - foreach ($user_rows as $user_id => $user_row) - { - if ($user_row['user_avatar'] && $user_row['user_avatar_type'] == 'avatar.driver.upload') - { - avatar_delete('user', $user_row); - } - - // Unlink accounts - foreach ($provider_collection as $provider_name => $auth_provider) - { - $provider_data = $auth_provider->get_auth_link_data($user_id); - - if ($provider_data !== null) - { - $link_data = array( - 'user_id' => $user_id, - 'link_method' => 'user_delete', - ); - - // BLOCK_VARS might contain hidden fields necessary for unlinking accounts - if (isset($provider_data['BLOCK_VARS']) && is_array($provider_data['BLOCK_VARS'])) - { - foreach ($provider_data['BLOCK_VARS'] as $provider_service) - { - if (!array_key_exists('HIDDEN_FIELDS', $provider_service)) - { - $provider_service['HIDDEN_FIELDS'] = array(); - } - - $auth_provider->unlink_account(array_merge($link_data, $provider_service['HIDDEN_FIELDS'])); - } - } - else - { - $auth_provider->unlink_account($link_data); - } - } - } - - // Decrement number of users if this user is active - if ($user_row['user_type'] != USER_INACTIVE && $user_row['user_type'] != USER_IGNORE) - { - --$num_users_delta; - } - - switch ($mode) - { - case 'retain': - if ($retain_username === false) - { - $post_username = $user->lang['GUEST']; - } - else - { - $post_username = $user_row['username']; - } - - // If the user is inactive and newly registered - // we assume no posts from the user, and save - // the queries - if ($user_row['user_type'] != USER_INACTIVE || $user_row['user_inactive_reason'] != INACTIVE_REGISTER || $user_row['user_posts']) - { - // When we delete these users and retain the posts, we must assign all the data to the guest user - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_last_poster_id = ' . ANONYMOUS . ", forum_last_poster_name = '" . $db->sql_escape($post_username) . "', forum_last_poster_colour = '' - WHERE forum_last_poster_id = $user_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET poster_id = ' . ANONYMOUS . ", post_username = '" . $db->sql_escape($post_username) . "' - WHERE poster_id = $user_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_poster = ' . ANONYMOUS . ", topic_first_poster_name = '" . $db->sql_escape($post_username) . "', topic_first_poster_colour = '' - WHERE topic_poster = $user_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_last_poster_id = ' . ANONYMOUS . ", topic_last_poster_name = '" . $db->sql_escape($post_username) . "', topic_last_poster_colour = '' - WHERE topic_last_poster_id = $user_id"; - $db->sql_query($sql); - - // Since we change every post by this author, we need to count this amount towards the anonymous user - - if ($user_row['user_posts']) - { - $added_guest_posts += $user_row['user_posts']; - } - } - break; - - case 'remove': - // there is nothing variant specific to deleting posts - break; - } - } - - if ($num_users_delta != 0) - { - $config->increment('num_users', $num_users_delta, false); - } - - // Now do the invariant tasks - // all queries performed in one call of this function are in a single transaction - // so this is kosher - if ($mode == 'retain') - { - // Assign more data to the Anonymous user - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET poster_id = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('poster_id', $user_ids); - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts + ' . $added_guest_posts . ' - WHERE user_id = ' . ANONYMOUS; - $db->sql_query($sql); - } - else if ($mode == 'remove') - { - if (!function_exists('delete_posts')) - { - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - - // Delete posts, attachments, etc. - // delete_posts can handle any number of IDs in its second argument - delete_posts('poster_id', $user_ids); - } - - $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) - { - $sql = "DELETE FROM $table - WHERE " . $user_id_sql; - $db->sql_query($sql); - } - $db->sql_return_on_error(); - - $cache->destroy('sql', MODERATOR_CACHE_TABLE); - - // Change user_id to anonymous for posts edited by this user - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_edit_user = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('post_edit_user', $user_ids); - $db->sql_query($sql); - - // Change user_id to anonymous for pms edited by this user - $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' - SET message_edit_user = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('message_edit_user', $user_ids); - $db->sql_query($sql); - - // Change user_id to anonymous for posts deleted by this user - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_delete_user = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('post_delete_user', $user_ids); - $db->sql_query($sql); - - // Change user_id to anonymous for topics deleted by this user - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_delete_user = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('topic_delete_user', $user_ids); - $db->sql_query($sql); - - // Delete user log entries about this user - $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE ' . $db->sql_in_set('reportee_id', $user_ids); - $db->sql_query($sql); - - // Change user_id to anonymous for this users triggered events - $sql = 'UPDATE ' . LOG_TABLE . ' - SET user_id = ' . ANONYMOUS . ' - WHERE ' . $user_id_sql; - $db->sql_query($sql); - - // Delete the user_id from the zebra table - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $user_id_sql . ' - OR ' . $db->sql_in_set('zebra_id', $user_ids); - $db->sql_query($sql); - - // Delete the user_id from the banlist - $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_userid', $user_ids); - $db->sql_query($sql); - - // Delete the user_id from the session table - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('session_user_id', $user_ids); - $db->sql_query($sql); - - // Clean the private messages tables from the user - if (!function_exists('phpbb_delete_user_pms')) - { - include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - } - phpbb_delete_users_pms($user_ids); - - $phpbb_notifications = $phpbb_container->get('notification_manager'); - $phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_ids); - - $db->sql_transaction('commit'); - - /** - * Event after a user is deleted - * - * @event core.delete_user_after - * @var string mode Mode of deletion (retain/delete posts) - * @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', 'user_rows'); - extract($phpbb_dispatcher->trigger_event('core.delete_user_after', compact($vars))); - - // Reset newest user info if appropriate - if (in_array($config['newest_user_id'], $user_ids)) - { - update_last_username(); - } - - return false; -} - -/** -* Flips user_type from active to inactive and vice versa, handles group membership updates -* -* @param string $mode can be flip for flipping from active/inactive, activate or deactivate -*/ -function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL) -{ - global $config, $db, $user, $auth, $phpbb_dispatcher; - - $deactivated = $activated = 0; - $sql_statements = array(); - - if (!is_array($user_id_ary)) - { - $user_id_ary = array($user_id_ary); - } - - if (!count($user_id_ary)) - { - return; - } - - $sql = 'SELECT user_id, group_id, user_type, user_inactive_reason - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary = array(); - - if ($row['user_type'] == USER_IGNORE || $row['user_type'] == USER_FOUNDER || - ($mode == 'activate' && $row['user_type'] != USER_INACTIVE) || - ($mode == 'deactivate' && $row['user_type'] == USER_INACTIVE)) - { - continue; - } - - if ($row['user_type'] == USER_INACTIVE) - { - $activated++; - } - else - { - $deactivated++; - - // Remove the users session key... - $user->reset_login_keys($row['user_id']); - } - - $sql_ary += array( - 'user_type' => ($row['user_type'] == USER_NORMAL) ? USER_INACTIVE : USER_NORMAL, - 'user_inactive_time' => ($row['user_type'] == USER_NORMAL) ? time() : 0, - 'user_inactive_reason' => ($row['user_type'] == USER_NORMAL) ? $reason : 0, - ); - - $sql_statements[$row['user_id']] = $sql_ary; - } - $db->sql_freeresult($result); - - /** - * Check or modify activated/deactivated users data before submitting it to the database - * - * @event core.user_active_flip_before - * @var string mode User type changing mode, can be: flip|activate|deactivate - * @var int reason Reason for changing user type, can be: INACTIVE_REGISTER|INACTIVE_PROFILE|INACTIVE_MANUAL|INACTIVE_REMIND - * @var int activated The number of users to be activated - * @var int deactivated The number of users to be deactivated - * @var array user_id_ary Array with user ids to change user type - * @var array sql_statements Array with users data to submit to the database, keys: user ids, values: arrays with user data - * @since 3.1.4-RC1 - */ - $vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements'); - extract($phpbb_dispatcher->trigger_event('core.user_active_flip_before', compact($vars))); - - if (count($sql_statements)) - { - foreach ($sql_statements as $user_id => $sql_ary) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - } - - $auth->acl_clear_prefetch(array_keys($sql_statements)); - } - - /** - * Perform additional actions after the users have been activated/deactivated - * - * @event core.user_active_flip_after - * @var string mode User type changing mode, can be: flip|activate|deactivate - * @var int reason Reason for changing user type, can be: INACTIVE_REGISTER|INACTIVE_PROFILE|INACTIVE_MANUAL|INACTIVE_REMIND - * @var int activated The number of users to be activated - * @var int deactivated The number of users to be deactivated - * @var array user_id_ary Array with user ids to change user type - * @var array sql_statements Array with users data to submit to the database, keys: user ids, values: arrays with user data - * @since 3.1.4-RC1 - */ - $vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements'); - extract($phpbb_dispatcher->trigger_event('core.user_active_flip_after', compact($vars))); - - if ($deactivated) - { - $config->increment('num_users', $deactivated * (-1), false); - } - - if ($activated) - { - $config->increment('num_users', $activated, false); - } - - // Update latest username - update_last_username(); -} - -/** -* Add a ban or ban exclusion to the banlist. Bans either a user, an IP or an email address -* -* @param string $mode Type of ban. One of the following: user, ip, email -* @param mixed $ban Banned entity. Either string or array with usernames, ips or email addresses -* @param int $ban_len Ban length in minutes -* @param string $ban_len_other Ban length as a date (YYYY-MM-DD) -* @param boolean $ban_exclude Exclude these entities from banning? -* @param string $ban_reason String describing the reason for this ban -* @return boolean -*/ -function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reason, $ban_give_reason = '') -{ - global $db, $user, $cache, $phpbb_log; - - // Delete stale bans - $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ban_end < ' . time() . ' - AND ban_end <> 0'; - $db->sql_query($sql); - - $ban_list = (!is_array($ban)) ? array_unique(explode("\n", $ban)) : $ban; - $ban_list_log = implode(', ', $ban_list); - - $current_time = time(); - - // Set $ban_end to the unix time when the ban should end. 0 is a permanent ban. - if ($ban_len) - { - if ($ban_len != -1 || !$ban_len_other) - { - $ban_end = max($current_time, $current_time + ($ban_len) * 60); - } - else - { - $ban_other = explode('-', $ban_len_other); - 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() - ->setDate((int) $ban_other[0], (int) $ban_other[1], (int) $ban_other[2]) - ->setTime(0, 0, 0) - ->getTimestamp() + $user->timezone->getOffset(new DateTime('UTC'))); - } - else - { - trigger_error('LENGTH_BAN_INVALID', E_USER_WARNING); - } - } - } - else - { - $ban_end = 0; - } - - $founder = $founder_names = array(); - - if (!$ban_exclude) - { - // Create a list of founder... - $sql = 'SELECT user_id, user_email, username_clean - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_FOUNDER; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $founder[$row['user_id']] = $row['user_email']; - $founder_names[$row['user_id']] = $row['username_clean']; - } - $db->sql_freeresult($result); - } - - $banlist_ary = array(); - - switch ($mode) - { - case 'user': - $type = 'ban_userid'; - - // At the moment we do not support wildcard username banning - - // Select the relevant user_ids. - $sql_usernames = array(); - - foreach ($ban_list as $username) - { - $username = trim($username); - if ($username != '') - { - $clean_name = utf8_clean_string($username); - if ($clean_name == $user->data['username_clean']) - { - trigger_error('CANNOT_BAN_YOURSELF', E_USER_WARNING); - } - if (in_array($clean_name, $founder_names)) - { - trigger_error('CANNOT_BAN_FOUNDER', E_USER_WARNING); - } - $sql_usernames[] = $clean_name; - } - } - - // Make sure we have been given someone to ban - if (!count($sql_usernames)) - { - trigger_error('NO_USER_SPECIFIED', E_USER_WARNING); - } - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('username_clean', $sql_usernames); - - // Do not allow banning yourself, the guest account, or founders. - $non_bannable = array($user->data['user_id'], ANONYMOUS); - if (count($founder)) - { - $sql .= ' AND ' . $db->sql_in_set('user_id', array_merge(array_keys($founder), $non_bannable), true); - } - else - { - $sql .= ' AND ' . $db->sql_in_set('user_id', $non_bannable, true); - } - - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - do - { - $banlist_ary[] = (int) $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); - } - else - { - $db->sql_freeresult($result); - trigger_error('NO_USERS', E_USER_WARNING); - } - $db->sql_freeresult($result); - break; - - case 'ip': - $type = 'ban_ip'; - - foreach ($ban_list as $ban_item) - { - if (preg_match('#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})[ ]*\-[ ]*([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#', trim($ban_item), $ip_range_explode)) - { - // This is an IP range - // Don't ask about all this, just don't ask ... ! - $ip_1_counter = $ip_range_explode[1]; - $ip_1_end = $ip_range_explode[5]; - - while ($ip_1_counter <= $ip_1_end) - { - $ip_2_counter = ($ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[2] : 0; - $ip_2_end = ($ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[6]; - - if ($ip_2_counter == 0 && $ip_2_end == 254) - { - $ip_2_counter = 256; - - $banlist_ary[] = "$ip_1_counter.*"; - } - - while ($ip_2_counter <= $ip_2_end) - { - $ip_3_counter = ($ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[3] : 0; - $ip_3_end = ($ip_2_counter < $ip_2_end || $ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[7]; - - if ($ip_3_counter == 0 && $ip_3_end == 254) - { - $ip_3_counter = 256; - - $banlist_ary[] = "$ip_1_counter.$ip_2_counter.*"; - } - - while ($ip_3_counter <= $ip_3_end) - { - $ip_4_counter = ($ip_3_counter == $ip_range_explode[3] && $ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[4] : 0; - $ip_4_end = ($ip_3_counter < $ip_3_end || $ip_2_counter < $ip_2_end) ? 254 : $ip_range_explode[8]; - - if ($ip_4_counter == 0 && $ip_4_end == 254) - { - $ip_4_counter = 256; - - $banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.*"; - } - - while ($ip_4_counter <= $ip_4_end) - { - $banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.$ip_4_counter"; - $ip_4_counter++; - } - $ip_3_counter++; - } - $ip_2_counter++; - } - $ip_1_counter++; - } - } - else if (preg_match('#^([0-9]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})$#', trim($ban_item)) || preg_match('#^[a-f0-9:]+\*?$#i', trim($ban_item))) - { - // Normal IP address - $banlist_ary[] = trim($ban_item); - } - else if (preg_match('#^\*$#', trim($ban_item))) - { - // Ban all IPs - $banlist_ary[] = '*'; - } - else if (preg_match('#^([\w\-_]\.?){2,}$#is', trim($ban_item))) - { - // hostname - $ip_ary = gethostbynamel(trim($ban_item)); - - if (!empty($ip_ary)) - { - foreach ($ip_ary as $ip) - { - if ($ip) - { - if (strlen($ip) > 40) - { - continue; - } - - $banlist_ary[] = $ip; - } - } - } - } - - if (empty($banlist_ary)) - { - trigger_error('NO_IPS_DEFINED', E_USER_WARNING); - } - } - break; - - case 'email': - $type = 'ban_email'; - - foreach ($ban_list as $ban_item) - { - $ban_item = trim($ban_item); - - if (preg_match('#^.*?@*|(([a-z0-9\-]+\.)+([a-z]{2,3}))$#i', $ban_item)) - { - if (strlen($ban_item) > 100) - { - continue; - } - - if (!count($founder) || !in_array($ban_item, $founder)) - { - $banlist_ary[] = $ban_item; - } - } - } - - if (count($ban_list) == 0) - { - trigger_error('NO_EMAILS_DEFINED', E_USER_WARNING); - } - break; - - default: - trigger_error('NO_MODE', E_USER_WARNING); - break; - } - - // Fetch currently set bans of the specified type and exclude state. Prevent duplicate bans. - $sql_where = ($type == 'ban_userid') ? 'ban_userid <> 0' : "$type <> ''"; - - $sql = "SELECT $type - FROM " . BANLIST_TABLE . " - WHERE $sql_where - AND ban_exclude = " . (int) $ban_exclude; - $result = $db->sql_query($sql); - - // Reset $sql_where, because we use it later... - $sql_where = ''; - - if ($row = $db->sql_fetchrow($result)) - { - $banlist_ary_tmp = array(); - do - { - switch ($mode) - { - case 'user': - $banlist_ary_tmp[] = $row['ban_userid']; - break; - - case 'ip': - $banlist_ary_tmp[] = $row['ban_ip']; - break; - - case 'email': - $banlist_ary_tmp[] = $row['ban_email']; - break; - } - } - while ($row = $db->sql_fetchrow($result)); - - $banlist_ary_tmp = array_intersect($banlist_ary, $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 . ' - WHERE ' . $db->sql_in_set($type, $banlist_ary_tmp) . ' - AND ban_exclude = ' . (int) $ban_exclude; - $db->sql_query($sql); - } - - unset($banlist_ary_tmp); - } - $db->sql_freeresult($result); - - // We have some entities to ban - if (count($banlist_ary)) - { - $sql_ary = array(); - - foreach ($banlist_ary as $ban_entry) - { - $sql_ary[] = array( - $type => $ban_entry, - 'ban_start' => (int) $current_time, - 'ban_end' => (int) $ban_end, - 'ban_exclude' => (int) $ban_exclude, - 'ban_reason' => (string) $ban_reason, - 'ban_give_reason' => (string) $ban_give_reason, - ); - } - - $db->sql_multi_insert(BANLIST_TABLE, $sql_ary); - - // If we are banning we want to logout anyone matching the ban - if (!$ban_exclude) - { - switch ($mode) - { - case 'user': - $sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $banlist_ary); - break; - - case 'ip': - $sql_where = 'WHERE ' . $db->sql_in_set('session_ip', $banlist_ary); - break; - - case 'email': - $banlist_ary_sql = array(); - - foreach ($banlist_ary as $ban_entry) - { - $banlist_ary_sql[] = (string) str_replace('*', '%', $ban_entry); - } - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_email', $banlist_ary_sql); - $result = $db->sql_query($sql); - - $sql_in = array(); - - if ($row = $db->sql_fetchrow($result)) - { - do - { - $sql_in[] = $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); - - $sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $sql_in); - } - $db->sql_freeresult($result); - break; - } - - if (isset($sql_where) && $sql_where) - { - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - $sql_where"; - $db->sql_query($sql); - - if ($mode == 'user') - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' ' . ((in_array('*', $banlist_ary)) ? '' : 'WHERE ' . $db->sql_in_set('user_id', $banlist_ary)); - $db->sql_query($sql); - } - } - } - - // Update log - $log_entry = ($ban_exclude) ? 'LOG_BAN_EXCLUDE_' : 'LOG_BAN_'; - - // Add to admin log, moderator log and user notes - $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) - { - $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 - )); - } - } - - $cache->destroy('sql', BANLIST_TABLE); - - return true; - } - - // There was nothing to ban/exclude. But destroying the cache because of the removal of stale bans. - $cache->destroy('sql', BANLIST_TABLE); - - return false; -} - -/** -* Unban User -*/ -function user_unban($mode, $ban) -{ - global $db, $user, $cache, $phpbb_log, $phpbb_dispatcher; - - // Delete stale bans - $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ban_end < ' . time() . ' - AND ban_end <> 0'; - $db->sql_query($sql); - - if (!is_array($ban)) - { - $ban = array($ban); - } - - $unban_sql = array_map('intval', $ban); - - if (count($unban_sql)) - { - // Grab details of bans for logging information later - switch ($mode) - { - case 'user': - $sql = 'SELECT u.username AS unban_info, u.user_id - FROM ' . USERS_TABLE . ' u, ' . BANLIST_TABLE . ' b - WHERE ' . $db->sql_in_set('b.ban_id', $unban_sql) . ' - AND u.user_id = b.ban_userid'; - break; - - case 'email': - $sql = 'SELECT ban_email AS unban_info - FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_id', $unban_sql); - break; - - case 'ip': - $sql = 'SELECT ban_ip AS unban_info - FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_id', $unban_sql); - break; - } - $result = $db->sql_query($sql); - - $l_unban_list = ''; - $user_ids_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $l_unban_list .= (($l_unban_list != '') ? ', ' : '') . $row['unban_info']; - if ($mode == 'user') - { - $user_ids_ary[] = $row['user_id']; - } - } - $db->sql_freeresult($result); - - $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_id', $unban_sql); - $db->sql_query($sql); - - // Add to moderator log, admin log and user notes - $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) - { - $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_UNBAN_' . strtoupper($mode), false, array( - 'reportee_id' => $user_id, - $l_unban_list - )); - } - } - - /** - * Use this event to perform actions after the unban has been performed - * - * @event core.user_unban - * @var string mode One of the following: user, ip, email - * @var array user_ids_ary Array with user_ids - * @since 3.1.11-RC1 - */ - $vars = array( - 'mode', - 'user_ids_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.user_unban', compact($vars))); - } - - $cache->destroy('sql', BANLIST_TABLE); - - return false; -} - -/** -* Internet Protocol Address Whois -* RFC3912: WHOIS Protocol Specification -* -* @param string $ip Ip address, either IPv4 or IPv6. -* -* @return string Empty string if not a valid ip address. -* Otherwise make_clickable()'ed whois result. -*/ -function user_ipwhois($ip) -{ - if (!filter_var($ip, FILTER_VALIDATE_IP)) - { - return ''; - } - - // IPv4 & IPv6 addresses - $whois_host = 'whois.arin.net.'; - - $ipwhois = ''; - - if (($fsk = @fsockopen($whois_host, 43))) - { - // CRLF as per RFC3912 - fputs($fsk, "$ip\r\n"); - while (!feof($fsk)) - { - $ipwhois .= fgets($fsk, 1024); - } - @fclose($fsk); - } - - $match = array(); - - // Test for referrals from $whois_host to other whois databases, roll on rwhois - if (preg_match('#ReferralServer:[\x20]*whois://(.+)#im', $ipwhois, $match)) - { - if (strpos($match[1], ':') !== false) - { - $pos = strrpos($match[1], ':'); - $server = substr($match[1], 0, $pos); - $port = (int) substr($match[1], $pos + 1); - unset($pos); - } - else - { - $server = $match[1]; - $port = 43; - } - - $buffer = ''; - - if (($fsk = @fsockopen($server, $port))) - { - fputs($fsk, "$ip\r\n"); - while (!feof($fsk)) - { - $buffer .= fgets($fsk, 1024); - } - @fclose($fsk); - } - - // Use the result from $whois_host if we don't get any result here - $ipwhois = (empty($buffer)) ? $ipwhois : $buffer; - } - - $ipwhois = htmlspecialchars($ipwhois); - - // Magic URL ;) - return trim(make_clickable($ipwhois, false, '')); -} - -/** -* Data validation ... used primarily but not exclusively by ucp modules -* -* "Master" function for validating a range of data types -*/ -function validate_data($data, $val_ary) -{ - global $user; - - $error = array(); - - foreach ($val_ary as $var => $val_seq) - { - if (!is_array($val_seq[0])) - { - $val_seq = array($val_seq); - } - - foreach ($val_seq as $validate) - { - $function = array_shift($validate); - array_unshift($validate, $data[$var]); - - if (is_array($function)) - { - $result = call_user_func_array(array($function[0], 'validate_' . $function[1]), $validate); - } - else - { - $function_prefix = (function_exists('phpbb_validate_' . $function)) ? 'phpbb_validate_' : 'validate_'; - $result = call_user_func_array($function_prefix . $function, $validate); - } - - if ($result) - { - // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted. - $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var); - } - } - } - - return $error; -} - -/** -* Validate String -* -* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function validate_string($string, $optional = false, $min = 0, $max = 0) -{ - if (empty($string) && $optional) - { - return false; - } - - if ($min && utf8_strlen(htmlspecialchars_decode($string)) < $min) - { - return 'TOO_SHORT'; - } - else if ($max && utf8_strlen(htmlspecialchars_decode($string)) > $max) - { - return 'TOO_LONG'; - } - - return false; -} - -/** -* Validate Number -* -* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function validate_num($num, $optional = false, $min = 0, $max = 1E99) -{ - if (empty($num) && $optional) - { - return false; - } - - if ($num < $min) - { - return 'TOO_SMALL'; - } - else if ($num > $max) - { - return 'TOO_LARGE'; - } - - return false; -} - -/** -* Validate Date -* @param String $string a date in the dd-mm-yyyy format -* @return boolean -*/ -function validate_date($date_string, $optional = false) -{ - $date = explode('-', $date_string); - if ((empty($date) || count($date) != 3) && $optional) - { - return false; - } - else if ($optional) - { - for ($field = 0; $field <= 1; $field++) - { - $date[$field] = (int) $date[$field]; - if (empty($date[$field])) - { - $date[$field] = 1; - } - } - $date[2] = (int) $date[2]; - // assume an arbitrary leap year - if (empty($date[2])) - { - $date[2] = 1980; - } - } - - if (count($date) != 3 || !checkdate($date[1], $date[0], $date[2])) - { - return 'INVALID'; - } - - return false; -} - - -/** -* Validate Match -* -* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function validate_match($string, $optional = false, $match = '') -{ - if (empty($string) && $optional) - { - return false; - } - - if (empty($match)) - { - return false; - } - - if (!preg_match($match, $string)) - { - return 'WRONG_DATA'; - } - - return false; -} - -/** -* Validate Language Pack ISO Name -* -* Tests whether a language name is valid and installed -* -* @param string $lang_iso The language string to test -* -* @return bool|string Either false if validation succeeded or -* a string which will be used as the error message -* (with the variable name appended) -*/ -function validate_language_iso_name($lang_iso) -{ - global $db; - - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($lang_iso) . "'"; - $result = $db->sql_query($sql); - $lang_id = (int) $db->sql_fetchfield('lang_id'); - $db->sql_freeresult($result); - - return ($lang_id) ? false : 'WRONG_DATA'; -} - -/** -* Validate Timezone Name -* -* Tests whether a timezone name is valid -* -* @param string $timezone The timezone string to test -* -* @return bool|string Either false if validation succeeded or -* a string which will be used as the error message -* (with the variable name appended) -*/ -function phpbb_validate_timezone($timezone) -{ - return (in_array($timezone, phpbb_get_timezone_identifiers($timezone))) ? false : 'TIMEZONE_INVALID'; -} - -/*** - * 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; - - $clean_username = utf8_clean_string($username); - $allowed_username = ($allowed_username === false) ? $user->data['username_clean'] : utf8_clean_string($allowed_username); - - if ($allowed_username == $clean_username) - { - return false; - } - - // 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_EMOJIS'; - } - - // ... fast checks first. - if (strpos($username, '"') !== false || strpos($username, '"') !== false || empty($clean_username)) - { - return 'INVALID_CHARS'; - } - - switch ($config['allow_name_chars']) - { - case 'USERNAME_CHARS_ANY': - $regex = '.+'; - break; - - case 'USERNAME_ALPHA_ONLY': - $regex = '[A-Za-z0-9]+'; - break; - - case 'USERNAME_ALPHA_SPACERS': - $regex = '[A-Za-z0-9-[\]_+ ]+'; - break; - - case 'USERNAME_LETTER_NUM': - $regex = '[\p{Lu}\p{Ll}\p{N}]+'; - break; - - case 'USERNAME_LETTER_NUM_SPACERS': - $regex = '[-\]_+ [\p{Lu}\p{Ll}\p{N}]+'; - break; - - case 'USERNAME_ASCII': - default: - $regex = '[\x01-\x7F]+'; - break; - } - - if (!preg_match('#^' . $regex . '$#u', $username)) - { - return 'INVALID_CHARS'; - } - - $sql = 'SELECT username - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape($clean_username) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return 'USERNAME_TAKEN'; - } - - $sql = 'SELECT group_name - FROM ' . GROUPS_TABLE . " - WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($username)) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return 'USERNAME_TAKEN'; - } - - if (!$allow_all_names) - { - $bad_usernames = $cache->obtain_disallowed_usernames(); - - foreach ($bad_usernames as $bad_username) - { - if (preg_match('#^' . $bad_username . '$#', $clean_username)) - { - return 'USERNAME_DISALLOWED'; - } - } - } - - return false; -} - -/** -* Check to see if the password meets the complexity settings -* -* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function validate_password($password) -{ - global $config; - - if ($password === '' || $config['pass_complex'] === 'PASS_TYPE_ANY') - { - // Password empty or no password complexity required. - return false; - } - - $upp = '\p{Lu}'; - $low = '\p{Ll}'; - $num = '\p{N}'; - $sym = '[^\p{Lu}\p{Ll}\p{N}]'; - $chars = array(); - - switch ($config['pass_complex']) - { - // No break statements below ... - // We require strong passwords in case pass_complex is not set or is invalid - default: - - // Require mixed case letters, numbers and symbols - case 'PASS_TYPE_SYMBOL': - $chars[] = $sym; - - // Require mixed case letters and numbers - case 'PASS_TYPE_ALPHA': - $chars[] = $num; - - // Require mixed case letters - case 'PASS_TYPE_CASE': - $chars[] = $low; - $chars[] = $upp; - } - - foreach ($chars as $char) - { - if (!preg_match('#' . $char . '#u', $password)) - { - return 'INVALID_CHARS'; - } - } - - return false; -} - -/** -* Check to see if email address is a valid address and contains a MX record -* -* @param string $email The email to check -* -* @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function phpbb_validate_email($email, $config = null) -{ - if ($config === null) - { - global $config; - } - - $email = strtolower($email); - - if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email)) - { - return 'EMAIL_INVALID'; - } - - // Check MX record. - // The idea for this is from reading the UseBB blog/announcement. :) - if ($config['email_check_mx']) - { - list(, $domain) = explode('@', $email); - - if (checkdnsrr($domain, 'A') === false && checkdnsrr($domain, 'MX') === false) - { - return 'DOMAIN_NO_MX_RECORD'; - } - } - - return false; -} - -/** -* Check to see if email address is banned or already present in the DB -* -* @param string $email The email to check -* @param string $allowed_email An allowed email, default being $user->data['user_email'] -* -* @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_user_email($email, $allowed_email = false) -{ - global $config, $db, $user; - - $email = strtolower($email); - $allowed_email = ($allowed_email === false) ? strtolower($user->data['user_email']) : strtolower($allowed_email); - - if ($allowed_email == $email) - { - return false; - } - - $validate_email = phpbb_validate_email($email, $config); - if ($validate_email) - { - return $validate_email; - } - - $ban = $user->check_ban(false, false, $email, true); - if (!empty($ban)) - { - return !empty($ban['ban_give_reason']) ? $ban['ban_give_reason'] : 'EMAIL_BANNED'; - } - - if (!$config['allow_emailreuse']) - { - $sql = 'SELECT user_email - FROM ' . USERS_TABLE . " - WHERE user_email = '" . $db->sql_escape($email) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return 'EMAIL_TAKEN'; - } - } - - return false; -} - -/** -* Validate jabber address -* Taken from the jabber class within flyspray (see author notes) -* -* @author flyspray.org -*/ -function validate_jabber($jid) -{ - if (!$jid) - { - return false; - } - - $separator_pos = strpos($jid, '@'); - - if ($separator_pos === false) - { - return 'WRONG_DATA'; - } - - $username = substr($jid, 0, $separator_pos); - $realm = substr($jid, $separator_pos + 1); - - if (strlen($username) == 0 || strlen($realm) < 3) - { - return 'WRONG_DATA'; - } - - $arr = explode('.', $realm); - - if (count($arr) == 0) - { - return 'WRONG_DATA'; - } - - foreach ($arr as $part) - { - if (substr($part, 0, 1) == '-' || substr($part, -1, 1) == '-') - { - return 'WRONG_DATA'; - } - - if (!preg_match("@^[a-zA-Z0-9-.]+$@", $part)) - { - return 'WRONG_DATA'; - } - } - - $boundary = array(array(0, 127), array(192, 223), array(224, 239), array(240, 247), array(248, 251), array(252, 253)); - - // Prohibited Characters RFC3454 + RFC3920 - $prohibited = array( - // Table C.1.1 - array(0x0020, 0x0020), // SPACE - // Table C.1.2 - array(0x00A0, 0x00A0), // NO-BREAK SPACE - array(0x1680, 0x1680), // OGHAM SPACE MARK - array(0x2000, 0x2001), // EN QUAD - array(0x2001, 0x2001), // EM QUAD - array(0x2002, 0x2002), // EN SPACE - array(0x2003, 0x2003), // EM SPACE - array(0x2004, 0x2004), // THREE-PER-EM SPACE - array(0x2005, 0x2005), // FOUR-PER-EM SPACE - array(0x2006, 0x2006), // SIX-PER-EM SPACE - array(0x2007, 0x2007), // FIGURE SPACE - array(0x2008, 0x2008), // PUNCTUATION SPACE - array(0x2009, 0x2009), // THIN SPACE - array(0x200A, 0x200A), // HAIR SPACE - array(0x200B, 0x200B), // ZERO WIDTH SPACE - array(0x202F, 0x202F), // NARROW NO-BREAK SPACE - array(0x205F, 0x205F), // MEDIUM MATHEMATICAL SPACE - array(0x3000, 0x3000), // IDEOGRAPHIC SPACE - // Table C.2.1 - array(0x0000, 0x001F), // [CONTROL CHARACTERS] - array(0x007F, 0x007F), // DELETE - // Table C.2.2 - array(0x0080, 0x009F), // [CONTROL CHARACTERS] - array(0x06DD, 0x06DD), // ARABIC END OF AYAH - array(0x070F, 0x070F), // SYRIAC ABBREVIATION MARK - array(0x180E, 0x180E), // MONGOLIAN VOWEL SEPARATOR - array(0x200C, 0x200C), // ZERO WIDTH NON-JOINER - array(0x200D, 0x200D), // ZERO WIDTH JOINER - array(0x2028, 0x2028), // LINE SEPARATOR - array(0x2029, 0x2029), // PARAGRAPH SEPARATOR - array(0x2060, 0x2060), // WORD JOINER - array(0x2061, 0x2061), // FUNCTION APPLICATION - array(0x2062, 0x2062), // INVISIBLE TIMES - array(0x2063, 0x2063), // INVISIBLE SEPARATOR - array(0x206A, 0x206F), // [CONTROL CHARACTERS] - array(0xFEFF, 0xFEFF), // ZERO WIDTH NO-BREAK SPACE - array(0xFFF9, 0xFFFC), // [CONTROL CHARACTERS] - array(0x1D173, 0x1D17A), // [MUSICAL CONTROL CHARACTERS] - // Table C.3 - array(0xE000, 0xF8FF), // [PRIVATE USE, PLANE 0] - array(0xF0000, 0xFFFFD), // [PRIVATE USE, PLANE 15] - array(0x100000, 0x10FFFD), // [PRIVATE USE, PLANE 16] - // Table C.4 - array(0xFDD0, 0xFDEF), // [NONCHARACTER CODE POINTS] - array(0xFFFE, 0xFFFF), // [NONCHARACTER CODE POINTS] - array(0x1FFFE, 0x1FFFF), // [NONCHARACTER CODE POINTS] - array(0x2FFFE, 0x2FFFF), // [NONCHARACTER CODE POINTS] - array(0x3FFFE, 0x3FFFF), // [NONCHARACTER CODE POINTS] - array(0x4FFFE, 0x4FFFF), // [NONCHARACTER CODE POINTS] - array(0x5FFFE, 0x5FFFF), // [NONCHARACTER CODE POINTS] - array(0x6FFFE, 0x6FFFF), // [NONCHARACTER CODE POINTS] - array(0x7FFFE, 0x7FFFF), // [NONCHARACTER CODE POINTS] - array(0x8FFFE, 0x8FFFF), // [NONCHARACTER CODE POINTS] - array(0x9FFFE, 0x9FFFF), // [NONCHARACTER CODE POINTS] - array(0xAFFFE, 0xAFFFF), // [NONCHARACTER CODE POINTS] - array(0xBFFFE, 0xBFFFF), // [NONCHARACTER CODE POINTS] - array(0xCFFFE, 0xCFFFF), // [NONCHARACTER CODE POINTS] - array(0xDFFFE, 0xDFFFF), // [NONCHARACTER CODE POINTS] - array(0xEFFFE, 0xEFFFF), // [NONCHARACTER CODE POINTS] - array(0xFFFFE, 0xFFFFF), // [NONCHARACTER CODE POINTS] - array(0x10FFFE, 0x10FFFF), // [NONCHARACTER CODE POINTS] - // Table C.5 - array(0xD800, 0xDFFF), // [SURROGATE CODES] - // Table C.6 - array(0xFFF9, 0xFFF9), // INTERLINEAR ANNOTATION ANCHOR - array(0xFFFA, 0xFFFA), // INTERLINEAR ANNOTATION SEPARATOR - array(0xFFFB, 0xFFFB), // INTERLINEAR ANNOTATION TERMINATOR - array(0xFFFC, 0xFFFC), // OBJECT REPLACEMENT CHARACTER - array(0xFFFD, 0xFFFD), // REPLACEMENT CHARACTER - // Table C.7 - array(0x2FF0, 0x2FFB), // [IDEOGRAPHIC DESCRIPTION CHARACTERS] - // Table C.8 - array(0x0340, 0x0340), // COMBINING GRAVE TONE MARK - array(0x0341, 0x0341), // COMBINING ACUTE TONE MARK - array(0x200E, 0x200E), // LEFT-TO-RIGHT MARK - array(0x200F, 0x200F), // RIGHT-TO-LEFT MARK - array(0x202A, 0x202A), // LEFT-TO-RIGHT EMBEDDING - array(0x202B, 0x202B), // RIGHT-TO-LEFT EMBEDDING - array(0x202C, 0x202C), // POP DIRECTIONAL FORMATTING - array(0x202D, 0x202D), // LEFT-TO-RIGHT OVERRIDE - array(0x202E, 0x202E), // RIGHT-TO-LEFT OVERRIDE - array(0x206A, 0x206A), // INHIBIT SYMMETRIC SWAPPING - array(0x206B, 0x206B), // ACTIVATE SYMMETRIC SWAPPING - array(0x206C, 0x206C), // INHIBIT ARABIC FORM SHAPING - array(0x206D, 0x206D), // ACTIVATE ARABIC FORM SHAPING - array(0x206E, 0x206E), // NATIONAL DIGIT SHAPES - array(0x206F, 0x206F), // NOMINAL DIGIT SHAPES - // Table C.9 - array(0xE0001, 0xE0001), // LANGUAGE TAG - array(0xE0020, 0xE007F), // [TAGGING CHARACTERS] - // RFC3920 - array(0x22, 0x22), // " - array(0x26, 0x26), // & - array(0x27, 0x27), // ' - array(0x2F, 0x2F), // / - array(0x3A, 0x3A), // : - array(0x3C, 0x3C), // < - array(0x3E, 0x3E), // > - array(0x40, 0x40) // @ - ); - - $pos = 0; - $result = true; - - while ($pos < strlen($username)) - { - $len = $uni = 0; - for ($i = 0; $i <= 5; $i++) - { - if (ord($username[$pos]) >= $boundary[$i][0] && ord($username[$pos]) <= $boundary[$i][1]) - { - $len = $i + 1; - $uni = (ord($username[$pos]) - $boundary[$i][0]) * pow(2, $i * 6); - - for ($k = 1; $k < $len; $k++) - { - $uni += (ord($username[$pos + $k]) - 128) * pow(2, ($i - $k) * 6); - } - - break; - } - } - - if ($len == 0) - { - return 'WRONG_DATA'; - } - - foreach ($prohibited as $pval) - { - if ($uni >= $pval[0] && $uni <= $pval[1]) - { - $result = false; - break 2; - } - } - - $pos = $pos + $len; - } - - if (!$result) - { - return 'WRONG_DATA'; - } - - return false; -} - -/** -* Validate hex colour value -* -* @param string $colour The hex colour value -* @param bool $optional Whether the colour value is optional. True if an empty -* string will be accepted as correct input, false if not. -* @return bool|string Error message if colour value is incorrect, false if it -* fits the hex colour code -*/ -function phpbb_validate_hex_colour($colour, $optional = false) -{ - if ($colour === '') - { - return (($optional) ? false : 'WRONG_DATA'); - } - - if (!preg_match('/^([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/', $colour)) - { - return 'WRONG_DATA'; - } - - return false; -} - -/** -* Verifies whether a style ID corresponds to an active style. -* -* @param int $style_id The style_id of a style which should be checked if activated or not. -* @return boolean -*/ -function phpbb_style_is_active($style_id) -{ - global $db; - - $sql = 'SELECT style_active - FROM ' . STYLES_TABLE . ' - WHERE style_id = '. (int) $style_id; - $result = $db->sql_query($sql); - - $style_is_active = (bool) $db->sql_fetchfield('style_active'); - $db->sql_freeresult($result); - - return $style_is_active; -} - -/** -* Remove avatar -*/ -function avatar_delete($mode, $row, $clean_db = false) -{ - global $phpbb_root_path, $config; - - // Check if the users avatar is actually *not* a group avatar - if ($mode == 'user') - { - if (strpos($row['user_avatar'], 'g') === 0 || (((int) $row['user_avatar'] !== 0) && ((int) $row['user_avatar'] !== (int) $row['user_id']))) - { - return false; - } - } - - if ($clean_db) - { - avatar_remove_db($row[$mode . '_avatar']); - } - $filename = get_avatar_filename($row[$mode . '_avatar']); - - if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . $filename)) - { - @unlink($phpbb_root_path . $config['avatar_path'] . '/' . $filename); - return true; - } - - return false; -} - -/** -* Generates avatar filename from the database entry -*/ -function get_avatar_filename($avatar_entry) -{ - global $config; - - if ($avatar_entry[0] === 'g') - { - $avatar_group = true; - $avatar_entry = substr($avatar_entry, 1); - } - else - { - $avatar_group = false; - } - $ext = substr(strrchr($avatar_entry, '.'), 1); - $avatar_entry = intval($avatar_entry); - return $config['avatar_salt'] . '_' . (($avatar_group) ? 'g' : '') . $avatar_entry . '.' . $ext; -} - -/** -* Returns an explanation string with maximum avatar settings -* -* @return string -*/ -function phpbb_avatar_explanation_string() -{ - global $config, $user; - - return $user->lang(($config['avatar_filesize'] == 0) ? 'AVATAR_EXPLAIN_NO_FILESIZE' : 'AVATAR_EXPLAIN', - $user->lang('PIXELS', (int) $config['avatar_max_width']), - $user->lang('PIXELS', (int) $config['avatar_max_height']), - round($config['avatar_filesize'] / 1024)); -} - -// -// Usergroup functions -// - -/** -* Add or edit a group. If we're editing a group we only update user -* parameters such as rank, etc. if they are changed -*/ -function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false) -{ - global $db, $user, $phpbb_container, $phpbb_log; - - /** @var \phpbb\group\helper $group_helper */ - $group_helper = $phpbb_container->get('group_helper'); - - $error = array(); - - // Attributes which also affect the users table - $user_attribute_ary = array('group_colour', 'group_rank', 'group_avatar', 'group_avatar_type', 'group_avatar_width', 'group_avatar_height'); - - // Check data. Limit group name length. - if (!utf8_strlen($name) || utf8_strlen($name) > 60) - { - $error[] = (!utf8_strlen($name)) ? $user->lang['GROUP_ERR_USERNAME'] : $user->lang['GROUP_ERR_USER_LONG']; - } - - $err = group_validate_groupname($group_id, $name); - if (!empty($err)) - { - $error[] = $user->lang[$err]; - } - - if (!in_array($type, array(GROUP_OPEN, GROUP_CLOSED, GROUP_HIDDEN, GROUP_SPECIAL, GROUP_FREE))) - { - $error[] = $user->lang['GROUP_ERR_TYPE']; - } - - $group_teampage = !empty($group_attributes['group_teampage']); - unset($group_attributes['group_teampage']); - - 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 - { - $current_legend = $legend->get_group_value($group_id); - $current_teampage = $teampage->get_group_value($group_id); - } - catch (\phpbb\groupposition\exception $exception) - { - trigger_error($user->lang($exception->getMessage())); - } - } - - if (!empty($group_attributes['group_legend'])) - { - if (($group_id && ($current_legend == \phpbb\groupposition\legend::GROUP_DISABLED)) || !$group_id) - { - // Old group currently not in the legend or new group, add at the end. - $group_attributes['group_legend'] = 1 + $legend->get_group_count(); - } - else - { - // Group stayes in the legend - $group_attributes['group_legend'] = $current_legend; - } - } - else if ($group_id && ($current_legend != \phpbb\groupposition\legend::GROUP_DISABLED)) - { - // Group is removed from the legend - try - { - $legend->delete_group($group_id, true); - } - catch (\phpbb\groupposition\exception $exception) - { - trigger_error($user->lang($exception->getMessage())); - } - $group_attributes['group_legend'] = \phpbb\groupposition\legend::GROUP_DISABLED; - } - else - { - $group_attributes['group_legend'] = \phpbb\groupposition\legend::GROUP_DISABLED; - } - - // Unset the objects, we don't need them anymore. - unset($legend); - - $user_ary = array(); - $sql_ary = array( - 'group_name' => (string) $name, - 'group_desc' => (string) $desc, - 'group_desc_uid' => '', - 'group_desc_bitfield' => '', - 'group_type' => (int) $type, - ); - - // Parse description - if ($desc) - { - 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 (count($group_attributes)) - { - // Merge them with $sql_ary to properly update the group - $sql_ary = array_merge($sql_ary, $group_attributes); - } - - // Setting the log message before we set the group id (if group gets added) - $log = ($group_id) ? 'LOG_GROUP_UPDATED' : 'LOG_GROUP_CREATED'; - - if ($group_id) - { - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE group_id = ' . $group_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $user_ary[] = $row['user_id']; - } - $db->sql_freeresult($result); - - if (isset($sql_ary['group_avatar'])) - { - remove_default_avatar($group_id, $user_ary); - } - - if (isset($sql_ary['group_rank'])) - { - remove_default_rank($group_id, $user_ary); - } - - $sql = 'UPDATE ' . GROUPS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE group_id = $group_id"; - $db->sql_query($sql); - - // Since we may update the name too, we need to do this on other tables too... - $sql = 'UPDATE ' . MODERATOR_CACHE_TABLE . " - SET group_name = '" . $db->sql_escape($sql_ary['group_name']) . "' - WHERE group_id = $group_id"; - $db->sql_query($sql); - - // One special case is the group skip auth setting. If this was changed we need to purge permissions for this group - if (isset($group_attributes['group_skip_auth'])) - { - // Get users within this group... - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . ' - WHERE group_id = ' . $group_id . ' - AND user_pending = 0'; - $result = $db->sql_query($sql); - - $user_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_id_ary[] = $row['user_id']; - } - $db->sql_freeresult($result); - - if (!empty($user_id_ary)) - { - global $auth; - - // Clear permissions cache of relevant users - $auth->acl_clear_prefetch($user_id_ary); - } - } - } - else - { - $sql = 'INSERT INTO ' . GROUPS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - } - - // Remove the group from the teampage, only if unselected and we are editing a group, - // which is currently displayed. - if (!$group_teampage && $group_id && $current_teampage != \phpbb\groupposition\teampage::GROUP_DISABLED) - { - try - { - $teampage->delete_group($group_id); - } - catch (\phpbb\groupposition\exception $exception) - { - trigger_error($user->lang($exception->getMessage())); - } - } - - if (!$group_id) - { - $group_id = $db->sql_nextid(); - - if (isset($sql_ary['group_avatar_type']) && $sql_ary['group_avatar_type'] == 'avatar.driver.upload') - { - group_correct_avatar($group_id, $sql_ary['group_avatar']); - } - } - - try - { - if ($group_teampage && $current_teampage == \phpbb\groupposition\teampage::GROUP_DISABLED) - { - $teampage->add_group($group_id); - } - - if ($group_teampage) - { - if ($current_teampage == \phpbb\groupposition\teampage::GROUP_DISABLED) - { - $teampage->add_group($group_id); - } - } - else if ($group_id && ($current_teampage != \phpbb\groupposition\teampage::GROUP_DISABLED)) - { - $teampage->delete_group($group_id); - } - } - catch (\phpbb\groupposition\exception $exception) - { - trigger_error($user->lang($exception->getMessage())); - } - unset($teampage); - - // Set user attributes - $sql_ary = array(); - if (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) - { - if (!isset($group_attributes[$attribute])) - { - continue; - } - - // If we are about to set an avatar, we will not overwrite user avatars if no group avatar is set... - if (strpos($attribute, 'group_avatar') === 0 && !$group_attributes[$attribute]) - { - continue; - } - - $sql_ary[$attribute] = $group_attributes[$attribute]; - } - } - - if (count($sql_ary) && count($user_ary)) - { - group_set_user_default($group_id, $user_ary, $sql_ary); - } - - $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 (count($error)) ? $error : false; -} - - -/** -* Changes a group avatar's filename to conform to the naming scheme -*/ -function group_correct_avatar($group_id, $old_entry) -{ - global $config, $db, $phpbb_root_path; - - $group_id = (int) $group_id; - $ext = substr(strrchr($old_entry, '.'), 1); - $old_filename = get_avatar_filename($old_entry); - $new_filename = $config['avatar_salt'] . "_g$group_id.$ext"; - $new_entry = 'g' . $group_id . '_' . substr(time(), -5) . ".$ext"; - - $avatar_path = $phpbb_root_path . $config['avatar_path']; - if (@rename($avatar_path . '/'. $old_filename, $avatar_path . '/' . $new_filename)) - { - $sql = 'UPDATE ' . GROUPS_TABLE . ' - SET group_avatar = \'' . $db->sql_escape($new_entry) . "' - WHERE group_id = $group_id"; - $db->sql_query($sql); - } -} - - -/** -* Remove avatar also for users not having the group as default -*/ -function avatar_remove_db($avatar_name) -{ - global $db; - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_avatar = '', - user_avatar_type = '' - WHERE user_avatar = '" . $db->sql_escape($avatar_name) . '\''; - $db->sql_query($sql); -} - - -/** -* Group Delete -*/ -function group_delete($group_id, $group_name = false) -{ - global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container, $phpbb_log; - - if (!$group_name) - { - $group_name = get_group_name($group_id); - } - - $start = 0; - - do - { - $user_id_ary = $username_ary = array(); - - // Batch query for group members, call group_user_del - $sql = 'SELECT u.user_id, u.username - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . " u - WHERE ug.group_id = $group_id - AND u.user_id = ug.user_id"; - $result = $db->sql_query_limit($sql, 200, $start); - - if ($row = $db->sql_fetchrow($result)) - { - do - { - $user_id_ary[] = $row['user_id']; - $username_ary[] = $row['username']; - - $start++; - } - while ($row = $db->sql_fetchrow($result)); - - group_user_del($group_id, $user_id_ary, $username_ary, $group_name); - } - else - { - $start = 0; - } - $db->sql_freeresult($result); - } - while ($start); - - // 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); - } - catch (\phpbb\groupposition\exception $exception) - { - // The group we want to delete does not exist. - // No reason to worry, we just continue the deleting process. - //trigger_error($user->lang($exception->getMessage())); - } - - try - { - /* @var $teampage \phpbb\groupposition\teampage */ - $teampage = $phpbb_container->get('groupposition.teampage'); - $teampage->delete_group($group_id); - unset($teampage); - } - catch (\phpbb\groupposition\exception $exception) - { - // The group we want to delete does not exist. - // No reason to worry, we just continue the deleting process. - //trigger_error($user->lang($exception->getMessage())); - } - - // Delete group - $sql = 'DELETE FROM ' . GROUPS_TABLE . " - WHERE group_id = $group_id"; - $db->sql_query($sql); - - // Delete auth entries from the groups table - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $db->sql_query($sql); - - /** - * Event after a group is deleted - * - * @event core.delete_group_after - * @var int group_id ID of the deleted group - * @var string group_name Name of the deleted group - * @since 3.1.0-a1 - */ - $vars = array('group_id', 'group_name'); - extract($phpbb_dispatcher->trigger_event('core.delete_group_after', compact($vars))); - - // Re-cache moderators - if (!function_exists('phpbb_cache_moderators')) - { - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - - phpbb_cache_moderators($db, $cache, $auth); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_GROUP_DELETE', false, array($group_name)); - - // Return false - no error - return false; -} - -/** -* Add user(s) to group -* -* @return mixed false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER' -*/ -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, $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 (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 . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary) . " - AND group_id = $group_id"; - $result = $db->sql_query($sql); - - $add_id_ary = $update_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $add_id_ary[] = (int) $row['user_id']; - - if ($leader && !$row['group_leader']) - { - $update_id_ary[] = (int) $row['user_id']; - } - } - $db->sql_freeresult($result); - - // Do all the users exist in this group? - $add_id_ary = array_diff($user_id_ary, $add_id_ary); - - // If we have no users - if (!count($add_id_ary) && !count($update_id_ary)) - { - return 'GROUP_USERS_EXIST'; - } - - $db->sql_transaction('begin'); - - // Insert the new users - if (count($add_id_ary)) - { - $sql_ary = array(); - - foreach ($add_id_ary as $user_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user_id, - 'group_id' => (int) $group_id, - 'group_leader' => (int) $leader, - 'user_pending' => (int) $pending, - ); - } - - $db->sql_multi_insert(USER_GROUP_TABLE, $sql_ary); - } - - if (count($update_id_ary)) - { - $sql = 'UPDATE ' . USER_GROUP_TABLE . ' - SET group_leader = 1 - WHERE ' . $db->sql_in_set('user_id', $update_id_ary) . " - AND group_id = $group_id"; - $db->sql_query($sql); - } - - if ($default) - { - group_user_attributes('default', $group_id, $user_id_ary, false, $group_name, $group_attributes); - } - - $db->sql_transaction('commit'); - - // Clear permissions cache of relevant users - $auth->acl_clear_prefetch($user_id_ary); - - /** - * Event after users are added to a group - * - * @event core.group_add_user_after - * @var int group_id ID of the group to which users are added - * @var string group_name Name of the group - * @var array user_id_ary IDs of the users which are added - * @var array username_ary names of the users which are added - * @var int pending Pending setting, 1 if user(s) added are pending - * @since 3.1.7-RC1 - */ - $vars = array( - 'group_id', - 'group_name', - 'user_id_ary', - 'username_ary', - 'pending', - ); - extract($phpbb_dispatcher->trigger_event('core.group_add_user_after', compact($vars))); - - if (!$group_name) - { - $group_name = get_group_name($group_id); - } - - $log = ($leader) ? 'LOG_MODS_ADDED' : (($pending) ? 'LOG_USERS_PENDING' : 'LOG_USERS_ADDED'); - - $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) - { - $phpbb_notifications->add_notifications('notification.type.group_request', array( - 'group_id' => $group_id, - 'user_id' => $user_id, - 'group_name' => $group_name, - )); - } - } - - // Return false - no error - return false; -} - -/** -* Remove a user/s from a given group. When we remove users we update their -* default group_id. We do this by examining which "special" groups they belong -* to. The selection is made based on a reasonable priority system -* -* @return false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER' -*/ -function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $log_action = true) -{ - global $db, $auth, $config, $user, $phpbb_dispatcher, $phpbb_container, $phpbb_log; - - if ($config['coppa_enable']) - { - $group_order = array('ADMINISTRATORS', 'GLOBAL_MODERATORS', 'NEWLY_REGISTERED', 'REGISTERED_COPPA', 'REGISTERED', 'BOTS', 'GUESTS'); - } - else - { - $group_order = array('ADMINISTRATORS', 'GLOBAL_MODERATORS', 'NEWLY_REGISTERED', 'REGISTERED', 'BOTS', 'GUESTS'); - } - - // We need both username and user_id info - $result = user_get_id_name($user_id_ary, $username_ary); - - if (empty($user_id_ary) || $result !== false) - { - return 'NO_USER'; - } - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_name', $group_order); - $result = $db->sql_query($sql); - - $group_order_id = $special_group_data = array(); - while ($row = $db->sql_fetchrow($result)) - { - $group_order_id[$row['group_name']] = $row['group_id']; - - $special_group_data[$row['group_id']] = array( - 'group_colour' => $row['group_colour'], - 'group_rank' => $row['group_rank'], - ); - - // Only set the group avatar if one is defined... - if ($row['group_avatar']) - { - $special_group_data[$row['group_id']] = array_merge($special_group_data[$row['group_id']], array( - 'group_avatar' => $row['group_avatar'], - 'group_avatar_type' => $row['group_avatar_type'], - 'group_avatar_width' => $row['group_avatar_width'], - 'group_avatar_height' => $row['group_avatar_height']) - ); - } - } - $db->sql_freeresult($result); - - // Get users default groups - we only need to reset default group membership if the group from which the user gets removed is set as default - $sql = 'SELECT user_id, group_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary); - $result = $db->sql_query($sql); - - $default_groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $default_groups[$row['user_id']] = $row['group_id']; - } - $db->sql_freeresult($result); - - // What special group memberships exist for these users? - $sql = 'SELECT g.group_id, g.group_name, ug.user_id - FROM ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g - WHERE ' . $db->sql_in_set('ug.user_id', $user_id_ary) . " - AND g.group_id = ug.group_id - AND g.group_id <> $group_id - AND g.group_type = " . GROUP_SPECIAL . ' - ORDER BY ug.user_id, g.group_id'; - $result = $db->sql_query($sql); - - $temp_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($default_groups[$row['user_id']] == $group_id && (!isset($temp_ary[$row['user_id']]) || $group_order_id[$row['group_name']] < $temp_ary[$row['user_id']])) - { - $temp_ary[$row['user_id']] = $row['group_id']; - } - } - $db->sql_freeresult($result); - - // sql_where_ary holds the new default groups and their users - $sql_where_ary = array(); - foreach ($temp_ary as $uid => $gid) - { - $sql_where_ary[$gid][] = $uid; - } - unset($temp_ary); - - foreach ($special_group_data as $gid => $default_data_ary) - { - 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]); - group_set_user_default($gid, $sql_where_ary[$gid], $default_data_ary); - } - } - unset($special_group_data); - - /** - * Event before users are removed from a group - * - * @event core.group_delete_user_before - * @var int group_id ID of the group from which users are deleted - * @var string group_name Name of the group - * @var array user_id_ary IDs of the users which are removed - * @var array username_ary names of the users which are removed - * @since 3.1.0-a1 - */ - $vars = array('group_id', 'group_name', 'user_id_ary', 'username_ary'); - extract($phpbb_dispatcher->trigger_event('core.group_delete_user_before', compact($vars))); - - $sql = 'DELETE FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - AND " . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - - // Clear permissions cache of relevant users - $auth->acl_clear_prefetch($user_id_ary); - - /** - * Event after users are removed from a group - * - * @event core.group_delete_user_after - * @var int group_id ID of the group from which users are deleted - * @var string group_name Name of the group - * @var array user_id_ary IDs of the users which are removed - * @var array username_ary names of the users which are removed - * @since 3.1.7-RC1 - */ - $vars = array('group_id', 'group_name', 'user_id_ary', 'username_ary'); - extract($phpbb_dispatcher->trigger_event('core.group_delete_user_after', compact($vars))); - - if ($log_action) - { - if (!$group_name) - { - $group_name = get_group_name($group_id); - } - - $log = 'LOG_GROUP_REMOVE'; - - if ($group_name) - { - $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); - - // Return false - no error - return false; -} - - -/** -* Removes the group avatar of the default group from the users in user_ids who have that group as default. -*/ -function remove_default_avatar($group_id, $user_ids) -{ - global $db; - - if (!is_array($user_ids)) - { - $user_ids = array($user_ids); - } - if (empty($user_ids)) - { - return false; - } - - $user_ids = array_map('intval', $user_ids); - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - if (!$row = $db->sql_fetchrow($result)) - { - $db->sql_freeresult($result); - return false; - } - $db->sql_freeresult($result); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_avatar = '', - user_avatar_type = '', - user_avatar_width = 0, - user_avatar_height = 0 - WHERE group_id = " . (int) $group_id . " - AND user_avatar = '" . $db->sql_escape($row['group_avatar']) . "' - AND " . $db->sql_in_set('user_id', $user_ids); - - $db->sql_query($sql); -} - -/** -* Removes the group rank of the default group from the users in user_ids who have that group as default. -*/ -function remove_default_rank($group_id, $user_ids) -{ - global $db; - - if (!is_array($user_ids)) - { - $user_ids = array($user_ids); - } - if (empty($user_ids)) - { - return false; - } - - $user_ids = array_map('intval', $user_ids); - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - if (!$row = $db->sql_fetchrow($result)) - { - $db->sql_freeresult($result); - return false; - } - $db->sql_freeresult($result); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_rank = 0 - WHERE group_id = ' . (int) $group_id . ' - AND user_rank <> 0 - AND user_rank = ' . (int) $row['group_rank'] . ' - AND ' . $db->sql_in_set('user_id', $user_ids); - $db->sql_query($sql); -} - -/** -* This is used to promote (to leader), demote or set as default a member/s -*/ -function group_user_attributes($action, $group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $group_attributes = false) -{ - 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 (empty($user_id_ary) || $result !== false) - { - return 'NO_USERS'; - } - - if (!$group_name) - { - $group_name = get_group_name($group_id); - } - - switch ($action) - { - case 'demote': - case 'promote': - - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - AND user_pending = 1 - AND " . $db->sql_in_set('user_id', $user_id_ary); - $result = $db->sql_query_limit($sql, 1); - $not_empty = ($db->sql_fetchrow($result)); - $db->sql_freeresult($result); - if ($not_empty) - { - return 'NO_VALID_USERS'; - } - - $sql = 'UPDATE ' . USER_GROUP_TABLE . ' - SET group_leader = ' . (($action == 'promote') ? 1 : 0) . " - WHERE group_id = $group_id - AND user_pending = 0 - AND " . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - - $log = ($action == 'promote') ? 'LOG_GROUP_PROMOTED' : 'LOG_GROUP_DEMOTED'; - break; - - case 'approve': - // Make sure we only approve those which are pending ;) - $sql = 'SELECT u.user_id, u.user_email, u.username, u.username_clean, u.user_notify_type, u.user_jabber, u.user_lang - FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug - WHERE ug.group_id = ' . $group_id . ' - AND ug.user_pending = 1 - AND ug.user_id = u.user_id - AND ' . $db->sql_in_set('ug.user_id', $user_id_ary); - $result = $db->sql_query($sql); - - $user_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_id_ary[] = $row['user_id']; - } - $db->sql_freeresult($result); - - if (!count($user_id_ary)) - { - return false; - } - - $sql = 'UPDATE ' . USER_GROUP_TABLE . " - SET user_pending = 0 - WHERE group_id = $group_id - 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( - 'user_ids' => $user_id_ary, - 'group_id' => $group_id, - 'group_name' => $group_name, - )); - $phpbb_notifications->delete_notifications('notification.type.group_request', $user_id_ary, $group_id); - - $log = 'LOG_USERS_APPROVED'; - break; - - case 'default': - // We only set default group for approved members of the group - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - AND user_pending = 0 - AND " . $db->sql_in_set('user_id', $user_id_ary); - $result = $db->sql_query($sql); - - $user_id_ary = $username_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_id_ary[] = $row['user_id']; - } - $db->sql_freeresult($result); - - $result = user_get_id_name($user_id_ary, $username_ary); - if (!count($user_id_ary) || $result !== false) - { - return 'NO_USERS'; - } - - $sql = 'SELECT user_id, group_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary, false, true); - $result = $db->sql_query($sql); - - $groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($groups[$row['group_id']])) - { - $groups[$row['group_id']] = array(); - } - $groups[$row['group_id']][] = $row['user_id']; - } - $db->sql_freeresult($result); - - foreach ($groups as $gid => $uids) - { - remove_default_rank($gid, $uids); - remove_default_avatar($gid, $uids); - } - group_set_user_default($group_id, $user_id_ary, $group_attributes); - $log = 'LOG_GROUP_DEFAULTS'; - break; - } - - /** - * Event to perform additional actions on setting user group attributes - * - * @event core.user_set_group_attributes - * @var int group_id ID of the group - * @var string group_name Name of the group - * @var array user_id_ary IDs of the users to set group attributes - * @var array username_ary Names of the users to set group attributes - * @var array group_attributes Group attributes which were changed - * @var string action Action to perform over the group members - * @since 3.1.10-RC1 - */ - $vars = array( - 'group_id', - 'group_name', - 'user_id_ary', - 'username_ary', - 'group_attributes', - 'action', - ); - extract($phpbb_dispatcher->trigger_event('core.user_set_group_attributes', compact($vars))); - - // Clear permissions cache of relevant users - $auth->acl_clear_prefetch($user_id_ary); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log, false, array($group_name, implode(', ', $username_ary))); - - group_update_listings($group_id); - - return false; -} - -/** -* A small version of validate_username to check for a group name's existence. To be called directly. -*/ -function group_validate_groupname($group_id, $group_name) -{ - global $db; - - $group_name = utf8_clean_string($group_name); - - if (!empty($group_id)) - { - $sql = 'SELECT group_name - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - return false; - } - - $allowed_groupname = utf8_clean_string($row['group_name']); - - if ($allowed_groupname == $group_name) - { - return false; - } - } - - $sql = 'SELECT group_name - FROM ' . GROUPS_TABLE . " - WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($group_name)) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return 'GROUP_NAME_TAKEN'; - } - - return false; -} - -/** -* Set users default group -* -* @access private -*/ -function group_set_user_default($group_id, $user_id_ary, $group_attributes = false, $update_listing = false) -{ - global $config, $phpbb_container, $db, $phpbb_dispatcher; - - if (empty($user_id_ary)) - { - return; - } - - $attribute_ary = array( - 'group_colour' => 'string', - 'group_rank' => 'int', - 'group_avatar' => 'string', - 'group_avatar_type' => 'string', - 'group_avatar_width' => 'int', - 'group_avatar_height' => 'int', - ); - - $sql_ary = array( - 'group_id' => $group_id - ); - - // Were group attributes passed to the function? If not we need to obtain them - if ($group_attributes === false) - { - $sql = 'SELECT ' . implode(', ', array_keys($attribute_ary)) . ' - FROM ' . GROUPS_TABLE . " - WHERE group_id = $group_id"; - $result = $db->sql_query($sql); - $group_attributes = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - foreach ($attribute_ary as $attribute => $type) - { - if (isset($group_attributes[$attribute])) - { - // If we are about to set an avatar or rank, we will not overwrite with empty, unless we are not actually changing the default group - if ((strpos($attribute, 'group_avatar') === 0 || strpos($attribute, 'group_rank') === 0) && !$group_attributes[$attribute]) - { - continue; - } - - settype($group_attributes[$attribute], $type); - $sql_ary[str_replace('group_', 'user_', $attribute)] = $group_attributes[$attribute]; - } - } - - $updated_sql_ary = $sql_ary; - - // Before we update the user attributes, we will update the rank for users that don't have a custom rank - if (isset($sql_ary['user_rank'])) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', array('user_rank' => $sql_ary['user_rank'])) . ' - WHERE user_rank = 0 - AND ' . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - unset($sql_ary['user_rank']); - } - - // Before we update the user attributes, we will update the avatar for users that don't have a custom avatar - $avatar_options = array('user_avatar', 'user_avatar_type', 'user_avatar_height', 'user_avatar_width'); - - if (isset($sql_ary['user_avatar'])) - { - $avatar_sql_ary = array(); - foreach ($avatar_options as $avatar_option) - { - if (isset($sql_ary[$avatar_option])) - { - $avatar_sql_ary[$avatar_option] = $sql_ary[$avatar_option]; - } - } - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $avatar_sql_ary) . " - WHERE user_avatar = '' - AND " . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - } - - // Remove the avatar options, as we already updated them - foreach ($avatar_options as $avatar_option) - { - unset($sql_ary[$avatar_option]); - } - - if (!empty($sql_ary)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - } - - if (isset($sql_ary['user_colour'])) - { - // Update any cached colour information for these users - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' - WHERE " . $db->sql_in_set('forum_last_poster_id', $user_id_ary); - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' - WHERE " . $db->sql_in_set('topic_poster', $user_id_ary); - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' - WHERE " . $db->sql_in_set('topic_last_poster_id', $user_id_ary); - $db->sql_query($sql); - - if (in_array($config['newest_user_id'], $user_id_ary)) - { - $config->set('newest_user_colour', $sql_ary['user_colour'], false); - } - } - - // Make all values available for the event - $sql_ary = $updated_sql_ary; - - /** - * Event when the default group is set for an array of users - * - * @event core.user_set_default_group - * @var int group_id ID of the group - * @var array user_id_ary IDs of the users - * @var array group_attributes Group attributes which were changed - * @var array update_listing Update the list of moderators and foes - * @var array sql_ary User attributes which were changed - * @since 3.1.0-a1 - */ - $vars = array('group_id', 'user_id_ary', 'group_attributes', 'update_listing', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.user_set_default_group', compact($vars))); - - if ($update_listing) - { - group_update_listings($group_id); - } - - // Because some tables/caches use usercolour-specific data we need to purge this here. - $phpbb_container->get('cache.driver')->destroy('sql', MODERATOR_CACHE_TABLE); -} - -/** -* Get group name -*/ -function get_group_name($group_id) -{ - global $db, $phpbb_container; - - $sql = 'SELECT group_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - return ''; - } - - /** @var \phpbb\group\helper $group_helper */ - $group_helper = $phpbb_container->get('group_helper'); - - return $group_helper->get_name($row['group_name']); -} - -/** -* Obtain either the members of a specified group, the groups the specified user is subscribed to -* or checking if a specified user is in a specified group. This function does not return pending memberships. -* -* Note: Never use this more than once... first group your users/groups -*/ -function group_memberships($group_id_ary = false, $user_id_ary = false, $return_bool = false) -{ - global $db; - - if (!$group_id_ary && !$user_id_ary) - { - return true; - } - - if ($user_id_ary) - { - $user_id_ary = (!is_array($user_id_ary)) ? array($user_id_ary) : $user_id_ary; - } - - if ($group_id_ary) - { - $group_id_ary = (!is_array($group_id_ary)) ? array($group_id_ary) : $group_id_ary; - } - - $sql = 'SELECT ug.*, u.username, u.username_clean, u.user_email - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u - WHERE ug.user_id = u.user_id - AND ug.user_pending = 0 AND '; - - if ($group_id_ary) - { - $sql .= ' ' . $db->sql_in_set('ug.group_id', $group_id_ary); - } - - if ($user_id_ary) - { - $sql .= ($group_id_ary) ? ' AND ' : ' '; - $sql .= $db->sql_in_set('ug.user_id', $user_id_ary); - } - - $result = ($return_bool) ? $db->sql_query_limit($sql, 1) : $db->sql_query($sql); - - $row = $db->sql_fetchrow($result); - - if ($return_bool) - { - $db->sql_freeresult($result); - return ($row) ? true : false; - } - - if (!$row) - { - return false; - } - - $return = array(); - - do - { - $return[] = $row; - } - while ($row = $db->sql_fetchrow($result)); - - $db->sql_freeresult($result); - - return $return; -} - -/** -* Re-cache moderators and foes if group has a_ or m_ permissions -*/ -function group_update_listings($group_id) -{ - global $db, $cache, $auth; - - $hold_ary = $auth->acl_group_raw_data($group_id, array('a_', 'm_')); - - if (empty($hold_ary)) - { - return; - } - - $mod_permissions = $admin_permissions = false; - - foreach ($hold_ary as $g_id => $forum_ary) - { - foreach ($forum_ary as $forum_id => $auth_ary) - { - foreach ($auth_ary as $auth_option => $setting) - { - if ($mod_permissions && $admin_permissions) - { - break 3; - } - - if ($setting != ACL_YES) - { - continue; - } - - if ($auth_option == 'm_') - { - $mod_permissions = true; - } - - if ($auth_option == 'a_') - { - $admin_permissions = true; - } - } - } - } - - if ($mod_permissions) - { - if (!function_exists('phpbb_cache_moderators')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - phpbb_cache_moderators($db, $cache, $auth); - } - - if ($mod_permissions || $admin_permissions) - { - if (!function_exists('phpbb_update_foes')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - phpbb_update_foes($db, $auth, array($group_id)); - } -} - - - -/** -* Funtion to make a user leave the NEWLY_REGISTERED system group. -* @access public -* @param $user_id The id of the user to remove from the group -*/ -function remove_newly_registered($user_id, $user_data = false) -{ - global $db; - - if ($user_data === false) - { - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - return false; - } - else - { - $user_data = $user_row; - } - } - - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = 'NEWLY_REGISTERED' - AND group_type = " . GROUP_SPECIAL; - $result = $db->sql_query($sql); - $group_id = (int) $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - - if (!$group_id) - { - return false; - } - - // We need to call group_user_del here, because this function makes sure everything is correctly changed. - // Force function to not log the removal of users from newly registered users group - group_user_del($group_id, $user_id, false, false, false); - - // Set user_new to 0 to let this not be triggered again - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new = 0 - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - - // The new users group was the users default group? - if ($user_data['group_id'] == $group_id) - { - // Which group is now the users default one? - $sql = 'SELECT group_id - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - $user_data['group_id'] = $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - } - - return $user_data['group_id']; -} - -/** -* Gets user ids of currently banned registered users. -* -* @param array $user_ids Array of users' ids to check for banning, -* leave empty to get complete list of banned ids -* @param bool|int $ban_end Bool True to get users currently banned -* Bool False to only get permanently banned users -* Int Unix timestamp to get users banned until that time -* @return array Array of banned users' ids if any, empty array otherwise -*/ -function phpbb_get_banned_user_ids($user_ids = array(), $ban_end = true) -{ - global $db; - - $sql_user_ids = (!empty($user_ids)) ? $db->sql_in_set('ban_userid', $user_ids) : 'ban_userid <> 0'; - - // Get banned User ID's - // Ignore stale bans which were not wiped yet - $banned_ids_list = array(); - $sql = 'SELECT ban_userid - FROM ' . BANLIST_TABLE . " - WHERE $sql_user_ids - AND ban_exclude <> 1"; - - if ($ban_end === true) - { - // Banned currently - $sql .= " AND (ban_end > " . time() . ' - OR ban_end = 0)'; - } - else if ($ban_end === false) - { - // Permanently banned - $sql .= " AND ban_end = 0"; - } - else - { - // Banned until a specified time - $sql .= " AND (ban_end > " . (int) $ban_end . ' - OR ban_end = 0)'; - } - - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $user_id = (int) $row['ban_userid']; - $banned_ids_list[$user_id] = $user_id; - } - $db->sql_freeresult($result); - - return $banned_ids_list; -} - -/** -* Function for assigning a template var if the zebra module got included -*/ -function phpbb_module_zebra($mode, &$module_row) -{ - global $template; - - $template->assign_var('S_ZEBRA_ENABLED', true); - - if ($mode == 'friends') - { - $template->assign_var('S_ZEBRA_FRIENDS_ENABLED', true); - } - - if ($mode == 'foes') - { - $template->assign_var('S_ZEBRA_FOES_ENABLED', true); - } -} diff --git a/install/update/new/includes/mcp/mcp_ban.php b/install/update/new/includes/mcp/mcp_ban.php deleted file mode 100644 index 6f748f5..0000000 --- a/install/update/new/includes/mcp/mcp_ban.php +++ /dev/null @@ -1,301 +0,0 @@ - -* @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 mcp_ban -{ - var $u_action; - - function main($id, $mode) - { - global $db, $user, $auth, $template, $request, $phpbb_dispatcher; - global $phpbb_root_path, $phpEx; - - if (!function_exists('user_ban')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - // Include the admin banning interface... - 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'); - - $user->add_lang(array('acp/ban', 'acp/users')); - $this->tpl_name = 'mcp_ban'; - - /** - * Use this event to pass perform actions when a ban is issued or revoked - * - * @event core.mcp_ban_main - * @var bool bansubmit True if a ban is issued - * @var bool unbansubmit True if a ban is removed - * @var string mode Mode of the ban that is being worked on - * @since 3.1.0-RC5 - */ - $vars = array( - 'bansubmit', - 'unbansubmit', - 'mode', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_ban_main', compact($vars))); - - // Ban submitted? - if ($bansubmit) - { - // Grab the list of entries - $ban = $request->variable('ban', '', $mode === 'user'); - $ban_length = $request->variable('banlength', 0); - $ban_length_other = $request->variable('banlengthother', ''); - $ban_exclude = $request->variable('banexclude', 0); - $ban_reason = $request->variable('banreason', '', true); - $ban_give_reason = $request->variable('bangivereason', '', true); - - if ($ban) - { - if (confirm_box(true)) - { - $abort_ban = false; - /** - * Use this event to modify the ban details before the ban is performed - * - * @event core.mcp_ban_before - * @var string mode One of the following: user, ip, email - * @var string ban Either string or array with usernames, ips or email addresses - * @var int ban_length Ban length in minutes - * @var string ban_length_other Ban length as a date (YYYY-MM-DD) - * @var bool ban_exclude Are we banning or excluding from another ban - * @var string ban_reason Ban reason displayed to moderators - * @var string ban_give_reason Ban reason displayed to the banned user - * @var mixed abort_ban Either false, or an error message that is displayed to the user. - * If a string is given the bans are not issued. - * @since 3.1.0-RC5 - */ - $vars = array( - 'mode', - 'ban', - 'ban_length', - 'ban_length_other', - 'ban_exclude', - 'ban_reason', - 'ban_give_reason', - 'abort_ban', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_ban_before', compact($vars))); - - if ($abort_ban) - { - trigger_error($abort_ban); - } - user_ban($mode, $ban, $ban_length, $ban_length_other, $ban_exclude, $ban_reason, $ban_give_reason); - - /** - * Use this event to perform actions after the ban has been performed - * - * @event core.mcp_ban_after - * @var string mode One of the following: user, ip, email - * @var string ban Either string or array with usernames, ips or email addresses - * @var int ban_length Ban length in minutes - * @var string ban_length_other Ban length as a date (YYYY-MM-DD) - * @var bool ban_exclude Are we banning or excluding from another ban - * @var string ban_reason Ban reason displayed to moderators - * @var string ban_give_reason Ban reason displayed to the banned user - * @since 3.1.0-RC5 - */ - $vars = array( - 'mode', - 'ban', - 'ban_length', - 'ban_length_other', - 'ban_exclude', - 'ban_reason', - 'ban_give_reason', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_ban_after', compact($vars))); - - trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . '

« ' . $user->lang['BACK_TO_PREV'] . ''); - } - else - { - $hidden_fields = array( - 'mode' => $mode, - 'ban' => $ban, - 'bansubmit' => true, - 'banlength' => $ban_length, - 'banlengthother' => $ban_length_other, - 'banexclude' => $ban_exclude, - 'banreason' => $ban_reason, - 'bangivereason' => $ban_give_reason, - ); - - /** - * Use this event to pass data from the ban form to the confirmation screen - * - * @event core.mcp_ban_confirm - * @var array hidden_fields Hidden fields that are passed through the confirm screen - * @since 3.1.0-RC5 - */ - $vars = array('hidden_fields'); - extract($phpbb_dispatcher->trigger_event('core.mcp_ban_confirm', compact($vars))); - - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($hidden_fields)); - } - } - } - else if ($unbansubmit) - { - $ban = $request->variable('unban', array('')); - - if ($ban) - { - if (confirm_box(true)) - { - user_unban($mode, $ban); - - trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . '

« ' . $user->lang['BACK_TO_PREV'] . ''); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'mode' => $mode, - 'unbansubmit' => true, - 'unban' => $ban))); - } - } - } - - // Ban length options - $ban_end_text = array(0 => $user->lang['PERMANENT'], 30 => $user->lang['30_MINS'], 60 => $user->lang['1_HOUR'], 360 => $user->lang['6_HOURS'], 1440 => $user->lang['1_DAY'], 10080 => $user->lang['7_DAYS'], 20160 => $user->lang['2_WEEKS'], 40320 => $user->lang['1_MONTH'], -1 => $user->lang['UNTIL'] . ' -> '); - - $ban_end_options = ''; - foreach ($ban_end_text as $length => $text) - { - $ban_end_options .= ''; - } - - // Define language vars - $this->page_title = $user->lang[strtoupper($mode) . '_BAN']; - - $l_ban_explain = $user->lang[strtoupper($mode) . '_BAN_EXPLAIN']; - $l_ban_exclude_explain = $user->lang[strtoupper($mode) . '_BAN_EXCLUDE_EXPLAIN']; - $l_unban_title = $user->lang[strtoupper($mode) . '_UNBAN']; - $l_unban_explain = $user->lang[strtoupper($mode) . '_UNBAN_EXPLAIN']; - $l_no_ban_cell = $user->lang[strtoupper($mode) . '_NO_BANNED']; - - switch ($mode) - { - case 'user': - $l_ban_cell = $user->lang['USERNAME']; - break; - - case 'ip': - $l_ban_cell = $user->lang['IP_HOSTNAME']; - break; - - case 'email': - $l_ban_cell = $user->lang['EMAIL_ADDRESS']; - break; - } - - acp_ban::display_ban_options($mode); - - $template->assign_vars(array( - 'L_TITLE' => $this->page_title, - 'L_EXPLAIN' => $l_ban_explain, - 'L_UNBAN_TITLE' => $l_unban_title, - 'L_UNBAN_EXPLAIN' => $l_unban_explain, - 'L_BAN_CELL' => $l_ban_cell, - 'L_BAN_EXCLUDE_EXPLAIN' => $l_ban_exclude_explain, - 'L_NO_BAN_CELL' => $l_no_ban_cell, - - 'S_USERNAME_BAN' => ($mode == 'user') ? true : false, - - 'U_ACTION' => $this->u_action, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=mcp_ban&field=ban'), - )); - - if ($mode === 'email' && !$auth->acl_get('a_user')) - { - return; - } - - // As a "service" we will check if any post id is specified and populate the username of the poster id if given - $post_id = $request->variable('p', 0); - $user_id = $request->variable('u', 0); - $pre_fill = false; - - if ($user_id && $user_id <> ANONYMOUS) - { - $sql = 'SELECT username, user_email, user_ip - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - switch ($mode) - { - case 'user': - $pre_fill = (string) $db->sql_fetchfield('username'); - break; - - case 'ip': - $pre_fill = (string) $db->sql_fetchfield('user_ip'); - break; - - case 'email': - $pre_fill = (string) $db->sql_fetchfield('user_email'); - break; - } - $db->sql_freeresult($result); - } - else if ($post_id) - { - $post_info = phpbb_get_post_data(array($post_id), 'm_ban'); - - if (count($post_info) && !empty($post_info[$post_id])) - { - switch ($mode) - { - case 'user': - $pre_fill = $post_info[$post_id]['username']; - break; - - case 'ip': - $pre_fill = $post_info[$post_id]['poster_ip']; - break; - - case 'email': - $pre_fill = $post_info[$post_id]['user_email']; - break; - } - - } - } - - if ($pre_fill) - { - // left for legacy template compatibility - $template->assign_var('USERNAMES', $pre_fill); - $template->assign_var('BAN_QUANTIFIER', $pre_fill); - } - } -} diff --git a/install/update/new/includes/mcp/mcp_logs.php b/install/update/new/includes/mcp/mcp_logs.php deleted file mode 100644 index dc098fc..0000000 --- a/install/update/new/includes/mcp/mcp_logs.php +++ /dev/null @@ -1,230 +0,0 @@ - -* @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; -} - -/** -* mcp_logs -* Handling warning the users -*/ -class mcp_logs -{ - var $u_action; - var $p_master; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $auth, $db, $user, $template, $request; - global $config, $phpbb_container, $phpbb_log; - - $user->add_lang('acp/common'); - - $action = $request->variable('action', array('' => '')); - - if (is_array($action)) - { - $action = key($action); - } - else - { - $action = $request->variable('action', ''); - } - - // Set up general vars - $start = $request->variable('start', 0); - $deletemark = ($action == 'del_marked') ? true : false; - $deleteall = ($action == 'del_all') ? true : false; - $marked = $request->variable('mark', array(0)); - - // Sort keys - $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_'))); - $forum_list[] = 0; - - $forum_id = $topic_id = 0; - - switch ($mode) - { - case 'front': - break; - - case 'forum_logs': - $forum_id = $request->variable('f', 0); - - if (!in_array($forum_id, $forum_list)) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } - - $forum_list = array($forum_id); - break; - - case 'topic_logs': - $topic_id = $request->variable('t', 0); - - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $forum_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - if (!in_array($forum_id, $forum_list)) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } - - $forum_list = array($forum_id); - break; - } - - // Delete entries if requested and able - if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs')) - { - if (confirm_box(true)) - { - if ($deletemark && count($marked)) - { - $conditions = array( - 'forum_id' => array('IN' => $forum_list), - 'log_id' => array('IN' => $marked), - ); - - $phpbb_log->delete('mod', $conditions); - } - else if ($deleteall) - { - $keywords = $request->variable('keywords', '', true); - - $conditions = array( - 'forum_id' => array('IN' => $forum_list), - 'keywords' => $keywords, - ); - - if ($sort_days) - { - $conditions['log_time'] = array('>=', time() - ($sort_days * 86400)); - } - - if ($mode == 'topic_logs') - { - $conditions['topic_id'] = $topic_id; - } - - $phpbb_log->delete('mod', $conditions); - } - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'f' => $forum_id, - 't' => $topic_id, - 'start' => $start, - 'delmarked' => $deletemark, - 'delall' => $deleteall, - 'mark' => $marked, - 'st' => $sort_days, - 'sk' => $sort_key, - 'sd' => $sort_dir, - 'i' => $id, - 'mode' => $mode, - 'action' => $request->variable('action', array('' => '')))) - ); - } - } - - // Sorting - $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_text = array('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'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - - // Define where and sort sql for use in displaying logs - $sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0; - $sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); - - $keywords = $request->variable('keywords', '', true); - $keywords_param = !empty($keywords) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; - - // Grab log data - $log_data = array(); - $log_count = 0; - $start = view_log('mod', $log_data, $log_count, $config['topics_per_page'], $start, $forum_list, $topic_id, 0, $sql_where, $sql_sort, $keywords); - - $base_url = $this->u_action . "&$u_sort_param$keywords_param"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'TOTAL' => $user->lang('TOTAL_LOGS', (int) $log_count), - - 'L_TITLE' => $user->lang['MCP_LOGS'], - - 'U_POST_ACTION' => $this->u_action . "&$u_sort_param$keywords_param&start=$start", - 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_LOGS' => ($log_count > 0), - 'S_KEYWORDS' => $keywords, - ) - ); - - foreach ($log_data as $row) - { - $data = array(); - - $checks = array('viewpost', 'viewtopic', 'viewforum'); - foreach ($checks as $check) - { - if (isset($row[$check]) && $row[$check]) - { - $data[] = '' . $user->lang['LOGVIEW_' . strtoupper($check)] . ''; - } - } - - $template->assign_block_vars('log', array( - 'USERNAME' => $row['username_full'], - 'IP' => $row['ip'], - 'DATE' => $user->format_date($row['time']), - 'ACTION' => $row['action'], - 'DATA' => (count($data)) ? implode(' | ', $data) : '', - 'ID' => $row['id'], - ) - ); - } - } -} diff --git a/install/update/new/includes/mcp/mcp_main.php b/install/update/new/includes/mcp/mcp_main.php deleted file mode 100644 index 744eaeb..0000000 --- a/install/update/new/includes/mcp/mcp_main.php +++ /dev/null @@ -1,1717 +0,0 @@ - -* @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; -} - -/** -* mcp_main -* Handling mcp actions -*/ -class mcp_main -{ - var $p_master; - var $u_action; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - 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->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - lock_unlock($action, $topic_ids); - break; - - case 'lock_post': - case 'unlock_post': - - $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0)); - - if (!count($post_ids)) - { - trigger_error('NO_POST_SELECTED'); - } - - lock_unlock($action, $post_ids); - break; - - case 'make_announce': - case 'make_sticky': - case 'make_global': - case 'make_normal': - - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - change_topic_type($action, $topic_ids); - break; - - case 'move': - $user->add_lang('viewtopic'); - - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - mcp_move_topic($topic_ids); - break; - - case 'fork': - $user->add_lang('viewtopic'); - - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - mcp_fork_topic($topic_ids); - break; - - case 'delete_topic': - $user->add_lang('viewtopic'); - - // f parameter is not reliable for permission usage, however we just use it to decide - // which permission we will check later on. So if it is manipulated, we will still catch it later on. - $forum_id = $request->variable('f', 0); - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false; - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - mcp_delete_topic($topic_ids, $soft_delete, $request->variable('delete_reason', '', true)); - break; - - case 'delete_post': - $user->add_lang('posting'); - - // f parameter is not reliable for permission usage, however we just use it to decide - // which permission we will check later on. So if it is manipulated, we will still catch it later on. - $forum_id = $request->variable('f', 0); - $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0)); - $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false; - - if (!count($post_ids)) - { - trigger_error('NO_POST_SELECTED'); - } - - mcp_delete_post($post_ids, $soft_delete, $request->variable('delete_reason', '', true)); - break; - - case 'restore_topic': - $user->add_lang('posting'); - - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - mcp_restore_topic($topic_ids); - break; - - default: - /** - * This event allows you to handle custom quickmod options - * - * @event core.modify_quickmod_actions - * @var string action Topic quick moderation action name - * @var bool quickmod Flag indicating whether MCP is in quick moderation mode - * @since 3.1.0-a4 - * @changed 3.1.0-RC4 Added variables: action, quickmod - */ - $vars = array('action', 'quickmod'); - extract($phpbb_dispatcher->trigger_event('core.modify_quickmod_actions', compact($vars))); - break; - } - - switch ($mode) - { - case 'front': - if (!function_exists('mcp_front_view')) - { - include($phpbb_root_path . 'includes/mcp/mcp_front.' . $phpEx); - } - - $user->add_lang('acp/common'); - - mcp_front_view($id, $mode, $action); - - $this->tpl_name = 'mcp_front'; - $this->page_title = 'MCP_MAIN'; - break; - - case 'forum_view': - if (!function_exists('mcp_forum_view')) - { - include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx); - } - - $user->add_lang('viewforum'); - - $forum_id = $request->variable('f', 0); - - $forum_info = phpbb_get_forum_data($forum_id, 'm_', true); - - if (!count($forum_info)) - { - $this->main('main', 'front'); - return; - } - - $forum_info = $forum_info[$forum_id]; - - mcp_forum_view($id, $mode, $action, $forum_info); - - $this->tpl_name = 'mcp_forum'; - $this->page_title = 'MCP_MAIN_FORUM_VIEW'; - break; - - case 'topic_view': - if (!function_exists('mcp_topic_view')) - { - include($phpbb_root_path . 'includes/mcp/mcp_topic.' . $phpEx); - } - - mcp_topic_view($id, $mode, $action); - - $this->tpl_name = 'mcp_topic'; - $this->page_title = 'MCP_MAIN_TOPIC_VIEW'; - break; - - case 'post_details': - if (!function_exists('mcp_post_details')) - { - include($phpbb_root_path . 'includes/mcp/mcp_post.' . $phpEx); - } - - mcp_post_details($id, $mode, $action); - - $this->tpl_name = ($action == 'whois') ? 'mcp_whois' : 'mcp_post'; - $this->page_title = 'MCP_MAIN_POST_DETAILS'; - break; - - default: - if ($quickmod) - { - switch ($action) - { - case 'lock': - case 'unlock': - case 'make_announce': - case 'make_sticky': - case 'make_global': - case 'make_normal': - case 'make_onindex': - case 'move': - case 'fork': - case 'delete_topic': - trigger_error('TOPIC_NOT_EXIST'); - break; - - case 'lock_post': - case 'unlock_post': - case 'delete_post': - trigger_error('POST_NOT_EXIST'); - break; - } - } - - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - } -} - -/** -* Lock/Unlock Topic/Post -*/ -function lock_unlock($action, $ids) -{ - global $user, $db, $request, $phpbb_log, $phpbb_dispatcher; - - if ($action == 'lock' || $action == 'unlock') - { - $table = TOPICS_TABLE; - $sql_id = 'topic_id'; - $set_id = 'topic_status'; - $l_prefix = 'TOPIC'; - } - else - { - $table = POSTS_TABLE; - $sql_id = 'post_id'; - $set_id = 'post_edit_locked'; - $l_prefix = 'POST'; - } - - $orig_ids = $ids; - - if (!phpbb_check_ids($ids, $table, $sql_id, array('m_lock'))) - { - // Make sure that for f_user_lock only the lock action is triggered. - if ($action != 'lock') - { - return; - } - - $ids = $orig_ids; - - if (!phpbb_check_ids($ids, $table, $sql_id, array('f_user_lock'))) - { - return; - } - } - unset($orig_ids); - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $redirect = reapply_sid($redirect); - - $s_hidden_fields = build_hidden_fields(array( - $sql_id . '_list' => $ids, - 'action' => $action, - 'redirect' => $redirect) - ); - - if (confirm_box(true)) - { - $sql = "UPDATE $table - SET $set_id = " . (($action == 'lock' || $action == 'lock_post') ? ITEM_LOCKED : ITEM_UNLOCKED) . ' - WHERE ' . $db->sql_in_set($sql_id, $ids); - $db->sql_query($sql); - - $data = ($action == 'lock' || $action == 'unlock') ? phpbb_get_topic_data($ids) : phpbb_get_post_data($ids); - - foreach ($data as $id => $row) - { - $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'] - )); - } - - /** - * Perform additional actions after locking/unlocking posts/topics - * - * @event core.mcp_lock_unlock_after - * @var string action Variable containing the action we perform on the posts/topics ('lock', 'unlock', 'lock_post' or 'unlock_post') - * @var array ids Array containing the post/topic IDs that have been locked/unlocked - * @var array data Array containing posts/topics data - * @since 3.1.7-RC1 - */ - $vars = array( - 'action', - 'ids', - 'data', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_lock_unlock_after', compact($vars))); - - $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]; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_PAGE', '', ''); - } - trigger_error($message); - } - else - { - confirm_box(false, strtoupper($action) . '_' . $l_prefix . ((count($ids) == 1) ? '' : 'S'), $s_hidden_fields); - } - - redirect($redirect); -} - -/** -* Change Topic Type -*/ -function change_topic_type($action, $topic_ids) -{ - 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 = (count($topic_ids) == 1) ? 'MCP_MAKE_ANNOUNCEMENT' : 'MCP_MAKE_ANNOUNCEMENTS'; - break; - - case 'make_global': - $new_topic_type = POST_GLOBAL; - $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 = (count($topic_ids) == 1) ? 'MCP_MAKE_STICKY' : 'MCP_MAKE_STICKIES'; - break; - - default: - $new_topic_type = POST_NORMAL; - $check_acl = false; - $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_NORMAL' : 'MCP_MAKE_NORMALS'; - break; - } - - $forum_id = phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', $check_acl, true); - - if ($forum_id === false) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $redirect = reapply_sid($redirect); - - $s_hidden_fields = array( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => $action, - 'redirect' => $redirect, - ); - - 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) && 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); - } - - $db->sql_transaction('commit'); - - $success_msg = (count($topic_ids) == 1) ? 'TOPIC_TYPE_CHANGED' : 'TOPICS_TYPE_CHANGED'; - - if (count($topic_ids)) - { - $data = phpbb_get_topic_data($topic_ids); - - foreach ($data as $topic_id => $row) - { - $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]; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_PAGE', '', ''); - } - trigger_error($message); - } - else - { - confirm_box(false, $l_new_type, build_hidden_fields($s_hidden_fields)); - } - - redirect($redirect); -} - -/** -* Move Topic -*/ -function mcp_move_topic($topic_ids) -{ - global $auth, $user, $db, $template, $phpbb_log, $request, $phpbb_dispatcher; - global $phpEx, $phpbb_root_path; - - // Here we limit the operation to one forum only - $forum_id = phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_move'), true); - - if ($forum_id === false) - { - return; - } - - $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( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => 'move', - 'redirect' => $redirect) - ); - - if ($to_forum_id) - { - $forum_data = phpbb_get_forum_data($to_forum_id, 'f_post'); - - if (!count($forum_data)) - { - $additional_msg = $user->lang['FORUM_NOT_EXIST']; - } - else - { - $forum_data = $forum_data[$to_forum_id]; - - if ($forum_data['forum_type'] != FORUM_POST) - { - $additional_msg = $user->lang['FORUM_NOT_POSTABLE']; - } - else if (!$auth->acl_get('f_post', $to_forum_id) || (!$auth->acl_get('m_approve', $to_forum_id) && !$auth->acl_get('f_noapprove', $to_forum_id))) - { - $additional_msg = $user->lang['USER_CANNOT_POST']; - } - else if ($forum_id == $to_forum_id) - { - $additional_msg = $user->lang['CANNOT_MOVE_SAME_FORUM']; - } - } - } - else if (isset($_POST['confirm'])) - { - $additional_msg = $user->lang['FORUM_NOT_EXIST']; - } - - if (!$to_forum_id || $additional_msg) - { - $request->overwrite('confirm', null, \phpbb\request\request_interface::POST); - $request->overwrite('confirm_key', null); - } - - if (confirm_box(true)) - { - $topic_data = phpbb_get_topic_data($topic_ids); - $leave_shadow = (isset($_POST['move_leave_shadow'])) ? true : false; - - $forum_sync_data = array(); - - $forum_sync_data[$forum_id] = current($topic_data); - $forum_sync_data[$to_forum_id] = $forum_data; - - $topics_moved = $topics_moved_unapproved = $topics_moved_softdeleted = 0; - $posts_moved = $posts_moved_unapproved = $posts_moved_softdeleted = 0; - - foreach ($topic_data as $topic_id => $topic_info) - { - if ($topic_info['topic_visibility'] == ITEM_APPROVED) - { - $topics_moved++; - } - else if ($topic_info['topic_visibility'] == ITEM_UNAPPROVED || $topic_info['topic_visibility'] == ITEM_REAPPROVE) - { - $topics_moved_unapproved++; - } - else if ($topic_info['topic_visibility'] == ITEM_DELETED) - { - $topics_moved_softdeleted++; - } - - $posts_moved += $topic_info['topic_posts_approved']; - $posts_moved_unapproved += $topic_info['topic_posts_unapproved']; - $posts_moved_softdeleted += $topic_info['topic_posts_softdeleted']; - } - - $db->sql_transaction('begin'); - - // Move topics, but do not resync yet - move_topics($topic_ids, $to_forum_id, false); - - if ($request->is_set_post('move_lock_topics') && $auth->acl_get('m_lock', $to_forum_id)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_status = ' . ITEM_LOCKED . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - - $shadow_topics = 0; - $forum_ids = array($to_forum_id); - foreach ($topic_data as $topic_id => $row) - { - // Get the list of forums to resync - $forum_ids[] = $row['forum_id']; - - // We add the $to_forum_id twice, because 'forum_id' is updated - // when the topic is moved again later. - $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_MOVE', false, array( - 'forum_id' => (int) $to_forum_id, - 'topic_id' => (int) $topic_id, - $row['forum_name'], - $forum_data['forum_name'], - (int) $row['forum_id'], - (int) $forum_data['forum_id'], - )); - - // Leave a redirection if required and only if the topic is visible to users - if ($leave_shadow && $row['topic_visibility'] == ITEM_APPROVED && $row['topic_type'] != POST_GLOBAL) - { - $shadow = array( - 'forum_id' => (int) $row['forum_id'], - 'icon_id' => (int) $row['icon_id'], - 'topic_attachment' => (int) $row['topic_attachment'], - 'topic_visibility' => ITEM_APPROVED, // a shadow topic is always approved - 'topic_reported' => 0, // a shadow topic is never reported - 'topic_title' => (string) $row['topic_title'], - 'topic_poster' => (int) $row['topic_poster'], - 'topic_time' => (int) $row['topic_time'], - 'topic_time_limit' => (int) $row['topic_time_limit'], - 'topic_views' => (int) $row['topic_views'], - 'topic_posts_approved' => (int) $row['topic_posts_approved'], - 'topic_posts_unapproved'=> (int) $row['topic_posts_unapproved'], - 'topic_posts_softdeleted'=> (int) $row['topic_posts_softdeleted'], - 'topic_status' => ITEM_MOVED, - 'topic_type' => POST_NORMAL, - 'topic_first_post_id' => (int) $row['topic_first_post_id'], - 'topic_first_poster_colour'=>(string) $row['topic_first_poster_colour'], - 'topic_first_poster_name'=> (string) $row['topic_first_poster_name'], - 'topic_last_post_id' => (int) $row['topic_last_post_id'], - 'topic_last_poster_id' => (int) $row['topic_last_poster_id'], - 'topic_last_poster_colour'=>(string) $row['topic_last_poster_colour'], - 'topic_last_poster_name'=> (string) $row['topic_last_poster_name'], - 'topic_last_post_subject'=> (string) $row['topic_last_post_subject'], - 'topic_last_post_time' => (int) $row['topic_last_post_time'], - 'topic_last_view_time' => (int) $row['topic_last_view_time'], - 'topic_moved_id' => (int) $row['topic_id'], - 'topic_bumped' => (int) $row['topic_bumped'], - 'topic_bumper' => (int) $row['topic_bumper'], - 'poll_title' => (string) $row['poll_title'], - 'poll_start' => (int) $row['poll_start'], - 'poll_length' => (int) $row['poll_length'], - 'poll_max_options' => (int) $row['poll_max_options'], - 'poll_last_vote' => (int) $row['poll_last_vote'] - ); - - /** - * Perform actions before shadow topic is created. - * - * @event core.mcp_main_modify_shadow_sql - * @var array shadow SQL array to be used by $db->sql_build_array - * @var array row Topic data - * @since 3.1.11-RC1 - * @changed 3.1.11-RC1 Added variable: row - */ - $vars = array( - 'shadow', - 'row', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_main_modify_shadow_sql', compact($vars))); - - $db->sql_query('INSERT INTO ' . TOPICS_TABLE . $db->sql_build_array('INSERT', $shadow)); - - // Shadow topics only count on new "topics" and not posts... a shadow topic alone has 0 posts - $shadow_topics++; - } - } - unset($topic_data); - - $sync_sql = array(); - if ($posts_moved) - { - $sync_sql[$to_forum_id][] = 'forum_posts_approved = forum_posts_approved + ' . (int) $posts_moved; - $sync_sql[$forum_id][] = 'forum_posts_approved = forum_posts_approved - ' . (int) $posts_moved; - } - if ($posts_moved_unapproved) - { - $sync_sql[$to_forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved + ' . (int) $posts_moved_unapproved; - $sync_sql[$forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved - ' . (int) $posts_moved_unapproved; - } - if ($posts_moved_softdeleted) - { - $sync_sql[$to_forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted + ' . (int) $posts_moved_softdeleted; - $sync_sql[$forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted - ' . (int) $posts_moved_softdeleted; - } - - if ($topics_moved) - { - $sync_sql[$to_forum_id][] = 'forum_topics_approved = forum_topics_approved + ' . (int) $topics_moved; - if ($topics_moved - $shadow_topics > 0) - { - $sync_sql[$forum_id][] = 'forum_topics_approved = forum_topics_approved - ' . (int) ($topics_moved - $shadow_topics); - } - } - if ($topics_moved_unapproved) - { - $sync_sql[$to_forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved + ' . (int) $topics_moved_unapproved; - $sync_sql[$forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved - ' . (int) $topics_moved_unapproved; - } - if ($topics_moved_softdeleted) - { - $sync_sql[$to_forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted + ' . (int) $topics_moved_softdeleted; - $sync_sql[$forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted - ' . (int) $topics_moved_softdeleted; - } - - $success_msg = (count($topic_ids) == 1) ? 'TOPIC_MOVED_SUCCESS' : 'TOPICS_MOVED_SUCCESS'; - - foreach ($sync_sql as $forum_id_key => $array) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . implode(', ', $array) . ' - WHERE forum_id = ' . $forum_id_key; - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - sync('forum', 'forum_id', array($forum_id, $to_forum_id)); - } - else - { - $template->assign_vars(array( - 'S_FORUM_SELECT' => make_forum_select($to_forum_id, $forum_id, false, true, true, true), - 'S_CAN_LEAVE_SHADOW' => true, - 'S_CAN_LOCK_TOPIC' => ($auth->acl_get('m_lock', $to_forum_id)) ? true : false, - 'ADDITIONAL_MSG' => $additional_msg) - ); - - confirm_box(false, 'MOVE_TOPIC' . ((count($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html'); - } - - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - - if (!$success_msg) - { - redirect($redirect); - } - else - { - meta_refresh(3, $redirect); - - $message = $user->lang[$success_msg]; - $message .= '

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

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

' . sprintf($user->lang['RETURN_NEW_FORUM'], '', ''); - - trigger_error($message); - } -} - -/** -* Restore Topics -*/ -function mcp_restore_topic($topic_ids) -{ - global $user, $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_log; - - if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_approve'))) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $forum_id = $request->variable('f', 0); - - $s_hidden_fields = build_hidden_fields(array( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => 'restore_topic', - 'redirect' => $redirect, - )); - $success_msg = ''; - - if (confirm_box(true)) - { - $success_msg = (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)) - { - $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, (count($topic_ids) == 1) ? 'RESTORE_TOPIC' : 'RESTORE_TOPICS', $s_hidden_fields); - } - - $topic_id = $request->variable('t', 0); - if (!$request->is_set('quickmod', \phpbb\request\request_interface::REQUEST)) - { - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - $redirect_message = 'PAGE'; - } - else if ($topic_id) - { - $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id); - $redirect_message = 'TOPIC'; - } - else - { - $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); - $redirect_message = 'FORUM'; - } - - if (!$success_msg) - { - redirect($redirect); - } - else - { - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . sprintf($user->lang['RETURN_' . $redirect_message], '', '')); - } -} - -/** -* Delete Topics -*/ -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, $phpbb_log; - - $check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete'; - if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array($check_permission))) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $forum_id = $request->variable('f', 0); - - $s_hidden_fields = array( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => $action, - 'redirect' => $redirect, - ); - $success_msg = ''; - - if (confirm_box(true)) - { - $success_msg = (count($topic_ids) == 1) ? 'TOPIC_DELETED_SUCCESS' : 'TOPICS_DELETED_SUCCESS'; - - $data = phpbb_get_topic_data($topic_ids); - - foreach ($data as $topic_id => $row) - { - if ($row['topic_moved_id']) - { - $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)) - { - $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 - { - $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) - { - delete_topics('topic_id', $topic_ids); - } - } - else - { - global $template; - - $user->add_lang('posting'); - - // If there are only shadow topics, we neither need a reason nor softdelete - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - AND topic_moved_id = 0'; - $result = $db->sql_query_limit($sql, 1); - $only_shadow = !$db->sql_fetchfield('topic_id'); - $db->sql_freeresult($result); - - $only_softdeleted = false; - if (!$only_shadow && $auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id)) - { - // If there are only soft deleted topics, we display a message why the option is not available - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - AND topic_visibility <> ' . ITEM_DELETED; - $result = $db->sql_query_limit($sql, 1); - $only_softdeleted = !$db->sql_fetchfield('topic_id'); - $db->sql_freeresult($result); - } - - $template->assign_vars(array( - 'S_SHADOW_TOPICS' => $only_shadow, - 'S_SOFTDELETED' => $only_softdeleted, - 'S_TOPIC_MODE' => true, - 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id), - 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id), - 'DELETE_TOPIC_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_TOPIC_PERMANENTLY', count($topic_ids)), - )); - - $count = count($topic_ids); - $l_confirm = $count === 1 ? 'DELETE_TOPIC' : 'DELETE_TOPICS'; - if ($only_softdeleted) - { - $l_confirm = array($l_confirm . '_PERMANENTLY', $count); - $s_hidden_fields['delete_permanent'] = '1'; - } - else if ($only_shadow || !$auth->acl_get('m_softdelete', $forum_id)) - { - $s_hidden_fields['delete_permanent'] = '1'; - } - - confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); - } - - $topic_id = $request->variable('t', 0); - if (!$request->is_set('quickmod', \phpbb\request\request_interface::REQUEST)) - { - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - $redirect_message = 'PAGE'; - } - else if ($is_soft && $topic_id) - { - $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id); - $redirect_message = 'TOPIC'; - } - else - { - $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); - $redirect_message = 'FORUM'; - } - - if (!$success_msg) - { - redirect($redirect); - } - else - { - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . sprintf($user->lang['RETURN_' . $redirect_message], '', '')); - } -} - -/** -* Delete Posts -*/ -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, $phpbb_log; - - $check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete'; - if (!phpbb_check_ids($post_ids, POSTS_TABLE, 'post_id', array($check_permission))) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $forum_id = $request->variable('f', 0); - - $s_hidden_fields = array( - 'post_id_list' => $post_ids, - 'f' => $forum_id, - 'action' => $action, - 'redirect' => $redirect, - ); - $success_msg = ''; - - if (confirm_box(true) && $is_soft) - { - $post_info = phpbb_get_post_data($post_ids); - - $topic_info = $approve_log = array(); - - // Group the posts by topic_id - foreach ($post_info as $post_id => $post_data) - { - if ($post_data['post_visibility'] != ITEM_APPROVED) - { - continue; - } - $topic_id = (int) $post_data['topic_id']; - - $topic_info[$topic_id]['posts'][] = (int) $post_id; - $topic_info[$topic_id]['forum_id'] = (int) $post_data['forum_id']; - - if ($post_id == $post_data['topic_first_post_id']) - { - $topic_info[$topic_id]['first_post'] = true; - } - - if ($post_id == $post_data['topic_last_post_id']) - { - $topic_info[$topic_id]['last_post'] = true; - } - - $approve_log[] = array( - 'forum_id' => $post_data['forum_id'], - 'topic_id' => $post_data['topic_id'], - 'post_id' => $post_id, - 'post_subject' => $post_data['post_subject'], - 'poster_id' => $post_data['poster_id'], - 'post_username' => $post_data['post_username'], - 'username' => $post_data['username'], - ); - } - - /* @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 = count($topic_info); - // None of the topics is really deleted, so a redirect won't hurt much. - $deleted_topics = 0; - - $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']; - $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); - - // Return links - $return_link = array(); - if ($affected_topics == 1 && $topic_id) - { - $return_link[] = sprintf($user->lang['RETURN_TOPIC'], '', ''); - } - $return_link[] = sprintf($user->lang['RETURN_FORUM'], '', ''); - - } - else if (confirm_box(true)) - { - if (!function_exists('delete_posts')) - { - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - - // Count the number of topics that are affected - // I did not use COUNT(DISTINCT ...) because I remember having problems - // with it on older versions of MySQL -- Ashe - - $sql = 'SELECT DISTINCT topic_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $result = $db->sql_query($sql); - - $topic_id_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_id_list[] = $row['topic_id']; - } - $affected_topics = count($topic_id_list); - $db->sql_freeresult($result); - - $post_data = phpbb_get_post_data($post_ids); - - foreach ($post_data as $id => $row) - { - $post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username']; - $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 - delete_posts('post_id', $post_ids); - - $sql = 'SELECT COUNT(topic_id) AS topics_left - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_id_list); - $result = $db->sql_query_limit($sql, 1); - - $deleted_topics = ($row = $db->sql_fetchrow($result)) ? ($affected_topics - $row['topics_left']) : $affected_topics; - $db->sql_freeresult($result); - - $topic_id = $request->variable('t', 0); - - // Return links - $return_link = array(); - if ($affected_topics == 1 && !$deleted_topics && $topic_id) - { - $return_link[] = sprintf($user->lang['RETURN_TOPIC'], '', ''); - } - $return_link[] = sprintf($user->lang['RETURN_FORUM'], '', ''); - - if (count($post_ids) == 1) - { - if ($deleted_topics) - { - // We deleted the only post of a topic, which in turn has - // been removed from the database - $success_msg = $user->lang['TOPIC_DELETED_SUCCESS']; - } - else - { - $success_msg = $user->lang['POST_DELETED_SUCCESS']; - } - } - else - { - if ($deleted_topics) - { - // Some of topics disappeared - $success_msg = $user->lang['POSTS_DELETED_SUCCESS'] . '

' . $user->lang['EMPTY_TOPICS_REMOVED_WARNING']; - } - else - { - $success_msg = $user->lang['POSTS_DELETED_SUCCESS']; - } - } - } - else - { - global $template; - - $user->add_lang('posting'); - - $only_softdeleted = false; - if ($auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id)) - { - // If there are only soft deleted posts, we display a message why the option is not available - $sql = 'SELECT post_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids) . ' - AND post_visibility <> ' . ITEM_DELETED; - $result = $db->sql_query_limit($sql, 1); - $only_softdeleted = !$db->sql_fetchfield('post_id'); - $db->sql_freeresult($result); - } - - $template->assign_vars(array( - 'S_SOFTDELETED' => $only_softdeleted, - 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id), - 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id), - 'DELETE_POST_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_POST_PERMANENTLY', count($post_ids)), - )); - - $count = count($post_ids); - $l_confirm = $count === 1 ? 'DELETE_POST' : 'DELETE_POSTS'; - if ($only_softdeleted) - { - $l_confirm = array($l_confirm . '_PERMANENTLY', $count); - $s_hidden_fields['delete_permanent'] = '1'; - } - else if (!$auth->acl_get('m_softdelete', $forum_id)) - { - $s_hidden_fields['delete_permanent'] = '1'; - } - - confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); - } - - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - - if (!$success_msg) - { - redirect($redirect); - } - else - { - if ($affected_topics != 1 || $deleted_topics || !$topic_id) - { - $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "f=$forum_id&i=main&mode=forum_view", false); - } - - meta_refresh(3, $redirect); - trigger_error($success_msg . '

' . sprintf($user->lang['RETURN_PAGE'], '', '') . '

' . implode('

', $return_link)); - } -} - -/** -* Fork Topic -*/ -function mcp_fork_topic($topic_ids) -{ - global $auth, $user, $db, $template, $config; - 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->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(); - - $s_hidden_fields = build_hidden_fields(array( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => 'fork', - 'redirect' => $redirect) - ); - - if ($to_forum_id) - { - $forum_data = phpbb_get_forum_data($to_forum_id, 'f_post'); - - if (!count($topic_ids)) - { - $additional_msg = $user->lang['NO_TOPIC_SELECTED']; - } - else if (!count($forum_data)) - { - $additional_msg = $user->lang['FORUM_NOT_EXIST']; - } - else - { - $forum_data = $forum_data[$to_forum_id]; - - if ($forum_data['forum_type'] != FORUM_POST) - { - $additional_msg = $user->lang['FORUM_NOT_POSTABLE']; - } - else if (!$auth->acl_get('f_post', $to_forum_id)) - { - $additional_msg = $user->lang['USER_CANNOT_POST']; - } - } - } - else if (isset($_POST['confirm'])) - { - $additional_msg = $user->lang['FORUM_NOT_EXIST']; - } - - if ($additional_msg) - { - $request->overwrite('confirm', null, \phpbb\request\request_interface::POST); - $request->overwrite('confirm_key', null); - } - - if (confirm_box(true)) - { - $topic_data = phpbb_get_topic_data($topic_ids, 'f_post'); - - $total_topics = $total_topics_unapproved = $total_topics_softdeleted = 0; - $total_posts = $total_posts_unapproved = $total_posts_softdeleted = 0; - $new_topic_id_list = array(); - - foreach ($topic_data as $topic_id => $topic_row) - { - if (!isset($search_type) && $topic_row['enable_indexing']) - { - // Select the search method and do some additional checks to ensure it can actually be utilised - $search_type = $config['search_type']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - $search_mode = 'post'; - - if ($error) - { - trigger_error($error); - } - } - else if (!isset($search_type) && !$topic_row['enable_indexing']) - { - $search_type = false; - } - - $sql_ary = array( - 'forum_id' => (int) $to_forum_id, - 'icon_id' => (int) $topic_row['icon_id'], - 'topic_attachment' => (int) $topic_row['topic_attachment'], - 'topic_visibility' => (int) $topic_row['topic_visibility'], - 'topic_reported' => 0, - 'topic_title' => (string) $topic_row['topic_title'], - 'topic_poster' => (int) $topic_row['topic_poster'], - 'topic_time' => (int) $topic_row['topic_time'], - 'topic_posts_approved' => (int) $topic_row['topic_posts_approved'], - 'topic_posts_unapproved' => (int) $topic_row['topic_posts_unapproved'], - 'topic_posts_softdeleted' => (int) $topic_row['topic_posts_softdeleted'], - 'topic_status' => (int) $topic_row['topic_status'], - 'topic_type' => (int) $topic_row['topic_type'], - 'topic_first_poster_name' => (string) $topic_row['topic_first_poster_name'], - 'topic_last_poster_id' => (int) $topic_row['topic_last_poster_id'], - 'topic_last_poster_name' => (string) $topic_row['topic_last_poster_name'], - 'topic_last_post_time' => (int) $topic_row['topic_last_post_time'], - 'topic_last_view_time' => (int) $topic_row['topic_last_view_time'], - 'topic_bumped' => (int) $topic_row['topic_bumped'], - 'topic_bumper' => (int) $topic_row['topic_bumper'], - 'poll_title' => (string) $topic_row['poll_title'], - 'poll_start' => (int) $topic_row['poll_start'], - 'poll_length' => (int) $topic_row['poll_length'], - 'poll_max_options' => (int) $topic_row['poll_max_options'], - 'poll_vote_change' => (int) $topic_row['poll_vote_change'], - ); - - /** - * Perform actions before forked topic is created. - * - * @event core.mcp_main_modify_fork_sql - * @var array sql_ary SQL array to be used by $db->sql_build_array - * @var array topic_row Topic data - * @since 3.1.11-RC1 - * @changed 3.1.11-RC1 Added variable: topic_row - */ - $vars = array( - 'sql_ary', - 'topic_row', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_main_modify_fork_sql', compact($vars))); - - $db->sql_query('INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - $new_topic_id = $db->sql_nextid(); - $new_topic_id_list[$topic_id] = $new_topic_id; - - switch ($topic_row['topic_visibility']) - { - case ITEM_APPROVED: - $total_topics++; - break; - case ITEM_UNAPPROVED: - case ITEM_REAPPROVE: - $total_topics_unapproved++; - break; - case ITEM_DELETED: - $total_topics_softdeleted++; - break; - } - - if ($topic_row['poll_start']) - { - $sql = 'SELECT * - FROM ' . POLL_OPTIONS_TABLE . " - WHERE topic_id = $topic_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary = array( - 'poll_option_id' => (int) $row['poll_option_id'], - 'topic_id' => (int) $new_topic_id, - 'poll_option_text' => (string) $row['poll_option_text'], - 'poll_option_total' => 0 - ); - - $db->sql_query('INSERT INTO ' . POLL_OPTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - } - $db->sql_freeresult($result); - } - - $sql = 'SELECT * - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - ORDER BY post_time ASC, post_id ASC"; - $result = $db->sql_query($sql); - - $post_rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $post_rows[] = $row; - } - $db->sql_freeresult($result); - - if (!count($post_rows)) - { - continue; - } - - foreach ($post_rows as $row) - { - $sql_ary = array( - 'topic_id' => (int) $new_topic_id, - 'forum_id' => (int) $to_forum_id, - 'poster_id' => (int) $row['poster_id'], - 'icon_id' => (int) $row['icon_id'], - 'poster_ip' => (string) $row['poster_ip'], - 'post_time' => (int) $row['post_time'], - 'post_visibility' => (int) $row['post_visibility'], - 'post_reported' => 0, - 'enable_bbcode' => (int) $row['enable_bbcode'], - 'enable_smilies' => (int) $row['enable_smilies'], - 'enable_magic_url' => (int) $row['enable_magic_url'], - 'enable_sig' => (int) $row['enable_sig'], - 'post_username' => (string) $row['post_username'], - 'post_subject' => (string) $row['post_subject'], - 'post_text' => (string) $row['post_text'], - 'post_edit_reason' => (string) $row['post_edit_reason'], - 'post_edit_user' => (int) $row['post_edit_user'], - 'post_checksum' => (string) $row['post_checksum'], - 'post_attachment' => (int) $row['post_attachment'], - 'bbcode_bitfield' => $row['bbcode_bitfield'], - 'bbcode_uid' => (string) $row['bbcode_uid'], - 'post_edit_time' => (int) $row['post_edit_time'], - 'post_edit_count' => (int) $row['post_edit_count'], - 'post_edit_locked' => (int) $row['post_edit_locked'], - 'post_postcount' => $row['post_postcount'], - ); - // Adjust post count only if the post can be incremented to the user counter - if ($row['post_postcount']) - { - if (isset($counter[$row['poster_id']])) - { - ++$counter[$row['poster_id']]; - } - else - { - $counter[$row['poster_id']] = 1; - } - } - $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: - $total_posts++; - break; - case ITEM_UNAPPROVED: - case ITEM_REAPPROVE: - $total_posts_unapproved++; - break; - case ITEM_DELETED: - $total_posts_softdeleted++; - break; - } - - // Copy whether the topic is dotted - markread('post', $to_forum_id, $new_topic_id, 0, $row['poster_id']); - - if (!empty($search_type)) - { - $search->index($search_mode, $new_post_id, $sql_ary['post_text'], $sql_ary['post_subject'], $sql_ary['poster_id'], ($topic_row['topic_type'] == POST_GLOBAL) ? 0 : $to_forum_id); - $search_mode = 'reply'; // After one we index replies - } - - // Copy Attachments - if ($row['post_attachment']) - { - $sql = 'SELECT * FROM ' . ATTACHMENTS_TABLE . " - WHERE post_msg_id = {$row['post_id']} - AND topic_id = $topic_id - AND in_message = 0"; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($attach_row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'post_msg_id' => (int) $new_post_id, - 'topic_id' => (int) $new_topic_id, - 'in_message' => 0, - 'is_orphan' => (int) $attach_row['is_orphan'], - 'poster_id' => (int) $attach_row['poster_id'], - 'physical_filename' => (string) utf8_basename($attach_row['physical_filename']), - 'real_filename' => (string) utf8_basename($attach_row['real_filename']), - 'download_count' => (int) $attach_row['download_count'], - 'attach_comment' => (string) $attach_row['attach_comment'], - 'extension' => (string) $attach_row['extension'], - 'mimetype' => (string) $attach_row['mimetype'], - 'filesize' => (int) $attach_row['filesize'], - 'filetime' => (int) $attach_row['filetime'], - 'thumbnail' => (int) $attach_row['thumbnail'] - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(ATTACHMENTS_TABLE, $sql_ary); - } - } - } - - // Copy topic subscriptions to new topic - $sql = 'SELECT user_id, notify_status - FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'topic_id' => (int) $new_topic_id, - 'user_id' => (int) $row['user_id'], - 'notify_status' => (int) $row['notify_status'], - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); - } - - // Copy bookmarks to new topic - $sql = 'SELECT user_id - FROM ' . BOOKMARKS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'topic_id' => (int) $new_topic_id, - 'user_id' => (int) $row['user_id'], - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); - } - } - - // Sync new topics, parent forums and board stats - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_posts_approved = forum_posts_approved + ' . $total_posts . ', - forum_posts_unapproved = forum_posts_unapproved + ' . $total_posts_unapproved . ', - forum_posts_softdeleted = forum_posts_softdeleted + ' . $total_posts_softdeleted . ', - forum_topics_approved = forum_topics_approved + ' . $total_topics . ', - forum_topics_unapproved = forum_topics_unapproved + ' . $total_topics_unapproved . ', - forum_topics_softdeleted = forum_topics_softdeleted + ' . $total_topics_softdeleted . ' - WHERE forum_id = ' . $to_forum_id; - $db->sql_query($sql); - - if (!empty($counter)) - { - // Do only one query per user and not a query per post. - foreach ($counter as $user_id => $count) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts + ' . (int) $count . ' - WHERE user_id = ' . (int) $user_id; - $db->sql_query($sql); - } - } - - sync('topic', 'topic_id', $new_topic_id_list); - sync('forum', 'forum_id', $to_forum_id); - - $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) - { - $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 = (count($topic_ids) == 1) ? 'TOPIC_FORKED_SUCCESS' : 'TOPICS_FORKED_SUCCESS'; - } - else - { - $template->assign_vars(array( - 'S_FORUM_SELECT' => make_forum_select($to_forum_id, false, false, true, true, true), - 'S_CAN_LEAVE_SHADOW' => false, - 'ADDITIONAL_MSG' => $additional_msg) - ); - - confirm_box(false, 'FORK_TOPIC' . ((count($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html'); - } - - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - - if (!$success_msg) - { - redirect($redirect); - } - else - { - $redirect_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); - meta_refresh(3, $redirect_url); - $return_link = sprintf($user->lang['RETURN_FORUM'], '', ''); - - if ($forum_id != $to_forum_id) - { - $return_link .= '

' . sprintf($user->lang['RETURN_NEW_FORUM'], '', ''); - } - - trigger_error($user->lang[$success_msg] . '

' . $return_link); - } -} diff --git a/install/update/new/includes/mcp/mcp_notes.php b/install/update/new/includes/mcp/mcp_notes.php deleted file mode 100644 index 74bd1f1..0000000 --- a/install/update/new/includes/mcp/mcp_notes.php +++ /dev/null @@ -1,258 +0,0 @@ - -* @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; -} - -/** -* mcp_notes -* Displays notes about a user -*/ -class mcp_notes -{ - var $p_master; - var $u_action; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $user, $template, $request; - global $phpbb_root_path, $phpEx; - - $action = $request->variable('action', array('' => '')); - - if (is_array($action)) - { - $action = key($action); - } - - $this->page_title = 'MCP_NOTES'; - - switch ($mode) - { - case 'front': - $template->assign_vars(array( - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=mcp&field=username&select_single=true'), - 'U_POST_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes'), - - 'L_TITLE' => $user->lang['MCP_NOTES'], - )); - - $this->tpl_name = 'mcp_notes_front'; - break; - - case 'user_notes': - $user->add_lang('acp/common'); - - $this->mcp_notes_user_view($action); - $this->tpl_name = 'mcp_notes_user'; - break; - } - } - - /** - * Display user notes - */ - function mcp_notes_user_view($action) - { - global $config, $phpbb_log, $request; - global $template, $db, $user, $auth, $phpbb_container; - - $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'); - - $sql_where = ($user_id) ? "user_id = $user_id" : "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE $sql_where"; - $result = $db->sql_query($sql); - $userrow = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$userrow) - { - trigger_error('NO_USER'); - } - - $user_id = $userrow['user_id']; - - // Populate user id to the currently active module (this module) - // The following method is another way of adjusting module urls. It is the easy variant if we want - // to directly adjust the current module url based on data retrieved within the same module. - if (strpos($this->u_action, "&u=$user_id") === false) - { - $this->p_master->adjust_url('&u=' . $user_id); - $this->u_action .= "&u=$user_id"; - } - - $deletemark = ($action == 'del_marked') ? true : false; - $deleteall = ($action == 'del_all') ? true : false; - $marked = $request->variable('marknote', array(0)); - $usernote = $request->variable('usernote', '', true); - - // Handle any actions - if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs')) - { - $where_sql = ''; - if ($deletemark && $marked) - { - $sql_in = array(); - foreach ($marked as $mark) - { - $sql_in[] = $mark; - } - $where_sql = ' AND ' . $db->sql_in_set('log_id', $sql_in); - unset($sql_in); - } - - if ($where_sql || $deleteall) - { - if (check_form_key('mcp_notes')) - { - $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE log_type = ' . LOG_USERS . " - AND reportee_id = $user_id - $where_sql"; - $db->sql_query($sql); - - $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'; - } - else - { - $msg = 'FORM_INVALID'; - } - $redirect = $this->u_action . '&u=' . $user_id; - meta_refresh(3, $redirect); - trigger_error($user->lang[$msg] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - } - - if ($usernote && $action == 'add_feedback') - { - if (check_form_key('mcp_notes')) - { - $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 - )); - - $msg = $user->lang['USER_FEEDBACK_ADDED']; - } - else - { - $msg = $user->lang['FORM_INVALID']; - } - $redirect = $this->u_action; - meta_refresh(3, $redirect); - - trigger_error($msg . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - - // Generate the appropriate user information for the user we are looking at - - $rank_title = $rank_img = ''; - $avatar_img = phpbb_get_user_avatar($userrow); - - $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_text = array('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_DATE'], 'c' => $user->lang['SORT_IP'], 'd' => $user->lang['SORT_ACTION']); - $sort_by_sql = array('a' => 'u.username_clean', 'b' => 'l.log_time', 'c' => 'l.log_ip', 'd' => 'l.log_operation'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $st, $sk, $sd, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - - // Define where and sort sql for use in displaying logs - $sql_where = ($st) ? (time() - ($st * 86400)) : 0; - $sql_sort = $sort_by_sql[$sk] . ' ' . (($sd == 'd') ? 'DESC' : 'ASC'); - - $keywords = $request->variable('keywords', '', true); - $keywords_param = !empty($keywords) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; - - $log_data = array(); - $log_count = 0; - $start = view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort, $keywords); - - if ($log_count) - { - $template->assign_var('S_USER_NOTES', true); - - foreach ($log_data as $row) - { - $template->assign_block_vars('usernotes', array( - 'REPORT_BY' => $row['username_full'], - 'REPORT_AT' => $user->format_date($row['time']), - 'ACTION' => $row['action'], - 'IP' => $row['ip'], - 'ID' => $row['id']) - ); - } - } - - $base_url = $this->u_action . "&$u_sort_param$keywords_param"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'U_POST_ACTION' => $this->u_action, - 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_KEYWORDS' => $keywords, - - 'L_TITLE' => $user->lang['MCP_NOTES_USER'], - - 'TOTAL_REPORTS' => $user->lang('LIST_REPORTS', (int) $log_count), - - 'RANK_TITLE' => $rank_title, - 'JOINED' => $user->format_date($userrow['user_regdate']), - 'POSTS' => ($userrow['user_posts']) ? $userrow['user_posts'] : 0, - 'WARNINGS' => ($userrow['user_warnings']) ? $userrow['user_warnings'] : 0, - - 'USERNAME_FULL' => get_username_string('full', $userrow['user_id'], $userrow['username'], $userrow['user_colour']), - 'USERNAME_COLOUR' => get_username_string('colour', $userrow['user_id'], $userrow['username'], $userrow['user_colour']), - 'USERNAME' => get_username_string('username', $userrow['user_id'], $userrow['username'], $userrow['user_colour']), - 'U_PROFILE' => get_username_string('profile', $userrow['user_id'], $userrow['username'], $userrow['user_colour']), - - 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $rank_img, - ) - ); - } - -} diff --git a/install/update/new/includes/mcp/mcp_topic.php b/install/update/new/includes/mcp/mcp_topic.php deleted file mode 100644 index 77db5f3..0000000 --- a/install/update/new/includes/mcp/mcp_topic.php +++ /dev/null @@ -1,834 +0,0 @@ - -* @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; -} - -/** -* View topic in MCP -*/ -function mcp_topic_view($id, $mode, $action) -{ - 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()); - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - $user->add_lang('viewtopic'); - - $topic_id = $request->variable('t', 0); - $topic_info = phpbb_get_topic_data(array($topic_id), false, true); - - if (!count($topic_info)) - { - trigger_error('TOPIC_NOT_EXIST'); - } - - $topic_info = $topic_info[$topic_id]; - - // Set up some vars - $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->variable('post_ids', array(0)); - $checked_ids = $post_id_list = $request->variable('post_id_list', array(0)); - - // Resync Topic? - if ($action == 'resync') - { - if (!function_exists('mcp_resync_topics')) - { - include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx); - } - mcp_resync_topics(array($topic_id)); - } - - // Split Topic? - if ($action == 'split_all' || $action == 'split_beyond') - { - if (!$sort) - { - split_topic($action, $topic_id, $to_forum_id, $subject); - } - $action = 'split'; - } - - // Merge Posts? - if ($action == 'merge_posts') - { - if (!$sort) - { - merge_posts($topic_id, $to_topic_id); - } - $action = 'merge'; - } - - if ($action == 'split' && !$subject) - { - $subject = $topic_info['topic_title']; - } - - // Restore or pprove posts? - if (($action == 'restore' || $action == 'approve') && $auth->acl_get('m_approve', $topic_info['forum_id'])) - { - 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 (!count($post_id_list)) - { - trigger_error('NO_POST_SELECTED'); - } - - if (!$sort) - { - mcp_queue::approve_posts($action, $post_id_list, $id, $mode); - } - } - - // Jumpbox, sort selects and that kind of things - make_jumpbox($url . "&i=$id&mode=forum_view", $topic_info['forum_id'], false, 'm_', true); - $where_sql = ($action == 'reports') ? 'WHERE post_reported = 1 AND ' : 'WHERE'; - - $sort_days = $total = 0; - $sort_key = $sort_dir = ''; - $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); - - /* @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->variable('posts_per_page', intval($config['posts_per_page']))); - if ($posts_per_page == 0) - { - $posts_per_page = $total; - } - - if ((!empty($sort_days_old) && $sort_days_old != $sort_days) || $total <= $posts_per_page) - { - $start = 0; - } - $start = $pagination->validate_start($start, $posts_per_page, $total); - - $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; - - $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(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[] = $row; - $post_id_list[] = $row['post_id']; - } - $db->sql_freeresult($result); - - // Get topic tracking info - if ($config['load_db_lastread']) - { - $tmp_topic_data = array($topic_id => $topic_info); - $topic_tracking_info = get_topic_tracking($topic_info['forum_id'], $topic_id, $tmp_topic_data, array($topic_info['forum_id'] => $topic_info['forum_mark_time'])); - unset($tmp_topic_data); - } - else - { - $topic_tracking_info = get_complete_topic_tracking($topic_info['forum_id'], $topic_id); - } - - $has_unapproved_posts = $has_deleted_posts = false; - - // Grab extensions - $attachments = array(); - if ($topic_info['topic_attachment'] && count($post_id_list)) - { - // Get attachments... - if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $topic_info['forum_id'])) - { - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $post_id_list) . ' - AND in_message = 0 - ORDER BY filetime DESC, post_msg_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $attachments[$row['post_msg_id']][] = $row; - } - $db->sql_freeresult($result); - } - } - - /** - * Event to modify the post data for the MCP topic review before assigning the posts - * - * @event core.mcp_topic_modify_post_data - * @var array attachments List of attachments post_id => array of attachments - * @var int forum_id The forum ID we are currently in - * @var int id ID of the tab we are displaying - * @var string mode Mode of the MCP page we are displaying - * @var array post_id_list Array with post ids we are going to display - * @var array rowset Array with the posts data - * @var int topic_id The topic ID we are currently reviewing - * @since 3.1.7-RC1 - */ - $vars = array( - 'attachments', - 'forum_id', - 'id', - 'mode', - 'post_id_list', - 'rowset', - 'topic_id', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_topic_modify_post_data', compact($vars))); - - foreach ($rowset as $current_row_number => $row) - { - $message = $row['post_text']; - $post_subject = ($row['post_subject'] != '') ? $row['post_subject'] : $topic_info['topic_title']; - - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); - - if (!empty($attachments[$row['post_id']])) - { - $update_count = array(); - parse_attachments($topic_info['forum_id'], $message, $attachments[$row['post_id']], $update_count); - } - - if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) - { - $has_unapproved_posts = true; - } - - if ($row['post_visibility'] == ITEM_DELETED) - { - $has_deleted_posts = true; - } - - $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false; - - $post_row = array( - 'POST_AUTHOR_FULL' => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - - 'POST_DATE' => $user->format_date($row['post_time']), - 'POST_SUBJECT' => $post_subject, - 'MESSAGE' => $message, - 'POST_ID' => $row['post_id'], - 'RETURN_TOPIC' => sprintf($user->lang['RETURN_TOPIC'], '', ''), - - 'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'), - - 'S_POST_REPORTED' => ($row['post_reported'] && $auth->acl_get('m_report', $topic_info['forum_id'])), - 'S_POST_UNAPPROVED' => (($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $topic_info['forum_id'])), - 'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED && $auth->acl_get('m_approve', $topic_info['forum_id'])), - 'S_CHECKED' => (($submitted_id_list && !in_array(intval($row['post_id']), $submitted_id_list)) || in_array(intval($row['post_id']), $checked_ids)) ? true : false, - 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false, - - 'U_POST_DETAILS' => "$url&i=$id&p={$row['post_id']}&mode=post_details" . (($forum_id) ? "&f=$forum_id" : ''), - 'U_MCP_APPROVE' => ($auth->acl_get('m_approve', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=approve_details&f=' . $topic_info['forum_id'] . '&p=' . $row['post_id']) : '', - 'U_MCP_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&f=' . $topic_info['forum_id'] . '&p=' . $row['post_id']) : '', - ); - - /** - * Event to modify the template data block for topic reviews in the MCP - * - * @event core.mcp_topic_review_modify_row - * @var int id ID of the tab we are displaying - * @var string mode Mode of the MCP page we are displaying - * @var int topic_id The topic ID we are currently reviewing - * @var int forum_id The forum ID we are currently in - * @var int start Start item of this page - * @var int current_row_number Number of the post on this page - * @var array post_row Template block array of the current post - * @var array row Array with original post and user data - * @var array topic_info Array with topic data - * @var int total Total posts count - * @since 3.1.4-RC1 - */ - $vars = array( - 'id', - 'mode', - 'topic_id', - 'forum_id', - 'start', - 'current_row_number', - 'post_row', - 'row', - 'topic_info', - 'total', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_topic_review_modify_row', compact($vars))); - - $template->assign_block_vars('postrow', $post_row); - - // Display not already displayed Attachments for this post, we already parsed them. ;) - if (!empty($attachments[$row['post_id']])) - { - foreach ($attachments[$row['post_id']] as $attachment) - { - $template->assign_block_vars('postrow.attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - } - - unset($rowset[$current_row_number]); - } - - // Display topic icons for split topic - $s_topic_icons = false; - - if ($auth->acl_gets('m_split', 'm_merge', (int) $topic_info['forum_id'])) - { - include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - $s_topic_icons = posting_gen_topic_icons('', $icon_id); - - // Has the user selected a topic for merge? - if ($to_topic_id) - { - $to_topic_info = phpbb_get_topic_data(array($to_topic_id), 'm_merge'); - - if (!count($to_topic_info)) - { - $to_topic_id = 0; - } - else - { - $to_topic_info = $to_topic_info[$to_topic_id]; - - if (!$to_topic_info['enable_icons'] || $auth->acl_get('!f_icons', $topic_info['forum_id'])) - { - $s_topic_icons = false; - } - } - } - } - - $s_hidden_fields = build_hidden_fields(array( - 'st_old' => $sort_days, - 'post_ids' => $post_id_list, - )); - - $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&t={$topic_info['topic_id']}&mode=$mode&action=$action&to_topic_id=$to_topic_id&posts_per_page=$posts_per_page&st=$sort_days&sk=$sort_key&sd=$sort_dir"); - if ($posts_per_page) - { - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total, $posts_per_page, $start); - } - - $template->assign_vars(array( - 'TOPIC_TITLE' => $topic_info['topic_title'], - 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_info['forum_id'] . '&t=' . $topic_info['topic_id']), - - 'TO_TOPIC_ID' => $to_topic_id, - 'TO_TOPIC_INFO' => ($to_topic_id) ? sprintf($user->lang['YOU_SELECTED_TOPIC'], $to_topic_id, '' . $to_topic_info['topic_title'] . '') : '', - - 'SPLIT_SUBJECT' => $subject, - 'POSTS_PER_PAGE' => $posts_per_page, - 'ACTION' => $action, - - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'), - 'DELETED_IMG' => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'), - 'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'), - - 'S_MCP_ACTION' => "$url&i=$id&mode=$mode&action=$action&start=$start", - 'S_FORUM_SELECT' => ($to_forum_id) ? make_forum_select($to_forum_id, false, false, true, true, true) : make_forum_select($topic_info['forum_id'], false, false, true, true, true), - 'S_CAN_SPLIT' => ($auth->acl_get('m_split', $topic_info['forum_id'])) ? true : false, - 'S_CAN_MERGE' => ($auth->acl_get('m_merge', $topic_info['forum_id'])) ? true : false, - 'S_CAN_DELETE' => ($auth->acl_get('m_delete', $topic_info['forum_id'])) ? true : false, - 'S_CAN_APPROVE' => ($has_unapproved_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false, - 'S_CAN_RESTORE' => ($has_deleted_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false, - 'S_CAN_LOCK' => ($auth->acl_get('m_lock', $topic_info['forum_id'])) ? true : false, - 'S_CAN_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? true : false, - 'S_CAN_SYNC' => $auth->acl_get('m_', $topic_info['forum_id']), - 'S_REPORT_VIEW' => ($action == 'reports') ? true : false, - 'S_MERGE_VIEW' => ($action == 'merge') ? true : false, - 'S_SPLIT_VIEW' => ($action == 'split') ? true : false, - - 'S_HIDDEN_FIELDS' => $s_hidden_fields, - - 'S_SHOW_TOPIC_ICONS' => $s_topic_icons, - 'S_TOPIC_ICON' => $icon_id, - - 'U_SELECT_TOPIC' => "$url&i=$id&mode=forum_view&action=merge_select" . (($forum_id) ? "&f=$forum_id" : ''), - - 'RETURN_TOPIC' => sprintf($user->lang['RETURN_TOPIC'], '', ''), - 'RETURN_FORUM' => sprintf($user->lang['RETURN_FORUM'], '', ''), - - 'TOTAL_POSTS' => $user->lang('VIEW_TOPIC_POSTS', (int) $total), - )); -} - -/** -* Split topic -*/ -function split_topic($action, $topic_id, $to_forum_id, $subject) -{ - global $db, $template, $user, $phpEx, $phpbb_root_path, $auth, $config, $phpbb_log, $request, $phpbb_dispatcher; - - $post_id_list = $request->variable('post_id_list', array(0)); - $forum_id = $request->variable('forum_id', 0); - $start = $request->variable('start', 0); - - if (!count($post_id_list)) - { - $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']); - return; - } - - if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_split'))) - { - return; - } - - $post_id = $post_id_list[0]; - $post_info = phpbb_get_post_data(array($post_id)); - - if (!count($post_info)) - { - $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']); - return; - } - - $post_info = $post_info[$post_id]; - $subject = trim($subject); - - // Make some tests - if (!$subject) - { - $template->assign_var('MESSAGE', $user->lang['EMPTY_SUBJECT']); - return; - } - - if ($to_forum_id <= 0) - { - $template->assign_var('MESSAGE', $user->lang['NO_DESTINATION_FORUM']); - return; - } - - $forum_info = phpbb_get_forum_data(array($to_forum_id), 'f_post'); - - if (!count($forum_info)) - { - $template->assign_var('MESSAGE', $user->lang['USER_CANNOT_POST']); - return; - } - - $forum_info = $forum_info[$to_forum_id]; - - if ($forum_info['forum_type'] != FORUM_POST) - { - $template->assign_var('MESSAGE', $user->lang['FORUM_NOT_POSTABLE']); - return; - } - - $redirect = $request->variable('redirect', build_url(array('quickmod'))); - - $s_hidden_fields = build_hidden_fields(array( - 'i' => 'main', - 'post_id_list' => $post_id_list, - 'f' => $forum_id, - 'mode' => 'topic_view', - 'start' => $start, - 'action' => $action, - 't' => $topic_id, - 'redirect' => $redirect, - 'subject' => $subject, - 'to_forum_id' => $to_forum_id, - 'icon' => $request->variable('icon', 0)) - ); - - if (confirm_box(true)) - { - if ($action == 'split_beyond') - { - $sort_days = $total = 0; - $sort_key = $sort_dir = ''; - $sort_by_sql = $sort_order_sql = array(); - phpbb_mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); - - $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; - - if ($sort_order_sql[0] == 'u') - { - $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE p.topic_id = $topic_id - AND p.poster_id = u.user_id - $limit_time_sql - ORDER BY $sort_order_sql"; - } - else - { - $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility - FROM ' . POSTS_TABLE . " p - WHERE p.topic_id = $topic_id - $limit_time_sql - ORDER BY $sort_order_sql"; - } - $result = $db->sql_query_limit($sql, 0, $start); - - $store = false; - $post_id_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - // If split from selected post (split_beyond), we split the unapproved items too. - if (($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $row['forum_id'])) - { -// continue; - } - - // Start to store post_ids as soon as we see the first post that was selected - if ($row['post_id'] == $post_id) - { - $store = true; - } - - if ($store) - { - $post_id_list[] = $row['post_id']; - } - } - $db->sql_freeresult($result); - } - - if (!count($post_id_list)) - { - trigger_error('NO_POST_SELECTED'); - } - - $icon_id = $request->variable('icon', 0); - - $sql_ary = array( - 'forum_id' => $to_forum_id, - 'topic_title' => $subject, - 'icon_id' => $icon_id, - 'topic_visibility' => 1 - ); - - $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $to_topic_id = $db->sql_nextid(); - move_posts($post_id_list, $to_topic_id); - - $topic_info = phpbb_get_topic_data(array($topic_id)); - $topic_info = $topic_info[$topic_id]; - - $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 . " - SET post_subject = '" . $db->sql_escape($subject) . "' - WHERE post_id = {$post_id_list[0]}"; - $db->sql_query($sql); - - // Grab data for first post in split topic - $sql_array = array( - 'SELECT' => 'p.post_id, p.forum_id, p.poster_id, p.post_text, f.enable_indexing', - 'FROM' => array( - POSTS_TABLE => 'p', - ), - 'LEFT_JOIN' => array( - array( - 'FROM' => array(FORUMS_TABLE => 'f'), - 'ON' => 'p.forum_id = f.forum_id', - ) - ), - 'WHERE' => "post_id = {$post_id_list[0]}", - ); - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query($sql); - $first_post_data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Index first post as if it were edited - if ($first_post_data['enable_indexing']) - { - // Select the search method and do some additional checks to ensure it can actually be utilised - $search_type = $config['search_type']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if ($error) - { - trigger_error($error); - } - - $search->index('edit', $first_post_data['post_id'], $first_post_data['post_text'], $subject, $first_post_data['poster_id'], $first_post_data['forum_id']); - } - - // Copy topic subscriptions to new topic - $sql = 'SELECT user_id, notify_status - FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'topic_id' => (int) $to_topic_id, - 'user_id' => (int) $row['user_id'], - 'notify_status' => (int) $row['notify_status'], - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); - } - - // Copy bookmarks to new topic - $sql = 'SELECT user_id - FROM ' . BOOKMARKS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'topic_id' => (int) $to_topic_id, - 'user_id' => (int) $row['user_id'], - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); - } - - $success_msg = 'TOPIC_SPLIT_SUCCESS'; - - // Update forum statistics - $config->increment('num_topics', 1, false); - - // Link back to both topics - $return_link = sprintf($user->lang['RETURN_TOPIC'], '', '') . '

' . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); - $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&t=$to_topic_id"); - $redirect = reapply_sid($redirect); - - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . $return_link); - } - else - { - confirm_box(false, ($action == 'split_all') ? 'SPLIT_TOPIC_ALL' : 'SPLIT_TOPIC_BEYOND', $s_hidden_fields); - } -} - -/** -* Merge selected posts into selected topic -*/ -function merge_posts($topic_id, $to_topic_id) -{ - global $db, $template, $user, $phpEx, $phpbb_root_path, $phpbb_log, $request, $phpbb_dispatcher; - - if (!$to_topic_id) - { - $template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']); - return; - } - - $sync_topics = array($topic_id, $to_topic_id); - - $topic_data = phpbb_get_topic_data($sync_topics, 'm_merge'); - - if (!count($topic_data) || empty($topic_data[$to_topic_id])) - { - $template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']); - return; - } - - $sync_forums = array(); - foreach ($topic_data as $data) - { - $sync_forums[$data['forum_id']] = $data['forum_id']; - } - - $topic_data = $topic_data[$to_topic_id]; - - $post_id_list = $request->variable('post_id_list', array(0)); - $start = $request->variable('start', 0); - - if (!count($post_id_list)) - { - $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']); - return; - } - - if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_merge'))) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('quickmod'))); - - $s_hidden_fields = build_hidden_fields(array( - 'i' => 'main', - 'post_id_list' => $post_id_list, - 'to_topic_id' => $to_topic_id, - 'mode' => 'topic_view', - 'action' => 'merge_posts', - 'start' => $start, - 'redirect' => $redirect, - 't' => $topic_id) - ); - $return_link = ''; - - if (confirm_box(true)) - { - $to_forum_id = $topic_data['forum_id']; - - move_posts($post_id_list, $to_topic_id, false); - - $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'; - - // Does the original topic still exist? If yes, link back to it - $sql = 'SELECT forum_id - FROM ' . POSTS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $return_link .= sprintf($user->lang['RETURN_TOPIC'], '', ''); - } - else - { - if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) - { - include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx); - } - - // If the topic no longer exist, we will update the topic watch table. - phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', array($topic_id), $to_topic_id); - - // If the topic no longer exist, we will update the bookmarks table. - phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', array($topic_id), $to_topic_id); - } - - // Re-sync the topics and forums because the auto-sync was deactivated in the call of move_posts() - sync('topic_reported', 'topic_id', $sync_topics); - sync('topic_attachment', 'topic_id', $sync_topics); - sync('topic', 'topic_id', $sync_topics, true); - sync('forum', 'forum_id', $sync_forums, true, true); - - // Link to the new topic - $return_link .= (($return_link) ? '

' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); - $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&t=$to_topic_id"); - $redirect = reapply_sid($redirect); - - /** - * Perform additional actions after merging posts. - * - * @event core.mcp_topics_merge_posts_after - * @var int topic_id The topic ID from which posts are being moved - * @var int to_topic_id The topic ID to which posts are being moved - * @since 3.1.11-RC1 - */ - $vars = array( - 'topic_id', - 'to_topic_id', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_topics_merge_posts_after', compact($vars))); - - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . $return_link); - } - else - { - confirm_box(false, 'MERGE_POSTS', $s_hidden_fields); - } -} diff --git a/install/update/new/includes/mcp/mcp_warn.php b/install/update/new/includes/mcp/mcp_warn.php deleted file mode 100644 index 7a8599f..0000000 --- a/install/update/new/includes/mcp/mcp_warn.php +++ /dev/null @@ -1,610 +0,0 @@ - -* @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; -} - -/** -* mcp_warn -* Handling warning the users -*/ -class mcp_warn -{ - var $p_master; - var $u_action; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $request; - - $action = $request->variable('action', array('' => '')); - - if (is_array($action)) - { - $action = key($action); - } - - $this->page_title = 'MCP_WARN'; - - add_form_key('mcp_warn'); - - switch ($mode) - { - case 'front': - $this->mcp_warn_front_view(); - $this->tpl_name = 'mcp_warn_front'; - break; - - case 'list': - $this->mcp_warn_list_view($action); - $this->tpl_name = 'mcp_warn_list'; - break; - - case 'warn_post': - $this->mcp_warn_post_view($action); - $this->tpl_name = 'mcp_warn_post'; - break; - - case 'warn_user': - $this->mcp_warn_user_view($action); - $this->tpl_name = 'mcp_warn_user'; - break; - } - } - - /** - * Generates the summary on the main page of the warning module - */ - function mcp_warn_front_view() - { - 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&form=mcp&field=username&select_single=true'), - 'U_POST_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user'), - )); - - // Obtain a list of the 5 naughtiest users.... - // These are the 5 users with the highest warning count - $highest = array(); - $count = 0; - - view_warned_users($highest, $count, 5); - - foreach ($highest as $row) - { - $template->assign_block_vars('highest', array( - 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - - 'WARNING_TIME' => $user->format_date($row['user_last_warning']), - 'WARNINGS' => $row['user_warnings'], - )); - } - - // And now the 5 most recent users to get in trouble - $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_colour, u.user_warnings, w.warning_time - FROM ' . USERS_TABLE . ' u, ' . WARNINGS_TABLE . ' w - WHERE u.user_id = w.user_id - ORDER BY w.warning_time DESC'; - $result = $db->sql_query_limit($sql, 5); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('latest', array( - 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - - 'WARNING_TIME' => $user->format_date($row['warning_time']), - 'WARNINGS' => $row['user_warnings'], - )); - } - $db->sql_freeresult($result); - } - - /** - * Lists all users with warnings - */ - function mcp_warn_list_view($action) - { - global $phpEx, $phpbb_root_path, $config, $phpbb_container; - global $template, $user, $auth, $request; - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - $user->add_lang('memberlist'); - - $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']); - $sort_by_sql = array('a' => 'username_clean', 'b' => 'user_last_warning', 'c' => 'user_warnings'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $st, $sk, $sd, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - - // Define where and sort sql for use in displaying logs - $sql_where = ($st) ? (time() - ($st * 86400)) : 0; - $sql_sort = $sort_by_sql[$sk] . ' ' . (($sd == 'd') ? 'DESC' : 'ASC'); - - $users = array(); - $user_count = 0; - - view_warned_users($users, $user_count, $config['topics_per_page'], $start, $sql_where, $sql_sort); - - foreach ($users as $row) - { - $template->assign_block_vars('user', array( - 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - - 'WARNING_TIME' => $user->format_date($row['user_last_warning']), - 'WARNINGS' => $row['user_warnings'], - )); - } - - $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=warn&mode=list&st=$st&sk=$sk&sd=$sd"); - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $user_count, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'U_POST_ACTION' => $this->u_action, - 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - - 'TOTAL_USERS' => $user->lang('LIST_USERS', (int) $user_count), - )); - } - - /** - * Handles warning the user when the warning is for a specific post - */ - function mcp_warn_post_view($action) - { - global $phpEx, $phpbb_root_path, $config, $request; - global $template, $db, $user, $phpbb_dispatcher; - - $post_id = $request->variable('p', 0); - $forum_id = $request->variable('f', 0); - $notify = (isset($_REQUEST['notify_user'])) ? true : false; - $warning = $request->variable('warning', '', true); - - $sql = 'SELECT u.*, p.* - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE p.post_id = $post_id - AND u.user_id = p.poster_id"; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error('NO_POST'); - } - - // There is no point issuing a warning to ignored users (ie anonymous and bots) - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error('CANNOT_WARN_ANONYMOUS'); - } - - // Prevent someone from warning themselves - if ($user_row['user_id'] == $user->data['user_id']) - { - trigger_error('CANNOT_WARN_SELF'); - } - - // Check if there is already a warning for this post to prevent multiple - // warnings for the same offence - $sql = 'SELECT post_id - FROM ' . WARNINGS_TABLE . " - WHERE post_id = $post_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - trigger_error('ALREADY_WARNED'); - } - - $user_id = $user_row['user_id']; - - if (strpos($this->u_action, "&f=$forum_id&p=$post_id") === false) - { - $this->p_master->adjust_url("&f=$forum_id&p=$post_id"); - $this->u_action .= "&f=$forum_id&p=$post_id"; - } - - // Check if can send a notification - if ($config['allow_privmsg']) - { - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($user_row); - $s_can_notify = ($auth2->acl_get('u_readpm')) ? true : false; - unset($auth2); - } - else - { - $s_can_notify = false; - } - - // Prevent against clever people - if ($notify && !$s_can_notify) - { - $notify = false; - } - - if ($warning && $action == 'add_warning') - { - if (check_form_key('mcp_warn')) - { - $s_mcp_warn_post = true; - - /** - * Event for before warning a user for a post. - * - * @event core.mcp_warn_post_before - * @var array user_row The entire user row - * @var string warning The warning message - * @var bool notify If true, we notify the user for the warning - * @var int post_id The post id for which the warning is added - * @var bool s_mcp_warn_post If true, we add the warning else we omit it - * @since 3.1.0-b4 - */ - $vars = array( - 'user_row', - 'warning', - 'notify', - 'post_id', - 's_mcp_warn_post', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_warn_post_before', compact($vars))); - - if ($s_mcp_warn_post) - { - add_warning($user_row, $warning, $notify, $post_id); - $message = $user->lang['USER_WARNING_ADDED']; - - /** - * Event for after warning a user for a post. - * - * @event core.mcp_warn_post_after - * @var array user_row The entire user row - * @var string warning The warning message - * @var bool notify If true, the user was notified for the warning - * @var int post_id The post id for which the warning is added - * @var string message Message displayed to the moderator - * @since 3.1.0-b4 - */ - $vars = array( - 'user_row', - 'warning', - 'notify', - 'post_id', - 'message', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_warn_post_after', compact($vars))); - } - } - else - { - $message = $user->lang['FORM_INVALID']; - } - - if (!empty($message)) - { - $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=notes&mode=user_notes&u=$user_id"); - meta_refresh(2, $redirect); - trigger_error($message . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - } - - // OK, they didn't submit a warning so lets build the page for them to do so - - // We want to make the message available here as a reminder - // Parse the message and subject - $parse_flags = OPTION_FLAG_SMILIES | ($user_row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); - $message = generate_text_for_display($user_row['post_text'], $user_row['bbcode_uid'], $user_row['bbcode_bitfield'], $parse_flags, true); - - // Generate the appropriate user information for the user we are looking at - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $user_rank_data = phpbb_get_user_rank($user_row, $user_row['user_posts']); - $avatar_img = phpbb_get_user_avatar($user_row); - - $template->assign_vars(array( - 'U_POST_ACTION' => $this->u_action, - - 'POST' => $message, - 'USERNAME' => $user_row['username'], - 'USER_COLOR' => (!empty($user_row['user_colour'])) ? $user_row['user_colour'] : '', - 'RANK_TITLE' => $user_rank_data['title'], - 'JOINED' => $user->format_date($user_row['user_regdate']), - 'POSTS' => ($user_row['user_posts']) ? $user_row['user_posts'] : 0, - 'WARNINGS' => ($user_row['user_warnings']) ? $user_row['user_warnings'] : 0, - - 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $user_rank_data['img'], - - 'L_WARNING_POST_DEFAULT' => sprintf($user->lang['WARNING_POST_DEFAULT'], generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&p=$post_id#p$post_id"), - - 'S_CAN_NOTIFY' => $s_can_notify, - )); - } - - /** - * Handles warning the user - */ - function mcp_warn_user_view($action) - { - global $phpEx, $phpbb_root_path, $config, $request; - global $template, $db, $user, $phpbb_dispatcher; - - $user_id = $request->variable('u', 0); - $username = $request->variable('username', '', true); - $notify = (isset($_REQUEST['notify_user'])) ? true : false; - $warning = $request->variable('warning', '', true); - - $sql_where = ($user_id) ? "user_id = $user_id" : "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE ' . $sql_where; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error('NO_USER'); - } - - // Prevent someone from warning themselves - if ($user_row['user_id'] == $user->data['user_id']) - { - trigger_error('CANNOT_WARN_SELF'); - } - - $user_id = $user_row['user_id']; - - if (strpos($this->u_action, "&u=$user_id") === false) - { - $this->p_master->adjust_url('&u=' . $user_id); - $this->u_action .= "&u=$user_id"; - } - - // Check if can send a notification - if ($config['allow_privmsg']) - { - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($user_row); - $s_can_notify = ($auth2->acl_get('u_readpm')) ? true : false; - unset($auth2); - } - else - { - $s_can_notify = false; - } - - // Prevent against clever people - if ($notify && !$s_can_notify) - { - $notify = false; - } - - if ($warning && $action == 'add_warning') - { - if (check_form_key('mcp_warn')) - { - $s_mcp_warn_user = true; - - /** - * Event for before warning a user from MCP. - * - * @event core.mcp_warn_user_before - * @var array user_row The entire user row - * @var string warning The warning message - * @var bool notify If true, we notify the user for the warning - * @var bool s_mcp_warn_user If true, we add the warning else we omit it - * @since 3.1.0-b4 - */ - $vars = array( - 'user_row', - 'warning', - 'notify', - 's_mcp_warn_user', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_warn_user_before', compact($vars))); - - if ($s_mcp_warn_user) - { - add_warning($user_row, $warning, $notify); - $message = $user->lang['USER_WARNING_ADDED']; - - /** - * Event for after warning a user from MCP. - * - * @event core.mcp_warn_user_after - * @var array user_row The entire user row - * @var string warning The warning message - * @var bool notify If true, the user was notified for the warning - * @var string message Message displayed to the moderator - * @since 3.1.0-b4 - */ - $vars = array( - 'user_row', - 'warning', - 'notify', - 'message', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_warn_user_after', compact($vars))); - } - } - else - { - $message = $user->lang['FORM_INVALID']; - } - - if (!empty($message)) - { - $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=notes&mode=user_notes&u=$user_id"); - meta_refresh(2, $redirect); - trigger_error($message . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - } - - // Generate the appropriate user information for the user we are looking at - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - $user_rank_data = phpbb_get_user_rank($user_row, $user_row['user_posts']); - $avatar_img = phpbb_get_user_avatar($user_row); - - // OK, they didn't submit a warning so lets build the page for them to do so - $template->assign_vars(array( - 'U_POST_ACTION' => $this->u_action, - - 'RANK_TITLE' => $user_rank_data['title'], - 'JOINED' => $user->format_date($user_row['user_regdate']), - 'POSTS' => ($user_row['user_posts']) ? $user_row['user_posts'] : 0, - 'WARNINGS' => ($user_row['user_warnings']) ? $user_row['user_warnings'] : 0, - - 'USERNAME_FULL' => get_username_string('full', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), - 'USERNAME_COLOUR' => get_username_string('colour', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), - 'USERNAME' => get_username_string('username', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), - 'U_PROFILE' => get_username_string('profile', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), - - 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $user_rank_data['img'], - - 'S_CAN_NOTIFY' => $s_can_notify, - )); - - return $user_id; - } -} - -/** -* Insert the warning into the database -*/ -function add_warning($user_row, $warning, $send_pm = true, $post_id = 0) -{ - global $phpEx, $phpbb_root_path, $config, $phpbb_log; - global $db, $user; - - if ($send_pm) - { - include_once($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx); - - // Attempt to translate warning to language of user being warned if user's language differs from issuer's language - if ($user_row['user_lang'] != $user->lang_name) - { - $lang = array(); - - $user_row['user_lang'] = (file_exists($phpbb_root_path . 'language/' . basename($user_row['user_lang']) . "/mcp." . $phpEx)) ? $user_row['user_lang'] : $config['default_lang']; - include($phpbb_root_path . 'language/' . basename($user_row['user_lang']) . "/mcp." . $phpEx); - - $warn_pm_subject = $lang['WARNING_PM_SUBJECT']; - $warn_pm_body = sprintf($lang['WARNING_PM_BODY'], $warning); - - unset($lang); - } - else - { - $warn_pm_subject = $user->lang('WARNING_PM_SUBJECT'); - $warn_pm_body = $user->lang('WARNING_PM_BODY', $warning); - } - - $message_parser = new parse_message(); - - $message_parser->message = $warn_pm_body; - $message_parser->parse(true, true, true, false, false, true, true); - - $pm_data = array( - 'from_user_id' => $user->data['user_id'], - 'from_user_ip' => $user->ip, - 'from_username' => $user->data['username'], - 'enable_sig' => false, - 'enable_bbcode' => true, - 'enable_smilies' => true, - 'enable_urls' => false, - 'icon_id' => 0, - 'bbcode_bitfield' => $message_parser->bbcode_bitfield, - 'bbcode_uid' => $message_parser->bbcode_uid, - 'message' => $message_parser->message, - 'address_list' => array('u' => array($user_row['user_id'] => 'to')), - ); - - submit_pm('post', $warn_pm_subject, $pm_data, false); - } - - $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'], - 'post_id' => $post_id, - 'log_id' => $log_id, - 'warning_time' => time(), - ); - - $db->sql_query('INSERT INTO ' . WARNINGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_warnings = user_warnings + 1, - user_last_warning = ' . time() . ' - WHERE user_id = ' . $user_row['user_id']; - $db->sql_query($sql); - - // We add this to the mod log too for moderators to see that a specific user got warned. - $sql = 'SELECT forum_id, topic_id - FROM ' . POSTS_TABLE . ' - WHERE post_id = ' . $post_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $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/install/update/new/includes/message_parser.php b/install/update/new/includes/message_parser.php deleted file mode 100644 index d6214c4..0000000 --- a/install/update/new/includes/message_parser.php +++ /dev/null @@ -1,2087 +0,0 @@ - -* @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; -} - -if (!class_exists('bbcode')) -{ - // The following lines are for extensions which include message_parser.php - // while $phpbb_root_path and $phpEx are out of the script scope - // which may lead to the 'Undefined variable' and 'failed to open stream' errors - if (!isset($phpbb_root_path)) - { - global $phpbb_root_path; - } - - if (!isset($phpEx)) - { - global $phpEx; - } - - include($phpbb_root_path . 'includes/bbcode.' . $phpEx); -} - -/** -* BBCODE FIRSTPASS -* BBCODE first pass class (functions for parsing messages for db storage) -*/ -class bbcode_firstpass extends bbcode -{ - var $message = ''; - var $warn_msg = array(); - var $parsed_items = array(); - var $mode; - - /** - * Parse BBCode - */ - function parse_bbcode() - { - if (!$this->bbcodes) - { - $this->bbcode_init(); - } - - global $user; - - $this->bbcode_bitfield = ''; - $bitfield = new bitfield(); - - foreach ($this->bbcodes as $bbcode_name => $bbcode_data) - { - if (isset($bbcode_data['disabled']) && $bbcode_data['disabled']) - { - foreach ($bbcode_data['regexp'] as $regexp => $replacement) - { - if (preg_match($regexp, $this->message)) - { - $this->warn_msg[] = sprintf($user->lang['UNAUTHORISED_BBCODE'] , '[' . $bbcode_name . ']'); - continue; - } - } - } - else - { - foreach ($bbcode_data['regexp'] as $regexp => $replacement) - { - // The pattern gets compiled and cached by the PCRE extension, - // it should not demand recompilation - if (preg_match($regexp, $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']); - } - } - } - } - - $this->bbcode_bitfield = $bitfield->get_base64(); - } - - /** - * Prepare some bbcodes for better parsing - */ - function prepare_bbcodes() - { - // Ok, seems like users instead want the no-parsing of urls, smilies, etc. after and before and within quote tags being tagged as "not a bug". - // Fine by me ;) Will ease our live... but do not come back and cry at us, we won't hear you. - - /* Add newline at the end and in front of each quote block to prevent parsing errors (urls, smilies, etc.) - if (strpos($this->message, '[quote') !== false && strpos($this->message, '[/quote]') !== false) - { - $this->message = str_replace("\r\n", "\n", $this->message); - - // We strip newlines and spaces after and before quotes in quotes (trimming) and then add exactly one newline - $this->message = preg_replace('#\[quote(=".*?")?\]\s*(.*?)\s*\[/quote\]#siu', '[quote\1]' . "\n" . '\2' ."\n[/quote]", $this->message); - } - */ - - // Add other checks which needs to be placed before actually parsing anything (be it bbcodes, smilies, urls...) - } - - /** - * Init bbcode data for later parsing - */ - function bbcode_init($allow_custom_bbcode = true) - { - global $phpbb_dispatcher; - - 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. - // To parse multiline URL we enable dotall option setting only for URL text - // but not for link itself, thus [url][/url] is not affected. - // - // 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' => 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(?:="(.*?)")?\](.+)\[/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 - $this->parsed_items = array(); - - foreach ($this->bbcodes as $tag => $bbcode_data) - { - $this->parsed_items[$tag] = 0; - } - - if (!$allow_custom_bbcode) - { - return; - } - - if (!is_array($rowset)) - { - global $db; - $rowset = array(); - - $sql = 'SELECT * - FROM ' . BBCODES_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $rowset[] = $row; - } - $db->sql_freeresult($result); - } - - foreach ($rowset as $row) - { - $this->bbcodes[$row['bbcode_tag']] = array( - 'bbcode_id' => (int) $row['bbcode_id'], - 'regexp' => array($row['first_pass_match'] => str_replace('$uid', $this->bbcode_uid, $row['first_pass_replace'])) - ); - } - - $bbcodes = $this->bbcodes; - - /** - * Event to modify the bbcode data for later parsing - * - * @event core.modify_bbcode_init - * @var array bbcodes Array of bbcode data for use in parsing - * @var array rowset Array of bbcode data from the database - * @since 3.1.0-a3 - */ - $vars = array('bbcodes', 'rowset'); - extract($phpbb_dispatcher->trigger_event('core.modify_bbcode_init', compact($vars))); - - $this->bbcodes = $bbcodes; - } - - /** - * Making some pre-checks for bbcodes as well as increasing the number of parsed items - */ - function check_bbcode($bbcode, &$in) - { - // when using the /e modifier, preg_replace slashes double-quotes but does not - // seem to slash anything else - $in = str_replace("\r\n", "\n", str_replace('\"', '"', $in)); - - // Trimming here to make sure no empty bbcodes are parsed accidently - if (trim($in) == '') - { - return false; - } - - $this->parsed_items[$bbcode]++; - - return true; - } - - /** - * Transform some characters in valid bbcodes - */ - function bbcode_specialchars($text) - { - $str_from = array('<', '>', '[', ']', '.', ':'); - $str_to = array('<', '>', '[', ']', '.', ':'); - - return str_replace($str_from, $str_to, $text); - } - - /** - * Parse size tag - */ - function bbcode_size($stx, $in) - { - global $user, $config; - - if (!$this->check_bbcode('size', $in)) - { - return $in; - } - - if ($config['max_' . $this->mode . '_font_size'] && $config['max_' . $this->mode . '_font_size'] < $stx) - { - $this->warn_msg[] = $user->lang('MAX_FONT_SIZE_EXCEEDED', (int) $config['max_' . $this->mode . '_font_size']); - - return '[size=' . $stx . ']' . $in . '[/size]'; - } - - // Do not allow size=0 - if ($stx <= 0) - { - return '[size=' . $stx . ']' . $in . '[/size]'; - } - - return '[size=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/size:' . $this->bbcode_uid . ']'; - } - - /** - * Parse color tag - */ - function bbcode_color($stx, $in) - { - if (!$this->check_bbcode('color', $in)) - { - return $in; - } - - return '[color=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/color:' . $this->bbcode_uid . ']'; - } - - /** - * Parse u tag - */ - function bbcode_underline($in) - { - if (!$this->check_bbcode('u', $in)) - { - return $in; - } - - return '[u:' . $this->bbcode_uid . ']' . $in . '[/u:' . $this->bbcode_uid . ']'; - } - - /** - * Parse b tag - */ - function bbcode_strong($in) - { - if (!$this->check_bbcode('b', $in)) - { - return $in; - } - - return '[b:' . $this->bbcode_uid . ']' . $in . '[/b:' . $this->bbcode_uid . ']'; - } - - /** - * Parse i tag - */ - function bbcode_italic($in) - { - if (!$this->check_bbcode('i', $in)) - { - return $in; - } - - return '[i:' . $this->bbcode_uid . ']' . $in . '[/i:' . $this->bbcode_uid . ']'; - } - - /** - * Parse img tag - */ - function bbcode_img($in) - { - global $user, $config; - - if (!$this->check_bbcode('img', $in)) - { - return $in; - } - - $in = trim($in); - $error = false; - - $in = str_replace(' ', '%20', $in); - - // Checking urls - if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $in) && !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $in)) - { - return '[img]' . $in . '[/img]'; - } - - // Try to cope with a common user error... not specifying a protocol but only a subdomain - if (!preg_match('#^[a-z0-9]+://#i', $in)) - { - $in = 'http://' . $in; - } - - if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width']) - { - $imagesize = new \FastImageSize\FastImageSize(); - $size_info = $imagesize->getImageSize(htmlspecialchars_decode($in)); - - 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'] < $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'] < $size_info['width']) - { - $error = true; - $this->warn_msg[] = $user->lang('MAX_IMG_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']); - } - } - } - - if ($error || $this->path_in_domain($in)) - { - return '[img]' . $in . '[/img]'; - } - - return '[img:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/img:' . $this->bbcode_uid . ']'; - } - - /** - * Parse flash tag - */ - function bbcode_flash($width, $height, $in) - { - global $user, $config; - - if (!$this->check_bbcode('flash', $in)) - { - return $in; - } - - $in = trim($in); - $error = false; - - // Do not allow 0-sizes generally being entered - if ($width <= 0 || $height <= 0) - { - return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; - } - - $in = str_replace(' ', '%20', $in); - - // Make sure $in is a URL. - if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $in) && - !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $in)) - { - return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; - } - - // Apply the same size checks on flash files as on images - if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width']) - { - if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $height) - { - $error = true; - $this->warn_msg[] = $user->lang('MAX_FLASH_HEIGHT_EXCEEDED', (int) $config['max_' . $this->mode . '_img_height']); - } - - if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $width) - { - $error = true; - $this->warn_msg[] = $user->lang('MAX_FLASH_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']); - } - } - - if ($error || $this->path_in_domain($in)) - { - return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; - } - - return '[flash=' . $width . ',' . $height . ':' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/flash:' . $this->bbcode_uid . ']'; - } - - /** - * Parse inline attachments [ia] - */ - function bbcode_attachment($stx, $in) - { - if (!$this->check_bbcode('attachment', $in)) - { - return $in; - } - - return '[attachment=' . $stx . ':' . $this->bbcode_uid . ']' . trim($in) . '[/attachment:' . $this->bbcode_uid . ']'; - } - - /** - * Parse code text from code tag - * @access private - */ - function bbcode_parse_code($stx, &$code) - { - switch (strtolower($stx)) - { - case 'php': - - $remove_tags = false; - - $str_from = array('<', '>', '[', ']', '.', ':', ':'); - $str_to = array('<', '>', '[', ']', '.', ':', ':'); - $code = str_replace($str_from, $str_to, $code); - - if (!preg_match('/\<\?.*?\?\>/is', $code)) - { - $remove_tags = true; - $code = ""; - } - - $conf = array('highlight.bg', 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string'); - foreach ($conf as $ini_var) - { - @ini_set($ini_var, str_replace('highlight.', 'syntax', $ini_var)); - } - - // Because highlight_string is specialcharing the text (but we already did this before), we have to reverse this in order to get correct results - $code = htmlspecialchars_decode($code); - $code = highlight_string($code, true); - - $str_from = array('', '', '','[', ']', '.', ':'); - $str_to = array('', '', '', '[', ']', '.', ':'); - - if ($remove_tags) - { - $str_from[] = '<?php '; - $str_to[] = ''; - $str_from[] = '<?php '; - $str_to[] = ''; - } - - $code = str_replace($str_from, $str_to, $code); - $code = preg_replace('#^()\n?(.*?)\n?()$#is', '$1$2$3', $code); - - if ($remove_tags) - { - $code = preg_replace('#()?\?>()#', '$1 $2', $code); - } - - $code = preg_replace('#^(.*)#s', '$2', $code); - $code = preg_replace('#(?:\s++| )*+$#u', '', $code); - - // remove newline at the end - if (!empty($code) && substr($code, -1) == "\n") - { - $code = substr($code, 0, -1); - } - - return "[code=$stx:" . $this->bbcode_uid . ']' . $code . '[/code:' . $this->bbcode_uid . ']'; - break; - - default: - return '[code:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($code) . '[/code:' . $this->bbcode_uid . ']'; - break; - } - } - - /** - * Parse code tag - * Expects the argument to start right after the opening [code] tag and to end with [/code] - */ - function bbcode_code($stx, $in) - { - if (!$this->check_bbcode('code', $in)) - { - return $in; - } - - // We remove the hardcoded elements from the code block here because it is not used in code blocks - // Having it here saves us one preg_replace per message containing [code] blocks - // Additionally, magic url parsing should go after parsing bbcodes, but for safety those are stripped out too... - $htm_match = get_preg_expression('bbcode_htm'); - unset($htm_match[4], $htm_match[5]); - $htm_replace = array('\1', '\1', '\2', '\1'); - - $out = $code_block = ''; - $open = 1; - - while ($in) - { - // Determine position and tag length of next code block - preg_match('#(.*?)(\[code(?:=([a-z]+))?\])(.+)#is', $in, $buffer); - $pos = (isset($buffer[1])) ? strlen($buffer[1]) : false; - $tag_length = (isset($buffer[2])) ? strlen($buffer[2]) : false; - - // Determine position of ending code tag - $pos2 = stripos($in, '[/code]'); - - // Which is the next block, ending code or code block - if ($pos !== false && $pos < $pos2) - { - // Open new block - if (!$open) - { - $out .= substr($in, 0, $pos); - $in = substr($in, $pos); - $stx = (isset($buffer[3])) ? $buffer[3] : ''; - $code_block = ''; - } - else - { - // Already opened block, just append to the current block - $code_block .= substr($in, 0, $pos) . ((isset($buffer[2])) ? $buffer[2] : ''); - $in = substr($in, $pos); - } - - $in = substr($in, $tag_length); - $open++; - } - else - { - // Close the block - if ($open == 1) - { - $code_block .= substr($in, 0, $pos2); - $code_block = preg_replace($htm_match, $htm_replace, $code_block); - - // Parse this code block - $out .= $this->bbcode_parse_code($stx, $code_block); - $code_block = ''; - $open--; - } - else if ($open) - { - // Close one open tag... add to the current code block - $code_block .= substr($in, 0, $pos2 + 7); - $open--; - } - else - { - // end code without opening code... will be always outside code block - $out .= substr($in, 0, $pos2 + 7); - } - - $in = substr($in, $pos2 + 7); - } - } - - // if now $code_block has contents we need to parse the remaining code while removing the last closing tag to match up. - if ($code_block) - { - $code_block = substr($code_block, 0, -7); - $code_block = preg_replace($htm_match, $htm_replace, $code_block); - - $out .= $this->bbcode_parse_code($stx, $code_block); - } - - return $out; - } - - /** - * Parse list bbcode - * Expects the argument to start with a tag - */ - function bbcode_parse_list($in) - { - if (!$this->check_bbcode('list', $in)) - { - return $in; - } - - // $tok holds characters to stop at. Since the string starts with a '[' we'll get everything up to the first ']' which should be the opening [list] tag - $tok = ']'; - $out = '['; - - // First character is [ - $in = substr($in, 1); - $list_end_tags = $item_end_tags = array(); - - do - { - $pos = strlen($in); - - for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i) - { - $tmp_pos = strpos($in, $tok[$i]); - - if ($tmp_pos !== false && $tmp_pos < $pos) - { - $pos = $tmp_pos; - } - } - - $buffer = substr($in, 0, $pos); - $tok = $in[$pos]; - - $in = substr($in, $pos + 1); - - if ($tok == ']') - { - // if $tok is ']' the buffer holds a tag - if (strtolower($buffer) == '/list' && count($list_end_tags)) - { - // valid [/list] tag, check nesting so that we don't hit false positives - 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) . ']['; - } - - $out .= array_pop($list_end_tags) . ']'; - $tok = '['; - } - else if (preg_match('#^list(=[0-9a-z]+)?$#i', $buffer, $m)) - { - // sub-list, add a closing tag - if (empty($m[1]) || preg_match('/^=(?:disc|square|circle)$/i', $m[1])) - { - array_push($list_end_tags, '/list:u:' . $this->bbcode_uid); - } - else - { - array_push($list_end_tags, '/list:o:' . $this->bbcode_uid); - } - $out .= 'list' . substr($buffer, 4) . ':' . $this->bbcode_uid . ']'; - $tok = '['; - } - else - { - if (($buffer == '*' || substr($buffer, -2) == '[*') && count($list_end_tags)) - { - // the buffer holds a bullet tag and we have a [list] tag open - if (count($item_end_tags) >= count($list_end_tags)) - { - if (substr($buffer, -2) == '[*') - { - $out .= substr($buffer, 0, -2) . '['; - } - // current li tag has not been closed - if (preg_match('/\n\[$/', $out, $m)) - { - $out = preg_replace('/\n\[$/', '[', $out); - $buffer = array_pop($item_end_tags) . "]\n[*:" . $this->bbcode_uid; - } - else - { - $buffer = array_pop($item_end_tags) . '][*:' . $this->bbcode_uid; - } - } - else - { - $buffer = '*:' . $this->bbcode_uid; - } - - $item_end_tags[] = '/*:m:' . $this->bbcode_uid; - } - else if ($buffer == '/*') - { - array_pop($item_end_tags); - $buffer = '/*:' . $this->bbcode_uid; - } - - $out .= $buffer . $tok; - $tok = '[]'; - } - } - else - { - // Not within a tag, just add buffer to the return string - $out .= $buffer . $tok; - $tok = ($tok == '[') ? ']' : '[]'; - } - } - while ($in); - - // do we have some tags open? close them now - if (count($item_end_tags)) - { - $out .= '[' . implode('][', $item_end_tags) . ']'; - } - if (count($list_end_tags)) - { - $out .= '[' . implode('][', $list_end_tags) . ']'; - } - - return $out; - } - - /** - * Parse quote bbcode - * Expects the argument to start with a tag - */ - function bbcode_quote($in) - { - $in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in))); - - if (!$in) - { - return ''; - } - - // To let the parser not catch tokens within quote_username quotes we encode them before we start this... - $in = preg_replace_callback('#quote="(.*?)"\]#i', function ($match) { - return 'quote="' . str_replace(array('[', ']', '\\\"'), array('[', ']', '\"'), $match[1]) . '"]'; - }, $in); - - $tok = ']'; - $out = '['; - - $in = substr($in, 1); - $close_tags = $error_ary = array(); - $buffer = ''; - - do - { - $pos = strlen($in); - for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i) - { - $tmp_pos = strpos($in, $tok[$i]); - if ($tmp_pos !== false && $tmp_pos < $pos) - { - $pos = $tmp_pos; - } - } - - $buffer .= substr($in, 0, $pos); - $tok = $in[$pos]; - $in = substr($in, $pos + 1); - - if ($tok == ']') - { - if (strtolower($buffer) == '/quote' && count($close_tags) && substr($out, -1, 1) == '[') - { - // we have found a closing tag - $out .= array_pop($close_tags) . ']'; - $tok = '['; - $buffer = ''; - - /* Add space at the end of the closing tag if not happened before to allow following urls/smilies to be parsed correctly - * Do not try to think for the user. :/ Do not parse urls/smilies if there is no space - is the same as with other bbcodes too. - * Also, we won't have any spaces within $in anyway, only adding up spaces -> #10982 - if (!$in || $in[0] !== ' ') - { - $out .= ' '; - }*/ - } - else if (preg_match('#^quote(?:="(.*?)")?$#is', $buffer, $m) && substr($out, -1, 1) == '[') - { - $this->parsed_items['quote']++; - array_push($close_tags, '/quote:' . $this->bbcode_uid); - - if (isset($m[1]) && $m[1]) - { - $username = str_replace(array('[', ']'), array('[', ']'), $m[1]); - $username = preg_replace('#\[(?!b|i|u|color|url|email|/b|/i|/u|/color|/url|/email)#iU', '[$1', $username); - - $end_tags = array(); - $error = false; - - preg_match_all('#\[((?:/)?(?:[a-z]+))#i', $username, $tags); - foreach ($tags[1] as $tag) - { - if ($tag[0] != '/') - { - $end_tags[] = '/' . $tag; - } - else - { - $end_tag = array_pop($end_tags); - $error = ($end_tag != $tag) ? true : false; - } - } - - if ($error) - { - $username = $m[1]; - } - - $out .= 'quote="' . $username . '":' . $this->bbcode_uid . ']'; - } - else - { - $out .= 'quote:' . $this->bbcode_uid . ']'; - } - - $tok = '['; - $buffer = ''; - } - else if (preg_match('#^quote="(.*?)#is', $buffer, $m)) - { - // the buffer holds an invalid opening tag - $buffer .= ']'; - } - else - { - $out .= $buffer . $tok; - $tok = '[]'; - $buffer = ''; - } - } - else - { -/** -* Old quote code working fine, but having errors listed in bug #3572 -* -* $out .= $buffer . $tok; -* $tok = ($tok == '[') ? ']' : '[]'; -* $buffer = ''; -*/ - - $out .= $buffer . $tok; - - if ($tok == '[') - { - // Search the text for the next tok... if an ending quote comes first, then change tok to [] - $pos1 = stripos($in, '[/quote'); - // If the token ] comes first, we change it to ] - $pos2 = strpos($in, ']'); - // If the token [ comes first, we change it to [ - $pos3 = strpos($in, '['); - - if ($pos1 !== false && ($pos2 === false || $pos1 < $pos2) && ($pos3 === false || $pos1 < $pos3)) - { - $tok = '[]'; - } - else if ($pos3 !== false && ($pos2 === false || $pos3 < $pos2)) - { - $tok = '['; - } - else - { - $tok = ']'; - } - } - else - { - $tok = '[]'; - } - $buffer = ''; - } - } - while ($in); - - $out .= $buffer; - - if (count($close_tags)) - { - $out .= '[' . implode('][', $close_tags) . ']'; - } - - foreach ($error_ary as $error_msg) - { - $this->warn_msg[] = $error_msg; - } - - return $out; - } - - /** - * Validate email - */ - function validate_email($var1, $var2) - { - $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1))); - $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2))); - - $txt = $var2; - $email = ($var1) ? $var1 : $var2; - - $validated = true; - - if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email)) - { - $validated = false; - } - - if (!$validated) - { - return '[email' . (($var1) ? "=$var1" : '') . ']' . $var2 . '[/email]'; - } - - $this->parsed_items['email']++; - - if ($var1) - { - $retval = '[email=' . $this->bbcode_specialchars($email) . ':' . $this->bbcode_uid . ']' . $txt . '[/email:' . $this->bbcode_uid . ']'; - } - else - { - $retval = '[email:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($email) . '[/email:' . $this->bbcode_uid . ']'; - } - - return $retval; - } - - /** - * Validate url - * - * @param string $var1 optional url parameter for url bbcode: [url(=$var1)]$var2[/url] - * @param string $var2 url bbcode content: [url(=$var1)]$var2[/url] - */ - function validate_url($var1, $var2) - { - $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1))); - $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2))); - - $url = ($var1) ? $var1 : $var2; - - if ($var1 && !$var2) - { - $var2 = $var1; - } - - if (!$url) - { - return '[url' . (($var1) ? '=' . $var1 : '') . ']' . $var2 . '[/url]'; - } - - $valid = false; - - $url = str_replace(' ', '%20', $url); - - // Checking urls - if (preg_match('#^' . get_preg_expression('url') . '$#iu', $url) || - preg_match('#^' . get_preg_expression('www_url') . '$#iu', $url) || - preg_match('#^' . preg_quote(generate_board_url(), '#') . get_preg_expression('relative_url') . '$#iu', $url)) - { - $valid = true; - } - - if ($valid) - { - $this->parsed_items['url']++; - - // if there is no scheme, then add http schema - if (!preg_match('#^[a-z][a-z\d+\-.]*:/{2}#i', $url)) - { - $url = 'http://' . $url; - } - - // Is this a link to somewhere inside this board? If so then remove the session id from the url - if (strpos($url, generate_board_url()) !== false && strpos($url, 'sid=') !== false) - { - $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}&/', '\1', $url); - $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}$/', '', $url); - $url = append_sid($url); - } - - return ($var1) ? '[url=' . $this->bbcode_specialchars($url) . ':' . $this->bbcode_uid . ']' . $var2 . '[/url:' . $this->bbcode_uid . ']' : '[url:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($url) . '[/url:' . $this->bbcode_uid . ']'; - } - - return '[url' . (($var1) ? '=' . $var1 : '') . ']' . $var2 . '[/url]'; - } - - /** - * Check if url is pointing to this domain/script_path/php-file - * - * @param string $url the url to check - * @return true if the url is pointing to this domain/script_path/php-file, false if not - * - * @access private - */ - function path_in_domain($url) - { - global $config, $phpEx, $user; - - if ($config['force_server_vars']) - { - $check_path = !empty($config['script_path']) ? $config['script_path'] : '/'; - } - else - { - $check_path = ($user->page['root_script_path'] != '/') ? substr($user->page['root_script_path'], 0, -1) : '/'; - } - - // Is the user trying to link to a php file in this domain and script path? - if (strpos($url, ".{$phpEx}") !== false && strpos($url, $check_path) !== false) - { - $server_name = $user->host; - - // Forcing server vars is the only way to specify/override the protocol - if ($config['force_server_vars'] || !$server_name) - { - $server_name = $config['server_name']; - } - - // Check again in correct order... - $pos_ext = strpos($url, ".{$phpEx}"); - $pos_path = strpos($url, $check_path); - $pos_domain = strpos($url, $server_name); - - if ($pos_domain !== false && $pos_path >= $pos_domain && $pos_ext >= $pos_path) - { - // Ok, actually we allow linking to some files (this may be able to be extended in some way later...) - if (strpos($url, '/' . $check_path . '/download/file.' . $phpEx) !== 0) - { - return false; - } - - return true; - } - } - - return false; - } -} - -/** -* Main message parser for posting, pm, etc. takes raw message -* and parses it for attachments, bbcode and smilies -*/ -class parse_message extends bbcode_firstpass -{ - var $attachment_data = array(); - var $filename_data = array(); - - // Helps ironing out user error - var $message_status = ''; - - var $allow_img_bbcode = true; - var $allow_flash_bbcode = true; - var $allow_quote_bbcode = true; - var $allow_url_bbcode = true; - - /** - * The plupload object used for dealing with attachments - * @var \phpbb\plupload\plupload - */ - protected $plupload; - - /** - * Init - give message here or manually - */ - function __construct($message = '') - { - // Init BBCode UID - $this->bbcode_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN); - $this->message = $message; - } - - /** - * Parse Message - */ - 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, $user, $phpbb_dispatcher, $phpbb_container; - - $this->mode = $mode; - - foreach (array('chars', 'smilies', 'urls', 'font_size', 'img_height', 'img_width') as $key) - { - if (!isset($config['max_' . $mode . '_' . $key])) - { - $config['max_' . $mode . '_' . $key] = 0; - } - } - - $this->allow_img_bbcode = $allow_img_bbcode; - $this->allow_flash_bbcode = $allow_flash_bbcode; - $this->allow_quote_bbcode = $allow_quote_bbcode; - $this->allow_url_bbcode = $allow_url_bbcode; - - // If false, then $this->message won't be altered, the text will be returned instead. - if (!$update_this_message) - { - $tmp_message = $this->message; - $return_message = &$this->message; - } - - if ($this->message_status == 'display') - { - $this->decode_message(); - } - - // Store message length... - $message_length = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)); - - // Maximum message length check. 0 disables this check completely. - if ((int) $config['max_' . $mode . '_chars'] > 0 && $message_length > (int) $config['max_' . $mode . '_chars']) - { - $this->warn_msg[] = $user->lang('CHARS_' . strtoupper($mode) . '_CONTAINS', $message_length) . '
' . $user->lang('TOO_MANY_CHARS_LIMIT', (int) $config['max_' . $mode . '_chars']); - return (!$update_this_message) ? $return_message : $this->warn_msg; - } - - // Minimum message length check for post only - if ($mode === 'post') - { - if (!$message_length || $message_length < (int) $config['min_post_chars']) - { - $this->warn_msg[] = (!$message_length) ? $user->lang['TOO_FEW_CHARS'] : ($user->lang('CHARS_POST_CONTAINS', $message_length) . '
' . $user->lang('TOO_FEW_CHARS_LIMIT', (int) $config['min_post_chars'])); - return (!$update_this_message) ? $return_message : $this->warn_msg; - } - } - - /** - * This event can be used for additional message checks/cleanup before parsing - * - * @event core.message_parser_check_message - * @var bool allow_bbcode Do we allow BBCodes - * @var bool allow_magic_url Do we allow magic urls - * @var bool allow_smilies Do we allow smilies - * @var bool allow_img_bbcode Do we allow image BBCode - * @var bool allow_flash_bbcode Do we allow flash BBCode - * @var bool allow_quote_bbcode Do we allow quote BBCode - * @var bool allow_url_bbcode Do we allow url BBCode - * @var bool update_this_message Do we alter the parsed message - * @var string mode Posting mode - * @var string message The message text to parse - * @var string bbcode_bitfield The bbcode_bitfield before parsing - * @var string bbcode_uid The bbcode_uid before parsing - * @var bool return Do we return after the event is triggered if $warn_msg is not empty - * @var array warn_msg Array of the warning messages - * @since 3.1.2-RC1 - * @changed 3.1.3-RC1 Added vars $bbcode_bitfield and $bbcode_uid - */ - $message = $this->message; - $warn_msg = $this->warn_msg; - $return = false; - $bbcode_bitfield = $this->bbcode_bitfield; - $bbcode_uid = $this->bbcode_uid; - $vars = array( - 'allow_bbcode', - 'allow_magic_url', - 'allow_smilies', - 'allow_img_bbcode', - 'allow_flash_bbcode', - 'allow_quote_bbcode', - 'allow_url_bbcode', - 'update_this_message', - 'mode', - 'message', - 'bbcode_bitfield', - 'bbcode_uid', - 'return', - 'warn_msg', - ); - extract($phpbb_dispatcher->trigger_event('core.message_parser_check_message', compact($vars))); - $this->message = $message; - $this->warn_msg = $warn_msg; - $this->bbcode_bitfield = $bbcode_bitfield; - $this->bbcode_uid = $bbcode_uid; - if ($return && !empty($this->warn_msg)) - { - return (!$update_this_message) ? $return_message : $this->warn_msg; - } - - // Get the parser - $parser = $phpbb_container->get('text_formatter.parser'); - - // 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'); - - // 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 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) - { - $this->remove_nested_quotes($config['max_quote_depth']); - } - - // Check for "empty" message. We do not check here for maximum length, because bbcode, smilies, etc. can add to the length. - // The maximum length check happened before any parsings. - if ($mode === 'post' && utf8_clean_string($this->message) === '') - { - $this->warn_msg[] = $user->lang['TOO_FEW_CHARS']; - return (!$update_this_message) ? $return_message : $this->warn_msg; - } - - // 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) - { - 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; - } - - if (!$update_this_message) - { - unset($this->message); - $this->message = $tmp_message; - return $return_message; - } - - $this->message_status = 'parsed'; - return false; - } - - /** - * Formatting text for display - */ - function format_display($allow_bbcode, $allow_magic_url, $allow_smilies, $update_this_message = true) - { - global $phpbb_container, $phpbb_dispatcher; - - // If false, then the parsed message get returned but internal message not processed. - if (!$update_this_message) - { - $tmp_message = $this->message; - $return_message = &$this->message; - } - - $text = $this->message; - $uid = $this->bbcode_uid; - - /** - * Event to modify the text before it is parsed - * - * @event core.modify_format_display_text_before - * @var string text The message text to parse - * @var string uid The bbcode uid - * @var bool allow_bbcode Do we allow bbcodes - * @var bool allow_magic_url Do we allow magic urls - * @var bool allow_smilies Do we allow smilies - * @var bool update_this_message Do we update the internal message - * with the parsed result - * @since 3.1.6-RC1 - */ - $vars = array('text', 'uid', 'allow_bbcode', 'allow_magic_url', 'allow_smilies', 'update_this_message'); - extract($phpbb_dispatcher->trigger_event('core.modify_format_display_text_before', compact($vars))); - - $this->message = $text; - $this->bbcode_uid = $uid; - unset($text, $uid); - - // 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); - } - - // 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->message = $phpbb_container->get('text_formatter.parser')->parse($this->message); - } - - $this->message = $phpbb_container->get('text_formatter.renderer')->render($this->message); - - $text = $this->message; - $uid = $this->bbcode_uid; - - /** - * Event to modify the text after it is parsed - * - * @event core.modify_format_display_text_after - * @var string text The message text to parse - * @var string uid The bbcode uid - * @var bool allow_bbcode Do we allow bbcodes - * @var bool allow_magic_url Do we allow magic urls - * @var bool allow_smilies Do we allow smilies - * @var bool update_this_message Do we update the internal message - * with the parsed result - * @since 3.1.0-a3 - */ - $vars = array('text', 'uid', 'allow_bbcode', 'allow_magic_url', 'allow_smilies', 'update_this_message'); - extract($phpbb_dispatcher->trigger_event('core.modify_format_display_text_after', compact($vars))); - - $this->message = $text; - $this->bbcode_uid = $uid; - - if (!$update_this_message) - { - unset($this->message); - $this->message = $tmp_message; - return $return_message; - } - - $this->message_status = 'display'; - return false; - } - - /** - * Decode message to be placed back into form box - */ - function decode_message($custom_bbcode_uid = '', $update_this_message = true) - { - // If false, then the parsed message get returned but internal message not processed. - if (!$update_this_message) - { - $tmp_message = $this->message; - $return_message = &$this->message; - } - - ($custom_bbcode_uid) ? decode_message($this->message, $custom_bbcode_uid) : decode_message($this->message, $this->bbcode_uid); - - if (!$update_this_message) - { - unset($this->message); - $this->message = $tmp_message; - return $return_message; - } - - $this->message_status = 'plain'; - return false; - } - - /** - * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx. - * Cuts down displayed size of link if over 50 chars, turns absolute links - * into relative versions when the server/script path matches the link - */ - function magic_url($server_url) - { - // We use the global make_clickable function - $this->message = make_clickable($this->message, $server_url); - } - - /** - * Parse Smilies - */ - function smilies($max_smilies = 0) - { - global $db, $user; - static $match; - static $replace; - - // See if the static arrays have already been filled on an earlier invocation - if (!is_array($match)) - { - $match = $replace = array(); - - // NOTE: obtain_* function? chaching the table contents? - - // For now setting the ttl to 10 minutes - switch ($db->get_sql_layer()) - { - case 'mssql_odbc': - case 'mssqlnative': - $sql = 'SELECT * - FROM ' . SMILIES_TABLE . ' - ORDER BY LEN(code) DESC'; - break; - - // LENGTH supported by MySQL, IBM DB2, Oracle and Access for sure... - default: - $sql = 'SELECT * - FROM ' . SMILIES_TABLE . ' - ORDER BY LENGTH(code) DESC'; - break; - } - $result = $db->sql_query($sql, 600); - - while ($row = $db->sql_fetchrow($result)) - { - if (empty($row['code'])) - { - continue; - } - - // (assertion) - $match[] = preg_quote($row['code'], '#'); - $replace[] = '' . $row['code'] . ''; - } - $db->sql_freeresult($result); - } - - if (count($match)) - { - if ($max_smilies) - { - // 'u' modifier has been added to correctly parse smilies within unicode strings - // For details: http://tracker.phpbb.com/browse/PHPBB3-10117 - $num_matches = preg_match_all('#(?<=^|[\n .])(?:' . implode('|', $match) . ')(?![^<>]*>)#u', $this->message, $matches); - unset($matches); - - if ($num_matches !== false && $num_matches > $max_smilies) - { - $this->warn_msg[] = sprintf($user->lang['TOO_MANY_SMILIES'], $max_smilies); - return; - } - } - - // Make sure the delimiter # is added in front and at the end of every element within $match - // 'u' modifier has been added to correctly parse smilies within unicode strings - // For details: http://tracker.phpbb.com/browse/PHPBB3-10117 - - $this->message = trim(preg_replace(explode(chr(0), '#(?<=^|[\n .])' . implode('(?![^<>]*>)#u' . chr(0) . '#(?<=^|[\n .])', $match) . '(?![^<>]*>)#u'), $replace, $this->message)); - } - } - - /** - * 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 = 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'])); - - $add_file = (isset($_POST['add_file'])) ? true : false; - $delete_file = (isset($_POST['delete_file'])) ? true : false; - - // First of all adjust comments if changed - $actual_comment_list = $request->variable('comment_list', array(''), true); - - foreach ($actual_comment_list as $comment_key => $comment) - { - if (!isset($this->attachment_data[$comment_key])) - { - continue; - } - - if ($this->attachment_data[$comment_key]['attach_comment'] != $actual_comment_list[$comment_key]) - { - $this->attachment_data[$comment_key]['attach_comment'] = $actual_comment_list[$comment_key]; - } - } - - $cfg = array(); - $cfg['max_attachments'] = ($is_message) ? $config['max_attachments_pm'] : $config['max_attachments']; - $forum_id = ($is_message) ? 0 : $forum_id; - - if ($submit && in_array($mode, array('post', 'reply', 'quote', 'edit')) && $upload_file) - { - if ($num_attachments < $cfg['max_attachments'] || $auth->acl_get('a_') || $auth->acl_get('m_', $forum_id)) - { - /** @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'] && !count($error)) - { - $sql_ary = array( - 'physical_filename' => $filedata['physical_filename'], - 'attach_comment' => $this->filename_data['filecomment'], - 'real_filename' => $filedata['real_filename'], - 'extension' => $filedata['extension'], - 'mimetype' => $filedata['mimetype'], - 'filesize' => $filedata['filesize'], - 'filetime' => $filedata['filetime'], - 'thumbnail' => $filedata['thumbnail'], - 'is_orphan' => 1, - 'in_message' => ($is_message) ? 1 : 0, - '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( - 'attach_id' => $db->sql_nextid(), - 'is_orphan' => 1, - 'real_filename' => $filedata['real_filename'], - 'attach_comment'=> $this->filename_data['filecomment'], - 'filesize' => $filedata['filesize'], - ); - - $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); - - /** - * 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'] = ''; - - // This Variable is set to false here, because Attachments are entered into the - // Database in two modes, one if the id_list is 0 and the second one if post_attach is true - // Since post_attach is automatically switched to true if an Attachment got added to the filesystem, - // but we are assigning an id of 0 here, we have to reset the post_attach variable to false. - // - // This is very relevant, because it could happen that the post got not submitted, but we do not - // know this circumstance here. We could be at the posting page or we could be redirected to the entered - // post. :) - $filedata['post_attach'] = false; - } - } - else - { - $error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']); - } - } - - if ($preview || $refresh || count($error)) - { - if (isset($this->plupload) && $this->plupload->is_active()) - { - $json_response = new \phpbb\json_response(); - } - - // Perform actions on temporary attachments - if ($delete_file) - { - include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - - $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']) - { - $sql = 'SELECT attach_id, physical_filename, thumbnail - FROM ' . ATTACHMENTS_TABLE . ' - WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id'] . ' - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $attachment_manager->unlink($row['physical_filename'], 'file'); - - if ($row['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']); - } - } - else - { - $attachment_manager->delete('attach', $this->attachment_data[$index]['attach_id']); - } - - unset($this->attachment_data[$index]); - $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); - if (isset($this->plupload) && $this->plupload->is_active()) - { - $json_response->send($this->attachment_data); - } - } - } - else if (($add_file || $preview) && $upload_file) - { - if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id)) - { - /** @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 (!count($error)) - { - $sql_ary = array( - 'physical_filename' => $filedata['physical_filename'], - 'attach_comment' => $this->filename_data['filecomment'], - 'real_filename' => $filedata['real_filename'], - 'extension' => $filedata['extension'], - 'mimetype' => $filedata['mimetype'], - 'filesize' => $filedata['filesize'], - 'filetime' => $filedata['filetime'], - 'thumbnail' => $filedata['thumbnail'], - 'is_orphan' => 1, - 'in_message' => ($is_message) ? 1 : 0, - '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( - 'attach_id' => $db->sql_nextid(), - 'is_orphan' => 1, - 'real_filename' => $filedata['real_filename'], - 'attach_comment'=> $this->filename_data['filecomment'], - 'filesize' => $filedata['filesize'], - ); - - $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); - - /** - * 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()) - { - $download_url = append_sid("{$phpbb_root_path}download/file.{$phpEx}", 'mode=view&id=' . $new_entry['attach_id']); - - // Send the client the attachment data to maintain state - $json_response->send(array('data' => $this->attachment_data, 'download_url' => $download_url)); - } - } - } - else - { - $error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']); - } - - if (!empty($error) && isset($this->plupload) && $this->plupload->is_active()) - { - // If this is a plupload (and thus ajax) request, give the - // client the first error we have - $json_response->send(array( - 'jsonrpc' => '2.0', - 'id' => 'id', - 'error' => array( - 'code' => 105, - 'message' => current($error), - ), - )); - } - } - } - - foreach ($error as $error_msg) - { - $this->warn_msg[] = $error_msg; - } - } - - /** - * Get Attachment Data - */ - function get_submitted_attachment_data($check_user_id = false) - { - global $user, $db; - global $request; - - $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 (!count($attachment_data)) - { - return; - } - - $not_orphan = $orphan = array(); - - foreach ($attachment_data as $pos => $var_ary) - { - if ($var_ary['is_orphan']) - { - $orphan[(int) $var_ary['attach_id']] = $pos; - } - else - { - $not_orphan[(int) $var_ary['attach_id']] = $pos; - } - } - - // Regenerate already posted attachments - if (count($not_orphan)) - { - // Get the attachment data, based on the poster id... - $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($not_orphan)) . ' - AND poster_id = ' . $check_user_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $pos = $not_orphan[$row['attach_id']]; - $this->attachment_data[$pos] = $row; - $this->attachment_data[$pos]['attach_comment'] = $attachment_data[$pos]['attach_comment']; - - unset($not_orphan[$row['attach_id']]); - } - $db->sql_freeresult($result); - } - - if (count($not_orphan)) - { - trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR); - } - - // Regenerate newly uploaded attachments - if (count($orphan)) - { - $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan)) . ' - AND poster_id = ' . $user->data['user_id'] . ' - AND is_orphan = 1'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $pos = $orphan[$row['attach_id']]; - $this->attachment_data[$pos] = $row; - $this->attachment_data[$pos]['attach_comment'] = $attachment_data[$pos]['attach_comment']; - - unset($orphan[$row['attach_id']]); - } - $db->sql_freeresult($result); - } - - if (count($orphan)) - { - trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR); - } - - ksort($this->attachment_data); - } - - /** - * Parse Poll - */ - function parse_poll(&$poll) - { - global $user, $config; - - $poll_max_options = $poll['poll_max_options']; - - // Parse Poll Option text - $tmp_message = $this->message; - - $poll['poll_options'] = preg_split('/\s*?\n\s*/', trim($poll['poll_option_text'])); - $poll['poll_options_size'] = count($poll['poll_options']); - - 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 - $this->message = $poll['poll_title']; - if (!$poll['poll_title'] && $poll['poll_options_size']) - { - $this->warn_msg[] = $user->lang['NO_POLL_TITLE']; - } - else - { - if (utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)) > 100) - { - $this->warn_msg[] = $user->lang['POLL_TITLE_TOO_LONG']; - } - $poll['poll_title'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false, 'poll'); - if (strlen($poll['poll_title']) > 255) - { - $this->warn_msg[] = $user->lang['POLL_TITLE_COMP_TOO_LONG']; - } - } - - if (count($poll['poll_options']) == 1) - { - $this->warn_msg[] = $user->lang['TOO_FEW_POLL_OPTIONS']; - } - else if ($poll['poll_options_size'] > (int) $config['max_poll_options']) - { - $this->warn_msg[] = $user->lang['TOO_MANY_POLL_OPTIONS']; - } - else if ($poll_max_options > $poll['poll_options_size']) - { - $this->warn_msg[] = $user->lang['TOO_MANY_USER_OPTIONS']; - } - - $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; - } - - /** - * Remove nested quotes at given depth in current parsed message - * - * @param integer $max_depth Depth limit - * @return null - */ - 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(?:="(.*?)")?:' . $this->bbcode_uid . '\\])', $this->message, $matches, PREG_OFFSET_CAPTURE); - - // Iterate over the quote tags to mark the ranges that must be removed - $depth = 0; - $ranges = array(); - $start_pos = 0; - foreach ($matches[0] as $match) - { - if ($match[0][1] === '/') - { - --$depth; - if ($depth == $max_depth) - { - $end_pos = $match[1] + strlen($match[0]); - $length = $end_pos - $start_pos; - $ranges[] = array($start_pos, $length); - } - } - else - { - ++$depth; - if ($depth == $max_depth + 1) - { - $start_pos = $match[1]; - } - } - } - - foreach (array_reverse($ranges) as $range) - { - list($start_pos, $length) = $range; - $this->message = substr_replace($this->message, '', $start_pos, $length); - } - } - - /** - * Setter function for passing the plupload object - * - * @param \phpbb\plupload\plupload $plupload The plupload object - * - * @return null - */ - public function set_plupload(\phpbb\plupload\plupload $plupload) - { - $this->plupload = $plupload; - } - - /** - * 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')") - * - * Accepts variable number of parameters - * - * @return mixed Validation result - */ - public function validate_bbcode_by_extension() - { - global $phpbb_dispatcher; - - $return = false; - $params_array = func_get_args(); - - /** - * Event to validate bbcode with the custom validating methods - * provided by extensions - * - * @event core.validate_bbcode_by_extension - * @var array params_array Array with the function parameters - * @var mixed return Validation result to return - * - * @since 3.1.5-RC1 - */ - $vars = array('params_array', 'return'); - extract($phpbb_dispatcher->trigger_event('core.validate_bbcode_by_extension', compact($vars))); - - return $return; - } -} diff --git a/install/update/new/includes/questionnaire/questionnaire.php b/install/update/new/includes/questionnaire/questionnaire.php deleted file mode 100644 index ec2e6fe..0000000 --- a/install/update/new/includes/questionnaire/questionnaire.php +++ /dev/null @@ -1,497 +0,0 @@ - -* @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; -} - -/** -* This class collects data which is used to create some usage statistics. -* -* The collected data is - after authorization of the administrator - submitted -* to a central server. For privacy reasons we try to collect only data which aren't private -* or don't give any information which might help to identify the user. -* -* @author Johannes Schlueter -* @copyright (c) 2007-2008 Johannes Schlueter -*/ -class phpbb_questionnaire_data_collector -{ - var $providers; - var $data = null; - var $install_id = ''; - - /** - * Constructor. - * - * @param string - */ - function __construct($install_id) - { - $this->install_id = $install_id; - $this->providers = array(); - } - - function add_data_provider($provider) - { - $this->providers[] = $provider; - } - - /** - * Get data as an array. - * - * @return array All Data - */ - function get_data_raw() - { - if (!$this->data) - { - $this->collect(); - } - - return $this->data; - } - - function get_data_for_form() - { - return base64_encode(json_encode($this->get_data_raw())); - } - - /** - * Collect info into the data property. - * - * @return null - */ - function collect() - { - foreach (array_keys($this->providers) as $key) - { - $provider = $this->providers[$key]; - $this->data[$provider->get_identifier()] = $provider->get_data(); - } - $this->data['install_id'] = $this->install_id; - } -} - -/** interface: get_indentifier(), get_data() */ - -/** -* Questionnaire PHP data provider -*/ -class phpbb_questionnaire_php_data_provider -{ - function get_identifier() - { - return 'PHP'; - } - - /** - * Get data about the PHP runtime setup. - * - * @return array - */ - function get_data() - { - return array( - 'version' => PHP_VERSION, - 'sapi' => PHP_SAPI, - 'int_size' => defined('PHP_INT_SIZE') ? PHP_INT_SIZE : '', - 'open_basedir' => (int) @ini_get('open_basedir'), - 'memory_limit' => @ini_get('memory_limit'), - 'allow_url_fopen' => (int) @ini_get('allow_url_fopen'), - 'allow_url_include' => (int) @ini_get('allow_url_include'), - 'file_uploads' => (int) @ini_get('file_uploads'), - 'upload_max_filesize' => @ini_get('upload_max_filesize'), - 'post_max_size' => @ini_get('post_max_size'), - 'disable_functions' => @ini_get('disable_functions'), - 'disable_classes' => @ini_get('disable_classes'), - 'enable_dl' => (int) @ini_get('enable_dl'), - 'filter.default' => @ini_get('filter.default'), - 'zend.ze1_compatibility_mode' => (int) @ini_get('zend.ze1_compatibility_mode'), - 'unicode.semantics' => (int) @ini_get('unicode.semantics'), - 'zend_thread_safty' => (int) function_exists('zend_thread_id'), - 'extensions' => implode(',', get_loaded_extensions()), - ); - } -} - -/** -* Questionnaire System data provider -*/ -class phpbb_questionnaire_system_data_provider -{ - function get_identifier() - { - return 'System'; - } - - /** - * Get data about the general system information, like OS or IP (shortened). - * - * @return array - */ - function get_data() - { - global $request; - - // Start discovering the IPV4 server address, if available - // Try apache, IIS, fall back to 0.0.0.0 - $server_address = htmlspecialchars_decode($request->server('SERVER_ADDR', $request->server('LOCAL_ADDR', '0.0.0.0'))); - - return array( - 'os' => PHP_OS, - 'httpd' => htmlspecialchars_decode($request->server('SERVER_SOFTWARE')), - // we don't want the real IP address (for privacy policy reasons) but only - // a network address to see whether your installation is running on a private or public network. - 'private_ip' => $this->is_private_ip($server_address), - 'ipv6' => strpos($server_address, ':') !== false, - ); - } - - /** - * Checks whether the given IP is in a private network. - * - * @param string $ip IP in v4 dot-decimal or v6 hex format - * @return bool true if the IP is from a private network, else false - */ - function is_private_ip($ip) - { - // IPv4 - if (strpos($ip, ':') === false) - { - $ip_address_ary = explode('.', $ip); - - // build ip - if (!isset($ip_address_ary[0]) || !isset($ip_address_ary[1])) - { - $ip_address_ary = explode('.', '0.0.0.0'); - } - - // IANA reserved addresses for private networks (RFC 1918) are: - // - 10.0.0.0/8 - // - 172.16.0.0/12 - // - 192.168.0.0/16 - 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')) - { - return true; - } - } - // IPv6 - else - { - // unique local unicast - $prefix = substr($ip, 0, 2); - if ($prefix == 'fc' || $prefix == 'fd') - { - return true; - } - } - - return false; - } -} - -/** -* Questionnaire phpBB data provider -*/ -class phpbb_questionnaire_phpbb_data_provider -{ - var $config; - var $unique_id; - - /** - * Constructor. - * - * @param array $config - */ - function __construct($config) - { - // generate a unique id if necessary - if (empty($config['questionnaire_unique_id'])) - { - $this->unique_id = unique_id(); - $config->set('questionnaire_unique_id', $this->unique_id); - } - else - { - $this->unique_id = $config['questionnaire_unique_id']; - } - - $this->config = $config; - } - - /** - * Returns a string identifier for this data provider - * - * @return string "phpBB" - */ - function get_identifier() - { - return 'phpBB'; - } - - /** - * Get data about this phpBB installation. - * - * @return array Relevant anonymous config options - */ - function get_data() - { - global $phpbb_config_php_file; - - extract($phpbb_config_php_file->get_all()); - unset($dbhost, $dbport, $dbname, $dbuser, $dbpasswd); // Just a precaution - - $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms); - - // Only send certain config vars - $config_vars = array( - 'active_sessions' => true, - 'allow_attachments' => true, - 'allow_autologin' => true, - 'allow_avatar' => true, - 'allow_avatar_local' => true, - 'allow_avatar_remote' => true, - 'allow_avatar_upload' => true, - 'allow_bbcode' => true, - 'allow_birthdays' => true, - 'allow_bookmarks' => true, - 'allow_emailreuse' => true, - 'allow_forum_notify' => true, - 'allow_mass_pm' => true, - 'allow_name_chars' => true, - 'allow_namechange' => true, - 'allow_nocensors' => true, - 'allow_pm_attach' => true, - 'allow_pm_report' => true, - 'allow_post_flash' => true, - 'allow_post_links' => true, - 'allow_privmsg' => true, - 'allow_quick_reply' => true, - 'allow_sig' => true, - 'allow_sig_bbcode' => true, - 'allow_sig_flash' => true, - 'allow_sig_img' => true, - 'allow_sig_links' => true, - 'allow_sig_pm' => true, - 'allow_sig_smilies' => true, - 'allow_smilies' => true, - 'allow_topic_notify' => true, - 'attachment_quota' => true, - 'auth_bbcode_pm' => true, - 'auth_flash_pm' => true, - 'auth_img_pm' => true, - 'auth_method' => true, - 'auth_smilies_pm' => true, - 'avatar_filesize' => true, - 'avatar_max_height' => true, - 'avatar_max_width' => true, - 'avatar_min_height' => true, - 'avatar_min_width' => true, - 'board_email_form' => true, - 'board_hide_emails' => true, - 'board_timezone' => true, - 'browser_check' => true, - 'bump_interval' => true, - 'bump_type' => true, - 'cache_gc' => true, - 'captcha_plugin' => true, - 'captcha_gd' => true, - 'captcha_gd_foreground_noise' => true, - 'captcha_gd_x_grid' => true, - 'captcha_gd_y_grid' => true, - 'captcha_gd_wave' => true, - 'captcha_gd_3d_noise' => true, - 'captcha_gd_fonts' => true, - 'confirm_refresh' => true, - 'check_attachment_content' => true, - 'check_dnsbl' => true, - 'chg_passforce' => true, - 'cookie_secure' => true, - 'coppa_enable' => true, - 'database_gc' => true, - 'dbms_version' => true, - 'default_dateformat' => true, - 'default_lang' => true, - 'display_last_edited' => true, - 'display_order' => true, - 'edit_time' => true, - 'email_check_mx' => true, - 'email_enable' => true, - 'email_force_sender' => true, - 'email_package_size' => true, - 'enable_confirm' => true, - 'enable_pm_icons' => true, - 'enable_post_confirm' => true, - 'feed_enable' => true, - 'feed_http_auth' => true, - 'feed_limit_post' => true, - 'feed_limit_topic' => true, - 'feed_overall' => true, - 'feed_overall_forums' => true, - 'feed_forum' => true, - 'feed_topic' => true, - 'feed_topics_new' => true, - 'feed_topics_active' => true, - 'feed_item_statistics' => true, - 'flood_interval' => true, - 'force_server_vars' => true, - 'form_token_lifetime' => true, - 'form_token_mintime' => true, - 'form_token_sid_guests' => true, - 'forward_pm' => true, - 'forwarded_for_check' => true, - 'full_folder_action' => true, - 'fulltext_native_common_thres' => true, - 'fulltext_native_load_upd' => true, - 'fulltext_native_max_chars' => true, - 'fulltext_native_min_chars' => true, - 'gzip_compress' => true, - 'hot_threshold' => true, - 'img_create_thumbnail' => true, - 'img_display_inlined' => true, - 'img_link_height' => true, - 'img_link_width' => true, - 'img_max_height' => true, - 'img_max_thumb_width' => true, - 'img_max_width' => true, - 'img_min_thumb_filesize' => true, - 'ip_check' => true, - 'jab_enable' => true, - 'jab_package_size' => true, - 'jab_use_ssl' => true, - 'limit_load' => true, - 'limit_search_load' => true, - 'load_anon_lastread' => true, - 'load_birthdays' => true, - 'load_cpf_memberlist' => true, - 'load_cpf_viewprofile' => true, - 'load_cpf_viewtopic' => true, - 'load_db_lastread' => true, - 'load_db_track' => true, - 'load_jumpbox' => true, - 'load_moderators' => true, - 'load_online' => true, - 'load_online_guests' => true, - 'load_online_time' => true, - 'load_onlinetrack' => true, - 'load_search' => true, - 'load_tplcompile' => true, - 'load_user_activity' => true, - 'max_attachments' => true, - 'max_attachments_pm' => true, - 'max_autologin_time' => true, - 'max_filesize' => true, - 'max_filesize_pm' => true, - 'max_login_attempts' => true, - 'max_name_chars' => true, - 'max_num_search_keywords' => true, - 'max_poll_options' => true, - 'max_post_chars' => true, - 'max_post_font_size' => true, - 'max_post_img_height' => true, - 'max_post_img_width' => true, - 'max_post_smilies' => true, - 'max_post_urls' => true, - 'max_quote_depth' => true, - 'max_reg_attempts' => true, - 'max_sig_chars' => true, - 'max_sig_font_size' => true, - 'max_sig_img_height' => true, - 'max_sig_img_width' => true, - 'max_sig_smilies' => true, - 'max_sig_urls' => true, - 'min_name_chars' => true, - 'min_pass_chars' => true, - 'min_post_chars' => true, - 'min_search_author_chars' => true, - 'mime_triggers' => true, - 'new_member_post_limit' => true, - 'new_member_group_default' => true, - 'override_user_style' => true, - 'pass_complex' => true, - 'pm_edit_time' => true, - 'pm_max_boxes' => true, - 'pm_max_msgs' => true, - 'pm_max_recipients' => true, - 'posts_per_page' => true, - 'print_pm' => true, - 'queue_interval' => true, - 'require_activation' => true, - 'referer_validation' => true, - 'search_block_size' => true, - 'search_gc' => true, - 'search_interval' => true, - 'search_anonymous_interval' => true, - 'search_type' => true, - 'search_store_results' => true, - 'secure_allow_deny' => true, - 'secure_allow_empty_referer' => true, - 'secure_downloads' => true, - 'session_gc' => true, - 'session_length' => true, - 'smtp_auth_method' => true, - 'smtp_delivery' => true, - 'topics_per_page' => true, - 'tpl_allow_php' => true, - 'version' => true, - 'warnings_expire_days' => true, - 'warnings_gc' => true, - - 'num_files' => true, - 'num_posts' => true, - 'num_topics' => true, - 'num_users' => true, - 'record_online_users' => true, - ); - - $result = array(); - foreach ($config_vars as $name => $void) - { - if (isset($this->config[$name])) - { - $result['config_' . $name] = $this->config[$name]; - } - } - - global $db, $request; - - $result['dbms'] = $dbms; - $result['acm_type'] = $acm_type; - $result['user_agent'] = 'Unknown'; - $result['dbms_version'] = $db->sql_server_info(true); - - // Try to get user agent vendor and version - $match = array(); - $user_agent = $request->header('User-Agent'); - $agents = array('firefox', 'msie', 'opera', 'chrome', 'safari', 'mozilla', 'seamonkey', 'konqueror', 'netscape', 'gecko', 'navigator', 'mosaic', 'lynx', 'amaya', 'omniweb', 'avant', 'camino', 'flock', 'aol'); - - // We check here 1 by 1 because some strings occur after others (for example Mozilla [...] Firefox/) - foreach ($agents as $agent) - { - if (preg_match('#(' . $agent . ')[/ ]?([0-9.]*)#i', $user_agent, $match)) - { - $result['user_agent'] = $match[1] . ' ' . $match[2]; - break; - } - } - - return $result; - } -} diff --git a/install/update/new/includes/startup.php b/install/update/new/includes/startup.php deleted file mode 100644 index 5ead3b7..0000000 --- a/install/update/new/includes/startup.php +++ /dev/null @@ -1,86 +0,0 @@ - -* @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; -} - -// Report all errors, except notices and deprecation messages -$level = E_ALL & ~E_NOTICE & ~E_DEPRECATED; -error_reporting($level); - -/** -* Minimum Requirement: PHP 7.1.3 -*/ -if (version_compare(PHP_VERSION, '7.1.3', '<')) -{ - die('You are running an unsupported PHP version. Please upgrade to PHP 7.1.3 or higher before trying to install or update to phpBB 3.3'); -} -// Register globals and magic quotes have been dropped in PHP 5.4 so no need for extra checks - - -// 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. - -// 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()); - -// Autoloading of dependencies. -// Three options are supported: -// 1. If dependencies are installed with Composer, Composer will create a -// vendor/autoload.php. If this file exists it will be -// automatically used by phpBB. This is the default mode that phpBB -// will use when shipped. -// 2. To disable composer autoloading, PHPBB_NO_COMPOSER_AUTOLOAD can be specified. -// Additionally specify PHPBB_AUTOLOAD=/path/to/autoload.php in the -// environment. This is useful for running CLI scripts and tests. -// /path/to/autoload.php should define and register class loaders -// for all of phpBB's dependencies. -// 3. You can also set PHPBB_NO_COMPOSER_AUTOLOAD without setting PHPBB_AUTOLOAD. -// In this case autoloading needs to be defined before running any phpBB -// script. This might be useful in cases when phpBB is integrated into a -// larger program. -if (getenv('PHPBB_NO_COMPOSER_AUTOLOAD')) -{ - if (getenv('PHPBB_AUTOLOAD')) - { - require(getenv('PHPBB_AUTOLOAD')); - } -} -else -{ - if (!file_exists($phpbb_root_path . 'vendor/autoload.php')) - { - trigger_error( - 'Composer dependencies have not been set up yet, run ' . - "'php ../composer.phar install' from the phpBB directory to do so.", - E_USER_ERROR - ); - } - require($phpbb_root_path . 'vendor/autoload.php'); -} - -$starttime = microtime(true); diff --git a/install/update/new/includes/ucp/ucp_attachments.php b/install/update/new/includes/ucp/ucp_attachments.php deleted file mode 100644 index 7808fed..0000000 --- a/install/update/new/includes/ucp/ucp_attachments.php +++ /dev/null @@ -1,219 +0,0 @@ - -* @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; -} - -/** -* ucp_attachments -* User attachments -*/ -class ucp_attachments -{ - var $u_action; - - function main($id, $mode) - { - global $template, $user, $db, $config, $phpEx, $phpbb_root_path, $phpbb_container, $request, $auth; - - $start = $request->variable('start', 0); - $sort_key = $request->variable('sk', 'a'); - $sort_dir = $request->variable('sd', 'a'); - - $delete = (isset($_POST['delete'])) ? true : false; - $delete_ids = array_keys($request->variable('attachment', array(0))); - - if ($delete && count($delete_ids)) - { - // Validate $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 && count($delete_ids)) - { - $s_hidden_fields = array( - 'delete' => 1 - ); - - foreach ($delete_ids as $attachment_id) - { - $s_hidden_fields['attachment'][$attachment_id] = 1; - } - - if (confirm_box(true)) - { - /** @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 = ((count($delete_ids) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED']) . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - else - { - confirm_box(false, (count($delete_ids) == 1) ? 'DELETE_ATTACHMENT' : 'DELETE_ATTACHMENTS', build_hidden_fields($s_hidden_fields)); - } - } - - // Select box eventually - $sort_key_text = array('a' => $user->lang['SORT_FILENAME'], 'b' => $user->lang['SORT_COMMENT'], 'c' => $user->lang['SORT_EXTENSION'], 'd' => $user->lang['SORT_SIZE'], 'e' => $user->lang['SORT_DOWNLOADS'], 'f' => $user->lang['SORT_POST_TIME'], 'g' => $user->lang['SORT_TOPIC_TITLE']); - $sort_key_sql = array('a' => 'a.real_filename', 'b' => 'a.attach_comment', 'c' => 'a.extension', 'd' => 'a.filesize', 'e' => 'a.download_count', 'f' => 'a.filetime', 'g' => 't.topic_title'); - - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - $s_sort_key = ''; - foreach ($sort_key_text as $key => $value) - { - $selected = ($sort_key == $key) ? ' selected="selected"' : ''; - $s_sort_key .= ''; - } - - $s_sort_dir = ''; - foreach ($sort_dir_text as $key => $value) - { - $selected = ($sort_dir == $key) ? ' selected="selected"' : ''; - $s_sort_dir .= ''; - } - - if (!isset($sort_key_sql[$sort_key])) - { - $sort_key = 'a'; - } - - $order_by = $sort_key_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); - - $sql = 'SELECT COUNT(attach_id) as num_attachments - FROM ' . ATTACHMENTS_TABLE . ' - WHERE poster_id = ' . $user->data['user_id'] . ' - AND is_orphan = 0'; - $result = $db->sql_query($sql); - $num_attachments = $db->sql_fetchfield('num_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, 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 ' . 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"; - $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); - - $row_count = 0; - if ($row = $db->sql_fetchrow($result)) - { - $template->assign_var('S_ATTACHMENT_ROWS', true); - - do - { - if ($row['in_message']) - { - $view_topic = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&p={$row['post_msg_id']}"); - } - else - { - $view_topic = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}") . "#p{$row['post_msg_id']}"; - } - - $template->assign_block_vars('attachrow', array( - 'ROW_NUMBER' => $row_count + ($start + 1), - 'FILENAME' => $row['real_filename'], - 'COMMENT' => bbcode_nl2br($row['attach_comment']), - 'EXTENSION' => $row['extension'], - 'SIZE' => get_formatted_filesize($row['filesize']), - 'DOWNLOAD_COUNT' => $row['download_count'], - 'POST_TIME' => $user->format_date($row['filetime']), - 'TOPIC_TITLE' => ($row['in_message']) ? $row['message_title'] : $row['topic_title'], - - 'ATTACH_ID' => $row['attach_id'], - 'POST_ID' => $row['post_msg_id'], - '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) - ); - - $row_count++; - } - while ($row = $db->sql_fetchrow($result)); - } - $db->sql_freeresult($result); - - $base_url = $this->u_action . "&sk=$sort_key&sd=$sort_dir"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_attachments, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'TOTAL_ATTACHMENTS' => $num_attachments, - 'NUM_ATTACHMENTS' => $user->lang('NUM_ATTACHMENTS', $num_attachments), - - 'L_TITLE' => $user->lang['UCP_ATTACHMENTS'], - - 'U_SORT_FILENAME' => $this->u_action . "&sk=a&sd=" . (($sort_key == 'a' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_FILE_COMMENT' => $this->u_action . "&sk=b&sd=" . (($sort_key == 'b' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_EXTENSION' => $this->u_action . "&sk=c&sd=" . (($sort_key == 'c' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_FILESIZE' => $this->u_action . "&sk=d&sd=" . (($sort_key == 'd' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_DOWNLOADS' => $this->u_action . "&sk=e&sd=" . (($sort_key == 'e' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_POST_TIME' => $this->u_action . "&sk=f&sd=" . (($sort_key == 'f' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_TOPIC_TITLE' => $this->u_action . "&sk=g&sd=" . (($sort_key == 'g' && $sort_dir == 'a') ? 'd' : 'a'), - - 'S_DISPLAY_MARK_ALL' => ($num_attachments) ? true : false, - 'S_DISPLAY_PAGINATION' => ($num_attachments) ? true : false, - 'S_UCP_ACTION' => $this->u_action, - 'S_SORT_OPTIONS' => $s_sort_key, - 'S_ORDER_SELECT' => $s_sort_dir) - ); - - $this->tpl_name = 'ucp_attachments'; - $this->page_title = 'UCP_ATTACHMENTS'; - } -} diff --git a/install/update/new/includes/ucp/ucp_groups.php b/install/update/new/includes/ucp/ucp_groups.php deleted file mode 100644 index 6eba3a0..0000000 --- a/install/update/new/includes/ucp/ucp_groups.php +++ /dev/null @@ -1,1142 +0,0 @@ - -* @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; -} - -/** -* ucp_groups -*/ -class ucp_groups -{ - var $u_action; - - function main($id, $mode) - { - global $config, $phpbb_root_path, $phpEx, $phpbb_admin_path; - global $db, $user, $auth, $cache, $template; - global $request, $phpbb_container, $phpbb_log; - - /** @var \phpbb\language\language $language Language object */ - $language = $phpbb_container->get('language'); - - $user->add_lang('groups'); - - $return_page = '

' . sprintf($user->lang['RETURN_PAGE'], '', ''); - - $mark_ary = $request->variable('mark', array(0)); - $submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST); - - /** @var \phpbb\group\helper $group_helper */ - $group_helper = $phpbb_container->get('group_helper'); - - switch ($mode) - { - case 'membership': - - $this->page_title = 'UCP_USERGROUPS_MEMBER'; - - if ($submit || isset($_POST['change_default'])) - { - $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) - { - trigger_error('NO_GROUP_SELECTED'); - } - - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE . " - WHERE group_id IN ($group_id, {$user->data['group_id']})"; - $result = $db->sql_query($sql); - - $group_row = array(); - while ($row = $db->sql_fetchrow($result)) - { - $row['group_name'] = $group_helper->get_name($row['group_name']); - $group_row[$row['group_id']] = $row; - } - $db->sql_freeresult($result); - - if (!count($group_row)) - { - trigger_error('GROUP_NOT_EXIST'); - } - - switch ($action) - { - case 'change_default': - // User already having this group set as default? - if ($group_id == $user->data['group_id']) - { - trigger_error($user->lang['ALREADY_DEFAULT_GROUP'] . $return_page); - } - - if (!$auth->acl_get('u_chggrp')) - { - send_status_line(403, 'Forbidden'); - trigger_error($user->lang['NOT_AUTHORISED'] . $return_page); - } - - // User needs to be member of the group in order to make it default - if (!group_memberships($group_id, $user->data['user_id'], true)) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - - if (confirm_box(true)) - { - group_user_attributes('default', $group_id, $user->data['user_id']); - - $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); - } - else - { - $s_hidden_fields = array( - 'default' => $group_id, - 'change_default'=> true - ); - - confirm_box(false, sprintf($user->lang['GROUP_CHANGE_DEFAULT'], $group_row[$group_id]['group_name']), build_hidden_fields($s_hidden_fields)); - } - - break; - - case 'resign': - - // User tries to resign from default group but is not allowed to change it? - if ($group_id == $user->data['group_id'] && !$auth->acl_get('u_chggrp')) - { - trigger_error($user->lang['NOT_RESIGN_FROM_DEFAULT_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - $row = current($row); - - $sql = 'SELECT group_type - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . $group_id; - $result = $db->sql_query($sql); - $group_type = (int) $db->sql_fetchfield('group_type'); - $db->sql_freeresult($result); - - if ($group_type != GROUP_OPEN && $group_type != GROUP_FREE) - { - trigger_error($user->lang['CANNOT_RESIGN_GROUP'] . $return_page); - } - - if (confirm_box(true)) - { - group_user_del($group_id, $user->data['user_id']); - - $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); - } - else - { - $s_hidden_fields = array( - 'selected' => $group_id, - 'action' => 'resign', - 'submit' => true - ); - - confirm_box(false, ($row['user_pending']) ? 'GROUP_RESIGN_PENDING' : 'GROUP_RESIGN_MEMBERSHIP', build_hidden_fields($s_hidden_fields)); - } - - break; - - case 'join': - - $sql = 'SELECT ug.*, u.username, u.username_clean, u.user_email - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u - WHERE ug.user_id = u.user_id - AND ug.group_id = ' . $group_id . ' - AND ug.user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - if ($row['user_pending']) - { - trigger_error($user->lang['ALREADY_IN_GROUP_PENDING'] . $return_page); - } - - trigger_error($user->lang['ALREADY_IN_GROUP'] . $return_page); - } - - // Check permission to join (open group or request) - if ($group_row[$group_id]['group_type'] != GROUP_OPEN && $group_row[$group_id]['group_type'] != GROUP_FREE) - { - trigger_error($user->lang['CANNOT_JOIN_GROUP'] . $return_page); - } - - if (confirm_box(true)) - { - if ($group_row[$group_id]['group_type'] == GROUP_FREE) - { - group_user_add($group_id, $user->data['user_id']); - } - else - { - group_user_add($group_id, $user->data['user_id'], false, false, false, 0, 1); - } - - $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); - } - else - { - $s_hidden_fields = array( - 'selected' => $group_id, - 'action' => 'join', - 'submit' => true - ); - - confirm_box(false, ($group_row[$group_id]['group_type'] == GROUP_FREE) ? 'GROUP_JOIN' : 'GROUP_JOIN_PENDING', build_hidden_fields($s_hidden_fields)); - } - - break; - - case 'demote': - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - $row = current($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - if (confirm_box(true)) - { - group_user_attributes('demote', $group_id, $user->data['user_id']); - - $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); - } - else - { - $s_hidden_fields = array( - 'selected' => $group_id, - 'action' => 'demote', - 'submit' => true - ); - - confirm_box(false, 'USER_GROUP_DEMOTE', build_hidden_fields($s_hidden_fields)); - } - - break; - } - } - - $sql = 'SELECT g.*, ug.group_leader, ug.user_pending - FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug - WHERE ug.user_id = ' . $user->data['user_id'] . ' - AND g.group_id = ug.group_id - ORDER BY g.group_type DESC, g.group_name'; - $result = $db->sql_query($sql); - - $group_id_ary = array(); - $leader_count = $member_count = $pending_count = 0; - while ($row = $db->sql_fetchrow($result)) - { - $block = ($row['group_leader']) ? 'leader' : (($row['user_pending']) ? 'pending' : 'member'); - - switch ($row['group_type']) - { - case GROUP_OPEN: - $group_status = 'OPEN'; - break; - - case GROUP_CLOSED: - $group_status = 'CLOSED'; - break; - - case GROUP_HIDDEN: - $group_status = 'HIDDEN'; - break; - - case GROUP_SPECIAL: - $group_status = 'SPECIAL'; - break; - - case GROUP_FREE: - $group_status = 'FREE'; - break; - } - - $template->assign_block_vars($block, array( - 'GROUP_ID' => $row['group_id'], - '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], - 'GROUP_COLOUR' => $row['group_colour'], - - 'U_VIEW_GROUP' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $row['group_id']), - - 'S_GROUP_DEFAULT' => ($row['group_id'] == $user->data['group_id']) ? true : false, - 'S_ROW_COUNT' => ${$block . '_count'}++) - ); - - $group_id_ary[] = (int) $row['group_id']; - } - $db->sql_freeresult($result); - - // Hide hidden groups unless user is an admin with group privileges - $sql_and = ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? '<> ' . GROUP_SPECIAL : 'NOT IN (' . GROUP_SPECIAL . ', ' . GROUP_HIDDEN . ')'; - - $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 ' . ((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); - - $nonmember_count = 0; - while ($row = $db->sql_fetchrow($result)) - { - switch ($row['group_type']) - { - case GROUP_OPEN: - $group_status = 'OPEN'; - break; - - case GROUP_CLOSED: - $group_status = 'CLOSED'; - break; - - case GROUP_HIDDEN: - $group_status = 'HIDDEN'; - break; - - case GROUP_SPECIAL: - $group_status = 'SPECIAL'; - break; - - case GROUP_FREE: - $group_status = 'FREE'; - break; - } - - $template->assign_block_vars('nonmember', array( - 'GROUP_ID' => $row['group_id'], - '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, - 'GROUP_STATUS' => $user->lang['GROUP_IS_' . $group_status], - 'S_CAN_JOIN' => ($row['group_type'] == GROUP_OPEN || $row['group_type'] == GROUP_FREE) ? true : false, - 'GROUP_COLOUR' => $row['group_colour'], - - 'U_VIEW_GROUP' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $row['group_id']), - - 'S_ROW_COUNT' => $nonmember_count++) - ); - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_CHANGE_DEFAULT' => ($auth->acl_get('u_chggrp')) ? true : false, - 'S_LEADER_COUNT' => $leader_count, - 'S_MEMBER_COUNT' => $member_count, - 'S_PENDING_COUNT' => $pending_count, - 'S_NONMEMBER_COUNT' => $nonmember_count, - - 'S_UCP_ACTION' => $this->u_action) - ); - - break; - - case 'manage': - - $this->page_title = 'UCP_USERGROUPS_MANAGE'; - $action = (isset($_POST['addusers'])) ? 'addusers' : $request->variable('action', ''); - $group_id = $request->variable('g', 0); - - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - add_form_key('ucp_groups'); - - if ($group_id) - { - $sql = 'SELECT g.*, t.teampage_position AS group_teampage - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . TEAMPAGE_TABLE . ' t - ON (t.group_id = g.group_id) - WHERE g.group_id = ' . $group_id; - $result = $db->sql_query($sql); - $group_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$group_row) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - // Check if the user is allowed to manage this group if set to founder only. - if ($user->data['user_type'] != USER_FOUNDER && $group_row['group_founder_manage']) - { - trigger_error($user->lang['NOT_ALLOWED_MANAGE_GROUP'] . $return_page, E_USER_WARNING); - } - - $group_name = $group_row['group_name']; - $group_type = $group_row['group_type']; - - $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true); - - $template->assign_vars(array( - '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']), - 'GROUP_TYPE' => $group_row['group_type'], - - 'AVATAR' => (empty($avatar) ? '' : $avatar), - 'AVATAR_IMAGE' => (empty($avatar) ? '' : $avatar), - 'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '', - 'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '', - )); - } - - switch ($action) - { - case 'edit': - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - $row = current($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $user->add_lang(array('acp/groups', 'acp/common')); - - $update = (isset($_POST['update'])) ? true : false; - - $error = array(); - - // Setup avatar data for later - $avatars_enabled = false; - $avatar_drivers = null; - $avatar_data = null; - $avatar_error = array(); - - /** @var \phpbb\avatar\manager $phpbb_avatar_manager */ - $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); - - if ($config['allow_avatar']) - { - $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers(); - - // This is normalised data, without the group_ prefix - $avatar_data = \phpbb\avatar\manager::clean_row($group_row, 'group'); - } - - // Handle deletion of avatars - if ($request->is_set_post('avatar_delete')) - { - if (confirm_box(true)) - { - $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, GROUPS_TABLE, 'group_'); - $cache->destroy('sql', GROUPS_TABLE); - - $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; - trigger_error($user->lang[$message] . $return_page); - } - else - { - confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( - 'avatar_delete' => true, - 'i' => $id, - 'mode' => $mode, - 'g' => $group_id, - 'action' => $action)) - ); - } - } - - // Did we submit? - if ($update) - { - $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->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->variable('group_colour', ''), - 'rank' => $request->variable('group_rank', 0), - 'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 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 (!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', '')); - - if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) - { - $driver = $phpbb_avatar_manager->get_driver($driver_name); - $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error); - - if ($result && empty($avatar_error)) - { - $result['avatar_type'] = $driver_name; - - $submit_ary = array_merge($submit_ary, $result); - } - } - - // Merge any avatars errors into the primary error array - $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); - } - - // Validate submitted colour value - if ($colour_error = validate_data($submit_ary, array('colour' => array('hex_colour', true)))) - { - // Replace "error" string with its real, localised form - $error = array_merge($error, $colour_error); - } - - if (!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 - // were made. - // However there are some attributes that need to be set everytime, - // otherwise the group gets removed from the feature. - $set_attributes = array('legend', 'teampage'); - - $group_attributes = array(); - $test_variables = array( - 'rank' => 'int', - 'colour' => 'string', - 'avatar' => 'string', - 'avatar_type' => 'string', - 'avatar_width' => 'int', - 'avatar_height' => 'int', - 'receive_pm' => 'int', - 'legend' => 'int', - 'teampage' => 'int', - 'message_limit' => 'int', - 'max_recipients'=> 'int', - ); - - foreach ($test_variables as $test => $type) - { - if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test] || isset($group_attributes['group_avatar']) && strpos($test, 'avatar') === 0 || in_array($test, $set_attributes))) - { - settype($submit_ary[$test], $type); - $group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test]; - } - } - - if (!($error = group_create($group_id, $group_type, $group_name, $group_desc, $group_attributes, $allow_desc_bbcode, $allow_desc_urls, $allow_desc_smilies))) - { - $cache->destroy('sql', GROUPS_TABLE); - $cache->destroy('sql', TEAMPAGE_TABLE); - - $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; - trigger_error($user->lang[$message] . $return_page); - } - } - - if (count($error)) - { - $error = array_map(array(&$user, 'lang'), $error); - $group_rank = $submit_ary['rank']; - - $group_desc_data = array( - 'text' => $group_desc, - 'allow_bbcode' => $allow_desc_bbcode, - 'allow_smilies' => $allow_desc_smilies, - 'allow_urls' => $allow_desc_urls - ); - } - } - else if (!$group_id) - { - $group_desc_data = array( - 'text' => '', - 'allow_bbcode' => true, - 'allow_smilies' => true, - 'allow_urls' => true - ); - $group_rank = 0; - $group_type = GROUP_OPEN; - } - else - { - $group_desc_data = generate_text_for_edit($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_options']); - $group_rank = $group_row['group_rank']; - } - - $sql = 'SELECT * - FROM ' . RANKS_TABLE . ' - WHERE rank_special = 1 - ORDER BY rank_title'; - $result = $db->sql_query($sql); - - $rank_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($group_rank && $row['rank_id'] == $group_rank) ? ' selected="selected"' : ''; - $rank_options .= ''; - } - $db->sql_freeresult($result); - - $type_free = ($group_type == GROUP_FREE) ? ' checked="checked"' : ''; - $type_open = ($group_type == GROUP_OPEN) ? ' checked="checked"' : ''; - $type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : ''; - $type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : ''; - - // Load up stuff for avatars - if ($config['allow_avatar']) - { - $avatars_enabled = false; - $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type'])); - - // Assign min and max values before generating avatar driver html - $template->assign_vars(array( - 'AVATAR_MIN_WIDTH' => $config['avatar_min_width'], - 'AVATAR_MAX_WIDTH' => $config['avatar_max_width'], - 'AVATAR_MIN_HEIGHT' => $config['avatar_min_height'], - 'AVATAR_MAX_HEIGHT' => $config['avatar_max_height'], - )); - - foreach ($avatar_drivers as $current_driver) - { - $driver = $phpbb_avatar_manager->get_driver($current_driver); - - $avatars_enabled = true; - $template->set_filenames(array( - 'avatar' => $driver->get_template_name(), - )); - - if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error)) - { - $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); - $driver_upper = strtoupper($driver_name); - $template->assign_block_vars('avatar_drivers', array( - 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), - 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), - - 'DRIVER' => $driver_name, - 'SELECTED' => $current_driver == $selected_driver, - 'OUTPUT' => $template->assign_display('avatar'), - )); - } - } - } - - if (isset($phpbb_avatar_manager) && !$update) - { - // Merge any avatars errors into the primary error array - $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); - } - - $template->assign_vars(array( - 'S_EDIT' => true, - 'S_INCLUDE_SWATCH' => true, - 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', - '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' => (count($error)) ? implode('
', $error) : '', - 'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '', - 'GROUP_MESSAGE_LIMIT' => (isset($group_row['group_message_limit'])) ? $group_row['group_message_limit'] : 0, - 'GROUP_MAX_RECIPIENTS' => (isset($group_row['group_max_recipients'])) ? $group_row['group_max_recipients'] : 0, - - 'GROUP_DESC' => $group_desc_data['text'], - 'S_DESC_BBCODE_CHECKED' => $group_desc_data['allow_bbcode'], - 'S_DESC_URLS_CHECKED' => $group_desc_data['allow_urls'], - 'S_DESC_SMILIES_CHECKED'=> $group_desc_data['allow_smilies'], - - 'S_RANK_OPTIONS' => $rank_options, - - 'GROUP_TYPE_FREE' => GROUP_FREE, - 'GROUP_TYPE_OPEN' => GROUP_OPEN, - 'GROUP_TYPE_CLOSED' => GROUP_CLOSED, - 'GROUP_TYPE_HIDDEN' => GROUP_HIDDEN, - 'GROUP_TYPE_SPECIAL' => GROUP_SPECIAL, - - 'GROUP_FREE' => $type_free, - 'GROUP_OPEN' => $type_open, - 'GROUP_CLOSED' => $type_closed, - 'GROUP_HIDDEN' => $type_hidden, - - 'S_UCP_ACTION' => $this->u_action . "&action=$action&g=$group_id", - 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(), - )); - - break; - - case 'list': - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - $row = current($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $user->add_lang(array('acp/groups', 'acp/common')); - $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 - FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . " ug - WHERE ug.group_id = $group_id - AND u.user_id = ug.user_id - AND ug.group_leader = 1 - ORDER BY ug.user_pending DESC, u.username_clean"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('leader', array( - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => $row['user_colour'], - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'U_USER_VIEW' => get_username_string('profile', $row['user_id'], $row['username']), - 'S_GROUP_DEFAULT' => ($row['group_id'] == $group_id) ? true : false, - 'JOINED' => ($row['user_regdate']) ? $user->format_date($row['user_regdate']) : ' - ', - 'USER_POSTS' => $row['user_posts'], - 'USER_ID' => $row['user_id']) - ); - } - $db->sql_freeresult($result); - - // Total number of group members (non-leaders) - $sql = 'SELECT COUNT(user_id) AS total_members - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - AND group_leader = 0"; - $result = $db->sql_query($sql); - $total_members = (int) $db->sql_fetchfield('total_members'); - $db->sql_freeresult($result); - - // Grab the members - $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_colour, u.user_regdate, u.user_posts, u.group_id, ug.group_leader, ug.user_pending - FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . " ug - WHERE ug.group_id = $group_id - AND u.user_id = ug.user_id - AND ug.group_leader = 0 - ORDER BY ug.user_pending DESC, u.username_clean"; - $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); - - $pending = false; - $approved = false; - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['user_pending'] && !$pending) - { - $template->assign_block_vars('member', array( - 'S_PENDING' => true) - ); - $template->assign_var('S_PENDING_SET', true); - - $pending = true; - } - else if (!$row['user_pending'] && !$approved) - { - $template->assign_block_vars('member', array( - 'S_APPROVED' => true) - ); - $template->assign_var('S_APPROVED_SET', true); - - $approved = true; - } - - $template->assign_block_vars('member', array( - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => $row['user_colour'], - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'U_USER_VIEW' => get_username_string('profile', $row['user_id'], $row['username']), - 'S_GROUP_DEFAULT' => ($row['group_id'] == $group_id) ? true : false, - 'JOINED' => ($row['user_regdate']) ? $user->format_date($row['user_regdate']) : ' - ', - 'USER_POSTS' => $row['user_posts'], - 'USER_ID' => $row['user_id']) - ); - } - $db->sql_freeresult($result); - - $s_action_options = ''; - $options = array('default' => 'DEFAULT', 'approve' => 'APPROVE', 'deleteusers' => 'DELETE'); - - foreach ($options as $option => $lang) - { - $s_action_options .= ''; - } - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - $base_url = $this->u_action . "&action=$action&g=$group_id"; - $start = $pagination->validate_start($start, $config['topics_per_page'], $total_members); - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_members, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'S_LIST' => true, - 'S_ACTION_OPTIONS' => $s_action_options, - - 'U_ACTION' => $this->u_action . "&g=$group_id", - 'S_UCP_ACTION' => $this->u_action . "&g=$group_id", - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=usernames'), - )); - - break; - - case 'approve': - - if (!$group_id) - { - 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); - } - $row = current($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $user->add_lang('acp/groups'); - - // Approve, demote or promote - group_user_attributes('approve', $group_id, $mark_ary, false, false); - - trigger_error($user->lang['USERS_APPROVED'] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - - break; - - case 'default': - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - $row = current($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $group_row['group_name'] = $group_helper->get_name($group_row['group_name']); - - if (confirm_box(true)) - { - if (!count($mark_ary)) - { - $start = 0; - - do - { - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - ORDER BY user_id"; - $result = $db->sql_query_limit($sql, 200, $start); - - $mark_ary = array(); - if ($row = $db->sql_fetchrow($result)) - { - do - { - $mark_ary[] = $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); - - group_user_attributes('default', $group_id, $mark_ary, false, $group_row['group_name'], $group_row); - - $start = (count($mark_ary) < 200) ? 0 : $start + 200; - } - else - { - $start = 0; - } - $db->sql_freeresult($result); - } - while ($start); - } - else - { - group_user_attributes('default', $group_id, $mark_ary, false, $group_row['group_name'], $group_row); - } - - $user->add_lang('acp/groups'); - - trigger_error($user->lang['GROUP_DEFS_UPDATED'] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - else - { - $user->add_lang('acp/common'); - - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'mark' => $mark_ary, - 'g' => $group_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action)) - ); - } - - // redirect to last screen - redirect($this->u_action . '&action=list&g=' . $group_id); - - break; - - case 'deleteusers': - - $user->add_lang(array('acp/groups', 'acp/common')); - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - $row = current($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $group_row['group_name'] = $group_helper->get_name($group_row['group_name']); - - if (confirm_box(true)) - { - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - $error = group_user_del($group_id, $mark_ary, false, $group_row['group_name']); - - if ($error) - { - trigger_error($user->lang[$error] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - - trigger_error($user->lang['GROUP_USERS_REMOVE'] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'mark' => $mark_ary, - 'g' => $group_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action)) - ); - } - - // redirect to last screen - redirect($this->u_action . '&action=list&g=' . $group_id); - - break; - - case 'addusers': - - $user->add_lang(array('acp/groups', 'acp/common')); - - $names = $request->variable('usernames', '', true); - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!$names) - { - trigger_error($user->lang['NO_USERS'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - $row = current($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $name_ary = array_unique(explode("\n", $names)); - $group_name = $group_helper->get_name($group_row['group_name']); - - $default = $request->variable('default', 0); - - if (confirm_box(true)) - { - $return_manage_page = '

' . $language->lang('RETURN_PAGE', '', ''); - - // Add user/s to group - if ($error = group_user_add($group_id, false, $name_ary, $group_name, $default, 0, 0, $group_row)) - { - $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($language->lang('GROUP_USERS_ADDED') . $return_manage_page); - } - else - { - $s_hidden_fields = array( - 'default' => $default, - 'usernames' => $names, - 'g' => $group_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action - ); - - 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'] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - - break; - - default: - $user->add_lang('acp/common'); - - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_desc, g.group_desc_uid, g.group_desc_bitfield, g.group_desc_options, g.group_type, ug.group_leader - FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug - WHERE ug.user_id = ' . $user->data['user_id'] . ' - AND g.group_id = ug.group_id - AND ug.group_leader = 1 - ORDER BY g.group_type DESC, g.group_name'; - $result = $db->sql_query($sql); - - while ($value = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('leader', array( - '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'], - 'GROUP_COLOUR' => $value['group_colour'], - - 'U_LIST' => $this->u_action . "&action=list&g={$value['group_id']}", - 'U_EDIT' => $this->u_action . "&action=edit&g={$value['group_id']}") - ); - } - $db->sql_freeresult($result); - - break; - } - - break; - } - - $this->tpl_name = 'ucp_groups_' . $mode; - } -} diff --git a/install/update/new/includes/ucp/ucp_pm.php b/install/update/new/includes/ucp/ucp_pm.php deleted file mode 100644 index 00d1ce7..0000000 --- a/install/update/new/includes/ucp/ucp_pm.php +++ /dev/null @@ -1,442 +0,0 @@ - -* @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; -} - -/** -* Private Message Class -* -* $_REQUEST['folder'] display folder with the id used -* $_REQUEST['folder'] inbox|outbox|sentbox display folder with the associated name -* -* Display Messages (default to inbox) - mode=view -* Display single message - mode=view&p=[msg_id] or &p=[msg_id] (short linkage) -* -* if the folder id with (&f=[folder_id]) is used when displaying messages, one query will be saved. If it is not used, phpBB needs to grab -* the folder id first in order to display the input boxes and folder names and such things. ;) phpBB always checks this against the database to make -* sure the user is able to view the message. -* -* Composing Messages (mode=compose): -* To specific user (u=[user_id]) -* To specific group (g=[group_id]) -* Quoting a post (action=quotepost&p=[post_id]) -* Quoting a PM (action=quote&p=[msg_id]) -* Forwarding a PM (action=forward&p=[msg_id]) -*/ -class ucp_pm -{ - var $u_action; - - function main($id, $mode) - { - global $user, $template, $phpbb_root_path, $auth, $phpEx, $db, $config, $request; - - if (!$user->data['is_registered']) - { - trigger_error('NO_MESSAGE'); - } - - // Is PM disabled? - if (!$config['allow_privmsg']) - { - trigger_error('PM_DISABLED'); - } - - $user->add_lang('posting'); - $template->assign_var('S_PRIVMSGS', true); - - // Folder directly specified? - $folder_specified = $request->variable('folder', ''); - - if (!in_array($folder_specified, array('inbox', 'outbox', 'sentbox'))) - { - $folder_specified = (int) $folder_specified; - } - else - { - $folder_specified = ($folder_specified == 'inbox') ? PRIVMSGS_INBOX : (($folder_specified == 'outbox') ? PRIVMSGS_OUTBOX : PRIVMSGS_SENTBOX); - } - - if (!$folder_specified) - { - $mode = (!$mode) ? $request->variable('mode', 'view') : $mode; - } - else - { - $mode = 'view'; - } - - if (!function_exists('get_folder')) - { - include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - } - - switch ($mode) - { - // Compose message - case 'compose': - $action = $request->variable('action', 'post'); - - $user_folders = get_folder($user->data['user_id']); - - if ($action != 'delete' && !$auth->acl_get('u_sendpm')) - { - // trigger_error('NO_AUTH_SEND_MESSAGE'); - $template->assign_vars(array( - 'S_NO_AUTH_SEND_MESSAGE' => true, - 'S_COMPOSE_PM_VIEW' => true, - )); - - $tpl_file = 'ucp_pm_viewfolder'; - break; - } - - 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'; - break; - - case 'options': - set_user_message_limit(); - get_folder($user->data['user_id']); - - 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'; - break; - - case 'drafts': - - get_folder($user->data['user_id']); - $this->p_name = 'pm'; - - 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; - $module->main($id, $mode); - - $this->tpl_name = $module->tpl_name; - $this->page_title = 'UCP_PM_DRAFTS'; - - unset($module); - return; - - break; - - case 'view': - - set_user_message_limit(); - - if ($folder_specified) - { - $folder_id = $folder_specified; - $action = 'view_folder'; - } - else - { - $folder_id = $request->variable('f', PRIVMSGS_NO_BOX); - $action = $request->variable('action', 'view_folder'); - } - - $msg_id = $request->variable('p', 0); - $view = $request->variable('view', ''); - - // View message if specified - if ($msg_id) - { - $action = 'view_message'; - } - - 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->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) - { - $move_pm = true; - $dest_folder = (int) $mark_option; - $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->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)) - { - // Return to folder view if single message moved - if ($action == 'view_message') - { - $msg_id = 0; - $folder_id = $request->variable('cur_folder_id', PRIVMSGS_NO_BOX); - $action = 'view_folder'; - } - } - } - - // Message Mark Options - if ($submit_mark) - { - handle_mark_actions($user->data['user_id'], $mark_option); - } - - // If new messages arrived, place them into the appropriate folder - $num_not_moved = $num_removed = 0; - $release = $request->variable('release', 0); - - if ($user->data['user_new_privmsg'] && ($action == 'view_folder' || $action == 'view_message')) - { - $return = place_pm_into_folder($global_privmsgs_rules, $release); - $num_not_moved = $return['not_moved']; - $num_removed = $return['removed']; - } - - if (!$msg_id && $folder_id == PRIVMSGS_NO_BOX) - { - $folder_id = PRIVMSGS_INBOX; - } - else if ($msg_id && $folder_id == PRIVMSGS_NO_BOX) - { - $sql = 'SELECT folder_id - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE msg_id = $msg_id - AND folder_id <> " . PRIVMSGS_NO_BOX . ' - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_MESSAGE'); - } - $folder_id = (int) $row['folder_id']; - } - - if ($request->variable('mark', '') == 'all' && check_link_hash($request->variable('token', ''), 'mark_all_pms_read')) - { - mark_folder_read($user->data['user_id'], $folder_id); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PM_MARK_ALL_READ_SUCCESS']; - - if ($request->is_ajax()) - { - $json_response = new \phpbb\json_response(); - $json_response->send(array( - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $message, - 'success' => true, - )); - } - $message .= '

' . $user->lang('RETURN_UCP', '', ''); - - trigger_error($message); - } - - $message_row = array(); - if ($action == 'view_message' && $msg_id) - { - // Get Message user want to see - if ($view == 'next' || $view == 'previous') - { - $sql_condition = ($view == 'next') ? '>' : '<'; - $sql_ordering = ($view == 'next') ? 'ASC' : 'DESC'; - - $sql = 'SELECT t.msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TABLE . " p2 - WHERE p2.msg_id = $msg_id - AND t.folder_id = $folder_id - AND t.user_id = " . $user->data['user_id'] . " - AND t.msg_id = p.msg_id - AND p.message_time $sql_condition p2.message_time - ORDER BY p.message_time $sql_ordering"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $message = ($view == 'next') ? 'NO_NEWER_PM' : 'NO_OLDER_PM'; - trigger_error($message); - } - else - { - $msg_id = $row['msg_id']; - } - } - - $sql = 'SELECT t.*, p.*, u.* - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE t.user_id = ' . $user->data['user_id'] . " - AND p.author_id = u.user_id - AND t.folder_id = $folder_id - AND t.msg_id = p.msg_id - AND p.msg_id = $msg_id"; - $result = $db->sql_query($sql); - $message_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$message_row) - { - trigger_error('NO_MESSAGE'); - } - - // Update unread status - update_unread_status($message_row['pm_unread'], $message_row['msg_id'], $user->data['user_id'], $folder_id); - } - - $folder = get_folder($user->data['user_id'], $folder_id); - - $s_folder_options = $s_to_folder_options = ''; - foreach ($folder as $f_id => $folder_ary) - { - $option = '' . $folder_ary['folder_name'] . (($folder_ary['unread_messages']) ? ' [' . $folder_ary['unread_messages'] . '] ' : '') . ''; - - $s_to_folder_options .= ($f_id != PRIVMSGS_OUTBOX && $f_id != PRIVMSGS_SENTBOX) ? $option : ''; - $s_folder_options .= $option; - } - clean_sentbox($folder[PRIVMSGS_SENTBOX]['num_messages']); - - // Header for message view - folder and so on - $folder_status = get_folder_status($folder_id, $folder); - - $template->assign_vars(array( - 'CUR_FOLDER_ID' => $folder_id, - 'CUR_FOLDER_NAME' => $folder_status['folder_name'], - 'NUM_NOT_MOVED' => $num_not_moved, - 'NUM_REMOVED' => $num_removed, - 'RELEASE_MESSAGE_INFO' => sprintf($user->lang['RELEASE_MESSAGES'], '', ''), - 'NOT_MOVED_MESSAGES' => $user->lang('NOT_MOVED_MESSAGES', (int) $num_not_moved), - 'RULE_REMOVED_MESSAGES' => $user->lang('RULE_REMOVED_MESSAGES', (int) $num_removed), - - 'S_FOLDER_OPTIONS' => $s_folder_options, - 'S_TO_FOLDER_OPTIONS' => $s_to_folder_options, - 'S_FOLDER_ACTION' => $this->u_action . '&action=view_folder', - 'S_PM_ACTION' => $this->u_action . '&action=' . $action, - - 'U_INBOX' => $this->u_action . '&folder=inbox', - 'U_OUTBOX' => $this->u_action . '&folder=outbox', - 'U_SENTBOX' => $this->u_action . '&folder=sentbox', - 'U_CREATE_FOLDER' => $this->u_action . '&mode=options', - 'U_CURRENT_FOLDER' => $this->u_action . '&folder=' . $folder_id, - 'U_MARK_ALL' => $this->u_action . '&folder=' . $folder_id . '&mark=all&token=' . generate_link_hash('mark_all_pms_read'), - - 'S_IN_INBOX' => ($folder_id == PRIVMSGS_INBOX) ? true : false, - 'S_IN_OUTBOX' => ($folder_id == PRIVMSGS_OUTBOX) ? true : false, - 'S_IN_SENTBOX' => ($folder_id == PRIVMSGS_SENTBOX) ? true : false, - - 'FOLDER_STATUS' => $folder_status['message'], - 'FOLDER_MAX_MESSAGES' => $folder_status['max'], - 'FOLDER_CUR_MESSAGES' => $folder_status['cur'], - 'FOLDER_REMAINING_MESSAGES' => $folder_status['remaining'], - 'FOLDER_PERCENT' => $folder_status['percent']) - ); - - if ($action == 'view_folder') - { - 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'; - } - else if ($action == 'view_message') - { - $template->assign_vars(array( - 'S_VIEW_MESSAGE' => true, - 'L_RETURN_TO_FOLDER' => $user->lang('RETURN_TO', $folder_status['folder_name']), - 'MSG_ID' => $msg_id, - )); - - if (!$msg_id) - { - trigger_error('NO_MESSAGE'); - } - - 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'; - } - - break; - - default: - trigger_error('NO_ACTION_MODE', E_USER_ERROR); - break; - } - - $template->assign_vars(array( - 'L_TITLE' => $user->lang['UCP_PM_' . strtoupper($mode)], - 'S_UCP_ACTION' => $this->u_action . ((isset($action)) ? "&action=$action" : '')) - ); - - // Set desired template - $this->tpl_name = $tpl_file; - $this->page_title = 'UCP_PM_' . strtoupper($mode); - } -} diff --git a/install/update/new/includes/ucp/ucp_pm_compose.php b/install/update/new/includes/ucp/ucp_pm_compose.php deleted file mode 100644 index 87a8c91..0000000 --- a/install/update/new/includes/ucp/ucp_pm_compose.php +++ /dev/null @@ -1,1562 +0,0 @@ - -* @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; -} - -/** -* Compose private message -* Called from ucp_pm with mode == 'compose' -*/ -function compose_pm($id, $mode, $action, $user_folders = array()) -{ - global $template, $db, $auth, $user, $cache; - 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; - - 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) - { - $action = 'post'; - } - add_form_key('ucp_pm_compose'); - - // Grab only parameters needed here - $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->variable('reply_to_all', 0); - - $address_list = $request->variable('address_list', array('' => array(0 => ''))); - - $preview = (isset($_POST['preview'])) ? true : false; - $save = (isset($_POST['save'])) ? true : false; - $load = (isset($_POST['load'])) ? true : false; - $cancel = (isset($_POST['cancel']) && !isset($_POST['save'])) ? true : false; - $delete = (isset($_POST['delete'])) ? true : false; - - $remove_u = (isset($_REQUEST['remove_u'])) ? true : false; - $remove_g = (isset($_REQUEST['remove_g'])) ? true : false; - $add_to = (isset($_REQUEST['add_to'])) ? true : false; - $add_bcc = (isset($_REQUEST['add_bcc'])) ? true : false; - - $refresh = isset($_POST['add_file']) || isset($_POST['delete_file']) || $save || $load - || $remove_u || $remove_g || $add_to || $add_bcc; - $submit = $request->is_set_post('post') && !$refresh && !$preview; - - $action = ($delete && !$preview && !$refresh && $submit) ? 'delete' : $action; - $select_single = ($config['allow_mass_pm'] && $auth->acl_get('u_masspm')) ? false : true; - - $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) - { - if ($msg_id) - { - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&action=view_message&p=' . $msg_id)); - } - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm')); - } - - // Since viewtopic.php language entries are used in several modes, - // we include the language file here - $user->add_lang('viewtopic'); - - /** - * Modify the default vars before composing a PM - * - * @event core.ucp_pm_compose_modify_data - * @var int msg_id post_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 the message is to - * @var bool submit Whether the form has been submitted - * @var bool preview Whether the user is previewing the PM or not - * @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. - * @since 3.1.4-RC1 - */ - $vars = array( - 'msg_id', - 'to_user_id', - 'to_group_id', - 'submit', - 'preview', - 'action', - 'delete', - 'reply_to_all', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_modify_data', compact($vars))); - - // Output PM_TO box if message composing - if ($action != 'edit') - { - // 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, g.group_colour - FROM ' . GROUPS_TABLE . ' g'; - - if (!$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) - { - $sql .= ' LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ')'; - } - - $sql .= ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? ' WHERE ' : ' AND '; - - $sql .= 'g.group_receive_pm = 1 - ORDER BY g.group_type DESC, g.group_name ASC'; - $result = $db->sql_query($sql); - - $group_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $group_options .= '' . $group_helper->get_name($row['group_name']) . ''; - } - $db->sql_freeresult($result); - } - - $template->assign_vars(array( - 'S_SHOW_PM_BOX' => true, - 'S_ALLOW_MASS_PM' => ($config['allow_mass_pm'] && $auth->acl_get('u_masspm')) ? true : false, - 'S_GROUP_OPTIONS' => ($config['allow_mass_pm'] && $auth->acl_get('u_masspm_group')) ? $group_options : '', - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=searchuser&form=postform&field=username_list&select_single=" . (int) $select_single), - )); - } - - $sql = ''; - $folder_id = 0; - - // What is all this following SQL for? Well, we need to know - // some basic information in all cases before we do anything. - switch ($action) - { - case 'post': - if (!$auth->acl_get('u_sendpm')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_SEND_MESSAGE'); - } - break; - - case 'reply': - case 'quote': - case 'forward': - case 'quotepost': - if (!$msg_id) - { - trigger_error('NO_MESSAGE'); - } - - if (!$auth->acl_get('u_sendpm')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_SEND_MESSAGE'); - } - - if ($action == 'quotepost') - { - $sql = 'SELECT p.post_id as msg_id, p.forum_id, p.post_text as message_text, p.poster_id as author_id, p.post_time as message_time, p.bbcode_bitfield, p.bbcode_uid, p.enable_sig, p.enable_smilies, p.enable_magic_url, t.topic_title as message_subject, u.username as quote_username - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . USERS_TABLE . " u - WHERE p.post_id = $msg_id - AND t.topic_id = p.topic_id - AND u.user_id = p.poster_id"; - } - else - { - $sql = 'SELECT t.folder_id, p.*, u.username as quote_username - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE t.user_id = ' . $user->data['user_id'] . " - AND p.author_id = u.user_id - AND t.msg_id = p.msg_id - AND p.msg_id = $msg_id"; - } - break; - - case 'edit': - if (!$msg_id) - { - trigger_error('NO_MESSAGE'); - } - - // check for outbox (not read) status, we do not allow editing if one user already having the message - $sql = 'SELECT p.*, t.folder_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p - WHERE t.user_id = ' . $user->data['user_id'] . ' - AND t.folder_id = ' . PRIVMSGS_OUTBOX . " - AND t.msg_id = $msg_id - AND t.msg_id = p.msg_id"; - break; - - case 'delete': - if (!$auth->acl_get('u_pm_delete')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_DELETE_MESSAGE'); - } - - if (!$msg_id) - { - trigger_error('NO_MESSAGE'); - } - - $sql = 'SELECT msg_id, pm_unread, pm_new, author_id, folder_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE user_id = ' . $user->data['user_id'] . " - AND msg_id = $msg_id"; - break; - - case 'smilies': - generate_smilies('window', 0); - break; - - default: - trigger_error('NO_ACTION_MODE', E_USER_ERROR); - break; - } - - 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'); - } - - if ($sql) - { - /** - * Alter sql query to get message for user to write the PM - * - * @event core.ucp_pm_compose_compose_pm_basic_info_query_before - * @var string sql String with the query to be executed - * @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 - * @var bool submit Whether the user is sending the PM or not - * @var bool preview Whether the user is previewing the PM or not - * @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. - * @since 3.1.0-RC5 - * @changed 3.2.0-a1 Removed undefined variables - */ - $vars = array( - 'sql', - 'msg_id', - 'to_user_id', - 'to_group_id', - 'submit', - 'preview', - 'action', - 'delete', - 'reply_to_all', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_compose_pm_basic_info_query_before', compact($vars))); - - $result = $db->sql_query($sql); - $post = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$post) - { - // If editing it could be the recipient already read the message... - if ($action == 'edit') - { - $sql = 'SELECT p.*, t.folder_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p - WHERE t.user_id = ' . $user->data['user_id'] . " - AND t.msg_id = $msg_id - AND t.msg_id = p.msg_id"; - $result = $db->sql_query($sql); - $post = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($post) - { - trigger_error('NO_EDIT_READ_MESSAGE'); - } - } - - trigger_error('NO_MESSAGE'); - } - - if ($action == 'quotepost') - { - 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'); - } - - /** - * Get the result of querying for the post to be quoted in the pm message - * - * @event core.ucp_pm_compose_quotepost_query_after - * @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 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 - * @var bool preview Whether the user is previewing the PM or not - * @var string action One of: post, reply, quote, forward, quotepost, edit, delete, smilies - * @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', - 'to_user_id', - 'to_group_id', - 'submit', - 'preview', - 'action', - 'delete', - 'reply_to_all', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_quotepost_query_after', compact($vars))); - - // Passworded forum? - if ($post['forum_id']) - { - $sql = 'SELECT forum_id, forum_name, forum_password - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . (int) $post['forum_id']; - $result = $db->sql_query($sql); - $forum_data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!empty($forum_data['forum_password'])) - { - login_forum_box($forum_data); - } - } - } - - $msg_id = (int) $post['msg_id']; - $folder_id = (isset($post['folder_id'])) ? $post['folder_id'] : 0; - $message_text = (isset($post['message_text'])) ? $post['message_text'] : ''; - - if ((!$post['author_id'] || ($post['author_id'] == ANONYMOUS && $action != 'delete')) && $msg_id) - { - trigger_error('NO_AUTHOR'); - } - - if ($action == 'quotepost') - { - // Decode text for message display - decode_message($message_text, $post['bbcode_uid']); - } - - if ($action != 'delete') - { - $enable_urls = $post['enable_magic_url']; - $enable_sig = (isset($post['enable_sig'])) ? $post['enable_sig'] : 0; - - $message_attachment = (isset($post['message_attachment'])) ? $post['message_attachment'] : 0; - $message_subject = $post['message_subject']; - $message_time = $post['message_time']; - $bbcode_uid = $post['bbcode_uid']; - - $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') && !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) - { - $address_list = array('u' => array($post['author_id'] => 'to')); - } - else - { - // We try to include every previously listed member from the TO Header - Reply to all - $address_list = rebuild_header(array('to' => $post['to_address'])); - - // Add the author (if he is already listed then this is no shame (it will be overwritten)) - $address_list['u'][$post['author_id']] = 'to'; - - // Now, make sure the user itself is not listed. ;) - if (isset($address_list['u'][$user->data['user_id']])) - { - unset($address_list['u'][$user->data['user_id']]); - } - } - } - 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'])); - } - - if ($action == 'quotepost') - { - $check_value = 0; - } - else - { - $check_value = (($post['enable_bbcode']+1) << 8) + (($post['enable_smilies']+1) << 4) + (($enable_urls+1) << 2) + (($post['enable_sig']+1) << 1); - } - } - } - else - { - $message_attachment = 0; - $message_text = $message_subject = ''; - - /** - * Predefine message text and subject - * - * @event core.ucp_pm_compose_predefined_message - * @var string message_text Message text - * @var string message_subject Messate subject - * @since 3.1.11-RC1 - */ - $vars = array('message_text', 'message_subject'); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_predefined_message', compact($vars))); - - if ($to_user_id && $to_user_id != ANONYMOUS && $action == 'post') - { - $address_list['u'][$to_user_id] = 'to'; - } - else if ($to_group_id && $action == 'post') - { - $address_list['g'][$to_group_id] = 'to'; - } - $check_value = 0; - } - - 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'); - } - - if ($action == 'edit' && !$refresh && !$preview && !$submit) - { - if (!($message_time > time() - ($config['pm_edit_time'] * 60) || !$config['pm_edit_time'])) - { - trigger_error('CANNOT_EDIT_MESSAGE_TIME'); - } - } - - if ($action == 'post') - { - $template->assign_var('S_NEW_MESSAGE', true); - } - - if (!isset($icon_id)) - { - $icon_id = 0; - } - - /* @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; - unset($message_text); - - $s_action = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=$mode&action=$action", true, $user->session_id); - $s_action .= (($folder_id) ? "&f=$folder_id" : '') . (($msg_id) ? "&p=$msg_id" : ''); - - // Delete triggered ? - if ($action == 'delete') - { - // Folder id has been determined by the SQL Statement - // $folder_id = $request->variable('f', PRIVMSGS_NO_BOX); - - // Do we need to confirm ? - if (confirm_box(true)) - { - delete_pm($user->data['user_id'], $msg_id, $folder_id); - - // jump to next message in "history"? nope, not for the moment. But able to be included later. - $meta_info = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&folder=$folder_id"); - $message = $user->lang['MESSAGE_DELETED']; - - meta_refresh(3, $meta_info); - $message .= '

' . sprintf($user->lang['RETURN_FOLDER'], '', ''); - trigger_error($message); - } - else - { - $s_hidden_fields = array( - 'p' => $msg_id, - 'f' => $folder_id, - 'action' => 'delete' - ); - - // "{$phpbb_root_path}ucp.$phpEx?i=pm&mode=compose" - confirm_box(false, 'DELETE_MESSAGE', build_hidden_fields($s_hidden_fields)); - } - - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&action=view_message&p=' . $msg_id)); - } - - // Get maximum number of allowed recipients - $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 - if (($action == 'reply' || $action == 'quote') && $max_recipients && $reply_to_all) - { - // We try to include every previously listed member from the TO Header - $list = rebuild_header(array('to' => $post['to_address'])); - - // Can be an empty array too ;) - $list = (!empty($list['u'])) ? $list['u'] : array(); - $list[$post['author_id']] = 'to'; - - if (isset($list[$user->data['user_id']])) - { - unset($list[$user->data['user_id']]); - } - - $max_recipients = ($max_recipients < count($list)) ? count($list) : $max_recipients; - - unset($list); - } - - // Handle User/Group adding/removing - handle_message_list_actions($address_list, $error, $remove_u, $remove_g, $add_to, $add_bcc); - - // Check mass pm to group permission - if ((!$config['allow_mass_pm'] || !$auth->acl_get('u_masspm_group')) && !empty($address_list['g'])) - { - $address_list = array(); - $error[] = $user->lang['NO_AUTH_GROUP_MESSAGE']; - } - - // Check mass pm to users permission - if ((!$config['allow_mass_pm'] || !$auth->acl_get('u_masspm')) && num_recipients($address_list) > 1) - { - $address_list = get_recipients($address_list, 1); - $error[] = $user->lang('TOO_MANY_RECIPIENTS', 1); - } - - // Check for too many 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); - } - - // Always check if the submitted attachment data is valid and belongs to the user. - // Further down (especially in submit_post()) we do not check this again. - $message_parser->get_submitted_attachment_data(); - - if ($message_attachment && !$submit && !$refresh && !$preview && $action == 'edit') - { - // Do not change to SELECT * - $sql = 'SELECT attach_id, is_orphan, attach_comment, real_filename, filesize - FROM ' . ATTACHMENTS_TABLE . " - WHERE post_msg_id = $msg_id - AND in_message = 1 - AND is_orphan = 0 - ORDER BY filetime DESC"; - $result = $db->sql_query($sql); - $message_parser->attachment_data = array_merge($message_parser->attachment_data, $db->sql_fetchrowset($result)); - $db->sql_freeresult($result); - } - - if (!in_array($action, array('quote', 'edit', 'delete', 'forward'))) - { - $enable_sig = ($config['allow_sig'] && $config['allow_sig_pm'] && $auth->acl_get('u_sig') && $user->optionget('attachsig')); - $enable_smilies = ($config['allow_smilies'] && $auth->acl_get('u_pm_smilies') && $user->optionget('smilies')); - $enable_bbcode = ($config['allow_bbcode'] && $auth->acl_get('u_pm_bbcode') && $user->optionget('bbcode')); - $enable_urls = true; - } - - $drafts = false; - - // User own some drafts? - if ($auth->acl_get('u_savedrafts') && $action != 'delete') - { - $sql = 'SELECT draft_id - FROM ' . DRAFTS_TABLE . ' - WHERE forum_id = 0 - AND topic_id = 0 - AND user_id = ' . $user->data['user_id'] . - (($draft_id) ? " AND draft_id <> $draft_id" : ''); - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $drafts = true; - } - } - - if ($action == 'edit') - { - $message_parser->bbcode_uid = $bbcode_uid; - } - - $bbcode_status = ($config['allow_bbcode'] && $config['auth_bbcode_pm'] && $auth->acl_get('u_pm_bbcode')) ? true : false; - $smilies_status = ($config['allow_smilies'] && $config['auth_smilies_pm'] && $auth->acl_get('u_pm_smilies')) ? true : false; - $img_status = ($config['auth_img_pm'] && $auth->acl_get('u_pm_img')) ? true : false; - $flash_status = ($config['auth_flash_pm'] && $auth->acl_get('u_pm_flash')) ? true : false; - $url_status = ($config['allow_post_links']) ? true : false; - - // Save Draft - if ($save && $auth->acl_get('u_savedrafts')) - { - $subject = $request->variable('subject', '', true); - $subject = (!$subject && $action != 'post') ? $user->lang['NEW_MESSAGE'] : $subject; - $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_parser->message, - ) - ); - $db->sql_query($sql); - - $redirect_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=$mode"); - - meta_refresh(3, $redirect_url); - $message = $user->lang['DRAFT_SAVED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - - trigger_error($message); - } - else - { - $s_hidden_fields = build_hidden_fields(array( - 'mode' => $mode, - 'action' => $action, - 'save' => true, - 'subject' => $subject, - 'message' => $message, - 'u' => $to_user_id, - 'g' => $to_group_id, - 'p' => $msg_id) - ); - $s_hidden_fields .= build_address_field($address_list); - - confirm_box(false, 'SAVE_DRAFT', $s_hidden_fields); - } - } - else - { - if (utf8_clean_string($subject) === '') - { - $error[] = $user->lang['EMPTY_MESSAGE_SUBJECT']; - } - - if (utf8_clean_string($message) === '') - { - $error[] = $user->lang['TOO_FEW_CHARS']; - } - } - - unset($subject, $message); - } - - // Load Draft - if ($draft_id && $auth->acl_get('u_savedrafts')) - { - $sql = 'SELECT draft_subject, draft_message - FROM ' . DRAFTS_TABLE . " - WHERE draft_id = $draft_id - AND topic_id = 0 - AND forum_id = 0 - AND user_id = " . $user->data['user_id']; - $result = $db->sql_query_limit($sql, 1); - - if ($row = $db->sql_fetchrow($result)) - { - $message_parser->message = $row['draft_message']; - $message_subject = $row['draft_subject']; - - $template->assign_var('S_DRAFT_LOADED', true); - } - else - { - $draft_id = 0; - } - $db->sql_freeresult($result); - } - - // Load Drafts - if ($load && $drafts) - { - load_drafts(0, 0, $id, $action, $msg_id); - } - - if ($submit || $preview || $refresh) - { - if (($submit || $preview) && !check_form_key('ucp_pm_compose')) - { - $error[] = $user->lang['FORM_INVALID']; - } - $subject = $request->variable('subject', '', true); - $message_parser->message = $request->variable('message', '', true); - - $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; - $enable_urls = (isset($_POST['disable_magic_url'])) ? 0 : 1; - $enable_sig = (!$config['allow_sig'] ||!$config['allow_sig_pm']) ? false : ((isset($_POST['attach_sig'])) ? true : false); - - /** - * Modify private message - * - * @event core.ucp_pm_compose_modify_parse_before - * @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 bool enable_sig Whether or not signature is enabled - * @var string subject PM subject text - * @var object message_parser The message parser object - * @var bool submit Whether or not the form has been sumitted - * @var bool preview Whether or not the signature is being previewed - * @var array error Any error strings - * @since 3.1.10-RC1 - */ - $vars = array( - 'enable_bbcode', - 'enable_smilies', - 'enable_urls', - 'enable_sig', - 'subject', - 'message_parser', - 'submit', - 'preview', - 'error', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_modify_parse_before', compact($vars))); - - // Parse Attachments - before checksum is calculated - if ($message_parser->check_attachment_form_token($language, $request, 'ucp_pm_compose')) - { - $message_parser->parse_attachments('fileupload', $action, 0, $submit, $preview, $refresh, true); - } - - if (count($message_parser->warn_msg) && !($remove_u || $remove_g || $add_to || $add_bcc)) - { - $error[] = implode('
', $message_parser->warn_msg); - $message_parser->warn_msg = array(); - } - - // Parse message - $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 (count($message_parser->warn_msg) && !$refresh) - { - $error[] = implode('
', $message_parser->warn_msg); - } - - if ($action != 'edit' && !$preview && !$refresh && $config['flood_interval'] && !$auth->acl_get('u_ignoreflood')) - { - // Flood check - $last_post_time = $user->data['user_lastpost_time']; - - if ($last_post_time) - { - if ($last_post_time && ($current_time - $last_post_time) < intval($config['flood_interval'])) - { - $error[] = $user->lang['FLOOD_ERROR']; - } - } - } - - // Subject defined - if ($submit) - { - if (utf8_clean_string($subject) === '') - { - $error[] = $user->lang['EMPTY_MESSAGE_SUBJECT']; - } - - if (!count($address_list)) - { - $error[] = $user->lang['NO_RECIPIENT']; - } - } - - // Store message, sync counters - if (!count($error) && $submit) - { - $pm_data = array( - 'msg_id' => (int) $msg_id, - 'from_user_id' => $user->data['user_id'], - 'from_user_ip' => $user->ip, - 'from_username' => $user->data['username'], - 'reply_from_root_level' => (isset($post['root_level'])) ? (int) $post['root_level'] : 0, - 'reply_from_msg_id' => (int) $msg_id, - 'icon_id' => (int) $icon_id, - 'enable_sig' => (bool) $enable_sig, - 'enable_bbcode' => (bool) $enable_bbcode, - 'enable_smilies' => (bool) $enable_smilies, - 'enable_urls' => (bool) $enable_urls, - 'bbcode_bitfield' => $message_parser->bbcode_bitfield, - 'bbcode_uid' => $message_parser->bbcode_uid, - 'message' => $message_parser->message, - 'attachment_data' => $message_parser->attachment_data, - 'filename_data' => $message_parser->filename_data, - 'address_list' => $address_list - ); - - // ((!$message_subject) ? $subject : $message_subject) - $msg_id = submit_pm($action, $subject, $pm_data); - - $return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&p=' . $msg_id); - $inbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'); - $outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); - - $folder_url = ''; - if (($folder_id > 0) && isset($user_folders[$folder_id])) - { - $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id); - } - - $return_box_url = ($action === 'post' || $action === 'edit') ? $outbox_folder_url : $inbox_folder_url; - $return_box_lang = ($action === 'post' || $action === 'edit') ? 'PM_OUTBOX' : 'PM_INBOX'; - - $save_message = ($action === 'edit') ? $user->lang['MESSAGE_EDITED'] : $user->lang['MESSAGE_STORED']; - $message = $save_message . '

' . $user->lang('VIEW_PRIVATE_MESSAGE', '', ''); - - $last_click_type = 'CLICK_RETURN_FOLDER'; - if ($folder_url) - { - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); - $last_click_type = 'CLICK_GOTO_FOLDER'; - } - $message .= '

' . sprintf($user->lang[$last_click_type], '', '', $user->lang[$return_box_lang]); - - meta_refresh(3, $return_message_url); - trigger_error($message); - } - - $message_subject = $subject; - } - - // Preview - if (!count($error) && $preview) - { - $preview_message = $message_parser->format_display($enable_bbcode, $enable_urls, $enable_smilies, false); - - $preview_signature = $user->data['user_sig']; - $preview_signature_uid = $user->data['user_sig_bbcode_uid']; - $preview_signature_bitfield = $user->data['user_sig_bbcode_bitfield']; - - // Signature - if ($enable_sig && $config['allow_sig'] && $preview_signature) - { - $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 - { - $preview_signature = ''; - } - - // Attachment Preview - if (count($message_parser->attachment_data)) - { - $template->assign_var('S_HAS_ATTACHMENTS', true); - - $update_count = array(); - $attachment_data = $message_parser->attachment_data; - - parse_attachments(false, $preview_message, $attachment_data, $update_count, true); - - foreach ($attachment_data as $i => $attachment) - { - $template->assign_block_vars('attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - unset($attachment_data); - } - - $preview_subject = censor_text($subject); - - if (!count($error)) - { - $template->assign_vars(array( - 'PREVIEW_SUBJECT' => $preview_subject, - 'PREVIEW_MESSAGE' => $preview_message, - 'PREVIEW_SIGNATURE' => $preview_signature, - - 'S_DISPLAY_PREVIEW' => true) - ); - } - unset($message_text); - } - - // Decode text for message display - $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); - - if (($action == 'quote' || $action == 'quotepost') && !$preview && !$refresh && !$submit) - { - if ($action == 'quotepost') - { - $post_id = $request->variable('p', 0); - if ($config['allow_post_links']) - { - $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 - { - $message_link = $user->lang['SUBJECT'] . $user->lang['COLON'] . ' ' . $message_subject . " (" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id})\n\n"; - } - } - else - { - $message_link = ''; - } - $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) - { - $fwd_to_field = write_pm_addresses(array('to' => $post['to_address']), 0, true); - - if ($config['allow_post_links']) - { - $quote_username_text = '[url=' . generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$post['author_id']}]{$quote_username}[/url]"; - } - else - { - $quote_username_text = $quote_username . ' (' . generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$post['author_id']})"; - } - - $forward_text = array(); - $forward_text[] = $user->lang['FWD_ORIGINAL_MESSAGE']; - $forward_text[] = sprintf($user->lang['FWD_SUBJECT'], censor_text($message_subject)); - $forward_text[] = sprintf($user->lang['FWD_DATE'], $user->format_date($message_time, false, true)); - $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'])); - - $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); - } - - $attachment_data = $message_parser->attachment_data; - $filename_data = $message_parser->filename_data; - $message_text = $message_parser->message; - - // MAIN PM PAGE BEGINS HERE - - // Generate smiley listing - generate_smilies('inline', 0); - - // Generate PM Icons - $s_pm_icons = false; - if ($config['enable_pm_icons']) - { - $s_pm_icons = posting_gen_topic_icons($action, $icon_id); - } - - // Generate inline attachment select box - posting_gen_inline_attachments($attachment_data); - - // Build address list for display - // array('u' => array($author_id => 'to')); - if (count($address_list)) - { - // Get Usernames and Group Names - $result = array(); - if (!empty($address_list['u'])) - { - $sql = 'SELECT user_id as id, username as name, user_colour as colour - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_map('intval', array_keys($address_list['u']))) . ' - ORDER BY username_clean ASC'; - $result['u'] = $db->sql_query($sql); - } - - if (!empty($address_list['g'])) - { - $sql = 'SELECT g.group_id AS id, g.group_name AS name, g.group_colour AS colour, g.group_type - FROM ' . GROUPS_TABLE . ' g'; - - if (!$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) - { - $sql .= ' LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ')'; - } - - $sql .= ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? ' WHERE ' : ' AND '; - - $sql .= 'g.group_receive_pm = 1 - AND ' . $db->sql_in_set('g.group_id', array_map('intval', array_keys($address_list['g']))) . ' - ORDER BY g.group_name ASC'; - - $result['g'] = $db->sql_query($sql); - } - - $u = $g = array(); - $_types = array('u', 'g'); - foreach ($_types as $type) - { - if (isset($result[$type]) && $result[$type]) - { - while ($row = $db->sql_fetchrow($result[$type])) - { - if ($type == 'g') - { - $row['name'] = $group_helper->get_name($row['name']); - } - - ${$type}[$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']); - } - $db->sql_freeresult($result[$type]); - } - } - - // Now Build the address list - foreach ($address_list as $type => $adr_ary) - { - foreach ($adr_ary as $id => $field) - { - if (!isset(${$type}[$id])) - { - unset($address_list[$type][$id]); - continue; - } - - $field = ($field == 'to') ? 'to' : 'bcc'; - $type = ($type == 'u') ? 'u' : 'g'; - $id = (int) $id; - - $tpl_ary = array( - 'IS_GROUP' => ($type == 'g') ? true : false, - 'IS_USER' => ($type == 'u') ? true : false, - 'UG_ID' => $id, - 'NAME' => ${$type}[$id]['name'], - 'COLOUR' => (${$type}[$id]['colour']) ? '#' . ${$type}[$id]['colour'] : '', - 'TYPE' => $type, - ); - - if ($type == 'u') - { - $tpl_ary = array_merge($tpl_ary, array( - 'U_VIEW' => get_username_string('profile', $id, ${$type}[$id]['name'], ${$type}[$id]['colour']), - 'NAME_FULL' => get_username_string('full', $id, ${$type}[$id]['name'], ${$type}[$id]['colour']), - )); - } - else - { - $tpl_ary = array_merge($tpl_ary, array( - 'U_VIEW' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $id), - )); - } - - $template->assign_block_vars($field . '_recipient', $tpl_ary); - } - } - } - - // Build hidden address list - $s_hidden_address_field = build_address_field($address_list); - - $bbcode_checked = (isset($enable_bbcode)) ? !$enable_bbcode : (($config['allow_bbcode'] && $auth->acl_get('u_pm_bbcode')) ? !$user->optionget('bbcode') : 1); - $smilies_checked = (isset($enable_smilies)) ? !$enable_smilies : (($config['allow_smilies'] && $auth->acl_get('u_pm_smilies')) ? !$user->optionget('smilies') : 1); - $urls_checked = (isset($enable_urls)) ? !$enable_urls : 0; - $sig_checked = $enable_sig; - - switch ($action) - { - case 'post': - $page_title = $user->lang['POST_NEW_PM']; - break; - - case 'quote': - $page_title = $user->lang['POST_QUOTE_PM']; - break; - - case 'quotepost': - $page_title = $user->lang['POST_PM_POST']; - break; - - case 'reply': - $page_title = $user->lang['POST_REPLY_PM']; - break; - - case 'edit': - $page_title = $user->lang['POST_EDIT_PM']; - break; - - case 'forward': - $page_title = $user->lang['POST_FORWARD_PM']; - break; - - default: - trigger_error('NO_ACTION_MODE', E_USER_ERROR); - break; - } - - $s_hidden_fields = (isset($check_value)) ? '' : ''; - $s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '' : ''; - - $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_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' => $user->lang(($bbcode_status ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '', ''), - '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' => (count($error)) ? implode('
', $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, - 'S_EDIT_POST' => ($action == 'edit'), - 'S_SHOW_PM_ICONS' => $s_pm_icons, - 'S_BBCODE_ALLOWED' => ($bbcode_status) ? 1 : 0, - 'S_BBCODE_CHECKED' => ($bbcode_checked) ? ' checked="checked"' : '', - 'S_SMILIES_ALLOWED' => $smilies_status, - 'S_SMILIES_CHECKED' => ($smilies_checked) ? ' checked="checked"' : '', - 'S_SIG_ALLOWED' => ($config['allow_sig'] && $config['allow_sig_pm'] && $auth->acl_get('u_sig')), - 'S_SIGNATURE_CHECKED' => ($sig_checked) ? ' checked="checked"' : '', - 'S_LINKS_ALLOWED' => $url_status, - 'S_MAGIC_URL_CHECKED' => ($urls_checked) ? ' checked="checked"' : '', - 'S_SAVE_ALLOWED' => ($auth->acl_get('u_savedrafts') && $action != 'edit') ? true : false, - 'S_HAS_DRAFTS' => ($auth->acl_get('u_savedrafts') && $drafts), - 'S_FORM_ENCTYPE' => $form_enctype, - 'S_ATTACH_DATA' => json_encode($message_parser->attachment_data), - - 'S_BBCODE_IMG' => $img_status, - 'S_BBCODE_FLASH' => $flash_status, - 'S_BBCODE_QUOTE' => true, - 'S_BBCODE_URL' => $url_status, - - 'S_POST_ACTION' => $s_action, - 'S_HIDDEN_ADDRESS_FIELD' => $s_hidden_address_field, - 'S_HIDDEN_FIELDS' => $s_hidden_fields, - - 'S_CLOSE_PROGRESS_WINDOW' => isset($_POST['add_file']), - 'U_PROGRESS_BAR' => append_sid("{$phpbb_root_path}posting.$phpEx", 'f=0&mode=popup'), - 'UA_PROGRESS_BAR' => addslashes(append_sid("{$phpbb_root_path}posting.$phpEx", 'f=0&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(); - - // Show attachment box for adding attachments if true - $allowed = ($auth->acl_get('u_pm_attach') && $config['allow_pm_attach'] && $form_enctype); - - if ($allowed) - { - $max_files = ($auth->acl_gets('a_', 'm_')) ? 0 : (int) $config['max_attachments_pm']; - $plupload->configure($cache, $template, $s_action, false, $max_files); - } - - // Attachment entry - posting_gen_attachment_entry($attachment_data, $filename_data, $allowed); - - // Message History - if ($action == 'reply' || $action == 'quote' || $action == 'forward') - { - if (message_history($msg_id, $user->data['user_id'], $post, array(), true)) - { - $template->assign_var('S_DISPLAY_HISTORY', true); - } - } -} - -/** -* For composing messages, handle list actions -*/ -function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove_g, $add_to, $add_bcc) -{ - global $auth, $db, $user; - global $request, $phpbb_dispatcher; - - // Delete User [TO/BCC] - if ($remove_u && $request->variable('remove_u', array(0 => ''))) - { - $remove_user_id = array_keys($request->variable('remove_u', array(0 => ''))); - - if (isset($remove_user_id[0])) - { - unset($address_list['u'][(int) $remove_user_id[0]]); - } - } - - // Delete Group [TO/BCC] - if ($remove_g && $request->variable('remove_g', array(0 => ''))) - { - $remove_group_id = array_keys($request->variable('remove_g', array(0 => ''))); - - if (isset($remove_group_id[0])) - { - unset($address_list['g'][(int) $remove_group_id[0]]); - } - } - - // Add Selected Groups - $group_list = $request->variable('group_list', array(0)); - - // Build usernames to add - $usernames = $request->variable('username', '', true); - $usernames = (empty($usernames)) ? array() : array($usernames); - - $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 && (count($group_list) || count($usernames))) - { - $add_to = true; - - global $refresh, $submit, $preview; - - $refresh = true; - $submit = false; - - // Preview is only true if there was also a message entered - if ($request->variable('message', '')) - { - $preview = true; - } - } - - // Add User/Group [TO] - if ($add_to || $add_bcc) - { - $type = ($add_to) ? 'to' : 'bcc'; - - if (count($group_list)) - { - foreach ($group_list as $group_id) - { - $address_list['g'][$group_id] = $type; - } - } - - // User ID's to add... - $user_id_ary = array(); - - // Reveal the correct user_ids - 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 (!count($user_id_ary)) - { - $error[] = $user->lang['PM_NO_USERS']; - } - } - - // Add Friends if specified - $friend_list = array_keys($request->variable('add_' . $type, array(0))); - $user_id_ary = array_merge($user_id_ary, $friend_list); - - foreach ($user_id_ary as $user_id) - { - if ($user_id == ANONYMOUS) - { - continue; - } - - $address_list['u'][$user_id] = $type; - } - } - - // Check for disallowed recipients - if (!empty($address_list['u'])) - { - $can_ignore_allow_pm = $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'); - - // Administrator deactivated users check and we need to check their - // PM status (do they want to receive PM's?) - // Only check PM status if not a moderator or admin, since they - // are allowed to override this user setting - $sql = 'SELECT user_id, user_allow_pm - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($address_list['u'])) . ' - AND ( - (user_type = ' . USER_INACTIVE . ' - AND user_inactive_reason = ' . INACTIVE_MANUAL . ') - ' . ($can_ignore_allow_pm ? '' : ' OR user_allow_pm = 0') . ' - )'; - - $result = $db->sql_query($sql); - - $removed_no_pm = $removed_no_permission = false; - while ($row = $db->sql_fetchrow($result)) - { - if (!$can_ignore_allow_pm && !$row['user_allow_pm']) - { - $removed_no_pm = true; - } - else - { - $removed_no_permission = true; - } - - unset($address_list['u'][$row['user_id']]); - } - $db->sql_freeresult($result); - - // print a notice about users not being added who do not want to receive pms - if ($removed_no_pm) - { - $error[] = $user->lang['PM_USERS_REMOVED_NO_PM']; - } - - // print a notice about users not being added who do not have permission to receive PMs - if ($removed_no_permission) - { - $error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION']; - } - - if (!count(array_keys($address_list['u']))) - { - return; - } - - // Check if users have permission to read PMs - $can_read = $auth->acl_get_list(array_keys($address_list['u']), 'u_readpm'); - $can_read = (empty($can_read) || !isset($can_read[0]['u_readpm'])) ? array() : $can_read[0]['u_readpm']; - $cannot_read_list = array_diff(array_keys($address_list['u']), $can_read); - if (!empty($cannot_read_list)) - { - foreach ($cannot_read_list as $cannot_read) - { - unset($address_list['u'][$cannot_read]); - } - - $error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION']; - } - - // Check if users are banned - $banned_user_list = phpbb_get_banned_user_ids(array_keys($address_list['u']), false); - if (!empty($banned_user_list)) - { - foreach ($banned_user_list as $banned_user) - { - unset($address_list['u'][$banned_user]); - } - - $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->variable(). -*/ -function build_address_field($address_list) -{ - $s_hidden_address_field = ''; - foreach ($address_list as $type => $adr_ary) - { - foreach ($adr_ary as $id => $field) - { - $s_hidden_address_field .= ''; - } - } - return $s_hidden_address_field; -} - -/** -* Return number of private message recipients -*/ -function num_recipients($address_list) -{ - $num_recipients = 0; - - foreach ($address_list as $field => $adr_ary) - { - $num_recipients += count($adr_ary); - } - - return $num_recipients; -} - -/** -* Get number of 'num_recipients' recipients from first position -*/ -function get_recipients($address_list, $num_recipients = 1) -{ - $recipient = array(); - - $count = 0; - foreach ($address_list as $field => $adr_ary) - { - foreach ($adr_ary as $id => $type) - { - if ($count >= $num_recipients) - { - break 2; - } - $recipient[$field][$id] = $type; - $count++; - } - } - - return $recipient; -} diff --git a/install/update/new/includes/ucp/ucp_pm_viewfolder.php b/install/update/new/includes/ucp/ucp_pm_viewfolder.php deleted file mode 100644 index ce40a25..0000000 --- a/install/update/new/includes/ucp/ucp_pm_viewfolder.php +++ /dev/null @@ -1,611 +0,0 @@ - -* @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; -} - -/** -* View message folder -* Called from ucp_pm with mode == 'view' && action == 'view_folder' -*/ -function view_folder($id, $mode, $folder_id, $folder) -{ - 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'); - - // Grab icons - $icons = $cache->obtain_icons(); - - $color_rows = array('message_reported', 'marked', 'replied'); - - $_module = new p_master(); - $_module->list_modules('ucp'); - $_module->set_active('zebra'); - - $zebra_enabled = ($_module->active_module === false) ? false : true; - - unset($_module); - - if ($zebra_enabled) - { - $color_rows = array_merge($color_rows, array('friend', 'foe')); - } - - foreach ($color_rows as $var) - { - $template->assign_block_vars('pm_colour_info', array( - 'IMG' => $user->img("pm_{$var}", ''), - 'CLASS' => "pm_{$var}_colour", - 'LANG' => $user->lang[strtoupper($var) . '_MESSAGE']) - ); - } - - $mark_options = array('mark_important', 'delete_marked'); - - // Minimise edits - if (!$auth->acl_get('u_pm_delete') && $key = array_search('delete_marked', $mark_options)) - { - unset($mark_options[$key]); - } - - $s_mark_options = ''; - foreach ($mark_options as $mark_option) - { - $s_mark_options .= ''; - } - - // We do the folder moving options here too, for template authors to use... - $s_folder_move_options = ''; - if ($folder_id != PRIVMSGS_NO_BOX && $folder_id != PRIVMSGS_OUTBOX) - { - foreach ($folder as $f_id => $folder_ary) - { - if ($f_id == PRIVMSGS_OUTBOX || $f_id == PRIVMSGS_SENTBOX || $f_id == $folder_id) - { - continue; - } - - $s_folder_move_options .= ''; - $s_folder_move_options .= sprintf($user->lang['MOVE_MARKED_TO_FOLDER'], $folder_ary['folder_name']); - $s_folder_move_options .= (($folder_ary['unread_messages']) ? ' [' . $folder_ary['unread_messages'] . '] ' : '') . ''; - } - } - $friend = $foe = array(); - - // Get friends and foes - $sql = 'SELECT * - FROM ' . ZEBRA_TABLE . ' - WHERE user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $friend[$row['zebra_id']] = $row['friend']; - $foe[$row['zebra_id']] = $row['foe']; - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_MARK_OPTIONS' => $s_mark_options, - 'S_MOVE_MARKED_OPTIONS' => $s_folder_move_options) - ); - - // Okay, lets dump out the page ... - if (count($folder_info['pm_list'])) - { - $address_list = array(); - - // Build Recipient List if in outbox/sentbox - max two additional queries - if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) - { - $address_list = get_recipient_strings($folder_info['rowset']); - } - - foreach ($folder_info['pm_list'] as $message_id) - { - $row = &$folder_info['rowset'][$message_id]; - - $folder_img = ($row['pm_unread']) ? 'pm_unread' : 'pm_read'; - $folder_alt = ($row['pm_unread']) ? 'NEW_MESSAGES' : 'NO_NEW_MESSAGES'; - - // Generate all URIs ... - $view_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=view&f=$folder_id&p=$message_id"); - $remove_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=compose&action=delete&p=$message_id"); - - $row_indicator = ''; - foreach ($color_rows as $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']])) - { - $row_indicator = $var; - break; - } - } - - // Send vars to template - $template->assign_block_vars('messagerow', array( - 'PM_CLASS' => ($row_indicator) ? 'pm_' . $row_indicator . '_colour' : '', - - 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $row['author_id'], $row['username'], $row['user_colour'], $row['username']), - 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $row['author_id'], $row['username'], $row['user_colour'], $row['username']), - 'MESSAGE_AUTHOR' => get_username_string('username', $row['author_id'], $row['username'], $row['user_colour'], $row['username']), - 'U_MESSAGE_AUTHOR' => get_username_string('profile', $row['author_id'], $row['username'], $row['user_colour'], $row['username']), - - 'FOLDER_ID' => $folder_id, - 'MESSAGE_ID' => $message_id, - 'SENT_TIME' => $user->format_date($row['message_time']), - 'SUBJECT' => censor_text($row['message_subject']), - 'FOLDER' => (isset($folder[$row['folder_id']])) ? $folder[$row['folder_id']]['folder_name'] : '', - 'U_FOLDER' => (isset($folder[$row['folder_id']])) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'folder=' . $row['folder_id']) : '', - 'PM_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? '' : '', - 'PM_ICON_URL' => (!empty($icons[$row['icon_id']])) ? $config['icons_path'] . '/' . $icons[$row['icon_id']]['img'] : '', - 'FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'FOLDER_IMG_STYLE' => $folder_img, - 'PM_IMG' => ($row_indicator) ? $user->img('pm_' . $row_indicator, '') : '', - 'ATTACH_ICON_IMG' => ($auth->acl_get('u_pm_download') && $row['message_attachment'] && $config['allow_pm_attach']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', - - 'S_PM_UNREAD' => ($row['pm_unread']) ? true : false, - 'S_PM_DELETED' => ($row['pm_deleted']) ? true : false, - 'S_PM_REPORTED' => (isset($row['report_id'])) ? true : false, - 'S_AUTHOR_DELETED' => ($row['author_id'] == ANONYMOUS) ? true : false, - - 'U_VIEW_PM' => ($row['pm_deleted']) ? '' : $view_message_url, - 'U_REMOVE_PM' => ($row['pm_deleted']) ? $remove_message_url : '', - 'U_MCP_REPORT' => (isset($row['report_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=pm_reports&mode=pm_report_details&r=' . $row['report_id']) : '', - 'RECIPIENTS' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? implode($user->lang['COMMA_SEPARATOR'], $address_list[$message_id]) : '') - ); - } - unset($folder_info['rowset']); - - $template->assign_vars(array( - 'S_SHOW_RECIPIENTS' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? true : false, - 'S_SHOW_COLOUR_LEGEND' => true, - - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'PM_REPORTED'), - 'S_PM_ICONS' => ($config['enable_pm_icons']) ? true : false) - ); - } - } - else - { - $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 === '')) - { - $template->assign_var('PROMPT', true); - } - else - { - // Build Recipient List if in outbox/sentbox - - $address_temp = $address = $data = array(); - - if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) - { - foreach ($folder_info['rowset'] as $message_id => $row) - { - $address_temp[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address'])); - $address[$message_id] = array(); - } - } - - foreach ($folder_info['pm_list'] as $message_id) - { - $row = &$folder_info['rowset'][$message_id]; - - include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - - $sql = 'SELECT p.message_text, p.bbcode_uid - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE t.user_id = ' . $user->data['user_id'] . " - AND p.author_id = u.user_id - AND t.folder_id = $folder_id - AND t.msg_id = p.msg_id - AND p.msg_id = $message_id"; - $result = $db->sql_query_limit($sql, 1); - $message_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $_types = array('u', 'g'); - foreach ($_types as $ug_type) - { - if (isset($address_temp[$message_id][$ug_type]) && count($address_temp[$message_id][$ug_type])) - { - if (!isset($address[$message_id][$ug_type])) - { - $address[$message_id][$ug_type] = array(); - } - if ($ug_type == 'u') - { - $sql = 'SELECT user_id as id, username as name - FROM ' . USERS_TABLE . ' - WHERE '; - } - else - { - $sql = 'SELECT group_id as id, group_name as name - FROM ' . GROUPS_TABLE . ' - WHERE '; - } - $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($address_temp[$message_id][$ug_type]))); - - $result = $db->sql_query($sql); - - while ($info_row = $db->sql_fetchrow($result)) - { - $address[$message_id][$ug_type][$address_temp[$message_id][$ug_type][$info_row['id']]][] = $info_row['name']; - unset($address_temp[$message_id][$ug_type][$info_row['id']]); - } - $db->sql_freeresult($result); - } - } - - // 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']) && 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(); - $address[$message_id]['u']['to'][] = $user->lang['UNDISCLOSED_RECIPIENT']; - } - - decode_message($message_row['message_text'], $message_row['bbcode_uid']); - - $data[] = array( - 'subject' => censor_text($row['message_subject']), - 'sender' => $row['username'], - // ISO 8601 date. For PHP4 we are able to hardcode the timezone because $user->format_date() does not set it. - 'date' => $user->format_date($row['message_time'], 'c', true), - 'to' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? $address[$message_id] : '', - 'message' => $message_row['message_text'] - ); - } - - switch ($export_type) - { - case 'CSV': - case 'CSV_EXCEL': - $mimetype = 'text/csv'; - $filetype = 'csv'; - - if ($export_type == 'CSV_EXCEL') - { - $enclosure = '"'; - $delimiter = ','; - $newline = "\r\n"; - } - else - { - $newline = "\n"; - } - - $string = ''; - foreach ($data as $value) - { - $recipients = $value['to']; - $value['to'] = $value['bcc'] = ''; - - if (is_array($recipients)) - { - foreach ($recipients as $values) - { - $value['bcc'] .= (isset($values['bcc']) && is_array($values['bcc'])) ? ',' . implode(',', $values['bcc']) : ''; - $value['to'] .= (isset($values['to']) && is_array($values['to'])) ? ',' . implode(',', $values['to']) : ''; - } - - // Remove the commas which will appear before the first entry. - $value['to'] = substr($value['to'], 1); - $value['bcc'] = substr($value['bcc'], 1); - } - - foreach ($value as $tag => $text) - { - $cell = str_replace($enclosure, $enclosure . $enclosure, $text); - - if (strpos($cell, $enclosure) !== false || strpos($cell, $delimiter) !== false || strpos($cell, $newline) !== false) - { - $string .= $enclosure . $text . $enclosure . $delimiter; - } - else - { - $string .= $cell . $delimiter; - } - } - $string = substr($string, 0, -1) . $newline; - } - break; - - case 'XML': - $mimetype = 'application/xml'; - $filetype = 'xml'; - $string = '' . "\n"; - $string .= "\n"; - - foreach ($data as $value) - { - $string .= "\t\n"; - - if (is_array($value['to'])) - { - foreach ($value['to'] as $key => $values) - { - foreach ($values as $type => $types) - { - foreach ($types as $name) - { - $string .= "\t\t$name\n"; - } - } - } - } - - unset($value['to']); - - foreach ($value as $tag => $text) - { - $string .= "\t\t<$tag>$text\n"; - } - - $string .= "\t\n"; - } - $string .= ''; - break; - } - - header('Cache-Control: private, no-cache'); - header("Content-Type: $mimetype; name=\"data.$filetype\""); - header("Content-disposition: attachment; filename=data.$filetype"); - echo $string; - exit; - } - } -} - -/** -* Get Messages from folder/user -*/ -function get_pm_from($folder_id, $folder, $user_id) -{ - global $user, $db, $template, $config, $auth, $phpbb_container, $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher; - - $start = $request->variable('start', 0); - - // Additional vars later, pm ordering is mostly different from post ordering. :/ - $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 - $limit_days = array(0 => $user->lang['ALL_MESSAGES'], 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']); - - // No sort by Author for sentbox/outbox (already only author available) - // Also, sort by msg_id for the time - private messages are not as prone to errors as posts are. - if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) - { - $sort_by_text = array('t' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); - $sort_by_sql = array('t' => 'p.message_time', 's' => array('p.message_subject', 'p.message_time')); - } - else - { - $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); - $sort_by_sql = array('a' => array('u.username_clean', 'p.message_time'), 't' => 'p.message_time', 's' => array('p.message_subject', 'p.message_time')); - } - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - 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); - - $folder_sql = 't.folder_id = ' . (int) $folder_id; - - // Limit pms to certain time frame, obtain correct pm count - if ($sort_days) - { - $min_post_time = time() - ($sort_days * 86400); - - if (isset($_POST['sort'])) - { - $start = 0; - } - - $sql = 'SELECT COUNT(t.msg_id) AS pm_count - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . " p - WHERE $folder_sql - AND t.user_id = $user_id - AND t.msg_id = p.msg_id - AND p.message_time >= $min_post_time"; - $result = $db->sql_query_limit($sql, 1); - $pm_count = (int) $db->sql_fetchfield('pm_count'); - $db->sql_freeresult($result); - - $sql_limit_time = "AND p.message_time >= $min_post_time"; - } - else - { - $pm_count = (!empty($folder[$folder_id]['num_messages'])) ? $folder[$folder_id]['num_messages'] : 0; - $sql_limit_time = ''; - } - - $base_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=view&action=view_folder&f=$folder_id&$u_sort_param"); - $start = $pagination->validate_start($start, $config['topics_per_page'], $pm_count); - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $pm_count, $config['topics_per_page'], $start); - - $template_vars = array( - 'TOTAL_MESSAGES' => $user->lang('VIEW_PM_MESSAGES', (int) $pm_count), - - 'POST_IMG' => (!$auth->acl_get('u_sendpm')) ? $user->img('button_topic_locked', 'POST_PM_LOCKED') : $user->img('button_pm_new', 'POST_NEW_PM'), - - 'S_NO_AUTH_SEND_MESSAGE' => !$auth->acl_get('u_sendpm'), - - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_TOPIC_ICONS' => ($config['enable_pm_icons']) ? true : false, - - 'U_POST_NEW_TOPIC' => ($auth->acl_get('u_sendpm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose') : '', - 'S_PM_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=view&action=view_folder&f=$folder_id" . (($start !== 0) ? "&start=$start" : '')), - ); - - /** - * Modify template variables before they are assigned - * - * @event core.ucp_pm_view_folder_get_pm_from_template - * @var int folder_id Folder ID - * @var array folder Folder data - * @var int user_id User ID - * @var string base_url Pagination base URL - * @var int start Pagination start - * @var int pm_count Count of PMs - * @var array template_vars Template variables to be assigned - * @since 3.1.11-RC1 - */ - $vars = array( - 'folder_id', - 'folder', - 'user_id', - 'base_url', - 'start', - 'pm_count', - 'template_vars', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_view_folder_get_pm_from_template', compact($vars))); - - $template->assign_vars($template_vars); - - // Grab all pm data - $rowset = $pm_list = array(); - - // If the user is trying to reach late pages, start searching from the end - $store_reverse = false; - $sql_limit = $config['topics_per_page']; - if ($start > $pm_count / 2) - { - $store_reverse = true; - - // Select the sort order - $direction = ($sort_dir == 'd') ? 'ASC' : 'DESC'; - $sql_limit = $pagination->reverse_limit($start, $sql_limit, $pm_count); - $sql_start = $pagination->reverse_start($start, $sql_limit, $pm_count); - } - else - { - // Select the sort order - $direction = ($sort_dir == 'd') ? 'DESC' : 'ASC'; - $sql_start = $start; - } - - // Sql sort order - if (is_array($sort_by_sql[$sort_key])) - { - $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction; - } - else - { - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction; - } - - $sql_ary = array( - 'SELECT' => 't.*, p.root_level, p.message_time, p.message_subject, p.icon_id, p.to_address, p.message_attachment, p.bcc_address, u.username, u.username_clean, u.user_colour, p.message_reported', - 'FROM' => array( - PRIVMSGS_TO_TABLE => 't', - PRIVMSGS_TABLE => 'p', - USERS_TABLE => 'u', - ), - 'WHERE' => "t.user_id = $user_id - AND p.author_id = u.user_id - AND $folder_sql - AND t.msg_id = p.msg_id - $sql_limit_time", - 'ORDER_BY' => $sql_sort_order, - ); - - /** - * Modify SQL before it is executed - * - * @event core.ucp_pm_view_folder_get_pm_from_sql - * @var array sql_ary SQL array - * @var int sql_limit SQL limit - * @var int sql_start SQL start - * @since 3.1.11-RC1 - */ - $vars = array( - 'sql_ary', - 'sql_limit', - 'sql_start', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_view_folder_get_pm_from_sql', compact($vars))); - - $result = $db->sql_query_limit($db->sql_build_query('SELECT', $sql_ary), $sql_limit, $sql_start); - - $pm_reported = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[$row['msg_id']] = $row; - $pm_list[] = $row['msg_id']; - if ($row['message_reported']) - { - $pm_reported[] = $row['msg_id']; - } - } - $db->sql_freeresult($result); - - // Fetch the report_ids, if there are any reported pms. - if (!empty($pm_reported) && $auth->acl_getf_global('m_report')) - { - $sql = 'SELECT pm_id, report_id - FROM ' . REPORTS_TABLE . ' - WHERE report_closed = 0 - AND ' . $db->sql_in_set('pm_id', $pm_reported); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $rowset[$row['pm_id']]['report_id'] = $row['report_id']; - } - $db->sql_freeresult($result); - } - - $pm_list = ($store_reverse) ? array_reverse($pm_list) : $pm_list; - - return array( - 'pm_count' => $pm_count, - 'pm_list' => $pm_list, - 'rowset' => $rowset - ); -} diff --git a/install/update/new/includes/ucp/ucp_profile.php b/install/update/new/includes/ucp/ucp_profile.php deleted file mode 100644 index dca7e7e..0000000 --- a/install/update/new/includes/ucp/ucp_profile.php +++ /dev/null @@ -1,847 +0,0 @@ - -* @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; -} - -/** -* ucp_profile -* Changing profile settings -* -* @todo what about pertaining user_sig_options? -*/ -class ucp_profile -{ - var $u_action; - - function main($id, $mode) - { - global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; - global $request, $phpbb_container, $phpbb_log, $phpbb_dispatcher; - - $user->add_lang('posting'); - - $submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST); - $error = $data = array(); - $s_hidden_fields = ''; - - switch ($mode) - { - case 'reg_details': - - $data = array( - '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), - ); - - /** - * Modify user registration data on editing account settings in UCP - * - * @event core.ucp_profile_reg_details_data - * @var array data Array with current or updated user registration data - * @var bool submit Flag indicating if submit button has been pressed - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_data', compact($vars))); - - add_form_key('ucp_reg_details'); - - if ($submit) - { - // Do not check cur_password, it is the old one. - $check_ary = array( - 'new_password' => array( - array('string', true, $config['min_pass_chars'], 0), - array('password')), - 'password_confirm' => array('string', true, $config['min_pass_chars'], 0), - 'email' => array( - array('string', false, 6, 60), - array('user_email')), - ); - - if ($auth->acl_get('u_chgname') && $config['allow_namechange']) - { - $check_ary['username'] = array( - array('string', false, $config['min_name_chars'], $config['max_name_chars']), - array('username'), - ); - } - - $error = validate_data($data, $check_ary); - - if ($auth->acl_get('u_chgpasswd') && $data['new_password'] && $data['password_confirm'] != $data['new_password']) - { - $error[] = ($data['password_confirm']) ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; - } - - // 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 (!count($error) && $auth->acl_get('u_chgpasswd') && $data['new_password'] && $passwords_manager->check($data['new_password'], $user->data['user_password'])) - { - $error[] = 'SAME_PASSWORD_ERROR'; - } - - if (!$passwords_manager->check($data['cur_password'], $user->data['user_password'])) - { - $error[] = ($data['cur_password']) ? 'CUR_PASSWORD_ERROR' : 'CUR_PASSWORD_EMPTY'; - } - - if (!check_form_key('ucp_reg_details')) - { - $error[] = 'FORM_INVALID'; - } - - /** - * Validate user data on editing registration data in UCP - * - * @event core.ucp_profile_reg_details_validate - * @var array data Array with user profile data - * @var bool submit Flag indicating if submit button has been pressed - * @var array error Array of any generated errors - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit', 'error'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_validate', compact($vars))); - - if (!count($error)) - { - $sql_ary = array( - 'username' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? $data['username'] : $user->data['username'], - 'username_clean' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? utf8_clean_string($data['username']) : $user->data['username_clean'], - 'user_email' => ($auth->acl_get('u_chgemail')) ? $data['email'] : $user->data['user_email'], - 'user_password' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? $passwords_manager->hash($data['new_password']) : $user->data['user_password'], - ); - - if ($auth->acl_get('u_chgname') && $config['allow_namechange'] && $data['username'] != $user->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(); - $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']) - { - $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'; - - if ($auth->acl_get('u_chgemail') && $config['email_enable'] && $data['email'] != $user->data['user_email'] && $user->data['user_type'] != USER_FOUNDER && ($config['require_activation'] == USER_ACTIVATION_SELF || $config['require_activation'] == USER_ACTIVATION_ADMIN)) - { - $message = ($config['require_activation'] == USER_ACTIVATION_SELF) ? 'ACCOUNT_EMAIL_CHANGED' : 'ACCOUNT_EMAIL_CHANGED_ADMIN'; - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $server_url = generate_board_url(); - - $user_actkey = gen_rand_string(mt_rand(6, 10)); - - $messenger = new messenger(false); - - $template_file = ($config['require_activation'] == USER_ACTIVATION_ADMIN) ? 'user_activate_inactive' : 'user_activate'; - $messenger->template($template_file, $user->data['user_lang']); - - $messenger->to($data['email'], $data['username']); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($data['username']), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user->data['user_id']}&k=$user_actkey") - ); - - $messenger->send(NOTIFY_EMAIL); - - if ($config['require_activation'] == USER_ACTIVATION_ADMIN) - { - $notifications_manager = $phpbb_container->get('notification_manager'); - $notifications_manager->add_notifications('notification.type.admin_activate_user', array( - 'user_id' => $user->data['user_id'], - 'user_actkey' => $user_actkey, - 'user_regdate' => time(), // Notification time - )); - } - - user_active_flip('deactivate', $user->data['user_id'], INACTIVE_PROFILE); - - // Because we want the profile to be reactivated we set user_newpasswd to empty (else the reactivation will fail) - $sql_ary['user_actkey'] = $user_actkey; - $sql_ary['user_newpasswd'] = ''; - } - - /** - * Modify user registration data before submitting it to the database - * - * @event core.ucp_profile_reg_details_sql_ary - * @var array data Array with current or updated user registration data - * @var array sql_ary Array with user registration data to submit to the database - * @since 3.1.4-RC1 - */ - $vars = array('data', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_sql_ary', compact($vars))); - - if (count($sql_ary)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . $user->data['user_id']; - $db->sql_query($sql); - } - - // Need to update config, forum, topic, posting, messages, etc. - if ($data['username'] != $user->data['username'] && $auth->acl_get('u_chgname') && $config['allow_namechange']) - { - user_update_name($user->data['username'], $data['username']); - } - - // Now, we can remove the user completely (kill the session) - NOT BEFORE!!! - if (!empty($sql_ary['user_actkey'])) - { - meta_refresh(5, append_sid($phpbb_root_path . 'index.' . $phpEx)); - $message = $user->lang[$message] . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - - // Because the user gets deactivated we log him out too, killing his session - $user->session_kill(); - } - else - { - meta_refresh(3, $this->u_action); - $message = $user->lang[$message] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - } - - trigger_error($message); - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $error) : '', - - 'USERNAME' => $data['username'], - 'EMAIL' => $data['email'], - 'PASSWORD_CONFIRM' => $data['password_confirm'], - 'NEW_PASSWORD' => $data['new_password'], - 'CUR_PASSWORD' => '', - - 'L_USERNAME_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars'])), - - 'S_FORCE_PASSWORD' => ($auth->acl_get('u_chgpasswd') && $config['chg_passforce'] && $user->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) ? true : false, - 'S_CHANGE_USERNAME' => ($config['allow_namechange'] && $auth->acl_get('u_chgname')) ? true : false, - 'S_CHANGE_EMAIL' => ($auth->acl_get('u_chgemail')) ? true : false, - 'S_CHANGE_PASSWORD' => ($auth->acl_get('u_chgpasswd')) ? true : false) - ); - break; - - case 'profile_info': - // 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' => $request->variable('jabber', $user->data['user_jabber'], true), - ); - - if ($config['allow_birthdays']) - { - $data['bday_day'] = $data['bday_month'] = $data['bday_year'] = 0; - - if ($user->data['user_birthday']) - { - list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user->data['user_birthday']); - } - - $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']); - } - - /** - * Modify user data on editing profile in UCP - * - * @event core.ucp_profile_modify_profile_info - * @var array data Array with user profile data - * @var bool submit Flag indicating if submit button has been pressed - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_profile_info', compact($vars))); - - add_form_key('ucp_profile_info'); - - if ($submit) - { - $validate_array = array( - 'jabber' => array( - array('string', true, 5, 255), - array('jabber')), - ); - - if ($config['allow_birthdays']) - { - $validate_array = array_merge($validate_array, array( - 'bday_day' => array('num', true, 1, 31), - 'bday_month' => array('num', true, 1, 12), - 'bday_year' => array('num', true, 1901, gmdate('Y', time()) + 50), - 'user_birthday' => array('date', true), - )); - } - - $error = validate_data($data, $validate_array); - - // validate custom profile fields - $cp->submit_cp_field('profile', $user->get_iso_lang_id(), $cp_data, $cp_error); - - if (count($cp_error)) - { - $error = array_merge($error, $cp_error); - } - - if (!check_form_key('ucp_profile_info')) - { - $error[] = 'FORM_INVALID'; - } - - /** - * Validate user data on editing profile in UCP - * - * @event core.ucp_profile_validate_profile_info - * @var array data Array with user profile data - * @var bool submit Flag indicating if submit button has been pressed - * @var array error Array of any generated errors - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit', 'error'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_validate_profile_info', compact($vars))); - - if (!count($error)) - { - $data['notify'] = $user->data['user_notify_type']; - - if ($data['notify'] == NOTIFY_IM && (!$config['jab_enable'] || !$data['jabber'] || !@extension_loaded('xml'))) - { - // User has not filled in a jabber address (Or one of the modules is disabled or jabber is disabled) - // Disable notify by Jabber now for this user. - $data['notify'] = NOTIFY_EMAIL; - } - - $sql_ary = array( - 'user_jabber' => $data['jabber'], - 'user_notify_type' => $data['notify'], - ); - - if ($config['allow_birthdays']) - { - $sql_ary['user_birthday'] = $data['user_birthday']; - } - - /** - * Modify profile data in UCP before submitting to the database - * - * @event core.ucp_profile_info_modify_sql_ary - * @var array cp_data Array with the user custom profile fields data - * @var array data Array with user profile data - * @var array sql_ary user options data we update - * @since 3.1.4-RC1 - */ - $vars = array('cp_data', 'data', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_info_modify_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); - - // Update Custom Fields - $cp->update_profile_field_data($user->data['user_id'], $cp_data); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PROFILE_UPDATED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - if ($config['allow_birthdays']) - { - $s_birthday_day_options = ''; - for ($i = 1; $i < 32; $i++) - { - $selected = ($i == $data['bday_day']) ? ' selected="selected"' : ''; - $s_birthday_day_options .= ""; - } - - $s_birthday_month_options = ''; - for ($i = 1; $i < 13; $i++) - { - $selected = ($i == $data['bday_month']) ? ' selected="selected"' : ''; - $s_birthday_month_options .= ""; - } - - $now = getdate(); - $s_birthday_year_options = ''; - for ($i = $now['year'] - 100; $i <= $now['year']; $i++) - { - $selected = ($i == $data['bday_year']) ? ' selected="selected"' : ''; - $s_birthday_year_options .= ""; - } - unset($now); - - $template->assign_vars(array( - 'S_BIRTHDAY_DAY_OPTIONS' => $s_birthday_day_options, - 'S_BIRTHDAY_MONTH_OPTIONS' => $s_birthday_month_options, - 'S_BIRTHDAY_YEAR_OPTIONS' => $s_birthday_year_options, - 'S_BIRTHDAYS_ENABLED' => true, - )); - } - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $error) : '', - 'S_JABBER_ENABLED' => $config['jab_enable'], - 'JABBER' => $data['jabber'], - )); - - // Get additional profile fields and assign them to the template block var 'profile_fields' - $user->get_profile_fields($user->data['user_id']); - - $cp->generate_profile_fields('profile', $user->get_iso_lang_id()); - - break; - - case 'signature': - - if (!$auth->acl_get('u_sig')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_SIGNATURE'); - } - - 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']) ? $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; - - $bbcode_flags = ($enable_bbcode ? OPTION_FLAG_BBCODE : 0) + ($enable_smilies ? OPTION_FLAG_SMILIES : 0) + ($enable_urls ? OPTION_FLAG_LINKS : 0); - - $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) - { - $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'; - } - } - - /** - * 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 (!$submit) - { - // Parse it for displaying - $signature_preview = generate_text_for_display($signature, $bbcode_uid, $bbcode_bitfield, $bbcode_flags); - } - else - { - if (!count($error)) - { - $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 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); - - $message = $user->lang['PROFILE_UPDATED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - - if ($request->is_set_post('preview')) - { - $decoded_message = generate_text_for_edit($signature, $bbcode_uid, $bbcode_flags); - } - - /** @var \phpbb\controller\helper $controller_helper */ - $controller_helper = $phpbb_container->get('controller.helper'); - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $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' => $user->lang(($config['allow_sig_bbcode'] ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '', ''), - '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'], - 'URL_STATUS' => ($config['allow_sig_links']) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], - 'MAX_FONT_SIZE' => (int) $config['max_sig_font_size'], - - 'L_SIGNATURE_EXPLAIN' => $user->lang('SIGNATURE_EXPLAIN', (int) $config['max_sig_chars']), - - 'S_BBCODE_ALLOWED' => $config['allow_sig_bbcode'], - 'S_SMILIES_ALLOWED' => $config['allow_sig_smilies'], - 'S_BBCODE_IMG' => ($config['allow_sig_img']) ? true : false, - 'S_BBCODE_FLASH' => ($config['allow_sig_flash']) ? true : false, - 'S_LINKS_ALLOWED' => ($config['allow_sig_links']) ? true : false) - ); - - add_form_key('ucp_sig'); - - // Build custom bbcodes array - display_custom_bbcodes(); - - // Generate smiley listing - generate_smilies('inline', 0); - - break; - - case 'avatar': - - add_form_key('ucp_avatar'); - - $avatars_enabled = false; - - 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(); - - // This is normalised data, without the user_ prefix - $avatar_data = \phpbb\avatar\manager::clean_row($user->data, 'user'); - - if ($submit) - { - if (check_form_key('ucp_avatar')) - { - $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); - - if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) - { - $driver = $phpbb_avatar_manager->get_driver($driver_name); - $result = $driver->process_form($request, $template, $user, $avatar_data, $error); - - if ($result && empty($error)) - { - // Success! Lets save the result in the database - $result = array( - 'user_avatar_type' => $driver_name, - 'user_avatar' => $result['avatar'], - 'user_avatar_width' => $result['avatar_width'], - 'user_avatar_height' => $result['avatar_height'], - ); - - /** - * Trigger events on successfull avatar change - * - * @event core.ucp_profile_avatar_sql - * @var array result Array with data to be stored in DB - * @since 3.1.11-RC1 - */ - $vars = array('result'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_avatar_sql', compact($vars))); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $result) . ' - WHERE user_id = ' . (int) $user->data['user_id']; - $db->sql_query($sql); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PROFILE_UPDATED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - } - } - else - { - $error[] = 'FORM_INVALID'; - } - } - - // Handle deletion of avatars - if ($request->is_set_post('avatar_delete')) - { - if (!confirm_box(true)) - { - confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( - 'avatar_delete' => true, - 'i' => $id, - 'mode' => $mode)) - ); - } - else - { - $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, USERS_TABLE, 'user_'); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PROFILE_UPDATED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - } - - $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user->data['user_avatar_type'])); - - $template->assign_vars(array( - 'AVATAR_MIN_WIDTH' => $config['avatar_min_width'], - 'AVATAR_MAX_WIDTH' => $config['avatar_max_width'], - 'AVATAR_MIN_HEIGHT' => $config['avatar_min_height'], - 'AVATAR_MAX_HEIGHT' => $config['avatar_max_height'], - )); - - foreach ($avatar_drivers as $current_driver) - { - $driver = $phpbb_avatar_manager->get_driver($current_driver); - - $avatars_enabled = true; - $template->set_filenames(array( - 'avatar' => $driver->get_template_name(), - )); - - if ($driver->prepare_form($request, $template, $user, $avatar_data, $error)) - { - $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); - $driver_upper = strtoupper($driver_name); - - $template->assign_block_vars('avatar_drivers', array( - 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), - 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), - - 'DRIVER' => $driver_name, - 'SELECTED' => $current_driver == $selected_driver, - 'OUTPUT' => $template->assign_display('avatar'), - )); - } - } - - // Replace "error" strings with their real, localised form - $error = $phpbb_avatar_manager->localize_errors($user, $error); - } - - $avatar = phpbb_get_user_avatar($user->data, 'USER_AVATAR', true); - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $error) : '', - 'AVATAR' => $avatar, - - 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', - - 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(), - - 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled), - )); - - break; - - case 'autologin_keys': - - add_form_key('ucp_autologin_keys'); - - if ($submit) - { - $keys = $request->variable('keys', array('')); - - if (!check_form_key('ucp_autologin_keys')) - { - $error[] = 'FORM_INVALID'; - } - - if (!count($error)) - { - if (!empty($keys)) - { - foreach ($keys as $key => $id) - { - $keys[$key] = $db->sql_like_expression($id . $db->get_any_char()); - } - $sql_where = '(key_id ' . implode(' OR key_id ', $keys) . ')'; - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $user->data['user_id'] . ' - AND ' . $sql_where ; - - $db->sql_query($sql); - - meta_refresh(3, $this->u_action); - $message = $user->lang['AUTOLOGIN_SESSION_KEYS_DELETED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - $sql = 'SELECT key_id, last_ip, last_login - FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $user->data['user_id'] . ' - ORDER BY last_login ASC'; - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('sessions', array( - 'KEY' => substr($row['key_id'], 0, 8), - 'IP' => $row['last_ip'], - 'LOGIN_TIME' => $user->format_date($row['last_login']), - )); - } - - $db->sql_freeresult($result); - - break; - } - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $error) : '', - - 'L_TITLE' => $user->lang['UCP_PROFILE_' . strtoupper($mode)], - - 'S_HIDDEN_FIELDS' => $s_hidden_fields, - 'S_UCP_ACTION' => $this->u_action) - ); - - // Set desired template - $this->tpl_name = 'ucp_profile_' . $mode; - $this->page_title = 'UCP_PROFILE_' . strtoupper($mode); - } -} diff --git a/install/update/new/includes/ucp/ucp_register.php b/install/update/new/includes/ucp/ucp_register.php deleted file mode 100644 index 00fa803..0000000 --- a/install/update/new/includes/ucp/ucp_register.php +++ /dev/null @@ -1,738 +0,0 @@ - -* @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; -} - -/** -* ucp_register -* Board registration -*/ -class ucp_register -{ - var $u_action; - - function main($id, $mode) - { - global $config, $db, $user, $template, $phpbb_root_path, $phpEx; - global $request, $phpbb_container, $phpbb_dispatcher; - - // - if ($config['require_activation'] == USER_ACTIVATION_DISABLE || - (in_array($config['require_activation'], array(USER_ACTIVATION_SELF, USER_ACTIVATION_ADMIN)) && !$config['email_enable'])) - { - trigger_error('UCP_REGISTER_DISABLE'); - } - - $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->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 - * - * To assign data to the template, use $template->assign_vars() - * - * @event core.ucp_register_requests_after - * @var bool coppa Is set coppa - * @var bool agreed Did user agree to coppa? - * @var bool submit Is set post submit? - * @var string change_lang Change language request - * @var string user_lang User language request - * @since 3.1.11-RC1 - */ - $vars = array( - 'coppa', - 'agreed', - 'submit', - 'change_lang', - 'user_lang', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_register_requests_after', compact($vars))); - - add_form_key('ucp_register'); - - if ($change_lang || $user_lang != $config['default_lang']) - { - $use_lang = ($change_lang) ? basename($change_lang) : basename($user_lang); - - if (!validate_language_iso_name($use_lang)) - { - if ($change_lang) - { - $submit = false; - - // Setting back agreed to let the user view the agreement in his/her language - $agreed = false; - } - - $user_lang = $use_lang; - } - else - { - $change_lang = ''; - $user_lang = $user->lang_name; - } - } - - /* @var $cp \phpbb\profilefields\manager */ - $cp = $phpbb_container->get('profilefields.manager'); - - $error = $cp_data = $cp_error = array(); - $s_hidden_fields = array(); - - // Handle login_link data added to $_hidden_fields - $login_link_data = $this->get_login_link_data_array(); - - 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', '')); - - $result = $auth_provider->login_link_has_necessary_data($login_link_data); - if ($result !== null) - { - $error[] = $user->lang[$result]; - } - - $s_hidden_fields = array_merge($s_hidden_fields, $this->get_login_link_data_for_hidden_fields($login_link_data)); - } - - if (!$agreed || ($coppa === false && $config['coppa_enable']) || ($coppa && !$config['coppa_enable'])) - { - $add_coppa = ($coppa !== false) ? '&coppa=' . $coppa : ''; - - $s_hidden_fields = array_merge($s_hidden_fields, array( - 'change_lang' => '', - )); - - // If we change the language, we want to pass on some more possible parameter. - if ($change_lang) - { - // We do not include the password - $s_hidden_fields = array_merge($s_hidden_fields, array( - 'username' => $request->variable('username', '', true), - 'email' => strtolower($request->variable('email', '')), - 'lang' => $user->lang_name, - 'tz' => $request->variable('tz', $config['board_timezone']), - )); - - } - - // Checking amount of available languages - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE; - $result = $db->sql_query($sql); - - $lang_row = array(); - while ($row = $db->sql_fetchrow($result)) - { - $lang_row[] = $row; - } - $db->sql_freeresult($result); - - if ($coppa === false && $config['coppa_enable']) - { - $now = getdate(); - $coppa_birthday = $user->create_datetime() - ->setDate($now['year'] - 13, $now['mon'], $now['mday'] - 1) - ->setTime(0, 0, 0) - ->format($user->lang['DATE_FORMAT'], true); - unset($now); - - $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), - 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), - - 'COOKIE_NAME' => $config['cookie_name'], - 'COOKIE_PATH' => $config['cookie_path'], - ); - } - else - { - $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, - 'S_REGISTRATION' => true, - 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_coppa), - - '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. - * - * To assign data to the template, use $template->assign_vars() - * - * @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 = $tpl_name; - return; - } - - // The CAPTCHA kicks in here. We can't help that the information gets lost on language change. - if ($config['enable_confirm']) - { - $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); - $captcha->init(CONFIRM_REG); - } - - $timezone = $config['board_timezone']; - - $data = array( - 'username' => $request->variable('username', '', true), - 'new_password' => $request->variable('new_password', '', true), - 'password_confirm' => $request->variable('password_confirm', '', true), - '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 - * - * To assign data to the template, use $template->assign_vars() - * - * @event core.ucp_register_data_before - * @var bool submit Do we display the form only - * or did the user press submit - * @var array data Array with current ucp registration data - * @since 3.1.4-RC1 - */ - $vars = array('submit', 'data'); - extract($phpbb_dispatcher->trigger_event('core.ucp_register_data_before', compact($vars))); - - // Check and initialize some variables if needed - if ($submit) - { - $error = validate_data($data, array( - 'username' => array( - array('string', false, $config['min_name_chars'], $config['max_name_chars']), - array('username', '')), - 'new_password' => array( - array('string', false, $config['min_pass_chars'], 0), - array('password')), - 'password_confirm' => array('string', false, $config['min_pass_chars'], 0), - 'email' => array( - array('string', false, 6, 60), - array('user_email')), - 'tz' => array('timezone'), - 'lang' => array('language_iso_name'), - )); - - if (!check_form_key('ucp_register')) - { - $error[] = $user->lang['FORM_INVALID']; - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - - if ($config['enable_confirm']) - { - $vc_response = $captcha->validate($data); - if ($vc_response !== false) - { - $error[] = $vc_response; - } - - if ($config['max_reg_attempts'] && $captcha->get_attempt_count() > $config['max_reg_attempts']) - { - $error[] = $user->lang['TOO_MANY_REGISTERS']; - } - } - - // DNSBL check - if ($config['check_dnsbl']) - { - if (($dnsbl = $user->check_dnsbl('register')) !== false) - { - $error[] = sprintf($user->lang['IP_BLACKLISTED'], $user->ip, $dnsbl[1]); - } - } - - // validate custom profile fields - $cp->submit_cp_field('register', $user->get_iso_lang_id(), $cp_data, $error); - - if (!count($error)) - { - if ($data['new_password'] != $data['password_confirm']) - { - $error[] = $user->lang['NEW_PASSWORD_ERROR']; - } - } - /** - * Check UCP registration data after they are submitted - * - * @event core.ucp_register_data_after - * @var bool submit Do we display the form only - * or did the user press submit - * @var array data Array with current ucp registration data - * @var array cp_data Array with custom profile fields data - * @var array error Array with list of errors - * @since 3.1.4-RC1 - */ - $vars = array('submit', 'data', 'cp_data', 'error'); - extract($phpbb_dispatcher->trigger_event('core.ucp_register_data_after', compact($vars))); - - if (!count($error)) - { - $server_url = generate_board_url(); - - // Which group by default? - $group_name = ($coppa) ? 'REGISTERED_COPPA' : 'REGISTERED'; - - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $db->sql_escape($group_name) . "' - AND group_type = " . GROUP_SPECIAL; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_GROUP'); - } - - $group_id = $row['group_id']; - - if (($coppa || - $config['require_activation'] == USER_ACTIVATION_SELF || - $config['require_activation'] == USER_ACTIVATION_ADMIN) && $config['email_enable']) - { - $user_actkey = gen_rand_string(mt_rand(6, 10)); - $user_type = USER_INACTIVE; - $user_inactive_reason = INACTIVE_REGISTER; - $user_inactive_time = time(); - } - else - { - $user_type = USER_NORMAL; - $user_actkey = ''; - $user_inactive_reason = 0; - $user_inactive_time = 0; - } - - // Instantiate passwords manager - /* @var $passwords_manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('passwords.manager'); - - $user_row = array( - 'username' => $data['username'], - 'user_password' => $passwords_manager->hash($data['new_password']), - 'user_email' => $data['email'], - 'group_id' => (int) $group_id, - 'user_timezone' => $data['tz'], - 'user_lang' => $data['lang'], - 'user_type' => $user_type, - 'user_actkey' => $user_actkey, - 'user_ip' => $user->ip, - 'user_regdate' => time(), - 'user_inactive_reason' => $user_inactive_reason, - 'user_inactive_time' => $user_inactive_time, - ); - - if ($config['new_member_post_limit']) - { - $user_row['user_new'] = 1; - } - /** - * Add into $user_row before user_add - * - * user_add allows adding more data into the users table - * - * @event core.ucp_register_user_row_after - * @var bool submit Do we display the form only - * or did the user press submit - * @var array cp_data Array with custom profile fields data - * @var array user_row Array with current ucp registration data - * @since 3.1.4-RC1 - */ - $vars = array('submit', 'cp_data', 'user_row'); - extract($phpbb_dispatcher->trigger_event('core.ucp_register_user_row_after', compact($vars))); - - // Register user... - $user_id = user_add($user_row, $cp_data); - - // This should not happen, because the required variables are listed above... - if ($user_id === false) - { - trigger_error('NO_USER', E_USER_ERROR); - } - - // Okay, captcha, your job is done. - if ($config['enable_confirm'] && isset($captcha)) - { - $captcha->reset(); - } - - if ($coppa && $config['email_enable']) - { - $message = $user->lang['ACCOUNT_COPPA']; - $email_template = 'coppa_welcome_inactive'; - } - else if ($config['require_activation'] == USER_ACTIVATION_SELF && $config['email_enable']) - { - $message = $user->lang['ACCOUNT_INACTIVE']; - $email_template = 'user_welcome_inactive'; - } - else if ($config['require_activation'] == USER_ACTIVATION_ADMIN && $config['email_enable']) - { - $message = $user->lang['ACCOUNT_INACTIVE_ADMIN']; - $email_template = 'admin_welcome_inactive'; - } - else - { - $message = $user->lang['ACCOUNT_ADDED']; - $email_template = 'user_welcome'; - - // Autologin after registration - $user->session_create($user_id, 0, false, 1); - } - - if ($config['email_enable']) - { - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $messenger = new messenger(false); - - $messenger->template($email_template, $data['lang']); - - $messenger->to($data['email'], $data['username']); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), - 'USERNAME' => htmlspecialchars_decode($data['username']), - 'PASSWORD' => htmlspecialchars_decode($data['new_password']), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey") - ); - - if ($coppa) - { - $messenger->assign_vars(array( - 'FAX_INFO' => $config['coppa_fax'], - 'MAIL_INFO' => $config['coppa_mail'], - 'EMAIL_ADDRESS' => $data['email']) - ); - } - - /** - * 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, - 'user_actkey' => $user_row['user_actkey'], - 'user_regdate' => $user_row['user_regdate'], - )); - } - - // Perform account linking if necessary - if (!empty($login_link_data)) - { - $login_link_data['user_id'] = $user_id; - - $result = $auth_provider->link_account($login_link_data); - - if ($result) - { - $message = $message . '

' . $user->lang[$result]; - } - } - - /** - * 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 . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - trigger_error($message); - } - } - - $s_hidden_fields = array_merge($s_hidden_fields, array( - 'agreed' => 'true', - 'change_lang' => 0, - )); - - if ($config['coppa_enable']) - { - $s_hidden_fields['coppa'] = $coppa; - } - - if ($config['enable_confirm']) - { - $s_hidden_fields = array_merge($s_hidden_fields, $captcha->get_hidden_fields()); - } - - // Visual Confirmation - Show images - if ($config['enable_confirm']) - { - $template->assign_vars(array( - 'CAPTCHA_TEMPLATE' => $captcha->get_template(), - )); - } - - // - $l_reg_cond = ''; - switch ($config['require_activation']) - { - case USER_ACTIVATION_SELF: - $l_reg_cond = $user->lang['UCP_EMAIL_ACTIVATE']; - break; - - case USER_ACTIVATION_ADMIN: - $l_reg_cond = $user->lang['UCP_ADMIN_ACTIVATE']; - break; - } - - /* @var $provider_collection \phpbb\auth\provider_collection */ - $provider_collection = $phpbb_container->get('auth.provider_collection'); - $auth_provider = $provider_collection->get_provider(); - - $auth_provider_data = $auth_provider->get_login_data(); - if ($auth_provider_data) - { - if (isset($auth_provider_data['VARS'])) - { - $template->assign_vars($auth_provider_data['VARS']); - } - - if (isset($auth_provider_data['BLOCK_VAR_NAME'])) - { - foreach ($auth_provider_data['BLOCK_VARS'] as $block_vars) - { - $template->assign_block_vars($auth_provider_data['BLOCK_VAR_NAME'], $block_vars); - } - } - - $template->assign_vars(array( - 'PROVIDER_TEMPLATE_FILE' => $auth_provider_data['TEMPLATE_FILE'], - )); - } - - // 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'], - 'EMAIL' => $data['email'], - - 'L_REG_COND' => $l_reg_cond, - 'L_USERNAME_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars'])), - - 'S_LANG_OPTIONS' => language_select($data['lang']), - 'S_TZ_PRESELECT' => !$submit, - 'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false, - 'S_REGISTRATION' => true, - 'S_COPPA' => $coppa, - '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('
', $error) : '', - 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - )); - - $template->assign_vars($template_vars); - - // - $user->profile_fields = array(); - - // Generate profile fields -> Template Block Variable profile_fields - $cp->generate_profile_fields('register', $user->get_iso_lang_id()); - - // - $this->tpl_name = $tpl_name; - } - - /** - * Creates the login_link data array - * - * @return array Returns an array of all POST paramaters whose names - * begin with 'login_link_' - */ - protected function get_login_link_data_array() - { - global $request; - - $var_names = $request->variable_names(\phpbb\request\request_interface::POST); - $login_link_data = array(); - $string_start_length = strlen('login_link_'); - - foreach ($var_names as $var_name) - { - if (strpos($var_name, 'login_link_') === 0) - { - $key_name = substr($var_name, $string_start_length); - $login_link_data[$key_name] = $request->variable($var_name, '', false, \phpbb\request\request_interface::POST); - } - } - - return $login_link_data; - } - - /** - * Prepends they key names of an associative array with 'login_link_' for - * inclusion on the page as hidden fields. - * - * @param array $data The array to be modified - * @return array The modified array - */ - protected function get_login_link_data_for_hidden_fields($data) - { - $new_data = array(); - - foreach ($data as $key => $value) - { - $new_data['login_link_' . $key] = $value; - } - - return $new_data; - } -} diff --git a/install/update/new/includes/ucp/ucp_resend.php b/install/update/new/includes/ucp/ucp_resend.php deleted file mode 100644 index 5592366..0000000 --- a/install/update/new/includes/ucp/ucp_resend.php +++ /dev/null @@ -1,163 +0,0 @@ - -* @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; -} - -/** -* ucp_resend -* Resending activation emails -*/ -class ucp_resend -{ - var $u_action; - - function main($id, $mode) - { - global $config, $phpbb_root_path, $phpEx; - global $db, $user, $auth, $template, $request; - - $username = $request->variable('username', '', true); - $email = strtolower($request->variable('email', '')); - $submit = (isset($_POST['submit'])) ? true : false; - - add_form_key('ucp_resend'); - - if ($submit) - { - if (!check_form_key('ucp_resend')) - { - trigger_error('FORM_INVALID'); - } - - $sql = 'SELECT user_id, group_id, username, user_email, user_type, user_lang, user_actkey, user_inactive_reason - FROM ' . USERS_TABLE . " - WHERE user_email = '" . $db->sql_escape($email) . "' - AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error('NO_EMAIL_USER'); - } - - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error('NO_USER'); - } - - if (!$user_row['user_actkey'] && $user_row['user_type'] != USER_INACTIVE) - { - trigger_error('ACCOUNT_ALREADY_ACTIVATED'); - } - - if (!$user_row['user_actkey'] || ($user_row['user_type'] == USER_INACTIVE && $user_row['user_inactive_reason'] == INACTIVE_MANUAL)) - { - trigger_error('ACCOUNT_DEACTIVATED'); - } - - // Determine coppa status on group (REGISTERED(_COPPA)) - $sql = 'SELECT group_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . $user_row['group_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_GROUP'); - } - - $coppa = ($row['group_name'] == 'REGISTERED_COPPA' && $row['group_type'] == GROUP_SPECIAL) ? true : false; - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $messenger = new messenger(false); - - if ($config['require_activation'] == USER_ACTIVATION_SELF || $coppa) - { - $messenger->template(($coppa) ? 'coppa_resend_inactive' : 'user_resend_inactive', $user_row['user_lang']); - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}") - ); - - if ($coppa) - { - $messenger->assign_vars(array( - 'FAX_INFO' => $config['coppa_fax'], - 'MAIL_INFO' => $config['coppa_mail'], - 'EMAIL_ADDRESS' => $user_row['user_email']) - ); - } - - $messenger->send(NOTIFY_EMAIL); - } - - if ($config['require_activation'] == USER_ACTIVATION_ADMIN) - { - // Grab an array of user_id's with a_user permissions ... these users can activate a user - $admin_ary = $auth->acl_get_list(false, 'a_user', false); - - $sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $admin_ary[0]['a_user']); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $messenger->template('admin_activate', $row['user_lang']); - $messenger->set_addresses($row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_USER_DETAILS' => generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$user_row['user_id']}", - 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}") - ); - - $messenger->send($row['user_notify_type']); - } - $db->sql_freeresult($result); - } - - meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx")); - - $message = ($config['require_activation'] == USER_ACTIVATION_ADMIN) ? $user->lang['ACTIVATION_EMAIL_SENT_ADMIN'] : $user->lang['ACTIVATION_EMAIL_SENT']; - $message .= '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - trigger_error($message); - } - - $template->assign_vars(array( - 'USERNAME' => $username, - 'EMAIL' => $email, - 'S_PROFILE_ACTION' => append_sid($phpbb_root_path . 'ucp.' . $phpEx, 'mode=resend_act')) - ); - - $this->tpl_name = 'ucp_resend'; - $this->page_title = 'UCP_RESEND'; - } -} diff --git a/install/update/new/includes/utf/utf_tools.php b/install/update/new/includes/utf/utf_tools.php deleted file mode 100644 index bb155ae..0000000 --- a/install/update/new/includes/utf/utf_tools.php +++ /dev/null @@ -1,1469 +0,0 @@ - -* @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; -} - -// Enforce ASCII only string handling -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 -* extensions, otherwise they will default to custom routines. -* -*/ - -/** -* 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) -{ - if (is_null($offset)) - { - return mb_strpos($str, $needle); - } - else - { - return mb_strpos($str, $needle, $offset); - } -} - -/** -* UTF-8 aware alternative to strtolower -* @ignore -*/ -function utf8_strtolower($str) -{ - return mb_strtolower($str); -} - -/** -* UTF-8 aware alternative to strtoupper -* @ignore -*/ -function utf8_strtoupper($str) -{ - return mb_strtoupper($str); -} - -/** -* UTF-8 aware alternative to substr -* @ignore -*/ -function utf8_substr($str, $offset, $length = null) -{ - if (is_null($length)) - { - return mb_substr($str, $offset); - } - else - { - return mb_substr($str, $offset, $length); - } -} - -/** -* Return the length (in characters) of a UTF-8 string -* @ignore -*/ -function utf8_strlen($text) -{ - return mb_strlen($text, 'utf-8'); -} - -/** -* UTF-8 aware alternative to str_split -* Convert a string to an array -* -* @author Harry Fuecks -* @param string $str UTF-8 encoded -* @param int $split_len number to characters to split string by -* @return array characters in string reverses -*/ -function utf8_str_split($str, $split_len = 1) -{ - if (!is_int($split_len) || $split_len < 1) - { - return false; - } - - $len = utf8_strlen($str); - if ($len <= $split_len) - { - return array($str); - } - - preg_match_all('/.{' . $split_len . '}|[^\x00]{1,' . $split_len . '}$/us', $str, $ar); - return $ar[0]; -} - -/** -* UTF-8 aware alternative to strspn -* Find length of initial segment matching the mask -* -* @author Harry Fuecks -*/ -function utf8_strspn($str, $mask, $start = null, $length = null) -{ - if ($start !== null || $length !== null) - { - $str = utf8_substr($str, $start, $length); - } - - preg_match('/^[' . $mask . ']+/u', $str, $matches); - - if (isset($matches[0])) - { - return utf8_strlen($matches[0]); - } - - return 0; -} - -/** -* UTF-8 aware alternative to ucfirst -* Make a string's first character uppercase -* -* @author Harry Fuecks -* @param string -* @return string with first character as upper case (if applicable) -*/ -function utf8_ucfirst($str) -{ - switch (utf8_strlen($str)) - { - case 0: - return ''; - break; - - case 1: - return utf8_strtoupper($str); - break; - - default: - preg_match('/^(.{1})(.*)$/us', $str, $matches); - return utf8_strtoupper($matches[1]) . $matches[2]; - break; - } -} - -/** -* Recode a string to UTF-8 -* -* If the encoding is not supported, the string is returned as-is -* -* @param string $string Original string -* @param string $encoding Original encoding (lowered) -* @return string The string, encoded in UTF-8 -*/ -function utf8_recode($string, $encoding) -{ - $encoding = strtolower($encoding); - - if ($encoding == 'utf-8' || !is_string($string) || empty($string)) - { - return $string; - } - - // we force iso-8859-1 to be cp1252 - if ($encoding == 'iso-8859-1') - { - $encoding = 'cp1252'; - } - // convert iso-8859-8-i to iso-8859-8 - else if ($encoding == 'iso-8859-8-i') - { - $encoding = 'iso-8859-8'; - $string = hebrev($string); - } - - // First, try iconv() - if (function_exists('iconv')) - { - $ret = @iconv($encoding, 'utf-8', $string); - - if (!empty($ret)) - { - return $ret; - } - } - - // Try the mb_string extension - if (function_exists('mb_convert_encoding')) - { - // mbstring is nasty on PHP4, we must make *sure* that we send a good encoding - switch ($encoding) - { - case 'iso-8859-1': - case 'iso-8859-2': - case 'iso-8859-4': - case 'iso-8859-7': - case 'iso-8859-9': - case 'iso-8859-15': - case 'windows-1251': - case 'windows-1252': - case 'cp1252': - case 'shift_jis': - case 'euc-kr': - case 'big5': - case 'gb2312': - $ret = @mb_convert_encoding($string, 'utf-8', $encoding); - - if (!empty($ret)) - { - return $ret; - } - } - } - - // Try the recode extension - if (function_exists('recode_string')) - { - $ret = @recode_string($encoding . '..utf-8', $string); - - if (!empty($ret)) - { - return $ret; - } - } - - // If nothing works, check if we have a custom transcoder available - if (!preg_match('#^[a-z0-9_ \\-]+$#', $encoding)) - { - // Make sure the encoding name is alphanumeric, we don't want it to be abused into loading arbitrary files - trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); - } - - global $phpbb_root_path, $phpEx; - - // iso-8859-* character encoding - if (preg_match('/iso[_ -]?8859[_ -]?(\\d+)/', $encoding, $array)) - { - switch ($array[1]) - { - case '1': - case '2': - case '4': - case '7': - case '8': - case '9': - case '15': - if (!function_exists('iso_8859_' . $array[1])) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx)) - { - trigger_error('Basic reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx); - } - return call_user_func('iso_8859_' . $array[1], $string); - break; - - default: - trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); - break; - } - } - - // CP/WIN character encoding - if (preg_match('/(?:cp|windows)[_\- ]?(\\d+)/', $encoding, $array)) - { - switch ($array[1]) - { - case '932': - break; - case '1250': - case '1251': - case '1252': - case '1254': - case '1255': - case '1256': - case '1257': - case '874': - if (!function_exists('cp' . $array[1])) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx)) - { - trigger_error('Basic reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx); - } - return call_user_func('cp' . $array[1], $string); - break; - - default: - trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); - break; - } - } - - // TIS-620 - if (preg_match('/tis[_ -]?620/', $encoding)) - { - if (!function_exists('tis_620')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx)) - { - trigger_error('Basic reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx); - } - return tis_620($string); - } - - // SJIS - if (preg_match('/sjis(?:[_ -]?win)?|(?:cp|ibm)[_ -]?932|shift[_ -]?jis/', $encoding)) - { - if (!function_exists('sjis')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx)) - { - trigger_error('CJK reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx); - } - return sjis($string); - } - - // EUC_KR - if (preg_match('/euc[_ -]?kr/', $encoding)) - { - if (!function_exists('euc_kr')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx)) - { - trigger_error('CJK reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx); - } - return euc_kr($string); - } - - // BIG-5 - if (preg_match('/big[_ -]?5/', $encoding)) - { - if (!function_exists('big5')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx)) - { - trigger_error('CJK reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx); - } - return big5($string); - } - - // GB2312 - if (preg_match('/gb[_ -]?2312/', $encoding)) - { - if (!function_exists('gb2312')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx)) - { - trigger_error('CJK reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx); - } - return gb2312($string); - } - - // Trigger an error?! Fow now just give bad data :-( - trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); -} - -/** - * 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 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]) . ';'; -} - -/** -* Converts a UTF-8 char to an NCR -* -* @param string $chr UTF-8 char -* @return integer UNICODE code point -*/ -function utf8_ord($chr) -{ - switch (strlen($chr)) - { - case 1: - return ord($chr); - break; - - case 2: - return ((ord($chr[0]) & 0x1F) << 6) | (ord($chr[1]) & 0x3F); - break; - - case 3: - return ((ord($chr[0]) & 0x0F) << 12) | ((ord($chr[1]) & 0x3F) << 6) | (ord($chr[2]) & 0x3F); - break; - - case 4: - return ((ord($chr[0]) & 0x07) << 18) | ((ord($chr[1]) & 0x3F) << 12) | ((ord($chr[2]) & 0x3F) << 6) | (ord($chr[3]) & 0x3F); - break; - - default: - return $chr; - } -} - -/** -* Converts an NCR to a UTF-8 char -* -* @param int $cp UNICODE code point -* @return string UTF-8 char -*/ -function utf8_chr($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); - } -} - -/** -* Convert Numeric Character References to UTF-8 chars -* -* Notes: -* - we do not convert NCRs recursively, if you pass &#38; it will return & -* - we DO NOT check for the existence of the Unicode characters, therefore an entity may be converted to an inexistent codepoint -* -* @param string $text String to convert, encoded in UTF-8 (no normal form required) -* @return string UTF-8 string where NCRs have been replaced with the actual chars -*/ -function utf8_decode_ncr($text) -{ - return preg_replace_callback('/&#([0-9]{1,6}|x[0-9A-F]{1,5});/i', 'utf8_decode_ncr_callback', $text); -} - -/** -* Callback used in decode_ncr() -* -* Takes a NCR (in decimal or hexadecimal) and returns a UTF-8 char. Attention, $m is an array. -* It will ignore most of invalid NCRs, but not all! -* -* @param array $m 0-based numerically indexed array passed by preg_replace_callback() -* @return string UTF-8 char -*/ -function utf8_decode_ncr_callback($m) -{ - $cp = (strncasecmp($m[1], 'x', 1)) ? $m[1] : hexdec(substr($m[1], 1)); - - return utf8_chr($cp); -} - -/** -* Case folds a unicode string as per Unicode 5.0, section 3.13 -* -* @param string $text text to be case folded -* @param string $option determines how we will fold the cases -* @return string case folded text -*/ -function utf8_case_fold($text, $option = 'full') -{ - static $uniarray = array(); - global $phpbb_root_path, $phpEx; - - // common is always set - if (!isset($uniarray['c'])) - { - $uniarray['c'] = include($phpbb_root_path . 'includes/utf/data/case_fold_c.' . $phpEx); - } - - // only set full if we need to - if ($option === 'full' && !isset($uniarray['f'])) - { - $uniarray['f'] = include($phpbb_root_path . 'includes/utf/data/case_fold_f.' . $phpEx); - } - - // only set simple if we need to - if ($option !== 'full' && !isset($uniarray['s'])) - { - $uniarray['s'] = include($phpbb_root_path . 'includes/utf/data/case_fold_s.' . $phpEx); - } - - // common is always replaced - $text = strtr($text, $uniarray['c']); - - if ($option === 'full') - { - // full replaces a character with multiple characters - $text = strtr($text, $uniarray['f']); - } - else - { - // simple replaces a character with another character - $text = strtr($text, $uniarray['s']); - } - - return $text; -} - -/** -* Takes the input and does a "special" case fold. It does minor normalization -* and returns NFKC compatable text -* -* @param string $text text to be case folded -* @param string $option determines how we will fold the cases -* @return string case folded text -*/ -function utf8_case_fold_nfkc($text, $option = 'full') -{ - static $fc_nfkc_closure = array( - "\xCD\xBA" => "\x20\xCE\xB9", - "\xCF\x92" => "\xCF\x85", - "\xCF\x93" => "\xCF\x8D", - "\xCF\x94" => "\xCF\x8B", - "\xCF\xB2" => "\xCF\x83", - "\xCF\xB9" => "\xCF\x83", - "\xE1\xB4\xAC" => "\x61", - "\xE1\xB4\xAD" => "\xC3\xA6", - "\xE1\xB4\xAE" => "\x62", - "\xE1\xB4\xB0" => "\x64", - "\xE1\xB4\xB1" => "\x65", - "\xE1\xB4\xB2" => "\xC7\x9D", - "\xE1\xB4\xB3" => "\x67", - "\xE1\xB4\xB4" => "\x68", - "\xE1\xB4\xB5" => "\x69", - "\xE1\xB4\xB6" => "\x6A", - "\xE1\xB4\xB7" => "\x6B", - "\xE1\xB4\xB8" => "\x6C", - "\xE1\xB4\xB9" => "\x6D", - "\xE1\xB4\xBA" => "\x6E", - "\xE1\xB4\xBC" => "\x6F", - "\xE1\xB4\xBD" => "\xC8\xA3", - "\xE1\xB4\xBE" => "\x70", - "\xE1\xB4\xBF" => "\x72", - "\xE1\xB5\x80" => "\x74", - "\xE1\xB5\x81" => "\x75", - "\xE1\xB5\x82" => "\x77", - "\xE2\x82\xA8" => "\x72\x73", - "\xE2\x84\x82" => "\x63", - "\xE2\x84\x83" => "\xC2\xB0\x63", - "\xE2\x84\x87" => "\xC9\x9B", - "\xE2\x84\x89" => "\xC2\xB0\x66", - "\xE2\x84\x8B" => "\x68", - "\xE2\x84\x8C" => "\x68", - "\xE2\x84\x8D" => "\x68", - "\xE2\x84\x90" => "\x69", - "\xE2\x84\x91" => "\x69", - "\xE2\x84\x92" => "\x6C", - "\xE2\x84\x95" => "\x6E", - "\xE2\x84\x96" => "\x6E\x6F", - "\xE2\x84\x99" => "\x70", - "\xE2\x84\x9A" => "\x71", - "\xE2\x84\x9B" => "\x72", - "\xE2\x84\x9C" => "\x72", - "\xE2\x84\x9D" => "\x72", - "\xE2\x84\xA0" => "\x73\x6D", - "\xE2\x84\xA1" => "\x74\x65\x6C", - "\xE2\x84\xA2" => "\x74\x6D", - "\xE2\x84\xA4" => "\x7A", - "\xE2\x84\xA8" => "\x7A", - "\xE2\x84\xAC" => "\x62", - "\xE2\x84\xAD" => "\x63", - "\xE2\x84\xB0" => "\x65", - "\xE2\x84\xB1" => "\x66", - "\xE2\x84\xB3" => "\x6D", - "\xE2\x84\xBB" => "\x66\x61\x78", - "\xE2\x84\xBE" => "\xCE\xB3", - "\xE2\x84\xBF" => "\xCF\x80", - "\xE2\x85\x85" => "\x64", - "\xE3\x89\x90" => "\x70\x74\x65", - "\xE3\x8B\x8C" => "\x68\x67", - "\xE3\x8B\x8E" => "\x65\x76", - "\xE3\x8B\x8F" => "\x6C\x74\x64", - "\xE3\x8D\xB1" => "\x68\x70\x61", - "\xE3\x8D\xB3" => "\x61\x75", - "\xE3\x8D\xB5" => "\x6F\x76", - "\xE3\x8D\xBA" => "\x69\x75", - "\xE3\x8E\x80" => "\x70\x61", - "\xE3\x8E\x81" => "\x6E\x61", - "\xE3\x8E\x82" => "\xCE\xBC\x61", - "\xE3\x8E\x83" => "\x6D\x61", - "\xE3\x8E\x84" => "\x6B\x61", - "\xE3\x8E\x85" => "\x6B\x62", - "\xE3\x8E\x86" => "\x6D\x62", - "\xE3\x8E\x87" => "\x67\x62", - "\xE3\x8E\x8A" => "\x70\x66", - "\xE3\x8E\x8B" => "\x6E\x66", - "\xE3\x8E\x8C" => "\xCE\xBC\x66", - "\xE3\x8E\x90" => "\x68\x7A", - "\xE3\x8E\x91" => "\x6B\x68\x7A", - "\xE3\x8E\x92" => "\x6D\x68\x7A", - "\xE3\x8E\x93" => "\x67\x68\x7A", - "\xE3\x8E\x94" => "\x74\x68\x7A", - "\xE3\x8E\xA9" => "\x70\x61", - "\xE3\x8E\xAA" => "\x6B\x70\x61", - "\xE3\x8E\xAB" => "\x6D\x70\x61", - "\xE3\x8E\xAC" => "\x67\x70\x61", - "\xE3\x8E\xB4" => "\x70\x76", - "\xE3\x8E\xB5" => "\x6E\x76", - "\xE3\x8E\xB6" => "\xCE\xBC\x76", - "\xE3\x8E\xB7" => "\x6D\x76", - "\xE3\x8E\xB8" => "\x6B\x76", - "\xE3\x8E\xB9" => "\x6D\x76", - "\xE3\x8E\xBA" => "\x70\x77", - "\xE3\x8E\xBB" => "\x6E\x77", - "\xE3\x8E\xBC" => "\xCE\xBC\x77", - "\xE3\x8E\xBD" => "\x6D\x77", - "\xE3\x8E\xBE" => "\x6B\x77", - "\xE3\x8E\xBF" => "\x6D\x77", - "\xE3\x8F\x80" => "\x6B\xCF\x89", - "\xE3\x8F\x81" => "\x6D\xCF\x89", - "\xE3\x8F\x83" => "\x62\x71", - "\xE3\x8F\x86" => "\x63\xE2\x88\x95\x6B\x67", - "\xE3\x8F\x87" => "\x63\x6F\x2E", - "\xE3\x8F\x88" => "\x64\x62", - "\xE3\x8F\x89" => "\x67\x79", - "\xE3\x8F\x8B" => "\x68\x70", - "\xE3\x8F\x8D" => "\x6B\x6B", - "\xE3\x8F\x8E" => "\x6B\x6D", - "\xE3\x8F\x97" => "\x70\x68", - "\xE3\x8F\x99" => "\x70\x70\x6D", - "\xE3\x8F\x9A" => "\x70\x72", - "\xE3\x8F\x9C" => "\x73\x76", - "\xE3\x8F\x9D" => "\x77\x62", - "\xE3\x8F\x9E" => "\x76\xE2\x88\x95\x6D", - "\xE3\x8F\x9F" => "\x61\xE2\x88\x95\x6D", - "\xF0\x9D\x90\x80" => "\x61", - "\xF0\x9D\x90\x81" => "\x62", - "\xF0\x9D\x90\x82" => "\x63", - "\xF0\x9D\x90\x83" => "\x64", - "\xF0\x9D\x90\x84" => "\x65", - "\xF0\x9D\x90\x85" => "\x66", - "\xF0\x9D\x90\x86" => "\x67", - "\xF0\x9D\x90\x87" => "\x68", - "\xF0\x9D\x90\x88" => "\x69", - "\xF0\x9D\x90\x89" => "\x6A", - "\xF0\x9D\x90\x8A" => "\x6B", - "\xF0\x9D\x90\x8B" => "\x6C", - "\xF0\x9D\x90\x8C" => "\x6D", - "\xF0\x9D\x90\x8D" => "\x6E", - "\xF0\x9D\x90\x8E" => "\x6F", - "\xF0\x9D\x90\x8F" => "\x70", - "\xF0\x9D\x90\x90" => "\x71", - "\xF0\x9D\x90\x91" => "\x72", - "\xF0\x9D\x90\x92" => "\x73", - "\xF0\x9D\x90\x93" => "\x74", - "\xF0\x9D\x90\x94" => "\x75", - "\xF0\x9D\x90\x95" => "\x76", - "\xF0\x9D\x90\x96" => "\x77", - "\xF0\x9D\x90\x97" => "\x78", - "\xF0\x9D\x90\x98" => "\x79", - "\xF0\x9D\x90\x99" => "\x7A", - "\xF0\x9D\x90\xB4" => "\x61", - "\xF0\x9D\x90\xB5" => "\x62", - "\xF0\x9D\x90\xB6" => "\x63", - "\xF0\x9D\x90\xB7" => "\x64", - "\xF0\x9D\x90\xB8" => "\x65", - "\xF0\x9D\x90\xB9" => "\x66", - "\xF0\x9D\x90\xBA" => "\x67", - "\xF0\x9D\x90\xBB" => "\x68", - "\xF0\x9D\x90\xBC" => "\x69", - "\xF0\x9D\x90\xBD" => "\x6A", - "\xF0\x9D\x90\xBE" => "\x6B", - "\xF0\x9D\x90\xBF" => "\x6C", - "\xF0\x9D\x91\x80" => "\x6D", - "\xF0\x9D\x91\x81" => "\x6E", - "\xF0\x9D\x91\x82" => "\x6F", - "\xF0\x9D\x91\x83" => "\x70", - "\xF0\x9D\x91\x84" => "\x71", - "\xF0\x9D\x91\x85" => "\x72", - "\xF0\x9D\x91\x86" => "\x73", - "\xF0\x9D\x91\x87" => "\x74", - "\xF0\x9D\x91\x88" => "\x75", - "\xF0\x9D\x91\x89" => "\x76", - "\xF0\x9D\x91\x8A" => "\x77", - "\xF0\x9D\x91\x8B" => "\x78", - "\xF0\x9D\x91\x8C" => "\x79", - "\xF0\x9D\x91\x8D" => "\x7A", - "\xF0\x9D\x91\xA8" => "\x61", - "\xF0\x9D\x91\xA9" => "\x62", - "\xF0\x9D\x91\xAA" => "\x63", - "\xF0\x9D\x91\xAB" => "\x64", - "\xF0\x9D\x91\xAC" => "\x65", - "\xF0\x9D\x91\xAD" => "\x66", - "\xF0\x9D\x91\xAE" => "\x67", - "\xF0\x9D\x91\xAF" => "\x68", - "\xF0\x9D\x91\xB0" => "\x69", - "\xF0\x9D\x91\xB1" => "\x6A", - "\xF0\x9D\x91\xB2" => "\x6B", - "\xF0\x9D\x91\xB3" => "\x6C", - "\xF0\x9D\x91\xB4" => "\x6D", - "\xF0\x9D\x91\xB5" => "\x6E", - "\xF0\x9D\x91\xB6" => "\x6F", - "\xF0\x9D\x91\xB7" => "\x70", - "\xF0\x9D\x91\xB8" => "\x71", - "\xF0\x9D\x91\xB9" => "\x72", - "\xF0\x9D\x91\xBA" => "\x73", - "\xF0\x9D\x91\xBB" => "\x74", - "\xF0\x9D\x91\xBC" => "\x75", - "\xF0\x9D\x91\xBD" => "\x76", - "\xF0\x9D\x91\xBE" => "\x77", - "\xF0\x9D\x91\xBF" => "\x78", - "\xF0\x9D\x92\x80" => "\x79", - "\xF0\x9D\x92\x81" => "\x7A", - "\xF0\x9D\x92\x9C" => "\x61", - "\xF0\x9D\x92\x9E" => "\x63", - "\xF0\x9D\x92\x9F" => "\x64", - "\xF0\x9D\x92\xA2" => "\x67", - "\xF0\x9D\x92\xA5" => "\x6A", - "\xF0\x9D\x92\xA6" => "\x6B", - "\xF0\x9D\x92\xA9" => "\x6E", - "\xF0\x9D\x92\xAA" => "\x6F", - "\xF0\x9D\x92\xAB" => "\x70", - "\xF0\x9D\x92\xAC" => "\x71", - "\xF0\x9D\x92\xAE" => "\x73", - "\xF0\x9D\x92\xAF" => "\x74", - "\xF0\x9D\x92\xB0" => "\x75", - "\xF0\x9D\x92\xB1" => "\x76", - "\xF0\x9D\x92\xB2" => "\x77", - "\xF0\x9D\x92\xB3" => "\x78", - "\xF0\x9D\x92\xB4" => "\x79", - "\xF0\x9D\x92\xB5" => "\x7A", - "\xF0\x9D\x93\x90" => "\x61", - "\xF0\x9D\x93\x91" => "\x62", - "\xF0\x9D\x93\x92" => "\x63", - "\xF0\x9D\x93\x93" => "\x64", - "\xF0\x9D\x93\x94" => "\x65", - "\xF0\x9D\x93\x95" => "\x66", - "\xF0\x9D\x93\x96" => "\x67", - "\xF0\x9D\x93\x97" => "\x68", - "\xF0\x9D\x93\x98" => "\x69", - "\xF0\x9D\x93\x99" => "\x6A", - "\xF0\x9D\x93\x9A" => "\x6B", - "\xF0\x9D\x93\x9B" => "\x6C", - "\xF0\x9D\x93\x9C" => "\x6D", - "\xF0\x9D\x93\x9D" => "\x6E", - "\xF0\x9D\x93\x9E" => "\x6F", - "\xF0\x9D\x93\x9F" => "\x70", - "\xF0\x9D\x93\xA0" => "\x71", - "\xF0\x9D\x93\xA1" => "\x72", - "\xF0\x9D\x93\xA2" => "\x73", - "\xF0\x9D\x93\xA3" => "\x74", - "\xF0\x9D\x93\xA4" => "\x75", - "\xF0\x9D\x93\xA5" => "\x76", - "\xF0\x9D\x93\xA6" => "\x77", - "\xF0\x9D\x93\xA7" => "\x78", - "\xF0\x9D\x93\xA8" => "\x79", - "\xF0\x9D\x93\xA9" => "\x7A", - "\xF0\x9D\x94\x84" => "\x61", - "\xF0\x9D\x94\x85" => "\x62", - "\xF0\x9D\x94\x87" => "\x64", - "\xF0\x9D\x94\x88" => "\x65", - "\xF0\x9D\x94\x89" => "\x66", - "\xF0\x9D\x94\x8A" => "\x67", - "\xF0\x9D\x94\x8D" => "\x6A", - "\xF0\x9D\x94\x8E" => "\x6B", - "\xF0\x9D\x94\x8F" => "\x6C", - "\xF0\x9D\x94\x90" => "\x6D", - "\xF0\x9D\x94\x91" => "\x6E", - "\xF0\x9D\x94\x92" => "\x6F", - "\xF0\x9D\x94\x93" => "\x70", - "\xF0\x9D\x94\x94" => "\x71", - "\xF0\x9D\x94\x96" => "\x73", - "\xF0\x9D\x94\x97" => "\x74", - "\xF0\x9D\x94\x98" => "\x75", - "\xF0\x9D\x94\x99" => "\x76", - "\xF0\x9D\x94\x9A" => "\x77", - "\xF0\x9D\x94\x9B" => "\x78", - "\xF0\x9D\x94\x9C" => "\x79", - "\xF0\x9D\x94\xB8" => "\x61", - "\xF0\x9D\x94\xB9" => "\x62", - "\xF0\x9D\x94\xBB" => "\x64", - "\xF0\x9D\x94\xBC" => "\x65", - "\xF0\x9D\x94\xBD" => "\x66", - "\xF0\x9D\x94\xBE" => "\x67", - "\xF0\x9D\x95\x80" => "\x69", - "\xF0\x9D\x95\x81" => "\x6A", - "\xF0\x9D\x95\x82" => "\x6B", - "\xF0\x9D\x95\x83" => "\x6C", - "\xF0\x9D\x95\x84" => "\x6D", - "\xF0\x9D\x95\x86" => "\x6F", - "\xF0\x9D\x95\x8A" => "\x73", - "\xF0\x9D\x95\x8B" => "\x74", - "\xF0\x9D\x95\x8C" => "\x75", - "\xF0\x9D\x95\x8D" => "\x76", - "\xF0\x9D\x95\x8E" => "\x77", - "\xF0\x9D\x95\x8F" => "\x78", - "\xF0\x9D\x95\x90" => "\x79", - "\xF0\x9D\x95\xAC" => "\x61", - "\xF0\x9D\x95\xAD" => "\x62", - "\xF0\x9D\x95\xAE" => "\x63", - "\xF0\x9D\x95\xAF" => "\x64", - "\xF0\x9D\x95\xB0" => "\x65", - "\xF0\x9D\x95\xB1" => "\x66", - "\xF0\x9D\x95\xB2" => "\x67", - "\xF0\x9D\x95\xB3" => "\x68", - "\xF0\x9D\x95\xB4" => "\x69", - "\xF0\x9D\x95\xB5" => "\x6A", - "\xF0\x9D\x95\xB6" => "\x6B", - "\xF0\x9D\x95\xB7" => "\x6C", - "\xF0\x9D\x95\xB8" => "\x6D", - "\xF0\x9D\x95\xB9" => "\x6E", - "\xF0\x9D\x95\xBA" => "\x6F", - "\xF0\x9D\x95\xBB" => "\x70", - "\xF0\x9D\x95\xBC" => "\x71", - "\xF0\x9D\x95\xBD" => "\x72", - "\xF0\x9D\x95\xBE" => "\x73", - "\xF0\x9D\x95\xBF" => "\x74", - "\xF0\x9D\x96\x80" => "\x75", - "\xF0\x9D\x96\x81" => "\x76", - "\xF0\x9D\x96\x82" => "\x77", - "\xF0\x9D\x96\x83" => "\x78", - "\xF0\x9D\x96\x84" => "\x79", - "\xF0\x9D\x96\x85" => "\x7A", - "\xF0\x9D\x96\xA0" => "\x61", - "\xF0\x9D\x96\xA1" => "\x62", - "\xF0\x9D\x96\xA2" => "\x63", - "\xF0\x9D\x96\xA3" => "\x64", - "\xF0\x9D\x96\xA4" => "\x65", - "\xF0\x9D\x96\xA5" => "\x66", - "\xF0\x9D\x96\xA6" => "\x67", - "\xF0\x9D\x96\xA7" => "\x68", - "\xF0\x9D\x96\xA8" => "\x69", - "\xF0\x9D\x96\xA9" => "\x6A", - "\xF0\x9D\x96\xAA" => "\x6B", - "\xF0\x9D\x96\xAB" => "\x6C", - "\xF0\x9D\x96\xAC" => "\x6D", - "\xF0\x9D\x96\xAD" => "\x6E", - "\xF0\x9D\x96\xAE" => "\x6F", - "\xF0\x9D\x96\xAF" => "\x70", - "\xF0\x9D\x96\xB0" => "\x71", - "\xF0\x9D\x96\xB1" => "\x72", - "\xF0\x9D\x96\xB2" => "\x73", - "\xF0\x9D\x96\xB3" => "\x74", - "\xF0\x9D\x96\xB4" => "\x75", - "\xF0\x9D\x96\xB5" => "\x76", - "\xF0\x9D\x96\xB6" => "\x77", - "\xF0\x9D\x96\xB7" => "\x78", - "\xF0\x9D\x96\xB8" => "\x79", - "\xF0\x9D\x96\xB9" => "\x7A", - "\xF0\x9D\x97\x94" => "\x61", - "\xF0\x9D\x97\x95" => "\x62", - "\xF0\x9D\x97\x96" => "\x63", - "\xF0\x9D\x97\x97" => "\x64", - "\xF0\x9D\x97\x98" => "\x65", - "\xF0\x9D\x97\x99" => "\x66", - "\xF0\x9D\x97\x9A" => "\x67", - "\xF0\x9D\x97\x9B" => "\x68", - "\xF0\x9D\x97\x9C" => "\x69", - "\xF0\x9D\x97\x9D" => "\x6A", - "\xF0\x9D\x97\x9E" => "\x6B", - "\xF0\x9D\x97\x9F" => "\x6C", - "\xF0\x9D\x97\xA0" => "\x6D", - "\xF0\x9D\x97\xA1" => "\x6E", - "\xF0\x9D\x97\xA2" => "\x6F", - "\xF0\x9D\x97\xA3" => "\x70", - "\xF0\x9D\x97\xA4" => "\x71", - "\xF0\x9D\x97\xA5" => "\x72", - "\xF0\x9D\x97\xA6" => "\x73", - "\xF0\x9D\x97\xA7" => "\x74", - "\xF0\x9D\x97\xA8" => "\x75", - "\xF0\x9D\x97\xA9" => "\x76", - "\xF0\x9D\x97\xAA" => "\x77", - "\xF0\x9D\x97\xAB" => "\x78", - "\xF0\x9D\x97\xAC" => "\x79", - "\xF0\x9D\x97\xAD" => "\x7A", - "\xF0\x9D\x98\x88" => "\x61", - "\xF0\x9D\x98\x89" => "\x62", - "\xF0\x9D\x98\x8A" => "\x63", - "\xF0\x9D\x98\x8B" => "\x64", - "\xF0\x9D\x98\x8C" => "\x65", - "\xF0\x9D\x98\x8D" => "\x66", - "\xF0\x9D\x98\x8E" => "\x67", - "\xF0\x9D\x98\x8F" => "\x68", - "\xF0\x9D\x98\x90" => "\x69", - "\xF0\x9D\x98\x91" => "\x6A", - "\xF0\x9D\x98\x92" => "\x6B", - "\xF0\x9D\x98\x93" => "\x6C", - "\xF0\x9D\x98\x94" => "\x6D", - "\xF0\x9D\x98\x95" => "\x6E", - "\xF0\x9D\x98\x96" => "\x6F", - "\xF0\x9D\x98\x97" => "\x70", - "\xF0\x9D\x98\x98" => "\x71", - "\xF0\x9D\x98\x99" => "\x72", - "\xF0\x9D\x98\x9A" => "\x73", - "\xF0\x9D\x98\x9B" => "\x74", - "\xF0\x9D\x98\x9C" => "\x75", - "\xF0\x9D\x98\x9D" => "\x76", - "\xF0\x9D\x98\x9E" => "\x77", - "\xF0\x9D\x98\x9F" => "\x78", - "\xF0\x9D\x98\xA0" => "\x79", - "\xF0\x9D\x98\xA1" => "\x7A", - "\xF0\x9D\x98\xBC" => "\x61", - "\xF0\x9D\x98\xBD" => "\x62", - "\xF0\x9D\x98\xBE" => "\x63", - "\xF0\x9D\x98\xBF" => "\x64", - "\xF0\x9D\x99\x80" => "\x65", - "\xF0\x9D\x99\x81" => "\x66", - "\xF0\x9D\x99\x82" => "\x67", - "\xF0\x9D\x99\x83" => "\x68", - "\xF0\x9D\x99\x84" => "\x69", - "\xF0\x9D\x99\x85" => "\x6A", - "\xF0\x9D\x99\x86" => "\x6B", - "\xF0\x9D\x99\x87" => "\x6C", - "\xF0\x9D\x99\x88" => "\x6D", - "\xF0\x9D\x99\x89" => "\x6E", - "\xF0\x9D\x99\x8A" => "\x6F", - "\xF0\x9D\x99\x8B" => "\x70", - "\xF0\x9D\x99\x8C" => "\x71", - "\xF0\x9D\x99\x8D" => "\x72", - "\xF0\x9D\x99\x8E" => "\x73", - "\xF0\x9D\x99\x8F" => "\x74", - "\xF0\x9D\x99\x90" => "\x75", - "\xF0\x9D\x99\x91" => "\x76", - "\xF0\x9D\x99\x92" => "\x77", - "\xF0\x9D\x99\x93" => "\x78", - "\xF0\x9D\x99\x94" => "\x79", - "\xF0\x9D\x99\x95" => "\x7A", - "\xF0\x9D\x99\xB0" => "\x61", - "\xF0\x9D\x99\xB1" => "\x62", - "\xF0\x9D\x99\xB2" => "\x63", - "\xF0\x9D\x99\xB3" => "\x64", - "\xF0\x9D\x99\xB4" => "\x65", - "\xF0\x9D\x99\xB5" => "\x66", - "\xF0\x9D\x99\xB6" => "\x67", - "\xF0\x9D\x99\xB7" => "\x68", - "\xF0\x9D\x99\xB8" => "\x69", - "\xF0\x9D\x99\xB9" => "\x6A", - "\xF0\x9D\x99\xBA" => "\x6B", - "\xF0\x9D\x99\xBB" => "\x6C", - "\xF0\x9D\x99\xBC" => "\x6D", - "\xF0\x9D\x99\xBD" => "\x6E", - "\xF0\x9D\x99\xBE" => "\x6F", - "\xF0\x9D\x99\xBF" => "\x70", - "\xF0\x9D\x9A\x80" => "\x71", - "\xF0\x9D\x9A\x81" => "\x72", - "\xF0\x9D\x9A\x82" => "\x73", - "\xF0\x9D\x9A\x83" => "\x74", - "\xF0\x9D\x9A\x84" => "\x75", - "\xF0\x9D\x9A\x85" => "\x76", - "\xF0\x9D\x9A\x86" => "\x77", - "\xF0\x9D\x9A\x87" => "\x78", - "\xF0\x9D\x9A\x88" => "\x79", - "\xF0\x9D\x9A\x89" => "\x7A", - "\xF0\x9D\x9A\xA8" => "\xCE\xB1", - "\xF0\x9D\x9A\xA9" => "\xCE\xB2", - "\xF0\x9D\x9A\xAA" => "\xCE\xB3", - "\xF0\x9D\x9A\xAB" => "\xCE\xB4", - "\xF0\x9D\x9A\xAC" => "\xCE\xB5", - "\xF0\x9D\x9A\xAD" => "\xCE\xB6", - "\xF0\x9D\x9A\xAE" => "\xCE\xB7", - "\xF0\x9D\x9A\xAF" => "\xCE\xB8", - "\xF0\x9D\x9A\xB0" => "\xCE\xB9", - "\xF0\x9D\x9A\xB1" => "\xCE\xBA", - "\xF0\x9D\x9A\xB2" => "\xCE\xBB", - "\xF0\x9D\x9A\xB3" => "\xCE\xBC", - "\xF0\x9D\x9A\xB4" => "\xCE\xBD", - "\xF0\x9D\x9A\xB5" => "\xCE\xBE", - "\xF0\x9D\x9A\xB6" => "\xCE\xBF", - "\xF0\x9D\x9A\xB7" => "\xCF\x80", - "\xF0\x9D\x9A\xB8" => "\xCF\x81", - "\xF0\x9D\x9A\xB9" => "\xCE\xB8", - "\xF0\x9D\x9A\xBA" => "\xCF\x83", - "\xF0\x9D\x9A\xBB" => "\xCF\x84", - "\xF0\x9D\x9A\xBC" => "\xCF\x85", - "\xF0\x9D\x9A\xBD" => "\xCF\x86", - "\xF0\x9D\x9A\xBE" => "\xCF\x87", - "\xF0\x9D\x9A\xBF" => "\xCF\x88", - "\xF0\x9D\x9B\x80" => "\xCF\x89", - "\xF0\x9D\x9B\x93" => "\xCF\x83", - "\xF0\x9D\x9B\xA2" => "\xCE\xB1", - "\xF0\x9D\x9B\xA3" => "\xCE\xB2", - "\xF0\x9D\x9B\xA4" => "\xCE\xB3", - "\xF0\x9D\x9B\xA5" => "\xCE\xB4", - "\xF0\x9D\x9B\xA6" => "\xCE\xB5", - "\xF0\x9D\x9B\xA7" => "\xCE\xB6", - "\xF0\x9D\x9B\xA8" => "\xCE\xB7", - "\xF0\x9D\x9B\xA9" => "\xCE\xB8", - "\xF0\x9D\x9B\xAA" => "\xCE\xB9", - "\xF0\x9D\x9B\xAB" => "\xCE\xBA", - "\xF0\x9D\x9B\xAC" => "\xCE\xBB", - "\xF0\x9D\x9B\xAD" => "\xCE\xBC", - "\xF0\x9D\x9B\xAE" => "\xCE\xBD", - "\xF0\x9D\x9B\xAF" => "\xCE\xBE", - "\xF0\x9D\x9B\xB0" => "\xCE\xBF", - "\xF0\x9D\x9B\xB1" => "\xCF\x80", - "\xF0\x9D\x9B\xB2" => "\xCF\x81", - "\xF0\x9D\x9B\xB3" => "\xCE\xB8", - "\xF0\x9D\x9B\xB4" => "\xCF\x83", - "\xF0\x9D\x9B\xB5" => "\xCF\x84", - "\xF0\x9D\x9B\xB6" => "\xCF\x85", - "\xF0\x9D\x9B\xB7" => "\xCF\x86", - "\xF0\x9D\x9B\xB8" => "\xCF\x87", - "\xF0\x9D\x9B\xB9" => "\xCF\x88", - "\xF0\x9D\x9B\xBA" => "\xCF\x89", - "\xF0\x9D\x9C\x8D" => "\xCF\x83", - "\xF0\x9D\x9C\x9C" => "\xCE\xB1", - "\xF0\x9D\x9C\x9D" => "\xCE\xB2", - "\xF0\x9D\x9C\x9E" => "\xCE\xB3", - "\xF0\x9D\x9C\x9F" => "\xCE\xB4", - "\xF0\x9D\x9C\xA0" => "\xCE\xB5", - "\xF0\x9D\x9C\xA1" => "\xCE\xB6", - "\xF0\x9D\x9C\xA2" => "\xCE\xB7", - "\xF0\x9D\x9C\xA3" => "\xCE\xB8", - "\xF0\x9D\x9C\xA4" => "\xCE\xB9", - "\xF0\x9D\x9C\xA5" => "\xCE\xBA", - "\xF0\x9D\x9C\xA6" => "\xCE\xBB", - "\xF0\x9D\x9C\xA7" => "\xCE\xBC", - "\xF0\x9D\x9C\xA8" => "\xCE\xBD", - "\xF0\x9D\x9C\xA9" => "\xCE\xBE", - "\xF0\x9D\x9C\xAA" => "\xCE\xBF", - "\xF0\x9D\x9C\xAB" => "\xCF\x80", - "\xF0\x9D\x9C\xAC" => "\xCF\x81", - "\xF0\x9D\x9C\xAD" => "\xCE\xB8", - "\xF0\x9D\x9C\xAE" => "\xCF\x83", - "\xF0\x9D\x9C\xAF" => "\xCF\x84", - "\xF0\x9D\x9C\xB0" => "\xCF\x85", - "\xF0\x9D\x9C\xB1" => "\xCF\x86", - "\xF0\x9D\x9C\xB2" => "\xCF\x87", - "\xF0\x9D\x9C\xB3" => "\xCF\x88", - "\xF0\x9D\x9C\xB4" => "\xCF\x89", - "\xF0\x9D\x9D\x87" => "\xCF\x83", - "\xF0\x9D\x9D\x96" => "\xCE\xB1", - "\xF0\x9D\x9D\x97" => "\xCE\xB2", - "\xF0\x9D\x9D\x98" => "\xCE\xB3", - "\xF0\x9D\x9D\x99" => "\xCE\xB4", - "\xF0\x9D\x9D\x9A" => "\xCE\xB5", - "\xF0\x9D\x9D\x9B" => "\xCE\xB6", - "\xF0\x9D\x9D\x9C" => "\xCE\xB7", - "\xF0\x9D\x9D\x9D" => "\xCE\xB8", - "\xF0\x9D\x9D\x9E" => "\xCE\xB9", - "\xF0\x9D\x9D\x9F" => "\xCE\xBA", - "\xF0\x9D\x9D\xA0" => "\xCE\xBB", - "\xF0\x9D\x9D\xA1" => "\xCE\xBC", - "\xF0\x9D\x9D\xA2" => "\xCE\xBD", - "\xF0\x9D\x9D\xA3" => "\xCE\xBE", - "\xF0\x9D\x9D\xA4" => "\xCE\xBF", - "\xF0\x9D\x9D\xA5" => "\xCF\x80", - "\xF0\x9D\x9D\xA6" => "\xCF\x81", - "\xF0\x9D\x9D\xA7" => "\xCE\xB8", - "\xF0\x9D\x9D\xA8" => "\xCF\x83", - "\xF0\x9D\x9D\xA9" => "\xCF\x84", - "\xF0\x9D\x9D\xAA" => "\xCF\x85", - "\xF0\x9D\x9D\xAB" => "\xCF\x86", - "\xF0\x9D\x9D\xAC" => "\xCF\x87", - "\xF0\x9D\x9D\xAD" => "\xCF\x88", - "\xF0\x9D\x9D\xAE" => "\xCF\x89", - "\xF0\x9D\x9E\x81" => "\xCF\x83", - "\xF0\x9D\x9E\x90" => "\xCE\xB1", - "\xF0\x9D\x9E\x91" => "\xCE\xB2", - "\xF0\x9D\x9E\x92" => "\xCE\xB3", - "\xF0\x9D\x9E\x93" => "\xCE\xB4", - "\xF0\x9D\x9E\x94" => "\xCE\xB5", - "\xF0\x9D\x9E\x95" => "\xCE\xB6", - "\xF0\x9D\x9E\x96" => "\xCE\xB7", - "\xF0\x9D\x9E\x97" => "\xCE\xB8", - "\xF0\x9D\x9E\x98" => "\xCE\xB9", - "\xF0\x9D\x9E\x99" => "\xCE\xBA", - "\xF0\x9D\x9E\x9A" => "\xCE\xBB", - "\xF0\x9D\x9E\x9B" => "\xCE\xBC", - "\xF0\x9D\x9E\x9C" => "\xCE\xBD", - "\xF0\x9D\x9E\x9D" => "\xCE\xBE", - "\xF0\x9D\x9E\x9E" => "\xCE\xBF", - "\xF0\x9D\x9E\x9F" => "\xCF\x80", - "\xF0\x9D\x9E\xA0" => "\xCF\x81", - "\xF0\x9D\x9E\xA1" => "\xCE\xB8", - "\xF0\x9D\x9E\xA2" => "\xCF\x83", - "\xF0\x9D\x9E\xA3" => "\xCF\x84", - "\xF0\x9D\x9E\xA4" => "\xCF\x85", - "\xF0\x9D\x9E\xA5" => "\xCF\x86", - "\xF0\x9D\x9E\xA6" => "\xCF\x87", - "\xF0\x9D\x9E\xA7" => "\xCF\x88", - "\xF0\x9D\x9E\xA8" => "\xCF\x89", - "\xF0\x9D\x9E\xBB" => "\xCF\x83", - "\xF0\x9D\x9F\x8A" => "\xCF\x9D", - ); - - // do the case fold - $text = utf8_case_fold($text, $option); - - // convert to NFKC - 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); - - return $text; -} - -/** -* Assume the input is NFC: -* Takes the input and does a "special" case fold. It does minor normalization as well. -* -* @param string $text text to be case folded -* @param string $option determines how we will fold the cases -* @return string case folded text -*/ -function utf8_case_fold_nfc($text, $option = 'full') -{ - static $uniarray = array(); - static $ypogegrammeni = array( - "\xCD\xBA" => "\x20\xCD\x85", - "\xE1\xBE\x80" => "\xE1\xBC\x80\xCD\x85", - "\xE1\xBE\x81" => "\xE1\xBC\x81\xCD\x85", - "\xE1\xBE\x82" => "\xE1\xBC\x82\xCD\x85", - "\xE1\xBE\x83" => "\xE1\xBC\x83\xCD\x85", - "\xE1\xBE\x84" => "\xE1\xBC\x84\xCD\x85", - "\xE1\xBE\x85" => "\xE1\xBC\x85\xCD\x85", - "\xE1\xBE\x86" => "\xE1\xBC\x86\xCD\x85", - "\xE1\xBE\x87" => "\xE1\xBC\x87\xCD\x85", - "\xE1\xBE\x88" => "\xE1\xBC\x88\xCD\x85", - "\xE1\xBE\x89" => "\xE1\xBC\x89\xCD\x85", - "\xE1\xBE\x8A" => "\xE1\xBC\x8A\xCD\x85", - "\xE1\xBE\x8B" => "\xE1\xBC\x8B\xCD\x85", - "\xE1\xBE\x8C" => "\xE1\xBC\x8C\xCD\x85", - "\xE1\xBE\x8D" => "\xE1\xBC\x8D\xCD\x85", - "\xE1\xBE\x8E" => "\xE1\xBC\x8E\xCD\x85", - "\xE1\xBE\x8F" => "\xE1\xBC\x8F\xCD\x85", - "\xE1\xBE\x90" => "\xE1\xBC\xA0\xCD\x85", - "\xE1\xBE\x91" => "\xE1\xBC\xA1\xCD\x85", - "\xE1\xBE\x92" => "\xE1\xBC\xA2\xCD\x85", - "\xE1\xBE\x93" => "\xE1\xBC\xA3\xCD\x85", - "\xE1\xBE\x94" => "\xE1\xBC\xA4\xCD\x85", - "\xE1\xBE\x95" => "\xE1\xBC\xA5\xCD\x85", - "\xE1\xBE\x96" => "\xE1\xBC\xA6\xCD\x85", - "\xE1\xBE\x97" => "\xE1\xBC\xA7\xCD\x85", - "\xE1\xBE\x98" => "\xE1\xBC\xA8\xCD\x85", - "\xE1\xBE\x99" => "\xE1\xBC\xA9\xCD\x85", - "\xE1\xBE\x9A" => "\xE1\xBC\xAA\xCD\x85", - "\xE1\xBE\x9B" => "\xE1\xBC\xAB\xCD\x85", - "\xE1\xBE\x9C" => "\xE1\xBC\xAC\xCD\x85", - "\xE1\xBE\x9D" => "\xE1\xBC\xAD\xCD\x85", - "\xE1\xBE\x9E" => "\xE1\xBC\xAE\xCD\x85", - "\xE1\xBE\x9F" => "\xE1\xBC\xAF\xCD\x85", - "\xE1\xBE\xA0" => "\xE1\xBD\xA0\xCD\x85", - "\xE1\xBE\xA1" => "\xE1\xBD\xA1\xCD\x85", - "\xE1\xBE\xA2" => "\xE1\xBD\xA2\xCD\x85", - "\xE1\xBE\xA3" => "\xE1\xBD\xA3\xCD\x85", - "\xE1\xBE\xA4" => "\xE1\xBD\xA4\xCD\x85", - "\xE1\xBE\xA5" => "\xE1\xBD\xA5\xCD\x85", - "\xE1\xBE\xA6" => "\xE1\xBD\xA6\xCD\x85", - "\xE1\xBE\xA7" => "\xE1\xBD\xA7\xCD\x85", - "\xE1\xBE\xA8" => "\xE1\xBD\xA8\xCD\x85", - "\xE1\xBE\xA9" => "\xE1\xBD\xA9\xCD\x85", - "\xE1\xBE\xAA" => "\xE1\xBD\xAA\xCD\x85", - "\xE1\xBE\xAB" => "\xE1\xBD\xAB\xCD\x85", - "\xE1\xBE\xAC" => "\xE1\xBD\xAC\xCD\x85", - "\xE1\xBE\xAD" => "\xE1\xBD\xAD\xCD\x85", - "\xE1\xBE\xAE" => "\xE1\xBD\xAE\xCD\x85", - "\xE1\xBE\xAF" => "\xE1\xBD\xAF\xCD\x85", - "\xE1\xBE\xB2" => "\xE1\xBD\xB0\xCD\x85", - "\xE1\xBE\xB3" => "\xCE\xB1\xCD\x85", - "\xE1\xBE\xB4" => "\xCE\xAC\xCD\x85", - "\xE1\xBE\xB7" => "\xE1\xBE\xB6\xCD\x85", - "\xE1\xBE\xBC" => "\xCE\x91\xCD\x85", - "\xE1\xBF\x82" => "\xE1\xBD\xB4\xCD\x85", - "\xE1\xBF\x83" => "\xCE\xB7\xCD\x85", - "\xE1\xBF\x84" => "\xCE\xAE\xCD\x85", - "\xE1\xBF\x87" => "\xE1\xBF\x86\xCD\x85", - "\xE1\xBF\x8C" => "\xCE\x97\xCD\x85", - "\xE1\xBF\xB2" => "\xE1\xBD\xBC\xCD\x85", - "\xE1\xBF\xB3" => "\xCF\x89\xCD\x85", - "\xE1\xBF\xB4" => "\xCF\x8E\xCD\x85", - "\xE1\xBF\xB7" => "\xE1\xBF\xB6\xCD\x85", - "\xE1\xBF\xBC" => "\xCE\xA9\xCD\x85", - ); - - // perform a small trick, avoid further normalization on composed points that contain U+0345 in their decomposition - $text = strtr($text, $ypogegrammeni); - - // do the case fold - $text = utf8_case_fold($text, $option); - - return $text; -} - -/** -* 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)) - { - 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; -} - -/** -* This function is used to generate a "clean" version of a string. -* Clean means that it is a case insensitive form (case folding) and that it is normalized (NFC). -* Additionally a homographs of one character are transformed into one specific character (preferably ASCII -* if it is an ASCII character). -* -* Please be aware that if you change something within this function or within -* functions used here you need to rebuild/update the username_clean column in the users table. And all other -* columns that store a clean string otherwise you will break this functionality. -* -* @param string $text An unclean string, mabye user input (has to be valid UTF-8!) -* @return string Cleaned up version of the input string -*/ -function utf8_clean_string($text) -{ - global $phpbb_root_path, $phpEx; - - static $homographs = array(); - if (empty($homographs)) - { - $homographs = include($phpbb_root_path . 'includes/utf/data/confusables.' . $phpEx); - } - - $text = utf8_case_fold_nfkc($text); - $text = strtr($text, $homographs); - // Other control characters - $text = preg_replace('#(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)#', '', $text); - - // we need to reduce multiple spaces to a single one - $text = preg_replace('# {2,}#', ' ', $text); - - // we can use trim here as all the other space characters should have been turned - // into normal ASCII spaces by now - return trim($text); -} - -/** -* A wrapper for htmlspecialchars($value, ENT_COMPAT, 'UTF-8') -*/ -function utf8_htmlspecialchars($value) -{ - return htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); -} - -/** -* Trying to convert returned system message to utf8 -* -* PHP assumes such messages are ISO-8859-1 so we'll do that too -* and if it breaks messages we'll blame it on them ;-) -*/ -function utf8_convert_message($message) -{ - // First of all check if conversion is neded at all, as there is no point - // in converting ASCII messages from ISO-8859-1 to UTF-8 - if (!preg_match('/[\x80-\xFF]/', $message)) - { - return utf8_htmlspecialchars($message); - } - - // else we need to convert some part of the message - return utf8_htmlspecialchars(utf8_recode($message, 'ISO-8859-1')); -} - -/** -* UTF8-compatible wordwrap replacement -* -* @param string $string The input string -* @param int $width The column width. Defaults to 75. -* @param string $break The line is broken using the optional break parameter. Defaults to '\n'. -* @param bool $cut If the cut is set to TRUE, the string is always wrapped at the specified width. So if you have a word that is larger than the given width, it is broken apart. -* -* @return string the given string wrapped at the specified column. -* -*/ -function utf8_wordwrap($string, $width = 75, $break = "\n", $cut = false) -{ - // We first need to explode on $break, not destroying existing (intended) breaks - $lines = explode($break, $string); - $new_lines = array(0 => ''); - $index = 0; - - foreach ($lines as $line) - { - $words = explode(' ', $line); - - for ($i = 0, $size = count($words); $i < $size; $i++) - { - $word = $words[$i]; - - // If cut is true we need to cut the word if it is > width chars - if ($cut && utf8_strlen($word) > $width) - { - $words[$i] = utf8_substr($word, $width); - $word = utf8_substr($word, 0, $width); - $i--; - } - - if (utf8_strlen($new_lines[$index] . $word) > $width) - { - $new_lines[$index] = substr($new_lines[$index], 0, -1); - $index++; - $new_lines[$index] = ''; - } - - $new_lines[$index] .= $word . ' '; - } - - $new_lines[$index] = substr($new_lines[$index], 0, -1); - $index++; - $new_lines[$index] = ''; - } - - unset($new_lines[$index]); - return implode($break, $new_lines); -} - -/** -* UTF8-safe basename() function -* -* basename() has some limitations and is dependent on the locale setting -* according to the PHP manual. Therefore we provide our own locale independent -* basename function. -* -* @param string $filename The filename basename() should be applied to -* @return string The basenamed filename -*/ -function utf8_basename($filename) -{ - // We always check for forward slash AND backward slash - // because they could be mixed or "sneaked" in. ;) - // You know, never trust user input... - if (strpos($filename, '/') !== false) - { - $filename = utf8_substr($filename, utf8_strrpos($filename, '/') + 1); - } - - if (strpos($filename, '\\') !== false) - { - $filename = utf8_substr($filename, utf8_strrpos($filename, '\\') + 1); - } - - return $filename; -} diff --git a/install/update/new/index.php b/install/update/new/index.php deleted file mode 100644 index 5622bc3..0000000 --- a/install/update/new/index.php +++ /dev/null @@ -1,252 +0,0 @@ - -* @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); -$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('viewforum'); - -// Mark notifications read -if (($mark_notification = $request->variable('mark_notification', 0))) -{ - if ($user->data['user_id'] == ANONYMOUS) - { - if ($request->is_ajax()) - { - trigger_error('LOGIN_REQUIRED'); - } - login_box('', $user->lang['LOGIN_REQUIRED']); - } - - 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('notification.method.board', array( - 'notification_id' => $mark_notification, - )); - - if (isset($notification['notifications'][$mark_notification])) - { - $notification = $notification['notifications'][$mark_notification]; - - $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(); - $json_response->send(array( - 'success' => true, - )); - } - - if (($redirect = $request->variable('redirect', ''))) - { - redirect(append_sid($phpbb_root_path . $redirect)); - } - - redirect($notification->get_redirect_url()); - } - } -} - -display_forums('', $config['load_moderators']); - -$order_legend = ($config['legend_sort_groupname']) ? 'group_name' : 'group_legend'; -// Grab group details for legend display -if ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) -{ - $sql = 'SELECT group_id, group_name, group_colour, group_type, group_legend - FROM ' . GROUPS_TABLE . ' - WHERE group_legend > 0 - ORDER BY ' . $order_legend . ' ASC'; -} -else -{ - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, g.group_legend - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE g.group_legend > 0 - AND (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ') - ORDER BY g.' . $order_legend . ' ASC'; -} -$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 = $group_helper->get_name($row['group_name']); - - if ($row['group_name'] == 'BOTS' || ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile'))) - { - $legend[] = '' . $group_name . '
'; - } - else - { - $legend[] = '' . $group_name . ''; - } -} -$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 ($show_birthdays) -{ - $time = $user->create_datetime(); - $now = phpbb_gmgetdate($time->getTimestamp() + $time->getOffset()); - - // Display birthdays of 29th february on 28th february in non-leap-years - $leap_year_birthdays = ''; - if ($now['mday'] == 28 && $now['mon'] == 2 && !$time->format('L')) - { - $leap_year_birthdays = " OR u.user_birthday LIKE '" . $db->sql_escape(sprintf('%2d-%2d-', 29, 2)) . "%'"; - } - - $sql_ary = array( - 'SELECT' => 'u.user_id, u.username, u.user_colour, u.user_birthday', - 'FROM' => array( - USERS_TABLE => 'u', - ), - 'LEFT_JOIN' => array( - array( - 'FROM' => array(BANLIST_TABLE => 'b'), - 'ON' => 'u.user_id = b.ban_userid', - ), - ), - 'WHERE' => "(b.ban_id IS NULL OR b.ban_exclude = 1) - AND (u.user_birthday LIKE '" . $db->sql_escape(sprintf('%2d-%2d-', $now['mday'], $now['mon'])) . "%' $leap_year_birthdays) - AND u.user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')', - ); - - /** - * Event to modify the SQL query to get birthdays data - * - * @event core.index_modify_birthdays_sql - * @var array now The assoc array with the 'now' local timestamp data - * @var array sql_ary The SQL array to get the birthdays data - * @var object time The user related Datetime object - * @since 3.1.7-RC1 - */ - $vars = array('now', 'sql_ary', 'time'); - extract($phpbb_dispatcher->trigger_event('core.index_modify_birthdays_sql', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - $rows = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - foreach ($rows as $row) - { - $birthday_username = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']); - $birthday_year = (int) substr($row['user_birthday'], -4); - $birthday_age = ($birthday_year) ? max(0, $now['year'] - $birthday_year) : ''; - - $birthdays[] = array( - 'USERNAME' => $birthday_username, - 'AGE' => $birthday_age, - ); - - // For 3.0 compatibility - $birthday_list[] = $birthday_username . (($birthday_age) ? " ({$birthday_age})" : ''); - } - - /** - * Event to modify the birthdays list - * - * @event core.index_modify_birthdays_list - * @var array birthdays Array with the users birthdays data - * @var array rows Array with the birthdays SQL query result - * @since 3.1.7-RC1 - */ - $vars = array('birthdays', 'rows'); - extract($phpbb_dispatcher->trigger_event('core.index_modify_birthdays_list', compact($vars))); - - $template->assign_block_vars_array('birthdays', $birthdays); -} - -// Assign index specific vars -$template->assign_vars(array( - 'TOTAL_POSTS' => $user->lang('TOTAL_POSTS_COUNT', (int) $config['num_posts']), - 'TOTAL_TOPICS' => $user->lang('TOTAL_TOPICS', (int) $config['num_topics']), - 'TOTAL_USERS' => $user->lang('TOTAL_USERS', (int) $config['num_users']), - 'NEWEST_USER' => $user->lang('NEWEST_USER', get_username_string('full', $config['newest_user_id'], $config['newest_username'], $config['newest_user_colour'])), - - 'LEGEND' => $legend, - 'BIRTHDAY_LIST' => (empty($birthday_list)) ? '' : implode($user->lang['COMMA_SEPARATOR'], $birthday_list), - - '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' => $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') . '&mark=forums&mark_time=' . time()) : '', - 'U_MCP' => ($auth->acl_get('m_') || $auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=front', true, $user->session_id) : '') -); - -$page_title = ($config['board_index_text'] !== '') ? $config['board_index_text'] : $user->lang['INDEX']; - -/** -* You can use this event to modify the page title and load data for the index -* -* @event core.index_modify_page_title -* @var string page_title Title of the index page -* @since 3.1.0-a1 -*/ -$vars = array('page_title'); -extract($phpbb_dispatcher->trigger_event('core.index_modify_page_title', compact($vars))); - -// Output page -page_header($page_title, true); - -$template->set_filenames(array( - 'body' => 'index_body.html') -); - -page_footer(); diff --git a/install/update/new/language/en/acp/attachments.php b/install/update/new/language/en/acp/attachments.php deleted file mode 100644 index 67454f8..0000000 --- a/install/update/new/language/en/acp/attachments.php +++ /dev/null @@ -1,167 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - 'ACP_ATTACHMENT_SETTINGS_EXPLAIN' => 'Here you can configure the main settings for attachments and the associated special categories.', - 'ACP_EXTENSION_GROUPS_EXPLAIN' => 'Here you can add, delete, modify or disable your extension groups. Further options include the assignment of a special category to them, changing the download mechanism and defining an upload icon which will be displayed in front of the attachment which belongs to the group.', - 'ACP_MANAGE_EXTENSIONS_EXPLAIN' => 'Here you can manage your allowed extensions. To activate your extensions, please refer to the extension groups management panel. We strongly recommend not to allow scripting extensions (such as php, php3, php4, phtml, pl, cgi, py, rb, asp, aspx, and so forth…).', - 'ACP_ORPHAN_ATTACHMENTS_EXPLAIN' => 'Here you are able to see orphaned files. This happens mostly if users are attaching files but not submitting the post. You are able to delete the files or attach them to existing posts. Attaching to posts requires a valid post ID, you have to determine this ID by yourself. This will assign the already uploaded attachment to the post you entered.', - 'ADD_EXTENSION' => 'Add extension', - 'ADD_EXTENSION_GROUP' => 'Add extension group', - 'ADMIN_UPLOAD_ERROR' => 'Errors while trying to attach file: “%s”.', - 'ALLOWED_FORUMS' => 'Allowed forums', - 'ALLOWED_FORUMS_EXPLAIN' => 'Able to post the assigned extensions at the selected (or all if selected) forums.', - 'ALLOWED_IN_PM_POST' => 'Allowed', - 'ALLOW_ATTACHMENTS' => 'Allow attachments', - 'ALLOW_ALL_FORUMS' => 'Allow all forums', - 'ALLOW_IN_PM' => 'Allowed in private messaging', - 'ALLOW_PM_ATTACHMENTS' => 'Allow attachments in private messages', - 'ALLOW_SELECTED_FORUMS' => 'Only forums selected below', - 'ASSIGNED_EXTENSIONS' => 'Assigned extensions', - 'ASSIGNED_GROUP' => 'Assigned extension group', - 'ATTACH_EXTENSIONS_URL' => 'Extensions', - 'ATTACH_EXT_GROUPS_URL' => 'Extension groups', - 'ATTACH_ID' => 'ID', - 'ATTACH_MAX_FILESIZE' => 'Maximum file size', - 'ATTACH_MAX_FILESIZE_EXPLAIN' => 'Maximum size of each file. If this value is 0, the uploadable filesize is only limited by your PHP configuration.', - 'ATTACH_MAX_PM_FILESIZE' => 'Maximum file size messaging', - 'ATTACH_MAX_PM_FILESIZE_EXPLAIN' => 'Maximum size of each file, with 0 being unlimited, attached to a private message.', - 'ATTACH_ORPHAN_URL' => 'Orphan attachments', - 'ATTACH_POST_ID' => 'Post ID', - 'ATTACH_POST_TYPE' => 'Post type', - 'ATTACH_QUOTA' => 'Total attachment quota', - 'ATTACH_QUOTA_EXPLAIN' => 'Maximum drive space available for attachments for the whole board, with 0 being unlimited.', - 'ATTACH_TO_POST' => 'Attach file to post', - - 'CAT_IMAGES' => 'Images', - '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', - 'CREATE_THUMBNAIL' => 'Create thumbnail', - 'CREATE_THUMBNAIL_EXPLAIN' => 'Create a thumbnail in all possible situations.', - - 'DEFINE_ALLOWED_IPS' => 'Define allowed IPs/hostnames', - 'DEFINE_DISALLOWED_IPS' => 'Define disallowed IPs/hostnames', - 'DOWNLOAD_ADD_IPS_EXPLAIN' => 'To specify several different IPs or hostnames enter each on a new line. To specify a range of IP addresses separate the start and end with a hyphen (-), to specify a wildcard use “*”.', - 'DOWNLOAD_REMOVE_IPS_EXPLAIN' => 'You can remove (or un-exclude) multiple IP addresses in one go using the appropriate combination of mouse and keyboard for your computer and browser. Excluded IPs have a blue background.', - 'DISPLAY_INLINED' => 'Display images inline', - 'DISPLAY_INLINED_EXPLAIN' => 'If set to No image attachments will show as a link.', - 'DISPLAY_ORDER' => 'Attachment display order', - 'DISPLAY_ORDER_EXPLAIN' => 'Display attachments ordered by time.', - - 'EDIT_EXTENSION_GROUP' => 'Edit extension group', - 'EXCLUDE_ENTERED_IP' => 'Enable this to exclude the entered IP/hostname.', - 'EXCLUDE_FROM_ALLOWED_IP' => 'Exclude IP from allowed IPs/hostnames', - 'EXCLUDE_FROM_DISALLOWED_IP' => 'Exclude IP from disallowed IPs/hostnames', - 'EXTENSIONS_UPDATED' => 'Extensions successfully updated.', - 'EXTENSION_EXIST' => 'The extension %s already exists.', - 'EXTENSION_GROUP' => 'Extension group', - 'EXTENSION_GROUPS' => 'Extension groups', - 'EXTENSION_GROUP_DELETED' => 'Extension group successfully deleted.', - 'EXTENSION_GROUP_EXIST' => 'The extension group %s already exists.', - - 'EXT_GROUP_ARCHIVES' => 'Archives', - 'EXT_GROUP_DOCUMENTS' => 'Documents', - 'EXT_GROUP_DOWNLOADABLE_FILES' => 'Downloadable Files', - 'EXT_GROUP_IMAGES' => 'Images', - 'EXT_GROUP_PLAIN_TEXT' => 'Plain Text', - - '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.
Click %3$shere%4$s to resynchronise them.', - - 'GO_TO_EXTENSIONS' => 'Go to extension management screen', - 'GROUP_NAME' => 'Group name', - - '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.', - - 'MAX_ATTACHMENTS' => 'Maximum number of attachments per post', - 'MAX_ATTACHMENTS_PM' => 'Maximum number of attachments per private message', - 'MAX_EXTGROUP_FILESIZE' => 'Maximum file size', - 'MAX_IMAGE_SIZE' => 'Maximum image dimensions', - 'MAX_IMAGE_SIZE_EXPLAIN' => 'Maximum size of image attachments. Set both values to 0px by 0px to disable dimension checking.', - 'MAX_THUMB_WIDTH' => 'Maximum thumbnail width/height in pixel', - 'MAX_THUMB_WIDTH_EXPLAIN' => 'A generated thumbnail will not exceed the width set here.', - 'MIN_THUMB_FILESIZE' => 'Minimum thumbnail file size', - 'MIN_THUMB_FILESIZE_EXPLAIN' => 'Do not create a thumbnail for images smaller than this.', - 'MODE_INLINE' => 'Inline', - 'MODE_PHYSICAL' => 'Physical', - - 'NOT_ALLOWED_IN_PM' => 'Only allowed in posts', - 'NOT_ALLOWED_IN_PM_POST' => 'Not allowed', - 'NOT_ASSIGNED' => 'Not assigned', - 'NO_ATTACHMENTS' => 'No attachments found for this period.', - 'NO_EXT_GROUP' => 'None', - 'NO_EXT_GROUP_NAME' => 'No group name entered', - 'NO_EXT_GROUP_SPECIFIED' => 'No extension group specified.', - 'NO_FILE_CAT' => 'None', - 'NO_IMAGE' => 'No image', - '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.', - - 'ONLY_ALLOWED_IN_PM' => 'Only allowed in private messages', - 'ORDER_ALLOW_DENY' => 'Allow', - 'ORDER_DENY_ALLOW' => 'Deny', - - 'REMOVE_ALLOWED_IPS' => 'Remove or un-exclude allowed IPs/hostnames', - 'REMOVE_DISALLOWED_IPS' => 'Remove or un-exclude disallowed IPs/hostnames', - 'RESYNC_FILES_STATS_CONFIRM' => 'Are you sure you wish to resynchronise file statistics?', - - '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 whitelist (Allow) or a blacklist (Deny).', - 'SECURE_DOWNLOADS' => 'Enable secure downloads', - 'SECURE_DOWNLOADS_EXPLAIN' => 'With this option enabled, downloads are limited to IP’s/hostnames you define.', - 'SECURE_DOWNLOAD_NOTICE' => 'Secure Downloads are not enabled. The settings below will be applied after enabling secure downloads.', - 'SECURE_DOWNLOAD_UPDATE_SUCCESS'=> 'The IP list has been updated successfully.', - 'SECURE_EMPTY_REFERRER' => 'Allow empty referrer', - 'SECURE_EMPTY_REFERRER_EXPLAIN' => 'Secure downloads are based on referrers. Do you want to allow downloads for those omitting the referrer?', - 'SETTINGS_CAT_IMAGES' => 'Image category settings', - 'SPECIAL_CATEGORY' => 'Special category', - 'SPECIAL_CATEGORY_EXPLAIN' => 'Special categories differ between the way presented within posts.', - 'SUCCESSFULLY_UPLOADED' => 'Successfully uploaded.', - 'SUCCESS_EXTENSION_GROUP_ADD' => 'Extension group successfully added.', - 'SUCCESS_EXTENSION_GROUP_EDIT' => 'Extension group successfully updated.', - - 'UPLOADING_FILES' => 'Uploading files', - 'UPLOADING_FILE_TO' => 'Uploading file “%1$s” to post number %2$d…', - 'UPLOAD_DENIED_FORUM' => 'You do not have the permission to upload files to forum “%s”.', - 'UPLOAD_DIR' => 'Upload directory', - 'UPLOAD_DIR_EXPLAIN' => 'Storage path for attachments. Please note that if you change this directory while already having uploaded attachments you need to manually copy the files to their new location.', - 'UPLOAD_ICON' => 'Upload icon', - 'UPLOAD_NOT_DIR' => 'The upload location you specified does not appear to be a directory.', -)); diff --git a/install/update/new/language/en/acp/board.php b/install/update/new/language/en/acp/board.php deleted file mode 100644 index a01a4f1..0000000 --- a/install/update/new/language/en/acp/board.php +++ /dev/null @@ -1,635 +0,0 @@ - -* @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(); -} - -// 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 - -// Board Settings -$lang = array_merge($lang, array( - 'ACP_BOARD_SETTINGS_EXPLAIN' => 'Here you can determine the basic operation of your board, give it a fitting name and description, and among other settings adjust the default values for timezone and language.', - 'BOARD_INDEX_TEXT' => 'Board index text', - 'BOARD_INDEX_TEXT_EXPLAIN' => 'This text is displayed as the board index in the board’s breadcrumbs. If not specified, it will default to “Board index”.', - '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 date() function.', - 'DEFAULT_LANGUAGE' => 'Default language', - 'DEFAULT_STYLE' => 'Default style', - 'DEFAULT_STYLE_EXPLAIN' => 'The default style for new users.', - 'DISABLE_BOARD' => 'Disable board', - 'DISABLE_BOARD_EXPLAIN' => 'This will make the board unavailable to users who are neither administrators nor moderators. You can also enter a short (255 character) message to display if you wish.', - 'DISPLAY_LAST_SUBJECT' => 'Display subject of last added post on forum list', - 'DISPLAY_LAST_SUBJECT_EXPLAIN' => 'The subject of the last added post will be displayed in the forum list with a hyperlink to the post. Subjects from password protected forums and forums in which user doesn’t have read access are not shown.', - 'DISPLAY_UNAPPROVED_POSTS' => 'Display unapproved posts to the author', - 'DISPLAY_UNAPPROVED_POSTS_EXPLAIN' => 'Unapproved posts can be viewed by the author. Does not apply to Guest posts.', - 'GUEST_STYLE' => 'Guest style', - 'GUEST_STYLE_EXPLAIN' => 'The board style for guests.', - 'OVERRIDE_STYLE' => 'Override user style', - 'OVERRIDE_STYLE_EXPLAIN' => 'Replaces user’s (and guest’s) style with the style as defined under "Default style".', - 'SITE_DESC' => 'Site description', - 'SITE_HOME_TEXT' => 'Main website text', - 'SITE_HOME_TEXT_EXPLAIN' => 'This text will be displayed as a link to your website homepage in the board’s breadcrumbs. If not specified, it will default to “Home”.', - 'SITE_HOME_URL' => 'Main website URL', - 'SITE_HOME_URL_EXPLAIN' => 'If specified, a link to this URL will be prepended to your board’s breadcrumbs and the board logo will link to this URL instead of the forum index. An absolute URL is required, e.g. http://www.phpbb.com.', - 'SITE_NAME' => 'Site name', - 'SYSTEM_TIMEZONE' => 'Guest timezone', - 'SYSTEM_TIMEZONE_EXPLAIN' => 'Timezone to use for displaying times to users who are not logged in (guests, bots). Logged in users set their timezone during registration and can change it in their user control panel.', - 'WARNINGS_EXPIRE' => 'Warning duration', - 'WARNINGS_EXPIRE_EXPLAIN' => 'Number of days that will elapse before a warning will automatically expire from a user’s record. Set this value to 0 to make warnings permanent.', -)); - -// Board Features -$lang = array_merge($lang, array( - 'ACP_BOARD_FEATURES_EXPLAIN' => 'Here you can enable/disable several board features.', - - 'ALLOW_ATTACHMENTS' => 'Allow attachments', - 'ALLOW_BIRTHDAYS' => 'Allow birthdays', - 'ALLOW_BIRTHDAYS_EXPLAIN' => 'Allow birthdays to be entered and age being displayed in profiles. Please note the birthday list within the board index is controlled by a separate load setting.', - 'ALLOW_BOOKMARKS' => 'Allow bookmarking topics', - 'ALLOW_BOOKMARKS_EXPLAIN' => 'User is able to store personal bookmarks.', - 'ALLOW_BBCODE' => 'Allow BBCode', - 'ALLOW_FORUM_NOTIFY' => 'Allow subscribing to forums', - 'ALLOW_NAME_CHANGE' => 'Allow username changes', - 'ALLOW_NO_CENSORS' => 'Allow disabling of word censoring', - 'ALLOW_NO_CENSORS_EXPLAIN' => 'Users can choose to disable the automatic word censoring of posts and private messages.', - 'ALLOW_PM_ATTACHMENTS' => 'Allow attachments in private messages', - 'ALLOW_PM_REPORT' => 'Allow users to report private messages', - 'ALLOW_PM_REPORT_EXPLAIN' => 'If this setting is enabled, users have the option of reporting a private message they have received or sent to the board’s moderators. These private messages will then be visible in the Moderator Control Panel.', - 'ALLOW_QUICK_REPLY' => 'Allow quick reply', - 'ALLOW_QUICK_REPLY_EXPLAIN' => 'This switch allows for the quick reply to be disabled board-wide. When enabled, forum specific settings will be used to determine whether the quick reply is displayed in individual forums.', - 'ALLOW_QUICK_REPLY_BUTTON' => 'Submit and enable quick reply in all forums', - 'ALLOW_SIG' => 'Allow signatures', - 'ALLOW_SIG_BBCODE' => 'Allow BBCode in user signatures', - 'ALLOW_SIG_FLASH' => 'Allow use of [FLASH] BBCode tag in user signatures', - 'ALLOW_SIG_IMG' => 'Allow use of [IMG] BBCode tag in user signatures', - 'ALLOW_SIG_LINKS' => 'Allow use of links in user signatures', - 'ALLOW_SIG_LINKS_EXPLAIN' => 'If disallowed the [URL] BBCode tag and automatic/magic URLs are disabled.', - 'ALLOW_SIG_SMILIES' => 'Allow use of smilies in user signatures', - 'ALLOW_SMILIES' => 'Allow smilies', - '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 -$lang = array_merge($lang, array( - 'ACP_AVATAR_SETTINGS_EXPLAIN' => 'Avatars are generally small, unique images a user can associate with themselves. Depending on the style they are usually displayed below the username when viewing topics. Here you can determine how users can define their avatars. Please note that in order to upload avatars you need to have created the directory you name below and ensure it can be written to by the web server. Please also note that file size limits are only imposed on uploaded avatars, they do not apply to remotely linked images.', - - 'ALLOW_AVATARS' => 'Enable avatars', - 'ALLOW_AVATARS_EXPLAIN' => 'Allow general usage of avatars;
If you disable avatars in general or avatars of a certain mode, the disabled avatars will no longer be shown on the board, but users will still be able to download their own avatars in the User Control Panel.', - 'ALLOW_GRAVATAR' => 'Enable gravatar avatars', - 'ALLOW_LOCAL' => 'Enable gallery avatars', - 'ALLOW_REMOTE' => 'Enable remote avatars', - 'ALLOW_REMOTE_EXPLAIN' => 'Avatars linked to from another website.
Warning: Enabling this feature might allow users to check for the existence of files and services that are only accessible on the local network.', - 'ALLOW_REMOTE_UPLOAD' => 'Enable remote avatar uploading', - 'ALLOW_REMOTE_UPLOAD_EXPLAIN' => 'Allow uploading of avatars from another website.
Warning: Enabling this feature might allow users to check for the existence of files and services that are only accessible on the local network.', - 'ALLOW_UPLOAD' => 'Enable avatar uploading', - 'AVATAR_GALLERY_PATH' => 'Avatar gallery path', - 'AVATAR_GALLERY_PATH_EXPLAIN' => 'Path under your phpBB root directory for pre-loaded images, e.g. images/avatars/gallery.
Double dots like ../ 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. images/avatars/upload.
Avatar uploading will not be available if this path is not writable.
Double dots like ../ 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', - 'MAX_FILESIZE_EXPLAIN' => 'For uploaded avatar files. If this value is 0, the uploaded filesize is only limited by your PHP configuration.', - 'MIN_AVATAR_SIZE' => 'Minimum avatar dimensions', - 'MIN_AVATAR_SIZE_EXPLAIN' => 'Width x Height in pixels.', -)); - -// Message Settings -$lang = array_merge($lang, array( - 'ACP_MESSAGE_SETTINGS_EXPLAIN' => 'Here you can set all default settings for private messaging.', - - 'ALLOW_BBCODE_PM' => 'Allow BBCode in private messages', - 'ALLOW_FLASH_PM' => 'Allow use of [FLASH] BBCode tag', - 'ALLOW_FLASH_PM_EXPLAIN' => 'Note that the ability to use flash in private messages, if enabled here, also depends on the permissions.', - 'ALLOW_FORWARD_PM' => 'Allow forwarding of private messages', - 'ALLOW_IMG_PM' => 'Allow use of [IMG] BBCode tag', - 'ALLOW_MASS_PM' => 'Allow sending of private messages to multiple users and groups', - 'ALLOW_MASS_PM_EXPLAIN' => 'Sending to groups can be adjusted per group within the group settings page.', - 'ALLOW_PRINT_PM' => 'Allow print view in private messaging', - 'ALLOW_QUOTE_PM' => 'Allow quotes in private messages', - 'ALLOW_SIG_PM' => 'Allow signature in private messages', - 'ALLOW_SMILIES_PM' => 'Allow smilies in private messages', - 'BOXES_LIMIT' => 'Maximum private messages per box', - 'BOXES_LIMIT_EXPLAIN' => 'Users may receive no more than this many messages in each of their private message boxes. Set this value to 0 to allow unlimited messages.', - 'BOXES_MAX' => 'Maximum private message folders', - 'BOXES_MAX_EXPLAIN' => 'By default users may create this many personal folders for private messages.', - 'ENABLE_PM_ICONS' => 'Enable use of topic icons in private messages', - 'FULL_FOLDER_ACTION' => 'Full folder default action', - 'FULL_FOLDER_ACTION_EXPLAIN'=> 'Default action to take if a user’s folder is full assuming the user’s folder action, if set at all, is not applicable. The only exception is for the “Sent messages” folder where the default action is always to delete old messages.', - 'HOLD_NEW_MESSAGES' => 'Hold new messages', - 'PM_EDIT_TIME' => 'Limit editing time', - 'PM_EDIT_TIME_EXPLAIN' => 'Limits the time available to edit a private message not already delivered. Setting the value to 0 disables this behaviour.', - 'PM_MAX_RECIPIENTS' => 'Maximum number of allowed recipients', - 'PM_MAX_RECIPIENTS_EXPLAIN' => 'The maximum number of allowed recipients in a private message. If 0 is entered, an unlimited number is allowed. This setting can be adjusted for every group within the group settings page.', -)); - -// Post Settings -$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 [URL] 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 [FLASH] BBCode tag in posts', - 'ALLOW_POST_FLASH_EXPLAIN' => 'If disallowed the [FLASH] BBCode tag is disabled in posts. Otherwise the permission system controls which users can use the [FLASH] BBCode tag.', - - 'BUMP_INTERVAL' => 'Bump interval', - 'BUMP_INTERVAL_EXPLAIN' => 'Number of minutes, hours or days between the last post to a topic and the ability to bump that topic. Setting the value to 0 disables bumping entirely.', - 'CHAR_LIMIT' => 'Maximum characters per post/message', - 'CHAR_LIMIT_EXPLAIN' => 'The number of characters allowed within a post/private message. Set to 0 for unlimited characters.', - 'DELETE_TIME' => 'Limit deleting time', - 'DELETE_TIME_EXPLAIN' => 'Limits the time available to delete a new post. Setting the value to 0 disables this behaviour.', - 'DISPLAY_LAST_EDITED' => 'Display last edited time information', - 'DISPLAY_LAST_EDITED_EXPLAIN' => 'Choose if the last edited by information to be displayed on posts.', - 'EDIT_TIME' => 'Limit editing time', - 'EDIT_TIME_EXPLAIN' => 'Limits the time available to edit a new post. Setting the value to 0 disables this behaviour.', - 'FLOOD_INTERVAL' => 'Flood interval', - 'FLOOD_INTERVAL_EXPLAIN' => 'Number of seconds a user must wait between posting new messages. To enable users to ignore this alter their permissions.', - 'HOT_THRESHOLD' => 'Popular topic threshold', - 'HOT_THRESHOLD_EXPLAIN' => 'Posts per topic threshold required for the popular topic annotation. Set to 0 to disable popular topics.', - 'MAX_POLL_OPTIONS' => 'Maximum number of poll options', - 'MAX_POST_FONT_SIZE' => 'Maximum font size per post', - 'MAX_POST_FONT_SIZE_EXPLAIN' => 'Maximum font size allowed in a post. Set to 0 for unlimited font size.', - 'MAX_POST_IMG_HEIGHT' => 'Maximum image height per post', - 'MAX_POST_IMG_HEIGHT_EXPLAIN' => 'Maximum height of an image/flash file in postings. Set to 0 for unlimited size.', - 'MAX_POST_IMG_WIDTH' => 'Maximum image width per post', - 'MAX_POST_IMG_WIDTH_EXPLAIN' => 'Maximum width of an image/flash file in postings. Set to 0 for unlimited size.', - 'MAX_POST_URLS' => 'Maximum links per post', - 'MAX_POST_URLS_EXPLAIN' => 'Maximum number of URLs in a post. Set to 0 for unlimited links.', - 'MIN_CHAR_LIMIT' => 'Minimum characters per post/message', - 'MIN_CHAR_LIMIT_EXPLAIN' => 'The minimum number of characters the user need to enter within a post/private message. The minimum for this setting is 1.', - 'POSTING' => 'Posting', - 'POSTS_PER_PAGE' => 'Posts per page', - 'QUOTE_DEPTH_LIMIT' => 'Maximum nesting depth for quotes', - 'QUOTE_DEPTH_LIMIT_EXPLAIN' => 'Maximum quote nesting depth in a post. Set to 0 for unlimited depth.', - 'SMILIES_LIMIT' => 'Maximum smilies per post', - 'SMILIES_LIMIT_EXPLAIN' => 'Maximum number of smilies in a post. Set to 0 for unlimited smilies.', - 'SMILIES_PER_PAGE' => 'Smilies per page', - 'TOPICS_PER_PAGE' => 'Topics per page', -)); - -// Signature Settings -$lang = array_merge($lang, array( - 'ACP_SIGNATURE_SETTINGS_EXPLAIN' => 'Here you can set all default settings for signatures.', - - 'MAX_SIG_FONT_SIZE' => 'Maximum signature font size', - 'MAX_SIG_FONT_SIZE_EXPLAIN' => 'Maximum font size allowed in user signatures. Set to 0 for unlimited size.', - 'MAX_SIG_IMG_HEIGHT' => 'Maximum signature image height', - 'MAX_SIG_IMG_HEIGHT_EXPLAIN' => 'Maximum height of an image/flash file in user signatures. Set to 0 for unlimited height.', - 'MAX_SIG_IMG_WIDTH' => 'Maximum signature image width', - 'MAX_SIG_IMG_WIDTH_EXPLAIN' => 'Maximum width of an image/flash file in user signatures. Set to 0 for unlimited width.', - 'MAX_SIG_LENGTH' => 'Maximum signature length', - 'MAX_SIG_LENGTH_EXPLAIN' => 'Maximum number of characters in user signatures.', - 'MAX_SIG_SMILIES' => 'Maximum smilies per signature', - 'MAX_SIG_SMILIES_EXPLAIN' => 'Maximum smilies allowed in user signatures. Set to 0 for unlimited smilies.', - 'MAX_SIG_URLS' => 'Maximum signature links', - 'MAX_SIG_URLS_EXPLAIN' => 'Maximum number of links in user signatures. Set to 0 for unlimited links.', -)); - -// Registration Settings -$lang = array_merge($lang, array( - 'ACP_REGISTER_SETTINGS_EXPLAIN' => 'Here you are able to define registration and profile related settings.', - - 'ACC_ACTIVATION' => 'Account activation', - 'ACC_ACTIVATION_EXPLAIN' => 'This determines whether users have immediate access to the board or if confirmation is required. You can also completely disable new registrations. “Board-wide email” must be enabled in order to use user or admin activation.', - 'ACC_ACTIVATION_WARNING' => 'Please note that the currently selected activation method requires emails to be enabled, otherwise registration will be disabled. We recommend to either select a different activation method or reenable emails.', - 'NEW_MEMBER_POST_LIMIT' => 'New member post limit', - 'NEW_MEMBER_POST_LIMIT_EXPLAIN' => 'New members are within the Newly Registered Users group until they reach this number of posts. You can use this group to keep them from using the PM system or to review their posts. A value of 0 disables this feature.', - 'NEW_MEMBER_GROUP_DEFAULT' => 'Set Newly Registered Users group to default', - 'NEW_MEMBER_GROUP_DEFAULT_EXPLAIN' => 'If set to yes, and a new member post limit is specified, newly registered users will not only be put into the Newly Registered Users group, but this group will also be their default one. This may come in handy if you want to assign a group default rank and/or avatar the user then inherits.', - - 'ACC_ADMIN' => 'By admin', - 'ACC_DISABLE' => 'Disable registration', - 'ACC_NONE' => 'No activation (immediate access)', - 'ACC_USER' => 'By user (email verification)', -// 'ACC_USER_ADMIN' => 'User + Admin', - 'ALLOW_EMAIL_REUSE' => 'Allow email address re-use', - 'ALLOW_EMAIL_REUSE_EXPLAIN' => 'Different users can register with the same email address.', - 'COPPA' => 'COPPA', - 'COPPA_FAX' => 'COPPA fax number', - 'COPPA_MAIL' => 'COPPA mailing address', - 'COPPA_MAIL_EXPLAIN' => 'This is the mailing address where parents will send COPPA registration forms.', - 'ENABLE_COPPA' => 'Enable COPPA', - 'ENABLE_COPPA_EXPLAIN' => 'This requires users to declare whether they are 13 or over for compliance with the U.S. COPPA. If this is disabled the COPPA specific groups will no longer be displayed.', - 'MAX_CHARS' => 'Max', - 'MIN_CHARS' => 'Min', - 'NO_AUTH_PLUGIN' => 'No suitable auth plugin found.', - 'PASSWORD_LENGTH' => 'Password length', - 'PASSWORD_LENGTH_EXPLAIN' => 'Minimum and maximum number of characters in passwords.', - 'REG_LIMIT' => 'Registration attempts', - 'REG_LIMIT_EXPLAIN' => 'Number of attempts users can make at solving the anti-spambot task before being locked out of that session.', - 'USERNAME_ALPHA_ONLY' => 'Alphanumeric only', - 'USERNAME_ALPHA_SPACERS' => 'Alphanumeric and spacers', - 'USERNAME_ASCII' => 'ASCII (no international unicode)', - 'USERNAME_LETTER_NUM' => 'Any letter and number', - 'USERNAME_LETTER_NUM_SPACERS' => 'Any letter, number, and spacer', - 'USERNAME_CHARS' => 'Limit username chars', - 'USERNAME_CHARS_ANY' => 'Any character', - 'USERNAME_CHARS_EXPLAIN' => 'Restrict type of characters that may be used in usernames, spacers are: space, -, +, _, [ and ].', - 'USERNAME_LENGTH' => 'Username length', - 'USERNAME_LENGTH_EXPLAIN' => 'Minimum and maximum number of characters in usernames.', -)); - -// Feeds -$lang = array_merge($lang, array( - 'ACP_FEED_MANAGEMENT' => 'General syndication feeds settings', - 'ACP_FEED_MANAGEMENT_EXPLAIN' => 'This module makes available various ATOM feeds, parsing any BBCode in posts to make them readable in external feeds.', - - 'ACP_FEED_GENERAL' => 'General feed settings', - 'ACP_FEED_POST_BASED' => 'Post-based feed settings', - 'ACP_FEED_TOPIC_BASED' => 'Topic-based feed settings', - '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.
Disabling this switches off all feeds, no matter how the options below are set.', - 'ACP_FEED_LIMIT' => 'Number of items', - 'ACP_FEED_LIMIT_EXPLAIN' => 'The maximum number of feed items to display.', - - 'ACP_FEED_OVERALL' => 'Enable board-wide feed', - 'ACP_FEED_OVERALL_EXPLAIN' => 'Board-wide new posts.', - 'ACP_FEED_FORUM' => 'Enable per-forum feeds', - 'ACP_FEED_FORUM_EXPLAIN' => 'Single forum and subforums new posts.', - 'ACP_FEED_TOPIC' => 'Enable per-topic feeds', - 'ACP_FEED_TOPIC_EXPLAIN' => 'Single topics new posts.', - - 'ACP_FEED_TOPICS_NEW' => 'Enable new topics feed', - 'ACP_FEED_TOPICS_NEW_EXPLAIN' => 'Enables the “New Topics” feed, which displays the last created topics including the first post.', - '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.
Select multiple forums by holding CTRL 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.', - - '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 auth=http 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
(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 not included in feeds. Select no forum to pull data from all forums.
Select/Deselect multiple forums by holding CTRL and clicking.', -)); - -// Visual Confirmation Settings -$lang = array_merge($lang, array( - 'ACP_VC_SETTINGS_EXPLAIN' => 'Here you can select and configure plugins, which are designed to block automated form submissions by spambots. These plugins typically work by challenging the user with a CAPTCHA, a test which is designed to be difficult for computers to solve.', - 'ACP_VC_EXT_GET_MORE' => 'For additional (and possibly better) anti-spam plugins, visit the phpBB.com Extensions Database. For more information on preventing spam on your board, visit the phpBB.com Knowledge Base.', - 'AVAILABLE_CAPTCHAS' => 'Available plugins', - 'CAPTCHA_UNAVAILABLE' => 'The plugin cannot be selected as its requirements are not met.', - 'CAPTCHA_GD' => 'GD image', - 'CAPTCHA_GD_3D' => 'GD 3D image', - 'CAPTCHA_GD_FOREGROUND_NOISE' => 'Foreground noise', - 'CAPTCHA_GD_EXPLAIN' => 'Uses GD to make a more advanced anti-spambot image.', - 'CAPTCHA_GD_FOREGROUND_NOISE_EXPLAIN' => 'Use foreground noise to make the image harder to read.', - 'CAPTCHA_GD_X_GRID' => 'Background noise x-axis', - 'CAPTCHA_GD_X_GRID_EXPLAIN' => 'Use lower settings of this to make the image harder to read. 0 will disable x-axis background noise.', - 'CAPTCHA_GD_Y_GRID' => 'Background noise y-axis', - 'CAPTCHA_GD_Y_GRID_EXPLAIN' => 'Use lower settings of this to make the image harder to read. 0 will disable y-axis background noise.', - 'CAPTCHA_GD_WAVE' => 'Wave distortion', - 'CAPTCHA_GD_WAVE_EXPLAIN' => 'This applies a wave distortion to the image.', - 'CAPTCHA_GD_3D_NOISE' => 'Add 3D-noise objects', - 'CAPTCHA_GD_3D_NOISE_EXPLAIN' => 'This adds additional objects to the image, over the letters.', - 'CAPTCHA_GD_FONTS' => 'Use different fonts', - 'CAPTCHA_GD_FONTS_EXPLAIN' => 'This setting controls how many different letter shapes are used. You can just use the default shapes or introduce altered letters. Adding lowercase letters is also possible.', - 'CAPTCHA_FONT_DEFAULT' => 'Default', - 'CAPTCHA_FONT_NEW' => 'New Shapes', - 'CAPTCHA_FONT_LOWER' => 'Also use lowercase', - 'CAPTCHA_NO_GD' => 'Simple image', - 'CAPTCHA_PREVIEW_MSG' => 'Your changes have not been saved, this is just a preview.', - 'CAPTCHA_PREVIEW_EXPLAIN' => 'The plugin as it would look like using the current selection.', - - 'CAPTCHA_SELECT' => 'Installed plugins', - 'CAPTCHA_SELECT_EXPLAIN' => 'The dropdown holds the plugins recognised by the board. Grey entries are not available right now and might need configuration prior to use.', - 'CAPTCHA_CONFIGURE' => 'Configure plugins', - 'CAPTCHA_CONFIGURE_EXPLAIN' => 'Change the settings for the selected plugin.', - 'CONFIGURE' => 'Configure', - 'CAPTCHA_NO_OPTIONS' => 'This plugin has no configuration options.', - - 'VISUAL_CONFIRM_POST' => 'Enable spambot countermeasures for guest postings', - 'VISUAL_CONFIRM_POST_EXPLAIN' => 'Requires guest users to pass the anti-spambot task to help prevent automated postings.', - 'VISUAL_CONFIRM_REG' => 'Enable spambot countermeasures for registrations', - 'VISUAL_CONFIRM_REG_EXPLAIN' => 'Requires new users to pass the anti-spambot task to help prevent automated registrations.', - 'VISUAL_CONFIRM_REFRESH' => 'Allow users to refresh the anti-spambot task', - 'VISUAL_CONFIRM_REFRESH_EXPLAIN' => 'Allows users to request a new anti-spambot task if they are unable to solve the current task during registration. Some plugins might not support this option.', -)); - -// 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 phpBB.com Knowledge Base - Fixing incorrect cookie settings.', - - 'COOKIE_DOMAIN' => 'Cookie domain', - 'COOKIE_DOMAIN_EXPLAIN' => 'In most cases the cookie domain is optional. Leave it blank if you are unsure.

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 example.com and forums.example.com, or perhaps forums.example.com and blog.example.com. Remove the subdomains until you find the common domain, example.com. 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' => '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', - 'ONLINE_LENGTH_EXPLAIN' => 'Number of minutes after which inactive users will not appear in “Who is online” listings. The higher this value the greater is the processing required to generate the listing.', - 'SESSION_LENGTH' => 'Session length', - 'SESSION_LENGTH_EXPLAIN' => 'Sessions will expire after this time, in seconds.', -)); - -// Contact Settings -$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. Please note that board-wide emails option must be enabled as well. You can find this option in General > Client Communication > Email settings.', - - 'CONTACT_US_INFO' => 'Contact information', - 'CONTACT_US_INFO_EXPLAIN' => 'The message is displayed on the contact page', - 'CONTACT_US_INFO_PREVIEW' => 'Contact page information - Preview', - 'CONTACT_US_INFO_UPDATED' => 'Contact page information has been updated.', -)); - -// Load Settings -$lang = array_merge($lang, array( - 'ACP_LOAD_SETTINGS_EXPLAIN' => 'Here you can enable and disable certain board functions to reduce the amount of processing required. On most servers there is no need to disable any functions. However on certain systems or in shared hosting environments it may be beneficial to disable capabilities you do not really need. You can also specify limits for system load and active sessions beyond which the board will go offline.', - - 'ALLOW_CDN' => 'Allow usage of third party content delivery networks', - 'ALLOW_CDN_EXPLAIN' => 'If this setting is enabled, some files will be served from external third party servers instead of your server. This reduces the network bandwidth required by your server, but may present a privacy issue for some board administrators. In a default phpBB installation, this includes loading “jQuery” and the font “Open Sans” from Google’s content delivery network.', - 'ALLOW_LIVE_SEARCHES' => 'Allow live searches', - 'ALLOW_LIVE_SEARCHES_EXPLAIN' => 'If this setting is enabled, users are provided with keyword suggestions as they type in certain fields throughout the board.', - 'CUSTOM_PROFILE_FIELDS' => 'Custom profile fields', - 'LIMIT_LOAD' => 'Limit system load', - 'LIMIT_LOAD_EXPLAIN' => 'If the system’s 1-minute load average exceeds this value the board will automatically go offline. A value of 1.0 equals ~100% utilisation of one processor. This only functions on UNIX based servers and where this information is accessible. The value here resets itself to 0 if phpBB was unable to get the load limit.', - 'LIMIT_SESSIONS' => 'Limit sessions', - 'LIMIT_SESSIONS_EXPLAIN' => 'If the number of sessions exceeds this value within a one minute period the board will go offline. Set to 0 for unlimited sessions.', - 'LOAD_CPF_MEMBERLIST' => 'Allow styles to display custom profile fields in memberlist', - 'LOAD_CPF_PM' => 'Display custom profile fields in private messages', - 'LOAD_CPF_VIEWPROFILE' => 'Display custom profile fields in user profiles', - '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', - 'YES_BIRTHDAYS_EXPLAIN' => 'If disabled the birthday listing is no longer displayed. To let this setting take effect the birthday feature needs to be enabled too.', - 'YES_JUMPBOX' => 'Enable display of jumpbox', - 'YES_MODERATORS' => 'Enable display of moderators', - 'YES_ONLINE' => 'Enable online user listings', - 'YES_ONLINE_EXPLAIN' => 'Display online user information on index, forum and topic pages.', - 'YES_ONLINE_GUESTS' => 'Enable online guest listings in viewonline', - 'YES_ONLINE_GUESTS_EXPLAIN' => 'Allow display of guest user information in viewonline.', - 'YES_ONLINE_TRACK' => 'Enable display of user online/offline information', - 'YES_ONLINE_TRACK_EXPLAIN' => 'Display online information for user in profiles and topic pages.', - 'YES_POST_MARKING' => 'Enable dotted topics', - 'YES_POST_MARKING_EXPLAIN' => 'Indicates whether user has posted to a topic.', - 'YES_READ_MARKING' => 'Enable server-side topic marking', - 'YES_READ_MARKING_EXPLAIN' => 'Stores read/unread status information in the database rather than a cookie.', - 'YES_UNREAD_SEARCH' => 'Enable search for unread posts', -)); - -// Auth settings -$lang = array_merge($lang, array( - 'ACP_AUTH_SETTINGS_EXPLAIN' => 'phpBB supports authentication plug-ins, or modules. These allow you determine how users are authenticated when they log into the board. By default four plug-ins are provided: DB, LDAP, Apache, and OAuth. Not all methods require additional information so only fill out fields if they are relevant to the selected method.', - - '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.
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', - - 'APACHE_SETUP_BEFORE_USE' => 'You have to setup apache authentication before you switch phpBB to this authentication method. Keep in mind that the username you use for apache authentication has to be the same as your phpBB username. Apache authentication can only be used with mod_php (not with a CGI version).', - - 'LDAP' => 'LDAP', - 'LDAP_DN' => 'LDAP base dn', - 'LDAP_DN_EXPLAIN' => 'This is the Distinguished Name, locating the user information, e.g. o=My Company,c=US.', - 'LDAP_EMAIL' => 'LDAP email attribute', - 'LDAP_EMAIL_EXPLAIN' => 'Set this to the name of your user entry email attribute (if one exists) in order to automatically set the email address for new users. Leaving this empty results in empty email address for users who log in for the first time.', - 'LDAP_INCORRECT_USER_PASSWORD' => 'Binding to LDAP server failed with specified user/password.', - '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.
Warning: 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.', - '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', - 'LDAP_SERVER_EXPLAIN' => 'If using LDAP this is the hostname or IP address of the LDAP server. Alternatively you can specify an URL like ldap://hostname:port/', - 'LDAP_UID' => 'LDAP uid', - 'LDAP_UID_EXPLAIN' => 'This is the key under which to search for a given login identity, e.g. uid, sn, etc.', - 'LDAP_USER' => 'LDAP user dn', - 'LDAP_USER_EXPLAIN' => 'Leave blank to use anonymous binding. If filled in phpBB uses the specified distinguished name on login attempts to find the correct user, e.g. uid=Username,ou=MyUnit,o=MyCompany,c=US. Required for Active Directory Servers.', - 'LDAP_USER_FILTER' => 'LDAP user filter', - 'LDAP_USER_FILTER_EXPLAIN' => 'Optionally you can further limit the searched objects with additional filters. For example objectClass=posixGroup would result in the use of (&(uid=$username)(objectClass=posixGroup))', -)); - -// Server Settings -$lang = array_merge($lang, array( - 'ACP_SERVER_SETTINGS_EXPLAIN' => 'Here you define server and domain dependent settings. Please ensure the data you enter is accurate, errors will result in emails containing incorrect information. When entering the domain name remember it does include http:// or other protocol term. Only alter the port number if you know your server uses a different value, port 80 is correct in most cases.', - - 'ENABLE_GZIP' => 'Enable GZip compression', - 'ENABLE_GZIP_EXPLAIN' => 'Generated content will be compressed prior to sending it to the user. This can reduce network traffic but will also increase CPU usage on both server and client side. Requires zlib PHP extension to be loaded.', - 'FORCE_SERVER_VARS' => 'Force server URL settings', - 'FORCE_SERVER_VARS_EXPLAIN' => 'If set to yes the server settings defined here will be used in favour of the automatically determined values.', - 'ICONS_PATH' => 'Post icons storage path', - 'ICONS_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/icons.', - 'MOD_REWRITE_ENABLE' => 'Enable URL Rewriting', - 'MOD_REWRITE_ENABLE_EXPLAIN' => 'When enabled, URLs containing ’app.php’ will be rewritten to remove the filename (i.e. app.php/foo will become /foo). Apache server’s mod_rewrite module is required for this functionality to work; if this option is enabled without mod_rewrite support, URLs on your board may be broken.', - 'MOD_REWRITE_DISABLED' => 'The mod_rewrite module on your Apache web server is disabled. Enable the module or contact your web hosting provider if you wish to enable this feature.', - 'MOD_REWRITE_INFORMATION_UNAVAILABLE' => 'We are unable to determine whether or not this server supports URL rewriting. This setting may be enabled but if URL rewriting is not available, paths generated by this board (such as for use in links) may be broken. Contact your web hosting provider if you are unsure whether or not you can safely enable this feature.', - 'PATH_SETTINGS' => 'Path settings', - 'RANKS_PATH' => 'Rank image storage path', - 'RANKS_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/ranks.', - 'SCRIPT_PATH' => 'Script path', - 'SCRIPT_PATH_EXPLAIN' => 'The path where phpBB is located relative to the domain name, e.g. /phpBB3.', - 'SERVER_NAME' => 'Domain name', - 'SERVER_NAME_EXPLAIN' => 'The domain name this board runs from (for example: www.example.com).', - 'SERVER_PORT' => 'Server port', - 'SERVER_PORT_EXPLAIN' => 'The port your server is running on, usually 80, only change if different.', - 'SERVER_PROTOCOL' => 'Server protocol', - 'SERVER_PROTOCOL_EXPLAIN' => 'This is used as the server protocol if these settings are forced. If empty or not forced the protocol is determined by the cookie secure settings (http:// or https://).', - 'SERVER_URL_SETTINGS' => 'Server URL settings', - 'SMILIES_PATH' => 'Smilies storage path', - 'SMILIES_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/smilies.', - 'UPLOAD_ICONS_PATH' => 'Extension group icons storage path', - 'UPLOAD_ICONS_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/upload_icons.', - 'USE_SYSTEM_CRON' => 'Run periodic tasks from system cron', - 'USE_SYSTEM_CRON_EXPLAIN' => 'When off, phpBB will arrange for periodic tasks to be run automatically. When on, phpBB will not schedule any periodic tasks by itself; a system administrator must arrange for bin/phpbbcli.php cron:run to be run by the system cron facility at regular intervals (e.g. every 5 minutes).', -)); - -// Security Settings -$lang = array_merge($lang, array( - 'ACP_SECURITY_SETTINGS_EXPLAIN' => 'Here you are able to define session and login related settings.', - - 'ALL' => 'All', - 'ALLOW_AUTOLOGIN' => 'Allow "Remember Me" logins', - 'ALLOW_AUTOLOGIN_EXPLAIN' => 'Determines whether users are given "Remember Me" option when they visit the board.', - 'ALLOW_PASSWORD_RESET' => 'Allow password reset ("Forgot Password")', - 'ALLOW_PASSWORD_RESET_EXPLAIN' => 'Determines whether or not users are able to use the "I forgot my password" link on the login page to recover their account. If you use an external authentication mechanism you may wish to disable this feature.', - 'AUTOLOGIN_LENGTH' => '"Remember Me" login key expiration length (in days)', - 'AUTOLOGIN_LENGTH_EXPLAIN' => 'Number of days after which "Remember Me" login keys are removed or zero to disable.', - 'BROWSER_VALID' => 'Validate browser', - 'BROWSER_VALID_EXPLAIN' => 'Enables browser validation for each session improving security.', - 'CHECK_DNSBL' => 'Check IP against DNS Blackhole List', - 'CHECK_DNSBL_EXPLAIN' => 'If enabled the user’s IP address is checked against the following DNSBL services on registration and posting: spamcop.net and www.spamhaus.org. This lookup may take a while, depending on the server’s configuration. If slowdowns are experienced or too many false positives reported it is recommended to disable this check.', - 'CLASS_B' => 'A.B', - 'CLASS_C' => 'A.B.C', - 'EMAIL_CHECK_MX' => 'Check email domain for valid MX record', - 'EMAIL_CHECK_MX_EXPLAIN' => 'If enabled, the email domain provided on registration and profile changes is checked for a valid MX record.', - 'FORCE_PASS_CHANGE' => 'Force password change', - 'FORCE_PASS_CHANGE_EXPLAIN' => 'Require user to change their password after a set number of days. Setting this value to 0 disables this behaviour.', - 'FORM_TIME_MAX' => 'Maximum time to submit forms', - 'FORM_TIME_MAX_EXPLAIN' => 'The time a user has to submit a form. Use -1 to disable. Note that a form might become invalid if the session expires, regardless of this setting.', - 'FORM_SID_GUESTS' => 'Tie forms to guest sessions', - 'FORM_SID_GUESTS_EXPLAIN' => 'If enabled, the form token issued to guests will be session-exclusive. This can cause problems with some ISPs.', - 'FORWARDED_FOR_VALID' => 'Validate X_FORWARDED_FOR header', - 'FORWARDED_FOR_VALID_EXPLAIN' => 'Sessions will only be continued if the sent X_FORWARDED_FOR header equals the one sent with the previous request. Bans will be checked against IPs in X_FORWARDED_FOR too.', - 'IP_VALID' => 'Session IP validation', - 'IP_VALID_EXPLAIN' => 'Determines how much of the users IP is used to validate a session; All compares the complete address, A.B.C the first x.x.x, A.B the first x.x, None disables checking. On IPv6 addresses A.B.C compares the first 4 blocks and A.B the first 3 blocks.', - 'IP_LOGIN_LIMIT_MAX' => 'Maximum number of login attempts per IP address', - 'IP_LOGIN_LIMIT_MAX_EXPLAIN' => 'The threshold of login attempts allowed from a single IP address before an anti-spambot task is triggered. Enter 0 to prevent the anti-spambot task from being triggered by IP addresses.', - '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 X_FORWARDED_FOR header', - 'IP_LOGIN_LIMIT_USE_FORWARDED_EXPLAIN' => 'Instead of limiting login attempts by IP address they are limited by X_FORWARDED_FOR values.
Warning: Only enable this if you are operating a proxy server that sets X_FORWARDED_FOR to trustworthy values.', - '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', - 'NO_REF_VALIDATION' => 'None', - 'PASSWORD_TYPE' => 'Password complexity', - 'PASSWORD_TYPE_EXPLAIN' => 'Determines how complex a password needs to be when set or altered, subsequent options include the previous ones.', - 'PASS_TYPE_ALPHA' => 'Must contain letters and numbers', - 'PASS_TYPE_ANY' => 'No requirements', - 'PASS_TYPE_CASE' => 'Must be mixed case', - 'PASS_TYPE_SYMBOL' => 'Must contain symbols', - 'REF_HOST' => 'Only validate host', - 'REF_PATH' => 'Also validate path', - 'REFERRER_VALID' => 'Validate Referrer', - '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, PHP and INCLUDEPHP 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 openssl.cafile or curl.cainfo 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' => '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 Sender 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', - 'BOARD_HIDE_EMAILS_EXPLAIN' => 'This function keeps email addresses completely private.', - 'CONTACT_EMAIL' => 'Contact email address', - '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 From and Reply-To 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_FORCE_SENDER' => 'Force from email address', - 'EMAIL_FORCE_SENDER_EXPLAIN' => 'This will set the Return-Path to the from email address instead of using the local user and hostname of the server. This setting does not apply when using SMTP.
Warning: Requires the user that the webserver runs as to be added as trusted user to the sendmail configuration.', - '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. 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.', - '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.
Warning: Allowing self-signed SSL certificates may cause security implications.', - '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.
Warning: 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.', - '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' => 'Do not provide a protocol (ssl:// or tls://) 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.
Warning: Connecting peers with unverified SSL certificates may cause security implications.', - '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.
Warning: Connecting to unverified peers may cause security implications.', - 'TEST_EMAIL_SENT' => 'The test email has been sent.
If you don’t receive it, please check your emails configuration.

If you require assistance, please visit the phpBB support forums.', - - '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.', -)); - -// Jabber settings -$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.
Warning: Allowing self-signed SSL certificates may cause security implications.', - '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 dns_get_record 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.', - 'JAB_PACKAGE_SIZE' => 'Jabber package size', - 'JAB_PACKAGE_SIZE_EXPLAIN' => 'This is the number of messages sent in one package. If set to 0 the message is sent immediately and will not be queued for later sending.', - 'JAB_PASSWORD' => 'Jabber password', - 'JAB_PASSWORD_EXPLAIN' => 'Warning: 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.', - 'JAB_PORT' => 'Jabber port', - 'JAB_PORT_EXPLAIN' => 'Leave blank unless you know it is not port 5222.', - 'JAB_SERVER' => 'Jabber server', - 'JAB_SERVER_EXPLAIN' => 'See %sjabber.org%s for a list of servers.', - 'JAB_SETTINGS_CHANGED' => 'Jabber settings changed successfully.', - 'JAB_USE_SSL' => 'Use SSL to connect', - 'JAB_USE_SSL_EXPLAIN' => 'If enabled a secure connection is tried to be established. The Jabber port will be modified to 5223 if port 5222 is specified.', - '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.
Warning: Connecting peers with unverified SSL certificates may cause security implications.', - '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.
Warning: Connecting to unverified peers may cause security implications.', -)); diff --git a/install/update/new/language/en/acp/common.php b/install/update/new/language/en/acp/common.php deleted file mode 100644 index 5ac4b44..0000000 --- a/install/update/new/language/en/acp/common.php +++ /dev/null @@ -1,823 +0,0 @@ - -* @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(); -} - -// 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 - -// Common -$lang = array_merge($lang, array( - 'ACP_ADMINISTRATORS' => 'Administrators', - 'ACP_ADMIN_LOGS' => 'Admin log', - 'ACP_ADMIN_ROLES' => 'Admin roles', - 'ACP_ATTACHMENTS' => 'Attachments', - 'ACP_ATTACHMENT_SETTINGS' => 'Attachment settings', - 'ACP_AUTH_SETTINGS' => 'Authentication', - 'ACP_AUTOMATION' => 'Automation', - 'ACP_AVATAR_SETTINGS' => 'Avatar settings', - - 'ACP_BACKUP' => 'Backup', - 'ACP_BAN' => 'Banning', - 'ACP_BAN_EMAILS' => 'Ban emails', - 'ACP_BAN_IPS' => 'Ban IPs', - 'ACP_BAN_USERNAMES' => 'Ban users', - 'ACP_BBCODES' => 'BBCodes', - 'ACP_BOARD_CONFIGURATION' => 'Board configuration', - 'ACP_BOARD_FEATURES' => 'Board features', - 'ACP_BOARD_MANAGEMENT' => 'Board management', - 'ACP_BOARD_SETTINGS' => 'Board settings', - 'ACP_BOTS' => 'Spiders/Robots', - - 'ACP_CAPTCHA' => 'CAPTCHA', - - 'ACP_CAT_CUSTOMISE' => 'Customise', - 'ACP_CAT_DATABASE' => 'Database', - 'ACP_CAT_DOT_MODS' => 'Extensions', - 'ACP_CAT_FORUMS' => 'Forums', - 'ACP_CAT_GENERAL' => 'General', - 'ACP_CAT_MAINTENANCE' => 'Maintenance', - 'ACP_CAT_PERMISSIONS' => 'Permissions', - 'ACP_CAT_POSTING' => 'Posting', - 'ACP_CAT_STYLES' => 'Styles', - 'ACP_CAT_SYSTEM' => 'System', - 'ACP_CAT_USERGROUP' => 'Users and Groups', - 'ACP_CAT_USERS' => 'Users', - 'ACP_CLIENT_COMMUNICATION' => 'Client communication', - 'ACP_COOKIE_SETTINGS' => 'Cookie settings', - 'ACP_CONTACT' => 'Contact page', - 'ACP_CONTACT_SETTINGS' => 'Contact page settings', - 'ACP_CRITICAL_LOGS' => 'Error log', - 'ACP_CUSTOM_PROFILE_FIELDS' => 'Custom profile fields', - - 'ACP_DATABASE' => 'Database management', - 'ACP_DISALLOW' => 'Disallow', - 'ACP_DISALLOW_USERNAMES' => 'Disallow usernames', - - 'ACP_EMAIL_SETTINGS' => 'Email settings', - 'ACP_EXTENSION_GROUPS' => 'Manage attachment extension groups', - 'ACP_EXTENSION_MANAGEMENT' => 'Extension management', - 'ACP_EXTENSIONS' => 'Manage extensions', - - 'ACP_FORUM_BASED_PERMISSIONS' => 'Forum based permissions', - 'ACP_FORUM_LOGS' => 'Forum logs', - 'ACP_FORUM_MANAGEMENT' => 'Forum management', - 'ACP_FORUM_MODERATORS' => 'Forum moderators', - 'ACP_FORUM_PERMISSIONS' => 'Forum permissions', - 'ACP_FORUM_PERMISSIONS_COPY' => 'Copy forum permissions', - 'ACP_FORUM_ROLES' => 'Forum roles', - - 'ACP_GENERAL_CONFIGURATION' => 'General configuration', - 'ACP_GENERAL_TASKS' => 'General tasks', - 'ACP_GLOBAL_MODERATORS' => 'Global moderators', - 'ACP_GLOBAL_PERMISSIONS' => 'Global permissions', - 'ACP_GROUPS' => 'Groups', - 'ACP_GROUPS_FORUM_PERMISSIONS' => 'Group forum permissions', - 'ACP_GROUPS_MANAGE' => 'Manage groups', - 'ACP_GROUPS_MANAGEMENT' => 'Group management', - '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', - 'ACP_INDEX' => 'ACP index', - - 'ACP_JABBER_SETTINGS' => 'Jabber settings', - - 'ACP_LANGUAGE' => 'Language management', - 'ACP_LANGUAGE_PACKS' => 'Language packs', - 'ACP_LOAD_SETTINGS' => 'Load settings', - 'ACP_LOGGING' => 'Logging', - - 'ACP_MAIN' => 'ACP index', - - 'ACP_MANAGE_ATTACHMENTS' => 'Manage attachments', - 'ACP_MANAGE_ATTACHMENTS_EXPLAIN' => 'Here you can list and delete files attached to posts and private messages.', - - 'ACP_MANAGE_EXTENSIONS' => 'Manage attachment extensions', - 'ACP_MANAGE_FORUMS' => 'Manage forums', - 'ACP_MANAGE_RANKS' => 'Manage ranks', - 'ACP_MANAGE_REASONS' => 'Manage report/denial reasons', - 'ACP_MANAGE_USERS' => 'Manage users', - 'ACP_MASS_EMAIL' => 'Mass email', - 'ACP_MESSAGES' => 'Messages', - 'ACP_MESSAGE_SETTINGS' => 'Private message settings', - 'ACP_MODULE_MANAGEMENT' => 'Module management', - 'ACP_MOD_LOGS' => 'Moderator log', - 'ACP_MOD_ROLES' => 'Moderator roles', - - 'ACP_NO_ITEMS' => 'There are no items yet.', - - 'ACP_ORPHAN_ATTACHMENTS' => 'Orphaned attachments', - - 'ACP_PERMISSIONS' => 'Permissions', - 'ACP_PERMISSION_MASKS' => 'Permission masks', - 'ACP_PERMISSION_ROLES' => 'Permission roles', - 'ACP_PERMISSION_TRACE' => 'Permission trace', - 'ACP_PHP_INFO' => 'PHP information', - 'ACP_POST_SETTINGS' => 'Post settings', - 'ACP_PRUNE_FORUMS' => 'Prune forums', - 'ACP_PRUNE_USERS' => 'Prune users', - 'ACP_PRUNING' => 'Pruning', - - 'ACP_QUICK_ACCESS' => 'Quick access', - - 'ACP_RANKS' => 'Ranks', - 'ACP_REASONS' => 'Report/denial reasons', - 'ACP_REGISTER_SETTINGS' => 'User registration settings', - - 'ACP_RESTORE' => 'Restore', - - 'ACP_FEED' => 'Feed management', - 'ACP_FEED_SETTINGS' => 'Feed settings', - - 'ACP_SEARCH' => 'Search configuration', - 'ACP_SEARCH_INDEX' => 'Search index', - 'ACP_SEARCH_SETTINGS' => 'Search settings', - - 'ACP_SECURITY_SETTINGS' => 'Security settings', - 'ACP_SERVER_CONFIGURATION' => 'Server configuration', - 'ACP_SERVER_SETTINGS' => 'Server settings', - 'ACP_SIGNATURE_SETTINGS' => 'Signature settings', - 'ACP_SMILIES' => 'Smilies', - 'ACP_STYLE_MANAGEMENT' => 'Style management', - 'ACP_STYLES' => 'Styles', - 'ACP_STYLES_CACHE' => 'Purge Cache', - 'ACP_STYLES_INSTALL' => 'Install Styles', - - 'ACP_SUBMIT_CHANGES' => 'Submit changes', - - 'ACP_TEMPLATES' => 'Templates', - 'ACP_THEMES' => 'Themes', - - 'ACP_UPDATE' => 'Updating', - 'ACP_USERS_FORUM_PERMISSIONS' => 'User forum permissions', - 'ACP_USERS_LOGS' => 'User logs', - 'ACP_USERS_PERMISSIONS' => 'User permissions', - 'ACP_USER_ATTACH' => 'Attachments', - 'ACP_USER_AVATAR' => 'Avatar', - 'ACP_USER_FEEDBACK' => 'Feedback', - 'ACP_USER_GROUPS' => 'Groups', - 'ACP_USER_MANAGEMENT' => 'User management', - 'ACP_USER_OVERVIEW' => 'Overview', - 'ACP_USER_PERM' => 'Permissions', - 'ACP_USER_PREFS' => 'Preferences', - 'ACP_USER_PROFILE' => 'Profile', - 'ACP_USER_RANK' => 'Rank', - 'ACP_USER_ROLES' => 'User roles', - 'ACP_USER_SECURITY' => 'User security', - 'ACP_USER_SIG' => 'Signature', - 'ACP_USER_WARNINGS' => 'Warnings', - - 'ACP_VC_SETTINGS' => 'Spambot countermeasures', - 'ACP_VC_CAPTCHA_DISPLAY' => 'CAPTCHA image preview', - 'ACP_VERSION_CHECK' => 'Check for updates', - 'ACP_VIEW_ADMIN_PERMISSIONS' => 'View administrative permissions', - 'ACP_VIEW_FORUM_MOD_PERMISSIONS' => 'View forum moderation permissions', - 'ACP_VIEW_FORUM_PERMISSIONS' => 'View forum-based permissions', - 'ACP_VIEW_GLOBAL_MOD_PERMISSIONS' => 'View global moderation permissions', - 'ACP_VIEW_USER_PERMISSIONS' => 'View user-based permissions', - - 'ACP_WORDS' => 'Word censoring', - - 'ACTION' => 'Action', - 'ACTIONS' => 'Actions', - 'ACTIVATE' => 'Activate', - 'ADD' => 'Add', - 'ADMIN' => 'Administration', - 'ADMIN_INDEX' => 'Admin index', - 'ADMIN_PANEL' => 'Administration Control Panel', - - 'ADM_LOGOUT' => 'ACP Logout', - 'ADM_LOGGED_OUT' => 'Successfully logged out from Administration Control Panel', - - 'BACK' => 'Back', - - '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 phpBB.com 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.', - 'DIRECTORY_NOT_DIR' => 'The entered path “%s” is not a directory.', - 'DIRECTORY_NOT_WRITABLE' => 'The entered path “%s” is not writable.', - 'DISABLE' => 'Disable', - 'DOWNLOAD' => 'Download', - 'DOWNLOAD_AS' => 'Download as', - 'DOWNLOAD_STORE' => 'Download or store file', - 'DOWNLOAD_STORE_EXPLAIN' => 'You may directly download the file or save it in your store/ folder.', - 'DOWNLOADS' => 'Downloads', - - 'EDIT' => 'Edit', - 'ENABLE' => 'Enable', - 'EXPORT_DOWNLOAD' => 'Download', - 'EXPORT_STORE' => 'Store', - - 'GENERAL_OPTIONS' => 'General options', - 'GENERAL_SETTINGS' => 'General settings', - 'GLOBAL_MASK' => 'Global permission mask', - - 'INSTALL' => 'Install', - '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:', - 'LOGIN_ADMIN' => 'To administer the board you must be an authenticated user.', - 'LOGIN_ADMIN_CONFIRM' => 'To administer the board you must re-authenticate yourself.', - 'LOGIN_ADMIN_SUCCESS' => 'You have successfully authenticated and will now be redirected to the Administration Control Panel.', - 'LOOK_UP_FORUM' => 'Select a forum', - 'LOOK_UP_FORUMS_EXPLAIN'=> 'You are able to select more than one forum.', - - 'MANAGE' => 'Manage', - 'MENU_TOGGLE' => 'Hide or display the side menu', - 'MORE' => 'More', // Not used at the moment - 'MORE_INFORMATION' => 'More information »', - 'MOVE_DOWN' => 'Move down', - 'MOVE_UP' => 'Move up', - - 'NOTIFY' => 'Notification', - 'NO_ADMIN' => 'You are not authorised to administer this board.', - 'NO_EMAILS_DEFINED' => 'No valid email addresses found.', - 'NO_FILES_TO_DELETE' => 'Attachments you selected for deletion do not exist.', - 'NO_PASSWORD_SUPPLIED' => 'You need to enter your password to access the Administration Control Panel.', - - 'OFF' => 'Off', - 'ON' => 'On', - - 'PARSE_BBCODE' => 'Parse BBCode', - 'PARSE_SMILIES' => 'Parse smilies', - 'PARSE_URLS' => 'Parse links', - 'PERMISSIONS_TRANSFERRED' => 'Permissions transferred', - '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 revert to your permission set 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.', - 'SELECT_ANONYMOUS' => 'Select anonymous user', - 'SELECT_OPTION' => 'Select option', - - 'SETTING_TOO_LOW' => 'The provided value for the setting “%1$s” is too low. The minimum acceptable value is %2$d.', - 'SETTING_TOO_BIG' => 'The provided value for the setting “%1$s” is too high. The maximum acceptable value is %2$d.', - 'SETTING_TOO_LONG' => 'The provided value for the setting “%1$s” is too long. The maximum acceptable length is %2$d.', - 'SETTING_TOO_SHORT' => 'The provided value for the setting “%1$s” is too short. The minimum acceptable length is %2$d.', - - 'SHOW_ALL_OPERATIONS' => 'Show all operations', - - 'TASKS_NOT_READY' => 'Not ready tasks:', - 'TASKS_READY' => 'Ready tasks:', - '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', -)); - -// PHP info -$lang = array_merge($lang, array( - 'ACP_PHP_INFO_EXPLAIN' => 'This page lists information on the version of PHP installed on this server. It includes details of loaded modules, available variables and default settings. This information may be useful when diagnosing problems. Please be aware that some hosting companies will limit what information is displayed here for security reasons. You are advised to not give out any details on this page except when asked by official team members on the support forums.', - - 'NO_PHPINFO_AVAILABLE' => 'Information about your PHP configuration is unable to be determined. Phpinfo() has been disabled for security reasons.', -)); - -// Logs -$lang = array_merge($lang, array( - 'ACP_ADMIN_LOGS_EXPLAIN' => 'This lists all the actions carried out by board administrators. You can sort by username, date, IP or action. If you have appropriate permissions you can also clear individual operations or the log as a whole.', - 'ACP_CRITICAL_LOGS_EXPLAIN' => 'This lists the actions carried out by the board itself. This log provides you with information you are able to use for solving specific problems, for example non-delivery of emails. You can sort by username, date, IP or action. If you have appropriate permissions you can also clear individual operations or the log as a whole.', - 'ACP_MOD_LOGS_EXPLAIN' => 'This lists all actions done on forums, topics and posts as well as actions carried out on users by moderators, including banning. You can sort by username, date, IP or action. If you have appropriate permissions you can also clear individual operations or the log as a whole.', - 'ACP_USERS_LOGS_EXPLAIN' => 'This lists all actions carried out by users or on users (reports, warnings and user notes).', - 'ALL_ENTRIES' => 'All entries', - - 'DISPLAY_LOG' => 'Display entries from previous', - - 'NO_ENTRIES' => 'No log entries for this period.', - - 'SORT_IP' => 'IP address', - 'SORT_DATE' => 'Date', - 'SORT_ACTION' => 'Log action', -)); - -// Index page -$lang = array_merge($lang, array( - 'ADMIN_INTRO' => 'Thank you for choosing phpBB as your board solution. This screen will give you a quick overview of all the various statistics of your board. The links on the left hand side of this screen allow you to control every aspect of your board experience. Each page will have instructions on how to use the tools.', - 'ADMIN_LOG' => 'Logged administrator actions', - 'ADMIN_LOG_INDEX_EXPLAIN' => 'This gives an overview of the last five actions carried out by board administrators. A full copy of the log can be viewed from the appropriate menu item or following the link below.', - 'AVATAR_DIR_SIZE' => 'Avatar directory size', - - 'BOARD_STARTED' => 'Board started', - 'BOARD_VERSION' => 'Board version', - - 'DATABASE_SERVER_INFO' => 'Database server', - 'DATABASE_SIZE' => 'Database size', - - // Environment configuration checks, mbstring related - 'ERROR_MBSTRING_FUNC_OVERLOAD' => 'Function overloading is improperly configured', - 'ERROR_MBSTRING_FUNC_OVERLOAD_EXPLAIN' => 'mbstring.func_overload must be set to either 0 or 4. You can check the current value on the PHP information page.', - 'ERROR_MBSTRING_ENCODING_TRANSLATION' => 'Transparent character encoding is improperly configured', - 'ERROR_MBSTRING_ENCODING_TRANSLATION_EXPLAIN' => 'mbstring.encoding_translation must be set to 0. You can check the current value on the PHP information page.', - 'ERROR_MBSTRING_HTTP_INPUT' => 'HTTP input character conversion is improperly configured', - 'ERROR_MBSTRING_HTTP_INPUT_EXPLAIN' => 'mbstring.http_input must be set to pass. You can check the current value on the PHP information page.', - 'ERROR_MBSTRING_HTTP_OUTPUT' => 'HTTP output character conversion is improperly configured', - 'ERROR_MBSTRING_HTTP_OUTPUT_EXPLAIN' => 'mbstring.http_output must be set to pass. You can check the current value on the PHP information page.', - - 'FILES_PER_DAY' => 'Attachments per day', - 'FORUM_STATS' => 'Board statistics', - - 'GZIP_COMPRESSION' => 'GZip compression', - - 'NO_SEARCH_INDEX' => 'The selected search backend does not have a search index.
Please create the index for “%1$s” in the %2$ssearch index%3$s section.', - 'NOT_AVAILABLE' => 'Not available', - 'NUMBER_FILES' => 'Number of attachments', - 'NUMBER_POSTS' => 'Number of posts', - 'NUMBER_TOPICS' => 'Number of topics', - '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', - - 'PURGE_CACHE' => 'Purge the cache', - 'PURGE_CACHE_CONFIRM' => 'Are you sure you wish to purge the cache?', - 'PURGE_CACHE_EXPLAIN' => 'Purge all cache related items, this includes any cached template files or queries.', - 'PURGE_CACHE_SUCCESS' => 'Cache successfully purged.', - - 'PURGE_SESSIONS' => 'Purge all sessions', - 'PURGE_SESSIONS_CONFIRM' => 'Are you sure you wish to purge all sessions? This will log out all users.', - 'PURGE_SESSIONS_EXPLAIN' => 'Purge all sessions. This will log out all users by truncating the session table.', - 'PURGE_SESSIONS_SUCCESS' => 'Sessions successfully purged.', - - 'RESET_DATE' => 'Reset board’s start date', - 'RESET_DATE_CONFIRM' => 'Are you sure you wish to reset the board’s start date?', - 'RESET_DATE_SUCCESS' => 'Board’s start date reset', - 'RESET_ONLINE' => 'Reset most users ever online', - 'RESET_ONLINE_CONFIRM' => 'Are you sure you wish to reset the most users ever online counter?', - 'RESET_ONLINE_SUCCESS' => 'Most users ever online reset', - 'RESYNC_POSTCOUNTS' => 'Resynchronise post counts', - 'RESYNC_POSTCOUNTS_EXPLAIN' => 'Only existing posts will be taken into consideration. Pruned posts will not be counted.', - 'RESYNC_POSTCOUNTS_CONFIRM' => 'Are you sure you wish to resynchronise post counts?', - 'RESYNC_POSTCOUNTS_SUCCESS' => 'Resynchronised post counts', - 'RESYNC_POST_MARKING' => 'Resynchronise dotted topics', - 'RESYNC_POST_MARKING_CONFIRM' => 'Are you sure you wish to resynchronise dotted topics?', - 'RESYNC_POST_MARKING_EXPLAIN' => 'First unmarks all topics and then correctly marks topics that have seen any activity during the past six months.', - 'RESYNC_POST_MARKING_SUCCESS' => 'Resynchronised dotted topics', - 'RESYNC_STATS' => 'Resynchronise statistics', - 'RESYNC_STATS_CONFIRM' => 'Are you sure you wish to resynchronise statistics?', - 'RESYNC_STATS_EXPLAIN' => 'Recalculates the total number of posts, topics, users and files.', - 'RESYNC_STATS_SUCCESS' => 'Resynchronised statistics', - 'RUN' => 'Run now', - - 'STATISTIC' => 'Statistic', - 'STATISTIC_RESYNC_OPTIONS' => 'Resynchronise or reset statistics', - - 'TIMEZONE_INVALID' => 'The timezone you selected is invalid.', - 'TIMEZONE_SELECTED' => '(currently selected)', - 'TOPICS_PER_DAY' => 'Topics per day', - - 'UPLOAD_DIR_SIZE' => 'Size of posted attachments', - 'USERS_PER_DAY' => 'Users per day', - - '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.
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', - - 'WELCOME_PHPBB' => 'Welcome to phpBB', - 'WRITABLE_CONFIG' => 'Your config file (config.php) is currently world-writable. We strongly encourage you to change the permissions to 640 or at least to 644 (for example: chmod 640 config.php).', -)); - -// Inactive Users -$lang = array_merge($lang, array( - 'INACTIVE_DATE' => 'Inactive date', - 'INACTIVE_REASON' => 'Reason', - 'INACTIVE_REASON_MANUAL' => 'Account deactivated by administrator', - 'INACTIVE_REASON_PROFILE' => 'Profile details changed', - 'INACTIVE_REASON_REGISTER' => 'Newly registered account', - 'INACTIVE_REASON_REMIND' => 'Forced user account reactivation', - 'INACTIVE_REASON_UNKNOWN' => 'Unknown', - 'INACTIVE_USERS' => 'Inactive users', - 'INACTIVE_USERS_EXPLAIN' => 'This is a list of users who have registered but whose accounts are inactive. You can activate, delete or remind (by sending an email) these users if you wish.', - 'INACTIVE_USERS_EXPLAIN_INDEX' => 'This is a list of the last 10 registered users who have inactive accounts. Accounts are inactive either because account activation was enabled in user registration settings and these users’ accounts have not yet been activated, or because these accounts have been deactivated. A full list is available by following the link below from where you can activate, delete or remind (by sending an email) these users if you wish.', - - 'NO_INACTIVE_USERS' => 'No inactive users', - - 'SORT_INACTIVE' => 'Inactive date', - 'SORT_LAST_VISIT' => 'Last visit', - 'SORT_REASON' => 'Reason', - 'SORT_REG_DATE' => 'Registration date', - 'SORT_LAST_REMINDER'=> 'Last reminded', - 'SORT_REMINDER' => 'Reminder sent', - - 'USER_IS_INACTIVE' => 'User is inactive', -)); - -// 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 anonymous. We base decisions about future phpBB versions on this information. The statistics are made available publically. We also share this data with the PHP project, the programming language phpBB is made with.', - 'EXPLAIN_SHOW_STATISTICS' => 'Using the button below you can preview all variables that will be transmitted.', - 'DONT_SEND_STATISTICS' => 'Return to the ACP if you do not wish to send statistical information to phpBB.', - 'GO_ACP_MAIN' => 'Go to the ACP start page', - 'HIDE_STATISTICS' => 'Hide details', - 'SEND_STATISTICS' => 'Send 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 -$lang = array_merge($lang, array( - 'LOG_ACL_ADD_USER_GLOBAL_U_' => 'Added or edited users’ user permissions
» %s', - 'LOG_ACL_ADD_GROUP_GLOBAL_U_' => 'Added or edited groups’ user permissions
» %s', - 'LOG_ACL_ADD_USER_GLOBAL_M_' => 'Added or edited users’ global moderator permissions
» %s', - 'LOG_ACL_ADD_GROUP_GLOBAL_M_' => 'Added or edited groups’ global moderator permissions
» %s', - 'LOG_ACL_ADD_USER_GLOBAL_A_' => 'Added or edited users’ administrator permissions
» %s', - 'LOG_ACL_ADD_GROUP_GLOBAL_A_' => 'Added or edited groups’ administrator permissions
» %s', - - 'LOG_ACL_ADD_ADMIN_GLOBAL_A_' => 'Added or edited Administrators
» %s', - 'LOG_ACL_ADD_MOD_GLOBAL_M_' => 'Added or edited Global Moderators
» %s', - - 'LOG_ACL_ADD_USER_LOCAL_F_' => 'Added or edited users’ forum access from %1$s
» %2$s', - 'LOG_ACL_ADD_USER_LOCAL_M_' => 'Added or edited users’ forum moderator access from %1$s
» %2$s', - 'LOG_ACL_ADD_GROUP_LOCAL_F_' => 'Added or edited groups’ forum access from %1$s
» %2$s', - 'LOG_ACL_ADD_GROUP_LOCAL_M_' => 'Added or edited groups’ forum moderator access from %1$s
» %2$s', - - 'LOG_ACL_ADD_MOD_LOCAL_M_' => 'Added or edited Moderators from %1$s
» %2$s', - 'LOG_ACL_ADD_FORUM_LOCAL_F_' => 'Added or edited forum permissions from %1$s
» %2$s', - - 'LOG_ACL_DEL_ADMIN_GLOBAL_A_' => 'Removed Administrators
» %s', - 'LOG_ACL_DEL_MOD_GLOBAL_M_' => 'Removed Global Moderators
» %s', - 'LOG_ACL_DEL_MOD_LOCAL_M_' => 'Removed Moderators from %1$s
» %2$s', - 'LOG_ACL_DEL_FORUM_LOCAL_F_' => 'Removed User/Group forum permissions from %1$s
» %2$s', - - 'LOG_ACL_TRANSFER_PERMISSIONS' => 'Permissions transferred from
» %s', - 'LOG_ACL_RESTORE_PERMISSIONS' => 'Own permissions restored after using permissions from
» %s', - - 'LOG_ADMIN_AUTH_FAIL' => 'Failed administration login attempt', - 'LOG_ADMIN_AUTH_SUCCESS' => 'Successful administration login', - - 'LOG_ATTACHMENTS_DELETED' => 'Removed user attachments
» %s', - - 'LOG_ATTACH_EXT_ADD' => 'Added or edited attachment extension
» %s', - 'LOG_ATTACH_EXT_DEL' => 'Removed attachment extension
» %s', - 'LOG_ATTACH_EXT_UPDATE' => 'Updated attachment extension
» %s', - 'LOG_ATTACH_EXTGROUP_ADD' => 'Added extension group
» %s', - 'LOG_ATTACH_EXTGROUP_EDIT' => 'Edited extension group
» %s', - 'LOG_ATTACH_EXTGROUP_DEL' => 'Removed extension group
» %s', - 'LOG_ATTACH_FILEUPLOAD' => 'Orphan File uploaded to Post
» ID %1$d - %2$s', - 'LOG_ATTACH_ORPHAN_DEL' => 'Orphan Files deleted
» %s', - - 'LOG_BAN_EXCLUDE_USER' => 'Excluded user from ban for reason “%1$s
» %2$s', - 'LOG_BAN_EXCLUDE_IP' => 'Excluded IP from ban for reason “%1$s
» %2$s', - 'LOG_BAN_EXCLUDE_EMAIL' => 'Excluded email from ban for reason “%1$s
» %2$s', - 'LOG_BAN_USER' => 'Banned user for reason “%1$s
» %2$s', - 'LOG_BAN_IP' => 'Banned IP for reason “%1$s
» %2$s', - 'LOG_BAN_EMAIL' => 'Banned email for reason “%1$s
» %2$s', - 'LOG_UNBAN_USER' => 'Unbanned user
» %s', - 'LOG_UNBAN_IP' => 'Unbanned IP
» %s', - 'LOG_UNBAN_EMAIL' => 'Unbanned email
» %s', - - 'LOG_BBCODE_ADD' => 'Added new BBCode
» %s', - 'LOG_BBCODE_EDIT' => 'Edited BBCode
» %s', - 'LOG_BBCODE_DELETE' => 'Deleted BBCode
» %s', - 'LOG_BBCODE_CONFIGURATION_ERROR' => 'Error while configuring BBCode: %1$s
» %2$s', - - 'LOG_BOT_ADDED' => 'New bot added
» %s', - 'LOG_BOT_DELETE' => 'Deleted bot
» %s', - 'LOG_BOT_UPDATED' => 'Existing bot updated
» %s', - - 'LOG_CLEAR_ADMIN' => 'Cleared admin log', - 'LOG_CLEAR_CRITICAL' => 'Cleared error log', - 'LOG_CLEAR_MOD' => 'Cleared moderator log', - 'LOG_CLEAR_USER' => 'Cleared user log
» %s', - 'LOG_CLEAR_USERS' => 'Cleared user logs', - - 'LOG_CONFIG_ATTACH' => 'Altered attachment settings', - 'LOG_CONFIG_AUTH' => 'Altered authentication settings', - 'LOG_CONFIG_AVATAR' => 'Altered avatar settings', - 'LOG_CONFIG_COOKIE' => 'Altered cookie settings', - 'LOG_CONFIG_EMAIL' => 'Altered email settings', - 'LOG_CONFIG_FEATURES' => 'Altered board features', - 'LOG_CONFIG_LOAD' => 'Altered load settings', - 'LOG_CONFIG_MESSAGE' => 'Altered private message settings', - 'LOG_CONFIG_POST' => 'Altered post settings', - 'LOG_CONFIG_REGISTRATION' => 'Altered user registration settings', - 'LOG_CONFIG_FEED' => 'Altered syndication feeds settings', - 'LOG_CONFIG_SEARCH' => 'Altered search settings', - 'LOG_CONFIG_SECURITY' => 'Altered security settings', - 'LOG_CONFIG_SERVER' => 'Altered server settings', - 'LOG_CONFIG_SETTINGS' => 'Altered board settings', - 'LOG_CONFIG_SIGNATURE' => 'Altered signature settings', - 'LOG_CONFIG_VISUAL' => 'Altered anti-spambot settings', - - 'LOG_APPROVE_TOPIC' => 'Approved topic
» %s', - 'LOG_BUMP_TOPIC' => 'User bumped topic
» %s', - 'LOG_DELETE_POST' => 'Deleted post “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_DELETE_SHADOW_TOPIC' => 'Deleted shadow topic
» %s', - 'LOG_DELETE_TOPIC' => 'Deleted topic “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_FORK' => 'Copied topic
» from %s', - 'LOG_LOCK' => 'Locked topic
» %s', - 'LOG_LOCK_POST' => 'Locked post
» %s', - 'LOG_MERGE' => 'Merged posts into topic
» %s', - 'LOG_MOVE' => 'Moved topic
» from %1$s to %2$s', - 'LOG_MOVED_TOPIC' => 'Moved topic
» %s', - 'LOG_PM_REPORT_CLOSED' => 'Closed PM report
» %s', - 'LOG_PM_REPORT_DELETED' => 'Deleted PM report
» %s', - 'LOG_POST_APPROVED' => 'Approved post
» %s', - 'LOG_POST_DISAPPROVED' => 'Disapproved post “%1$s” written by “%3$s” for the following reason
» %2$s', - 'LOG_POST_EDITED' => 'Edited post “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_POST_RESTORED' => 'Restored post
» %s', - 'LOG_REPORT_CLOSED' => 'Closed report
» %s', - 'LOG_REPORT_DELETED' => 'Deleted report
» %s', - 'LOG_RESTORE_TOPIC' => 'Restored topic “%1$s” written by
» %2$s', - 'LOG_SOFTDELETE_POST' => 'Soft deleted post “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_SOFTDELETE_TOPIC' => 'Soft deleted topic “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_SPLIT_DESTINATION' => 'Moved split posts
» to %s', - 'LOG_SPLIT_SOURCE' => 'Split posts
» from %s', - - 'LOG_TOPIC_APPROVED' => 'Approved topic
» %s', - 'LOG_TOPIC_RESTORED' => 'Restored topic
» %s', - 'LOG_TOPIC_DISAPPROVED' => 'Disapproved topic “%1$s” written by “%3$s” for the following reason
» %2$s', - 'LOG_TOPIC_RESYNC' => 'Resynchronised topic counters
» %s', - 'LOG_TOPIC_TYPE_CHANGED' => 'Changed topic type
» %s', - 'LOG_UNLOCK' => 'Unlocked topic
» %s', - 'LOG_UNLOCK_POST' => 'Unlocked post
» %s', - - 'LOG_DISALLOW_ADD' => 'Added disallowed username
» %s', - 'LOG_DISALLOW_DELETE' => 'Deleted disallowed username', - - 'LOG_DB_BACKUP' => 'Database backup', - 'LOG_DB_DELETE' => 'Deleted database backup', - 'LOG_DB_RESTORE' => 'Restored database backup', - - 'LOG_DOWNLOAD_EXCLUDE_IP' => 'Excluded IP/hostname from download list
» %s', - 'LOG_DOWNLOAD_IP' => 'Added IP/hostname to download list
» %s', - 'LOG_DOWNLOAD_REMOVE_IP' => 'Removed IP/hostname from download list
» %s', - - 'LOG_ERROR_JABBER' => 'Jabber error
» %s', - 'LOG_ERROR_EMAIL' => 'Email error
» %s', - 'LOG_ERROR_CAPTCHA' => 'CAPTCHA error
» %s', - - 'LOG_FORUM_ADD' => 'Created new forum
» %s', - 'LOG_FORUM_COPIED_PERMISSIONS' => 'Copied forum permissions from %1$s
» %2$s', - 'LOG_FORUM_DEL_FORUM' => 'Deleted forum
» %s', - 'LOG_FORUM_DEL_FORUMS' => 'Deleted forum and its subforums
» %s', - 'LOG_FORUM_DEL_MOVE_FORUMS' => 'Deleted forum and moved subforums to %1$s
» %2$s', - 'LOG_FORUM_DEL_MOVE_POSTS' => 'Deleted forum and moved posts to %1$s
» %2$s', - 'LOG_FORUM_DEL_MOVE_POSTS_FORUMS' => 'Deleted forum and its subforums, moved posts to %1$s
» %2$s', - 'LOG_FORUM_DEL_MOVE_POSTS_MOVE_FORUMS' => 'Deleted forum, moved posts to %1$s and subforums to %2$s
» %3$s', - 'LOG_FORUM_DEL_POSTS' => 'Deleted forum and its posts
» %s', - 'LOG_FORUM_DEL_POSTS_FORUMS' => 'Deleted forum, its posts and subforums
» %s', - 'LOG_FORUM_DEL_POSTS_MOVE_FORUMS' => 'Deleted forum and its posts, moved subforums to %1$s
» %2$s', - 'LOG_FORUM_EDIT' => 'Edited forum details
» %s', - 'LOG_FORUM_MOVE_DOWN' => 'Moved forum %1$s below %2$s', - 'LOG_FORUM_MOVE_UP' => 'Moved forum %1$s above %2$s', - 'LOG_FORUM_SYNC' => 'Re-synchronised forum
» %s', - - 'LOG_GENERAL_ERROR' => 'A general error occurred: %1$s
» %2$s', - - 'LOG_GROUP_CREATED' => 'New usergroup created
» %s', - 'LOG_GROUP_DEFAULTS' => 'Group “%1$s” made default for members
» %2$s', - 'LOG_GROUP_DELETE' => 'Usergroup deleted
» %s', - 'LOG_GROUP_DEMOTED' => 'Leaders demoted in usergroup %1$s
» %2$s', - 'LOG_GROUP_PROMOTED' => 'Members promoted to leader in usergroup %1$s
» %2$s', - 'LOG_GROUP_REMOVE' => 'Members removed from usergroup %1$s
» %2$s', - 'LOG_GROUP_UPDATED' => 'Usergroup details updated
» %s', - 'LOG_MODS_ADDED' => 'Added new leaders to usergroup %1$s
» %2$s', - 'LOG_USERS_ADDED' => 'Added new members to usergroup %1$s
» %2$s', - 'LOG_USERS_APPROVED' => 'Users approved in usergroup %1$s
» %2$s', - 'LOG_USERS_PENDING' => 'Users requested to join group “%1$s” and need to be approved
» %2$s', - - 'LOG_IMAGE_GENERATION_ERROR' => 'Error while creating image
» Error in %1$s on line %2$s: %3$s', - - 'LOG_INACTIVE_ACTIVATE' => 'Activated inactive users
» %s', - 'LOG_INACTIVE_DELETE' => 'Deleted inactive users
» %s', - 'LOG_INACTIVE_REMIND' => 'Sent reminder emails to inactive users
» %s', - 'LOG_INSTALL_CONVERTED' => 'Converted from %1$s to phpBB %2$s', - 'LOG_INSTALL_INSTALLED' => 'Installed phpBB %s', - - 'LOG_IP_BROWSER_FORWARDED_CHECK' => 'Session IP/browser/X_FORWARDED_FOR check failed
»User IP “%1$s” checked against session IP “%2$s”, user browser string “%3$s” checked against session browser string “%4$s” and user X_FORWARDED_FOR string “%5$s” checked against session X_FORWARDED_FOR string “%6$s”.', - - 'LOG_JAB_CHANGED' => 'Jabber account changed', - 'LOG_JAB_PASSCHG' => 'Jabber password changed', - 'LOG_JAB_REGISTER' => 'Jabber account registered', - 'LOG_JAB_SETTINGS_CHANGED' => 'Jabber settings changed', - - 'LOG_LANGUAGE_PACK_DELETED' => 'Deleted language pack
» %s', - 'LOG_LANGUAGE_PACK_INSTALLED' => 'Installed language pack
» %s', - 'LOG_LANGUAGE_PACK_UPDATED' => 'Updated language pack details
» %s', - 'LOG_LANGUAGE_FILE_REPLACED' => 'Replaced language file
» %s', - 'LOG_LANGUAGE_FILE_SUBMITTED' => 'Submitted language file and placed in store folder
» %s', - - 'LOG_MASS_EMAIL' => 'Sent mass email
» %s', - - 'LOG_MCP_CHANGE_POSTER' => 'Changed poster in topic “%1$s”
» from %2$s to %3$s', - - 'LOG_MODULE_DISABLE' => 'Module disabled
» %s', - 'LOG_MODULE_ENABLE' => 'Module enabled
» %s', - 'LOG_MODULE_MOVE_DOWN' => 'Module moved down
» %1$s below %2$s', - 'LOG_MODULE_MOVE_UP' => 'Module moved up
» %1$s above %2$s', - 'LOG_MODULE_REMOVED' => 'Module removed
» %s', - 'LOG_MODULE_ADD' => 'Module added
» %s', - 'LOG_MODULE_EDIT' => 'Module edited
» %s', - - 'LOG_A_ROLE_ADD' => 'Admin role added
» %s', - 'LOG_A_ROLE_EDIT' => 'Admin role edited
» %s', - 'LOG_A_ROLE_REMOVED' => 'Admin role removed
» %s', - 'LOG_F_ROLE_ADD' => 'Forum role added
» %s', - 'LOG_F_ROLE_EDIT' => 'Forum role edited
» %s', - 'LOG_F_ROLE_REMOVED' => 'Forum role removed
» %s', - 'LOG_M_ROLE_ADD' => 'Moderator role added
» %s', - 'LOG_M_ROLE_EDIT' => 'Moderator role edited
» %s', - 'LOG_M_ROLE_REMOVED' => 'Moderator role removed
» %s', - 'LOG_U_ROLE_ADD' => 'User role added
» %s', - 'LOG_U_ROLE_EDIT' => 'User role edited
» %s', - 'LOG_U_ROLE_REMOVED' => 'User role removed
» %s', - - 'LOG_PLUPLOAD_TIDY_FAILED' => 'Unable to open %1$s for tidying, check permissions.
Exception: %2$s
Trace: %3$s', - - 'LOG_PROFILE_FIELD_ACTIVATE' => 'Profile field activated
» %s', - 'LOG_PROFILE_FIELD_CREATE' => 'Profile field added
» %s', - 'LOG_PROFILE_FIELD_DEACTIVATE' => 'Profile field deactivated
» %s', - 'LOG_PROFILE_FIELD_EDIT' => 'Profile field changed
» %s', - 'LOG_PROFILE_FIELD_REMOVED' => 'Profile field removed
» %s', - - 'LOG_PRUNE' => 'Pruned forums
» %s', - 'LOG_AUTO_PRUNE' => 'Auto-pruned forums
» %s', - 'LOG_PRUNE_SHADOW' => 'Auto-pruned shadow topics
» %s', - 'LOG_PRUNE_USER_DEAC' => 'Users deactivated
» %s', - 'LOG_PRUNE_USER_DEL_DEL' => 'Users pruned and posts deleted
» %s', - 'LOG_PRUNE_USER_DEL_ANON' => 'Users pruned and posts retained
» %s', - - 'LOG_PURGE_CACHE' => 'Purged cache', - 'LOG_PURGE_SESSIONS' => 'Purged sessions', - - 'LOG_RANK_ADDED' => 'Added new rank
» %s', - 'LOG_RANK_REMOVED' => 'Removed rank
» %s', - 'LOG_RANK_UPDATED' => 'Updated rank
» %s', - - 'LOG_REASON_ADDED' => 'Added report/denial reason
» %s', - 'LOG_REASON_REMOVED' => 'Removed report/denial reason
» %s', - 'LOG_REASON_UPDATED' => 'Updated report/denial reason
» %s', - - 'LOG_REFERER_INVALID' => 'Referrer validation failed
»Referrer was “%1$s”. The request was rejected and the session killed.', - 'LOG_RESET_DATE' => 'Board start date reset', - 'LOG_RESET_ONLINE' => 'Most users online reset', - 'LOG_RESYNC_FILES_STATS' => 'File statistics resynchronised', - 'LOG_RESYNC_POSTCOUNTS' => 'User post counts resynchronised', - 'LOG_RESYNC_POST_MARKING' => 'Dotted topics resynchronised', - 'LOG_RESYNC_STATS' => 'Post, topic and user statistics resynchronised', - - 'LOG_SEARCH_INDEX_CREATED' => 'Created search index for
» %s', - 'LOG_SEARCH_INDEX_REMOVED' => 'Removed search index for
» %s', - 'LOG_SPHINX_ERROR' => 'Sphinx Error
» %s', - 'LOG_STYLE_ADD' => 'Added new style
» %s', - 'LOG_STYLE_DELETE' => 'Deleted style
» %s', - 'LOG_STYLE_EDIT_DETAILS' => 'Edited style
» %s', - 'LOG_STYLE_EXPORT' => 'Exported style
» %s', - - // @deprecated 3.1 - 'LOG_TEMPLATE_ADD_DB' => 'Added new template set to database
» %s', - // @deprecated 3.1 - 'LOG_TEMPLATE_ADD_FS' => 'Add new template set on filesystem
» %s', - 'LOG_TEMPLATE_CACHE_CLEARED' => 'Deleted cached versions of template files in template set %1$s
» %2$s', - 'LOG_TEMPLATE_DELETE' => 'Deleted template set
» %s', - 'LOG_TEMPLATE_EDIT' => 'Edited template set %1$s
» %2$s', - 'LOG_TEMPLATE_EDIT_DETAILS' => 'Edited template details
» %s', - 'LOG_TEMPLATE_EXPORT' => 'Exported template set
» %s', - // @deprecated 3.1 - 'LOG_TEMPLATE_REFRESHED' => 'Refreshed template set
» %s', - - // @deprecated 3.1 - 'LOG_THEME_ADD_DB' => 'Added new theme to database
» %s', - // @deprecated 3.1 - 'LOG_THEME_ADD_FS' => 'Add new theme on filesystem
» %s', - 'LOG_THEME_DELETE' => 'Theme deleted
» %s', - 'LOG_THEME_EDIT_DETAILS' => 'Edited theme details
» %s', - 'LOG_THEME_EDIT' => 'Edited theme %1$s', - 'LOG_THEME_EDIT_FILE' => 'Edited theme %1$s
» Modified file %2$s', - 'LOG_THEME_EXPORT' => 'Exported theme
» %s', - // @deprecated 3.1 - 'LOG_THEME_REFRESHED' => 'Refreshed theme
» %s', - - 'LOG_UPDATE_DATABASE' => 'Updated Database from version %1$s to version %2$s', - 'LOG_UPDATE_PHPBB' => 'Updated phpBB from version %1$s to version %2$s', - - 'LOG_USER_ACTIVE' => 'User activated
» %s', - 'LOG_USER_BAN_USER' => 'Banned User via user management for reason “%1$s
» %2$s', - 'LOG_USER_BAN_IP' => 'Banned IP via user management for reason “%1$s
» %2$s', - 'LOG_USER_BAN_EMAIL' => 'Banned email via user management for reason “%1$s
» %2$s', - 'LOG_USER_DELETED' => 'Deleted user
» %s', - 'LOG_USER_DEL_ATTACH' => 'Removed all attachments made by the user
» %s', - 'LOG_USER_DEL_AVATAR' => 'Removed user avatar
» %s', - 'LOG_USER_DEL_OUTBOX' => 'Emptied user outbox
» %s', - 'LOG_USER_DEL_POSTS' => 'Removed all posts made by the user
» %s', - 'LOG_USER_DEL_SIG' => 'Removed user signature
» %s', - 'LOG_USER_INACTIVE' => 'User deactivated
» %s', - 'LOG_USER_MOVE_POSTS' => 'Moved user posts
» posts by “%1$s” to forum “%2$s”', - 'LOG_USER_NEW_PASSWORD' => 'Changed user password
» %s', - 'LOG_USER_REACTIVATE' => 'Forced user account reactivation
» %s', - 'LOG_USER_REMOVED_NR' => 'Removed newly registered flag from user
» %s', - - 'LOG_USER_UPDATE_EMAIL' => 'User “%1$s” changed email
» from “%2$s” to “%3$s”', - 'LOG_USER_UPDATE_NAME' => 'Changed username
» from “%1$s” to “%2$s”', - 'LOG_USER_USER_UPDATE' => 'Updated user details
» %s', - - 'LOG_USER_ACTIVE_USER' => 'User account activated', - 'LOG_USER_DEL_AVATAR_USER' => 'User avatar removed', - 'LOG_USER_DEL_SIG_USER' => 'User signature removed', - 'LOG_USER_FEEDBACK' => 'Added user feedback
» %s', - 'LOG_USER_GENERAL' => 'Entry added:
» %s', - 'LOG_USER_INACTIVE_USER' => 'User account de-activated', - 'LOG_USER_LOCK' => 'User locked own topic
» %s', - 'LOG_USER_MOVE_POSTS_USER' => 'Moved all posts to forum» %s', - 'LOG_USER_REACTIVATE_USER' => 'Forced user account reactivation', - 'LOG_USER_UNLOCK' => 'User unlocked own topic
» %s', - 'LOG_USER_WARNING' => 'Added user warning
» %s', - 'LOG_USER_WARNING_BODY' => 'The following warning was issued to this user
» %s', - - 'LOG_USER_GROUP_CHANGE' => 'User changed default group
» %s', - 'LOG_USER_GROUP_DEMOTE' => 'User demoted as leaders from usergroup
» %s', - 'LOG_USER_GROUP_JOIN' => 'User joined group
» %s', - 'LOG_USER_GROUP_JOIN_PENDING' => 'User joined group and needs to be approved
» %s', - 'LOG_USER_GROUP_RESIGN' => 'User resigned membership from group
» %s', - - 'LOG_WARNING_DELETED' => 'Deleted user warning
» %s', - 'LOG_WARNINGS_DELETED' => array( - 1 => 'Deleted user warning
» %1$s', - 2 => 'Deleted %2$d user warnings
» %1$s', // Example: 'Deleted 2 user warnings
» username' - ), - 'LOG_WARNINGS_DELETED_ALL' => 'Deleted all user warnings
» %s', - - 'LOG_WORD_ADD' => 'Added word censor
» %s', - 'LOG_WORD_DELETE' => 'Deleted word censor
» %s', - 'LOG_WORD_EDIT' => 'Edited word censor
» %s', - - 'LOG_EXT_ENABLE' => 'Extension enabled
» %s', - 'LOG_EXT_DISABLE' => 'Extension disabled
» %s', - 'LOG_EXT_PURGE' => 'Extension’s data deleted
» %s', - 'LOG_EXT_UPDATE' => 'Extension updated
» %s', -)); diff --git a/install/update/new/language/en/acp/forums.php b/install/update/new/language/en/acp/forums.php deleted file mode 100644 index 3ab1523..0000000 --- a/install/update/new/language/en/acp/forums.php +++ /dev/null @@ -1,168 +0,0 @@ - -* @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(); -} - -// 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 - -// Forum Admin -$lang = array_merge($lang, array( - 'AUTO_PRUNE_DAYS' => 'Auto-prune post age', - 'AUTO_PRUNE_DAYS_EXPLAIN' => 'Number of days since last post after which topic is removed.', - 'AUTO_PRUNE_FREQ' => 'Auto-prune frequency', - 'AUTO_PRUNE_FREQ_EXPLAIN' => 'Time in days between pruning events.', - 'AUTO_PRUNE_VIEWED' => 'Auto-prune post viewed age', - 'AUTO_PRUNE_VIEWED_EXPLAIN' => 'Number of days since topic was viewed after which topic is removed.', - 'AUTO_PRUNE_SHADOW_FREQ' => 'Auto-prune shadow topics frequency', - 'AUTO_PRUNE_SHADOW_DAYS' => 'Auto-prune shadow topics age', - 'AUTO_PRUNE_SHADOW_DAYS_EXPLAIN' => 'Number of days after which shadow topic is removed.', - 'AUTO_PRUNE_SHADOW_FREQ_EXPLAIN' => 'Time in days between pruning events.', - - 'CONTINUE' => 'Continue', - 'COPY_PERMISSIONS' => 'Copy permissions from', - 'COPY_PERMISSIONS_EXPLAIN' => 'To ease up the permission setup for your new forum, you can copy the permissions of an existing forum.', - 'COPY_PERMISSIONS_ADD_EXPLAIN' => 'Once created, the forum will have the same permissions as the one you select here. If no forum is selected the newly created forum will not be visible until permissions had been set.', - 'COPY_PERMISSIONS_EDIT_EXPLAIN' => 'If you select to copy permissions, the forum will have the same permissions as the one you select here. This will overwrite any permissions you have previously set for this forum with the permissions of the forum you select here. If no forum is selected the current permissions will be kept.', - 'COPY_TO_ACL' => 'Alternatively, you are also able to %sset up new permissions%s for this forum.', - 'CREATE_FORUM' => 'Create new forum', - - 'DECIDE_MOVE_DELETE_CONTENT' => 'Delete content or move to forum', - 'DECIDE_MOVE_DELETE_SUBFORUMS' => 'Delete subforums or move to forum', - 'DEFAULT_STYLE' => 'Default style', - 'DELETE_ALL_POSTS' => 'Delete posts', - 'DELETE_SUBFORUMS' => 'Delete subforums and posts', - 'DISPLAY_ACTIVE_TOPICS' => 'Enable active topics', - 'DISPLAY_ACTIVE_TOPICS_EXPLAIN' => 'If set to yes active topics in selected subforums will be displayed under this category.', - - 'EDIT_FORUM' => 'Edit forum', - 'ENABLE_INDEXING' => 'Enable search indexing', - 'ENABLE_INDEXING_EXPLAIN' => 'If set to yes posts made to this forum will be indexed for searching.', - 'ENABLE_POST_REVIEW' => 'Enable post review', - 'ENABLE_POST_REVIEW_EXPLAIN' => 'If set to yes users are able to review their post if new posts were made to the topic while users wrote theirs. This should be disabled for chat forums.', - 'ENABLE_QUICK_REPLY' => 'Enable quick reply', - 'ENABLE_QUICK_REPLY_EXPLAIN' => 'Enables the quick reply in this forum. This setting is not considered if the quick reply is disabled board wide. The quick reply will only be displayed for users who have permission to post in this forum.', - 'ENABLE_RECENT' => 'Display active topics', - 'ENABLE_RECENT_EXPLAIN' => 'If set to yes topics made to this forum will be shown in the active topics list.', - 'ENABLE_TOPIC_ICONS' => 'Enable topic icons', - - 'FORUM_ADMIN' => 'Forum administration', - 'FORUM_ADMIN_EXPLAIN' => 'In phpBB3 everything is forum based. A category is just a special type of forum. Each forum can have an unlimited number of sub-forums and you can determine whether each may be posted to or not (i.e. whether it acts like an old category). Here you can add, edit, delete, lock, unlock individual forums as well as set certain additional controls. If your posts and topics have got out of sync you can also resynchronise a forum. You need to copy or set appropriate permissions for newly created forums to have them displayed.', - 'FORUM_AUTO_PRUNE' => 'Enable auto-pruning', - 'FORUM_AUTO_PRUNE_EXPLAIN' => 'Prunes the forum of topics, set the frequency/age parameters below.', - 'FORUM_CREATED' => 'Forum created successfully.', - 'FORUM_DATA_NEGATIVE' => 'Pruning parameters cannot be negative.', - 'FORUM_DESC_TOO_LONG' => 'The forum description is too long, it must be less than 4000 characters.', - 'FORUM_DELETE' => 'Delete forum', - '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. 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.', - 'FORUM_IMAGE_NO_EXIST' => 'The specified forum image does not exist', - 'FORUM_LINK_EXPLAIN' => 'Full URL (including the protocol, i.e.: http://) to the destination location that clicking this forum will take the user, e.g.: http://www.phpbb.com/.', - 'FORUM_LINK_TRACK' => 'Track link redirects', - '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.
It contains the following unsupported characters:
%s', - 'FORUM_PARENT' => 'Parent forum', - 'FORUM_PASSWORD' => 'Forum password', - 'FORUM_PASSWORD_CONFIRM' => 'Confirm forum password', - 'FORUM_PASSWORD_CONFIRM_EXPLAIN' => 'Only needs to be set if a forum password is entered.', - 'FORUM_PASSWORD_EXPLAIN' => 'Defines a password for this forum, use the permission system in preference.', - 'FORUM_PASSWORD_UNSET' => 'Remove forum password', - 'FORUM_PASSWORD_UNSET_EXPLAIN' => 'Check here if you want to remove the forum password.', - 'FORUM_PASSWORD_OLD' => 'The forum password is using an old hashing method and should be changed.', - 'FORUM_PASSWORD_MISMATCH' => 'The passwords you entered did not match.', - 'FORUM_PRUNE_SETTINGS' => 'Forum prune settings', - 'FORUM_PRUNE_SHADOW' => 'Enable auto-pruning of shadow topics', - 'FORUM_PRUNE_SHADOW_EXPLAIN' => 'Prunes the forum of shadow topics, set the frequency/age parameters below.', - 'FORUM_RESYNCED' => 'Forum “%s” successfully resynced', - 'FORUM_RULES_EXPLAIN' => 'Forum rules are displayed at any page within the given forum.', - 'FORUM_RULES_LINK' => 'Link to forum rules', - 'FORUM_RULES_LINK_EXPLAIN' => 'You are able to enter the URL of the page/post containing your forum rules here. This setting will override the forum rules text you specified.', - 'FORUM_RULES_PREVIEW' => 'Forum rules preview', - 'FORUM_RULES_TOO_LONG' => 'The forum rules must be less than 4000 characters.', - 'FORUM_SETTINGS' => 'Forum settings', - 'FORUM_STATUS' => 'Forum status', - 'FORUM_STYLE' => 'Forum style', - 'FORUM_TOPICS_PAGE' => 'Topics per page', - 'FORUM_TOPICS_PAGE_EXPLAIN' => 'If non-zero this value will override the default topics per page setting.', - 'FORUM_TYPE' => 'Forum type', - 'FORUM_UPDATED' => 'Forum information updated successfully.', - - 'FORUM_WITH_SUBFORUMS_NOT_TO_LINK' => 'You want to change a postable forum having subforums to a link. Please move all subforums out of this forum before you proceed, because after changing to a link you are no longer able to see the subforums currently connected to this forum.', - - 'GENERAL_FORUM_SETTINGS' => 'General forum settings', - - 'LINK' => 'Link', - 'LIMIT_SUBFORUMS' => 'Limit legend to direct child-subforums', - 'LIMIT_SUBFORUMS_EXPLAIN' => 'Limits the subforums to be displayed to subforums that are direct descendants (children) of the current forum. Disabling this will display all subforums with the “List subforums in legend” option enabled, regardless of depth.', - 'LIST_INDEX' => 'List subforum in parent-forum’s legend', - 'LIST_INDEX_EXPLAIN' => 'Displays this forum on the index and elsewhere as a link within the legend of its parent-forum if the parent-forum’s “List subforums in legend” option is enabled.', - 'LIST_SUBFORUMS' => 'List subforums in legend', - 'LIST_SUBFORUMS_EXPLAIN' => 'Displays this forum’s subforums on the index and elsewhere as a link within the legend if their “List subforum in parent-forum’s legend” option is enabled.', - 'LOCKED' => 'Locked', - - 'MOVE_POSTS_NO_POSTABLE_FORUM' => 'The forum you selected for moving the posts to is not postable. Please select a postable forum.', - 'MOVE_POSTS_TO' => 'Move posts to', - 'MOVE_SUBFORUMS_TO' => 'Move subforums to', - - 'NO_DESTINATION_FORUM' => 'You have not specified a forum to move content to.', - 'NO_FORUM_ACTION' => 'No action defined for what happens with the forum content.', - 'NO_PARENT' => 'No parent', - 'NO_PERMISSIONS' => 'Do not copy permissions', - 'NO_PERMISSION_FORUM_ADD' => 'You do not have the necessary permissions to add forums.', - 'NO_PERMISSION_FORUM_DELETE' => 'You do not have the necessary permissions to delete forums.', - - 'PARENT_IS_LINK_FORUM' => 'The parent you specified is a forum link. Link forums are not able to hold other forums, please specify a category or forum as the parent forum.', - 'PARENT_NOT_EXIST' => 'Parent does not exist.', - 'PRUNE_ANNOUNCEMENTS' => 'Prune announcements', - 'PRUNE_STICKY' => 'Prune stickies', - 'PRUNE_OLD_POLLS' => 'Prune old polls', - 'PRUNE_OLD_POLLS_EXPLAIN' => 'Removes topics with polls not voted in for post age days.', - - 'REDIRECT_ACL' => 'Now you are able to %sset permissions%s for this forum.', - - 'SYNC_IN_PROGRESS' => 'Synchronizing forum', - 'SYNC_IN_PROGRESS_EXPLAIN' => 'Currently resyncing topic range %1$d/%2$d.', - - 'TYPE_CAT' => 'Category', - 'TYPE_FORUM' => 'Forum', - 'TYPE_LINK' => 'Link', - - 'UNLOCKED' => 'Unlocked', -)); diff --git a/install/update/new/language/en/acp/permissions.php b/install/update/new/language/en/acp/permissions.php deleted file mode 100644 index 875e424..0000000 --- a/install/update/new/language/en/acp/permissions.php +++ /dev/null @@ -1,287 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - 'ACP_PERMISSIONS_EXPLAIN' => ' -

Permissions are highly granular and grouped into four major sections, which are:

- -

Global Permissions

-

These are used to control access on a global level and apply to the entire bulletin board. They are further divided into User Permissions, Group Permissions, Administrators and Global Moderators.

- -

Forum Based Permissions

-

These are used to control access on a per forum basis. They are further divided into Forum Permissions, Forum Moderators, User Forum Permissions and Group Forum Permissions.

- -

Permission Roles

-

These are used to create different sets of permissions for the different permission types later being able to be assigned on a role-based basis. The default roles should cover the administration of bulletin boards large and small, though within each of the four divisions, you can add/edit/delete roles as you see fit.

- -

Permission Masks

-

These are used to view the effective permissions assigned to Users, Moderators (Local and Global), Administrators or Forums.

- -
- -

For further information on setting up and managing permissions on your phpBB3 board, please see the section on Setting permissions of our Quick Start Guide.

- ', - - 'ACL_NEVER' => 'Never', - 'ACL_SET' => 'Setting permissions', - 'ACL_SET_EXPLAIN' => 'Permissions are based on a simple YES/NO system. Setting an option to NEVER for a user or usergroup overrides any other value assigned to it. If you do not wish to assign a value for an option for this user or group select NO. If values are assigned for this option elsewhere they will be used in preference, else NEVER is assumed. All objects marked (with the checkbox in front of them) will copy the permission set you defined.', - 'ACL_SETTING' => 'Setting', - - 'ACL_TYPE_A_' => 'Administrative permissions', - 'ACL_TYPE_F_' => 'Forum permissions', - 'ACL_TYPE_M_' => 'Moderative permissions', - 'ACL_TYPE_U_' => 'User permissions', - - 'ACL_TYPE_GLOBAL_A_' => 'Administrative permissions', - 'ACL_TYPE_GLOBAL_U_' => 'User permissions', - 'ACL_TYPE_GLOBAL_M_' => 'Global Moderator permissions', - 'ACL_TYPE_LOCAL_M_' => 'Forum Moderator permissions', - 'ACL_TYPE_LOCAL_F_' => 'Forum permissions', - - 'ACL_NO' => 'No', - 'ACL_VIEW' => 'Viewing permissions', - 'ACL_VIEW_EXPLAIN' => 'Here you can see the effective permissions the user/group is having. A red square indicates that the user/group does not have the permission, a green square indicates that the user/group does have the permission.', - 'ACL_YES' => 'Yes', - - 'ACP_ADMINISTRATORS_EXPLAIN' => 'Here you can assign administrator permissions to users or groups. All users with administrator permissions can view the administration control panel.', - 'ACP_FORUM_MODERATORS_EXPLAIN' => 'Here you can assign users and groups as forum moderators. To assign users access to forums, to define global moderative permissions or administrators please use the appropriate page.', - 'ACP_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can alter which users and groups can access which forums. To assign moderators or define administrators please use the appropriate page.', - 'ACP_FORUM_PERMISSIONS_COPY_EXPLAIN' => 'Here you can copy forum permissions from one forum to one or more other forums.', - 'ACP_GLOBAL_MODERATORS_EXPLAIN' => 'Here you can assign global moderator permissions to users or groups. These moderators are like ordinary moderators except they have access to every forum on your board.', - 'ACP_GROUPS_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can assign forum permissions to groups.', - 'ACP_GROUPS_PERMISSIONS_EXPLAIN' => 'Here you can assign global permissions to groups - user permissions, global moderator permissions and administrator permissions. User permissions include capabilities such as the use of avatars, sending private messages, et cetera; global moderator permissions such as approving posts, manage topics, manage bans, et cetera and lastly administrator permissions such as altering permissions, define custom BBCodes, manage forums, et cetera. Individual user permissions should only be changed in rare occasions, the preferred method is putting users in groups and assigning the group permissions.', - 'ACP_ADMIN_ROLES_EXPLAIN' => 'Here you are able to manage the roles for administrative permissions. Roles are effective permissions, if you change a role the items having this role assigned will change its permissions too.', - 'ACP_FORUM_ROLES_EXPLAIN' => 'Here you are able to manage the roles for forum permissions. Roles are effective permissions, if you change a role the items having this role assigned will change its permissions too.', - 'ACP_MOD_ROLES_EXPLAIN' => 'Here you are able to manage the roles for moderative permissions. Roles are effective permissions, if you change a role the items having this role assigned will change its permissions too.', - 'ACP_USER_ROLES_EXPLAIN' => 'Here you are able to manage the roles for user permissions. Roles are effective permissions, if you change a role the items having this role assigned will change its permissions too.', - 'ACP_USERS_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can assign forum permissions to users.', - 'ACP_USERS_PERMISSIONS_EXPLAIN' => 'Here you can assign global permissions to users - user permissions, global moderator permissions and administrator permissions. User permissions include capabilities such as the use of avatars, sending private messages, et cetera; global moderator permissions such as approving posts, manage topics, manage bans, et cetera and lastly administrator permissions such as altering permissions, define custom BBCodes, manage forums, et cetera. To alter these settings for large numbers of users the Group permissions system is the preferred method. User permissions should only be changed in rare occasions, the preferred method is putting users in groups and assigning the group permissions.', - 'ACP_VIEW_ADMIN_PERMISSIONS_EXPLAIN' => 'Here you can view the effective administrative permissions assigned to the selected users/groups.', - 'ACP_VIEW_GLOBAL_MOD_PERMISSIONS_EXPLAIN' => 'Here you can view the global moderative permissions assigned to the selected users/groups.', - 'ACP_VIEW_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can view the forum permissions assigned to the selected users/groups and forums.', - 'ACP_VIEW_FORUM_MOD_PERMISSIONS_EXPLAIN' => 'Here you can view the forum moderator permissions assigned to the selected users/groups and forums.', - 'ACP_VIEW_USER_PERMISSIONS_EXPLAIN' => 'Here you can view the effective user permissions assigned to the selected users/groups.', - - 'ADD_GROUPS' => 'Add groups', - 'ADD_PERMISSIONS' => 'Add permissions', - 'ADD_USERS' => 'Add users', - 'ADVANCED_PERMISSIONS' => 'Advanced Permissions', - 'ALL_GROUPS' => 'Select all groups', - 'ALL_NEVER' => 'All NEVER', - 'ALL_NO' => 'All NO', - 'ALL_USERS' => 'Select all users', - 'ALL_YES' => 'All YES', - 'APPLY_ALL_PERMISSIONS' => 'Apply all permissions', - 'APPLY_PERMISSIONS' => 'Apply permissions', - 'APPLY_PERMISSIONS_EXPLAIN' => 'The permissions and role defined for this item will only be applied to this item and all checked items.', - 'AUTH_UPDATED' => 'Permissions have been updated.', - - 'COPY_PERMISSIONS_CONFIRM' => 'Are you sure you wish to carry out this operation? Please be aware that this will overwrite any existing permissions on the selected targets.', - 'COPY_PERMISSIONS_FORUM_FROM_EXPLAIN' => 'The source forum you want to copy permissions from.', - 'COPY_PERMISSIONS_FORUM_TO_EXPLAIN' => 'The destination forums you want the copied permissions applied to.', - 'COPY_PERMISSIONS_FROM' => 'Copy permissions from', - 'COPY_PERMISSIONS_TO' => 'Apply permissions to', - - 'CREATE_ROLE' => 'Create role', - 'CREATE_ROLE_FROM' => 'Use settings from…', - 'CUSTOM' => 'Custom…', - - 'DEFAULT' => 'Default', - 'DELETE_ROLE' => 'Delete role', - 'DELETE_ROLE_CONFIRM' => 'Are you sure you want to remove this role? Items having this role assigned will not lose their permission settings.', - 'DISPLAY_ROLE_ITEMS' => 'View items using this role', - - 'EDIT_PERMISSIONS' => 'Edit permissions', - 'EDIT_ROLE' => 'Edit role', - - 'GROUPS_NOT_ASSIGNED' => 'No group assigned to this role', - - 'LOOK_UP_GROUP' => 'Look up usergroup', - 'LOOK_UP_USER' => 'Look up user', - - 'MANAGE_GROUPS' => 'Manage groups', - 'MANAGE_USERS' => 'Manage users', - - 'NO_AUTH_SETTING_FOUND' => 'Permission settings not defined.', - 'NO_ROLE_ASSIGNED' => 'No role assigned…', - 'NO_ROLE_ASSIGNED_EXPLAIN' => 'Setting to this role does not change permissions on the right. If you want to unset/remove all permissions you should use the “All NO” link.', - 'NO_ROLE_AVAILABLE' => 'No role available', - 'NO_ROLE_NAME_SPECIFIED' => 'Please give the role a name.', - 'NO_ROLE_SELECTED' => 'Role could not be found.', - 'NO_USER_GROUP_SELECTED' => 'You haven’t selected any user or group.', - - 'ONLY_FORUM_DEFINED' => 'You only defined forums in your selection. Please also select at least one user or one group.', - - 'PERMISSION_APPLIED_TO_ALL' => 'Permissions and role will also be applied to all checked objects', - 'PLUS_SUBFORUMS' => '+Subforums', - - 'REMOVE_PERMISSIONS' => 'Remove permissions', - 'REMOVE_ROLE' => 'Remove role', - 'RESULTING_PERMISSION' => 'Resulting permission', - 'ROLE' => 'Role', - 'ROLE_ADD_SUCCESS' => 'Role successfully added.', - 'ROLE_ASSIGNED_TO' => 'Users/Groups assigned to %s', - 'ROLE_DELETED' => 'Role successfully removed.', - 'ROLE_DESCRIPTION' => 'Role description', - - 'ROLE_ADMIN_FORUM' => 'Forum Admin', - 'ROLE_ADMIN_FULL' => 'Full Admin', - 'ROLE_ADMIN_STANDARD' => 'Standard Admin', - 'ROLE_ADMIN_USERGROUP' => 'User and Groups Admin', - 'ROLE_FORUM_BOT' => 'Bot Access', - 'ROLE_FORUM_FULL' => 'Full Access', - 'ROLE_FORUM_LIMITED' => 'Limited Access', - 'ROLE_FORUM_LIMITED_POLLS' => 'Limited Access + Polls', - 'ROLE_FORUM_NOACCESS' => 'No Access', - 'ROLE_FORUM_ONQUEUE' => 'On Moderation Queue', - 'ROLE_FORUM_POLLS' => 'Standard Access + Polls', - 'ROLE_FORUM_READONLY' => 'Read Only Access', - 'ROLE_FORUM_STANDARD' => 'Standard Access', - 'ROLE_FORUM_NEW_MEMBER' => 'Newly Registered User Access', - 'ROLE_MOD_FULL' => 'Full Moderator', - 'ROLE_MOD_QUEUE' => 'Queue Moderator', - 'ROLE_MOD_SIMPLE' => 'Simple Moderator', - 'ROLE_MOD_STANDARD' => 'Standard Moderator', - 'ROLE_USER_FULL' => 'All Features', - 'ROLE_USER_LIMITED' => 'Limited Features', - 'ROLE_USER_NOAVATAR' => 'No Avatar', - 'ROLE_USER_NOPM' => 'No Private Messages', - 'ROLE_USER_STANDARD' => 'Standard Features', - 'ROLE_USER_NEW_MEMBER' => 'Newly Registered User Features', - - 'ROLE_DESCRIPTION_ADMIN_FORUM' => 'Can access the forum management and forum permission settings.', - 'ROLE_DESCRIPTION_ADMIN_FULL' => 'Has access to all administrative functions of this board.
Not recommended.', - 'ROLE_DESCRIPTION_ADMIN_STANDARD' => 'Has access to most administrative features but is not allowed to use server or system related tools.', - 'ROLE_DESCRIPTION_ADMIN_USERGROUP' => 'Can manage groups and users: Able to change permissions, settings, manage bans, and manage ranks.', - 'ROLE_DESCRIPTION_FORUM_BOT' => 'This role is recommended for bots and search spiders.', - 'ROLE_DESCRIPTION_FORUM_FULL' => 'Can use all forum features, including posting of announcements and stickies. Can also ignore the flood limit.
Not recommended for normal users.', - 'ROLE_DESCRIPTION_FORUM_LIMITED' => 'Can use some forum features, but cannot attach files or use post icons.', - 'ROLE_DESCRIPTION_FORUM_LIMITED_POLLS' => 'As per Limited Access but can also create polls.', - 'ROLE_DESCRIPTION_FORUM_NOACCESS' => 'Can neither see nor access the forum.', - 'ROLE_DESCRIPTION_FORUM_ONQUEUE' => 'Can use most forum features including attachments, but posts and topics need to be approved by a moderator.', - 'ROLE_DESCRIPTION_FORUM_POLLS' => 'Like Standard Access but can also create polls.', - 'ROLE_DESCRIPTION_FORUM_READONLY' => 'Can read the forum, but cannot create new topics or reply to posts.', - 'ROLE_DESCRIPTION_FORUM_STANDARD' => 'Can use most forum features including attachments and deleting own topics, but cannot lock own topics, and cannot create polls.', - 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER' => 'A role for members of the special newly registered users group; contains NEVER permissions to lock features for new users.', - 'ROLE_DESCRIPTION_MOD_FULL' => 'Can use all moderating features, including banning.', - 'ROLE_DESCRIPTION_MOD_QUEUE' => 'Can use the Moderation Queue to validate and edit posts, but nothing else.', - 'ROLE_DESCRIPTION_MOD_SIMPLE' => 'Can only use basic topic actions. Cannot send warnings or use moderation queue.', - 'ROLE_DESCRIPTION_MOD_STANDARD' => 'Can use most moderating tools, but cannot ban users or change the post author.', - 'ROLE_DESCRIPTION_USER_FULL' => 'Can use all available forum features for users, including changing the user name or ignoring the flood limit.
Not recommended.', - 'ROLE_DESCRIPTION_USER_LIMITED' => 'Can access some of the user features. Attachments, emails, or instant messages are not allowed.', - 'ROLE_DESCRIPTION_USER_NOAVATAR' => 'Has a limited feature set and is not allowed to use the Avatar feature.', - 'ROLE_DESCRIPTION_USER_NOPM' => 'Has a limited feature set, and is not allowed to use Private Messages.', - 'ROLE_DESCRIPTION_USER_STANDARD' => 'Can access most but not all user features. Cannot change user name or ignore the flood limit, for instance.', - 'ROLE_DESCRIPTION_USER_NEW_MEMBER' => 'A role for members of the special newly registered users group; contains NEVER permissions to lock features for new users.', - - 'ROLE_DESCRIPTION_EXPLAIN' => 'You are able to enter a short explanation of what the role is doing or for what it is meant for. The text you enter here will be displayed within the permissions screens too.', - 'ROLE_DESCRIPTION_LONG' => 'The role description is too long, please limit it to 4000 characters.', - 'ROLE_DETAILS' => 'Role details', - 'ROLE_EDIT_SUCCESS' => 'Role successfully edited.', - 'ROLE_NAME' => 'Role name', - 'ROLE_NAME_ALREADY_EXIST' => 'A role named %s already exist for the specified permission type.', - 'ROLE_NOT_ASSIGNED' => 'Role has not been assigned yet.', - - 'SELECTED_FORUM_NOT_EXIST' => 'The selected forum(s) do not exist.', - 'SELECTED_GROUP_NOT_EXIST' => 'The selected group(s) do not exist.', - 'SELECTED_USER_NOT_EXIST' => 'The selected user(s) do not exist.', - 'SELECT_FORUM_SUBFORUM_EXPLAIN' => 'The forum you select here will include all subforums into the selection.', - 'SELECT_ROLE' => 'Select role…', - 'SELECT_TYPE' => 'Select type', - 'SET_PERMISSIONS' => 'Set permissions', - 'SET_ROLE_PERMISSIONS' => 'Set role permissions', - 'SET_USERS_PERMISSIONS' => 'Set user permissions', - 'SET_USERS_FORUM_PERMISSIONS' => 'Set user forum permissions', - - 'TRACE_DEFAULT' => 'By default every permission is NO (unset). So the permission can be overwritten by other settings.', - 'TRACE_FOR' => 'Trace for', - 'TRACE_GLOBAL_SETTING' => '%s (global)', - 'TRACE_GROUP_NEVER_TOTAL_NEVER' => 'This group’s permission is set to NEVER like the total result so the old result is kept.', - 'TRACE_GROUP_NEVER_TOTAL_NEVER_LOCAL' => 'This group’s permission for this forum is set to NEVER like the total result so the old result is kept.', - 'TRACE_GROUP_NEVER_TOTAL_NO' => 'This group’s permission is set to NEVER which becomes the new total value because it wasn’t set yet (set to NO).', - 'TRACE_GROUP_NEVER_TOTAL_NO_LOCAL' => 'This group’s permission for this forum is set to NEVER which becomes the new total value because it wasn’t set yet (set to NO).', - 'TRACE_GROUP_NEVER_TOTAL_YES' => 'This group’s permission is set to NEVER which overwrites the total YES to a NEVER for this user.', - 'TRACE_GROUP_NEVER_TOTAL_YES_LOCAL' => 'This group’s permission for this forum is set to NEVER which overwrites the total YES to a NEVER for this user.', - 'TRACE_GROUP_NO' => 'The permission is NO for this group so the old total value is kept.', - 'TRACE_GROUP_NO_LOCAL' => 'The permission is NO for this group within this forum so the old total value is kept.', - 'TRACE_GROUP_YES_TOTAL_NEVER' => 'This group’s permission is set to YES but the total NEVER cannot be overwritten.', - 'TRACE_GROUP_YES_TOTAL_NEVER_LOCAL' => 'This group’s permission for this forum is set to YES but the total NEVER cannot be overwritten.', - 'TRACE_GROUP_YES_TOTAL_NO' => 'This group’s permission is set to YES which becomes the new total value because it wasn’t set yet (set to NO).', - 'TRACE_GROUP_YES_TOTAL_NO_LOCAL' => 'This group’s permission for this forum is set to YES which becomes the new total value because it wasn’t set yet (set to NO).', - 'TRACE_GROUP_YES_TOTAL_YES' => 'This group’s permission is set to YES and the total permission is already set to YES, so the total result is kept.', - 'TRACE_GROUP_YES_TOTAL_YES_LOCAL' => 'This group’s permission for this forum is set to YES and the total permission is already set to YES, so the total result is kept.', - 'TRACE_PERMISSION' => 'Trace permission - %s', - 'TRACE_RESULT' => 'Trace result', - 'TRACE_SETTING' => 'Trace setting', - - 'TRACE_USER_GLOBAL_YES_TOTAL_YES' => 'The forum independent user permission evaluates to YES but the total permission is already set to YES, so the total result is kept. %sTrace global permission%s', - 'TRACE_USER_GLOBAL_YES_TOTAL_NEVER' => 'The forum independent user permission evaluates to YES which overwrites the current local result NEVER. %sTrace global permission%s', - 'TRACE_USER_GLOBAL_NEVER_TOTAL_KEPT' => 'The forum independent user permission evaluates to NEVER which doesn’t influence the local permission. %sTrace global permission%s', - - 'TRACE_USER_FOUNDER' => 'The user is a founder, therefore admin permissions are always set to YES.', - 'TRACE_USER_KEPT' => 'The user’s permission is NO so the old total value is kept.', - 'TRACE_USER_KEPT_LOCAL' => 'The user’s permission for this forum is NO so the old total value is kept.', - 'TRACE_USER_NEVER_TOTAL_NEVER' => 'The user’s permission is set to NEVER and the total value is set to NEVER, so nothing is changed.', - 'TRACE_USER_NEVER_TOTAL_NEVER_LOCAL' => 'The user’s permission for this forum is set to NEVER and the total value is set to NEVER, so nothing is changed.', - 'TRACE_USER_NEVER_TOTAL_NO' => 'The user’s permission is set to NEVER which becomes the total value because it was set to NO.', - 'TRACE_USER_NEVER_TOTAL_NO_LOCAL' => 'The user’s permission for this forum is set to NEVER which becomes the total value because it was set to NO.', - 'TRACE_USER_NEVER_TOTAL_YES' => 'The user’s permission is set to NEVER and overwrites the previous YES.', - 'TRACE_USER_NEVER_TOTAL_YES_LOCAL' => 'The user’s permission for this forum is set to NEVER and overwrites the previous YES.', - 'TRACE_USER_NO_TOTAL_NO' => 'The user’s permission is NO and the total value was set to NO so it defaults to NEVER.', - 'TRACE_USER_NO_TOTAL_NO_LOCAL' => 'The user’s permission for this forum is NO and the total value was set to NO so it defaults to NEVER.', - 'TRACE_USER_YES_TOTAL_NEVER' => 'The user’s permission is set to YES but the total NEVER cannot be overwritten.', - 'TRACE_USER_YES_TOTAL_NEVER_LOCAL' => 'The user’s permission for this forum is set to YES but the total NEVER cannot be overwritten.', - 'TRACE_USER_YES_TOTAL_NO' => 'The user’s permission is set to YES which becomes the total value because it was set to NO.', - 'TRACE_USER_YES_TOTAL_NO_LOCAL' => 'The user’s permission for this forum is set to YES which becomes the total value because it was set to NO.', - 'TRACE_USER_YES_TOTAL_YES' => 'The user’s permission is set to YES and the total value is set to YES, so nothing is changed.', - 'TRACE_USER_YES_TOTAL_YES_LOCAL' => 'The user’s permission for this forum is set to YES and the total value is set to YES, so nothing is changed.', - 'TRACE_WHO' => 'Who', - 'TRACE_TOTAL' => 'Total', - - 'USERS_NOT_ASSIGNED' => 'No users are assigned to this role', - 'USER_IS_MEMBER_OF_DEFAULT' => 'is a member of the following pre-defined groups', - 'USER_IS_MEMBER_OF_CUSTOM' => 'is a member of the following user defined groups', - - 'VIEW_ASSIGNED_ITEMS' => 'View assigned items', - 'VIEW_LOCAL_PERMS' => 'Local permissions', - 'VIEW_GLOBAL_PERMS' => 'Global permissions', - 'VIEW_PERMISSIONS' => 'View permissions', - - 'WRONG_PERMISSION_TYPE' => 'Wrong permission type selected.', - 'WRONG_PERMISSION_SETTING_FORMAT' => 'The permission settings are in a wrong format, phpBB is not able to process them correctly.', -)); diff --git a/install/update/new/language/en/acp/permissions_phpbb.php b/install/update/new/language/en/acp/permissions_phpbb.php deleted file mode 100644 index ab89399..0000000 --- a/install/update/new/language/en/acp/permissions_phpbb.php +++ /dev/null @@ -1,215 +0,0 @@ - -* @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(); -} - -// 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 - -/** -* EXTENSION-DEVELOPERS PLEASE NOTE -* -* You are able to put your permission sets into your extension. -* The permissions logic should be added via the 'core.permissions' event. -* You can easily add new permission categories, types and permissions, by -* simply merging them into the respective arrays. -* The respective language strings should be added into a language file, that -* start with 'permissions_', so they are automatically loaded within the ACP. -*/ - -$lang = array_merge($lang, array( - 'ACL_CAT_ACTIONS' => 'Actions', - 'ACL_CAT_CONTENT' => 'Content', - 'ACL_CAT_FORUMS' => 'Forums', - 'ACL_CAT_MISC' => 'Misc', - 'ACL_CAT_PERMISSIONS' => 'Permissions', - 'ACL_CAT_PM' => 'Private messages', - 'ACL_CAT_POLLS' => 'Polls', - 'ACL_CAT_POST' => 'Post', - 'ACL_CAT_POST_ACTIONS' => 'Post actions', - 'ACL_CAT_POSTING' => 'Posting', - 'ACL_CAT_PROFILE' => 'Profile', - 'ACL_CAT_SETTINGS' => 'Settings', - 'ACL_CAT_TOPIC_ACTIONS' => 'Topic actions', - 'ACL_CAT_USER_GROUP' => 'Users & Groups', -)); - -// User Permissions -$lang = array_merge($lang, array( - 'ACL_U_VIEWPROFILE' => 'Can view profiles, memberlist and online list', - 'ACL_U_CHGNAME' => 'Can change username', - 'ACL_U_CHGPASSWD' => 'Can change password', - 'ACL_U_CHGEMAIL' => 'Can change email address', - 'ACL_U_CHGAVATAR' => 'Can change avatar', - 'ACL_U_CHGGRP' => 'Can change default usergroup', - 'ACL_U_CHGPROFILEINFO' => 'Can change profile field information', - - 'ACL_U_ATTACH' => 'Can attach files', - 'ACL_U_DOWNLOAD' => 'Can download files', - '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 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', - 'ACL_U_PM_FORWARD' => 'Can forward private messages', - 'ACL_U_PM_EMAILPM' => 'Can email private messages', - 'ACL_U_PM_PRINTPM' => 'Can print private messages', - 'ACL_U_PM_ATTACH' => 'Can attach files in private messages', - 'ACL_U_PM_DOWNLOAD' => 'Can download files in private messages', - 'ACL_U_PM_BBCODE' => 'Can use BBCode in private messages', - 'ACL_U_PM_SMILIES' => 'Can use smilies in private messages', - 'ACL_U_PM_IMG' => 'Can use [img] BBCode tag in private messages', - 'ACL_U_PM_FLASH' => 'Can use [flash] BBCode tag in private messages', - - 'ACL_U_SENDEMAIL' => 'Can send emails', - 'ACL_U_SENDIM' => 'Can send instant messages', - 'ACL_U_IGNOREFLOOD' => 'Can ignore flood limit', - 'ACL_U_HIDEONLINE' => 'Can hide online status', - 'ACL_U_VIEWONLINE' => 'Can view hidden online users', - 'ACL_U_SEARCH' => 'Can search board', -)); - -// 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', - 'ACL_F_PRINT' => 'Can print topics', - 'ACL_F_EMAIL' => 'Can email topics', - 'ACL_F_BUMP' => 'Can bump topics', - 'ACL_F_USER_LOCK' => 'Can lock own topics', - 'ACL_F_DOWNLOAD' => 'Can download files', - 'ACL_F_REPORT' => 'Can report posts', - - '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', - 'ACL_F_SOFTDELETE' => 'Can soft delete own posts
Moderators, who have the approve posts permission, can restore soft deleted posts.', - 'ACL_F_IGNOREFLOOD' => 'Can ignore flood limit', - 'ACL_F_POSTCOUNT' => 'Increment post counter
Please note that this setting only affects new posts.', - 'ACL_F_NOAPPROVE' => 'Can post without approval', - - 'ACL_F_ATTACH' => 'Can attach files', - 'ACL_F_ICONS' => 'Can use topic/post icons', - 'ACL_F_BBCODE' => 'Can use BBCode', - 'ACL_F_FLASH' => 'Can use [flash] BBCode tag', - 'ACL_F_IMG' => 'Can use [img] BBCode tag', - 'ACL_F_SIGS' => 'Can use signatures', - 'ACL_F_SMILIES' => 'Can use smilies', - - 'ACL_F_POLL' => 'Can create polls', - 'ACL_F_VOTE' => 'Can vote in polls', - 'ACL_F_VOTECHG' => 'Can change existing vote', -)); - -// Moderator Permissions -$lang = array_merge($lang, array( - 'ACL_M_EDIT' => 'Can edit posts', - 'ACL_M_DELETE' => 'Can permanently delete posts', - 'ACL_M_SOFTDELETE' => 'Can soft delete posts
Moderators, who have the approve posts permission, can restore soft deleted posts.', - 'ACL_M_APPROVE' => 'Can approve and restore posts', - 'ACL_M_REPORT' => 'Can close and delete reports', - 'ACL_M_CHGPOSTER' => 'Can change post author', - - 'ACL_M_MOVE' => 'Can move topics', - 'ACL_M_LOCK' => 'Can lock topics', - 'ACL_M_SPLIT' => 'Can split topics', - 'ACL_M_MERGE' => 'Can merge topics', - - 'ACL_M_INFO' => 'Can view post details', - 'ACL_M_WARN' => 'Can issue warnings
This setting is only assigned globally. It is not forum based.', // This moderator setting is only global (and not local) - 'ACL_M_PM_REPORT' => 'Can close and delete reports of private messages
This setting is only assigned globally. It is not forum based.', // This moderator setting is only global (and not local) - 'ACL_M_BAN' => 'Can manage bans
This setting is only assigned globally. It is not forum based.', // This moderator setting is only global (and not local) -)); - -// Admin Permissions -$lang = array_merge($lang, array( - 'ACL_A_BOARD' => 'Can alter board settings/check for updates', - 'ACL_A_SERVER' => 'Can alter server/communication settings', - 'ACL_A_JABBER' => 'Can alter Jabber settings', - 'ACL_A_PHPINFO' => 'Can view php settings', - - 'ACL_A_FORUM' => 'Can manage forums', - 'ACL_A_FORUMADD' => 'Can add new forums', - 'ACL_A_FORUMDEL' => 'Can delete forums', - 'ACL_A_PRUNE' => 'Can prune forums', - - 'ACL_A_ICONS' => 'Can alter topic/post icons and smilies', - 'ACL_A_WORDS' => 'Can alter word censors', - 'ACL_A_BBCODE' => 'Can define BBCode tags', - 'ACL_A_ATTACH' => 'Can alter attachment related settings', - - 'ACL_A_USER' => 'Can manage users
This also includes seeing the users browser agent within the viewonline list.', - 'ACL_A_USERDEL' => 'Can delete/prune users', - 'ACL_A_GROUP' => 'Can manage groups', - 'ACL_A_GROUPADD' => 'Can add new groups', - 'ACL_A_GROUPDEL' => 'Can delete groups', - 'ACL_A_RANKS' => 'Can manage ranks', - 'ACL_A_PROFILE' => 'Can manage custom profile fields', - 'ACL_A_NAMES' => 'Can manage disallowed names', - 'ACL_A_BAN' => 'Can manage bans', - - 'ACL_A_VIEWAUTH' => 'Can view permission masks', - 'ACL_A_AUTHGROUPS' => 'Can alter permissions for individual groups', - 'ACL_A_AUTHUSERS' => 'Can alter permissions for individual users', - 'ACL_A_FAUTH' => 'Can alter forum permission class', - 'ACL_A_MAUTH' => 'Can alter moderator permission class', - 'ACL_A_AAUTH' => 'Can alter admin permission class', - 'ACL_A_UAUTH' => 'Can alter user permission class', - 'ACL_A_ROLES' => 'Can manage roles', - 'ACL_A_SWITCHPERM' => 'Can use others permissions', - - 'ACL_A_STYLES' => 'Can manage styles', - 'ACL_A_EXTENSIONS' => 'Can manage extensions', - 'ACL_A_VIEWLOGS' => 'Can view logs', - 'ACL_A_CLEARLOGS' => 'Can clear logs', - 'ACL_A_MODULES' => 'Can manage modules', - 'ACL_A_LANGUAGE' => 'Can manage language packs', - 'ACL_A_EMAIL' => 'Can send mass email', - 'ACL_A_BOTS' => 'Can manage bots', - 'ACL_A_REASONS' => 'Can manage report/denial reasons', - 'ACL_A_BACKUP' => 'Can backup/restore database', - 'ACL_A_SEARCH' => 'Can manage search backends and settings', -)); diff --git a/install/update/new/language/en/acp/posting.php b/install/update/new/language/en/acp/posting.php deleted file mode 100644 index 3bff6b9..0000000 --- a/install/update/new/language/en/acp/posting.php +++ /dev/null @@ -1,291 +0,0 @@ - -* @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(); -} - -// 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 - -// BBCodes -// Note to translators: you can translate everything but what's between { and } -$lang = array_merge($lang, array( - 'ACP_BBCODES_EXPLAIN' => 'BBCode is a special implementation of HTML offering greater control over what and how something is displayed. From this page you can add, remove and edit custom BBCodes.', - 'ADD_BBCODE' => 'Add a new BBCode', - - 'BBCODE_DANGER' => 'The BBCode you are trying to add seems unsafe. If the BBCode uses a {TEXT} token in a sensitive context, try using a more restrictive type instead. Only proceed if you understand the risks involved.', - 'BBCODE_DANGER_PROCEED' => 'Proceed', //'I understand the risk', - - 'BBCODE_ADDED' => 'BBCode added successfully.', - 'BBCODE_EDITED' => 'BBCode edited successfully.', - 'BBCODE_DELETED' => 'The BBCode has been removed successfully.', - 'BBCODE_NOT_EXIST' => 'The BBCode you selected does not exist.', - 'BBCODE_HELPLINE' => 'Help line', - 'BBCODE_HELPLINE_EXPLAIN' => 'This field contains the mouse over text of the BBCode.', - 'BBCODE_HELPLINE_TEXT' => 'Help line text', - 'BBCODE_HELPLINE_TOO_LONG' => 'The help line you entered is too long.', - - 'BBCODE_INVALID_TAG_NAME' => 'The BBCode tag name that you selected already exists.', - 'BBCODE_INVALID' => 'Your BBCode is constructed in an invalid form.', - 'BBCODE_INVALID_TEMPLATE' => 'Your BBCode’s template is invalid.', - '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.', - 'BBCODE_USAGE' => 'BBCode usage', - 'BBCODE_USAGE_EXAMPLE' => '[highlight={COLOR}]{TEXT}[/highlight]

[font={SIMPLETEXT1}]{SIMPLETEXT2}[/font]', - 'BBCODE_USAGE_EXPLAIN' => 'Here you define how to use the BBCode. Replace any variable input by the corresponding token (%ssee below%s).', - - 'EXAMPLE' => 'Example:', - 'EXAMPLES' => 'Examples:', - - 'HTML_REPLACEMENT' => 'HTML replacement', - 'HTML_REPLACEMENT_EXAMPLE' => '<span style="background-color: {COLOR};">{TEXT}</span>

<span style="font-family: {SIMPLETEXT1};">{SIMPLETEXT2}</span>', - 'HTML_REPLACEMENT_EXPLAIN' => 'Here you define the default HTML replacement. Do not forget to put back tokens you used above!', - - 'TOKEN' => 'Token', - 'TOKENS' => 'Tokens', - 'TOKENS_EXPLAIN' => 'Tokens are placeholders for user input. The input will be validated only if it matches the corresponding definition. If needed, you can number them by adding a number as the last character between the braces, e.g. {TEXT1}, {TEXT2}.

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

Please note that only tokens listed below are able to be used within custom BBCodes.', - 'TOKEN_DEFINITION' => 'What can it be?', - '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…', - '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 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 #FF1234 or a CSS colour keyword such as fuchsia or InactiveBorder', - ), -)); - -// Smilies and topic icons -$lang = array_merge($lang, array( - 'ACP_ICONS_EXPLAIN' => 'From this page you can add, remove and edit the icons users may add to their topics or posts. These icons are generally displayed next to topic titles on the forum listing, or the post subjects in topic listings. You can also install and create new packages of icons.', - 'ACP_SMILIES_EXPLAIN' => 'Smilies or emoticons are typically small, sometimes animated images used to convey an emotion or feeling. From this page you can add, remove and edit the emoticons users can use in their posts and private messages. You can also install and create new packages of smilies.', - 'ADD_SMILIES' => 'Add multiple smilies', - 'ADD_SMILEY_CODE' => 'Add additional smiley code', - 'ADD_ICONS' => 'Add multiple icons', - 'AFTER_ICONS' => 'After %s', - 'AFTER_SMILIES' => 'After %s', - - 'CODE' => 'Code', - 'CURRENT_ICONS' => 'Current icons', - 'CURRENT_ICONS_EXPLAIN' => 'Choose what to do with the currently installed icons.', - 'CURRENT_SMILIES' => 'Current smilies', - 'CURRENT_SMILIES_EXPLAIN' => 'Choose what to do with the currently installed smilies.', - - 'DISPLAY_ON_POSTING' => 'Display on posting page', - 'DISPLAY_POSTING' => 'On posting page', - 'DISPLAY_POSTING_NO' => 'Not on posting page', - - 'EDIT_ICONS' => 'Edit icons', - 'EDIT_SMILIES' => 'Edit smilies', - 'EMOTION' => 'Emotion', - 'EXPORT_ICONS' => 'Export and download icons.pak', - 'EXPORT_ICONS_EXPLAIN' => '%sOn clicking this link, the configuration for your installed icons will be packaged into icons.pak which once downloaded can be used to create a .zip or .tgz file containing all of your icons plus this icons.pak configuration file%s.', - 'EXPORT_SMILIES' => 'Export and download smilies.pak', - 'EXPORT_SMILIES_EXPLAIN' => '%sOn clicking this link, the configuration for your installed smilies will be packaged into smilies.pak which once downloaded can be used to create a .zip or .tgz file containing all of your smilies plus this smilies.pak configuration file%s.', - - 'FIRST' => 'First', - - 'ICONS_ADD' => 'Add a new icon', - 'ICONS_ADDED' => array( - 0 => 'No icons were added.', - 1 => 'The icon has been added successfully.', - 2 => 'The icons have been added successfully.', - ), - 'ICONS_CONFIG' => 'Icon configuration', - 'ICONS_DELETED' => 'The icon has been removed successfully.', - 'ICONS_EDIT' => 'Edit icon', - 'ICONS_EDITED' => array( - 0 => 'No icons were updated.', - 1 => 'The icon has been updated successfully.', - 2 => 'The icons have been updated successfully.', - ), - 'ICONS_HEIGHT' => 'Icon height', - 'ICONS_IMAGE' => 'Icon image', - 'ICONS_IMPORTED' => 'The icons pack has been installed successfully.', - 'ICONS_IMPORT_SUCCESS' => 'The icons pack was imported successfully.', - 'ICONS_LOCATION' => 'Icon location', - 'ICONS_NOT_DISPLAYED' => 'The following icons are not displayed on the posting page', - 'ICONS_ORDER' => 'Icon order', - 'ICONS_URL' => 'Icon image file', - 'ICONS_WIDTH' => 'Icon width', - 'IMPORT_ICONS' => 'Install icons package', - 'IMPORT_SMILIES' => 'Install smilies package', - - 'KEEP_ALL' => 'Keep all', - - 'MASS_ADD_SMILIES' => 'Add multiple smilies', - - 'NO_ICONS_ADD' => 'There are no icons available for adding.', - 'NO_ICONS_EDIT' => 'There are no icons available for modifying.', - 'NO_ICONS_EXPORT' => 'You have no icons with which to create a package.', - 'NO_ICONS_PAK' => 'No icon packages found.', - 'NO_SMILIES_ADD' => 'There are no smilies available for adding.', - 'NO_SMILIES_EDIT' => 'There are no smilies available for modifying.', - 'NO_SMILIES_EXPORT' => 'You have no smilies with which to create a package.', - 'NO_SMILIES_PAK' => 'No smiley packages found.', - - 'PAK_FILE_NOT_READABLE' => 'Could not read .pak file.', - - 'REPLACE_MATCHES' => 'Replace matches', - - 'SELECT_PACKAGE' => 'Select a package file', - 'SMILIES_ADD' => 'Add a new smiley', - 'SMILIES_ADDED' => array( - 0 => 'No smilies were added.', - 1 => 'The smiley has been added successfully.', - 2 => 'The smilies have been added successfully.', - ), - 'SMILIES_CODE' => 'Smiley code', - 'SMILIES_CONFIG' => 'Smiley configuration', - 'SMILIES_DELETED' => 'The smiley has been removed successfully.', - 'SMILIES_EDIT' => 'Edit smiley', - 'SMILIE_NO_CODE' => 'The smiley “%s” was ignored, as there was no code entered.', - 'SMILIE_NO_EMOTION' => 'The smiley “%s” was ignored, as there was no emotion entered.', - 'SMILIE_NO_FILE' => 'The smiley “%s” was ignored, as the file is missing.', - 'SMILIES_EDITED' => array( - 0 => 'No smilies were updated.', - 1 => 'The smiley has been updated successfully.', - 2 => 'The smilies have been updated successfully.', - ), - 'SMILIES_EMOTION' => 'Emotion', - 'SMILIES_HEIGHT' => 'Smiley height', - 'SMILIES_IMAGE' => 'Smiley image', - 'SMILIES_IMPORTED' => 'The smilies pack has been installed successfully.', - 'SMILIES_IMPORT_SUCCESS' => 'The smilies pack was imported successfully.', - 'SMILIES_LOCATION' => 'Smiley location', - 'SMILIES_NOT_DISPLAYED' => 'The following smilies are not displayed on the posting page', - 'SMILIES_ORDER' => 'Smiley order', - 'SMILIES_URL' => 'Smiley image file', - 'SMILIES_WIDTH' => 'Smiley width', - - 'TOO_MANY_SMILIES' => array( - 1 => 'Limit of %d smiley reached.', - 2 => 'Limit of %d smilies reached.', - ), - - 'WRONG_PAK_TYPE' => 'The specified package does not contain the appropriate data.', -)); - -// Word censors -$lang = array_merge($lang, array( - 'ACP_WORDS_EXPLAIN' => 'From this control panel you can add, edit, and remove words that will be automatically censored on your forums. People are still allowed to register with usernames containing these words. Wildcards (*) are accepted in the word field, e.g. *test* will match detestable, test* would match testing, *test would match detest.', - 'ADD_WORD' => 'Add new word', - - 'EDIT_WORD' => 'Edit word censor', - 'ENTER_WORD' => 'You must enter a word and its replacement.', - - 'NO_WORD' => 'No word selected for editing.', - - 'REPLACEMENT' => 'Replacement', - - 'UPDATE_WORD' => 'Update word censor', - - 'WORD' => 'Word', - 'WORD_ADDED' => 'The word censor has been successfully added.', - 'WORD_REMOVED' => 'The selected word censor has been successfully removed.', - 'WORD_UPDATED' => 'The selected word censor has been successfully updated.', -)); - -// Ranks -$lang = array_merge($lang, array( - 'ACP_RANKS_EXPLAIN' => 'Using this form you can add, edit, view and delete ranks. You can also create special ranks which can be applied to a user via the user management facility.', - 'ADD_RANK' => 'Add new rank', - - 'MUST_SELECT_RANK' => 'You must select a rank.', - - 'NO_ASSIGNED_RANK' => 'No special rank assigned.', - 'NO_RANK_TITLE' => 'You haven’t specified a title for the rank.', - 'NO_UPDATE_RANKS' => 'The rank was successfully deleted. However user accounts using this rank were not updated. You will need to manually reset the rank on these accounts.', - - 'RANK_ADDED' => 'The rank was successfully added.', - 'RANK_IMAGE' => 'Rank image', - 'RANK_IMAGE_EXPLAIN' => 'Use this to define a small image associated with the rank. The path is relative to the root phpBB directory.', - 'RANK_IMAGE_IN_USE' => '(In use)', - 'RANK_MINIMUM' => 'Minimum posts', - 'RANK_REMOVED' => 'The rank was successfully deleted.', - 'RANK_SPECIAL' => 'Set as special rank', - 'RANK_TITLE' => 'Rank title', - 'RANK_UPDATED' => 'The rank was successfully updated.', -)); - -// Disallow Usernames -$lang = array_merge($lang, array( - 'ACP_DISALLOW_EXPLAIN' => 'Here you can control usernames which will not be allowed to be used. Disallowed usernames are allowed to contain a wildcard character of *.', - 'ADD_DISALLOW_EXPLAIN' => 'You can disallow a username using the wildcard character * to match any character.', - 'ADD_DISALLOW_TITLE' => 'Add a disallowed username', - - 'DELETE_DISALLOW_EXPLAIN' => 'You can remove a disallowed username by selecting the username from this list and clicking submit.', - 'DELETE_DISALLOW_TITLE' => 'Remove a disallowed username', - 'DISALLOWED_ALREADY' => 'The name you entered is already disallowed.', - 'DISALLOWED_DELETED' => 'The disallowed username has been successfully removed.', - 'DISALLOW_SUCCESSFUL' => 'The disallowed username has been successfully added.', - - 'NO_DISALLOWED' => 'No disallowed usernames', - 'NO_USERNAME_SPECIFIED' => 'You haven’t selected or entered a username to operate with.', -)); - -// Reasons -$lang = array_merge($lang, array( - 'ACP_REASONS_EXPLAIN' => 'Here you can manage the reasons used in reports and denial messages when disapproving posts. There is one default reason (marked with a *) you are not able to remove, this reason is normally used for custom messages if no reason fits.', - 'ADD_NEW_REASON' => 'Add new reason', - 'AVAILABLE_TITLES' => 'Available localised reason titles', - - 'IS_NOT_TRANSLATED' => 'Reason has not been localised.', - 'IS_NOT_TRANSLATED_EXPLAIN' => 'Reason has not been localised. If you want to provide the localised form, specify the correct key from the language files report reasons section.', - 'IS_TRANSLATED' => 'Reason has been localised.', - 'IS_TRANSLATED_EXPLAIN' => 'Reason has been localised. If the title you enter here is specified within the language files report reasons section, the localised form of the title and description will be used.', - - 'NO_REASON' => 'Reason could not be found.', - 'NO_REASON_INFO' => 'You have to specify a title and a description for this reason.', - 'NO_REMOVE_DEFAULT_REASON' => 'You are not able to remove the default reason “Other”.', - - 'REASON_ADD' => 'Add report/denial reason', - 'REASON_ADDED' => 'Report/denial reason successfully added.', - 'REASON_ALREADY_EXIST' => 'A reason with this title already exist, please enter another title for this reason.', - 'REASON_DESCRIPTION' => 'Reason description', - 'REASON_DESC_TRANSLATED' => 'Displayed reason description', - 'REASON_EDIT' => 'Edit report/denial reason', - 'REASON_EDIT_EXPLAIN' => 'Here you are able to add or edit a reason. If the reason is translated the localised version is used instead of the description entered here.', - 'REASON_REMOVED' => 'Report/denial reason successfully removed.', - 'REASON_TITLE' => 'Reason title', - 'REASON_TITLE_TRANSLATED' => 'Displayed reason title', - 'REASON_UPDATED' => 'Report/denial reason successfully updated.', - - 'USED_IN_REPORTS' => 'Used in reports', -)); diff --git a/install/update/new/language/en/acp/profile.php b/install/update/new/language/en/acp/profile.php deleted file mode 100644 index 87c9505..0000000 --- a/install/update/new/language/en/acp/profile.php +++ /dev/null @@ -1,176 +0,0 @@ - -* @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(); -} - -// 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 - -// Custom profile fields -$lang = array_merge($lang, array( - 'ADDED_PROFILE_FIELD' => 'Successfully added custom profile field.', - 'ALPHA_DOTS' => 'Alphanumeric and dots (periods)', - 'ALPHA_ONLY' => 'Alphanumeric only', - 'ALPHA_SPACERS' => 'Alphanumeric and spacers', - 'ALPHA_UNDERSCORE' => 'Alphanumeric and underscores', - 'ALPHA_PUNCTUATION' => 'Alphanumeric with comma, dots, underscore and dashes beginning with a letter', - 'ALWAYS_TODAY' => 'Always the current date', - - 'BOOL_ENTRIES_EXPLAIN' => 'Enter your options now', - 'BOOL_TYPE_EXPLAIN' => 'Define the type, either a checkbox or radio buttons. A checkbox will only be displayed if it is checked for a given user. In that case the second language option will be used. Radio buttons will display regardless of their value.', - - 'CHANGED_PROFILE_FIELD' => 'Successfully changed profile field.', - 'CHARS_ANY' => 'Any character', - 'CHECKBOX' => 'Checkbox', - 'COLUMNS' => 'Columns', - 'CP_LANG_DEFAULT_VALUE' => 'Default value', - 'CP_LANG_EXPLAIN' => 'Field description', - 'CP_LANG_EXPLAIN_EXPLAIN' => 'The explanation for this field presented to the user.', - 'CP_LANG_NAME' => 'Field name/title presented to the user', - 'CP_LANG_OPTIONS' => 'Options', - 'CREATE_NEW_FIELD' => 'Create new field', - 'CUSTOM_FIELDS_NOT_TRANSLATED' => 'At least one custom profile field has not yet been translated. Please enter the required information by clicking on the “Translate” link.', - - 'DEFAULT_ISO_LANGUAGE' => 'Default language [%s]', - 'DEFAULT_LANGUAGE_NOT_FILLED' => 'The language entries for the default language are not filled for this profile field.', - 'DEFAULT_VALUE' => 'Default value', - 'DELETE_PROFILE_FIELD' => 'Remove profile field', - 'DELETE_PROFILE_FIELD_CONFIRM' => 'Are you sure you want to delete this profile field?', - 'DISPLAY_AT_PROFILE' => 'Display in user control panel', - 'DISPLAY_AT_PROFILE_EXPLAIN' => 'The user is able to change this profile field within the user control panel.', - 'DISPLAY_AT_REGISTER' => 'Display on registration screen', - 'DISPLAY_AT_REGISTER_EXPLAIN' => 'If this option is enabled, the field will be displayed on registration.', - 'DISPLAY_ON_MEMBERLIST' => 'Display on memberlist screen', - 'DISPLAY_ON_MEMBERLIST_EXPLAIN' => 'If this option is enabled, the field will be displayed in the user rows on the memberlist screen.', - 'DISPLAY_ON_PM' => 'Display on view private message screen', - 'DISPLAY_ON_PM_EXPLAIN' => 'If this option is enabled, the field will be displayed in the mini-profile on the private message screen.', - 'DISPLAY_ON_VT' => 'Display on viewtopic screen', - 'DISPLAY_ON_VT_EXPLAIN' => 'If this option is enabled, the field will be displayed in the mini-profile on the topic screen.', - 'DISPLAY_PROFILE_FIELD' => 'Publicly display profile field', - 'DISPLAY_PROFILE_FIELD_EXPLAIN' => 'The profile field will be shown in all locations allowed within the load settings. Setting this to “no” will hide the field from topic pages, profiles and the memberlist.', - 'DROPDOWN_ENTRIES_EXPLAIN' => 'Enter your options now, every option in one line.', - - 'EDIT_DROPDOWN_LANG_EXPLAIN' => 'Please note that you are able to change your options text and also able to add new options to the end. It is not advised to add new options between existing options - this could result in wrong options assigned to your users. This can also happen if you remove options in-between. Removing options from the end result in users having assigned this item now reverting back to the default one.', - 'EMPTY_FIELD_IDENT' => 'Empty field identification', - 'EMPTY_USER_FIELD_NAME' => 'Please enter a field name/title', - 'ENTRIES' => 'Entries', - 'EVERYTHING_OK' => 'Everything OK', - - 'FIELD_BOOL' => 'Boolean (Yes/No)', - 'FIELD_CONTACT_DESC' => 'Contact description', - 'FIELD_CONTACT_URL' => 'Contact link', - 'FIELD_DATE' => 'Date', - 'FIELD_DESCRIPTION' => 'Field description', - 'FIELD_DESCRIPTION_EXPLAIN' => 'The explanation for this field presented to the user.', - 'FIELD_DROPDOWN' => 'Dropdown box', - 'FIELD_GOOGLEPLUS' => 'Google+', - 'FIELD_IDENT' => 'Field identification', - 'FIELD_IDENT_ALREADY_EXIST' => 'The chosen field identification already exist. Please choose another name.', - 'FIELD_IDENT_EXPLAIN' => 'The field identification is a name to identify the profile field within the database and the templates.', - 'FIELD_INT' => 'Numbers', - 'FIELD_IS_CONTACT' => 'Display field as a contact field', - 'FIELD_IS_CONTACT_EXPLAIN' => 'Contact fields are displayed within the contact section of the user profile and are displayed differently in the mini profile next to posts and private messages. You can use %s as a placeholder variable which will be replaced by a value provided by the user.', - 'FIELD_LENGTH' => 'Length of input box', - 'FIELD_NOT_FOUND' => 'Profile field not found.', - 'FIELD_STRING' => 'Single text field', - 'FIELD_TEXT' => 'Textarea', - 'FIELD_TYPE' => 'Field type', - 'FIELD_TYPE_EXPLAIN' => 'You are not able to change the field type later.', - 'FIELD_URL' => 'URL (Link)', - 'FIELD_VALIDATION' => 'Field validation', - 'FIRST_OPTION' => 'First option', - - 'HIDE_PROFILE_FIELD' => 'Hide profile field', - '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', - 'ISO_LANGUAGE' => 'Language [%s]', - - 'LANG_SPECIFIC_OPTIONS' => 'Language specific options [%s]', - - 'LETTER_NUM_DOTS' => 'Any letters, numbers and dots (periods)', - 'LETTER_NUM_ONLY' => 'Any letters and numbers', - 'LETTER_NUM_PUNCTUATION' => 'Any letters, numbers, comma, dots, underscores and dashes beginning with any letter', - 'LETTER_NUM_SPACERS' => 'Any letters, numbers and spacers', - 'LETTER_NUM_UNDERSCORE' => 'Any letters, numbers and underscores', - - 'MAX_FIELD_CHARS' => 'Maximum number of characters', - 'MAX_FIELD_NUMBER' => 'Highest allowed number', - 'MIN_FIELD_CHARS' => 'Minimum number of characters', - 'MIN_FIELD_NUMBER' => 'Lowest allowed number', - - 'NO_FIELD_ENTRIES' => 'No entries defined', - 'NO_FIELD_ID' => 'No field id specified.', - 'NO_FIELD_TYPE' => 'No Field type specified.', - 'NO_VALUE_OPTION' => 'Option equal to non entered value', - 'NO_VALUE_OPTION_EXPLAIN' => 'Value for a non-entry. If the field is required, the user gets an error if he choose the option selected here.', - 'NUMBERS_ONLY' => 'Only numbers (0-9)', - - 'PROFILE_BASIC_OPTIONS' => 'Basic options', - 'PROFILE_FIELD_ACTIVATED' => 'Profile field successfully activated.', - 'PROFILE_FIELD_DEACTIVATED' => 'Profile field successfully deactivated.', - 'PROFILE_LANG_OPTIONS' => 'Language specific options', - 'PROFILE_TYPE_OPTIONS' => 'Profile type specific options', - - 'RADIO_BUTTONS' => 'Radio buttons', - 'REMOVED_PROFILE_FIELD' => 'Successfully removed profile field.', - 'REQUIRED_FIELD' => 'Required field', - 'REQUIRED_FIELD_EXPLAIN' => 'Force profile field to be filled out or specified by user or administrator. If display at registration screen option is disabled, the field will only be required when the user edits their profile.', - 'ROWS' => 'Rows', - - 'SAVE' => 'Save', - 'SECOND_OPTION' => 'Second option', - 'SHOW_NOVALUE_FIELD' => 'Show field if no value was selected', - 'SHOW_NOVALUE_FIELD_EXPLAIN' => 'Determines if the profile field should be displayed if no value was selected for optional fields or if no value has been selected yet for required fields.', - 'STEP_1_EXPLAIN_CREATE' => 'Here you can enter the first basic parameters of your new profile field. This information is needed for the second step where you’ll be able to set remaining options and tweak your profile field further.', - 'STEP_1_EXPLAIN_EDIT' => 'Here you can change the basic parameters of your profile field. The relevant options are re-calculated within the second step.', - 'STEP_1_TITLE_CREATE' => 'Add profile field', - 'STEP_1_TITLE_EDIT' => 'Edit profile field', - 'STEP_2_EXPLAIN_CREATE' => 'Here you are able to define some common options you may want to adjust.', - 'STEP_2_EXPLAIN_EDIT' => 'Here you are able to change some common options.
Please note that changes to profile fields will not affect existing profile fields entered by your users.', - '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. 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.', - - 'TEXT_DEFAULT_VALUE_EXPLAIN' => 'Enter a default text to be displayed, a default value. Leave empty if you want to show it empty at the first place.', - 'TRANSLATE' => 'Translate', - - 'USER_FIELD_NAME' => 'Field name/title presented to the user', - - 'VISIBILITY_OPTION' => 'Visibility options', -)); diff --git a/install/update/new/language/en/acp/styles.php b/install/update/new/language/en/acp/styles.php deleted file mode 100644 index 44be3c1..0000000 --- a/install/update/new/language/en/acp/styles.php +++ /dev/null @@ -1,91 +0,0 @@ - -* @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 = []; -} - -// 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 - -$lang = array_merge($lang, [ - 'ACP_STYLES_EXPLAIN' => 'Here you can manage the styles available on your board.
Please note you cannot uninstall the “prosilver” 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', - - '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.
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.', - - 'PURGED_CACHE' => 'Cache was purged.', - - '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_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_PHPBB_VERSION' => 'phpBB Version', - 'STYLE_USED_BY' => 'Used by (including robots)', - 'STYLE_VERSION' => 'Style version', - - 'UNINSTALL_PROSILVER' => 'You cannot uninstall the style “prosilver”.', - 'UNINSTALL_DEFAULT' => 'You cannot uninstall the default style.', - - 'BROWSE_STYLES_DATABASE' => 'Browse styles database', -]); diff --git a/install/update/new/language/en/captcha_recaptcha.php b/install/update/new/language/en/captcha_recaptcha.php deleted file mode 100644 index 68546ae..0000000 --- a/install/update/new/language/en/captcha_recaptcha.php +++ /dev/null @@ -1,52 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - '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 www.google.com/recaptcha.', - 'CAPTCHA_RECAPTCHA' => 'reCaptcha', - 'RECAPTCHA_INCORRECT' => 'The solution you provided was incorrect', - 'RECAPTCHA_NOSCRIPT' => 'Please enable JavaScript in your browser to load the challenge.', - - 'RECAPTCHA_PUBLIC' => 'Site key', - 'RECAPTCHA_PUBLIC_EXPLAIN' => 'Your site reCAPTCHA key. Keys can be obtained on www.google.com/recaptcha. Please, use reCAPTCHA v2 > Invisible reCAPTCHA badge type.', - 'RECAPTCHA_PRIVATE' => 'Secret key', - 'RECAPTCHA_PRIVATE_EXPLAIN' => 'Your secret reCAPTCHA key. Keys can be obtained on www.google.com/recaptcha. Please, use reCAPTCHA v2 > Invisible reCAPTCHA badge type.', - - 'RECAPTCHA_INVISIBLE' => 'This CAPTCHA is actually invisible. To verify that it works, a small icon should appear in right bottom corner of this page.', -)); diff --git a/install/update/new/language/en/cli.php b/install/update/new/language/en/cli.php deleted file mode 100644 index 122010d..0000000 --- a/install/update/new/language/en/cli.php +++ /dev/null @@ -1,175 +0,0 @@ - -* @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; -} - -/** -* DO NOT CHANGE -*/ -if (empty($lang) || !is_array($lang)) -{ - $lang = array(); -} - -// DEVELOPERS PLEASE NOTE -// -// 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 - -$lang = array_merge($lang, array( - 'CLI_CONFIG_CANNOT_CACHED' => 'Set this option if the configuration option changes too frequently to be efficiently cached.', - 'CLI_CONFIG_CURRENT' => 'Current configuration value, use 0 and 1 to specify boolean values', - 'CLI_CONFIG_DELETE_SUCCESS' => 'Successfully deleted config %s.', - 'CLI_CONFIG_NEW' => 'New configuration value, use 0 and 1 to specify boolean values', - 'CLI_CONFIG_NOT_EXISTS' => 'Config %s does not exist', - 'CLI_CONFIG_OPTION_NAME' => 'The configuration option’s name', - 'CLI_CONFIG_PRINT_WITHOUT_NEWLINE' => 'Set this option if the value should be printed without a new line at the end.', - 'CLI_CONFIG_INCREMENT_BY' => 'Amount to increment by', - 'CLI_CONFIG_INCREMENT_SUCCESS' => 'Successfully incremented config %s', - 'CLI_CONFIG_SET_FAILURE' => 'Could not set config %s', - 'CLI_CONFIG_SET_SUCCESS' => 'Successfully set config %s', - - '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.', - 'CLI_DESCRIPTION_FIND_MIGRATIONS' => 'Finds migrations that are not depended upon.', - 'CLI_DESCRIPTION_FIX_LEFT_RIGHT_IDS' => 'Repairs the tree structure of the forums and modules.', - '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_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_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_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 --deactivate option. -To optionally send an activation email to the user, use the --send-email option.', - 'CLI_HELP_USER_ADD' => 'The %command.name% 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 --send-email 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/install/update/new/language/en/common.php b/install/update/new/language/en/common.php deleted file mode 100644 index 31914cf..0000000 --- a/install/update/new/language/en/common.php +++ /dev/null @@ -1,1453 +0,0 @@ - -* @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(); -} - -// 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 -// -// Some characters you may want to copy&paste: -// ’ » “ ” … -// - -$lang = array_merge($lang, array( - 'TRANSLATION_INFO' => '', - 'DIRECTION' => 'ltr', - 'DATE_FORMAT' => '|d M Y|', // 01 Jan 2007 (with Relative days enabled) - 'DATETIME_FORMAT' => '|d M Y, H:i|', // 01 Jan 2007, 13:37 (with Relative days enabled) - 'USER_LANG' => 'en-gb', - - // You can define different rules for the determination of plural forms here. - // See https://area51.phpbb.com/docs/dev/32x/language/plurals.html for more information - // or ask the translation manager for help. - 'PLURAL_RULE' => 1, - - '1_DAY' => '1 day', - '1_MONTH' => '1 month', - '1_YEAR' => '1 year', - '2_WEEKS' => '2 weeks', - '3_MONTHS' => '3 months', - '6_MONTHS' => '6 months', - '7_DAYS' => '7 days', - - '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.', - 'ACP' => 'Administration Control Panel', - 'ACP_SHORT' => 'ACP', - 'ACTIVE' => 'active', - 'ACTIVE_ERROR' => 'The specified username is currently inactive. If you have problems activating your account, please contact a board administrator.', - 'ADMINISTRATOR' => 'Administrator', - 'ADMINISTRATORS' => 'Administrators', - 'AGE' => 'Age', - 'AIM' => 'AIM', - 'AJAX_ERROR_TITLE' => 'AJAX error', - 'AJAX_ERROR_TEXT' => 'Something went wrong when processing your request.', - 'AJAX_ERROR_TEXT_ABORT' => 'User aborted request.', - 'AJAX_ERROR_TEXT_TIMEOUT' => 'Your request timed out; please try again.', - 'AJAX_ERROR_TEXT_PARSERERROR' => 'Something went wrong with the request and the server returned an invalid reply.', - 'ALLOWED' => 'Allowed', - 'ALL_FILES' => 'All files', - 'ALL_FORUMS' => 'All forums', - 'ALL_MESSAGES' => 'All messages', - 'ALL_POSTS' => 'All posts', - 'ALL_TIMES' => 'All times are %1$s', - '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.', - 'ASCENDING' => 'Ascending', - 'ATTACHMENTS' => 'Attachments', - '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_REQUEST' => 'Something went wrong when processing your OAuth request.', - '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.', - 'AVATAR_DISALLOWED_EXTENSION' => 'This file cannot be displayed because the extension %s is not allowed.', - 'AVATAR_EMPTY_REMOTE_DATA' => 'The specified avatar could not be uploaded because the remote data appears to be invalid or corrupted.', - '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.
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.
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.', - 'AVATAR_WRONG_SIZE' => 'The submitted avatar is %5$s wide and %6$s high. Avatars must be at least %1$s wide and %2$s high, but no larger than %3$s wide and %4$s high.', - - 'BACK_TO_TOP' => 'Top', - 'BACK_TO_PREV' => 'Back to previous page', - 'BAN_TRIGGERED_BY_EMAIL'=> 'A ban has been issued on your email address.', - 'BAN_TRIGGERED_BY_IP' => 'A ban has been issued on your IP address.', - 'BAN_TRIGGERED_BY_USER' => 'A ban has been issued on your username.', - 'BBCODE_GUIDE' => 'BBCode guide', - 'BCC' => 'BCC', - 'BIRTHDAYS' => 'Birthdays', - 'BOARD_BAN_PERM' => 'You have been permanently banned from this board.

Please contact the %2$sBoard Administrator%3$s for more information.', - 'BOARD_BAN_REASON' => 'Reason given for ban: %s', - 'BOARD_BAN_TIME' => 'You have been banned from this board until %1$s.

Please contact the %2$sBoard Administrator%3$s for more information.', - 'BOARD_DISABLE' => 'Sorry but this board is currently unavailable.', - 'BOARD_DISABLED' => 'This board is currently disabled.', - 'BOARD_UNAVAILABLE' => 'Sorry but the board is temporarily unavailable, please try again in a few minutes.', - 'BROWSING_FORUM' => 'Users browsing this forum: %1$s', - 'BROWSING_FORUM_GUESTS' => 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', - 'BUTTON_PM_NEW' => 'New PM', - 'BUTTON_PM_REPLY' => 'Send Reply', - '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', - - 'CANCEL' => 'Cancel', - 'CHANGE' => 'Change', - 'CHANGE_FONT_SIZE' => 'Change font size', - 'CHANGING_PREFERENCES' => 'Changing board preferences', - 'CHANGING_PROFILE' => 'Changing profile settings', - 'CHARACTERS' => array( - 1 => '%d character', - 2 => '%d characters', - ), - 'COLLAPSE_VIEW' => 'Collapse view', - 'CLOSE_WINDOW' => 'Close window', - 'COLOUR_SWATCH' => 'Colour swatch', - 'COLON' => ':', - 'COMMA_SEPARATOR' => ', ', // Comma used to join lists into a single string, use localised comma if appropriate, eg: Ideographic or Arabic - 'CONFIRM' => 'Confirm', - 'CONFIRM_CODE' => 'Confirmation code', - 'CONFIRM_CODE_EXPLAIN' => 'Enter the code exactly as it appears. All letters are case insensitive.', - 'CONFIRM_CODE_WRONG' => 'The confirmation code you entered was incorrect.', - 'CONFIRM_OPERATION' => 'Are you sure you wish to carry out this operation?', - 'CONFIRM_AVATAR_DELETE' => 'Are you sure you wish to delete this avatar?', - 'CONGRATULATIONS' => 'Congratulations to', - 'CONNECTION_FAILED' => 'Connection failed.', - 'CONNECTION_SUCCESS' => 'Connection was successful!', - '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', - - 'DAY' => 'Day', - 'DAYS' => 'Days', - 'DELETE' => 'Delete', - 'DELETE_ALL' => 'Delete all', - 'DELETE_COOKIES' => 'Delete cookies', - 'DELETE_MARKED' => 'Delete marked', - 'DELETE_POST' => 'Delete post', - 'DELIMITER' => 'Delimiter', - 'DESCENDING' => 'Descending', - 'DISABLED' => 'Disabled', - 'DISPLAY' => 'Display', - 'DISPLAY_GUESTS' => 'Display guests', - 'DISPLAY_MESSAGES' => 'Display messages from previous', - 'DISPLAY_POSTS' => 'Display posts from previous', - 'DISPLAY_TOPICS' => 'Display topics from previous', - 'DOWNLOADED' => 'Downloaded', - 'DOWNLOADING_FILE' => 'Downloading file', - 'DOWNLOAD_COUNTS' => array( - 0 => 'Not downloaded yet', - 1 => 'Downloaded %d time', - 2 => 'Downloaded %d times', - ), - - 'EDIT_POST' => 'Edit post', - 'ELLIPSIS' => '…', - 'EMAIL' => 'Email', // Short form for EMAIL_ADDRESS - 'EMAIL_ADDRESS' => 'Email address', - 'EMAIL_INVALID_EMAIL' => 'The email address you entered is invalid.', - 'EMAIL_SMTP_ERROR_RESPONSE' => 'Ran into problems sending email at Line %1$s. Response: %2$s.', - 'EMPTY_SUBJECT' => 'You must specify a subject when posting a new topic.', - 'EMPTY_MESSAGE_SUBJECT' => 'You must specify a subject when composing a new message.', - 'ENABLED' => 'Enabled', - 'ENCLOSURE' => 'Enclosure', - 'ENTER_USERNAME' => 'Enter username', - 'ERR_CHANGING_DIRECTORY' => 'Unable to change directory.', - 'ERR_CONNECTING_SERVER' => 'Error connecting to the server.', - 'ERR_JAB_AUTH' => 'Could not authorise on Jabber server.', - 'ERR_JAB_CONNECT' => 'Could not connect to Jabber server.', - 'ERR_UNABLE_TO_LOGIN' => 'The specified username or password is incorrect.', - 'ERR_UNWATCHING' => 'An error occurred while trying to unsubscribe.', - 'ERR_WATCHING' => 'An error occurred while trying to subscribe.', - 'ERR_WRONG_PATH_TO_PHPBB' => 'The phpBB path specified appears to be invalid.', - 'ERROR' => 'Error', - 'EXPAND_VIEW' => 'Expand view', - 'EXTENSION' => 'Extension', - 'EXTENSION_DISABLED' => 'The extension %s is not enabled.', - 'EXTENSION_DISABLED_AFTER_POSTING' => 'The extension %s has been deactivated and can no longer be displayed.', - 'EXTENSION_DOES_NOT_EXIST' => 'The extension %s does not exist.', - - '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', - 'FILE_COMMENT' => 'File comment', - 'FILE_CONTENT_ERR' => 'Could not read the contents of file: %s', - 'FILE_JSON_DECODE_ERR' => 'Failed to decode json file: %s', - 'FILE_NOT_FOUND' => 'The requested file could not be found: %s', - 'FIND_USERNAME' => 'Find a member', - 'FOLDER' => 'Folder', - 'FORGOT_PASS' => 'I forgot my password', - 'FORM_INVALID' => 'The submitted form was invalid. Try submitting again.', - 'FORUM' => 'Forum', - 'FORUMS' => 'Forums', - 'FORUMS_MARKED' => 'Forums have been marked read.', - 'FORUM_CAT' => 'Forum category', - 'FORUM_INDEX' => 'Board index', - 'FORUM_LINK' => 'Forum link', - 'FORUM_LOCATION' => 'Forum location', - 'FORUM_LOCKED' => 'Forum locked', - 'FORUM_RULES' => 'Forum rules', - 'FORUM_RULES_LINK' => 'Please click here to view the forum rules', - 'FROM' => 'from', - 'FSOCK_DISABLED' => 'The operation could not be completed because the fsockopen function has been disabled or the server being queried could not be found.', - 'FSOCK_TIMEOUT' => 'A timeout occurred while reading from the network stream.', - - 'FILESYSTEM_CANNOT_CHANGE_FILE_GROUP' => 'Unable to change file group', - 'FILESYSTEM_CANNOT_CHANGE_FILE_PERMISSIONS' => 'Unable to change file permissions', - 'FILESYSTEM_CANNOT_COPY_FILES' => 'Unable to copy files', - 'FILESYSTEM_CANNOT_CREATE_SYMLINK' => 'Unable to create a symlink', - 'FILESYSTEM_CANNOT_CREATE_DIRECTORY' => 'Unable to create directory', - 'FILESYSTEM_CANNOT_DELETE_FILES' => 'Unable to delete files from the system', - 'FILESYSTEM_CANNOT_DUMP_FILE' => 'Unable to dump into file', - 'FILESYSTEM_CANNOT_MIRROR_DIRECTORY' => 'Unable to mirror directory', - 'FILESYSTEM_CANNOT_RENAME_FILE' => 'Unable to rename a file from the system', - 'FILESYSTEM_CANNOT_TOUCH_FILES' => 'Unable to create file or change file timestamps', - - 'FTP_FSOCK_HOST' => 'FTP host', - 'FTP_FSOCK_HOST_EXPLAIN' => 'FTP server used to connect your site.', - 'FTP_FSOCK_PASSWORD' => 'FTP password', - 'FTP_FSOCK_PASSWORD_EXPLAIN' => 'Password for your FTP username.', - 'FTP_FSOCK_PORT' => 'FTP port', - 'FTP_FSOCK_PORT_EXPLAIN' => 'Port used to connect to your server.', - 'FTP_FSOCK_ROOT_PATH' => 'Path to phpBB', - 'FTP_FSOCK_ROOT_PATH_EXPLAIN' => 'Path from the root to your phpBB board.', - 'FTP_FSOCK_TIMEOUT' => 'FTP timeout', - 'FTP_FSOCK_TIMEOUT_EXPLAIN' => 'The amount of time, in seconds, that the system will wait for a reply from your server.', - 'FTP_FSOCK_USERNAME' => 'FTP username', - 'FTP_FSOCK_USERNAME_EXPLAIN' => 'Username used to connect to your server.', - - 'FTP_HOST' => 'FTP host', - 'FTP_HOST_EXPLAIN' => 'FTP server used to connect your site.', - 'FTP_PASSWORD' => 'FTP password', - 'FTP_PASSWORD_EXPLAIN' => 'Password for your FTP username.', - 'FTP_PORT' => 'FTP port', - 'FTP_PORT_EXPLAIN' => 'Port used to connect to your server.', - 'FTP_ROOT_PATH' => 'Path to phpBB', - 'FTP_ROOT_PATH_EXPLAIN' => 'Path from the root to your phpBB board.', - 'FTP_TIMEOUT' => 'FTP timeout', - 'FTP_TIMEOUT_EXPLAIN' => 'The amount of time, in seconds, that the system will wait for a reply from your server.', - 'FTP_USERNAME' => 'FTP username', - 'FTP_USERNAME_EXPLAIN' => 'Username used to connect to your server.', - - 'GENERAL_ERROR' => 'General Error', - 'GB' => 'GB', - 'GIB' => 'GiB', - 'GO' => 'Go', - 'GOOGLEPLUS' => 'Google+', - 'GOTO_FIRST_POST' => 'Go to first post', - 'GOTO_LAST_POST' => 'Go to last post', - 'GOTO_PAGE' => 'Go to page', - 'GROUP' => 'Group', - 'GROUPS' => 'Groups', - 'GROUP_ERR_TYPE' => 'Inappropriate group type specified.', - 'GROUP_ERR_USERNAME' => 'No group name specified.', - 'GROUP_ERR_USER_LONG' => 'Group names cannot exceed 60 characters. The specified group name is too long.', - 'GUEST' => 'Guest', - 'GUEST_USERS_ONLINE' => array( - 1 => 'There is %d guest user online', - 2 => 'There are %d guest users online', - ), - 'GUEST_USERS_TOTAL' => array( - 1 => '%d guest', - 2 => '%d guests', - ), - 'G_ADMINISTRATORS' => 'Administrators', - 'G_BOTS' => 'Bots', - 'G_GUESTS' => 'Guests', - 'G_REGISTERED' => 'Registered users', - 'G_REGISTERED_COPPA' => 'Registered COPPA users', - 'G_GLOBAL_MODERATORS' => 'Global moderators', - 'G_NEWLY_REGISTERED' => 'Newly registered users', - - 'HIDDEN_USERS_ONLINE' => array( - 1 => '%d hidden user', - 2 => '%d hidden users', - ), - 'HIDDEN_USERS_TOTAL' => array( - 1 => '%d hidden', - 2 => '%d hidden', - ), - 'HIDE_GUESTS' => 'Hide guests', - 'HIDE_ME' => 'Hide my online status this session', - 'HOURS' => 'Hours', - 'HOME' => 'Home', - - 'ICQ' => 'ICQ', - 'IF' => 'If', - 'IMAGE' => 'Image', - 'IMAGE_FILETYPE_INVALID' => 'Image file type %d for mimetype %s not supported.', - 'IMAGE_FILETYPE_MISMATCH' => 'Image file type mismatch: expected extension %1$s but extension %2$s given.', - 'IN' => 'in', - 'INACTIVE' => 'Inactive', - 'INDEX' => 'Index page', - 'INFORMATION' => 'Information', - 'INSECURE_REDIRECT' => 'Tried to redirect to potentially insecure url.', - 'INTERESTS' => 'Interests', - 'INVALID_DIGEST_CHALLENGE' => 'Invalid digest challenge.', - 'INVALID_EMAIL_LOG' => '%s possibly an invalid email address?', - 'INVALID_FEED_ATTACHMENTS' => 'The selected feed tried fetching attachments with invalid constraints.', - 'INVALID_PLURAL_RULE' => 'The chosen plural rule is invalid. Valid values are integers between 0 and 15.', - 'IP' => 'IP', - 'IP_BLACKLISTED' => 'Your IP %1$s has been blocked because it is blacklisted. For details please see %2$s.', - - 'JABBER' => 'Jabber', - 'JOINED' => 'Joined', - 'JUMP_PAGE' => 'Enter the page number you wish to go to', - 'JUMP_TO' => 'Jump to', - 'JUMP_TO_PAGE' => 'Jump to page', - 'JUMP_TO_PAGE_CLICK' => 'Click to jump to page…', - - 'KB' => 'KB', - 'KIB' => 'KiB', - - 'LAST_POST' => 'Last post', - 'LAST_UPDATED' => 'Last updated', - 'LAST_VISIT' => 'Last visit', - 'LDAP_NO_LDAP_EXTENSION' => 'LDAP extension not available.', - 'LDAP_NO_SERVER_CONNECTION' => 'Could not connect to LDAP server.', - 'LDAP_SEARCH_FAILED' => 'An error occurred while searching the LDAP directory.', - 'LEGEND' => 'Legend', - 'LIVE_SEARCHES_NOT_ALLOWED' => 'Live searches are not allowed.', - 'LOADING' => 'Loading', - 'LOCATION' => 'Location', - 'LOCK_POST' => 'Lock post', - 'LOCK_POST_EXPLAIN' => 'Prevent editing', - 'LOCK_TOPIC' => 'Lock topic', - 'LOGIN' => 'Login', - 'LOGIN_CHECK_PM' => 'Log in to check your private messages.', - 'LOGIN_CONFIRMATION' => 'Confirmation of login', - 'LOGIN_CONFIRM_EXPLAIN' => 'To prevent brute forcing accounts the board requires you to enter a confirmation code after a maximum amount of failed logins. The code is displayed in the image you should see below. If you are visually impaired or cannot otherwise read this code please contact the %sBoard Administrator%s.', // unused - 'LOGIN_ERROR_ATTEMPTS' => 'You exceeded the maximum allowed number of login attempts. In addition to your username and password you now also have to pass the CAPTCHA test.', - 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE' => 'You have not been authenticated by Apache.', - 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST' => 'A non-existant OAuth service has been requested.', - 'LOGIN_ERROR_PASSWORD' => 'You have specified an incorrect password. Please check your password and try again. If you continue to have problems please contact the %sBoard Administrator%s.', - 'LOGIN_ERROR_PASSWORD_CONVERT' => 'It was not possible to convert your password when updating this bulletin board’s software. Please %srequest a new password%s. If you continue to have problems please contact the %sBoard Administrator%s.', - 'LOGIN_ERROR_USERNAME' => 'You have specified an incorrect username. Please check your username and try again. If you continue to have problems please contact the %sBoard Administrator%s.', - 'LOGIN_FORUM' => 'To view or post in this forum you must enter its password.', - 'LOGIN_INFO' => 'In order to login you must be registered. Registering takes only a few moments but gives you increased capabilities. The board administrator may also grant additional permissions to registered users. Before you register please ensure you are familiar with our terms of use and related policies. Please ensure you read any forum rules as you navigate around the board.', - 'LOGIN_VIEWFORUM' => 'The board requires you to be registered and logged in to view this forum.', - 'LOGIN_EXPLAIN_EDIT' => 'In order to edit posts in this forum you have to be registered and logged in.', - 'LOGIN_EXPLAIN_VIEWONLINE' => 'In order to view the online list you have to be registered and logged in.', - 'LOGIN_REQUIRED' => 'You need to login to perform this action.', - 'LOGOUT' => 'Logout', - 'LOGOUT_USER' => 'Logout [ %s ]', - 'LOG_ME_IN' => 'Remember me', - - 'MAIN' => 'Main', - 'MARK' => 'Mark', - 'MARK_ALL' => 'Mark all', - 'MARK_ALL_READ' => 'Mark all read', - 'MARK_FORUMS_READ' => 'Mark forums read', - 'MARK_READ' => 'Mark read', - 'MARK_SUBFORUMS_READ' => 'Mark subforums read', - 'MB' => 'MB', - 'MIB' => 'MiB', - 'MCP' => 'Moderator Control Panel', - 'MCP_SHORT' => 'MCP', - 'MEMBERLIST' => 'Members', - 'MEMBERLIST_EXPLAIN' => 'View complete list of members', - 'MERGE' => 'Merge', - 'MERGE_POSTS' => 'Move posts', - 'MERGE_TOPIC' => 'Merge topic', - 'MESSAGE' => 'Message', - 'MESSAGES' => 'Messages', - 'MESSAGES_COUNT' => array( - 1 => '%d message', - 2 => '%d messages', - ), - 'MESSAGE_BODY' => 'Message body', - 'MINUTES' => 'Minutes', - 'MODERATE' => 'Moderate', - 'MODERATOR' => 'Moderator', - 'MODERATORS' => 'Moderators', - 'MODULE_NOT_ACCESS' => 'Module not accessible', - 'MODULE_NOT_FIND' => 'Cannot find module %s', - 'MODULE_FILE_INCORRECT_CLASS' => 'Module file %s does not contain correct class [%s]', - 'MONTH' => 'Month', - 'MOVE' => 'Move', - - 'NA' => 'N/A', - 'NEWEST_USER' => 'Our newest member %s', - 'NEW_MESSAGE' => 'New message', - 'NEW_MESSAGES' => 'New messages', - 'NEW_POST' => 'New post', // Not used anymore - 'NEW_POSTS' => 'New posts', // Not used anymore - 'NEXT' => 'Next', // Used in pagination - 'NEXT_STEP' => 'Next', - 'NEVER' => 'Never', - 'NO' => 'No', - 'NO_NOTIFICATIONS' => 'You have no notifications', - 'NOT_ALLOWED_MANAGE_GROUP' => 'You are not allowed to manage this group.', - 'NOT_AUTHORISED' => 'You are not authorised to access this area.', - 'NOT_WATCHING_FORUM' => 'You are no longer subscribed to updates on this forum.', - 'NOT_WATCHING_TOPIC' => 'You are no longer subscribed to this topic.', - 'NOTIFICATIONS' => 'Notifications', - // This applies for NOTIFICATION_BOOKMARK and NOTIFICATION_POST. - // %1$s will return a list of users that's concatenated using "," and "and" - see STRING_LIST - // Once the user count reaches 5 users or more, the list is trimmed using NOTIFICATION_X_OTHERS - // Once the user count reaches 20 users or more, the list is trimmed using NOTIFICATION_MANY_OTHERS - // Examples: - // A replied... - // A and B replied... - // A, B and C replied... - // A, B, C and 2 others replied... - // A, B, C and others replied... - 'NOTIFICATION_BOOKMARK' => array( - 1 => 'Reply from %1$s in bookmarked topic:', - ), - 'NOTIFICATION_FORUM' => 'Forum: %1$s', - 'NOTIFICATION_GROUP_REQUEST' => 'Group request from %1$s to join the group %2$s.', - 'NOTIFICATION_GROUP_REQUEST_APPROVED' => 'Group request approved to join the group %1$s.', - 'NOTIFICATION_METHOD_INVALID' => 'The method "%s" does not refer to a valid notification method.', - 'NOTIFICATION_PM' => 'Private Message from %1$s:', - 'NOTIFICATION_POST' => array( - 1 => 'Reply from %1$s in topic:', - ), - 'NOTIFICATION_POST_APPROVED' => 'Post approved:', - 'NOTIFICATION_POST_DISAPPROVED' => 'Post disapproved:', - 'NOTIFICATION_POST_IN_QUEUE' => 'Post approval request by %1$s:', - 'NOTIFICATION_QUOTE' => array( - 1 => 'Quoted by %1$s in:', - ), - 'NOTIFICATION_REFERENCE' => '"%1$s"', - 'NOTIFICATION_REASON' => 'Reason: %1$s.', - 'NOTIFICATION_REPORT_PM' => 'Private Message reported by %1$s:', - 'NOTIFICATION_REPORT_POST' => 'Post reported by %1$s:', - 'NOTIFICATION_REPORT_CLOSED' => 'Report closed by %1$s for:', - 'NOTIFICATION_TOPIC' => 'New topic by %1$s:', - 'NOTIFICATION_TOPIC_APPROVED' => 'Topic approved:', - 'NOTIFICATION_TOPIC_DISAPPROVED' => 'Topic disapproved:', - 'NOTIFICATION_TOPIC_IN_QUEUE' => 'Topic approval request by %1$s:', - 'NOTIFICATION_TYPE_NOT_EXIST' => 'The notification type "%s" is missing from the file system.', - 'NOTIFICATION_ADMIN_ACTIVATE_USER' => 'Activation required for deactivated or newly registered user: “%1$s”', - // Used in conjunction with NOTIFICATION_BOOKMARK and NOTIFICATION_POST. - 'NOTIFICATION_MANY_OTHERS' => 'others', - 'NOTIFICATION_X_OTHERS' => array( - 2 => '%d others', - ), - 'NOTIFY_ADMIN' => 'Please notify the board administrator or webmaster.', - 'NOTIFY_ADMIN_EMAIL' => 'Please notify the board administrator or webmaster: %1$s', - 'NO_ACCESS_ATTACHMENT' => 'You are not allowed to access this file.', - 'NO_ACTION' => 'No action specified.', - 'NO_ADMINISTRATORS' => 'There are no administrators.', - 'NO_AUTH_ADMIN' => 'Access to the Administration Control Panel is not allowed as you do not have administrative permissions.', - 'NO_AUTH_ADMIN_USER_DIFFER' => 'You are not able to re-authenticate as a different user.', - 'NO_AUTH_OPERATION' => 'You do not have the necessary permissions to complete this operation.', - 'NO_AVATARS' => 'No avatars currently available', - 'NO_CONNECT_TO_SMTP_HOST' => 'Could not connect to smtp host : %1$s : %2$s', - 'NO_BIRTHDAYS' => 'No birthdays today', - 'NO_EMAIL_MESSAGE' => 'Email message was blank.', - 'NO_EMAIL_RESPONSE_CODE' => 'Could not get mail server response codes.', - 'NO_EMAIL_SUBJECT' => 'No email subject specified.', - 'NO_FORUM' => 'The forum you selected does not exist.', - 'NO_FORUMS' => 'This board has no forums.', - 'NO_GROUP' => 'The requested usergroup does not exist.', - 'NO_GROUP_MEMBERS' => 'This group currently has no members.', - 'NO_IPS_DEFINED' => 'No IP addresses or hostnames defined', - 'NO_MEMBERS' => 'No members found for this search criterion.', - 'NO_MESSAGES' => 'No messages', - 'NO_MODE' => 'No mode specified.', - 'NO_MODERATORS' => 'There are no moderators.', - 'NO_NEW_MESSAGES' => 'No new messages', - 'NO_NEW_POSTS' => 'No new posts', // Not used anymore - 'NO_ONLINE_USERS' => 'No registered users', - 'NO_POSTS' => 'No posts', - 'NO_POSTS_TIME_FRAME' => 'No posts exist inside this topic for the selected time frame.', - 'NO_FEED_ENABLED' => 'Feeds are not available on this board.', - 'NO_FEED' => 'The requested feed is not available.', - 'NO_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.', - 'NO_TOPIC' => 'The requested topic does not exist.', - 'NO_TOPIC_FORUM' => 'The topic or forum no longer exists.', - 'NO_TOPICS' => 'There are no topics or posts in this forum.', - 'NO_TOPICS_TIME_FRAME' => 'No topics exist inside this forum for the selected time frame.', - 'NO_UNREAD_POSTS' => 'No unread posts', - 'NO_UPLOAD_FORM_FOUND' => 'Upload initiated but no valid file upload form found.', - 'NO_USER' => 'The requested user does not exist.', - 'NO_USERS' => 'The requested users do not exist.', - 'NO_USER_SPECIFIED' => 'No username was specified.', - - // Nullar/Singular/Plural language entry. The key numbers define the number range in which a certain grammatical expression is valid. - 'NUM_ATTACHMENTS' => array( - 1 => '%d attachment', - 2 => '%d attachments', - ), - 'NUM_POSTS_IN_QUEUE' => array( - 0 => 'No posts in queue', // 0 - 1 => '1 post in queue', // 1 - 2 => '%d posts in queue', // 2+ - ), - - 'OCCUPATION' => 'Occupation', - 'OFFLINE' => 'Offline', - 'ONLINE' => 'Online', - 'ONLINE_BUDDIES' => 'Online friends', - // "... :: x registered and y hidden" - 'ONLINE_USERS_TOTAL' => array( - 1 => 'In total there is %1$d user online :: %2$s and %3$s', - 2 => 'In total there are %1$d users online :: %2$s and %3$s', - ), - // "... :: x registered, y hidden and z guests" - 'ONLINE_USERS_TOTAL_GUESTS' => array( - 1 => 'In total there is %1$d user online :: %2$s, %3$s and %4$s', - 2 => 'In total there are %1$d users online :: %2$s, %3$s and %4$s', - ), - 'OPTIONS' => 'Options', - - 'PAGE_NOT_FOUND' => 'The requested page could not be found.', - 'PAGE_OF' => 'Page %1$d of %2$d', - 'PAGE_TITLE_NUMBER' => 'Page %s', - 'PASSWORD' => 'Password', - 'PIXEL' => 'px', - 'PIXELS' => array( - 1 => '%d pixel', - 2 => '%d pixels', - ), - 'PLEASE_WAIT' => 'Please wait.', - 'PM' => 'PM', - 'PM_REPORTED' => 'Click to view report', - 'POSTING_MESSAGE' => 'Posting message in %s', - 'POSTING_PRIVATE_MESSAGE' => 'Composing private message', - 'POST' => 'Post', - 'POST_ANNOUNCEMENT' => 'Announce', - 'POST_STICKY' => 'Sticky', - 'POSTED' => 'Posted', - 'POSTED_IN_FORUM' => 'in', - 'POSTED_ON_DATE' => 'on', - 'POSTS' => 'Posts', - 'POSTS_UNAPPROVED' => 'At least one post in this topic has not been approved.', - 'POSTS_UNAPPROVED_FORUM'=> 'At least one post in this forum has not been approved.', - 'POST_BY_AUTHOR' => 'by', - 'POST_BY_FOE' => '%1$s, who is currently on your ignore list, made this post.', - 'POST_DISPLAY' => '%1$sDisplay this post%2$s.', - 'POST_DAY' => '%.2f posts per day', - 'POST_DELETED_ACTION' => 'Deleted post:', - 'POST_DELETED' => 'This post has been deleted.', - 'POST_DELETED_BY' => '%2$s deleted the post by %1$s on %3$s.', - 'POST_DELETED_BY_REASON'=> '%2$s deleted the post by %1$s on %3$s for the following reason: %4$s', - 'POST_DETAILS' => 'Post details', - 'POST_NEW_TOPIC' => 'Post new topic', - 'POST_PCT' => '%.2f%% of all posts', - 'POST_PCT_ACTIVE' => '%.2f%% of user’s posts', - 'POST_PCT_ACTIVE_OWN' => '%.2f%% of your posts', - 'POST_REPLY' => 'Post a reply', - 'POST_REPORTED' => 'Click to view report', - 'POST_SUBJECT' => 'Post subject', - 'POST_TIME' => 'Post time', - 'POST_TOPIC' => 'Post a new topic', - 'POST_UNAPPROVED_ACTION' => 'Post awaiting approval:', - 'POST_UNAPPROVED' => 'This post has not been approved.', - 'POST_UNAPPROVED_EXPLAIN' => 'This post is not visible to other users until it has been approved by a moderator.', - 'POWERED_BY' => 'Powered by %s', - 'PREVIEW' => 'Preview', - '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', - 'PROFILE' => 'User Control Panel', - - 'QUICK_LINKS' => 'Quick links', - - 'RANK' => 'Rank', - 'READING_FORUM' => 'Viewing topics in %s', - 'READING_GLOBAL_ANNOUNCE' => 'Reading global announcement', - 'READING_LINK' => 'Following forum link %s', - 'READING_TOPIC' => 'Reading topic in %s', - 'READ_PROFILE' => 'Profile', - 'REASON' => 'Reason', - 'RECORD_ONLINE_USERS' => 'Most users ever online was %1$s on %2$s', - 'REDIRECT' => 'Redirect', - 'REDIRECTS' => 'Total redirects', - 'REGISTER' => 'Register', - 'REGISTERED_USERS' => 'Registered users:', - // "... and 2 hidden users online" - 'REG_USERS_ONLINE' => array( - 1 => 'There is %1$d registered user and %2$s online', - 2 => 'There are %1$d registered users and %2$s online', - ), - 'REG_USERS_TOTAL' => array( - 1 => '%d registered', - 2 => '%d registered', - ), - 'REMOVE' => 'Remove', - 'REMOVE_INSTALL' => 'Please delete, move or rename the install directory before you use your board. If this directory is still present, only the Administration Control Panel (ACP) will be accessible.', - 'REPLIES' => 'Replies', - 'REPLY_WITH_QUOTE' => 'Reply with quote', - 'REPLYING_GLOBAL_ANNOUNCE' => 'Replying to global announcement', - 'REPLYING_MESSAGE' => 'Replying to message in %s', - 'REPORT_BY' => 'Report by', - 'REPORT_POST' => 'Report this post', - 'REPORTING_POST' => 'Reporting post', - 'RESEND_ACTIVATION' => 'Resend activation email', - 'RESET' => 'Reset', - 'RESTORE_PERMISSIONS' => 'Restore permissions', - 'RETURN_INDEX' => '%sReturn to the index page%s', - 'RETURN_FORUM' => '%sReturn to the forum last visited%s', - 'RETURN_PAGE' => '%sReturn to the previous page%s', - 'RETURN_TOPIC' => '%sReturn to the topic last visited%s', - 'RETURN_TO' => 'Return to “%s”', - 'RETURN_TO_INDEX' => 'Return to Board Index', - 'FEED' => 'Feed', - 'FEED_NEWS' => 'News', - 'FEED_TOPICS_ACTIVE' => 'Active Topics', - 'FEED_TOPICS_NEW' => 'New Topics', - 'RULES_ATTACH_CAN' => 'You can post attachments in this forum', - 'RULES_ATTACH_CANNOT' => 'You cannot post attachments in this forum', - 'RULES_DELETE_CAN' => 'You can delete your posts in this forum', - 'RULES_DELETE_CANNOT' => 'You cannot delete your posts in this forum', - 'RULES_DOWNLOAD_CAN' => 'You can download attachments in this forum', - 'RULES_DOWNLOAD_CANNOT' => 'You cannot download attachments in this forum', - 'RULES_EDIT_CAN' => 'You can edit your posts in this forum', - 'RULES_EDIT_CANNOT' => 'You cannot edit your posts in this forum', - 'RULES_LOCK_CAN' => 'You can lock your topics in this forum', - 'RULES_LOCK_CANNOT' => 'You cannot lock your topics in this forum', - 'RULES_POST_CAN' => 'You can post new topics in this forum', - 'RULES_POST_CANNOT' => 'You cannot post new topics in this forum', - 'RULES_REPLY_CAN' => 'You can reply to topics in this forum', - 'RULES_REPLY_CANNOT' => 'You cannot reply to topics in this forum', - 'RULES_VOTE_CAN' => 'You can vote in polls in this forum', - 'RULES_VOTE_CANNOT' => 'You cannot vote in polls in this forum', - - 'SEARCH' => 'Search', - 'SEARCH_MINI' => 'Search…', - 'SEARCH_ADV' => 'Advanced search', - 'SEARCH_ADV_EXPLAIN' => 'View the advanced search options', - 'SEARCH_KEYWORDS' => 'Search for keywords', - 'SEARCHING_FORUMS' => 'Searching forums', - 'SEARCH_ACTIVE_TOPICS' => 'Active topics', - 'SEARCH_FOR' => 'Search for', - 'SEARCH_FORUM' => 'Search this forum…', - 'SEARCH_NEW' => 'New posts', - 'SEARCH_POSTS_BY' => 'Search posts by', - 'SEARCH_SELF' => 'Your posts', - 'SEARCH_TOPIC' => 'Search this topic…', - 'SEARCH_UNANSWERED' => 'Unanswered topics', - 'SEARCH_UNREAD' => 'Unread posts', - 'SEARCH_USER_POSTS' => 'Search user’s posts', - 'SECONDS' => 'Seconds', - 'SEE_ALL' => 'See All', - 'SELECT' => 'Select', - 'SELECT_ALL_CODE' => 'Select all', - 'SELECT_DESTINATION_FORUM' => 'Please select a destination forum', - 'SELECT_FORUM' => 'Select a forum', - 'SEND_EMAIL' => 'Send email', // Used for submit buttons - 'SEND_EMAIL_USER' => 'Send email to %s', - 'SEND_PRIVATE_MESSAGE' => 'Send private message', - 'SETTINGS' => 'Settings', - 'SIGNATURE' => 'Signature', - 'SKIP' => 'Skip to content', - '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', - 'SORT_USERNAME' => 'Username', - 'SPLIT_TOPIC' => 'Split topic', - 'SQL_ERROR_OCCURRED' => 'An SQL error occurred while fetching this page. Please contact the %sBoard Administrator%s if this problem persists.', - 'STATISTICS' => 'Statistics', - 'START_WATCHING_FORUM' => 'Subscribe forum', - 'START_WATCHING_TOPIC' => 'Subscribe topic', - 'STOP_WATCHING_FORUM' => 'Unsubscribe forum', - 'STOP_WATCHING_TOPIC' => 'Unsubscribe topic', - 'STRING_LIST_MULTI' => '%1$s, and %2$s', - 'STRING_LIST_SIMPLE' => '%1$s and %2$s', - 'SUBFORUM' => 'Subforum', - 'SUBFORUMS' => 'Subforums', - 'SUBJECT' => 'Subject', - 'SUBMIT' => 'Submit', - - 'TB' => 'TB', - 'TERMS_LINK' => 'Terms', - 'TERMS_USE' => 'Terms of use', - 'TEST_CONNECTION' => 'Test connection', - 'THE_TEAM' => 'The team', - 'TIB' => 'TiB', - 'TIME' => 'Time', - 'TIMEOUT_PROCESSING_REQ' => 'Request timed out.', - - 'TOO_LARGE' => 'The value you entered is too large.', - 'TOO_LARGE_MAX_RECIPIENTS' => 'The value of Maximum number of allowed recipients per private message setting you entered is too large.', - - 'TOO_LONG' => 'The value you entered is too long.', - - 'TOO_LONG_CONFIRM_CODE' => 'The confirm code you entered is too long.', - 'TOO_LONG_DATEFORMAT' => 'The date format you entered is too long.', - 'TOO_LONG_JABBER' => 'The Jabber account name you entered is too long.', - 'TOO_LONG_NEW_PASSWORD' => 'The password you entered is too long.', - 'TOO_LONG_PASSWORD_CONFIRM' => 'The password confirmation you entered is too long.', - 'TOO_LONG_USER_PASSWORD' => 'The password you entered is too long.', - 'TOO_LONG_USERNAME' => 'The username you entered is too long.', - 'TOO_LONG_EMAIL' => 'The email address you entered is too long.', - - 'TOO_MANY_VOTE_OPTIONS' => 'You have tried to vote for too many options.', - - 'TOO_SHORT' => 'The value you entered is too short.', - - 'TOO_SHORT_CONFIRM_CODE' => 'The confirm code you entered is too short.', - 'TOO_SHORT_DATEFORMAT' => 'The date format you entered is too short.', - 'TOO_SHORT_JABBER' => 'The Jabber account name you entered is too short.', - 'TOO_SHORT_NEW_PASSWORD' => 'The password you entered is too short.', - 'TOO_SHORT_PASSWORD_CONFIRM' => 'The password confirmation you entered is too short.', - 'TOO_SHORT_USER_PASSWORD' => 'The password you entered is too short.', - 'TOO_SHORT_USERNAME' => 'The username you entered is too short.', - 'TOO_SHORT_EMAIL' => 'The email address you entered is too short.', - 'TOO_SHORT_EMAIL_CONFIRM' => 'The email address confirmation you entered is too short.', - 'TOO_SMALL' => 'The value you entered is too small.', - 'TOO_SMALL_MAX_RECIPIENTS' => 'The value of Maximum number of allowed recipients per private message setting you entered is too small.', - - 'TOPIC' => 'Topic', - 'TOPICS' => 'Topics', - 'TOPICS_UNAPPROVED' => 'At least one topic in this forum has not been approved.', - 'TOPIC_ICON' => 'Topic icon', - 'TOPIC_LOCKED' => 'This topic is locked, you cannot edit posts or make further replies.', - 'TOPIC_LOCKED_SHORT'=> 'Topic locked', - 'TOPIC_MOVED' => 'Moved topic', - '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( - 1 => '%d log', - 2 => '%d logs', - ), - 'TOTAL_PMS' => array( - 1 => '%d private message in total', - 2 => '%d private messages in total', - ), - 'TOPIC_POLL' => 'This topic has a poll.', - 'TOTAL_POSTS' => 'Total posts', - 'TOTAL_POSTS_COUNT' => array( - 2 => 'Total posts %d', - ), - 'TOPIC_REPORTED' => 'This topic has been reported', - 'TOTAL_TOPICS' => array( - 2 => 'Total topics %d', - ), - 'TOTAL_USERS' => array( - 2 => 'Total members %d', - ), - 'TRACKED_PHP_ERROR' => 'Tracked PHP errors: %s', - 'TWITTER' => 'Twitter', - - 'UNABLE_GET_IMAGE_SIZE' => 'It was not possible to determine the dimensions of the image. Please verify that the URL you entered is correct.', - 'UNABLE_TO_DELIVER_FILE'=> 'Unable to deliver file.', - 'UNKNOWN_BROWSER' => 'Unknown browser', - 'UNMARK_ALL' => 'Unmark all', - 'UNREAD_MESSAGES' => 'Unread messages', - 'UNREAD_POST' => 'Unread post', - 'UNREAD_POSTS' => 'Unread posts', - 'UNWATCH_FORUM_CONFIRM' => 'Are you sure you wish to unsubscribe from this forum?', - 'UNWATCH_FORUM_DETAILED' => 'Are you sure you wish to unsubscribe from the forum “%s”?', - 'UNWATCH_TOPIC_CONFIRM' => 'Are you sure you wish to unsubscribe from this topic?', - 'UNWATCH_TOPIC_DETAILED' => 'Are you sure you wish to unsubscribe from the topic “%s”?', - 'UNWATCHED_FORUMS' => 'You are no longer subscribed to the selected forums.', - 'UNWATCHED_TOPICS' => 'You are no longer subscribed to the selected topics.', - 'UNWATCHED_FORUMS_TOPICS' => 'You are no longer subscribed to the selected entries.', - 'UPDATE' => 'Update', - 'UPLOAD_IN_PROGRESS' => 'The upload is currently in progress.', - 'URL_REDIRECT' => 'If your browser does not support meta redirection %splease click HERE to be redirected%s.', - 'USERGROUPS' => 'Groups', - 'USERNAME' => 'Username', - 'USERNAMES' => 'Usernames', - 'USER_AVATAR' => 'User avatar', - 'USER_CANNOT_READ' => 'You cannot read posts in this forum.', - 'USER_POSTS' => array( - 1 => '%d Post', - 2 => '%d Posts', - ), - 'USERS' => 'Users', - 'USE_PERMISSIONS' => 'Test out user’s permissions', - - 'USER_NEW_PERMISSION_DISALLOWED' => 'We are sorry, but you are not authorised to use this feature. You may have just registered here and may need to participate more in discussions to be able to use this feature.', - - 'VARIANT_DATE_SEPARATOR' => ' / ', // Used in date format dropdown, eg: "Today, 13:37 / 01 Jan 2007, 13:37" ... to join a relative date with calendar date - 'VIEWED' => 'Viewed', - 'VIEWED_COUNTS' => array( - 0 => 'Not viewed yet', - 1 => 'Viewed %d time', - 2 => 'Viewed %d times', - ), - 'VIEWING_CONTACT_ADMIN' => 'Viewing contact page', - 'VIEWING_FAQ' => 'Viewing FAQ', - 'VIEWING_MEMBERS' => 'Viewing member details', - 'VIEWING_ONLINE' => 'Viewing who is online', - 'VIEWING_MCP' => 'Viewing moderator control panel', - 'VIEWING_MEMBER_PROFILE' => 'Viewing member profile', - 'VIEWING_PRIVATE_MESSAGES' => 'Viewing private messages', - 'VIEWING_REGISTER' => 'Registering account', - 'VIEWING_UCP' => 'Viewing user control panel', - 'VIEWS' => 'Views', - 'VIEW_BOOKMARKS' => 'View bookmarks', - 'VIEW_FORUM_LOGS' => 'View Logs', - 'VIEW_LATEST_POST' => 'View the latest post', - 'VIEW_NEWEST_POST' => 'View first unread post', - 'VIEW_NOTES' => 'View user notes', - 'VIEW_ONLINE_TIMES' => array( - 1 => 'based on users active over the past %d minute', - 2 => 'based on users active over the past %d minutes', - ), - 'VIEW_TOPIC' => 'View topic', - 'VIEW_TOPIC_ANNOUNCEMENT' => 'Announcement: ', - 'VIEW_TOPIC_GLOBAL' => 'Global Announcement: ', - 'VIEW_TOPIC_LOCKED' => 'Locked: ', - 'VIEW_TOPIC_LOGS' => 'View logs', - 'VIEW_TOPIC_MOVED' => 'Moved: ', - 'VIEW_TOPIC_POLL' => 'Poll: ', - 'VIEW_TOPIC_STICKY' => 'Sticky: ', - 'VISIT_WEBSITE' => 'Visit website', - - 'WARNINGS' => 'Warnings', - 'WARN_USER' => 'Warn user', - 'WATCH_FORUM_CONFIRM' => 'Are you sure you wish to subscribe to this forum?', - 'WATCH_FORUM_DETAILED' => 'Are you sure you wish to subscribe to the forum “%s”?', - 'WATCH_TOPIC_CONFIRM' => 'Are you sure you wish to subscribe to this topic?', - 'WATCH_TOPIC_DETAILED' => 'Are you sure you wish to subscribe to the topic “%s”?', - 'WELCOME_SUBJECT' => 'Welcome to %s forums', - 'WEBSITE' => 'Website', - 'WHOIS' => 'Whois', - 'WHO_IS_ONLINE' => 'Who is online', - 'WRONG_PASSWORD' => 'You entered an incorrect password.', - - 'WRONG_DATA_COLOUR' => 'The colour value you entered is invalid.', - 'WRONG_DATA_JABBER' => 'The name you entered is not a valid Jabber account name.', - 'WRONG_DATA_LANG' => 'The language you specified is not valid.', - 'WRONG_DATA_POST_SD' => 'The post sort direction you specified is not valid.', - 'WRONG_DATA_POST_SK' => 'The post sort option you specified is not valid.', - 'WRONG_DATA_TOPIC_SD' => 'The topic sort direction you specified is not valid.', - 'WRONG_DATA_TOPIC_SK' => 'The topic sort option you specified is not valid.', - 'WROTE' => 'wrote', - - 'YAHOO' => 'Yahoo Messenger', - 'YOUTUBE' => 'YouTube', - 'YEAR' => 'Year', - 'YEAR_MONTH_DAY' => '(YYYY-MM-DD)', - 'YES' => 'Yes', - 'YOU_LAST_VISIT' => 'Last visit was: %s', - - 'datetime' => array( - 'TODAY' => 'Today', - 'TOMORROW' => 'Tomorrow', - 'YESTERDAY' => 'Yesterday', - 'AGO' => array( - 0 => 'less than a minute ago', - 1 => '%d minute ago', - 2 => '%d minutes ago', - ), - - 'Sunday' => 'Sunday', - 'Monday' => 'Monday', - 'Tuesday' => 'Tuesday', - 'Wednesday' => 'Wednesday', - 'Thursday' => 'Thursday', - 'Friday' => 'Friday', - 'Saturday' => 'Saturday', - - 'Sun' => 'Sun', - 'Mon' => 'Mon', - 'Tue' => 'Tue', - 'Wed' => 'Wed', - 'Thu' => 'Thu', - 'Fri' => 'Fri', - 'Sat' => 'Sat', - - 'January' => 'January', - 'February' => 'February', - 'March' => 'March', - 'April' => 'April', - 'May' => 'May', - 'June' => 'June', - 'July' => 'July', - 'August' => 'August', - 'September' => 'September', - 'October' => 'October', - 'November' => 'November', - 'December' => 'December', - - 'Jan' => 'Jan', - 'Feb' => 'Feb', - 'Mar' => 'Mar', - 'Apr' => 'Apr', - 'May_short' => 'May', // Short representation of "May". May_short used because in English the short and long date are the same for May. - 'Jun' => 'Jun', - 'Jul' => 'Jul', - 'Aug' => 'Aug', - 'Sep' => 'Sep', - 'Oct' => 'Oct', - 'Nov' => 'Nov', - 'Dec' => 'Dec', - ), - - // Timezones can be translated. We use this for the Etc/GMT timezones here, - // because they are named invers to their offset. - 'timezones' => array( - 'UTC' => 'UTC', - 'UTC_OFFSET' => 'UTC%1$s', - 'UTC_OFFSET_CURRENT' => 'UTC%1$s - %2$s', - - 'Etc/GMT-12' => 'UTC+12', - 'Etc/GMT-11' => 'UTC+11', - 'Etc/GMT-10' => 'UTC+10', - 'Etc/GMT-9' => 'UTC+9', - 'Etc/GMT-8' => 'UTC+8', - 'Etc/GMT-7' => 'UTC+7', - 'Etc/GMT-6' => 'UTC+6', - 'Etc/GMT-5' => 'UTC+5', - 'Etc/GMT-4' => 'UTC+4', - 'Etc/GMT-3' => 'UTC+3', - 'Etc/GMT-2' => 'UTC+2', - 'Etc/GMT-1' => 'UTC+1', - 'Etc/GMT+1' => 'UTC-1', - 'Etc/GMT+2' => 'UTC-2', - 'Etc/GMT+3' => 'UTC-3', - 'Etc/GMT+4' => 'UTC-4', - 'Etc/GMT+5' => 'UTC-5', - 'Etc/GMT+6' => 'UTC-6', - 'Etc/GMT+7' => 'UTC-7', - 'Etc/GMT+8' => 'UTC-8', - 'Etc/GMT+9' => 'UTC-9', - 'Etc/GMT+10' => 'UTC-10', - 'Etc/GMT+11' => 'UTC-11', - 'Etc/GMT+12' => 'UTC-12', - - 'Africa/Abidjan' => 'Africa/Abidjan', - 'Africa/Accra' => 'Africa/Accra', - 'Africa/Addis_Ababa' => 'Africa/Addis Ababa', - 'Africa/Algiers' => 'Africa/Algiers', - 'Africa/Asmara' => 'Africa/Asmara', - 'Africa/Bamako' => 'Africa/Bamako', - 'Africa/Bangui' => 'Africa/Bangui', - 'Africa/Banjul' => 'Africa/Banjul', - 'Africa/Bissau' => 'Africa/Bissau', - 'Africa/Blantyre' => 'Africa/Blantyre', - 'Africa/Brazzaville' => 'Africa/Brazzaville', - 'Africa/Bujumbura' => 'Africa/Bujumbura', - 'Africa/Cairo' => 'Africa/Cairo', - 'Africa/Casablanca' => 'Africa/Casablanca', - 'Africa/Ceuta' => 'Africa/Ceuta', - 'Africa/Conakry' => 'Africa/Conakry', - 'Africa/Dakar' => 'Africa/Dakar', - 'Africa/Dar_es_Salaam' => 'Africa/Dar es Salaam', - 'Africa/Djibouti' => 'Africa/Djibouti', - 'Africa/Douala' => 'Africa/Douala', - 'Africa/El_Aaiun' => 'Africa/El Aaiun', - 'Africa/Freetown' => 'Africa/Freetown', - 'Africa/Gaborone' => 'Africa/Gaborone', - 'Africa/Harare' => 'Africa/Harare', - 'Africa/Johannesburg' => 'Africa/Johannesburg', - 'Africa/Juba' => 'Africa/Juba', - 'Africa/Kampala' => 'Africa/Kampala', - 'Africa/Khartoum' => 'Africa/Khartoum', - 'Africa/Kigali' => 'Africa/Kigali', - 'Africa/Kinshasa' => 'Africa/Kinshasa', - 'Africa/Lagos' => 'Africa/Lagos', - 'Africa/Libreville' => 'Africa/Libreville', - 'Africa/Lome' => 'Africa/Lome', - 'Africa/Luanda' => 'Africa/Luanda', - 'Africa/Lubumbashi' => 'Africa/Lubumbashi', - 'Africa/Lusaka' => 'Africa/Lusaka', - 'Africa/Malabo' => 'Africa/Malabo', - 'Africa/Maputo' => 'Africa/Maputo', - 'Africa/Maseru' => 'Africa/Maseru', - 'Africa/Mbabane' => 'Africa/Mbabane', - 'Africa/Mogadishu' => 'Africa/Mogadishu', - 'Africa/Monrovia' => 'Africa/Monrovia', - 'Africa/Nairobi' => 'Africa/Nairobi', - 'Africa/Ndjamena' => 'Africa/Ndjamena', - 'Africa/Niamey' => 'Africa/Niamey', - 'Africa/Nouakchott' => 'Africa/Nouakchott', - 'Africa/Ouagadougou' => 'Africa/Ouagadougou', - 'Africa/Porto-Novo' => 'Africa/Porto-Novo', - 'Africa/Sao_Tome' => 'Africa/Sao Tome', - 'Africa/Tripoli' => 'Africa/Tripoli', - 'Africa/Tunis' => 'Africa/Tunis', - 'Africa/Windhoek' => 'Africa/Windhoek', - - 'America/Adak' => 'America/Adak', - 'America/Anchorage' => 'America/Anchorage', - 'America/Anguilla' => 'America/Anguilla', - 'America/Antigua' => 'America/Antigua', - 'America/Araguaina' => 'America/Araguaina', - - 'America/Argentina/Buenos_Aires' => 'America/Argentina/Buenos Aires', - 'America/Argentina/Catamarca' => 'America/Argentina/Catamarca', - 'America/Argentina/Cordoba' => 'America/Argentina/Cordoba', - 'America/Argentina/Jujuy' => 'America/Argentina/Jujuy', - 'America/Argentina/La_Rioja' => 'America/Argentina/La Rioja', - 'America/Argentina/Mendoza' => 'America/Argentina/Mendoza', - 'America/Argentina/Rio_Gallegos' => 'America/Argentina/Rio Gallegos', - 'America/Argentina/Salta' => 'America/Argentina/Salta', - 'America/Argentina/San_Juan' => 'America/Argentina/San Juan', - 'America/Argentina/San_Luis' => 'America/Argentina/San Luis', - 'America/Argentina/Tucuman' => 'America/Argentina/Tucuman', - 'America/Argentina/Ushuaia' => 'America/Argentina/Ushuaia', - - 'America/Aruba' => 'America/Aruba', - 'America/Asuncion' => 'America/Asuncion', - 'America/Atikokan' => 'America/Atikokan', - 'America/Bahia' => 'America/Bahia', - 'America/Bahia_Banderas' => 'America/Bahia Banderas', - 'America/Barbados' => 'America/Barbados', - 'America/Belem' => 'America/Belem', - 'America/Belize' => 'America/Belize', - 'America/Blanc-Sablon' => 'America/Blanc-Sablon', - 'America/Boa_Vista' => 'America/Boa Vista', - 'America/Bogota' => 'America/Bogota', - 'America/Boise' => 'America/Boise', - 'America/Cambridge_Bay' => 'America/Cambridge Bay', - 'America/Campo_Grande' => 'America/Campo Grande', - 'America/Cancun' => 'America/Cancun', - 'America/Caracas' => 'America/Caracas', - 'America/Cayenne' => 'America/Cayenne', - 'America/Cayman' => 'America/Cayman', - 'America/Chicago' => 'America/Chicago', - 'America/Chihuahua' => 'America/Chihuahua', - 'America/Costa_Rica' => 'America/Costa Rica', - 'America/Creston' => 'America/Creston', - 'America/Cuiaba' => 'America/Cuiaba', - 'America/Curacao' => 'America/Curacao', - 'America/Danmarkshavn' => 'America/Danmarkshavn', - 'America/Dawson' => 'America/Dawson', - 'America/Dawson_Creek' => 'America/Dawson Creek', - 'America/Denver' => 'America/Denver', - 'America/Detroit' => 'America/Detroit', - 'America/Dominica' => 'America/Dominica', - 'America/Edmonton' => 'America/Edmonton', - 'America/Eirunepe' => 'America/Eirunepe', - 'America/El_Salvador' => 'America/El Salvador', - 'America/Fortaleza' => 'America/Fortaleza', - 'America/Glace_Bay' => 'America/Glace Bay', - 'America/Godthab' => 'America/Godthab', - 'America/Goose_Bay' => 'America/Goose Bay', - 'America/Grand_Turk' => 'America/Grand Turk', - 'America/Grenada' => 'America/Grenada', - 'America/Guadeloupe' => 'America/Guadeloupe', - 'America/Guatemala' => 'America/Guatemala', - 'America/Guayaquil' => 'America/Guayaquil', - 'America/Guyana' => 'America/Guyana', - 'America/Halifax' => 'America/Halifax', - 'America/Havana' => 'America/Havana', - 'America/Hermosillo' => 'America/Hermosillo', - 'America/Indiana/Indianapolis' => 'America/Indiana/Indianapolis', - 'America/Indiana/Knox' => 'America/Indiana/Knox', - 'America/Indiana/Marengo' => 'America/Indiana/Marengo', - 'America/Indiana/Petersburg' => 'America/Indiana/Petersburg', - 'America/Indiana/Tell_City' => 'America/Indiana/Tell City', - 'America/Indiana/Vevay' => 'America/Indiana/Vevay', - 'America/Indiana/Vincennes' => 'America/Indiana/Vincennes', - 'America/Indiana/Winamac' => 'America/Indiana/Winamac', - 'America/Inuvik' => 'America/Inuvik', - 'America/Iqaluit' => 'America/Iqaluit', - 'America/Jamaica' => 'America/Jamaica', - 'America/Juneau' => 'America/Juneau', - 'America/Kentucky/Louisville' => 'America/Kentucky/Louisville', - 'America/Kentucky/Monticello' => 'America/Kentucky/Monticello', - 'America/Kralendijk' => 'America/Kralendijk', - 'America/La_Paz' => 'America/La Paz', - 'America/Lima' => 'America/Lima', - 'America/Los_Angeles' => 'America/Los Angeles', - 'America/Lower_Princes' => 'America/Lower Princes', - 'America/Maceio' => 'America/Maceio', - 'America/Managua' => 'America/Managua', - 'America/Manaus' => 'America/Manaus', - 'America/Marigot' => 'America/Marigot', - 'America/Martinique' => 'America/Martinique', - 'America/Matamoros' => 'America/Matamoros', - 'America/Mazatlan' => 'America/Mazatlan', - 'America/Menominee' => 'America/Menominee', - 'America/Merida' => 'America/Merida', - 'America/Metlakatla' => 'America/Metlakatla', - 'America/Mexico_City' => 'America/Mexico City', - 'America/Miquelon' => 'America/Miquelon', - 'America/Moncton' => 'America/Moncton', - 'America/Monterrey' => 'America/Monterrey', - 'America/Montevideo' => 'America/Montevideo', - 'America/Montreal' => 'America/Montreal', - 'America/Montserrat' => 'America/Montserrat', - 'America/Nassau' => 'America/Nassau', - 'America/New_York' => 'America/New York', - 'America/Nipigon' => 'America/Nipigon', - 'America/Nome' => 'America/Nome', - 'America/Noronha' => 'America/Noronha', - 'America/North_Dakota/Beulah' => 'America/North Dakota/Beulah', - 'America/North_Dakota/Center' => 'America/North Dakota/Center', - 'America/North_Dakota/New_Salem' => 'America/North Dakota/New Salem', - 'America/Ojinaga' => 'America/Ojinaga', - 'America/Panama' => 'America/Panama', - 'America/Pangnirtung' => 'America/Pangnirtung', - 'America/Paramaribo' => 'America/Paramaribo', - 'America/Phoenix' => 'America/Phoenix', - 'America/Port-au-Prince' => 'America/Port-au-Prince', - 'America/Port_of_Spain' => 'America/Port of Spain', - 'America/Porto_Velho' => 'America/Porto Velho', - 'America/Puerto_Rico' => 'America/Puerto Rico', - 'America/Rainy_River' => 'America/Rainy River', - 'America/Rankin_Inlet' => 'America/Rankin Inlet', - 'America/Recife' => 'America/Recife', - 'America/Regina' => 'America/Regina', - 'America/Resolute' => 'America/Resolute', - 'America/Rio_Branco' => 'America/Rio Branco', - 'America/Santa_Isabel' => 'America/Santa Isabel', - 'America/Santarem' => 'America/Santarem', - 'America/Santiago' => 'America/Santiago', - 'America/Santo_Domingo' => 'America/Santo Domingo', - 'America/Sao_Paulo' => 'America/Sao Paulo', - 'America/Scoresbysund' => 'America/Scoresbysund', - 'America/Shiprock' => 'America/Shiprock', - 'America/Sitka' => 'America/Sitka', - 'America/St_Barthelemy' => 'America/St. Barthelemy', - 'America/St_Johns' => 'America/St. Johns', - 'America/St_Kitts' => 'America/St. Kitts', - 'America/St_Lucia' => 'America/St. Lucia', - 'America/St_Thomas' => 'America/St. Thomas', - 'America/St_Vincent' => 'America/St. Vincent', - 'America/Swift_Current' => 'America/Swift Current', - 'America/Tegucigalpa' => 'America/Tegucigalpa', - 'America/Thule' => 'America/Thule', - 'America/Thunder_Bay' => 'America/Thunder Bay', - 'America/Tijuana' => 'America/Tijuana', - 'America/Toronto' => 'America/Toronto', - 'America/Tortola' => 'America/Tortola', - 'America/Vancouver' => 'America/Vancouver', - 'America/Whitehorse' => 'America/Whitehorse', - 'America/Winnipeg' => 'America/Winnipeg', - 'America/Yakutat' => 'America/Yakutat', - 'America/Yellowknife' => 'America/Yellowknife', - - 'Antarctica/Casey' => 'Antarctica/Casey', - 'Antarctica/Davis' => 'Antarctica/Davis', - 'Antarctica/DumontDUrville' => 'Antarctica/DumontDUrville', - 'Antarctica/Macquarie' => 'Antarctica/Macquarie', - 'Antarctica/Mawson' => 'Antarctica/Mawson', - 'Antarctica/McMurdo' => 'Antarctica/McMurdo', - 'Antarctica/Palmer' => 'Antarctica/Palmer', - 'Antarctica/Rothera' => 'Antarctica/Rothera', - 'Antarctica/South_Pole' => 'Antarctica/South Pole', - 'Antarctica/Syowa' => 'Antarctica/Syowa', - 'Antarctica/Vostok' => 'Antarctica/Vostok', - - 'Arctic/Longyearbyen' => 'Arctic/Longyearbyen', - - 'Asia/Aden' => 'Asia/Aden', - 'Asia/Almaty' => 'Asia/Almaty', - 'Asia/Amman' => 'Asia/Amman', - 'Asia/Anadyr' => 'Asia/Anadyr', - 'Asia/Aqtau' => 'Asia/Aqtau', - 'Asia/Aqtobe' => 'Asia/Aqtobe', - 'Asia/Ashgabat' => 'Asia/Ashgabat', - 'Asia/Baghdad' => 'Asia/Baghdad', - 'Asia/Bahrain' => 'Asia/Bahrain', - 'Asia/Baku' => 'Asia/Baku', - 'Asia/Bangkok' => 'Asia/Bangkok', - 'Asia/Beirut' => 'Asia/Beirut', - 'Asia/Bishkek' => 'Asia/Bishkek', - 'Asia/Brunei' => 'Asia/Brunei', - 'Asia/Choibalsan' => 'Asia/Choibalsan', - 'Asia/Chongqing' => 'Asia/Chongqing', - 'Asia/Colombo' => 'Asia/Colombo', - 'Asia/Damascus' => 'Asia/Damascus', - 'Asia/Dhaka' => 'Asia/Dhaka', - 'Asia/Dili' => 'Asia/Dili', - 'Asia/Dubai' => 'Asia/Dubai', - 'Asia/Dushanbe' => 'Asia/Dushanbe', - 'Asia/Gaza' => 'Asia/Gaza', - 'Asia/Harbin' => 'Asia/Harbin', - 'Asia/Hebron' => 'Asia/Hebron', - 'Asia/Ho_Chi_Minh' => 'Asia/Ho Chi Minh', - 'Asia/Hong_Kong' => 'Asia/Hong Kong', - 'Asia/Hovd' => 'Asia/Hovd', - 'Asia/Irkutsk' => 'Asia/Irkutsk', - 'Asia/Jakarta' => 'Asia/Jakarta', - 'Asia/Jayapura' => 'Asia/Jayapura', - 'Asia/Jerusalem' => 'Asia/Jerusalem', - 'Asia/Kabul' => 'Asia/Kabul', - 'Asia/Kamchatka' => 'Asia/Kamchatka', - 'Asia/Karachi' => 'Asia/Karachi', - 'Asia/Kashgar' => 'Asia/Kashgar', - 'Asia/Kathmandu' => 'Asia/Kathmandu', - 'Asia/Khandyga' => 'Asia/Khandyga', - 'Asia/Kolkata' => 'Asia/Kolkata', - 'Asia/Krasnoyarsk' => 'Asia/Krasnoyarsk', - 'Asia/Kuala_Lumpur' => 'Asia/Kuala Lumpur', - 'Asia/Kuching' => 'Asia/Kuching', - 'Asia/Kuwait' => 'Asia/Kuwait', - 'Asia/Macau' => 'Asia/Macau', - 'Asia/Magadan' => 'Asia/Magadan', - 'Asia/Makassar' => 'Asia/Makassar', - 'Asia/Manila' => 'Asia/Manila', - 'Asia/Muscat' => 'Asia/Muscat', - 'Asia/Nicosia' => 'Asia/Nicosia', - 'Asia/Novokuznetsk' => 'Asia/Novokuznetsk', - 'Asia/Novosibirsk' => 'Asia/Novosibirsk', - 'Asia/Omsk' => 'Asia/Omsk', - 'Asia/Oral' => 'Asia/Oral', - 'Asia/Phnom_Penh' => 'Asia/Phnom Penh', - 'Asia/Pontianak' => 'Asia/Pontianak', - 'Asia/Pyongyang' => 'Asia/Pyongyang', - 'Asia/Qatar' => 'Asia/Qatar', - 'Asia/Qyzylorda' => 'Asia/Qyzylorda', - 'Asia/Rangoon' => 'Asia/Rangoon', - 'Asia/Riyadh' => 'Asia/Riyadh', - 'Asia/Sakhalin' => 'Asia/Sakhalin', - 'Asia/Samarkand' => 'Asia/Samarkand', - 'Asia/Seoul' => 'Asia/Seoul', - 'Asia/Shanghai' => 'Asia/Shanghai', - 'Asia/Singapore' => 'Asia/Singapore', - 'Asia/Taipei' => 'Asia/Taipei', - 'Asia/Tashkent' => 'Asia/Tashkent', - 'Asia/Tbilisi' => 'Asia/Tbilisi', - 'Asia/Tehran' => 'Asia/Tehran', - 'Asia/Thimphu' => 'Asia/Thimphu', - 'Asia/Tokyo' => 'Asia/Tokyo', - 'Asia/Ulaanbaatar' => 'Asia/Ulaanbaatar', - 'Asia/Urumqi' => 'Asia/Urumqi', - 'Asia/Ust-Nera' => 'Asia/Ust-Nera', - 'Asia/Vientiane' => 'Asia/Vientiane', - 'Asia/Vladivostok' => 'Asia/Vladivostok', - 'Asia/Yakutsk' => 'Asia/Yakutsk', - 'Asia/Yekaterinburg' => 'Asia/Yekaterinburg', - 'Asia/Yerevan' => 'Asia/Yerevan', - - 'Atlantic/Azores' => 'Atlantic/Azores', - 'Atlantic/Bermuda' => 'Atlantic/Bermuda', - 'Atlantic/Canary' => 'Atlantic/Canary', - 'Atlantic/Cape_Verde' => 'Atlantic/Cape Verde', - 'Atlantic/Faroe' => 'Atlantic/Faroe', - 'Atlantic/Madeira' => 'Atlantic/Madeira', - 'Atlantic/Reykjavik' => 'Atlantic/Reykjavik', - 'Atlantic/South_Georgia' => 'Atlantic/South Georgia', - 'Atlantic/St_Helena' => 'Atlantic/St. Helena', - 'Atlantic/Stanley' => 'Atlantic/Stanley', - - 'Australia/Adelaide' => 'Australia/Adelaide', - 'Australia/Brisbane' => 'Australia/Brisbane', - 'Australia/Broken_Hill' => 'Australia/Broken Hill', - 'Australia/Currie' => 'Australia/Currie', - 'Australia/Darwin' => 'Australia/Darwin', - 'Australia/Eucla' => 'Australia/Eucla', - 'Australia/Hobart' => 'Australia/Hobart', - 'Australia/Lindeman' => 'Australia/Lindeman', - 'Australia/Lord_Howe' => 'Australia/Lord Howe', - 'Australia/Melbourne' => 'Australia/Melbourne', - 'Australia/Perth' => 'Australia/Perth', - 'Australia/Sydney' => 'Australia/Sydney', - - 'Europe/Amsterdam' => 'Europe/Amsterdam', - 'Europe/Andorra' => 'Europe/Andorra', - 'Europe/Athens' => 'Europe/Athens', - 'Europe/Belgrade' => 'Europe/Belgrade', - 'Europe/Berlin' => 'Europe/Berlin', - 'Europe/Bratislava' => 'Europe/Bratislava', - 'Europe/Brussels' => 'Europe/Brussels', - 'Europe/Bucharest' => 'Europe/Bucharest', - 'Europe/Budapest' => 'Europe/Budapest', - 'Europe/Busingen' => 'Europe/Busingen', - 'Europe/Chisinau' => 'Europe/Chisinau', - 'Europe/Copenhagen' => 'Europe/Copenhagen', - 'Europe/Dublin' => 'Europe/Dublin', - 'Europe/Gibraltar' => 'Europe/Gibraltar', - 'Europe/Guernsey' => 'Europe/Guernsey', - 'Europe/Helsinki' => 'Europe/Helsinki', - 'Europe/Isle_of_Man' => 'Europe/Isle of Man', - 'Europe/Istanbul' => 'Europe/Istanbul', - 'Europe/Jersey' => 'Europe/Jersey', - 'Europe/Kaliningrad' => 'Europe/Kaliningrad', - 'Europe/Kiev' => 'Europe/Kiev', - 'Europe/Lisbon' => 'Europe/Lisbon', - 'Europe/Ljubljana' => 'Europe/Ljubljana', - 'Europe/London' => 'Europe/London', - 'Europe/Luxembourg' => 'Europe/Luxembourg', - 'Europe/Madrid' => 'Europe/Madrid', - 'Europe/Malta' => 'Europe/Malta', - 'Europe/Mariehamn' => 'Europe/Mariehamn', - 'Europe/Minsk' => 'Europe/Minsk', - 'Europe/Monaco' => 'Europe/Monaco', - 'Europe/Moscow' => 'Europe/Moscow', - 'Europe/Oslo' => 'Europe/Oslo', - 'Europe/Paris' => 'Europe/Paris', - 'Europe/Podgorica' => 'Europe/Podgorica', - 'Europe/Prague' => 'Europe/Prague', - 'Europe/Riga' => 'Europe/Riga', - 'Europe/Rome' => 'Europe/Rome', - 'Europe/Samara' => 'Europe/Samara', - 'Europe/San_Marino' => 'Europe/San Marino', - 'Europe/Sarajevo' => 'Europe/Sarajevo', - 'Europe/Simferopol' => 'Europe/Simferopol', - 'Europe/Skopje' => 'Europe/Skopje', - 'Europe/Sofia' => 'Europe/Sofia', - 'Europe/Stockholm' => 'Europe/Stockholm', - 'Europe/Tallinn' => 'Europe/Tallinn', - 'Europe/Tirane' => 'Europe/Tirane', - 'Europe/Uzhgorod' => 'Europe/Uzhgorod', - 'Europe/Vaduz' => 'Europe/Vaduz', - 'Europe/Vatican' => 'Europe/Vatican', - 'Europe/Vienna' => 'Europe/Vienna', - 'Europe/Vilnius' => 'Europe/Vilnius', - 'Europe/Volgograd' => 'Europe/Volgograd', - 'Europe/Warsaw' => 'Europe/Warsaw', - 'Europe/Zagreb' => 'Europe/Zagreb', - 'Europe/Zaporozhye' => 'Europe/Zaporozhye', - 'Europe/Zurich' => 'Europe/Zurich', - - 'Indian/Antananarivo' => 'Indian/Antananarivo', - 'Indian/Chagos' => 'Indian/Chagos', - 'Indian/Christmas' => 'Indian/Christmas', - 'Indian/Cocos' => 'Indian/Cocos', - 'Indian/Comoro' => 'Indian/Comoro', - 'Indian/Kerguelen' => 'Indian/Kerguelen', - 'Indian/Mahe' => 'Indian/Mahe', - 'Indian/Maldives' => 'Indian/Maldives', - 'Indian/Mauritius' => 'Indian/Mauritius', - 'Indian/Mayotte' => 'Indian/Mayotte', - 'Indian/Reunion' => 'Indian/Reunion', - - 'Pacific/Apia' => 'Pacific/Apia', - 'Pacific/Auckland' => 'Pacific/Auckland', - 'Pacific/Chatham' => 'Pacific/Chatham', - 'Pacific/Chuuk' => 'Pacific/Chuuk', - 'Pacific/Easter' => 'Pacific/Easter', - 'Pacific/Efate' => 'Pacific/Efate', - 'Pacific/Enderbury' => 'Pacific/Enderbury', - 'Pacific/Fakaofo' => 'Pacific/Fakaofo', - 'Pacific/Fiji' => 'Pacific/Fiji', - 'Pacific/Funafuti' => 'Pacific/Funafuti', - 'Pacific/Galapagos' => 'Pacific/Galapagos', - 'Pacific/Gambier' => 'Pacific/Gambier', - 'Pacific/Guadalcanal' => 'Pacific/Guadalcanal', - 'Pacific/Guam' => 'Pacific/Guam', - 'Pacific/Honolulu' => 'Pacific/Honolulu', - 'Pacific/Johnston' => 'Pacific/Johnston', - 'Pacific/Kiritimati' => 'Pacific/Kiritimati', - 'Pacific/Kosrae' => 'Pacific/Kosrae', - 'Pacific/Kwajalein' => 'Pacific/Kwajalein', - 'Pacific/Majuro' => 'Pacific/Majuro', - 'Pacific/Marquesas' => 'Pacific/Marquesas', - 'Pacific/Midway' => 'Pacific/Midway', - 'Pacific/Nauru' => 'Pacific/Nauru', - 'Pacific/Niue' => 'Pacific/Niue', - 'Pacific/Norfolk' => 'Pacific/Norfolk', - 'Pacific/Noumea' => 'Pacific/Noumea', - 'Pacific/Pago_Pago' => 'Pacific/Pago Pago', - 'Pacific/Palau' => 'Pacific/Palau', - 'Pacific/Pitcairn' => 'Pacific/Pitcairn', - 'Pacific/Pohnpei' => 'Pacific/Pohnpei', - 'Pacific/Port_Moresby' => 'Pacific/Port Moresby', - 'Pacific/Rarotonga' => 'Pacific/Rarotonga', - 'Pacific/Saipan' => 'Pacific/Saipan', - 'Pacific/Tahiti' => 'Pacific/Tahiti', - 'Pacific/Tarawa' => 'Pacific/Tarawa', - 'Pacific/Tongatapu' => 'Pacific/Tongatapu', - 'Pacific/Wake' => 'Pacific/Wake', - 'Pacific/Wallis' => 'Pacific/Wallis', - ), - - // The value is only an example and will get replaced by the current time on view - 'dateformats' => array( - 'd M Y, H:i' => '01 Jan 2007, 13:37', - 'd M Y H:i' => '01 Jan 2007 13:37', - 'M jS, \'y, H:i' => 'Jan 1st, \'07, 13:37', - 'D M d, Y g:i a' => 'Mon Jan 01, 2007 1:37 pm', - 'F jS, Y, g:i a' => 'January 1st, 2007, 1:37 pm', - '|d M Y|, H:i' => 'Today, 13:37 / 01 Jan 2007, 13:37', - '|F jS, Y|, g:i a' => 'Today, 1:37 pm / January 1st, 2007, 1:37 pm', - ), - - // The default dateformat which will be used on new installs in this language - // Translators should change this if a the usual date format is different - 'default_dateformat' => 'D M d, Y g:i a', // Mon Jan 01, 2007 1:37 pm - -)); diff --git a/install/update/new/language/en/email/admin_activate.txt b/install/update/new/language/en/email/admin_activate.txt deleted file mode 100644 index 71faca7..0000000 --- a/install/update/new/language/en/email/admin_activate.txt +++ /dev/null @@ -1,13 +0,0 @@ -Subject: Activate user account - -Hello, - -The account owned by "{USERNAME}" has been deactivated or newly created, you should check the details of this user (if required) and handle it appropriately. - -Use this link to view the user's profile: -{U_USER_DETAILS} - -You may activate the account immediately by clicking on this link: -{U_ACTIVATE} - -{EMAIL_SIG} diff --git a/install/update/new/language/en/email/user_forgot_password.txt b/install/update/new/language/en/email/user_forgot_password.txt deleted file mode 100644 index 4826a7b..0000000 --- a/install/update/new/language/en/email/user_forgot_password.txt +++ /dev/null @@ -1,13 +0,0 @@ -Subject: Account password reset - -Hello {USERNAME} - -You are receiving this notification because you have requested to recover a forgotten password for your account on "{SITENAME}". - -To reset your password, please click the link provided below: - -{U_RESET_PASSWORD} - -If you did not authorize the request you can ignore this email. Please contact the board administrator if you keep receiving it. - -{EMAIL_SIG} diff --git a/install/update/new/language/en/install.php b/install/update/new/language/en/install.php deleted file mode 100644 index 530c003..0000000 --- a/install/update/new/language/en/install.php +++ /dev/null @@ -1,598 +0,0 @@ - - * @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(); -} - -// 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 - -// Common installer pages -$lang = array_merge($lang, array( - 'INSTALL_PANEL' => 'Installation Panel', - 'SELECT_LANG' => 'Select language', - - 'STAGE_INSTALL' => 'Installing phpBB', - - // Introduction page - 'INTRODUCTION_TITLE' => 'Introduction', - 'INTRODUCTION_BODY' => 'Welcome to phpBB3!

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.

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 the installation guide.

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.', - - // Support page - 'SUPPORT_TITLE' => 'Support', - 'SUPPORT_BODY' => 'Full support will be provided for the current stable release of phpBB3, free of charge. This includes:

  • installation
  • configuration
  • technical questions
  • problems relating to potential bugs in the software
  • updating from Release Candidate (RC) versions to the latest stable version
  • converting from phpBB 2.0.x to phpBB3
  • converting from other discussion board software to phpBB3 (please see the Convertors Forum)

We encourage users still running beta versions of phpBB3 to replace their installation with a fresh copy of the latest version.

Extensions / Styles

For issues relating to Extensions, please post in the appropriate Extensions Forum.
For issues relating to styles, templates and themes, please post in the appropriate Styles Forum.

If your question relates to a specific package, please post directly in the topic dedicated to the package.

Obtaining Support

Support Section
Quick Start Guide

To ensure you stay up to date with the latest news and releases, follow us on Twitter and Facebook

', - - // License - 'LICENSE_TITLE' => 'General Public License', - - // Install page - 'INSTALL_INTRO' => 'Welcome to Installation', - 'INSTALL_INTRO_BODY' => 'With this option, it is possible to install phpBB3 onto your server.

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

- -
    -
  • The Database Type - the database you will be using.
  • -
  • The Database server hostname or DSN - the address of the database server.
  • -
  • The Database server port - the port of the database server (most of the time this is not needed).
  • -
  • The Database name - the name of the database on the server.
  • -
  • The Database username and Database password - the login data to access the database.
  • -
- -

Note: if you are installing using SQLite, you should enter the full path to your database file in the DSN field and leave the username and password fields blank. For security reasons, you should make sure that the database file is not stored in a location accessible from the web.

- -

phpBB3 supports the following databases:

-
    -
  • MySQL 4.1.3 or above (MySQLi required)
  • -
  • PostgreSQL 8.3+
  • -
  • SQLite 3.6.15+
  • -
  • MS SQL Server 2000 or above (directly or via ODBC)
  • -
  • MS SQL Server 2005 or above (native)
  • -
  • Oracle
  • -
- -

Only those databases supported on your server will be displayed.', - - 'ACP_LINK' => 'Take me to the ACP', - - 'INSTALL_PHPBB_INSTALLED' => 'phpBB is already installed.', - 'INSTALL_PHPBB_NOT_INSTALLED' => 'phpBB is not installed yet.', -)); - -// 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 7.1.3 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', -)); - -// General error messages -$lang = array_merge($lang, array( - 'INST_ERR_MISSING_DATA' => 'You must fill out all fields in this block.', - - '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.', -)); - -// Data obtaining translations -$lang = array_merge($lang, array( - 'STAGE_OBTAIN_DATA' => 'Set installation data', - - // - // Admin data - // - 'STAGE_ADMINISTRATOR' => 'Administrator details', - - // 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.', - - // 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_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 NLS_CHARACTERSET parameter to UTF8. 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 UNICODE or UTF8 encoding. Try installing with a database in UNICODE or UTF8 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', - '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' => '

Incomplete update

- -

We noticed that the last update of your phpBB installation hasn’t been completed. Visit the database updater, ensure Update database only is selected and click on Submit. Don\'t forget to delete the "install"-directory after you have updated the database successfully.

', - - // - // Server data - // - // Form labels - 'UPGRADE_INSTRUCTIONS' => 'A new feature release %1$s is available. Please read the release announcement to learn about what it has to offer, and how to upgrade.', - 'SERVER_CONFIG' => 'Server configuration', - 'SCRIPT_PATH' => 'Script path', - 'SCRIPT_PATH_EXPLAIN' => 'The path where phpBB is located relative to the domain name, e.g. /phpBB3.', -)); - -// Default database schema entries... -$lang = array_merge($lang, array( - 'CONFIG_BOARD_EMAIL_SIG' => 'Thanks, The Management', - 'CONFIG_SITE_DESC' => 'A short text to describe your forum', - 'CONFIG_SITENAME' => 'yourdomain.com', - - 'DEFAULT_INSTALL_POST' => 'This is an example post in your phpBB3 installation. Everything seems to be working. You may delete this post if you like and continue to set up your board. During the installation process your first category and your first forum are assigned an appropriate set of permissions for the predefined usergroups administrators, bots, global moderators, guests, registered users and registered COPPA users. If you also choose to delete your first category and your first forum, do not forget to assign permissions for all these usergroups for all new categories and forums you create. It is recommended to rename your first category and your first forum and copy permissions from these while creating new categories and forums. Have fun!', - - 'FORUMS_FIRST_CATEGORY' => 'Your first category', - 'FORUMS_TEST_FORUM_DESC' => 'Description of your first forum.', - 'FORUMS_TEST_FORUM_TITLE' => 'Your first forum', - - 'RANKS_SITE_ADMIN_TITLE' => 'Site Admin', - 'REPORT_WAREZ' => 'The post contains links to illegal or pirated software.', - 'REPORT_SPAM' => 'The reported post has the only purpose to advertise for a website or another product.', - 'REPORT_OFF_TOPIC' => 'The reported post is off topic.', - 'REPORT_OTHER' => 'The reported post does not fit into any other category, please use the further information field.', - - 'SMILIES_ARROW' => 'Arrow', - 'SMILIES_CONFUSED' => 'Confused', - 'SMILIES_COOL' => 'Cool', - 'SMILIES_CRYING' => 'Crying or Very Sad', - 'SMILIES_EMARRASSED' => 'Embarrassed', - 'SMILIES_EVIL' => 'Evil or Very Mad', - 'SMILIES_EXCLAMATION' => 'Exclamation', - 'SMILIES_GEEK' => 'Geek', - 'SMILIES_IDEA' => 'Idea', - 'SMILIES_LAUGHING' => 'Laughing', - 'SMILIES_MAD' => 'Mad', - 'SMILIES_MR_GREEN' => 'Mr. Green', - 'SMILIES_NEUTRAL' => 'Neutral', - 'SMILIES_QUESTION' => 'Question', - 'SMILIES_RAZZ' => 'Razz', - 'SMILIES_ROLLING_EYES' => 'Rolling Eyes', - 'SMILIES_SAD' => 'Sad', - 'SMILIES_SHOCKED' => 'Shocked', - 'SMILIES_SMILE' => 'Smile', - 'SMILIES_SURPRISED' => 'Surprised', - 'SMILIES_TWISTED_EVIL' => 'Twisted Evil', - 'SMILIES_UBER_GEEK' => 'Uber Geek', - 'SMILIES_VERY_HAPPY' => 'Very Happy', - 'SMILIES_WINK' => 'Wink', - - '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.
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.

The file update itself can be done in two different ways.

Manual Update

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.

Automatic Update with FTP

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.

', - 'UPDATE_INSTRUCTIONS' => ' - -

Release announcement

- -

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.

- -
- -

How to update your installation with the Full Package

- -

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:

- -
    -
  1. Backup all board files and the database.
  2. -
  3. Go to the phpBB.com downloads page and download the latest "Full Package" archive.
  4. -
  5. Unpack the archive.
  6. -
  7. Remove (delete) the config.php file, and the /images, /store and /files folders from the package (not your site).
  8. -
  9. Go to the ACP, Board settings, and make sure prosilver is set as the default style. If not, set it to prosilver.
  10. -
  11. Delete the /vendor and /cache folders from the board’s root folder on the host.
  12. -
  13. 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 /ext folder when uploading the new phpBB3 contents.)
  14. -
  15. Now start the update process by pointing your browser to the install folder.
  16. -
  17. Follow the steps to update the database and let that run to completion.
  18. -
  19. Via FTP or SSH delete the /install folder from the root of your board installation.

  20. -
- -

You now have a new up to date board containing all your users and posts. Follow up tasks:

-
    -
  • Update your language pack
  • -
  • Update your style

  • -
- -

How to update your installation with the Automatic Update Package

- -

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:

- -
    -
  1. Go to the phpBB.com downloads page and download the "Automatic Update Package" archive.
  2. -
  3. Unpack the archive.
  4. -
  5. Upload the complete uncompressed "install" and "vendor" folders to your phpBB root directory (where your config.php file is).

  6. -
- -

Once uploaded your board will be offline for normal users due to the install directory you uploaded now being present.

- Now start the update process by pointing your browser to the install folder.
-
- You will then be guided through the update process. You will be notified once the update is complete. -

- ', -)); - -// 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 <<< 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.
» %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:
»%s.', - 'MAKE_FOLDERS_WRITABLE' => 'Please make sure that these folders exist and are writable by the webserver then try again:
»%s.', - - 'INSTALL_TEST' => 'Test again', - - 'NO_TABLES_FOUND' => 'No tables found.', - 'TABLES_MISSING' => 'Could not find these tables
» %s.', - '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.
» 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 %2$s.', - 'SPECIFY_OPTIONS' => 'Specify conversion options', - 'FORUM_PATH' => 'Board path', - 'FORUM_PATH_EXPLAIN' => 'This is the relative path on disk to your former board from the root of this phpBB3 installation.', - '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
» %s', - 'STARTING_CONVERT' => 'Starting conversion process', - 'CONFIG_CONVERT' => 'Converting the configuration', - 'DONE' => 'Done', - 'PREPROCESS_STEP' => 'Executing pre-processing functions/queries', - 'FILLING_TABLE' => 'Filling table %s', - 'FILLING_TABLES' => 'Filling tables', - 'DB_ERR_INSERT' => 'Error while processing INSERT query.', - 'DB_ERR_LAST' => 'Error while processing query_last.', - 'DB_ERR_QUERY_FIRST' => 'Error while executing query_first.', - 'DB_ERR_QUERY_FIRST_TABLE' => 'Error while executing query_first, %s (“%s”).', - 'DB_ERR_SELECT' => 'Error while running SELECT query.', - 'STEP_PERCENT_COMPLETED' => 'Step %d of %d', - '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 entry %1$s to %2$s.', - 'SYNC_TOPICS' => 'Starting to synchronise topics', - 'SYNC_TOPIC_ID' => 'Synchronising topics from topic_id %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

%s', - - // Finish conversion - 'CONVERT_COMPLETE' => 'Conversion completed', - 'CONVERT_COMPLETE_EXPLAIN' => 'You have now successfully converted your board to phpBB 3.3. You can now login and access your board. 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 Documentation and the support forums.', - - '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/install/update/new/language/en/migrator.php b/install/update/new/language/en/migrator.php deleted file mode 100644 index 0380254..0000000 --- a/install/update/new/language/en/migrator.php +++ /dev/null @@ -1,81 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - 'CONFIG_NOT_EXIST' => 'The config setting "%s" unexpectedly does not exist.', - - 'GROUP_NOT_EXIST' => 'The group "%s" unexpectedly does not exist.', - - 'MIGRATION_APPLY_DEPENDENCIES' => 'Apply dependencies of %s.', - 'MIGRATION_DATA_DONE' => 'Installed Data: %1$s; Time: %2$.2f seconds', - 'MIGRATION_DATA_IN_PROGRESS' => 'Installing Data: %1$s; Time: %2$.2f seconds', - 'MIGRATION_DATA_RUNNING' => 'Installing Data: %s.', - '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:

%s', - '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.', - 'MIGRATION_INVALID_DATA_UNKNOWN_TYPE' => 'A migration is invalid. An unknown migration tool type was encountered.', - 'MIGRATION_INVALID_DATA_UNDEFINED_TOOL' => 'A migration is invalid. An undefined migration tool was encountered.', - 'MIGRATION_INVALID_DATA_UNDEFINED_METHOD' => 'A migration is invalid. An undefined migration tool method was encountered.', - - 'MODULE_ERROR' => 'An error occurred while creating a module: %s', - 'MODULE_EXISTS' => 'A module already exists: %s', - 'MODULE_EXIST_MULTIPLE' => 'Several modules with the given parent module langname already exist: %s. Try using before/after keys to clarify the module placement.', - 'MODULE_INFO_FILE_NOT_EXIST' => 'A required module info file is missing: %2$s', - 'MODULE_NOT_EXIST' => 'A required module does not exist: %s', - - 'PARENT_MODULE_FIND_ERROR' => 'Unable to determine the parent module identifier: %s', - 'PERMISSION_NOT_EXIST' => 'The permission setting "%s" unexpectedly does not exist.', - - 'ROLE_NOT_EXIST' => 'The permission role "%s" unexpectedly does not exist.', -)); diff --git a/install/update/new/language/en/posting.php b/install/update/new/language/en/posting.php deleted file mode 100644 index 639b8d8..0000000 --- a/install/update/new/language/en/posting.php +++ /dev/null @@ -1,287 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - 'ADD_ATTACHMENT' => 'Upload attachment', - 'ADD_ATTACHMENT_EXPLAIN' => 'If you wish to attach one or more files enter the details below.', - 'ADD_FILE' => 'Add the file', - '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)', - - 'BBCODE_A_HELP' => 'Inline uploaded attachment: [attachment=]filename.ext[/attachment]', - 'BBCODE_B_HELP' => 'Bold text: [b]text[/b]', - 'BBCODE_C_HELP' => 'Code display: [code]code[/code]', - 'BBCODE_D_HELP' => 'Flash: [flash=width,height]http://url[/flash]', - 'BBCODE_F_HELP' => 'Font size: [size=85]small text[/size]', - 'BBCODE_IS_OFF' => '%sBBCode%s is OFF', - 'BBCODE_IS_ON' => '%sBBCode%s is ON', - 'BBCODE_I_HELP' => 'Italic text: [i]text[/i]', - 'BBCODE_L_HELP' => 'List: [list][*]text[/list]', - 'BBCODE_LISTITEM_HELP' => 'List item: [*]text', - 'BBCODE_O_HELP' => 'Ordered list: e.g. [list=1][*]First point[/list] or [list=a][*]Point a[/list]', - 'BBCODE_P_HELP' => 'Insert image: [img]http://image_url[/img]', - 'BBCODE_Q_HELP' => 'Quote text: [quote]text[/quote]', - 'BBCODE_S_HELP' => 'Font colour: [color=red]text[/color] or [color=#FF0000]text[/color]', - 'BBCODE_U_HELP' => 'Underline text: [u]text[/u]', - 'BBCODE_W_HELP' => 'Insert URL: [url]http://url[/url] or [url=http://url]URL text[/url]', - 'BBCODE_Y_HELP' => 'List: Add list element', - 'BUMP_ERROR' => 'You cannot bump this topic so soon after the last post.', - - 'CANNOT_DELETE_REPLIED' => 'Sorry but you may only delete posts which have not been replied to.', - 'CANNOT_EDIT_POST_LOCKED' => 'This post has been locked. You can no longer edit that post.', - 'CANNOT_EDIT_TIME' => 'You can no longer edit or delete that post.', - 'CANNOT_POST_ANNOUNCE' => 'Sorry but you cannot post announcements.', - 'CANNOT_POST_STICKY' => 'Sorry but you cannot post sticky topics.', - 'CHANGE_TOPIC_TO' => 'Change topic type to', - 'CHARS_POST_CONTAINS' => array( - 1 => 'Your message contains %1$d character.', - 2 => 'Your message contains %1$d characters.', - ), - 'CHARS_SIG_CONTAINS' => array( - 1 => 'Your signature contains %1$d character.', - 2 => 'Your signature contains %1$d characters.', - ), - 'CLOSE_TAGS' => 'Close tags', - 'CURRENT_TOPIC' => 'Current topic', - - 'DELETE_FILE' => 'Delete file', - 'DELETE_MESSAGE' => 'Delete message', - 'DELETE_MESSAGE_CONFIRM' => 'Are you sure you want to delete this message?', - 'DELETE_OWN_POSTS' => 'Sorry but you can only delete your own posts.', - 'DELETE_PERMANENTLY' => 'Delete permanently', - 'DELETE_POST_CONFIRM' => 'Are you sure you want to delete this post?', - 'DELETE_POST_PERMANENTLY_CONFIRM' => 'Are you sure you want to permanently delete this post?', - 'DELETE_POST_PERMANENTLY' => array( - 1 => 'Permanently delete this post so it can not be recovered', - 2 => 'Permanently delete %1$d posts so they can not be recovered', - ), - 'DELETE_POSTS_CONFIRM' => 'Are you sure you want to delete these posts?', - 'DELETE_POSTS_PERMANENTLY_CONFIRM' => 'Are you sure you want to permanently delete these posts?', - 'DELETE_REASON' => 'Reason for deletion', - 'DELETE_REASON_EXPLAIN' => 'The specified reason for deletion will be visible to moderators.', - 'DELETE_POST_WARN' => 'Delete this post', - 'DELETE_TOPIC_CONFIRM' => 'Are you sure you want to delete this topic?', - 'DELETE_TOPIC_PERMANENTLY' => array( - 1 => 'Permanently delete this topic so it can not be recovered', - 2 => 'Permanently delete %1$d topics so they can not be recovered', - ), - 'DELETE_TOPIC_PERMANENTLY_CONFIRM' => 'Are you sure you want to permanently delete this topic?', - 'DELETE_TOPICS_CONFIRM' => 'Are you sure you want to delete these topics?', - 'DELETE_TOPICS_PERMANENTLY_CONFIRM' => 'Are you sure you want to permanently delete these topics?', - 'DISABLE_BBCODE' => 'Disable BBCode', - 'DISABLE_MAGIC_URL' => 'Do not automatically parse URLs', - 'DISABLE_SMILIES' => 'Disable smilies', - 'DISALLOWED_CONTENT' => 'The upload was rejected because the uploaded file was identified as a possible attack vector.', - 'DISALLOWED_EXTENSION' => 'The extension %s is not allowed.', - 'DRAFT_LOADED' => 'Draft loaded into posting area, you may want to finish your post now.
Your draft will be deleted after submitting this post.', - 'DRAFT_LOADED_PM' => 'Draft loaded into message area, you may want to finish your private message now.
Your draft will be deleted after submitting this private message.', - 'DRAFT_SAVED' => 'Draft successfully saved.', - 'DRAFT_TITLE' => 'Draft title', - - 'EDIT_REASON' => 'Reason for editing this post', - 'EMPTY_FILEUPLOAD' => 'The uploaded file is empty.', - 'EMPTY_MESSAGE' => 'You must enter a message when posting.', - 'EMPTY_REMOTE_DATA' => 'File could not be uploaded, please try uploading the file manually.', - - 'FLASH_IS_OFF' => '[flash] is OFF', - 'FLASH_IS_ON' => '[flash] is ON', - 'FLOOD_ERROR' => 'You cannot make another post so soon after your last.', - 'FONT_COLOR' => 'Font colour', - 'FONT_COLOR_HIDE' => 'Hide font colour', - 'FONT_HUGE' => 'Huge', - 'FONT_LARGE' => 'Large', - 'FONT_NORMAL' => 'Normal', - 'FONT_SIZE' => 'Font size', - 'FONT_SMALL' => 'Small', - 'FONT_TINY' => 'Tiny', - - 'GENERAL_UPLOAD_ERROR' => 'Could not upload attachment to %s.', - - 'IMAGES_ARE_OFF' => '[img] is OFF', - 'IMAGES_ARE_ON' => '[img] is ON', - 'INVALID_FILENAME' => '%s is an invalid filename.', - - 'LOAD' => 'Load', - 'LOAD_DRAFT' => 'Load draft', - '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.', - - 'MAX_FONT_SIZE_EXCEEDED' => 'You may only use fonts up to size %d.', - 'MAX_FLASH_HEIGHT_EXCEEDED' => array( - 1 => 'Your flash files may only be up to %d pixel high.', - 2 => 'Your flash files may only be up to %d pixels high.', - ), - 'MAX_FLASH_WIDTH_EXCEEDED' => array( - 1 => 'Your flash files may only be up to %d pixel wide.', - 2 => 'Your flash files may only be up to %d pixels wide.', - ), - 'MAX_IMG_HEIGHT_EXCEEDED' => array( - 1 => 'Your images may only be up to %1$d pixel high.', - 2 => 'Your images may only be up to %1$d pixels high.', - ), - 'MAX_IMG_WIDTH_EXCEEDED' => array( - 1 => 'Your images may only be up to %d pixel wide.', - 2 => 'Your images may only be up to %d pixels wide.', - ), - - 'MESSAGE_BODY_EXPLAIN' => array( - 0 => '', // zero means no limit, so we don't view a message here. - 1 => 'Enter your message here, it may contain no more than %d character.', - 2 => 'Enter your message here, it may contain no more than %d characters.', - ), - 'MESSAGE_DELETED' => 'This message has been deleted successfully.', - 'MORE_SMILIES' => 'View more smilies', - - 'NOTIFY_REPLY' => 'Notify me when a reply is posted', - 'NOT_UPLOADED' => 'File could not be uploaded.', - 'NO_DELETE_POLL_OPTIONS' => 'You cannot delete existing poll options.', - 'NO_PM_ICON' => 'No PM icon', - '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.
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.
Please note this is set in php.ini and cannot be overridden.', - 'PLACE_INLINE' => 'Place inline', - 'POLL_DELETE' => 'Delete poll', - 'POLL_FOR' => 'Run poll for', - 'POLL_FOR_EXPLAIN' => 'Enter 0 for a never ending poll.', - 'POLL_MAX_OPTIONS' => 'Options per user', - 'POLL_MAX_OPTIONS_EXPLAIN' => 'This is the number of options each user may select when voting.', - 'POLL_OPTIONS' => 'Poll options', - 'POLL_OPTIONS_EXPLAIN' => array( - 1 => 'Place each option on a new line. You may enter %d option.', - 2 => 'Place each option on a new line. You may enter up to %d options.', - ), - 'POLL_OPTIONS_EDIT_EXPLAIN' => array( - 1 => 'Place each option on a new line. You may enter %d option. If you remove or add options all previous votes will be reset.', - 2 => 'Place each option on a new line. You may enter up to %d options. If you remove or add options all previous votes will be reset.', - ), - 'POLL_QUESTION' => 'Poll question', - '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.', - 'POLL_VOTE_CHANGE' => 'Allow re-voting', - 'POLL_VOTE_CHANGE_EXPLAIN' => 'If enabled users are able to change their vote.', - 'POSTED_ATTACHMENTS' => 'Posted attachments', - 'POST_APPROVAL_NOTIFY' => 'You will be notified when your post has been approved.', - 'POST_CONFIRMATION' => 'Confirmation of post', - 'POST_CONFIRM_EXPLAIN' => 'To prevent automated posts the board requires you to enter a confirmation code. The code is displayed in the image you should see below. If you are visually impaired or cannot otherwise read this code please contact the %sBoard Administrator%s.', - 'POST_DELETED' => 'This post has been deleted successfully.', - 'POST_EDITED' => 'This post has been edited successfully.', - 'POST_EDITED_MOD' => 'This post has been edited successfully, but it will need to be approved by a moderator before it is publicly viewable.', - 'POST_GLOBAL' => 'Global', - 'POST_ICON' => 'Post icon', - 'POST_NORMAL' => 'Normal', - 'POST_REVIEW' => 'Post review', - 'POST_REVIEW_EDIT' => 'Post review', - 'POST_REVIEW_EDIT_EXPLAIN' => 'This post has been altered by another user while you were editing it. You may wish to review the current version of this post and adjust your edits.', - 'POST_REVIEW_EXPLAIN' => 'At least one new post has been made to this topic. You may wish to review your post in light of this.', - 'POST_STORED' => 'This message has been posted successfully.', - 'POST_STORED_MOD' => 'This message has been submitted successfully, but it will need to be approved by a moderator before it is publicly viewable.', - 'POST_TOPIC_AS' => 'Post topic as', - 'PROGRESS_BAR' => 'Progress bar', - - 'QUOTE_DEPTH_EXCEEDED' => array( - 1 => 'You may embed only %d quote within each other.', - 2 => 'You may embed only %d quotes within each other.', - ), - 'QUOTE_NO_NESTING' => 'You may not embed quotes within each other.', - - 'REMOTE_UPLOAD_TIMEOUT' => 'The specified file could not be uploaded because the request timed out.', - 'SAVE' => 'Save', - 'SAVE_DATE' => 'Saved at', - 'SAVE_DRAFT' => 'Save draft', - 'SAVE_DRAFT_CONFIRM' => 'Please note that saved drafts only include the subject and the message, any other element will be removed. Do you want to save your draft now?', - 'SMILIES' => 'Smilies', - 'SMILIES_ARE_OFF' => 'Smilies are OFF', - 'SMILIES_ARE_ON' => 'Smilies are ON', - '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/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.', - 'TOO_FEW_CHARS_LIMIT' => array( - 1 => 'You need to enter at least %1$d character.', - 2 => 'You need to enter at least %1$d characters.', - ), - 'TOO_FEW_POLL_OPTIONS' => 'You must enter at least two poll options.', - 'TOO_MANY_ATTACHMENTS' => 'Cannot add another attachment, %d is the maximum.', - 'TOO_MANY_CHARS' => 'Your message contains too many characters.', - 'TOO_MANY_CHARS_LIMIT' => array( - 2 => 'The maximum number of allowed characters is %1$d.', - ), - 'TOO_MANY_POLL_OPTIONS' => 'You have tried to enter too many poll options.', - 'TOO_MANY_SMILIES' => 'Your message contains too many smilies. The maximum number of smilies allowed is %d.', - 'TOO_MANY_URLS' => 'Your message contains too many URLs. The maximum number of URLs allowed is %d.', - 'TOO_MANY_USER_OPTIONS' => 'You cannot specify more options per user than existing poll options.', - 'TOPIC_BUMPED' => 'Topic has been bumped successfully.', - - 'UNAUTHORISED_BBCODE' => 'You cannot use certain BBCodes: %s.', - 'UNSUPPORTED_CHARACTERS_MESSAGE' => 'Your message contains the following unsupported characters:
%s', - 'UNSUPPORTED_CHARACTERS_SUBJECT' => 'Your subject contains the following unsupported characters:
%s', - 'UPDATE_COMMENT' => 'Update comment', - 'URL_INVALID' => 'The URL you specified is invalid.', - 'URL_NOT_FOUND' => 'The file specified could not be found.', - 'URL_IS_OFF' => '[url] is OFF', - 'URL_IS_ON' => '[url] is ON', - 'USER_CANNOT_BUMP' => 'You cannot bump topics in this forum.', - 'USER_CANNOT_DELETE' => 'You cannot delete posts in this forum.', - 'USER_CANNOT_EDIT' => 'You cannot edit posts in this forum.', - 'USER_CANNOT_REPLY' => 'You cannot reply in this forum.', - 'USER_CANNOT_FORUM_POST' => 'You are not able to do posting operations on this forum due to the forum type not supporting it.', - - 'VIEW_MESSAGE' => '%sView your submitted message%s', - 'VIEW_PRIVATE_MESSAGE' => '%sView your submitted private message%s', - - 'WRONG_FILESIZE' => 'The file is too big, maximum allowed size is %1$d %2$s.', - 'WRONG_SIZE' => 'The image must be at least %1$s wide, %2$s high and at most %3$s wide and %4$s high. The submitted image is %5$s wide and %6$s high.', -)); diff --git a/install/update/new/language/en/ucp.php b/install/update/new/language/en/ucp.php deleted file mode 100644 index 57319ae..0000000 --- a/install/update/new/language/en/ucp.php +++ /dev/null @@ -1,666 +0,0 @@ - -* @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(); -} - -// 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 - -// Privacy policy and T&C -$lang = array_merge($lang, array( - 'TERMS_OF_USE_CONTENT' => 'By accessing “%1$s” (hereinafter “we”, “us”, “our”, “%1$s”, “%2$s”), you agree to be legally bound by the following terms. If you do not agree to be legally bound by all of the following terms then please do not access and/or use “%1$s”. We may change these at any time and we’ll do our utmost in informing you, though it would be prudent to review this regularly yourself as your continued usage of “%1$s” after changes mean you agree to be legally bound by these terms as they are updated and/or amended.
-
- Our forums are powered by phpBB (hereinafter “they”, “them”, “their”, “phpBB software”, “www.phpbb.com”, “phpBB Limited”, “phpBB Teams”) which is a bulletin board solution released under the “GNU General Public License v2” (hereinafter “GPL”) and can be downloaded from www.phpbb.com. The phpBB software only facilitates internet based discussions; phpBB Limited is not responsible for what we allow and/or disallow as permissible content and/or conduct. For further information about phpBB, please see: https://www.phpbb.com/.
-
- You agree not to post any abusive, obscene, vulgar, slanderous, hateful, threatening, sexually-orientated or any other material that may violate any laws be it of your country, the country where “%1$s” is hosted or International Law. Doing so may lead to you being immediately and permanently banned, with notification of your Internet Service Provider if deemed required by us. The IP address of all posts are recorded to aid in enforcing these conditions. You agree that “%1$s” have the right to remove, edit, move or close any topic at any time should we see fit. As a user you agree to any information you have entered to being stored in a database. While this information will not be disclosed to any third party without your consent, neither “%1$s” nor phpBB shall be held responsible for any hacking attempt that may lead to the data being compromised. - ', - - 'PRIVACY_POLICY' => 'This policy explains in detail how “%1$s” along with its affiliated companies (hereinafter “we”, “us”, “our”, “%1$s”, “%2$s”) and phpBB (hereinafter “they”, “them”, “their”, “phpBB software”, “www.phpbb.com”, “phpBB Limited”, “phpBB Teams”) use any information collected during any session of usage by you (hereinafter “your information”).
-
- Your information is collected via two ways. Firstly, by browsing “%1$s” will cause the phpBB software to create a number of cookies, which are small text files that are downloaded on to your computer’s web browser temporary files. The first two cookies just contain a user identifier (hereinafter “user-id”) and an anonymous session identifier (hereinafter “session-id”), automatically assigned to you by the phpBB software. A third cookie will be created once you have browsed topics within “%1$s” and is used to store which topics have been read, thereby improving your user experience.
-
- We may also create cookies external to the phpBB software whilst browsing “%1$s”, though these are outside the scope of this document which is intended to only cover the pages created by the phpBB software. The second way in which we collect your information is by what you submit to us. This can be, and is not limited to: posting as an anonymous user (hereinafter “anonymous posts”), registering on “%1$s” (hereinafter “your account”) and posts submitted by you after registration and whilst logged in (hereinafter “your posts”).
-
- Your account will at a bare minimum contain a uniquely identifiable name (hereinafter “your user name”), a personal password used for logging into your account (hereinafter “your password”) and a personal, valid email address (hereinafter “your email”). Your information for your account at “%1$s” is protected by data-protection laws applicable in the country that hosts us. Any information beyond your user name, your password, and your email address required by “%1$s” during the registration process is either mandatory or optional, at the discretion of “%1$s”. In all cases, you have the option of what information in your account is publicly displayed. Furthermore, within your account, you have the option to opt-in or opt-out of automatically generated emails from the phpBB software.
-
- Your password is ciphered (a one-way hash) so that it is secure. However, it is recommended that you do not reuse the same password across a number of different websites. Your password is the means of accessing your account at “%1$s”, so please guard it carefully and under no circumstance will anyone affiliated with “%1$s”, phpBB or another 3rd party, legitimately ask you for your password. Should you forget your password for your account, you can use the “I forgot my password” feature provided by the phpBB software. This process will ask you to submit your user name and your email, then the phpBB software will generate a new password to reclaim your account.
- ', -)); - -// Common language entries -$lang = array_merge($lang, array( - 'ACCOUNT_ACTIVE' => 'Your account has now been activated. Thank you for registering.', - 'ACCOUNT_ACTIVE_ADMIN' => 'The account has now been activated.', - 'ACCOUNT_ACTIVE_PROFILE' => 'Your account has now been successfully reactivated.', - 'ACCOUNT_ADDED' => 'Thank you for registering, your account has been created.', - 'ACCOUNT_COPPA' => 'Your account has been created but has to be approved, please check your email for details.', - 'ACCOUNT_EMAIL_CHANGED' => 'Your account has been updated. However, this board requires account reactivation on email changes. An activation key has been sent to the new email address you provided. Please check your email for further information.', - 'ACCOUNT_EMAIL_CHANGED_ADMIN' => 'Your account has been updated. However, this board requires account reactivation by the administrators on email changes. An email has been sent to them and you will be informed when your account has been reactivated.', - 'ACCOUNT_INACTIVE' => 'Your account has been created. However, this board requires account activation. An activation key has been sent to the email address you provided. Please check your email for further information and also be sure to check your junk mail box. It may take a while to get the email depending on your email provider.', - 'ACCOUNT_INACTIVE_ADMIN' => 'Your account has been created. However, this board requires account activation by the administrator group. An email has been sent to them and you will be informed when your account has been activated.', - 'ACTIVATION_EMAIL_SENT' => 'The activation email has been sent to your email address.', - 'ACTIVATION_EMAIL_SENT_ADMIN' => 'The activation email has been sent to the administrators email addresses.', - 'ADD' => 'Add', - 'ADD_BCC' => 'Add [BCC]', - 'ADD_FOES' => 'Add new foes', - 'ADD_FOES_EXPLAIN' => 'You may enter several usernames each on a different line.', - 'ADD_FOLDER' => 'Add folder', - 'ADD_FRIENDS' => 'Add new friends', - 'ADD_FRIENDS_EXPLAIN' => 'You may enter several usernames each on a different line.', - 'ADD_NEW_RULE' => 'Add new rule', - 'ADD_RULE' => 'Add rule', - 'ADD_TO' => 'Add [To]', - 'ADD_USERS_UCP_EXPLAIN' => 'Here you can add new users to the group. You may select whether this group becomes the new default for the selected users. Please enter each username on a separate line.', - 'ADMIN_EMAIL' => 'Administrators can email me information', - 'AGREE' => 'I agree to these terms', - 'ALLOW_PM' => 'Allow users to send you private messages', - 'ALLOW_PM_EXPLAIN' => 'Note that administrators and moderators will always be able to send you messages.', - 'ALREADY_ACTIVATED' => 'You have already activated your account.', - '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', - 'AVATAR_DRIVER_GRAVATAR_EXPLAIN'=> 'Gravatar is a service that allows you to maintain the same avatar across multiple websites. Visit Gravatar for more information.', - 'AVATAR_DRIVER_LOCAL_TITLE' => 'Gallery avatar', - 'AVATAR_DRIVER_LOCAL_EXPLAIN' => 'You can choose your avatar from a locally available set of avatars.', - 'AVATAR_DRIVER_REMOTE_TITLE' => 'Remote avatar', - 'AVATAR_DRIVER_REMOTE_EXPLAIN' => 'Link to avatar images from another website.', - 'AVATAR_DRIVER_UPLOAD_TITLE' => 'Upload avatar', - 'AVATAR_DRIVER_UPLOAD_EXPLAIN' => 'Upload your own custom avatar.', - 'AVATAR_EXPLAIN' => 'Maximum dimensions; width: %1$s, height: %2$s, file size: %3$.2f KiB.', - 'AVATAR_EXPLAIN_NO_FILESIZE' => 'Maximum dimensions; width: %1$s, height: %2$s.', - 'AVATAR_FEATURES_DISABLED' => 'The avatar functionality is currently disabled.', - 'AVATAR_GALLERY' => 'Local gallery', - 'AVATAR_GENERAL_UPLOAD_ERROR' => 'Could not upload avatar to %s.', - 'AVATAR_NOT_ALLOWED' => 'Your avatar cannot be displayed because avatars have been disallowed.', - 'AVATAR_PAGE' => 'Page', - 'AVATAR_SELECT' => 'Select your avatar', - 'AVATAR_TYPE' => 'Avatar type', - 'AVATAR_TYPE_NOT_ALLOWED' => 'Your current avatar cannot be displayed because its type has been disallowed.', - - 'BACK_TO_DRAFTS' => 'Back to saved drafts', - 'BACK_TO_LOGIN' => 'Back to login screen', - '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 date() function.', - 'BOARD_LANGUAGE' => 'My language', - 'BOARD_STYLE' => 'My board style', - 'BOARD_TIMEZONE' => 'My timezone', - 'BOOKMARKS' => 'Bookmarks', - 'BOOKMARKS_EXPLAIN' => 'You can bookmark topics for future reference. Select the checkbox for any bookmark you wish to delete, then press the Remove marked bookmarks button.', - 'BOOKMARKS_DISABLED' => 'Bookmarks are disabled on this board.', - 'BOOKMARKS_REMOVED' => 'Bookmarks removed successfully.', - - 'CANNOT_EDIT_MESSAGE_TIME' => 'You can no longer edit or delete that message.', - 'CANNOT_MOVE_TO_SAME_FOLDER'=> 'Messages cannot be moved to the folder you want to remove.', - 'CANNOT_MOVE_FROM_SPECIAL' => 'Messages cannot be moved from the outbox.', - 'CANNOT_RENAME_FOLDER' => 'This folder cannot be renamed.', - 'CANNOT_REMOVE_FOLDER' => 'This folder cannot be removed.', - 'CHANGE_DEFAULT_GROUP' => 'Change default group', - 'CHANGE_PASSWORD' => 'Change password', - 'CLICK_GOTO_FOLDER' => '%1$sGo to your “%3$s” folder%2$s', - 'CLICK_RETURN_FOLDER' => '%1$sReturn to your “%3$s” folder%2$s', - 'CONFIRMATION' => 'Confirmation of registration', - 'CONFIRM_CHANGES' => 'Confirm changes', - 'CONFIRM_EXPLAIN' => 'To prevent automated registrations the board requires you to enter a confirmation code. The code is displayed in the image you should see below. If you are visually impaired or cannot otherwise read this code please contact the %sBoard Administrator%s.', - 'VC_REFRESH' => 'Refresh confirmation code', - 'VC_REFRESH_EXPLAIN' => 'If you cannot read the code you can request a new one by clicking the button.', - - 'CONFIRM_PASSWORD' => 'Confirm password', - 'CONFIRM_PASSWORD_EXPLAIN' => 'You only need to confirm your password if you changed it above.', - 'COPPA_BIRTHDAY' => 'To continue with the registration procedure please tell us when you were born.', - 'COPPA_COMPLIANCE' => 'COPPA compliance', - 'COPPA_EXPLAIN' => 'Please note that clicking submit will create your account. However it cannot be activated until a parent or guardian approves your registration. You will be emailed a copy of the necessary form with details of where to send it.', - 'CREATE_FOLDER' => 'Add folder…', - 'CURRENT_IMAGE' => 'Current image', - 'CURRENT_PASSWORD' => 'Current password', - 'CURRENT_PASSWORD_EXPLAIN' => 'You must enter your current password if you wish to alter your email address or username.', - 'CURRENT_CHANGE_PASSWORD_EXPLAIN' => 'To change your password, your email address, or your username, you must enter your current password.', - 'CUR_PASSWORD_EMPTY' => 'You did not enter your current password.', - 'CUR_PASSWORD_ERROR' => 'The current password you entered is incorrect.', - 'CUSTOM_DATEFORMAT' => 'Custom…', - - 'DEFAULT_ACTION' => 'Default action', - 'DEFAULT_ACTION_EXPLAIN' => 'This action will be triggered if none of the above is applicable.', - 'DEFAULT_ADD_SIG' => 'Attach my signature by default', - 'DEFAULT_BBCODE' => 'Enable BBCode by default', - 'DEFAULT_NOTIFY' => 'Notify me upon replies by default', - 'DEFAULT_SMILIES' => 'Enable smilies by default', - 'DEFINED_RULES' => 'Defined rules', - 'DELETED_TOPIC' => 'Topic has been removed.', - 'DELETE_ATTACHMENT' => 'Delete attachment', - 'DELETE_ATTACHMENTS' => 'Delete attachments', - 'DELETE_ATTACHMENT_CONFIRM' => 'Are you sure you want to delete this attachment?', - 'DELETE_ATTACHMENTS_CONFIRM'=> 'Are you sure you want to delete these attachments?', - 'DELETE_AVATAR' => 'Delete image', - 'DELETE_COOKIES_CONFIRM' => 'Are you sure you want to delete all cookies set by this board?', - 'DELETE_MARKED_PM' => 'Delete marked messages', - 'DELETE_MARKED_PM_CONFIRM' => 'Are you sure you want to delete all marked messages?', - 'DELETE_OLDEST_MESSAGES' => 'Delete oldest messages', - 'DELETE_MESSAGE' => 'Delete message', - 'DELETE_MESSAGE_CONFIRM' => 'Are you sure you want to delete this private message?', - 'DELETE_MESSAGES_IN_FOLDER' => 'Delete all messages within removed folder', - 'DELETE_RULE' => 'Delete rule', - 'DELETE_RULE_CONFIRM' => 'Are you sure you want to delete this rule?', - 'DEMOTE_SELECTED' => 'Demote selected', - 'DISABLE_CENSORS' => 'Enable word censoring', - 'DISPLAY_GALLERY' => 'Display gallery', - 'DOMAIN_NO_MX_RECORD_EMAIL' => 'The entered email domain has no valid MX record.', - 'DOWNLOADS' => 'Downloads', - 'DRAFTS_DELETED' => 'All selected drafts were successfully deleted.', - 'DRAFTS_EXPLAIN' => 'Here you can view, edit and delete your saved drafts.', - 'DRAFT_UPDATED' => 'Draft successfully updated.', - - 'EDIT_DRAFT_EXPLAIN' => 'Here you are able to edit your draft. Drafts do not contain attachment and poll information.', - 'EMAIL_BANNED_EMAIL' => 'The email address you entered is not allowed to be used.', - 'EMAIL_REMIND' => 'This must be the email address associated with your account. If you have not changed this via your user control panel then it is the email address you registered your account with.', - 'EMAIL_TAKEN_EMAIL' => 'The entered email address is already in use.', - 'EMPTY_DRAFT' => 'You must enter a message to submit your changes.', - 'EMPTY_DRAFT_TITLE' => 'You must enter a draft title.', - 'EXPORT_AS_XML' => 'Export as XML', - 'EXPORT_AS_CSV' => 'Export as CSV', - 'EXPORT_AS_CSV_EXCEL' => 'Export as CSV (Excel)', - 'EXPORT_AS_TXT' => 'Export as TXT', - 'EXPORT_AS_MSG' => 'Export as MSG', - 'EXPORT_FOLDER' => 'Export this view', - - 'FIELD_REQUIRED' => 'The field “%s” must be completed.', - 'FIELD_TOO_SHORT' => array( - 1 => 'The field “%2$s” is too short, a minimum of %1$d character is required.', - 2 => 'The field “%2$s” is too short, a minimum of %1$d characters is required.', - ), - 'FIELD_TOO_LONG' => array( - 1 => 'The field “%2$s” is too long, a maximum of %1$d character is allowed.', - 2 => 'The field “%2$s” is too long, a maximum of %1$d characters is allowed.', - ), - 'FIELD_TOO_SMALL' => 'The value of “%2$s” is too small, a minimum value of %1$d is required.', - 'FIELD_TOO_LARGE' => 'The value of “%2$s” is too large, a maximum value of %1$d is allowed.', - 'FIELD_INVALID_CHARS_INVALID' => 'The field “%s” has invalid characters.', - 'FIELD_INVALID_CHARS_NUMBERS_ONLY' => 'The field “%s” has invalid characters, only numbers are allowed.', - 'FIELD_INVALID_CHARS_ALPHA_DOTS' => 'The field “%s” has invalid characters, only alphanumeric or . characters are allowed.', - 'FIELD_INVALID_CHARS_ALPHA_ONLY' => 'The field “%s” has invalid characters, only alphanumeric characters are allowed.', - 'FIELD_INVALID_CHARS_ALPHA_PUNCTUATION' => 'The field “%s” has invalid characters, only alphanumeric or _,-. characters are allowed and the first character must be alphabetic.', - 'FIELD_INVALID_CHARS_ALPHA_SPACERS' => 'The field “%s” has invalid characters, only alphanumeric, space or -+_[] characters are allowed.', - 'FIELD_INVALID_CHARS_ALPHA_UNDERSCORE' => 'The field “%s” has invalid characters, only alphanumeric or _ characters are allowed.', - 'FIELD_INVALID_CHARS_LETTER_NUM_DOTS' => 'The field “%s” has invalid characters, only letter, number or . characters are allowed.', - 'FIELD_INVALID_CHARS_LETTER_NUM_ONLY' => 'The field “%s” has invalid characters, only letter and number characters are allowed.', - 'FIELD_INVALID_CHARS_LETTER_NUM_PUNCTUATION' => 'The field “%s” has invalid characters, only letter, number or _,-. characters are allowed and the first character must be alphabetic.', - 'FIELD_INVALID_CHARS_LETTER_NUM_SPACERS' => 'The field “%s” has invalid characters, only letter, number, space or -+_[] characters are allowed.', - 'FIELD_INVALID_CHARS_LETTER_NUM_UNDERSCORE' => 'The field “%s” has invalid characters, only letter, number or _ characters are allowed.', - 'FIELD_INVALID_DATE' => 'The field “%s” has an invalid date.', - 'FIELD_INVALID_URL' => 'The field “%s” has an invalid url.', - 'FIELD_INVALID_VALUE' => 'The field “%s” has an invalid value.', - - 'FOE_MESSAGE' => 'Message from foe', - 'FOES_EXPLAIN' => 'Foes are users which will be ignored by default. Posts by these users will not be fully visible. Personal messages from foes are still permitted. Please note that you cannot ignore moderators or administrators.', - 'FOES_UPDATED' => 'Your foes list has been updated successfully.', - 'FOLDER_ADDED' => 'Folder successfully added.', - 'FOLDER_MESSAGE_STATUS' => array( - 1 => '%2$d out of %1$s stored', - 2 => '%2$d out of %1$s stored', - ), - 'FOLDER_NAME_EMPTY' => 'You must enter a name for this folder.', - 'FOLDER_NAME_EXIST' => 'Folder %s already exists.', - 'FOLDER_OPTIONS' => 'Folder options', - 'FOLDER_RENAMED' => 'Folder successfully renamed.', - 'FOLDER_REMOVED' => 'Folder successfully removed.', - 'FOLDER_STATUS_MSG' => array( - 1 => 'Folder is %3$d%% full (%2$d out of %1$s stored)', - 2 => 'Folder is %3$d%% full (%2$d out of %1$s stored)', - ), - 'FORWARD_PM' => 'Forward PM', - 'FORCE_PASSWORD_EXPLAIN' => 'Before you may continue browsing the board you are required to change your password.', - 'FRIEND_MESSAGE' => 'Message from friend', - 'FRIENDS' => 'Friends', - 'FRIENDS_EXPLAIN' => 'Friends enable you quick access to members you communicate with frequently. If the template has relevant support any posts made by a friend may be highlighted.', - 'FRIENDS_OFFLINE' => 'Offline', - 'FRIENDS_ONLINE' => 'Online', - 'FRIENDS_UPDATED' => 'Your friends list has been updated successfully.', - 'FULL_FOLDER_OPTION_CHANGED'=> 'The action to take when a folder is full has been changed successfully.', - 'FWD_ORIGINAL_MESSAGE' => '-------- Original Message --------', - 'FWD_SUBJECT' => 'Subject: %s', - 'FWD_DATE' => 'Date: %s', - 'FWD_FROM' => 'From: %s', - 'FWD_TO' => 'To: %s', - - 'GLOBAL_ANNOUNCEMENT' => 'Global announcement', - - 'GRAVATAR_AVATAR_EMAIL' => 'Gravatar email', - 'GRAVATAR_AVATAR_EMAIL_EXPLAIN' => 'Enter the email address you used for registering your account on Gravatar.', - 'GRAVATAR_AVATAR_SIZE' => 'Avatar dimensions', - 'GRAVATAR_AVATAR_SIZE_EXPLAIN' => 'Specify the width and height of the avatar, leave blank to attempt automatic verification.', - - 'HIDE_ONLINE' => 'Hide my online status', - 'HIDE_ONLINE_EXPLAIN' => 'Changing this setting won’t become effective until your next visit to the board.', - 'HOLD_NEW_MESSAGES' => 'Do not accept new messages (New messages will be held back until enough space is available)', - 'HOLD_NEW_MESSAGES_SHORT' => 'New messages will be held back', - - 'IF_FOLDER_FULL' => 'If folder is full', - '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.', - - 'JOIN_SELECTED' => 'Join selected', - - 'LANGUAGE' => 'Language', - 'LINK_REMOTE_AVATAR' => 'Link off-site', - 'LINK_REMOTE_AVATAR_EXPLAIN'=> 'Enter the URL of the location containing the avatar image you wish to link to.', - 'LINK_REMOTE_SIZE' => 'Avatar dimensions', - 'LINK_REMOTE_SIZE_EXPLAIN' => 'Specify the width and height of the avatar, leave blank to attempt automatic verification.', - 'LOGIN_EXPLAIN_UCP' => 'Please login in order to access the User Control Panel.', - 'LOGIN_LINK' => 'Link or register your account on an external service with your board account', - 'LOGIN_LINK_EXPLAIN' => 'You have attempted to login with an external service that is not yet connected to an account on this board. You must now either link this account to an existing account or create a new account.', - 'LOGIN_LINK_MISSING_DATA' => 'Data that is necessary to link your account with an external service is not available. Please restart the login process.', - 'LOGIN_LINK_NO_DATA_PROVIDED' => 'No data has been provided to this page to link an external account to a forum account. Please contact the board administrator if you continue to experience problems.', - 'LOGIN_KEY' => 'Login Key', - 'LOGIN_TIME' => 'Login Time', - 'LOGIN_REDIRECT' => 'You have been successfully logged in.', - 'LOGOUT_FAILED' => 'You were not logged out, as the request did not match your session. Please contact the board administrator if you continue to experience problems.', - 'LOGOUT_REDIRECT' => 'You have been successfully logged out.', - - 'MARK_IMPORTANT' => 'Mark/Unmark as important', - 'MARKED_MESSAGE' => 'Marked message', - 'MAX_FOLDER_REACHED' => 'Maximum number of allowed user defined folders reached.', - 'MESSAGE_BY_AUTHOR' => 'by', - 'MESSAGE_COLOURS' => 'Message colours', - 'MESSAGE_DELETED' => 'Message successfully deleted.', - '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', - 'MESSAGES_DELETED' => 'Messages successfully deleted', - 'MOVE_DELETED_MESSAGES_TO' => 'Move messages from removed folder to', - 'MOVE_DOWN' => 'Move down', - 'MOVE_MARKED_TO_FOLDER' => 'Move marked to %s', - 'MOVE_PM_ERROR' => array( - 1 => 'An error occurred while moving the messages to the new folder, only %2$d out of %1$s was moved.', - 2 => 'An error occurred while moving the messages to the new folder, only %2$d out of %1$s were moved.', - ), - 'MOVE_TO_FOLDER' => 'Move to folder', - 'MOVE_UP' => 'Move up', - - 'NEW_FOLDER_NAME' => 'New folder name', - 'NEW_PASSWORD' => 'New password', - 'NEW_PASSWORD_CONFIRM_EMPTY' => 'You did not enter a confirm password.', - 'NEW_PASSWORD_ERROR' => 'The passwords you entered do not match.', - - 'NOTIFICATIONS_MARK_ALL_READ' => 'Mark all notifications read', - 'NOTIFICATIONS_MARK_ALL_READ_CONFIRM' => 'Are you sure you want to mark all notifications read?', - 'NOTIFICATIONS_MARK_ALL_READ_SUCCESS' => 'All notifications have been marked read.', - 'NOTIFICATION_GROUP_MISCELLANEOUS' => 'Miscellaneous Notifications', - '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', - 'NOTIFICATION_TYPE_BOOKMARK' => 'Someone replies to a topic you have bookmarked', - 'NOTIFICATION_TYPE_GROUP_REQUEST' => 'Someone requests to join a group you lead', - 'NOTIFICATION_TYPE_IN_MODERATION_QUEUE' => 'A post or topic needs approval', - 'NOTIFICATION_TYPE_MODERATION_QUEUE' => 'Your topics/posts are approved or disapproved by a moderator', - 'NOTIFICATION_TYPE_PM' => 'Someone sends you a private message', - 'NOTIFICATION_TYPE_POST' => 'Someone replies to a topic to which you are subscribed', - 'NOTIFICATION_TYPE_QUOTE' => 'Someone quotes you in a post', - 'NOTIFICATION_TYPE_REPORT' => 'Someone reports a post', - 'NOTIFICATION_TYPE_TOPIC' => 'Someone creates a topic in a forum to which you are subscribed', - 'NOTIFICATION_TYPE_ADMIN_ACTIVATE_USER' => 'User requiring activation', - - 'NOTIFY_METHOD' => 'Notification method', - 'NOTIFY_METHOD_BOTH' => 'Both', - 'NOTIFY_METHOD_EMAIL' => 'Email only', - 'NOTIFY_METHOD_EXPLAIN' => 'Method for sending messages sent via this board.', - 'NOTIFY_METHOD_IM' => 'Jabber only', - 'NOTIFY_ON_PM' => 'Notify me on new private messages', - 'NOT_ADDED_FRIENDS_ANONYMOUS' => 'You cannot add the anonymous user to your friends list.', - 'NOT_ADDED_FRIENDS_BOTS' => 'You cannot add bots to your friends list.', - 'NOT_ADDED_FRIENDS_FOES' => 'You cannot add users to your friends list who are on your foes list.', - 'NOT_ADDED_FRIENDS_SELF' => 'You cannot add yourself to the friends list.', - 'NOT_ADDED_FOES_MOD_ADMIN' => 'You cannot add administrators and moderators to your foes list.', - 'NOT_ADDED_FOES_ANONYMOUS' => 'You cannot add the anonymous user to your foes list.', - 'NOT_ADDED_FOES_BOTS' => 'You cannot add bots to your foes list.', - 'NOT_ADDED_FOES_FRIENDS' => 'You cannot add users to your foes list who are on your friends list.', - 'NOT_ADDED_FOES_SELF' => 'You cannot add yourself to the foes list.', - 'NOT_AGREE' => 'I do not agree to these terms', - 'NOT_ENOUGH_SPACE_FOLDER' => 'The destination folder “%s” seems to be full. The requested action has not been taken.', - 'NOT_MOVED_MESSAGES' => array( - 1 => 'You have %d private message currently on hold because of full folder.', - 2 => 'You have %d private messages currently on hold because of full folder.', - ), - 'NO_ACTION_MODE' => 'No message action specified.', - 'NO_AUTHOR' => 'No author defined for this message', - 'NO_AVATAR' => 'No avatar selected', - 'NO_AVATAR_CATEGORY' => 'None', - - 'NO_AUTH_DELETE_MESSAGE' => 'You are not authorised to delete private messages.', - '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_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.', - - 'NO_BCC_RECIPIENT' => 'None', - 'NO_BOOKMARKS' => 'You have no bookmarks.', - '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', - 'NO_FRIENDS_ONLINE' => 'No friends online', - 'NO_GROUP_SELECTED' => 'No group specified.', - 'NO_IMPORTANT_NEWS' => 'No important announcements present.', - 'NO_MESSAGE' => 'Private message could not be found.', - 'NO_NEW_FOLDER_NAME' => 'You have to specify a new folder name.', - 'NO_NEWER_PM' => 'No newer messages.', - 'NO_OLDER_PM' => 'No older messages.', - 'NO_PASSWORD_SUPPLIED' => 'You cannot login without a password.', - 'NO_RECIPIENT' => 'No recipient defined.', - 'NO_RESET_TOKEN' => 'You did not provide a password reset token.', - 'NO_RULES_DEFINED' => 'No rules defined.', - 'NO_SAVED_DRAFTS' => 'No drafts saved.', - 'NO_TO_RECIPIENT' => 'None', - 'NO_WATCHED_FORUMS' => 'You are not subscribed to any forums.', - 'NO_WATCHED_SELECTED' => 'You have not selected any subscribed topics or forums.', - 'NO_WATCHED_TOPICS' => 'You are not subscribed to any topics.', - - 'PASS_TYPE_ALPHA_EXPLAIN' => 'Password must be at least %1$s long, must contain letters in mixed case and must contain numbers.', - 'PASS_TYPE_ANY_EXPLAIN' => 'Must be at least %1$s long.', - 'PASS_TYPE_CASE_EXPLAIN' => 'Password must be at least %1$s long and must contain letters in mixed case.', - 'PASS_TYPE_SYMBOL_EXPLAIN' => 'Password must be at least %1$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_RESET' => 'Your password has been successfully reset.', - 'PASSWORD_RESET_LINK_SENT' => 'If your account exists, a password reset link 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, you have requested multiple password resets within a short time frame, or you are not allowed to change your password. Contact an administrator if any of those reasons apply. Also, please check your spam filter.', - 'PERMISSIONS_RESTORED' => 'Successfully restored original permissions.', - 'PERMISSIONS_TRANSFERRED' => 'Successfully transferred permissions from %s, you are now able to browse the board with this user’s permissions.
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.', - 'PM_FROM' => 'From', - 'PM_FROM_REMOVED_AUTHOR' => 'This message was sent by a user no longer registered.', - 'PM_ICON' => 'PM icon', - 'PM_INBOX' => 'Inbox', - 'PM_MARK_ALL_READ' => 'Mark all messages read', - 'PM_MARK_ALL_READ_SUCCESS' => 'All private messages in this folder have been marked read', - 'PM_NO_USERS' => 'The requested users to be added do not exist.', - 'PM_OUTBOX' => 'Outbox', - 'PM_SENTBOX' => 'Sent messages', - 'PM_SUBJECT' => 'Message subject', - 'PM_TO' => 'Send to', - 'PM_TOOLS' => 'Message tools', - 'PM_USERS_REMOVED_NO_PERMISSION' => 'Some users couldn’t be added as they do not have permission to read private messages.', - 'PM_USERS_REMOVED_NO_PM' => 'Some users couldn’t be added as they have disabled private message receipt.', - 'POST_EDIT_PM' => 'Edit message', - 'POST_FORWARD_PM' => 'Forward message', - 'POST_NEW_PM' => 'Compose message', - 'POST_PM_LOCKED' => 'Private messaging is locked.', - 'POST_PM_POST' => 'Quote post', - 'POST_QUOTE_PM' => 'Quote message', - 'POST_REPLY_PM' => 'Reply to message', - 'PRINT_PM' => 'Print view', - 'PREFERENCES_UPDATED' => 'Your preferences have been updated.', - 'PROFILE_INFO_NOTICE' => 'Please note that this information may be viewable to other members. Be careful when including any personal details. Any fields marked with a * must be completed.', - 'PROFILE_UPDATED' => 'Your profile has been updated.', - 'PROFILE_AUTOLOGIN_KEYS' => 'The "Remember Me" login keys automatically log you in when you visit the board. If you logout, the remember me login key is deleted only on the computer you are using to logout. Here you can see remember login keys created on other computers you used to access this site.', - 'PROFILE_NO_AUTOLOGIN_KEYS' => 'There are no saved "Remember Me" login keys.', - - 'RECIPIENT' => 'Recipient', - 'RECIPIENTS' => 'Recipients', - 'REGISTRATION' => 'Registration', - 'OAUTH_REGISTRATION' => 'Registration using external services', - 'RELEASE_MESSAGES' => '%sRelease all on-hold messages%s… they will be re-sorted into the appropriate folder if enough space is made available.', - 'REMOVE_ADDRESS' => 'Remove address', - 'REMOVE_SELECTED_BOOKMARKS' => 'Remove selected bookmarks', - 'REMOVE_SELECTED_BOOKMARKS_CONFIRM' => 'Are you sure you want to delete all selected bookmarks?', - 'REMOVE_BOOKMARK_MARKED' => 'Remove marked bookmarks', - 'REMOVE_FOLDER' => 'Remove folder', - 'REMOVE_FOLDER_CONFIRM' => 'Are you sure you want to remove this folder?', - 'RENAME' => 'Rename', - 'RENAME_FOLDER' => 'Rename folder', - 'REPLIED_MESSAGE' => 'Replied to message', - 'REPLY_TO_ALL' => 'Reply to sender and all recipients.', - 'REPORT_PM' => 'Report private message', - 'RESET_PASSWORD' => 'Reset password', - 'RESET_TOKEN_EXPIRED_OR_INVALID' => 'The password reset token you supplied is invalid or has expired.', - 'RESIGN_SELECTED' => 'Resign selected', - 'RETURN_FOLDER' => '%1$sReturn to previous folder%2$s', - 'RETURN_UCP' => '%sReturn to the User Control Panel%s', - 'RULE_ADDED' => 'Rule successfully added.', - 'RULE_ALREADY_DEFINED' => 'This rule was defined previously.', - 'RULE_DELETED' => 'Rule successfully removed.', - 'RULE_LIMIT_REACHED' => 'You cannot add more PM rules. You have reached the maximum number of rules.', - 'RULE_NOT_DEFINED' => 'Rule not correctly specified.', - 'RULE_REMOVED_MESSAGES' => array( - 1 => '%d private message was removed due to private message filters.', - 2 => '%d private messages were removed due to private message filters.', - ), - - 'SAME_PASSWORD_ERROR' => 'The new password you entered is the same as your current password.', - 'SEARCH_YOUR_POSTS' => 'Show your posts', - 'SENT_AT' => 'Sent', // Used before dates in private messages - 'SHOW_EMAIL' => 'Users can contact me by email', - 'SIGNATURE_EXPLAIN' => 'This is a block of text that can be added to posts you make. There is a %d character limit.', - 'SIGNATURE_PREVIEW' => 'Your signature will appear like this in posts', - 'SIGNATURE_TOO_LONG' => 'Your signature is too long.', - 'SELECT_CURRENT_TIME' => 'Select current time', - 'SELECT_TIMEZONE' => 'Select timezone', - 'SORT' => 'Sort', - 'SORT_COMMENT' => 'File comment', - 'SORT_DOWNLOADS' => 'Downloads', - 'SORT_EXTENSION' => 'Extension', - 'SORT_FILENAME' => 'Filename', - 'SORT_POST_TIME' => 'Post time', - 'SORT_SIZE' => 'File size', - - 'TIMEZONE' => 'Timezone', - 'TIMEZONE_DATE_SUGGESTION' => 'Suggestion: %s', - 'TIMEZONE_INVALID' => 'The timezone you selected is invalid.', - 'TO' => 'Recipient', - 'TO_MASS' => 'Recipients', - 'TO_ADD' => 'Add recipient', - 'TO_ADD_MASS' => 'Add recipients', - 'TO_ADD_GROUPS' => 'Add groups', - 'TOO_MANY_RECIPIENTS' => 'You tried to send a private message to too many recipients.', - 'TOO_MANY_REGISTERS' => 'You have exceeded the maximum number of registration attempts for this session. Please try again later.', - - 'UCP' => 'User Control Panel', - 'UCP_ACTIVATE' => 'Activate account', - 'UCP_ADMIN_ACTIVATE' => 'Please note that you will need to enter a valid email address before your account is activated. The administrator will review your account and if approved you will receive an email at the address you specified.', - 'UCP_ATTACHMENTS' => 'Attachments', - 'UCP_AUTH_LINK' => 'External accounts', - 'UCP_AUTH_LINK_ASK' => 'You currently have no account associated with this external service. Click the button below to link your board account to an account with this external service.', - 'UCP_AUTH_LINK_ID' => 'Unique identifier', - 'UCP_AUTH_LINK_LINK' => 'Link', - 'UCP_AUTH_LINK_MANAGE' => 'Manage external account associations', - 'UCP_AUTH_LINK_NOT_SUPPORTED' => 'Linking board accounts to external services is not supported by this board’s current authentication method.', - 'UCP_AUTH_LINK_TITLE' => 'Manage your external account associations', - 'UCP_AUTH_LINK_UNLINK' => 'Unlink', - 'UCP_COPPA_BEFORE' => 'Before %s', - 'UCP_COPPA_ON_AFTER' => 'On or after %s', - 'UCP_EMAIL_ACTIVATE' => 'Please note that you will need to enter a valid email address before your account is activated. You will receive an email at the address you provide that contains an account activation link.', - 'UCP_JABBER' => 'Jabber address', - 'UCP_LOGIN_LINK' => 'Set up an external account association', - - 'UCP_MAIN' => 'Overview', - 'UCP_MAIN_ATTACHMENTS' => 'Manage attachments', - 'UCP_MAIN_BOOKMARKS' => 'Manage bookmarks', - 'UCP_MAIN_DRAFTS' => 'Manage drafts', - 'UCP_MAIN_FRONT' => 'Front page', - 'UCP_MAIN_SUBSCRIBED' => 'Manage subscriptions', - - 'UCP_NO_ATTACHMENTS' => 'You have posted no files.', - - 'UCP_NOTIFICATION_LIST' => 'Manage notifications', - 'UCP_NOTIFICATION_LIST_EXPLAIN' => 'Here you may view all past notifications.', - 'UCP_NOTIFICATION_OPTIONS' => 'Edit notification options', - 'UCP_NOTIFICATION_OPTIONS_EXPLAIN' => 'Here you can set your preferred notification methods for the board.', - - 'UCP_PREFS' => 'Board preferences', - 'UCP_PREFS_PERSONAL' => 'Edit global settings', - 'UCP_PREFS_POST' => 'Edit posting defaults', - 'UCP_PREFS_VIEW' => 'Edit display options', - - 'UCP_PM' => 'Private messages', - 'UCP_PM_COMPOSE' => 'Compose message', - 'UCP_PM_DRAFTS' => 'Manage PM drafts', - 'UCP_PM_OPTIONS' => 'Rules, folders & settings', - 'UCP_PM_UNREAD' => 'Unread messages', - 'UCP_PM_VIEW' => 'View messages', - - 'UCP_PROFILE' => 'Profile', - 'UCP_PROFILE_AVATAR' => 'Edit avatar', - 'UCP_PROFILE_PROFILE_INFO' => 'Edit profile', - 'UCP_PROFILE_REG_DETAILS' => 'Edit account settings', - 'UCP_PROFILE_SIGNATURE' => 'Edit signature', - 'UCP_PROFILE_AUTOLOGIN_KEYS'=> 'Manage “Remember Me” login keys', - - 'UCP_USERGROUPS' => 'Usergroups', - 'UCP_USERGROUPS_MEMBER' => 'Edit memberships', - 'UCP_USERGROUPS_MANAGE' => 'Manage groups', - - 'UCP_PASSWORD_RESET_DISABLED' => 'The password reset functionality has been disabled. If you need help accessing your account, please contact the %sBoard Administrator%s', - 'UCP_REGISTER_DISABLE' => 'Creating a new account is currently not possible.', - 'UCP_RESEND' => 'Send activation email', - 'UCP_WELCOME' => 'Welcome to the User Control Panel. From here you can monitor, view and update your profile, preferences, subscribed forums and topics. You can also send messages to other users (if permitted). Please ensure you read any announcements before continuing.', - 'UCP_ZEBRA' => 'Friends & Foes', - 'UCP_ZEBRA_FOES' => 'Manage foes', - 'UCP_ZEBRA_FRIENDS' => 'Manage friends', - 'UNDISCLOSED_RECIPIENT' => 'Undisclosed Recipient', - 'UNKNOWN_FOLDER' => 'Unknown folder', - 'UNWATCH_MARKED' => 'Unwatch marked', - 'UPLOAD_AVATAR_FILE' => 'Upload from your machine', - 'UPLOAD_AVATAR_URL' => 'Upload from a URL', - 'UPLOAD_AVATAR_URL_EXPLAIN' => 'Enter the URL of the location containing the image. The image will be copied to this site.', - 'USERNAME_ALPHA_ONLY_EXPLAIN' => 'Username must be between %1$s and %2$s long and use only alphanumeric characters.', - 'USERNAME_ALPHA_SPACERS_EXPLAIN'=> 'Username must be between %1$s and %2$s long and use alphanumeric, space or -+_[] characters.', - 'USERNAME_ASCII_EXPLAIN' => 'Username must be between %1$s and %2$s long and use only ASCII characters, so no special symbols.', - 'USERNAME_LETTER_NUM_EXPLAIN' => 'Username must be between %1$s and %2$s long and use only letter or number characters.', - 'USERNAME_LETTER_NUM_SPACERS_EXPLAIN'=> 'Username must be between %1$s and %2$s long and use letter, number, space or -+_[] characters.', - 'USERNAME_CHARS_ANY_EXPLAIN' => 'Length must be between %1$s and %2$s.', - 'USERNAME_TAKEN_USERNAME' => 'The username you entered is already in use, please select an alternative.', - 'USERNAME_DISALLOWED_USERNAME' => 'The username you entered has been disallowed or contains a disallowed word. Please choose a different name.', - 'USER_NOT_FOUND_OR_INACTIVE' => 'The usernames you specified could either not be found or are not activated users.', - - 'VIEW_AVATARS' => 'Display avatars', - 'VIEW_EDIT' => 'View/Edit', - 'VIEW_FLASH' => 'Display Flash animations', - 'VIEW_IMAGES' => 'Display images within posts', - 'VIEW_NEXT_HISTORY' => 'Next PM in history', - 'VIEW_NEXT_PM' => 'Next PM', - 'VIEW_PM' => 'View message', - 'VIEW_PM_INFO' => 'Message details', - 'VIEW_PM_MESSAGES' => array( - 1 => '%d message', - 2 => '%d messages', - ), - 'VIEW_PREVIOUS_HISTORY' => 'Previous PM in history', - 'VIEW_PREVIOUS_PM' => 'Previous PM', - 'VIEW_PROFILE' => 'View profile', - 'VIEW_SIGS' => 'Display signatures', - 'VIEW_SMILIES' => 'Display smilies as images', - 'VIEW_TOPICS_DAYS' => 'Display topics from previous days', - 'VIEW_TOPICS_DIR' => 'Display topic order direction', - 'VIEW_TOPICS_KEY' => 'Display topics ordering by', - 'VIEW_POSTS_DAYS' => 'Display posts from previous days', - 'VIEW_POSTS_DIR' => 'Display post order direction', - 'VIEW_POSTS_KEY' => 'Display posts ordering by', - - 'WATCHED_EXPLAIN' => 'Below is a list of forums and topics you are subscribed to. You will be notified of new posts in either. To unsubscribe mark the forum or topic and then press the Unwatch marked button.', - 'WATCHED_FORUMS' => 'Watched forums', - 'WATCHED_TOPICS' => 'Watched topics', - 'WRONG_ACTIVATION' => 'The activation key you supplied does not match any in the database.', - - 'YOUR_DETAILS' => 'Your activity', - 'YOUR_FOES' => 'Your foes', - 'YOUR_FOES_EXPLAIN' => 'To remove usernames select them and click submit.', - 'YOUR_FRIENDS' => 'Your friends', - 'YOUR_FRIENDS_EXPLAIN' => 'To remove usernames select them and click submit.', - 'YOUR_WARNINGS' => 'Your warning level', - - 'PM_ACTION' => array( - 'PLACE_INTO_FOLDER' => 'Place into folder', - 'MARK_AS_READ' => 'Mark as read', - 'MARK_AS_IMPORTANT' => 'Mark message', - 'DELETE_MESSAGE' => 'Delete message', - ), - 'PM_CHECK' => array( - 'SUBJECT' => 'Subject', - 'SENDER' => 'Sender', - 'MESSAGE' => 'Message', - 'STATUS' => 'Message status', - 'TO' => 'Sent To', - ), - 'PM_RULE' => array( - 'IS_LIKE' => 'is like', - 'IS_NOT_LIKE' => 'is not like', - 'IS' => 'is', - 'IS_NOT' => 'is not', - 'BEGINS_WITH' => 'begins with', - 'ENDS_WITH' => 'ends with', - 'IS_FRIEND' => 'is friend', - 'IS_FOE' => 'is foe', - 'IS_USER' => 'is user', - 'IS_GROUP' => 'is in usergroup', - 'ANSWERED' => 'answered', - 'FORWARDED' => 'forwarded', - 'TO_GROUP' => 'to my default usergroup', - 'TO_ME' => 'to me', - ), - - 'GROUPS_EXPLAIN' => 'Usergroups enable board admins to better administer users. By default you will be placed in a specific group, this is your default group. This group defines how you may appear to other users, for example your username colouration, avatar, rank, etc. Depending on whether the administrator allows it you may be allowed to change your default group. You may also be placed in or allowed to join other groups. Some groups may give you additional permissions to view content or increase your capabilities in other areas.', - 'GROUP_LEADER' => 'Leaderships', - 'GROUP_MEMBER' => 'Memberships', - 'GROUP_PENDING' => 'Pending memberships', - 'GROUP_NONMEMBER' => 'Non-memberships', - 'GROUP_DETAILS' => 'Group details', - - 'NO_LEADER' => 'No group leaderships', - 'NO_MEMBER' => 'No group memberships', - 'NO_PENDING' => 'No pending memberships', - 'NO_NONMEMBER' => 'No non-member groups', -)); diff --git a/install/update/new/mcp.php b/install/update/new/mcp.php deleted file mode 100644 index c8fb023..0000000 --- a/install/update/new/mcp.php +++ /dev/null @@ -1,331 +0,0 @@ - -* @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); -$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_admin.' . $phpEx); -include($phpbb_root_path . 'includes/functions_mcp.' . $phpEx); -require($phpbb_root_path . 'includes/functions_module.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup('mcp'); - -$module = new p_master(); - -// Setting a variable to let the style designer know where he is... -$template->assign_var('S_IN_MCP', true); - -// Basic parameter data -$id = $request->variable('i', ''); - -$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']) -{ - if ($user->data['is_bot']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - login_box('', $user->lang['LOGIN_EXPLAIN_MCP']); -} - -$quickmod = (isset($_REQUEST['quickmod'])) ? true : false; -$action = $request->variable('action', ''); -$action_ary = $request->variable('action', array('' => 0)); - -$forum_action = $request->variable('forum_action', ''); -if ($forum_action !== '' && $request->variable('sort', false, false, \phpbb\request\request_interface::POST)) -{ - $action = $forum_action; -} - -if (count($action_ary)) -{ - $action = key($action_ary); -} -unset($action_ary); - -if ($mode == 'topic_logs') -{ - $id = 'logs'; - $quickmod = false; -} - -$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) -{ - // We determine the topic and forum id here, to make sure the moderator really has moderative rights on this post - $sql = 'SELECT topic_id, forum_id - FROM ' . POSTS_TABLE . " - WHERE post_id = $post_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $topic_id = (int) $row['topic_id']; - $forum_id = (int) $row['forum_id']; -} -else if ($topic_id) -{ - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . " - WHERE topic_id = $topic_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $forum_id = (int) $row['forum_id']; -} - -// If the user doesn't have any moderator powers (globally or locally) he can't access the mcp -if (!$auth->acl_getf_global('m_')) -{ - // Except he is using one of the quickmod tools for users - $user_quickmod_actions = array( - 'lock' => 'f_user_lock', - 'make_sticky' => 'f_sticky', - 'make_announce' => 'f_announce', - 'make_global' => 'f_announce_global', - 'make_normal' => array('f_announce', 'f_announce_global', 'f_sticky') - ); - - $allow_user = false; - if ($quickmod && isset($user_quickmod_actions[$action]) && $user->data['is_registered'] && $auth->acl_gets($user_quickmod_actions[$action], $forum_id)) - { - $topic_info = phpbb_get_topic_data(array($topic_id)); - if ($topic_info[$topic_id]['topic_poster'] == $user->data['user_id']) - { - $allow_user = true; - } - } - - if (!$allow_user) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } -} - -// 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'); -} - -/** -* Allow applying additional permissions to MCP access besides f_read -* -* @event core.mcp_global_f_read_auth_after -* @var string action The action the user tried to execute -* @var int forum_id The forum the user tried to access -* @var string mode The MCP module the user is trying to access -* @var p_master module Module system class -* @var bool quickmod True if the user is accessing using quickmod tools -* @var int topic_id The topic the user tried to access -* @since 3.1.3-RC1 -*/ -$vars = array( - 'action', - 'forum_id', - 'mode', - 'module', - 'quickmod', - 'topic_id', -); -extract($phpbb_dispatcher->trigger_event('core.mcp_global_f_read_auth_after', compact($vars))); - -if ($forum_id) -{ - $module->acl_forum_id = $forum_id; -} - -// Instantiate module system and generate list of available modules -$module->list_modules('mcp'); - -if ($quickmod) -{ - $mode = 'quickmod'; - - switch ($action) - { - case 'lock': - case 'unlock': - case 'lock_post': - case 'unlock_post': - case 'make_sticky': - case 'make_announce': - case 'make_global': - case 'make_normal': - case 'fork': - case 'move': - case 'delete_post': - case 'delete_topic': - case 'restore_topic': - $module->load('mcp', 'main', 'quickmod'); - return; - break; - - case 'topic_logs': - // Reset start parameter if we jumped from the quickmod dropdown - if ($request->variable('start', 0)) - { - $request->overwrite('start', 0); - } - - $module->set_active('logs', 'topic_logs'); - break; - - case 'merge_topic': - $module->set_active('main', 'forum_view'); - break; - - case 'split': - case 'merge': - $module->set_active('main', 'topic_view'); - break; - - default: - // If needed, the flag can be set to true within event listener - // to indicate that the action was handled properly - // and to pass by the trigger_error() call below - $is_valid_action = false; - - /** - * This event allows you to add custom quickmod options - * - * @event core.modify_quickmod_options - * @var object module Instance of module system class - * @var string action Quickmod option - * @var bool is_valid_action Flag indicating if the action was handled properly - * @since 3.1.0-a4 - */ - $vars = array('module', 'action', 'is_valid_action'); - extract($phpbb_dispatcher->trigger_event('core.modify_quickmod_options', compact($vars))); - - if (!$is_valid_action) - { - trigger_error($user->lang('QUICKMOD_ACTION_NOT_ALLOWED', $action), E_USER_ERROR); - } - break; - } -} -else -{ - // Select the active module - $module->set_active($id, $mode); -} - -// Hide some of the options if we don't have the relevant information to use them -if (!$post_id) -{ - $module->set_display('main', 'post_details', false); - $module->set_display('warn', 'warn_post', false); -} - -if ($mode == '' || $mode == 'unapproved_topics' || $mode == 'unapproved_posts' || $mode == 'deleted_topics' || $mode == 'deleted_posts') -{ - $module->set_display('queue', 'approve_details', false); -} - -if ($mode == '' || $mode == 'reports' || $mode == 'reports_closed' || $mode == 'pm_reports' || $mode == 'pm_reports_closed' || $mode == 'pm_report_details') -{ - $module->set_display('reports', 'report_details', false); -} - -if ($mode == '' || $mode == 'reports' || $mode == 'reports_closed' || $mode == 'pm_reports' || $mode == 'pm_reports_closed' || $mode == 'report_details') -{ - $module->set_display('pm_reports', 'pm_report_details', false); -} - -if (!$topic_id) -{ - $module->set_display('main', 'topic_view', false); - $module->set_display('logs', 'topic_logs', false); -} - -if (!$forum_id) -{ - $module->set_display('main', 'forum_view', false); - $module->set_display('logs', 'forum_logs', false); -} - -if (!$user_id && $username == '') -{ - $module->set_display('notes', 'user_notes', false); - $module->set_display('warn', 'warn_user', false); -} - -/** -* This event allows you to set display option for custom MCP modules -* -* @event core.modify_mcp_modules_display_option -* @var p_master module Module system class -* @var string mode MCP mode -* @var int user_id User id -* @var int forum_id Forum id -* @var int topic_id Topic id -* @var int post_id Post id -* @var string username User name -* @var int id Parent module id -* @since 3.1.0-b2 -*/ -$vars = array( - 'module', - 'mode', - 'user_id', - 'forum_id', - 'topic_id', - 'post_id', - 'username', - 'id', -); -extract($phpbb_dispatcher->trigger_event('core.modify_mcp_modules_display_option', compact($vars))); - -$template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $user->lang('MCP'), - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}mcp.$phpEx"), -)); - -// Load and execute the relevant module -$module->load_active(); - -// Assign data to the template engine for the list of modules -$module->assign_tpl_vars(append_sid("{$phpbb_root_path}mcp.$phpEx")); - -// Generate urls for letting the moderation control panel being accessed in different modes -$template->assign_vars(array( - 'U_MCP' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main'), - 'U_MCP_FORUM' => ($forum_id) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=forum_view&f=$forum_id") : '', - 'U_MCP_TOPIC' => ($forum_id && $topic_id) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=topic_view&t=$topic_id") : '', - 'U_MCP_POST' => ($forum_id && $topic_id && $post_id) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=post_details&t=$topic_id&p=$post_id") : '', -)); - -// Generate the page, do not display/query online list -$module->display($module->get_page_title()); diff --git a/install/update/new/memberlist.php b/install/update/new/memberlist.php deleted file mode 100644 index e933b54..0000000 --- a/install/update/new/memberlist.php +++ /dev/null @@ -1,1852 +0,0 @@ - -* @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); -$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); - -$mode = $request->variable('mode', ''); - -if ($mode === 'contactadmin') -{ - define('SKIP_CHECK_BAN', true); - define('SKIP_CHECK_DISABLED', true); -} - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup(array('memberlist', 'groups')); - -// Setting a variable to let the style designer know where he is... -$template->assign_var('S_IN_MEMBERLIST', true); - -// Grab data -$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') -{ - send_status_line(301, 'Moved Permanently'); - redirect(append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=team')); -} - -// Check our mode... -if (!in_array($mode, array('', 'group', 'viewprofile', 'email', 'contact', 'contactadmin', 'searchuser', 'team', 'livesearch'))) -{ - trigger_error('NO_MODE'); -} - -switch ($mode) -{ - case 'email': - case 'contactadmin': - break; - - case 'livesearch': - if (!$config['allow_live_searches']) - { - trigger_error('LIVE_SEARCHES_NOT_ALLOWED'); - } - // No break - - default: - // 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('', ((isset($user->lang['LOGIN_EXPLAIN_' . strtoupper($mode)])) ? $user->lang['LOGIN_EXPLAIN_' . strtoupper($mode)] : $user->lang['LOGIN_EXPLAIN_MEMBERLIST'])); - } - break; -} - -/** @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->variable('sk', $default_key); -$sort_dir = $request->variable('sd', 'a'); - -$user_types = array(USER_NORMAL, USER_FOUNDER); -if ($auth->acl_get('a_user')) -{ - $user_types[] = USER_INACTIVE; -} - -// What do you want to do today? ... oops, I think that line is taken ... -switch ($mode) -{ - case 'team': - // Display a listing of board admins, moderators - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $page_title = $user->lang['THE_TEAM']; - $template_html = 'memberlist_team.html'; - - $sql = 'SELECT * - FROM ' . TEAMPAGE_TABLE . ' - ORDER BY teampage_position ASC'; - $result = $db->sql_query($sql, 3600); - $teampage_data = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - $sql_ary = array( - 'SELECT' => 'g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id as ug_user_id, t.teampage_id', - - 'FROM' => array(GROUPS_TABLE => 'g'), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(TEAMPAGE_TABLE => 't'), - 'ON' => 't.group_id = g.group_id', - ), - array( - 'FROM' => array(USER_GROUP_TABLE => 'ug'), - 'ON' => 'ug.group_id = g.group_id AND ug.user_pending = 0 AND ug.user_id = ' . (int) $user->data['user_id'], - ), - ), - ); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - - $group_ids = $groups_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['group_type'] == GROUP_HIDDEN && !$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel') && $row['ug_user_id'] != $user->data['user_id']) - { - $row['group_name'] = $user->lang['GROUP_UNDISCLOSED']; - $row['u_group'] = ''; - } - else - { - $row['group_name'] = $group_helper->get_name($row['group_name']); - $row['u_group'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $row['group_id']); - } - - if ($row['teampage_id']) - { - // Only put groups into the array we want to display. - // We are fetching all groups, to ensure we got all data for default groups. - $group_ids[] = (int) $row['group_id']; - } - $groups_ary[(int) $row['group_id']] = $row; - } - $db->sql_freeresult($result); - - $sql_ary = array( - 'SELECT' => 'u.user_id, u.group_id as default_group, u.username, u.username_clean, u.user_colour, u.user_type, u.user_rank, u.user_posts, u.user_allow_pm, g.group_id', - - 'FROM' => array( - USER_GROUP_TABLE => 'ug', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(USERS_TABLE => 'u'), - 'ON' => 'ug.user_id = u.user_id', - ), - array( - 'FROM' => array(GROUPS_TABLE => 'g'), - 'ON' => 'ug.group_id = g.group_id', - ), - ), - - 'WHERE' => $db->sql_in_set('g.group_id', $group_ids, false, true) . ' AND ug.user_pending = 0', - - 'ORDER_BY' => 'u.username_clean ASC', - ); - - /** - * Modify the query used to get the users for the team page - * - * @event core.memberlist_team_modify_query - * @var array sql_ary Array containing the query - * @var array group_ids Array of group ids - * @var array teampage_data The teampage data - * @since 3.1.3-RC1 - */ - $vars = array( - 'sql_ary', - 'group_ids', - 'teampage_data', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_team_modify_query', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - - $user_ary = $user_ids = $group_users = array(); - while ($row = $db->sql_fetchrow($result)) - { - $row['forums'] = ''; - $row['forums_ary'] = array(); - $user_ary[(int) $row['user_id']] = $row; - $user_ids[] = (int) $row['user_id']; - $group_users[(int) $row['group_id']][] = (int) $row['user_id']; - } - $db->sql_freeresult($result); - - $user_ids = array_unique($user_ids); - - if (!empty($user_ids) && $config['teampage_forums']) - { - $template->assign_var('S_DISPLAY_MODERATOR_FORUMS', true); - // Get all moderators - $perm_ary = $auth->acl_get_list($user_ids, array('m_'), false); - - foreach ($perm_ary as $forum_id => $forum_ary) - { - foreach ($forum_ary as $auth_option => $id_ary) - { - foreach ($id_ary as $id) - { - if (!$forum_id) - { - $user_ary[$id]['forums'] = $user->lang['ALL_FORUMS']; - } - else - { - $user_ary[$id]['forums_ary'][] = $forum_id; - } - } - } - } - - $sql = 'SELECT forum_id, forum_name - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - - $forums = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forums[$row['forum_id']] = $row['forum_name']; - } - $db->sql_freeresult($result); - - foreach ($user_ary as $user_id => $user_data) - { - if (!$user_data['forums']) - { - foreach ($user_data['forums_ary'] as $forum_id) - { - $user_ary[$user_id]['forums_options'] = true; - if (isset($forums[$forum_id])) - { - if ($auth->acl_get('f_list', $forum_id)) - { - $user_ary[$user_id]['forums'] .= ''; - } - } - } - } - } - } - - $parent_team = 0; - foreach ($teampage_data as $team_data) - { - // If this team entry has no group, it's a category - if (!$team_data['group_id']) - { - $template->assign_block_vars('group', array( - 'GROUP_NAME' => $team_data['teampage_name'], - )); - - $parent_team = (int) $team_data['teampage_id']; - continue; - } - - $group_data = $groups_ary[(int) $team_data['group_id']]; - $group_id = (int) $team_data['group_id']; - - if (!$team_data['teampage_parent']) - { - // If the group does not have a parent category, we display the groupname as category - $template->assign_block_vars('group', array( - 'GROUP_NAME' => $group_data['group_name'], - 'GROUP_COLOR' => $group_data['group_colour'], - 'U_GROUP' => $group_data['u_group'], - )); - } - - // Display group members. - if (!empty($group_users[$group_id])) - { - foreach ($group_users[$group_id] as $user_id) - { - if (isset($user_ary[$user_id])) - { - $row = $user_ary[$user_id]; - if ($config['teampage_memberships'] == 1 && ($group_id != $groups_ary[$row['default_group']]['group_id']) && $groups_ary[$row['default_group']]['teampage_id']) - { - // Display users in their primary group, instead of the first group, when it is displayed on the teampage. - continue; - } - - $user_rank_data = phpbb_get_user_rank($row, (($row['user_id'] == ANONYMOUS) ? false : $row['user_posts'])); - - $template_vars = array( - 'USER_ID' => $row['user_id'], - 'FORUMS' => $row['forums'], - 'FORUM_OPTIONS' => (isset($row['forums_options'])) ? true : false, - 'RANK_TITLE' => $user_rank_data['title'], - - 'GROUP_NAME' => $groups_ary[$row['default_group']]['group_name'], - 'GROUP_COLOR' => $groups_ary[$row['default_group']]['group_colour'], - 'U_GROUP' => $groups_ary[$row['default_group']]['u_group'], - - 'RANK_IMG' => $user_rank_data['img'], - 'RANK_IMG_SRC' => $user_rank_data['img_src'], - - 'S_INACTIVE' => $row['user_type'] == USER_INACTIVE, - - 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($row['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $row['user_id']) : '', - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), - 'USER_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), - 'U_VIEW_PROFILE' => get_username_string('profile', $row['user_id'], $row['username'], $row['user_colour']), - ); - - /** - * Modify the template vars for displaying the user in the groups on the teampage - * - * @event core.memberlist_team_modify_template_vars - * @var array template_vars Array containing the query - * @var array row Array containing the action user row - * @var array groups_ary Array of groups with all users that should be displayed - * @since 3.1.3-RC1 - */ - $vars = array( - 'template_vars', - 'row', - 'groups_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_team_modify_template_vars', compact($vars))); - - $template->assign_block_vars('group.user', $template_vars); - - if ($config['teampage_memberships'] != 2) - { - unset($user_ary[$user_id]); - } - } - } - } - } - - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $page_title, - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=team"), - )); - - $template->assign_vars(array( - 'PM_IMG' => $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE'])) - ); - break; - - case 'contact': - - $page_title = $user->lang['IM_USER']; - $template_html = 'memberlist_im.html'; - - if (!$auth->acl_get('u_sendim')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } - - $presence_img = ''; - switch ($action) - { - case 'jabber': - $lang = 'JABBER'; - $sql_field = 'user_jabber'; - $s_select = (@extension_loaded('xml') && $config['jab_enable']) ? 'S_SEND_JABBER' : 'S_NO_SEND_JABBER'; - $s_action = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=$action&u=$user_id"); - break; - - default: - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - - // Grab relevant data - $sql = "SELECT user_id, username, user_email, user_lang, $sql_field - FROM " . USERS_TABLE . " - WHERE user_id = $user_id - AND user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_USER'); - } - else if (empty($row[$sql_field])) - { - trigger_error('IM_NO_DATA'); - } - - // Post data grab actions - switch ($action) - { - case 'jabber': - add_form_key('memberlist_messaging'); - - if ($submit && @extension_loaded('xml') && $config['jab_enable']) - { - if (check_form_key('memberlist_messaging')) - { - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $subject = sprintf($user->lang['IM_JABBER_SUBJECT'], $user->data['username'], $config['server_name']); - $message = $request->variable('message', '', true); - - if (empty($message)) - { - trigger_error('EMPTY_MESSAGE_IM'); - } - - $messenger = new messenger(false); - - $messenger->template('profile_send_im', $row['user_lang']); - $messenger->subject(htmlspecialchars_decode($subject)); - - $messenger->replyto($user->data['user_email']); - $messenger->set_addresses($row); - - $messenger->assign_vars(array( - 'BOARD_CONTACT' => phpbb_get_board_contact($config, $phpEx), - 'FROM_USERNAME' => htmlspecialchars_decode($user->data['username']), - 'TO_USERNAME' => htmlspecialchars_decode($row['username']), - 'MESSAGE' => htmlspecialchars_decode($message)) - ); - - $messenger->send(NOTIFY_IM); - - $s_select = 'S_SENT_JABBER'; - } - else - { - trigger_error('FORM_INVALID'); - } - } - break; - } - - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $page_title, - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=$action&u=$user_id"), - )); - - // Send vars to the template - $template->assign_vars(array( - 'IM_CONTACT' => $row[$sql_field], - 'A_IM_CONTACT' => addslashes($row[$sql_field]), - - 'USERNAME' => $row['username'], - 'CONTACT_NAME' => $row[$sql_field], - 'SITENAME' => $config['sitename'], - - 'PRESENCE_IMG' => $presence_img, - - 'L_SEND_IM_EXPLAIN' => $user->lang['IM_' . $lang], - 'L_IM_SENT_JABBER' => sprintf($user->lang['IM_SENT_JABBER'], $row['username']), - - $s_select => true, - 'S_IM_ACTION' => $s_action) - ); - - break; - - case 'viewprofile': - // Display a profile - if ($user_id == ANONYMOUS && !$username) - { - trigger_error('NO_USER'); - } - - // Get user... - $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); - - if (!$member) - { - trigger_error('NO_USER'); - } - - // a_user admins and founder are able to view inactive users and bots to be able to manage them more easily - // Normal users are able to see at least users having only changed their profile settings but not yet reactivated. - if (!$auth->acl_get('a_user') && $user->data['user_type'] != USER_FOUNDER) - { - if ($member['user_type'] == USER_IGNORE) - { - trigger_error('NO_USER'); - } - else if ($member['user_type'] == USER_INACTIVE && $member['user_inactive_reason'] != INACTIVE_PROFILE) - { - trigger_error('NO_USER'); - } - } - - $user_id = (int) $member['user_id']; - - // Get group memberships - // Also get visiting user's groups to determine hidden group memberships if necessary. - $auth_hidden_groups = ($user_id === (int) $user->data['user_id'] || $auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? true : false; - $sql_uid_ary = ($auth_hidden_groups) ? array($user_id) : array($user_id, (int) $user->data['user_id']); - - // Do the SQL thang - $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(); - while ($row = $db->sql_fetchrow($result)) - { - $row['user_id'] = (int) $row['user_id']; - $row['group_id'] = (int) $row['group_id']; - - if ($row['user_id'] == $user_id) - { - $profile_groups[] = $row; - } - else - { - $user_groups[$row['group_id']] = $row['group_id']; - } - } - $db->sql_freeresult($result); - - // Filter out hidden groups and sort groups by name - $group_data = $group_sort = array(); - foreach ($profile_groups as $row) - { - 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; - } - unset($profile_groups); - 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) - { - $row = $group_data[$group_id]; - - $group_options .= ''; - } - unset($group_data); - unset($group_sort); - - // What colour is the zebra - $sql = 'SELECT friend, foe - FROM ' . ZEBRA_TABLE . " - WHERE zebra_id = $user_id - AND user_id = {$user->data['user_id']}"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - - $foe = $row ? (bool) $row['foe'] : false; - $friend = $row ? (bool) $row['friend'] : false; - - $db->sql_freeresult($result); - - if ($config['load_onlinetrack']) - { - $sql = 'SELECT MAX(session_time) AS session_time, MIN(session_viewonline) AS session_viewonline - FROM ' . SESSIONS_TABLE . " - WHERE session_user_id = $user_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $member['session_time'] = (isset($row['session_time'])) ? $row['session_time'] : 0; - $member['session_viewonline'] = (isset($row['session_viewonline'])) ? $row['session_viewonline'] : 0; - unset($row); - } - - if ($config['load_user_activity']) - { - display_user_activity($member); - } - - // Do the relevant calculations - $memberdays = max(1, round((time() - $member['user_regdate']) / 86400)); - $posts_per_day = $member['user_posts'] / $memberdays; - $percentage = ($config['num_posts']) ? min(100, ($member['user_posts'] / $config['num_posts']) * 100) : 0; - - - if ($member['user_sig']) - { - $parse_flags = ($member['user_sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - $member['user_sig'] = generate_text_for_display($member['user_sig'], $member['user_sig_bbcode_uid'], $member['user_sig_bbcode_bitfield'], $parse_flags, true); - } - - // We need to check if the modules 'zebra' ('friends' & 'foes' mode), 'notes' ('user_notes' mode) and 'warn' ('warn_user' mode) are accessible to decide if we can display appropriate links - $zebra_enabled = $friends_enabled = $foes_enabled = $user_notes_enabled = $warn_user_enabled = false; - - // Only check if the user is logged in - if ($user->data['is_registered']) - { - if (!class_exists('p_master')) - { - include($phpbb_root_path . 'includes/functions_module.' . $phpEx); - } - $module = new p_master(); - - $module->list_modules('ucp'); - $module->list_modules('mcp'); - - $user_notes_enabled = ($module->loaded('mcp_notes', 'user_notes')) ? true : false; - $warn_user_enabled = ($module->loaded('mcp_warn', 'warn_user')) ? true : false; - $zebra_enabled = ($module->loaded('ucp_zebra')) ? true : false; - $friends_enabled = ($module->loaded('ucp_zebra', 'friends')) ? true : false; - $foes_enabled = ($module->loaded('ucp_zebra', 'foes')) ? true : false; - - unset($module); - } - - // Custom Profile Fields - $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(); - } - - /** - * Modify user data before we display the profile - * - * @event core.memberlist_view_profile - * @var array member Array with user's data - * @var bool user_notes_enabled Is the mcp user notes module enabled? - * @var bool warn_user_enabled Is the mcp warnings module enabled? - * @var bool zebra_enabled Is the ucp zebra module enabled? - * @var bool friends_enabled Is the ucp friends module enabled? - * @var bool foes_enabled Is the ucp foes module enabled? - * @var bool friend Is the user friend? - * @var bool foe Is the user foe? - * @var array profile_fields Array with user's profile field data - * @since 3.1.0-a1 - * @changed 3.1.0-b2 Added friend and foe status - * @changed 3.1.0-b3 Added profile fields data - */ - $vars = array( - 'member', - 'user_notes_enabled', - 'warn_user_enabled', - 'zebra_enabled', - 'friends_enabled', - 'foes_enabled', - 'friend', - 'foe', - 'profile_fields', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_view_profile', compact($vars))); - - $template->assign_vars(phpbb_show_profile($member, $user_notes_enabled, $warn_user_enabled)); - - // If the user has m_approve permission or a_user permission, then list then display unapproved posts - if ($auth->acl_getf_global('m_approve') || $auth->acl_get('a_user')) - { - $sql = 'SELECT COUNT(post_id) as posts_in_queue - FROM ' . POSTS_TABLE . ' - WHERE poster_id = ' . $user_id . ' - AND ' . $db->sql_in_set('post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)); - $result = $db->sql_query($sql); - $member['posts_in_queue'] = (int) $db->sql_fetchfield('posts_in_queue'); - $db->sql_freeresult($result); - } - else - { - $member['posts_in_queue'] = 0; - } - - // 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), - - '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']), - - '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&mode=overview&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&mode=user&u=' . $user_id, true, $user->session_id) : '', - 'U_MCP_QUEUE' => ($auth->acl_getf_global('m_approve')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue', true, $user->session_id) : '', - - 'U_SWITCH_PERMISSIONS' => ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_id) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&u={$user_id}&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&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&add=' . urlencode(htmlspecialchars_decode($member['username']))) : '', - 'U_ADD_FOE' => (!$friend && !$foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&mode=foes&add=' . urlencode(htmlspecialchars_decode($member['username']))) : '', - 'U_REMOVE_FRIEND' => ($friend && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&remove=1&usernames[]=' . $user_id) : '', - 'U_REMOVE_FOE' => ($foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&remove=1&mode=foes&usernames[]=' . $user_id) : '', - - 'U_CANONICAL' => generate_board_url() . '/' . append_sid("memberlist.$phpEx", 'mode=viewprofile&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'])) - { - $template->assign_vars($profile_fields['row']); - } - - if (!empty($profile_fields['blockrow'])) - { - foreach ($profile_fields['blockrow'] as $field_data) - { - $template->assign_block_vars('custom_fields', $field_data); - } - } - - // Inactive reason/account? - if ($member['user_type'] == USER_INACTIVE) - { - $user->add_lang('acp/common'); - - $inactive_reason = $user->lang['INACTIVE_REASON_UNKNOWN']; - - switch ($member['user_inactive_reason']) - { - case INACTIVE_REGISTER: - $inactive_reason = $user->lang['INACTIVE_REASON_REGISTER']; - break; - - case INACTIVE_PROFILE: - $inactive_reason = $user->lang['INACTIVE_REASON_PROFILE']; - break; - - case INACTIVE_MANUAL: - $inactive_reason = $user->lang['INACTIVE_REASON_MANUAL']; - break; - - case INACTIVE_REMIND: - $inactive_reason = $user->lang['INACTIVE_REASON_REMIND']; - break; - } - - $template->assign_vars(array( - 'S_USER_INACTIVE' => true, - 'USER_INACTIVE_REASON' => $inactive_reason) - ); - } - - // Now generate page title - $page_title = sprintf($user->lang['VIEWING_PROFILE'], $member['username']); - $template_html = 'memberlist_view.html'; - - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $user->lang('MEMBERLIST'), - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}memberlist.$phpEx"), - )); - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $member['username'], - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=viewprofile&u=$user_id"), - )); - - break; - - case 'contactadmin': - case 'email': - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $user_id = $request->variable('u', 0); - $topic_id = $request->variable('t', 0); - - if ($user_id) - { - $form_name = 'user'; - } - else if ($topic_id) - { - $form_name = 'topic'; - } - else if ($mode === 'contactadmin') - { - $form_name = 'admin'; - } - else - { - trigger_error('NO_EMAIL'); - } - - /** @var $form \phpbb\message\form */ - $form = $phpbb_container->get('message.form.' . $form_name); - - $form->bind($request); - $error = $form->check_allow(); - if ($error) - { - trigger_error($error); - } - - if ($request->is_set_post('submit')) - { - $messenger = new messenger(false); - $form->submit($messenger); - } - - $page_title = $form->get_page_title(); - $template_html = $form->get_template_file(); - $form->render($template); - - if ($user_id) - { - $navlink_name = $user->lang('SEND_EMAIL'); - $navlink_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&u=$user_id"); - } - else if ($topic_id) - { - $sql = 'SELECT f.parent_id, f.forum_parents, f.left_id, f.right_id, f.forum_type, f.forum_name, f.forum_id, f.forum_desc, f.forum_desc_uid, f.forum_desc_bitfield, f.forum_desc_options, f.forum_options, t.topic_title - FROM ' . FORUMS_TABLE . ' as f, - ' . TOPICS_TABLE . ' as t - WHERE t.forum_id = f.forum_id'; - $result = $db->sql_query($sql); - $topic_data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - generate_forum_nav($topic_data); - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $topic_data['topic_title'], - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id"), - )); - - $navlink_name = $user->lang('EMAIL_TOPIC'); - $navlink_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&t=$topic_id"); - } - else if ($mode === 'contactadmin') - { - $navlink_name = $user->lang('CONTACT_ADMIN'); - $navlink_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contactadmin"); - } - - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $navlink_name, - 'U_BREADCRUMB' => $navlink_url, - )); - - break; - - case 'livesearch': - - $username_chars = $request->variable('username', '', true); - - $sql = 'SELECT username, user_id, user_colour - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_type', $user_types) . ' - AND username_clean ' . $db->sql_like_expression(utf8_clean_string($username_chars) . $db->get_any_char()); - $result = $db->sql_query_limit($sql, 10); - $user_list = array(); - - while ($row = $db->sql_fetchrow($result)) - { - $user_list[] = array( - 'user_id' => (int) $row['user_id'], - 'result' => $row['username'], - 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'display' => get_username_string('no_profile', $row['user_id'], $row['username'], $row['user_colour']), - ); - } - $db->sql_freeresult($result); - $json_response = new \phpbb\json_response(); - $json_response->send(array( - 'keyword' => $username_chars, - 'results' => $user_list, - )); - - break; - - case 'group': - default: - // The basic memberlist - $page_title = $user->lang['MEMBERLIST']; - $template_html = 'memberlist_body.html'; - - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $page_title, - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}memberlist.$phpEx"), - )); - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - - // Sorting - $sort_key_text = array('a' => $user->lang['SORT_USERNAME'], 'c' => $user->lang['SORT_JOINED'], 'd' => $user->lang['SORT_POST_COUNT']); - $sort_key_sql = array('a' => 'u.username_clean', 'c' => 'u.user_regdate', 'd' => 'u.user_posts'); - - if ($config['jab_enable']) - { - $sort_key_text['k'] = $user->lang['JABBER']; - $sort_key_sql['k'] = 'u.user_jabber'; - } - - if ($auth->acl_get('a_user')) - { - $sort_key_text['e'] = $user->lang['SORT_EMAIL']; - $sort_key_sql['e'] = 'u.user_email'; - } - - if ($auth->acl_get('u_viewonline')) - { - $sort_key_text['l'] = $user->lang['SORT_LAST_ACTIVE']; - $sort_key_sql['l'] = 'u.user_lastvisit'; - } - - $sort_key_text['m'] = $user->lang['SORT_RANK']; - $sort_key_sql['m'] = 'u.user_rank'; - - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - $s_sort_key = ''; - foreach ($sort_key_text as $key => $value) - { - $selected = ($sort_key == $key) ? ' selected="selected"' : ''; - $s_sort_key .= ''; - } - - $s_sort_dir = ''; - foreach ($sort_dir_text as $key => $value) - { - $selected = ($sort_dir == $key) ? ' selected="selected"' : ''; - $s_sort_dir .= ''; - } - - // Additional sorting options for user search ... if search is enabled, if not - // then only admins can make use of this (for ACP functionality) - $sql_select = $sql_where_data = $sql_from = $sql_where = $order_by = ''; - - - $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'); - - // 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') || count(array_intersect($request->variable_names(\phpbb\request\request_interface::GET), $search_params)) > 0) && ($config['load_search'] || $auth->acl_get('a_'))) - { - $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->variable('joined_select', 'lt'); - $active_select = $request->variable('active_select', 'lt'); - $count_select = $request->variable('count_select', 'eq'); - - $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' => '='); - - $find_count = array('lt' => $user->lang['LESS_THAN'], 'eq' => $user->lang['EQUAL_TO'], 'gt' => $user->lang['MORE_THAN']); - $s_find_count = ''; - foreach ($find_count as $key => $value) - { - $selected = ($count_select == $key) ? ' selected="selected"' : ''; - $s_find_count .= ''; - } - - $find_time = array('lt' => $user->lang['BEFORE'], 'gt' => $user->lang['AFTER']); - $s_find_join_time = ''; - foreach ($find_time as $key => $value) - { - $selected = ($joined_select == $key) ? ' selected="selected"' : ''; - $s_find_join_time .= ''; - } - - $s_find_active_time = ''; - foreach ($find_time as $key => $value) - { - $selected = ($active_select == $key) ? ' selected="selected"' : ''; - $s_find_active_time .= ''; - } - - $sql_where .= ($username) ? ' AND u.username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($username))) : ''; - $sql_where .= ($auth->acl_get('a_user') && $email) ? ' AND u.user_email ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $email)) . ' ' : ''; - $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]) && count($joined) == 3) - { - $joined_time = gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]); - - if ($joined_time !== false) - { - $sql_where .= " AND u.user_regdate " . $find_key_match[$joined_select] . ' ' . $joined_time; - } - } - - 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) - { - 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 . ')'; - } - } - } - - $sql_where .= ($search_group_id) ? " AND u.user_id = ug.user_id AND ug.group_id = $search_group_id AND ug.user_pending = 0 " : ''; - - if ($search_group_id) - { - $sql_from = ', ' . USER_GROUP_TABLE . ' ug '; - } - - if ($ipdomain && $auth->acl_getf_global('m_info')) - { - if (strspn($ipdomain, 'abcdefghijklmnopqrstuvwxyz')) - { - $hostnames = gethostbynamel($ipdomain); - - if ($hostnames !== false) - { - $ips = "'" . implode('\', \'', array_map(array($db, 'sql_escape'), preg_replace('#([0-9]{1,3}\.[0-9]{1,3}[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})#', "\\1", gethostbynamel($ipdomain)))) . "'"; - } - else - { - $ips = false; - } - } - else - { - $ips = "'" . str_replace('*', '%', $db->sql_escape($ipdomain)) . "'"; - } - - if ($ips === false) - { - // A minor fudge but it does the job :D - $sql_where .= " AND u.user_id = 0"; - } - else - { - $ip_forums = array_keys($auth->acl_getf('m_info', true)); - - $sql = 'SELECT DISTINCT poster_id - FROM ' . POSTS_TABLE . ' - WHERE poster_ip ' . ((strpos($ips, '%') !== false) ? 'LIKE' : 'IN') . " ($ips) - AND " . $db->sql_in_set('forum_id', $ip_forums); - - /** - * Modify sql query for members search by ip address / hostname - * - * @event core.memberlist_modify_ip_search_sql_query - * @var string ipdomain The host name - * @var string ips IP address list for the given host name - * @var string sql The SQL query for searching members by IP address - * @since 3.1.7-RC1 - */ - $vars = array( - 'ipdomain', - 'ips', - 'sql', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_ip_search_sql_query', compact($vars))); - - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $ip_sql = array(); - do - { - $ip_sql[] = $row['poster_id']; - } - while ($row = $db->sql_fetchrow($result)); - - $sql_where .= ' AND ' . $db->sql_in_set('u.user_id', $ip_sql); - } - else - { - // A minor fudge but it does the job :D - $sql_where .= " AND u.user_id = 0"; - } - unset($ip_forums); - - $db->sql_freeresult($result); - } - } - } - - $first_char = $request->variable('first_char', ''); - - if ($first_char == 'other') - { - for ($i = 97; $i < 123; $i++) - { - $sql_where .= ' AND u.username_clean NOT ' . $db->sql_like_expression(chr($i) . $db->get_any_char()); - } - } - else if ($first_char) - { - $sql_where .= ' AND u.username_clean ' . $db->sql_like_expression(substr($first_char, 0, 1) . $db->get_any_char()); - } - - // Are we looking at a usergroup? If so, fetch additional info - // and further restrict the user info query - if ($mode == 'group') - { - // We JOIN here to save a query for determining membership for hidden groups. ;) - $sql = 'SELECT g.*, ug.user_id, ug.group_leader - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug ON (ug.user_pending = 0 AND ug.user_id = ' . $user->data['user_id'] . " AND ug.group_id = $group_id) - WHERE g.group_id = $group_id"; - $result = $db->sql_query($sql); - $group_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$group_row) - { - trigger_error('NO_GROUP'); - } - - switch ($group_row['group_type']) - { - case GROUP_OPEN: - $group_row['l_group_type'] = 'OPEN'; - break; - - case GROUP_CLOSED: - $group_row['l_group_type'] = 'CLOSED'; - break; - - case GROUP_HIDDEN: - $group_row['l_group_type'] = 'HIDDEN'; - - // Check for membership or special permissions - if (!$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel') && $group_row['user_id'] != $user->data['user_id']) - { - trigger_error('NO_GROUP'); - } - break; - - case GROUP_SPECIAL: - $group_row['l_group_type'] = 'SPECIAL'; - break; - - case GROUP_FREE: - $group_row['l_group_type'] = 'FREE'; - break; - } - - $avatar_img = phpbb_get_group_avatar($group_row); - - // ... same for group rank - $group_rank_data = array( - 'title' => null, - 'img' => null, - 'img_src' => null, - ); - if ($group_row['group_rank']) - { - $group_rank_data = $group_helper->get_rank($group_row); - - if ($group_rank_data['img']) - { - $group_rank_data['img'] .= '
'; - } - } - // include modules for manage groups link display or not - // need to ensure the module is active - $can_manage_group = false; - if ($user->data['is_registered'] && $group_row['group_leader']) - { - if (!class_exists('p_master')) - { - include($phpbb_root_path . 'includes/functions_module.' . $phpEx); - } - $module = new p_master; - $module->list_modules('ucp'); - - if ($module->is_active('ucp_groups', 'manage')) - { - $can_manage_group = true; - } - unset($module); - } - - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $group_helper->get_name($group_row['group_name']), - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=group&g=$group_id"), - )); - - $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_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' => $group_rank_data['title'], - - 'AVATAR_IMG' => $avatar_img, - '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&mode=compose&g=' . $group_id) : '', - 'U_MANAGE' => ($can_manage_group) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_groups&mode=manage') : false,) - ); - - $sql_select = ', ug.group_leader'; - $sql_from = ', ' . USER_GROUP_TABLE . ' ug '; - $order_by = 'ug.group_leader DESC, '; - - $sql_where .= " AND ug.user_pending = 0 AND u.user_id = ug.user_id AND ug.group_id = $group_id"; - $sql_where_data = " AND u.user_id = ug.user_id AND ug.group_id = $group_id"; - } - - // Sorting and order - if (!isset($sort_key_sql[$sort_key])) - { - $sort_key = $default_key; - } - - $order_by .= $sort_key_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); - - // Unfortunately we must do this here for sorting by rank, else the sort order is applied wrongly - if ($sort_key == 'm') - { - $order_by .= ', u.user_posts DESC'; - } - - /** - * Modify sql query data for members search - * - * @event core.memberlist_modify_sql_query_data - * @var string order_by SQL ORDER BY clause condition - * @var string sort_dir The sorting direction - * @var string sort_key The sorting key - * @var array sort_key_sql Arraty with the sorting conditions data - * @var string sql_from SQL FROM clause condition - * @var string sql_select SQL SELECT fields list - * @var string sql_where SQL WHERE clause condition - * @var string sql_where_data SQL WHERE clause additional conditions data - * @since 3.1.7-RC1 - */ - $vars = array( - 'order_by', - 'sort_dir', - 'sort_key', - 'sort_key_sql', - 'sql_from', - 'sql_select', - 'sql_where', - 'sql_where_data', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_sql_query_data', compact($vars))); - - // Count the users ... - $sql = 'SELECT COUNT(u.user_id) AS total_users - FROM ' . USERS_TABLE . " u$sql_from - WHERE " . $db->sql_in_set('u.user_type', $user_types) . " - $sql_where"; - $result = $db->sql_query($sql); - $total_users = (int) $db->sql_fetchfield('total_users'); - $db->sql_freeresult($result); - - // Build a relevant pagination_url - $params = $sort_params = array(); - - // 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), - 'sd' => array('sd', 'a'), - 'form' => array('form', ''), - 'field' => array('field', ''), - 'select_single' => array('select_single', $select_single), - 'username' => array('username', '', true), - 'email' => array('email', ''), - 'jabber' => array('jabber', ''), - 'search_group_id' => array('search_group_id', 0), - 'joined_select' => array('joined_select', 'lt'), - 'active_select' => array('active_select', 'lt'), - 'count_select' => array('count_select', 'eq'), - 'joined' => array('joined', ''), - 'active' => array('active', ''), - 'count' => ($request->variable('count', '') !== '') ? array('count', 0) : array('count', ''), - 'ip' => array('ip', ''), - 'first_char' => array('first_char', ''), - ); - - $u_first_char_params = array(); - foreach ($check_params as $key => $call) - { - if (!isset($_REQUEST[$key])) - { - continue; - } - - $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; - - if ($key != 'first_char') - { - $u_first_char_params[] = $param; - } - if ($key != 'sk' && $key != 'sd') - { - $sort_params[] = $param; - } - } - - $u_hide_find_member = append_sid("{$phpbb_root_path}memberlist.$phpEx", "start=$start" . (!empty($params) ? '&' . implode('&', $params) : '')); - - if ($mode) - { - $params[] = "mode=$mode"; - $u_first_char_params[] = "mode=$mode"; - } - $sort_params[] = "mode=$mode"; - - $u_first_char_params = implode('&', $u_first_char_params); - $u_first_char_params .= ($u_first_char_params) ? '&' : ''; - - $first_characters = array(); - $first_characters[''] = $user->lang['ALL']; - for ($i = 97; $i < 123; $i++) - { - $first_characters[chr($i)] = chr($i - 32); - } - $first_characters['other'] = $user->lang['OTHER']; - - $first_char_block_vars = []; - - foreach ($first_characters as $char => $desc) - { - $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('&', $params)); - $sort_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", implode('&', $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->variable('search_group_id', 0); - $s_group_select = ''; - $group_ids = array(); - - /** - * @todo add this to a separate function (function is responsible for returning the groups the user is able to see based on the users group membership) - */ - - if ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) - { - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE; - - if (!$config['coppa_enable']) - { - $sql .= " WHERE group_name <> 'REGISTERED_COPPA'"; - } - - $sql .= ' ORDER BY group_name ASC'; - } - else - { - $sql = 'SELECT g.group_id, g.group_name, g.group_type - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ')'; - - if (!$config['coppa_enable']) - { - $sql .= " AND g.group_name <> 'REGISTERED_COPPA'"; - } - - $sql .= ' ORDER BY g.group_name ASC'; - } - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $group_ids[] = $row['group_id']; - $s_group_select .= ''; - } - $db->sql_freeresult($result); - - if ($group_selected !== 0 && !in_array($group_selected, $group_ids)) - { - trigger_error('NO_GROUP'); - } - - $template->assign_vars(array( - 'USERNAME' => $username, - 'EMAIL' => $email, - 'JABBER' => $jabber, - 'JOINED' => implode('-', $joined), - 'ACTIVE' => implode('-', $active), - 'COUNT' => $count, - 'IP' => $ipdomain, - - 'S_IP_SEARCH_ALLOWED' => ($auth->acl_getf_global('m_info')) ? true : false, - 'S_EMAIL_SEARCH_ALLOWED'=> ($auth->acl_get('a_user')) ? true : false, - 'S_JABBER_ENABLED' => $config['jab_enable'], - 'S_IN_SEARCH_POPUP' => ($form && $field) ? true : false, - 'S_SEARCH_USER' => ($mode == 'searchuser' || ($mode == '' && $submit)), - 'S_FORM_NAME' => $form, - 'S_FIELD_NAME' => $field, - 'S_SELECT_SINGLE' => $select_single, - 'S_COUNT_OPTIONS' => $s_find_count, - 'S_SORT_OPTIONS' => $s_sort_key, - 'S_JOINED_TIME_OPTIONS' => $s_find_join_time, - 'S_ACTIVE_TIME_OPTIONS' => $s_find_active_time, - 'S_GROUP_SELECT' => $s_group_select, - 'S_USER_SEARCH_ACTION' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=searchuser&form=$form&field=$field")) - ); - } - - $start = $pagination->validate_start($start, $config['topics_per_page'], $total_users); - - // Get us some users :D - $sql = "SELECT u.user_id - FROM " . USERS_TABLE . " u - $sql_from - WHERE " . $db->sql_in_set('u.user_type', $user_types) . " - $sql_where - ORDER BY $order_by"; - $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); - - $user_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_list[] = (int) $row['user_id']; - } - $db->sql_freeresult($result); - - // 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'); - foreach ($cp_row as $profile_field) - { - $template->assign_block_vars('custom_fields', $profile_field); - } - } - - $leaders_set = false; - // So, did we get any users? - if (count($user_list)) - { - // Session time?! Session time... - $sql = 'SELECT session_user_id, MAX(session_time) AS session_time - FROM ' . SESSIONS_TABLE . ' - WHERE session_time >= ' . (time() - $config['session_length']) . ' - AND ' . $db->sql_in_set('session_user_id', $user_list) . ' - GROUP BY session_user_id'; - $result = $db->sql_query($sql); - - $session_times = array(); - while ($row = $db->sql_fetchrow($result)) - { - $session_times[$row['session_user_id']] = $row['session_time']; - } - $db->sql_freeresult($result); - - // Do the SQL thang - if ($mode == 'group') - { - $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_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(); - while ($row = $db->sql_fetchrow($result)) - { - $row['session_time'] = (!empty($session_times[$row['user_id']])) ? $session_times[$row['user_id']] : 0; - $row['last_visit'] = (!empty($row['session_time'])) ? $row['session_time'] : $row['user_lastvisit']; - - $id_cache[$row['user_id']] = $row; - } - - $db->sql_freeresult($result); - - // 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 - $profile_fields_cache = $cp->grab_profile_fields_data($user_list); - - // Filter the fields we don't want to show - foreach ($profile_fields_cache as $user_id => $user_profile_fields) - { - foreach ($user_profile_fields as $field_ident => $profile_field) - { - if (!$profile_field['data']['field_show_on_ml']) - { - unset($profile_fields_cache[$user_id][$field_ident]); - } - } - } - } - - // If we sort by last active date we need to adjust the id cache due to user_lastvisit not being the last active date... - if ($sort_key == 'l') - { -// uasort($id_cache, create_function('$first, $second', "return (\$first['last_visit'] == \$second['last_visit']) ? 0 : ((\$first['last_visit'] < \$second['last_visit']) ? $lesser_than : ($lesser_than * -1));")); - usort($user_list, 'phpbb_sort_last_active'); - } - - // do we need to display contact fields as such - $use_contact_fields = true; - - /** - * Modify list of users before member row is created - * - * @event core.memberlist_memberrow_before - * @var array user_list Array containing list of users - * @var bool use_contact_fields Should we display contact fields as such? - * @since 3.1.7-RC1 - */ - $vars = array('user_list', 'use_contact_fields'); - extract($phpbb_dispatcher->trigger_event('core.memberlist_memberrow_before', compact($vars))); - - for ($i = 0, $end = count($user_list); $i < $end; ++$i) - { - $user_id = $user_list[$i]; - $row = $id_cache[$user_id]; - $is_leader = (isset($row['group_leader']) && $row['group_leader']) ? true : false; - $leaders_set = ($leaders_set || $is_leader); - - $cp_row = array(); - if ($config['load_cpf_memberlist']) - { - $cp_row = (isset($profile_fields_cache[$user_id])) ? $cp->generate_profile_fields_template_data($profile_fields_cache[$user_id], $use_contact_fields) : array(); - } - - $memberrow = array_merge(phpbb_show_profile($row, false, false, false), array( - 'ROW_NUMBER' => $i + ($start + 1), - - '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']) && count($cp_row['row'])) - { - $memberrow = array_merge($memberrow, $cp_row['row']); - } - - $template->assign_block_vars('memberrow', $memberrow); - - if (isset($cp_row['blockrow']) && count($cp_row['blockrow'])) - { - foreach ($cp_row['blockrow'] as $field_data) - { - $template->assign_block_vars('memberrow.custom_fields', $field_data); - } - } - - unset($id_cache[$user_id]); - } - } - - $pagination->generate_template_pagination($pagination_url, 'pagination', 'start', $total_users, $config['topics_per_page'], $start); - - // Generate page - $template_vars = array( - 'TOTAL_USERS' => $user->lang('LIST_USERS', (int) $total_users), - - 'PROFILE_IMG' => $user->img('icon_user_profile', $user->lang['PROFILE']), - 'PM_IMG' => $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE']), - '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']), - - 'U_FIND_MEMBER' => ($config['load_search'] || $auth->acl_get('a_')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser' . (($start) ? "&start=$start" : '') . (!empty($params) ? '&' . implode('&', $params) : '')) : '', - 'U_HIDE_FIND_MEMBER' => ($mode == 'searchuser' || ($mode == '' && $submit)) ? $u_hide_find_member : '', - 'U_LIVE_SEARCH' => ($config['allow_live_searches']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=livesearch') : false, - 'U_SORT_USERNAME' => $sort_url . '&sk=a&sd=' . (($sort_key == 'a' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_JOINED' => $sort_url . '&sk=c&sd=' . (($sort_key == 'c' && $sort_dir == 'd') ? 'a' : 'd'), - 'U_SORT_POSTS' => $sort_url . '&sk=d&sd=' . (($sort_key == 'd' && $sort_dir == 'd') ? 'a' : 'd'), - 'U_SORT_EMAIL' => $sort_url . '&sk=e&sd=' . (($sort_key == 'e' && $sort_dir == 'd') ? 'a' : 'd'), - 'U_SORT_ACTIVE' => ($auth->acl_get('u_viewonline')) ? $sort_url . '&sk=l&sd=' . (($sort_key == 'l' && $sort_dir == 'd') ? 'a' : 'd') : '', - 'U_SORT_RANK' => $sort_url . '&sk=m&sd=' . (($sort_key == 'm' && $sort_dir == 'd') ? 'a' : 'd'), - 'U_LIST_CHAR' => $sort_url . '&sk=a&sd=' . (($sort_key == 'l' && $sort_dir == 'd') ? 'a' : 'd'), - - 'S_SHOW_GROUP' => ($mode == 'group') ? true : false, - 'S_VIEWONLINE' => $auth->acl_get('u_viewonline'), - 'S_LEADERS_SET' => $leaders_set, - 'S_MODE_SELECT' => $s_sort_key, - 'S_ORDER_SELECT' => $s_sort_dir, - '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 -page_header($page_title); - -$template->set_filenames(array( - 'body' => $template_html) -); -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - -page_footer(); diff --git a/install/update/new/phpbb/auth/provider/apache.php b/install/update/new/phpbb/auth/provider/apache.php deleted file mode 100644 index a713674..0000000 --- a/install/update/new/phpbb/auth/provider/apache.php +++ /dev/null @@ -1,285 +0,0 @@ - -* @license 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; - -use phpbb\config\config; -use phpbb\db\driver\driver_interface; -use phpbb\language\language; -use phpbb\request\request_interface; -use phpbb\request\type_cast_helper; -use phpbb\user; - -/** -* Apache authentication provider for phpBB3 -*/ -class apache extends base -{ - /** @var config phpBB config */ - protected $config; - - /** @var driver_interface Database object */ - protected $db; - - /** @var language Language object */ - protected $language; - - /** @var request_interface Request object */ - protected $request; - - /** @var user User object */ - protected $user; - - /** @var string Relative path to phpBB root */ - protected $phpbb_root_path; - - /** @var string PHP file extension */ - protected $php_ext; - - /** - * Apache Authentication Constructor - * - * @param config $config Config object - * @param driver_interface $db Database object - * @param language $language Language object - * @param request_interface $request Request object - * @param user $user User object - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $php_ext PHP file extension - */ - public function __construct(config $config, driver_interface $db, language $language, request_interface $request, user $user, $phpbb_root_path, $php_ext) - { - $this->config = $config; - $this->db = $db; - $this->language = $language; - $this->request = $request; - $this->user = $user; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - } - - /** - * {@inheritdoc} - */ - public function init() - { - if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER) || $this->user->data['username'] !== htmlspecialchars_decode($this->request->server('PHP_AUTH_USER'))) - { - return $this->language->lang('APACHE_SETUP_BEFORE_USE'); - } - return false; - } - - /** - * {@inheritdoc} - */ - public function login($username, $password) - { - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER)) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $php_auth_user = htmlspecialchars_decode($this->request->server('PHP_AUTH_USER')); - $php_auth_pw = htmlspecialchars_decode($this->request->server('PHP_AUTH_PW')); - - if (!empty($php_auth_user) && !empty($php_auth_pw)) - { - if ($php_auth_user !== $username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type - FROM ' . USERS_TABLE . " - WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - - // this is the user's first login so create an empty profile - return array( - 'status' => LOGIN_SUCCESS_CREATE_PROFILE, - 'error_msg' => false, - 'user_row' => $this->user_row($php_auth_user), - ); - } - - // Not logged into apache - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - /** - * {@inheritdoc} - */ - public function autologin() - { - if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER)) - { - return array(); - } - - $php_auth_user = htmlspecialchars_decode($this->request->server('PHP_AUTH_USER')); - $php_auth_pw = htmlspecialchars_decode($this->request->server('PHP_AUTH_PW')); - - if (!empty($php_auth_user) && !empty($php_auth_pw)) - { - $type_cast_helper = new type_cast_helper(); - $type_cast_helper->set_var($php_auth_user, $php_auth_user, 'string', true); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - return ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ? array() : $row; - } - - if (!function_exists('user_add')) - { - include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); - } - - // create the user if he does not exist yet - user_add($this->user_row($php_auth_user)); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($php_auth_user)) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - return $row; - } - } - - return array(); - } - - /** - * This function generates an array which can be passed to the user_add - * function in order to create a user - * - * @param string $username The username of the new user. - * - * @return array Contains data that can be passed directly to - * the user_add function. - */ - private function user_row($username) - { - // first retrieve default 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) - { - trigger_error('NO_GROUP'); - } - - // generate user account data - return array( - 'username' => $username, - 'user_password' => '', - 'user_email' => '', - 'group_id' => (int) $row['group_id'], - 'user_type' => USER_NORMAL, - 'user_ip' => $this->user->ip, - 'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0, - ); - } - - /** - * {@inheritdoc} - */ - public function validate_session($user) - { - // Check if PHP_AUTH_USER is set and handle this case - if ($this->request->is_set('PHP_AUTH_USER', request_interface::SERVER)) - { - $php_auth_user = $this->request->server('PHP_AUTH_USER'); - - return ($php_auth_user === $user['username']) ? true : false; - } - - // PHP_AUTH_USER is not set. A valid session is now determined by the user type (anonymous/bot or not) - if ($user['user_type'] == USER_IGNORE) - { - return true; - } - - return false; - } -} diff --git a/install/update/new/phpbb/auth/provider/base.php b/install/update/new/phpbb/auth/provider/base.php deleted file mode 100644 index 30e0a0f..0000000 --- a/install/update/new/phpbb/auth/provider/base.php +++ /dev/null @@ -1,108 +0,0 @@ - -* @license 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; - -/** -* Base authentication provider class that all other providers should implement -*/ -abstract class base implements provider_interface -{ - /** - * {@inheritdoc} - */ - public function init() - { - return; - } - - /** - * {@inheritdoc} - */ - public function autologin() - { - return; - } - - /** - * {@inheritdoc} - */ - public function acp() - { - return; - } - - /** - * {@inheritdoc} - */ - public function get_acp_template($new_config) - { - return; - } - - /** - * {@inheritdoc} - */ - public function get_login_data() - { - return; - } - - /** - * {@inheritdoc} - */ - public function get_auth_link_data($user_id = 0) - { - return; - } - - /** - * {@inheritdoc} - */ - public function logout($data, $new_session) - { - return; - } - - /** - * {@inheritdoc} - */ - public function validate_session($user) - { - return; - } - - /** - * {@inheritdoc} - */ - public function login_link_has_necessary_data($login_link_data) - { - return; - } - - /** - * {@inheritdoc} - */ - public function link_account(array $link_data) - { - return; - } - - /** - * {@inheritdoc} - */ - public function unlink_account(array $link_data) - { - return; - } -} diff --git a/install/update/new/phpbb/auth/provider/db.php b/install/update/new/phpbb/auth/provider/db.php deleted file mode 100644 index a70734f..0000000 --- a/install/update/new/phpbb/auth/provider/db.php +++ /dev/null @@ -1,259 +0,0 @@ - -* @license 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; - -use phpbb\captcha\factory; -use phpbb\config\config; -use phpbb\db\driver\driver_interface; -use phpbb\passwords\manager; -use phpbb\request\request_interface; -use phpbb\user; - -/** - * Database authentication provider for phpBB3 - * This is for authentication via the integrated user table - */ -class db extends base -{ - /** @var factory CAPTCHA factory */ - protected $captcha_factory; - - /** @var config phpBB config */ - protected $config; - - /** @var driver_interface DBAL driver instance */ - protected $db; - - /** @var request_interface Request object */ - protected $request; - - /** @var user User object */ - protected $user; - - /** @var string phpBB root path */ - protected $phpbb_root_path; - - /** @var string PHP file extension */ - protected $php_ext; - - /** - * phpBB passwords manager - * - * @var manager - */ - protected $passwords_manager; - - /** - * Database Authentication Constructor - * - * @param factory $captcha_factory - * @param config $config - * @param driver_interface $db - * @param manager $passwords_manager - * @param request_interface $request - * @param user $user - * @param string $phpbb_root_path - * @param string $php_ext - */ - public function __construct(factory $captcha_factory, config $config, driver_interface $db, manager $passwords_manager, request_interface $request, user $user, $phpbb_root_path, $php_ext) - { - $this->captcha_factory = $captcha_factory; - $this->config = $config; - $this->db = $db; - $this->passwords_manager = $passwords_manager; - $this->request = $request; - $this->user = $user; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - } - - /** - * {@inheritdoc} - */ - public function login($username, $password) - { - // Auth plugins get the password untrimmed. - // For compatibility we trim() here. - $password = trim($password); - - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $username_clean = utf8_clean_string($username); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if (($this->user->ip && !$this->config['ip_login_limit_use_forwarded']) || - ($this->user->forwarded_for && $this->config['ip_login_limit_use_forwarded'])) - { - $sql = 'SELECT COUNT(*) AS attempts - FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE attempt_time > ' . (time() - (int) $this->config['ip_login_limit_time']); - if ($this->config['ip_login_limit_use_forwarded']) - { - $sql .= " AND attempt_forwarded_for = '" . $this->db->sql_escape($this->user->forwarded_for) . "'"; - } - else - { - $sql .= " AND attempt_ip = '" . $this->db->sql_escape($this->user->ip) . "' "; - } - - $result = $this->db->sql_query($sql); - $attempts = (int) $this->db->sql_fetchfield('attempts'); - $this->db->sql_freeresult($result); - - $attempt_data = array( - 'attempt_ip' => $this->user->ip, - 'attempt_browser' => trim(substr($this->user->browser, 0, 149)), - 'attempt_forwarded_for' => $this->user->forwarded_for, - 'attempt_time' => time(), - 'user_id' => ($row) ? (int) $row['user_id'] : 0, - 'username' => $username, - 'username_clean' => $username_clean, - ); - $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $this->db->sql_build_array('INSERT', $attempt_data); - $this->db->sql_query($sql); - } - else - { - $attempts = 0; - } - - if (!$row) - { - if ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']) - { - return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $show_captcha = ($this->config['max_login_attempts'] && $row['user_login_attempts'] >= $this->config['max_login_attempts']) || - ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']); - - // If there are too many login attempts, we need to check for a confirm image - // Every auth module is able to define what to do by itself... - if ($show_captcha) - { - $captcha = $this->captcha_factory->get_instance($this->config['captcha_plugin']); - $captcha->init(CONFIRM_LOGIN); - $vc_response = $captcha->validate($row); - if ($vc_response) - { - return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', - 'user_row' => $row, - ); - } - else - { - $captcha->reset(); - } - - } - - // Check password ... - if ($this->passwords_manager->check($password, $row['user_password'], $row)) - { - // Check for old password hash... - if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32) - { - $hash = $this->passwords_manager->hash($password); - - // Update the password in the users table to the new format - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_password = '" . $this->db->sql_escape($hash) . "' - WHERE user_id = {$row['user_id']}"; - $this->db->sql_query($sql); - - $row['user_password'] = $hash; - } - - $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE user_id = ' . $row['user_id']; - $this->db->sql_query($sql); - - if ($row['user_login_attempts'] != 0) - { - // Successful, reset login attempts (the user passed all stages) - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_login_attempts = 0 - WHERE user_id = ' . $row['user_id']; - $this->db->sql_query($sql); - } - - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... set user_login_attempts to zero... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - - // Password incorrect - increase login attempts - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_login_attempts = user_login_attempts + 1 - WHERE user_id = ' . (int) $row['user_id'] . ' - AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX; - $this->db->sql_query($sql); - - // Give status about wrong password... - return array( - 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, - 'error_msg' => 'LOGIN_ERROR_PASSWORD', - 'user_row' => $row, - ); - } -} diff --git a/install/update/new/phpbb/auth/provider/ldap.php b/install/update/new/phpbb/auth/provider/ldap.php deleted file mode 100644 index 43699f7..0000000 --- a/install/update/new/phpbb/auth/provider/ldap.php +++ /dev/null @@ -1,359 +0,0 @@ - -* @license 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; - -use phpbb\config\config; -use phpbb\db\driver\driver_interface; -use phpbb\language\language; -use phpbb\user; - -/** - * Database authentication provider for phpBB3 - * This is for authentication via the integrated user table - */ -class ldap extends base -{ - /** @var config phpBB config */ - protected $config; - - /** @var driver_interface DBAL driver interface */ - protected $db; - - /** @var language phpBB language class */ - protected $language; - - /** @var user phpBB user */ - protected $user; - - /** - * LDAP Authentication Constructor - * - * @param config $config Config object - * @param driver_interface $db DBAL driver interface - * @param language $language Language object - * @param user $user User object - */ - public function __construct(config $config, driver_interface $db, language $language, user $user) - { - $this->config = $config; - $this->db = $db; - $this->language = $language; - $this->user = $user; - } - - /** - * {@inheritdoc} - */ - public function init() - { - if (!@extension_loaded('ldap')) - { - return $this->language->lang('LDAP_NO_LDAP_EXTENSION'); - } - - $this->config['ldap_port'] = (int) $this->config['ldap_port']; - if ($this->config['ldap_port']) - { - $ldap = @ldap_connect($this->config['ldap_server'], $this->config['ldap_port']); - } - else - { - $ldap = @ldap_connect($this->config['ldap_server']); - } - - if (!$ldap) - { - return $this->language->lang('LDAP_NO_SERVER_CONNECTION'); - } - - @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); - @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); - - if ($this->config['ldap_user'] || $this->config['ldap_password']) - { - if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password']))) - { - return $this->language->lang('LDAP_INCORRECT_USER_PASSWORD'); - } - } - - // ldap_connect only checks whether the specified server is valid, so the connection might still fail - $search = @ldap_search( - $ldap, - htmlspecialchars_decode($this->config['ldap_base_dn']), - $this->ldap_user_filter($this->user->data['username']), - (empty($this->config['ldap_email'])) ? - array(htmlspecialchars_decode($this->config['ldap_uid'])) : - array(htmlspecialchars_decode($this->config['ldap_uid']), htmlspecialchars_decode($this->config['ldap_email'])), - 0, - 1 - ); - - if ($search === false) - { - return $this->language->lang('LDAP_SEARCH_FAILED'); - } - - $result = @ldap_get_entries($ldap, $search); - - @ldap_close($ldap); - - if (!is_array($result) || count($result) < 2) - { - return $this->language->lang('LDAP_NO_IDENTITY', $this->user->data['username']); - } - - if (!empty($this->config['ldap_email']) && !isset($result[0][htmlspecialchars_decode($this->config['ldap_email'])])) - { - return $this->language->lang('LDAP_NO_EMAIL'); - } - - return false; - } - - /** - * {@inheritdoc} - */ - public function login($username, $password) - { - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!@extension_loaded('ldap')) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_LDAP_EXTENSION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $this->config['ldap_port'] = (int) $this->config['ldap_port']; - if ($this->config['ldap_port']) - { - $ldap = @ldap_connect($this->config['ldap_server'], $this->config['ldap_port']); - } - else - { - $ldap = @ldap_connect($this->config['ldap_server']); - } - - if (!$ldap) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); - @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); - - if ($this->config['ldap_user'] || $this->config['ldap_password']) - { - if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password']))) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - } - - $search = @ldap_search( - $ldap, - htmlspecialchars_decode($this->config['ldap_base_dn']), - $this->ldap_user_filter($username), - (empty($this->config['ldap_email'])) ? - array(htmlspecialchars_decode($this->config['ldap_uid'])) : - array(htmlspecialchars_decode($this->config['ldap_uid']), htmlspecialchars_decode($this->config['ldap_email'])), - 0, - 1 - ); - - $ldap_result = @ldap_get_entries($ldap, $search); - - if (is_array($ldap_result) && count($ldap_result) > 1) - { - if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password))) - { - @ldap_close($ldap); - - $sql ='SELECT user_id, username, user_password, user_passchg, user_email, user_type - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - unset($ldap_result); - - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... set user_login_attempts to zero... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - else - { - // retrieve default group id - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $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) - { - trigger_error('NO_GROUP'); - } - - // generate user account data - $ldap_user_row = array( - 'username' => $username, - 'user_password' => '', - 'user_email' => (!empty($this->config['ldap_email'])) ? utf8_htmlspecialchars($ldap_result[0][htmlspecialchars_decode($this->config['ldap_email'])][0]) : '', - 'group_id' => (int) $row['group_id'], - 'user_type' => USER_NORMAL, - 'user_ip' => $this->user->ip, - 'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0, - ); - - unset($ldap_result); - - // this is the user's first login so create an empty profile - return array( - 'status' => LOGIN_SUCCESS_CREATE_PROFILE, - 'error_msg' => false, - 'user_row' => $ldap_user_row, - ); - } - } - else - { - unset($ldap_result); - @ldap_close($ldap); - - // Give status about wrong password... - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'LOGIN_ERROR_PASSWORD', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - } - - @ldap_close($ldap); - - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - /** - * {@inheritdoc} - */ - public function acp() - { - // These are fields required in the config table - return array( - 'ldap_server', 'ldap_port', 'ldap_base_dn', 'ldap_uid', 'ldap_user_filter', 'ldap_email', 'ldap_user', 'ldap_password', - ); - } - - /** - * {@inheritdoc} - */ - public function get_acp_template($new_config) - { - return array( - 'TEMPLATE_FILE' => 'auth_provider_ldap.html', - 'TEMPLATE_VARS' => array( - 'AUTH_LDAP_BASE_DN' => $new_config['ldap_base_dn'], - 'AUTH_LDAP_EMAIL' => $new_config['ldap_email'], - 'AUTH_LDAP_PASSORD' => $new_config['ldap_password'] !== '' ? '********' : '', - 'AUTH_LDAP_PORT' => $new_config['ldap_port'], - 'AUTH_LDAP_SERVER' => $new_config['ldap_server'], - 'AUTH_LDAP_UID' => $new_config['ldap_uid'], - 'AUTH_LDAP_USER' => $new_config['ldap_user'], - 'AUTH_LDAP_USER_FILTER' => $new_config['ldap_user_filter'], - ), - ); - } - - /** - * Generates a filter string for ldap_search to find a user - * - * @param $username string Username identifying the searched user - * - * @return string A filter string for ldap_search - */ - private function ldap_user_filter($username) - { - $filter = '(' . $this->config['ldap_uid'] . '=' . $this->ldap_escape(htmlspecialchars_decode($username)) . ')'; - if ($this->config['ldap_user_filter']) - { - $_filter = ($this->config['ldap_user_filter'][0] == '(' && substr($this->config['ldap_user_filter'], -1) == ')') ? $this->config['ldap_user_filter'] : "({$this->config['ldap_user_filter']})"; - $filter = "(&{$filter}{$_filter})"; - } - return $filter; - } - - /** - * Escapes an LDAP AttributeValue - * - * @param string $string The string to be escaped - * @return string The escaped string - */ - private function ldap_escape($string) - { - return str_replace(array('*', '\\', '(', ')'), array('\\*', '\\\\', '\\(', '\\)'), $string); - } -} diff --git a/install/update/new/phpbb/auth/provider/oauth/oauth.php b/install/update/new/phpbb/auth/provider/oauth/oauth.php deleted file mode 100644 index 29ffe6d..0000000 --- a/install/update/new/phpbb/auth/provider/oauth/oauth.php +++ /dev/null @@ -1,859 +0,0 @@ - - * @license 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; - -use OAuth\Common\Http\Exception\TokenResponseException; -use OAuth\ServiceFactory; -use OAuth\Common\Consumer\Credentials; -use OAuth\Common\Service\ServiceInterface; -use OAuth\OAuth1\Service\AbstractService as OAuth1Service; -use OAuth\OAuth2\Service\AbstractService as OAuth2Service; -use phpbb\auth\provider\base; -use phpbb\auth\provider\db; -use phpbb\auth\provider\oauth\service\exception; -use phpbb\config\config; -use phpbb\db\driver\driver_interface; -use phpbb\di\service_collection; -use phpbb\event\dispatcher; -use phpbb\language\language; -use phpbb\request\request_interface; -use phpbb\user; - -/** - * OAuth authentication provider for phpBB3 - */ -class oauth extends base -{ - /** @var config */ - protected $config; - - /** @var driver_interface */ - protected $db; - - /** @var db */ - protected $db_auth; - - /** @var dispatcher */ - protected $dispatcher; - - /** @var language */ - protected $language; - - /** @var request_interface */ - protected $request; - - /** @var service_collection */ - protected $service_providers; - - /** @var user */ - protected $user; - - /** @var string OAuth table: token storage */ - protected $oauth_token_table; - - /** @var string OAuth table: state */ - protected $oauth_state_table; - - /** @var string OAuth table: account association */ - protected $oauth_account_table; - - /** @var string Users table */ - protected $users_table; - - /** @var string phpBB root path */ - protected $root_path; - - /** @var string php File extension */ - protected $php_ext; - - /** - * Constructor. - * - * @param config $config Config object - * @param driver_interface $db Database object - * @param db $db_auth DB auth provider - * @param dispatcher $dispatcher Event dispatcher object - * @param language $language Language object - * @param request_interface $request Request object - * @param service_collection $service_providers OAuth providers service collection - * @param user $user User object - * @param string $oauth_token_table OAuth table: token storage - * @param string $oauth_state_table OAuth table: state - * @param string $oauth_account_table OAuth table: account association - * @param string $users_table User table - * @param string $root_path phpBB root path - * @param string $php_ext php File extension - */ - public function __construct( - config $config, - driver_interface $db, - db $db_auth, - dispatcher $dispatcher, - language $language, - request_interface $request, - service_collection $service_providers, - user $user, - $oauth_token_table, - $oauth_state_table, - $oauth_account_table, - $users_table, - $root_path, - $php_ext - ) - { - $this->config = $config; - $this->db = $db; - $this->db_auth = $db_auth; - $this->dispatcher = $dispatcher; - $this->language = $language; - $this->service_providers = $service_providers; - $this->request = $request; - $this->user = $user; - - $this->oauth_token_table = $oauth_token_table; - $this->oauth_state_table = $oauth_state_table; - $this->oauth_account_table = $oauth_account_table; - $this->users_table = $users_table; - $this->root_path = $root_path; - $this->php_ext = $php_ext; - } - - /** - * {@inheritdoc} - */ - public function init() - { - // This does not test whether or not the key and secret provided are valid. - foreach ($this->service_providers as $service_provider) - { - $credentials = $service_provider->get_service_credentials(); - - if (($credentials['key'] && !$credentials['secret']) || (!$credentials['key'] && $credentials['secret'])) - { - return $this->language->lang('AUTH_PROVIDER_OAUTH_ERROR_ELEMENT_MISSING'); - } - } - - return false; - } - - /** - * {@inheritdoc} - */ - public function login($username, $password) - { - // Temporary workaround for only having one authentication provider available - if (!$this->request->is_set('oauth_service')) - { - return $this->db_auth->login($username, $password); - } - - // Request the name of the OAuth service - $provider = $this->request->variable('oauth_service', '', false); - $service_name = $this->get_service_name($provider); - - if ($provider === '' || !array_key_exists($service_name, $this->service_providers)) - { - return [ - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST', - 'user_row' => ['user_id' => ANONYMOUS], - ]; - } - - // Get the service credentials for the given service - $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); - $query = 'mode=login&login=external&oauth_service=' . $provider; - - try - { - /** @var OAuth1Service|OAuth2Service $service */ - $service = $this->get_service($provider, $storage, $query); - } - catch (\Exception $e) - { - return [ - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => $e->getMessage(), - 'user_row' => ['user_id' => ANONYMOUS], - ]; - } - - if ($this->is_set_code($service)) - { - $this->service_providers[$service_name]->set_external_service_provider($service); - - try - { - $unique_id = $this->service_providers[$service_name]->perform_auth_login(); - } - catch (exception $e) - { - return [ - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => $e->getMessage(), - 'user_row' => ['user_id' => ANONYMOUS], - ]; - } - - /** - * Check to see if this provider is already associated with an account. - * - * Enforcing a data type to make sure it are strings and not integers, - * so values are quoted in the SQL WHERE statement. - */ - $data = [ - 'provider' => (string) utf8_strtolower($provider), - 'oauth_provider_id' => (string) $unique_id - ]; - - $sql = 'SELECT user_id - FROM ' . $this->oauth_account_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); - - $redirect_data = array( - 'auth_provider' => 'oauth', - 'login_link_oauth_service' => $provider, - ); - - /** - * 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 ServiceInterface service OAuth service - * @since 3.2.3-RC1 - * @changed 3.2.6-RC1 Added redirect_data - */ - $vars = [ - '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 - return [ - 'status' => LOGIN_SUCCESS_LINK_PROFILE, - 'error_msg' => 'LOGIN_OAUTH_ACCOUNT_NOT_LINKED', - 'user_row' => [], - 'redirect_data' => $redirect_data, - ]; - } - - // Retrieve the user's account - $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); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if (!$row) - { - return [ - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY', - 'user_row' => ['user_id' => ANONYMOUS], - ]; - } - - /** - * 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->root_path, $this->php_ext); - - $message = $this->language->lang($message, $till_date, '', ''); - $message .= !empty($ban['ban_give_reason']) ? '

' . $this->language->lang('BOARD_BAN_REASON', $ban['ban_give_reason']) : ''; - $message .= !empty($ban['ban_triggered_by']) ? '

' . $this->language->lang('BAN_TRIGGERED_BY_' . utf8_strtoupper($ban['ban_triggered_by'])) . '' : ''; - - return [ - '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 successfully logged in via OAuth. - * - * @event core.auth_oauth_login_after - * @var array row User row - * @since 3.1.11-RC1 - */ - $vars = [ - 'row', - ]; - extract($this->dispatcher->trigger_event('core.auth_oauth_login_after', compact($vars))); - - // The user is now authenticated and can be logged in - return [ - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ]; - } - else - { - return $this->set_redirect($service); - } - } - - /** - * {@inheritdoc} - */ - public function get_login_data() - { - $login_data = [ - 'TEMPLATE_FILE' => 'login_body_oauth.html', - 'BLOCK_VAR_NAME' => 'oauth', - 'BLOCK_VARS' => [], - ]; - - foreach ($this->service_providers as $service_name => $service_provider) - { - // Only include data if the credentials are set - $credentials = $service_provider->get_service_credentials(); - - if ($credentials['key'] && $credentials['secret']) - { - $provider = $this->get_provider($service_name); - $redirect_url = generate_board_url() . '/ucp.' . $this->php_ext . '?mode=login&login=external&oauth_service=' . $provider; - - $login_data['BLOCK_VARS'][$service_name] = [ - 'REDIRECT_URL' => redirect($redirect_url, true), - 'SERVICE_NAME' => $this->get_provider_title($provider), - ]; - } - } - - return $login_data; - } - - /** - * {@inheritdoc} - */ - public function acp() - { - $ret = []; - - foreach ($this->service_providers as $service_name => $service_provider) - { - $provider = $this->get_provider($service_name); - - $provider = utf8_strtolower($provider); - - $ret[] = 'auth_oauth_' . $provider . '_key'; - $ret[] = 'auth_oauth_' . $provider . '_secret'; - } - - return $ret; - } - - /** - * {@inheritdoc} - */ - public function get_acp_template($new_config) - { - $ret = [ - 'BLOCK_VAR_NAME' => 'oauth_services', - 'BLOCK_VARS' => [], - 'TEMPLATE_FILE' => 'auth_provider_oauth.html', - 'TEMPLATE_VARS' => [], - ]; - - foreach ($this->service_providers as $service_name => $service_provider) - { - $provider = $this->get_provider($service_name); - - $ret['BLOCK_VARS'][$provider] = [ - 'NAME' => $provider, - 'ACTUAL_NAME' => $this->get_provider_title($provider), - 'KEY' => $new_config['auth_oauth_' . utf8_strtolower($provider) . '_key'], - 'SECRET' => $new_config['auth_oauth_' . utf8_strtolower($provider) . '_secret'], - ]; - } - - return $ret; - } - - /** - * {@inheritdoc} - */ - public function login_link_has_necessary_data($login_link_data) - { - if (empty($login_link_data)) - { - return 'LOGIN_LINK_NO_DATA_PROVIDED'; - } - - if (!array_key_exists('oauth_service', $login_link_data) || !$login_link_data['oauth_service'] || - !array_key_exists('link_method', $login_link_data) || !$login_link_data['link_method']) - { - return 'LOGIN_LINK_MISSING_DATA'; - } - - return null; - } - - /** - * {@inheritdoc} - */ - public function link_account(array $link_data) - { - // Check for a valid link method (auth_link or login_link) - if (!array_key_exists('link_method', $link_data) || - !in_array($link_data['link_method'], ['auth_link', 'login_link'])) - { - return 'LOGIN_LINK_MISSING_DATA'; - } - - // We must have an oauth_service listed, check for it two ways - if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service']) - { - $link_data['oauth_service'] = $this->request->variable('oauth_service', ''); - - if (!$link_data['oauth_service']) - { - return 'LOGIN_LINK_MISSING_DATA'; - } - } - - $service_name = $this->get_service_name($link_data['oauth_service']); - - if (!array_key_exists($service_name, $this->service_providers)) - { - return 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST'; - } - - switch ($link_data['link_method']) - { - case 'auth_link': - return $this->link_account_auth_link($link_data, $service_name); - case 'login_link': - return $this->link_account_login_link($link_data, $service_name); - default: - return 'LOGIN_LINK_MISSING_DATA'; - } - } - - /** - * {@inheritdoc} - */ - public function logout($data, $new_session) - { - // Clear all tokens belonging to the user - $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); - $storage->clearAllTokens(); - - return; - } - - /** - * {@inheritdoc} - */ - public function get_auth_link_data($user_id = 0) - { - $user_ids = []; - $block_vars = []; - - $sql = 'SELECT oauth_provider_id, provider - FROM ' . $this->oauth_account_table . ' - WHERE user_id = ' . ($user_id > 0 ? (int) $user_id : (int) $this->user->data['user_id']); - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $user_ids[$row['provider']] = $row['oauth_provider_id']; - } - $this->db->sql_freeresult($result); - - foreach ($this->service_providers as $service_name => $service_provider) - { - // Only include data if the credentials are set - $credentials = $service_provider->get_service_credentials(); - - if ($credentials['key'] && $credentials['secret']) - { - $provider = $this->get_provider($service_name); - - $block_vars[$service_name] = [ - 'SERVICE_NAME' => $this->get_provider_title($provider), - 'UNIQUE_ID' => isset($user_ids[$provider]) ? $user_ids[$provider] : null, - 'HIDDEN_FIELDS' => [ - 'link' => !isset($user_ids[$provider]), - 'oauth_service' => $provider, - ], - ]; - } - } - - return [ - 'BLOCK_VAR_NAME' => 'oauth', - 'BLOCK_VARS' => $block_vars, - - 'TEMPLATE_FILE' => 'ucp_auth_link_oauth.html', - ]; - } - - /** - * {@inheritdoc} - */ - public function unlink_account(array $link_data) - { - if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service']) - { - return 'LOGIN_LINK_MISSING_DATA'; - } - - // Remove user specified in $link_data if possible - $user_id = isset($link_data['user_id']) ? $link_data['user_id'] : $this->user->data['user_id']; - - // Remove the link - $sql = 'DELETE FROM ' . $this->oauth_account_table . " - WHERE provider = '" . $this->db->sql_escape($link_data['oauth_service']) . "' - AND user_id = " . (int) $user_id; - $this->db->sql_query($sql); - - $service_name = $this->get_service_name($link_data['oauth_service']); - - // Clear all tokens belonging to the user on this service - $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); - $storage->clearToken($service_name); - - return false; - } - - /** - * Performs the account linking for login_link. - * - * @param array $link_data The same variable given to - * {@see \phpbb\auth\provider\provider_interface::link_account} - * @param string $service_name The name of the service being used in linking. - * @return string|false Returns a language key (string) if an error is encountered, - * or false on success. - */ - protected function link_account_login_link(array $link_data, $service_name) - { - $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); - - // Check for an access token, they should have one - if (!$storage->has_access_token_by_session($service_name)) - { - return 'LOGIN_LINK_ERROR_OAUTH_NO_ACCESS_TOKEN'; - } - - // Prepare for an authentication request - $query = 'mode=login_link&login_link_oauth_service=' . $link_data['oauth_service']; - - try - { - $service = $this->get_service($link_data['oauth_service'], $storage, $query); - } - catch (\Exception $e) - { - return $e->getMessage(); - } - - $this->service_providers[$service_name]->set_external_service_provider($service); - - try - { - // The user has already authenticated successfully, request to authenticate again - $unique_id = $this->service_providers[$service_name]->perform_token_auth(); - } - catch (exception $e) - { - return $e->getMessage(); - } - - // Insert into table, they will be able to log in after this - $data = [ - 'user_id' => $link_data['user_id'], - 'provider' => utf8_strtolower($link_data['oauth_service']), - 'oauth_provider_id' => $unique_id, - ]; - - $this->link_account_perform_link($data); - - // Update token storage to store the user_id - $storage->set_user_id($link_data['user_id']); - - return false; - } - - /** - * Performs the account linking for auth_link. - * - * @param array $link_data The same variable given to - * {@see \phpbb\auth\provider\provider_interface::link_account} - * @param string $service_name The name of the service being used in linking. - * @return string|false Returns a language constant (string) if an error is encountered, - * or false on success. - */ - protected function link_account_auth_link(array $link_data, $service_name) - { - $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); - $query = 'i=ucp_auth_link&mode=auth_link&link=1&oauth_service=' . $link_data['oauth_service']; - - try - { - /** @var OAuth1Service|OAuth2Service $service */ - $service = $this->get_service($link_data['oauth_service'], $storage, $query); - } - catch (\Exception $e) - { - return $e->getMessage(); - } - - if ($this->is_set_code($service)) - { - $this->service_providers[$service_name]->set_external_service_provider($service); - - try - { - $unique_id = $this->service_providers[$service_name]->perform_auth_login(); - } - catch (exception $e) - { - return $e->getMessage(); - } - - // Insert into table, they will be able to log in after this - $data = [ - 'user_id' => $this->user->data['user_id'], - 'provider' => utf8_strtolower($link_data['oauth_service']), - 'oauth_provider_id' => $unique_id, - ]; - - $this->link_account_perform_link($data); - - return false; - } - else - { - return $this->set_redirect($service); - } - } - - /** - * Performs the query that inserts an account link - * - * @param array $data This array is passed to db->sql_build_array - */ - 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->oauth_account_table . " - 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->oauth_account_table . ' ' . $this->db->sql_build_array('INSERT', $data); - $this->db->sql_query($sql); - - /** - * Event is triggered after user links account. - * - * @event core.auth_oauth_link_after - * @var array data User row - * @since 3.1.11-RC1 - */ - $vars = [ - 'data', - ]; - extract($this->dispatcher->trigger_event('core.auth_oauth_link_after', compact($vars))); - } - - /** - * Returns a new service object. - * - * @param string $provider The name of the provider - * @param token_storage $storage Token storage object - * @param string $query The query string used for the redirect uri - * @return ServiceInterface - * @throws exception When OAuth service was not created - */ - protected function get_service($provider, token_storage $storage, $query) - { - $service_name = $this->get_service_name($provider); - - /** @see \phpbb\auth\provider\oauth\service\service_interface::get_service_credentials */ - $service_credentials = $this->service_providers[$service_name]->get_service_credentials(); - - /** @see \phpbb\auth\provider\oauth\service\service_interface::get_auth_scope */ - $scopes = $this->service_providers[$service_name]->get_auth_scope(); - - $callback = generate_board_url() . "/ucp.{$this->php_ext}?{$query}"; - - // Setup the credentials for the requests - $credentials = new Credentials( - $service_credentials['key'], - $service_credentials['secret'], - $callback - ); - - $service_factory = new ServiceFactory; - - // Allow providers to register a custom class or override the provider name - if ($class = $this->service_providers[$service_name]->get_external_service_class()) - { - if (class_exists($class)) - { - try - { - $service_factory->registerService($provider, $class); - } - catch (\OAuth\Common\Exception\Exception $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - } - else - { - $provider = $class; - } - } - - $service = $service_factory->createService($provider, $credentials, $storage, $scopes); - - if (!$service) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_SERVICE_NOT_CREATED'); - } - - return $service; - } - - /** - * Returns the service name for an OAuth provider name. - * - * @param string $provider The OAuth provider name - * @return string The service name - */ - protected function get_service_name($provider) - { - if (strpos($provider, 'auth.provider.oauth.service.') !== 0) - { - $provider = 'auth.provider.oauth.service.' . utf8_strtolower($provider); - } - - return $provider; - } - - /** - * Returns the OAuth provider name from a service name. - * - * @param string $service_name The service name - * @return string The OAuth provider name - */ - protected function get_provider($service_name) - { - return str_replace('auth.provider.oauth.service.', '', $service_name); - } - - /** - * Returns the localized title for the OAuth provider. - * - * @param string $provider The OAuth provider name - * @return string The OAuth provider title - */ - protected function get_provider_title($provider) - { - return $this->language->lang('AUTH_PROVIDER_OAUTH_SERVICE_' . utf8_strtoupper($provider)); - } - - /** - * Returns whether or not the authorization code is set. - * - * @param OAuth1Service|OAuth2Service $service The external OAuth service - * @return bool Whether or not the authorization code is set in the URL - * for the respective OAuth service's version - */ - protected function is_set_code($service) - { - switch ($service::OAUTH_VERSION) - { - case 1: - return $this->request->is_set('oauth_token', request_interface::GET); - - case 2: - return $this->request->is_set('code', request_interface::GET); - - default: - return false; - } - } - - /** - * Sets a redirect to the authorization uri. - * - * @param OAuth1Service|OAuth2Service $service The external OAuth service - * @return array|false Array if an error occurred, - * false on success - */ - protected function set_redirect($service) - { - $parameters = []; - - if ($service::OAUTH_VERSION === 1) - { - try - { - $token = $service->requestRequestToken(); - $parameters = ['oauth_token' => $token->getRequestToken()]; - } - catch (TokenResponseException $e) - { - return [ - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => $e->getMessage(), - 'user_row' => ['user_id' => ANONYMOUS], - ]; - } - } - - redirect($service->getAuthorizationUri($parameters), false, true); - - return false; - } -} diff --git a/install/update/new/phpbb/auth/provider/oauth/service/base.php b/install/update/new/phpbb/auth/provider/oauth/service/base.php deleted file mode 100644 index 5ab426a..0000000 --- a/install/update/new/phpbb/auth/provider/oauth/service/base.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @license 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; - -/** - * Base OAuth abstract class that all OAuth services should implement - */ -abstract class base implements service_interface -{ - /** - * External OAuth service provider - * - * @var \OAuth\Common\Service\ServiceInterface - */ - protected $service_provider; - - /** - * {@inheritdoc} - */ - public function get_auth_scope() - { - return []; - } - - /** - * {@inheritdoc} - */ - public function get_external_service_class() - { - return ''; - } - - /** - * {@inheritdoc} - */ - public function get_external_service_provider() - { - return $this->service_provider; - } - - /** - * {@inheritdoc} - */ - public function set_external_service_provider(\OAuth\Common\Service\ServiceInterface $service_provider) - { - $this->service_provider = $service_provider; - } -} diff --git a/install/update/new/phpbb/auth/provider/oauth/service/bitly.php b/install/update/new/phpbb/auth/provider/oauth/service/bitly.php deleted file mode 100644 index ca131b2..0000000 --- a/install/update/new/phpbb/auth/provider/oauth/service/bitly.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @license 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; - -/** - * Bitly OAuth service - */ -class bitly extends base -{ - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\request\request_interface */ - protected $request; - - /** - * Constructor. - * - * @param \phpbb\config\config $config Config object - * @param \phpbb\request\request_interface $request Request object - */ - 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 [ - 'key' => $this->config['auth_oauth_bitly_key'], - 'secret' => $this->config['auth_oauth_bitly_secret'], - ]; - } - - /** - * {@inheritdoc} - */ - public function perform_auth_login() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Bitly)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - try - { - // This was a callback request, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); - } - catch (\OAuth\Common\Http\Exception\TokenResponseException $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - try - { - // Send a request with it - $result = (array) json_decode($this->service_provider->request('user/info'), true); - } - catch (\OAuth\Common\Exception\Exception $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - // Return the unique identifier returned from bitly - return $result['data']['login']; - } - - /** - * {@inheritdoc} - */ - public function perform_token_auth() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Bitly)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - try - { - // Send a request with it - $result = (array) json_decode($this->service_provider->request('user/info'), true); - } - catch (\OAuth\Common\Exception\Exception $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - // Return the unique identifier - return $result['data']['login']; - } -} diff --git a/install/update/new/phpbb/auth/provider/oauth/service/facebook.php b/install/update/new/phpbb/auth/provider/oauth/service/facebook.php deleted file mode 100644 index f7dbe30..0000000 --- a/install/update/new/phpbb/auth/provider/oauth/service/facebook.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @license 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; - -/** - * Facebook OAuth service - */ -class facebook extends base -{ - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\request\request_interface */ - protected $request; - - /** - * Constructor. - * - * @param \phpbb\config\config $config Config object - * @param \phpbb\request\request_interface $request Request object - */ - 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 [ - 'key' => $this->config['auth_oauth_facebook_key'], - 'secret' => $this->config['auth_oauth_facebook_secret'], - ]; - } - - /** - * {@inheritdoc} - */ - public function perform_auth_login() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - try - { - // This was a callback request, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); - } - catch (\OAuth\Common\Http\Exception\TokenResponseException $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - try - { - // Send a request with it - $result = (array) json_decode($this->service_provider->request('/me'), true); - } - catch (\OAuth\Common\Exception\Exception $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - // Return the unique identifier - return $result['id']; - } - - /** - * {@inheritdoc} - */ - public function perform_token_auth() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - try - { - // Send a request with it - $result = (array) json_decode($this->service_provider->request('/me'), true); - } - catch (\OAuth\Common\Exception\Exception $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - // Return the unique identifier - return $result['id']; - } -} diff --git a/install/update/new/phpbb/auth/provider/oauth/service/google.php b/install/update/new/phpbb/auth/provider/oauth/service/google.php deleted file mode 100644 index 6e671ab..0000000 --- a/install/update/new/phpbb/auth/provider/oauth/service/google.php +++ /dev/null @@ -1,118 +0,0 @@ - - * @license 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; - -/** - * Google OAuth service - */ -class google extends base -{ - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\request\request_interface */ - protected $request; - - /** - * Constructor. - * - * @param \phpbb\config\config $config Config object - * @param \phpbb\request\request_interface $request Request object - */ - public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request) - { - $this->config = $config; - $this->request = $request; - } - - /** - * {@inheritdoc} - */ - public function get_auth_scope() - { - return [ - 'userinfo_email', - 'userinfo_profile', - ]; - } - - /** - * {@inheritdoc} - */ - public function get_service_credentials() - { - return [ - 'key' => $this->config['auth_oauth_google_key'], - 'secret' => $this->config['auth_oauth_google_secret'], - ]; - } - - /** - * {@inheritdoc} - */ - public function perform_auth_login() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Google)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - try - { - // This was a callback request, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); - } - catch (\OAuth\Common\Http\Exception\TokenResponseException $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - try - { - // Send a request with it - $result = (array) json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true); - } - catch (\OAuth\Common\Exception\Exception $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - // Return the unique identifier - return $result['id']; - } - - /** - * {@inheritdoc} - */ - public function perform_token_auth() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Google)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - try - { - // Send a request with it - $result = (array) json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true); - } - catch (\OAuth\Common\Exception\Exception $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - // Return the unique identifier - return $result['id']; - } -} diff --git a/install/update/new/phpbb/auth/provider/oauth/service/service_interface.php b/install/update/new/phpbb/auth/provider/oauth/service/service_interface.php deleted file mode 100644 index 239e661..0000000 --- a/install/update/new/phpbb/auth/provider/oauth/service/service_interface.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @license 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; - -/** - * OAuth service interface - */ -interface service_interface -{ - /** - * Returns an array of the scopes necessary for auth - * - * @return array An array of the required scopes - */ - public function get_auth_scope(); - - /** - * Returns an array containing the service credentials belonging to requested - * service. - * - * @return array An array containing the 'key' and the 'secret' of the - * service in the form: - * array( - * 'key' => string - * 'secret' => string - * ) - */ - public function get_service_credentials(); - - /** - * Returns the results of the authentication in json format - * - * @throws \phpbb\auth\provider\oauth\service\exception - * @return string The unique identifier returned by the service provider - * that is used to authenticate the user with phpBB. - */ - public function perform_auth_login(); - - /** - * Returns the results of the authentication in json format - * Use this function when the user already has an access token - * - * @throws \phpbb\auth\provider\oauth\service\exception - * @return string The unique identifier returned by the service provider - * that is used to authenticate the user with phpBB. - */ - public function perform_token_auth(); - - /** - * Returns the class of external library service provider that has to be used. - * - * @return string If the string is a class, it will register the provided string as a class, - * which later will be generated as the OAuth external service provider. - * If the string is not a class, it will use this string, - * trying to generate a service for the version 2 and 1 respectively: - * \OAuth\OAuth2\Service\ - * If the string is empty, it will default to OAuth's standard service classes, - * trying to generate a service for the version 2 and 1 respectively: - * \OAuth\OAuth2\Service\Facebook - */ - public function get_external_service_class(); - - /** - * Returns the external library service provider once it has been set - */ - public function get_external_service_provider(); - - /** - * Sets the external library service provider - * - * @param \OAuth\Common\Service\ServiceInterface $service_provider - */ - public function set_external_service_provider(\OAuth\Common\Service\ServiceInterface $service_provider); -} diff --git a/install/update/new/phpbb/auth/provider/oauth/service/twitter.php b/install/update/new/phpbb/auth/provider/oauth/service/twitter.php deleted file mode 100644 index 35cbc9e..0000000 --- a/install/update/new/phpbb/auth/provider/oauth/service/twitter.php +++ /dev/null @@ -1,111 +0,0 @@ - - * @license 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 base -{ - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\request\request_interface */ - protected $request; - - /** - * Constructor. - * - * @param \phpbb\config\config $config Config object - * @param \phpbb\request\request_interface $request Request object - */ - 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 [ - '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 exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - $storage = $this->service_provider->getStorage(); - - try - { - /** @var \OAuth\OAuth1\Token\TokenInterface $token */ - $token = $storage->retrieveAccessToken('Twitter'); - } - catch (\OAuth\Common\Storage\Exception\TokenNotFoundException $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - $secret = $token->getRequestTokenSecret(); - - try - { - // This was a callback request, get the token - $this->service_provider->requestAccessToken( - $this->request->variable('oauth_token', ''), - $this->request->variable('oauth_verifier', ''), - $secret - ); - } - catch (\OAuth\Common\Http\Exception\TokenResponseException $e) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); - } - - // Send a request with it - $result = (array) json_decode($this->service_provider->request('account/verify_credentials.json'), true); - - // Return the unique identifier - return $result['id']; - } - - /** - * {@inheritdoc} - */ - public function perform_token_auth() - { - if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - // Send a request with it - $result = (array) json_decode($this->service_provider->request('account/verify_credentials.json'), true); - - // Return the unique identifier - return $result['id']; - } -} diff --git a/install/update/new/phpbb/auth/provider/oauth/token_storage.php b/install/update/new/phpbb/auth/provider/oauth/token_storage.php deleted file mode 100644 index c0f585d..0000000 --- a/install/update/new/phpbb/auth/provider/oauth/token_storage.php +++ /dev/null @@ -1,620 +0,0 @@ - - * @license 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; - -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 - */ -class token_storage implements TokenStorageInterface -{ - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\user */ - protected $user; - - /** @var string OAuth table: token storage */ - protected $oauth_token_table; - - /** @var string OAuth table: state */ - protected $oauth_state_table; - - /** @var TokenInterface OAuth token */ - protected $cachedToken; - - /** @var string OAuth state */ - protected $cachedState; - - /** - * Constructor. - * - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\user $user User object - * @param string $oauth_token_table OAuth table: token storage - * @param string $oauth_state_table OAuth table: state - */ - 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->oauth_token_table = $oauth_token_table; - $this->oauth_state_table = $oauth_state_table; - } - - /** - * {@inheritdoc} - */ - public function retrieveAccessToken($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedToken instanceof TokenInterface) - { - return $this->cachedToken; - } - - $data = [ - '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->_retrieve_access_token($data); - } - - /** - * {@inheritdoc} - */ - public function storeAccessToken($service, TokenInterface $token) - { - $service = $this->get_service_name_for_db($service); - - $this->cachedToken = $token; - - $data = [ - 'oauth_token' => $this->json_encode_token($token), - ]; - - $sql = 'UPDATE ' . $this->oauth_token_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $data) . ' - 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); - - if (!$this->db->sql_affectedrows()) - { - $data = [ - '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; - } - - /** - * {@inheritdoc} - */ - public function hasAccessToken($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedToken) - { - return true; - } - - $data = [ - '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->has_access_token($data); - } - - /** - * {@inheritdoc} - */ - public function clearToken($service) - { - $service = $this->get_service_name_for_db($service); - - $this->cachedToken = null; - - $sql = 'DELETE FROM ' . $this->oauth_token_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 clearAllTokens() - { - $this->cachedToken = null; - - $sql = 'DELETE FROM ' . $this->oauth_token_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; - } - - /** - * {@inheritdoc} - */ - public function storeAuthorizationState($service, $state) - { - $service = $this->get_service_name_for_db($service); - - $this->cachedState = $state; - - $data = [ - '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 = [ - '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 = [ - '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; - } - - /** - * Updates the user_id field in the database associated with the token. - * - * @param int $user_id The user identifier - * @return void - */ - public function set_user_id($user_id) - { - if (!$this->cachedToken) - { - return; - } - - $data = [ - 'user_id' => (int) $user_id, - ]; - - $sql = 'UPDATE ' . $this->oauth_token_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $data) . ' - WHERE user_id = ' . (int) $this->user->data['user_id'] . " - AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'"; - $this->db->sql_query($sql); - } - - /** - * Checks to see if an access token exists solely by the session_id of the user. - * - * @param string $service The OAuth service name - * @return bool true if the user's access token exists, - * false if the user's access token does not exist - */ - public function has_access_token_by_session($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedToken) - { - return true; - } - - $data = [ - 'session_id' => $this->user->data['session_id'], - 'provider' => $service, - ]; - - return $this->has_access_token($data); - } - - /** - * Checks to see if a state exists solely by the session_id of the user. - * - * @param string $service The OAuth service name - * @return bool true if the user's state exists, - * false if the user's state does not exist - */ - public function has_state_by_session($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedState) - { - return true; - } - - $data = [ - '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 The SQL WHERE data - * @return bool true if the user's access token exists, - * false if the user's access token does not exist - */ - protected function has_access_token($data) - { - return (bool) $this->get_access_token_row($data); - } - - /** - * A helper function that performs the query for retrieving access token functions by session. - * Also checks if the token is a valid token. - * - * @param string $service The OAuth service provider name - * @return TokenInterface - * @throws TokenNotFoundException - */ - public function retrieve_access_token_by_session($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedToken instanceof TokenInterface) - { - return $this->cachedToken; - } - - $data = [ - 'session_id' => $this->user->data['session_id'], - 'provider' => $service, - ]; - - return $this->_retrieve_access_token($data); - } - - /** - * A helper function that performs the query for retrieving state functions by session. - * - * @param string $service The OAuth service provider name - * @return string The OAuth state - * @throws AuthorizationStateNotFoundException - */ - public function retrieve_state_by_session($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedState) - { - return $this->cachedState; - } - - $data = [ - '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. - * - * @param array $data The SQL WHERE data - * @return TokenInterface - * @throws TokenNotFoundException - */ - protected function _retrieve_access_token($data) - { - $row = $this->get_access_token_row($data); - - if (!$row) - { - throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_NOT_STORED'); - } - - $token = $this->json_decode_token($row['oauth_token']); - - // Ensure that the token was serialized/unserialized correctly - if (!($token instanceof TokenInterface)) - { - $this->clearToken($data['provider']); - - throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED'); - } - - $this->cachedToken = $token; - - return $token; - } - - /** - * A helper function that performs the query for retrieve state functions. - * - * @param array $data The SQL WHERE data - * @return string The OAuth state - * @throws 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 The SQL WHERE data - * @return array|false array with the OAuth token row, - * false if the token does not exist - */ - protected function get_access_token_row($data) - { - $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 The SQL WHERE data - * @return array|false array with the OAuth state row, - * false if the state does not exist - */ - 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); - $this->db->sql_freeresult($result); - - return $row; - } - - /** - * A helper function that JSON encodes a TokenInterface's data. - * - * @param TokenInterface $token - * @return string The json encoded TokenInterface's data - */ - public function json_encode_token(TokenInterface $token) - { - $members = [ - 'accessToken' => $token->getAccessToken(), - 'endOfLife' => $token->getEndOfLife(), - 'extraParams' => $token->getExtraParams(), - 'refreshToken' => $token->getRefreshToken(), - - 'token_class' => get_class($token), - ]; - - // Handle additional data needed for OAuth1 tokens - if ($token instanceof StdOAuth1Token) - { - $members['requestToken'] = $token->getRequestToken(); - $members['requestTokenSecret'] = $token->getRequestTokenSecret(); - $members['accessTokenSecret'] = $token->getAccessTokenSecret(); - } - - return json_encode($members); - } - - /** - * A helper function that JSON decodes a data string and creates a TokenInterface. - * - * @param string $json The json encoded TokenInterface's data - * @return TokenInterface - * @throws TokenNotFoundException - */ - public function json_decode_token($json) - { - $token_data = json_decode($json, true); - - if ($token_data === null) - { - throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED'); - } - - $token_class = $token_data['token_class']; - $access_token = $token_data['accessToken']; - $refresh_token = $token_data['refreshToken']; - $endOfLife = $token_data['endOfLife']; - $extra_params = $token_data['extraParams']; - - /** - * Create the token - * @var TokenInterface $token - */ - $token = new $token_class($access_token, $refresh_token, TokenInterface::EOL_NEVER_EXPIRES, $extra_params); - $token->setEndOfLife($endOfLife); - - // Handle OAuth 1.0 specific elements - if ($token instanceof StdOAuth1Token) - { - $token->setRequestToken($token_data['requestToken']); - $token->setRequestTokenSecret($token_data['requestTokenSecret']); - $token->setAccessTokenSecret($token_data['accessTokenSecret']); - } - - return $token; - } - - /** - * Returns the service name as it must be stored in the database. - * - * @param string $provider The OAuth provider name - * @return string The OAuth service name - */ - protected function get_service_name_for_db($provider) - { - // Enforce the naming convention for oauth services - if (strpos($provider, 'auth.provider.oauth.service.') !== 0) - { - $provider = 'auth.provider.oauth.service.' . strtolower($provider); - } - - return $provider; - } -} diff --git a/install/update/new/phpbb/auth/provider/provider_interface.php b/install/update/new/phpbb/auth/provider/provider_interface.php deleted file mode 100644 index 21c73a3..0000000 --- a/install/update/new/phpbb/auth/provider/provider_interface.php +++ /dev/null @@ -1,198 +0,0 @@ - -* @license 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; - -/** -* The interface authentication provider classes have to implement. -*/ -interface provider_interface -{ - /** - * Checks whether the user is currently identified to the authentication - * provider. - * Called in acp_board while setting authentication plugins. - * Changing to an authentication provider will not be permitted in acp_board - * if there is an error. - * - * @return boolean|string False if the user is identified, otherwise an - * error message, or null if not implemented. - */ - public function init(); - - /** - * Performs login. - * - * @param string $username The name of the user being authenticated. - * @param string $password The password of the user. - * @return array An associative array of the format: - * array( - * 'status' => status constant - * 'error_msg' => string - * 'user_row' => array - * ) - * A fourth key of the array may be present: - * 'redirect_data' This key is only used when 'status' is - * equal to LOGIN_SUCCESS_LINK_PROFILE and its value is an - * associative array that is turned into GET variables on - * the redirect url. - */ - public function login($username, $password); - - /** - * Autologin function - * - * @return array|null containing the user row, empty if no auto login - * should take place, or null if not implemented. - */ - public function autologin(); - - /** - * This function is used to output any required fields in the authentication - * admin panel. It also defines any required configuration table fields. - * - * @return array|null Returns null if not implemented or an array of the - * configuration fields of the provider. - */ - public function acp(); - - /** - * This function updates the template with variables related to the acp - * options with whatever configuration values are passed to it as an array. - * It then returns the name of the acp file related to this authentication - * provider. - * - * @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: - * array( - * 'TEMPLATE_FILE' => string, - * 'TEMPLATE_VARS' => array(...), - * ) - * An optional third element may be added to this - * array: 'BLOCK_VAR_NAME'. If this is present, - * then its value should be a string that is used - * to designate the name of the loop used in the - * ACP template file. When this is present, an - * additional key named 'BLOCK_VARS' is required. - * This must be an array containing at least one - * array of variables that will be assigned during - * the loop in the template. An example of this is - * presented below: - * array( - * 'BLOCK_VAR_NAME' => string, - * 'BLOCK_VARS' => array( - * 'KEY IS UNIMPORTANT' => array(...), - * ), - * 'TEMPLATE_FILE' => string, - * 'TEMPLATE_VARS' => array(...), - * ) - */ - public function get_acp_template($new_config); - - /** - * Returns an array of data necessary to build custom elements on the login - * form. - * - * @return array|null If this function is not implemented on an auth - * provider then it returns null. If it is implemented - * it will return an array of up to four elements of - * which only 'TEMPLATE_FILE'. If 'BLOCK_VAR_NAME' is - * present then 'BLOCK_VARS' must also be present in - * the array. The fourth element 'VARS' is also - * optional. The array, with all four elements present - * looks like the following: - * array( - * 'TEMPLATE_FILE' => string, - * 'BLOCK_VAR_NAME' => string, - * 'BLOCK_VARS' => array(...), - * 'VARS' => array(...), - * ) - */ - public function get_login_data(); - - /** - * Performs additional actions during logout. - * - * @param array $data An array corresponding to - * \phpbb\session::data - * @param boolean $new_session True for a new session, false for no new - * session. - */ - public function logout($data, $new_session); - - /** - * The session validation function checks whether the user is still logged - * into phpBB. - * - * @param array $user - * @return boolean true if the given user is authenticated, false if the - * session should be closed, or null if not implemented. - */ - public function validate_session($user); - - /** - * Checks to see if $login_link_data contains all information except for the - * user_id of an account needed to successfully link an external account to - * a forum account. - * - * @param array $login_link_data Any data needed to link a phpBB account to - * an external account. - * @return string|null Returns a string with a language constant if there - * is data missing or null if there is no error. - */ - public function login_link_has_necessary_data($login_link_data); - - /** - * Links an external account to a phpBB account. - * - * @param array $link_data Any data needed to link a phpBB account to - * an external account. - */ - public function link_account(array $link_data); - - /** - * Returns an array of data necessary to build the ucp_auth_link page - * - * @param int $user_id User ID for whom the data should be retrieved. - * defaults to 0, which is not a valid ID. The method - * should fall back to the current user's ID in this - * case. - * @return array|null If this function is not implemented on an auth - * provider then it returns null. If it is implemented - * it will return an array of up to four elements of - * which only 'TEMPLATE_FILE'. If 'BLOCK_VAR_NAME' is - * present then 'BLOCK_VARS' must also be present in - * the array. The fourth element 'VARS' is also - * optional. The array, with all four elements present - * looks like the following: - * array( - * 'TEMPLATE_FILE' => string, - * 'BLOCK_VAR_NAME' => string, - * 'BLOCK_VARS' => array(...), - * 'VARS' => array(...), - * ) - */ - public function get_auth_link_data($user_id = 0); - - /** - * Unlinks an external account from a phpBB account. - * - * @param array $link_data Any data needed to unlink a phpBB account - * from a phpbb account. - */ - public function unlink_account(array $link_data); -} diff --git a/install/update/new/phpbb/avatar/driver/remote.php b/install/update/new/phpbb/avatar/driver/remote.php deleted file mode 100644 index b16549f..0000000 --- a/install/update/new/phpbb/avatar/driver/remote.php +++ /dev/null @@ -1,236 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\avatar\driver; - -/** -* Handles avatars hosted remotely -*/ -class remote extends \phpbb\avatar\driver\driver -{ - /** - * {@inheritdoc} - */ - public function get_data($row) - { - return array( - 'src' => $row['avatar'], - 'width' => $row['avatar_width'], - 'height' => $row['avatar_height'], - ); - } - - /** - * {@inheritdoc} - */ - public function prepare_form($request, $template, $user, $row, &$error) - { - $template->assign_vars(array( - 'AVATAR_REMOTE_WIDTH' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_remote_width', ''), - 'AVATAR_REMOTE_HEIGHT' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_remote_width', ''), - 'AVATAR_REMOTE_URL' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar']) ? $row['avatar'] : '', - )); - - return true; - } - - /** - * {@inheritdoc} - */ - 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); - - if (empty($url)) - { - return false; - } - - if (!preg_match('#^(http|https|ftp)://#i', $url)) - { - $url = 'http://' . $url; - } - - if (!function_exists('validate_data')) - { - require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); - } - - $validate_array = validate_data( - array( - 'url' => $url, - ), - array( - 'url' => array('string', true, 5, 255), - ) - ); - - $error = array_merge($error, $validate_array); - - if (!empty($error)) - { - 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) || - 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)) - { - $error[] = 'AVATAR_URL_INVALID'; - return false; - } - - // Get image dimensions - if (($width <= 0 || $height <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false)) - { - $error[] = 'UNABLE_GET_IMAGE_SIZE'; - return false; - } - - if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['height'] <= 0)) - { - $error[] = 'AVATAR_NO_SIZE'; - return false; - } - - $width = ($width && $height) ? $width : $image_data['width']; - $height = ($width && $height) ? $height : $image_data['height']; - - if ($width <= 0 || $height <= 0) - { - $error[] = 'AVATAR_NO_SIZE'; - return false; - } - - $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')) - { - // Timeout after 1 second - stream_set_timeout($file_stream, 1); - // read some data to ensure headers are present - fread($file_stream, 1024); - $meta = stream_get_meta_data($file_stream); - - if (isset($meta['wrapper_data']['headers']) && is_array($meta['wrapper_data']['headers'])) - { - $headers = $meta['wrapper_data']['headers']; - } - else if (isset($meta['wrapper_data']) && is_array($meta['wrapper_data'])) - { - $headers = $meta['wrapper_data']; - } - else - { - $headers = array(); - } - - foreach ($headers as $header) - { - $header = preg_split('/ /', $header, 2); - if (strtr(strtolower(trim($header[0], ':')), '_', '-') === 'content-type') - { - if (strpos($header[1], 'image/') !== 0) - { - $error[] = 'AVATAR_URL_INVALID'; - fclose($file_stream); - return false; - } - else - { - fclose($file_stream); - break; - } - } - } - } - else - { - $error[] = 'AVATAR_URL_INVALID'; - return false; - } - - if (!empty($image_data) && (!isset($types[$image_data['type']]) || !in_array($extension, $types[$image_data['type']]))) - { - if (!isset($types[$image_data['type']])) - { - $error[] = 'UNABLE_GET_IMAGE_SIZE'; - } - else - { - $error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data['type']][0], $extension); - } - - return false; - } - - if ($this->config['avatar_max_width'] || $this->config['avatar_max_height']) - { - if ($width > $this->config['avatar_max_width'] || $height > $this->config['avatar_max_height']) - { - $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height); - return false; - } - } - - if ($this->config['avatar_min_width'] || $this->config['avatar_min_height']) - { - if ($width < $this->config['avatar_min_width'] || $height < $this->config['avatar_min_height']) - { - $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height); - return false; - } - } - - return array( - 'avatar' => $url, - 'avatar_width' => $width, - 'avatar_height' => $height, - ); - } - - /** - * {@inheritdoc} - */ - public function get_template_name() - { - return 'ucp_avatar_options_remote.html'; - } -} diff --git a/install/update/new/phpbb/avatar/driver/upload.php b/install/update/new/phpbb/avatar/driver/upload.php deleted file mode 100644 index a5b704b..0000000 --- a/install/update/new/phpbb/avatar/driver/upload.php +++ /dev/null @@ -1,332 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\avatar\driver; - -/** -* Handles avatars uploaded to the board -*/ -class upload extends \phpbb\avatar\driver\driver -{ - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * @var \phpbb\event\dispatcher_interface - */ - 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\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\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->dispatcher = $dispatcher; - $this->files_factory = $files_factory; - $this->cache = $cache; - } - - /** - * {@inheritdoc} - */ - public function get_data($row) - { - $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $this->path_helper->get_web_root_path(); - - return array( - 'src' => $root_path . 'download/file.' . $this->php_ext . '?avatar=' . $row['avatar'], - 'width' => $row['avatar_width'], - 'height' => $row['avatar_height'], - ); - } - - /** - * {@inheritdoc} - */ - public function prepare_form($request, $template, $user, $row, &$error) - { - if (!$this->can_upload()) - { - return false; - } - - $template->assign_vars(array( - 'S_UPLOAD_AVATAR_URL' => ($this->config['allow_avatar_remote_upload']) ? true : false, - 'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'], - 'AVATAR_ALLOWED_EXTENSIONS' => implode(',', preg_replace('/^/', '.', $this->allowed_extensions)), - )); - - return true; - } - - /** - * {@inheritdoc} - */ - public function process_form($request, $template, $user, $row, &$error) - { - if (!$this->can_upload()) - { - return 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->handle_upload('files.types.form', 'avatar_upload_file'); - } - else if (!empty($this->config['allow_avatar_remote_upload']) && !empty($url)) - { - if (!preg_match('#^(http|https|ftp)://#i', $url)) - { - $url = 'http://' . $url; - } - - if (!function_exists('validate_data')) - { - require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); - } - - $validate_array = validate_data( - array( - 'url' => $url, - ), - array( - 'url' => array('string', true, 5, 255), - ) - ); - - $error = array_merge($error, $validate_array); - - if (!empty($error)) - { - return false; - } - - // 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)://(?:(.*?\.)*?[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)) - { - $error[] = 'AVATAR_URL_INVALID'; - return false; - } - - $file = $upload->handle_upload('files.types.remote', $url); - } - else - { - return false; - } - - $prefix = $this->config['avatar_salt'] . '_'; - $file->clean_filename('avatar', $prefix, $row['id']); - - // If there was an error during upload, then abort operation - if (count($file->error)) - { - $file->remove(); - $error = $file->error; - return false; - } - - // Calculate new destination - $destination = $this->config['avatar_path']; - - // Adjust destination path (no trailing slash) - if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\') - { - $destination = substr($destination, 0, -1); - } - - $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination); - if ($destination && ($destination[0] == '/' || $destination[0] == "\\")) - { - $destination = ''; - } - - $filedata = array( - 'filename' => $file->get('filename'), - 'filesize' => $file->get('filesize'), - 'mimetype' => $file->get('mimetype'), - 'extension' => $file->get('extension'), - 'physical_filename' => $file->get('realname'), - 'real_filename' => $file->get('uploadname'), - ); - - /** - * Before moving new file in place (and eventually overwriting the existing avatar with the newly uploaded avatar) - * - * @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', - 'error', - ); - extract($this->dispatcher->trigger_event('core.avatar_driver_upload_move_file_before', compact($vars))); - - unset($filedata); - - if (!count($error)) - { - // Move file and overwrite any existing image - $file->move_file($destination, true); - } - - // If there was an error during move, then clean up leftovers - $error = array_merge($error, $file->error); - if (count($error)) - { - $file->remove(); - return false; - } - - // Delete current avatar if not overwritten - $ext = substr(strrchr($row['avatar'], '.'), 1); - if ($ext && $ext !== $file->get('extension')) - { - $this->delete($row); - } - - return array( - 'avatar' => $row['id'] . '_' . time() . '.' . $file->get('extension'), - 'avatar_width' => $file->get('width'), - 'avatar_height' => $file->get('height'), - ); - } - - /** - * {@inheritdoc} - */ - public function prepare_form_acp($user) - { - return array( - 'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), - 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - ); - } - - /** - * {@inheritdoc} - */ - public function delete($row) - { - - $error = array(); - $destination = $this->config['avatar_path']; - $prefix = $this->config['avatar_salt'] . '_'; - $ext = substr(strrchr($row['avatar'], '.'), 1); - $filename = $this->phpbb_root_path . $destination . '/' . $prefix . $row['id'] . '.' . $ext; - - /** - * Before deleting an existing avatar - * - * @event core.avatar_driver_upload_delete_before - * @var string destination Destination directory where the file is going to be deleted - * @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 deleted - * @since 3.1.6-RC1 - */ - $vars = array( - 'destination', - 'prefix', - 'row', - 'error', - ); - extract($this->dispatcher->trigger_event('core.avatar_driver_upload_delete_before', compact($vars))); - - if (!count($error) && $this->filesystem->exists($filename)) - { - try - { - $this->filesystem->remove($filename); - return true; - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Fail is covered by return statement below - } - } - - return false; - } - - /** - * {@inheritdoc} - */ - public function get_template_name() - { - return 'ucp_avatar_options_upload.html'; - } - - /** - * Check if user is able to upload an avatar - * - * @return bool True if user can upload, false if not - */ - protected function can_upload() - { - 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/install/update/new/phpbb/cache/driver/memcached.php b/install/update/new/phpbb/cache/driver/memcached.php deleted file mode 100644 index fbb587a..0000000 --- a/install/update/new/phpbb/cache/driver/memcached.php +++ /dev/null @@ -1,148 +0,0 @@ - -* @license 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; - -if (!defined('PHPBB_ACM_MEMCACHED_PORT')) -{ - define('PHPBB_ACM_MEMCACHED_PORT', 11211); -} - -if (!defined('PHPBB_ACM_MEMCACHED_COMPRESS')) -{ - define('PHPBB_ACM_MEMCACHED_COMPRESS', true); -} - -if (!defined('PHPBB_ACM_MEMCACHED_HOST')) -{ - define('PHPBB_ACM_MEMCACHED_HOST', 'localhost'); -} - -if (!defined('PHPBB_ACM_MEMCACHED')) -{ - //can define multiple servers with host1/port1,host2/port2 format - define('PHPBB_ACM_MEMCACHED', PHPBB_ACM_MEMCACHED_HOST . '/' . PHPBB_ACM_MEMCACHED_PORT); -} - -/** -* ACM for Memcached -*/ -class memcached extends \phpbb\cache\driver\memory -{ - /** @var string Extension to use */ - protected $extension = 'memcached'; - - /** @var \Memcached Memcached class */ - protected $memcached; - - /** @var int Flags */ - protected $flags = 0; - - /** - * Memcached constructor - * - * @param string $memcached_servers Memcached servers string (optional) - */ - public function __construct($memcached_servers = '') - { - // Call the parent constructor - parent::__construct(); - - $memcached_servers = $memcached_servers ?: PHPBB_ACM_MEMCACHED; - - $this->memcached = new \Memcached(); - $this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); - // Memcached defaults to using compression, disable if we don't want - // to use it - if (!PHPBB_ACM_MEMCACHED_COMPRESS) - { - $this->memcached->setOption(\Memcached::OPT_COMPRESSION, false); - } - - $server_list = []; - foreach (explode(',', $memcached_servers) as $u) - { - if (preg_match('#(.*)/(\d+)#', $u, $parts)) - { - $server_list[] = [trim($parts[1]), (int) trim($parts[2])]; - } - } - - $this->memcached->addServers($server_list); - - if (empty($server_list) || empty($this->memcached->getStats())) - { - trigger_error('Could not connect to memcached server(s).'); - } - } - - /** - * {@inheritDoc} - */ - public function unload() - { - parent::unload(); - - unset($this->memcached); - } - - /** - * {@inheritDoc} - */ - public function purge() - { - $this->memcached->flush(); - - parent::purge(); - } - - /** - * Fetch an item from the cache - * - * @param string $var Cache key - * - * @return mixed Cached data - */ - protected function _read($var) - { - return $this->memcached->get($this->key_prefix . $var); - } - - /** - * Store data in the cache - * - * @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 - */ - protected function _write($var, $data, $ttl = 2592000) - { - if (!$this->memcached->replace($this->key_prefix . $var, $data, $ttl)) - { - return $this->memcached->set($this->key_prefix . $var, $data, $ttl); - } - return true; - } - - /** - * Remove an item from the cache - * - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - protected function _delete($var) - { - return $this->memcached->delete($this->key_prefix . $var); - } -} diff --git a/install/update/new/phpbb/cache/driver/memory.php b/install/update/new/phpbb/cache/driver/memory.php deleted file mode 100644 index 956936b..0000000 --- a/install/update/new/phpbb/cache/driver/memory.php +++ /dev/null @@ -1,282 +0,0 @@ - -* @license 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 Abstract Memory Class -*/ -abstract class memory extends \phpbb\cache\driver\base -{ - var $key_prefix; - - /** - * Set cache path - */ - function __construct() - { - global $dbname, $table_prefix, $phpbb_container; - - $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)) - { - global $acm_type; - - trigger_error("Could not find required extension [{$this->extension}] for the ACM module $acm_type.", E_USER_ERROR); - } - - if (isset($this->function) && !function_exists($this->function)) - { - global $acm_type; - - trigger_error("The required function [{$this->function}] is not available for the ACM module $acm_type.", E_USER_ERROR); - } - } - - /** - * {@inheritDoc} - */ - function load() - { - // grab the global cache - $data = $this->_read('global'); - - if ($data !== false) - { - $this->vars = $data; - return true; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function save() - { - if (!$this->is_modified) - { - return; - } - - $this->_write('global', $this->vars, 2592000); - - $this->is_modified = false; - } - - /** - * {@inheritDoc} - */ - function tidy() - { - global $config; - - // cache has auto GC, no need to have any code here :) - $config->set('cache_last_gc', time(), false); - } - - /** - * {@inheritDoc} - */ - function get($var_name) - { - if ($var_name[0] == '_') - { - if (!$this->_exists($var_name)) - { - return false; - } - - return $this->_read($var_name); - } - else - { - return ($this->_exists($var_name)) ? $this->vars[$var_name] : false; - } - } - - /** - * {@inheritDoc} - */ - function put($var_name, $var, $ttl = 2592000) - { - if ($var_name[0] == '_') - { - $this->_write($var_name, $var, $ttl); - } - else - { - $this->vars[$var_name] = $var; - $this->is_modified = true; - } - } - - /** - * {@inheritDoc} - */ - function destroy($var_name, $table = '') - { - if ($var_name == 'sql' && !empty($table)) - { - if (!is_array($table)) - { - $table = array($table); - } - - foreach ($table as $table_name) - { - // gives us the md5s that we want - $temp = $this->_read('sql_' . $table_name); - - if ($temp === false) - { - continue; - } - - // delete each query ref - foreach ($temp as $md5_id => $void) - { - $this->_delete('sql_' . $md5_id); - } - - // delete the table ref - $this->_delete('sql_' . $table_name); - } - - return; - } - - if (!$this->_exists($var_name)) - { - return; - } - - if ($var_name[0] == '_') - { - $this->_delete($var_name); - } - else if (isset($this->vars[$var_name])) - { - $this->is_modified = true; - unset($this->vars[$var_name]); - - // We save here to let the following cache hits succeed - $this->save(); - } - } - - /** - * {@inheritDoc} - */ - function _exists($var_name) - { - if ($var_name[0] == '_') - { - return $this->_isset($var_name); - } - else - { - if (!count($this->vars)) - { - $this->load(); - } - - return isset($this->vars[$var_name]); - } - } - - /** - * {@inheritDoc} - */ - function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl) - { - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - $query_id = md5($query); - - // determine which tables this query belongs to - // Some queries use backticks, namely the get_database_size() query - // don't check for conformity, the SQL would error and not reach here. - if (!preg_match_all('/(?:FROM \\(?(`?\\w+`?(?: \\w+)?(?:, ?`?\\w+`?(?: \\w+)?)*)\\)?)|(?:JOIN (`?\\w+`?(?: \\w+)?))/', $query, $regs, PREG_SET_ORDER)) - { - // Bail out if the match fails. - return $query_result; - } - - $tables = array(); - foreach ($regs as $match) - { - if ($match[0][0] == 'F') - { - $tables = array_merge($tables, array_map('trim', explode(',', $match[1]))); - } - else - { - $tables[] = $match[2]; - } - } - - foreach ($tables as $table_name) - { - // Remove backticks - $table_name = ($table_name[0] == '`') ? substr($table_name, 1, -1) : $table_name; - - if (($pos = strpos($table_name, ' ')) !== false) - { - $table_name = substr($table_name, 0, $pos); - } - - $temp = $this->_read('sql_' . $table_name); - - if ($temp === false) - { - $temp = array(); - } - - $temp[$query_id] = true; - - // This must never expire - $this->_write('sql_' . $table_name, $temp, 0); - } - - // store them in the right place - $this->sql_rowset[$query_id] = array(); - $this->sql_row_pointer[$query_id] = 0; - - while ($row = $db->sql_fetchrow($query_result)) - { - $this->sql_rowset[$query_id][] = $row; - } - $db->sql_freeresult($query_result); - - $this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl); - - return $query_id; - } - - /** - * Check if a cache var exists - * - * @access protected - * @param string $var Cache key - * @return bool True if it exists, otherwise false - */ - function _isset($var) - { - // Most caches don't need to check - return true; - } -} diff --git a/install/update/new/phpbb/captcha/non_gd.php b/install/update/new/phpbb/captcha/non_gd.php deleted file mode 100644 index 8105187..0000000 --- a/install/update/new/phpbb/captcha/non_gd.php +++ /dev/null @@ -1,386 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\captcha; - -/** -* Main non-gd captcha class -* @ignore -*/ -class non_gd -{ - var $filtered_pngs; - var $width = 320; - var $height = 50; - - /** - * Define filtered pngs on init - */ - function __construct() - { - // If we can we will generate a single filtered png, we avoid nastiness via emulation of some Zlib stuff - $this->define_filtered_pngs(); - } - - /** - * Create the image containing $code with a seed of $seed - */ - function execute($code, $seed) - { - $img_height = $this->height - 10; - $img_width = 0; - - mt_srand($seed); - - $char_widths = $hold_chars = array(); - $code_len = strlen($code); - - for ($i = 0; $i < $code_len; $i++) - { - $char = $code[$i]; - - $width = mt_rand(0, 4); - $raw_width = $this->filtered_pngs[$char]['width']; - $char_widths[$i] = $width; - $img_width += $raw_width - $width; - - // Split the char into chunks of $raw_width + 1 length - if (empty($hold_chars[$char])) - { - $hold_chars[$char] = str_split(base64_decode($this->filtered_pngs[$char]['data']), $raw_width + 1); - } - } - - $offset_x = mt_rand(0, $this->width - $img_width); - $offset_y = mt_rand(0, $this->height - $img_height); - - $image = ''; - for ($i = 0; $i < $this->height; $i++) - { - $image .= chr(0); - - if ($i > $offset_y && $i < $offset_y + $img_height) - { - for ($j = 0; $j < $offset_x; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - - for ($j = 0; $j < $code_len; $j++) - { - $image .= $this->randomise(substr($hold_chars[$code[$j]][$i - $offset_y - 1], 1), $char_widths[$j]); - } - - for ($j = $offset_x + $img_width; $j < $this->width; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - } - else - { - for ($j = 0; $j < $this->width; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - } - } - unset($hold_chars); - - $image = $this->create_png($image, $this->width, $this->height); - - // Output image - header('Content-Type: image/png'); - header('Cache-control: no-cache, no-store'); - echo $image; - exit; - } - - /** - * This is designed to randomise the pixels of the image data within - * certain limits so as to keep it readable. It also varies the image - * width a little - */ - function randomise($scanline, $width) - { - $new_line = ''; - - $end = strlen($scanline) - ceil($width/2); - for ($i = (int) floor($width / 2); $i < $end; $i++) - { - $pixel = ord($scanline[$i]); - - if ($pixel < 190) - { - $new_line .= chr(mt_rand(0, 205)); - } - else if ($pixel > 190) - { - $new_line .= chr(mt_rand(145, 255)); - } - else - { - $new_line .= $scanline[$i]; - } - } - - return $new_line; - } - - /** - * This creates a chunk of the given type, with the given data - * of the given length adding the relevant crc - */ - function png_chunk($length, $type, $data) - { - $raw = $type . $data; - - return pack('N', $length) . $raw . pack('N', crc32($raw)); - } - - /** - * Creates greyscale 8bit png - The PNG spec can be found at - * http://www.libpng.org/pub/png/spec/PNG-Contents.html we use - * png because it's a fully recognised open standard and supported - * by practically all modern browsers and OSs - */ - function create_png($raw_image, $width, $height) - { - // SIG - $image = pack('C8', 137, 80, 78, 71, 13, 10, 26, 10); - - // IHDR - $raw = pack('N2', $width, $height); - $raw .= pack('C5', 8, 0, 0, 0, 0); - $image .= $this->png_chunk(13, 'IHDR', $raw); - - // IDAT - if (@extension_loaded('zlib')) - { - $raw_image = gzcompress($raw_image); - $length = strlen($raw_image); - } - else - { - // The total length of this image, uncompressed, is just a calculation of pixels - $length = ($width + 1) * $height; - - // Adler-32 hash generation - // Note: The hash is _backwards_ so we must reverse it - - if (@extension_loaded('hash')) - { - $adler_hash = strrev(hash('adler32', $raw_image, true)); - } - else if (@extension_loaded('mhash')) - { - $adler_hash = strrev(mhash(MHASH_ADLER32, $raw_image)); - } - else - { - // Optimized Adler-32 loop ported from the GNU Classpath project - $temp_length = $length; - $s1 = 1; - $s2 = $index = 0; - - while ($temp_length > 0) - { - // We can defer the modulo operation: - // s1 maximally grows from 65521 to 65521 + 255 * 3800 - // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 - $substract_value = ($temp_length < 3800) ? $temp_length : 3800; - $temp_length -= $substract_value; - - while (--$substract_value >= 0) - { - $s1 += ord($raw_image[$index]); - $s2 += $s1; - - $index++; - } - - $s1 %= 65521; - $s2 %= 65521; - } - $adler_hash = pack('N', ($s2 << 16) | $s1); - } - - // This is the same thing as gzcompress($raw_image, 0) but does not need zlib - $raw_image = pack('C3v2', 0x78, 0x01, 0x01, $length, ~$length) . $raw_image . $adler_hash; - - // The Zlib header + Adler hash make us add on 11 - $length += 11; - } - - // IDAT - $image .= $this->png_chunk($length, 'IDAT', $raw_image); - - // IEND - $image .= $this->png_chunk(0, 'IEND', ''); - - return $image; - } - - /** - * png image data - * Each 'data' element is base64_encoded uncompressed IDAT - */ - function define_filtered_pngs() - { - $this->filtered_pngs = array( - '0' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////olFAkBAAAGDyA4P///M31/////////////wD////////////////0dAgAAAAAAAAAAAAEcPipFGHn////////////AP//////////////6DAAAAAAAAAAAAAAAAAALSEAN+T///////////8A//////////////xAAAAAAAAAAAAAAAAAAAAAACPA/////////////wD/////////////oAAAAAAAAAAAAAAAAAAAAAAAev//////////////AP////////////8oAAAAAAAAPNj/zDAAAAAAAABD//////////////8A////////////1AAAAAAAABjw////5BAAAAAAAADo/////////////wD///////////+QAAAAAAAAbP//////QgAAAAAAAKj/////////////AP///////////1wAAAAAAACs/////8AXAAAAAAAAcP////////////8A////////////OAAAAAAAAND////dNwAAAAAAAABI/////////////wD///////////8gAAAAAAAA4P//7koACwAAAAAAACT/////////////AP///////////wgAAAAAAAD///VqAwaPAAAAAAAAEP////////////8A////////////AAAAAAAAAP/8kQYDavUAAAAAAAAA/////////////wD///////////8AAAAAAAAA/6kNAEru/wAAAAAAAAD/////////////AP///////////wAAAAAAAADAIwA33f//AAAAAAAAAP////////////8A////////////FAAAAAAAADYAI8D///8AAAAAAAAQ/////////////wD///////////8kAAAAAAAAAA2p////5AAAAAAAACD/////////////AP///////////0gAAAAAAAAFkfz////UAAAAAAAAQP////////////8A////////////cAAAAAAAAET1/////7AAAAAAAABo/////////////wD///////////+oAAAAAAAAXfX/////sAAAAAAAAGj/////////////AAAAALgAAAAAAAAwAAAAAAAAAAAAAAD////////////oAAAAAAAACOT////oEAAAAAAAAOD/////////////AP////////////8+AAAAAAAAKMz/zDQAAAAAAAA0//////////////8A////////////7jgAAAAAAAAAAAAAAAAAAAAAAKT//////////////wD///////////VqAwIAAAAAAAAAAAAAAAAAAAA8////////////////AP//////////rQcDaVEAAAAAAAAAAAAAAAAAKOj///////////////8A///////////nblnu/IAIAAAAAAAAAAAAAFzw/////////////////wD////////////79////+iITCAAAAAgSITg////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////w==', - 'width' => 40 - ), - '1' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////8BAAAAAAAP//////////////////AP////////////////////////9sAAAAAAAA//////////////////8A////////////////////////pAAAAAAAAAD//////////////////wD//////////////////////6wEAAAAAAAAAP//////////////////AP////////////////////h4AAAAAAAAAAAA//////////////////8A//////////////////ygJAAAAAAAAAAAAAD//////////////////wD//////////////9x8HAAAAAAAAAAAAAAAAP//////////////////AP//////////////AAAAAAAAAAAAAAAAAAAA//////////////////8A//////////////8AAAAAAAAAAAAAAAAAAAD//////////////////wD//////////////wAAAAAAAAR4AAAAAAAAAP//////////////////AP//////////////AAAAAAA4zP8AAAAAAAAA//////////////////8A//////////////8AAAA4sP///wAAAAAAAAD//////////////////wD//////////////yR80P//////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '2' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////okFAkCAAABCBIfNT///////////////////8A///////////////8hAgAAAAAAAAAAAAAAFTo/////////////////wD//////////////1QAAAAAAAAAAAAAAAAAACjo////////////////AP////////////+MAAAAAAAAAAAAAAAAAAAAADj///////////////8A////////////9BAAAAAAAAAAAAAAAAAAAAAAALD//////////////wD///////////+gAAAAAAAAAHjs+KwMAAAAAAAAVP//////////////AP///////////1gAAAAAAABM/////6QAAAAAAAAU//////////////8A////////////KAAAAAAAALj/////+AAAAAAAAAD//////////////wD///////////+MfGBMOCAI8P/////wAAAAAAAACP//////////////AP///////////////////////////5wAAAAAAAAw//////////////8A///////////////////////////oFAAAAAAAAHz//////////////wD/////////////////////////6CgAAAAAAAAE3P//////////////AP///////////////////////9ggAAAAAAAAAHT///////////////8A//////////////////////+0DAAAAAAAAAA8+P///////////////wD/////////////////////gAAAAAAAAAAAKOj/////////////////AP//////////////////9FAAAAAAAAAAADzw//////////////////8A/////////////////+g4AAAAAAAAAABk/P///////////////////wD////////////////oKAAAAAAAAAAMqP//////////////////////AP//////////////6CgAAAAAAAAAMNz///////////////////////8A//////////////g4AAAAAAAAAFT0/////////////////////////wD/////////////bAAAAAAAAABU/P//////////////////////////AP///////////8wAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A////////////SAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////9AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////xAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '3' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////8sGg0FAAAACA4cLz8////////////////////AP//////////////rBgAAAAAAAAAAAAAACTA//////////////////8A/////////////3QAAAAAAAAAAAAAAAAAAASs/////////////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAjc////////////////AP//////////6AwAAAAAAAAAAAAAAAAAAAAAAGT///////////////8A//////////94AAAAAAAABJDw/8g4AAAAAAAAHP///////////////wD//////////yAAAAAAAACE/////9gAAAAAAAAA////////////////AP///////////NSwiGQ4FOT//////AAAAAAAABD///////////////8A//////////////////////////+YAAAAAAAAVP///////////////wD//////////////////////P/ggAQAAAAAAATM////////////////AP////////////////////9gAAAAAAAAAAAElP////////////////8A/////////////////////0AAAAAAAAAAHLj//////////////////wD/////////////////////OAAAAAAAAAAwkPj/////////////////AP////////////////////8gAAAAAAAAAAAAINj///////////////8A/////////////////////xAAAAAAAAAAAAAAIPD//////////////wD/////////////////////uOz/4HgEAAAAAAAAhP//////////////AP///////////////////////////3wAAAAAAAAw//////////////8A////////////////////////////6AAAAAAAAAj//////////////wD/////////////////////////////AAAAAAAAAP//////////////AP//////////tJh8YEQoDNz//////+AAAAAAAAAY//////////////8A//////////88AAAAAAAAaP//////dAAAAAAAAEz//////////////wD//////////6QAAAAAAAAAdOD/5HQAAAAAAAAApP//////////////AP///////////CgAAAAAAAAAAAAAAAAAAAAAACD4//////////////8A////////////yAQAAAAAAAAAAAAAAAAAAAAEuP///////////////wD/////////////rAQAAAAAAAAAAAAAAAAABJD/////////////////AP//////////////zDQAAAAAAAAAAAAAACTA//////////////////8A/////////////////8BwOCAAAAAUNGi0/P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '4' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////////////nAAAAAAAAAD///////////////8A/////////////////////////8AEAAAAAAAAAP///////////////wD////////////////////////gGAAAAAAAAAAA////////////////AP//////////////////////9DAAAAAAAAAAAAD///////////////8A//////////////////////9UAAAAAAAAAAAAAP///////////////wD/////////////////////hAAAAAAAAAAAAAAA////////////////AP///////////////////7QAAAAAAAAAAAAAAAD///////////////8A///////////////////UDAAAAAAUAAAAAAAAAP///////////////wD/////////////////7CQAAAAABMAAAAAAAAAA////////////////AP////////////////xEAAAAAACU/wAAAAAAAAD///////////////8A////////////////cAAAAAAAZP//AAAAAAAAAP///////////////wD//////////////6AAAAAAADz8//8AAAAAAAAA////////////////AP/////////////IBAAAAAAc6P///wAAAAAAAAD///////////////8A////////////5BgAAAAADMz/////AAAAAAAAAP///////////////wD///////////g0AAAAAACk//////8AAAAAAAAA////////////////AP//////////XAAAAAAAfP///////wAAAAAAAAD///////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP///////////////////////////wAAAAAAAAD///////////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '5' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////8AAAAAAAAAAAAAAAAAAAAAAA//////////////8A///////////////MAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////6wAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////iAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////////9kAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////0QAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////IAAAAAAAYP////////////////////////////8A//////////////wAAAAAAAB8/////////////////////////////wD/////////////3AAAAAAAAIj/////////////////////////////AP////////////+4AAAAAAAAoLRYHAAEKGTE//////////////////8A/////////////5QAAAAAAAAQAAAAAAAAAABY9P///////////////wD/////////////dAAAAAAAAAAAAAAAAAAAAAA89P//////////////AP////////////9QAAAAAAAAAAAAAAAAAAAAAABg//////////////8A/////////////zAAAAAAAAAAAAAAAAAAAAAAAADQ/////////////wD/////////////IAAAAAAAAGjY/+h4BAAAAAAAAGz/////////////AP//////////////9NS0lHSc//////90AAAAAAAALP////////////8A/////////////////////////////9QAAAAAAAAE/////////////wD//////////////////////////////wAAAAAAAAD/////////////AP/////////////////////////////8AAAAAAAAEP////////////8A////////////pIRwWEAgDOD//////8wAAAAAAAA8/////////////wD///////////9EAAAAAAAAaP//////ZAAAAAAAAHz/////////////AP///////////6QAAAAAAAAAaOD/4GQAAAAAAAAE4P////////////8A/////////////CQAAAAAAAAAAAAAAAAAAAAAAGD//////////////wD/////////////yAQAAAAAAAAAAAAAAAAAAAAc7P//////////////AP//////////////rAwAAAAAAAAAAAAAAAAAGNj///////////////8A////////////////0EAAAAAAAAAAAAAAAFTo/////////////////wD//////////////////8h4QCAAAAAcQHzU////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '6' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////+0ZCwMAAAUNGjI////////////////////AP/////////////////EMAAAAAAAAAAAAABM6P////////////////8A////////////////lAQAAAAAAAAAAAAAAAAo6P///////////////wD//////////////6wAAAAAAAAAAAAAAAAAAABI////////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAACw//////////////8A/////////////3AAAAAAAAAoxP/YPAAAAAAAAEj//////////////wD////////////4EAAAAAAACOD////YDCBAVGiAoP//////////////AP///////////7gAAAAAAABY//////////////////////////////8A////////////eAAAAAAAAJT//////////////////////////////wD///////////9MAAAAAAAAvP/IXBgABCx03P//////////////////AP///////////ygAAAAAAADcdAAAAAAAAAAEiP////////////////8A////////////FAAAAAAAAFAAAAAAAAAAAAAAcP///////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAlP//////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAQ8P////////////8A////////////AAAAAAAAAABAyP/kZAAAAAAAAACQ/////////////wD///////////8MAAAAAAAALPj/////WAAAAAAAAET/////////////AP///////////yQAAAAAAACY///////MAAAAAAAAFP////////////8A////////////SAAAAAAAAMD///////wAAAAAAAAA/////////////wD///////////9wAAAAAAAAvP///////wAAAAAAAAD/////////////AP///////////7QAAAAAAACI///////UAAAAAAAAJP////////////8A////////////+AwAAAAAACDw/////2wAAAAAAABY/////////////wD/////////////cAAAAAAAADC8/Ox4AAAAAAAAAKj/////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAAAk/P////////////8A//////////////+oAAAAAAAAAAAAAAAAAAAABLj//////////////wD///////////////+QAAAAAAAAAAAAAAAAAACQ////////////////AP////////////////+0JAAAAAAAAAAAAAAkuP////////////////8A///////////////////8sGg0FAAADCxgqPz//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '7' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAABP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAy4/////////////wD//////////////////////////+QUAAAAAAAEuP//////////////AP/////////////////////////8QAAAAAAAAKT///////////////8A/////////////////////////4wAAAAAAAB0/////////////////wD////////////////////////cCAAAAAAANPz/////////////////AP///////////////////////0QAAAAAAATY//////////////////8A//////////////////////+0AAAAAAAAeP///////////////////wD//////////////////////CQAAAAAABTw////////////////////AP////////////////////+gAAAAAAAAkP////////////////////8A/////////////////////ywAAAAAABDw/////////////////////wD///////////////////+4AAAAAAAAbP//////////////////////AP///////////////////1wAAAAAAADQ//////////////////////8A///////////////////4DAAAAAAAMP///////////////////////wD//////////////////7QAAAAAAAB8////////////////////////AP//////////////////aAAAAAAAAMj///////////////////////8A//////////////////8oAAAAAAAM/P///////////////////////wD/////////////////8AAAAAAAAET/////////////////////////AP////////////////+0AAAAAAAAcP////////////////////////8A/////////////////4wAAAAAAACY/////////////////////////wD/////////////////WAAAAAAAAMD/////////////////////////AP////////////////80AAAAAAAA4P////////////////////////8A/////////////////xAAAAAAAAD4/////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '8' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////////IdDQUAAAEIEiA1P//////////////////AP/////////////////gRAAAAAAAAAAAAAAAROD///////////////8A////////////////0BgAAAAAAAAAAAAAAAAAEMj//////////////wD///////////////AcAAAAAAAAAAAAAAAAAAAAHPD/////////////AP//////////////hAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A//////////////8sAAAAAAAAKMz/zCgAAAAAAAAs/////////////wD//////////////wAAAAAAAADM////zAAAAAAAAAD/////////////AP//////////////BAAAAAAAAP//////AAAAAAAABP////////////8A//////////////8sAAAAAAAAzP///9QAAAAAAAAw/////////////wD//////////////3wAAAAAAAAoyP/YNAAAAAAAAIT/////////////AP//////////////7BgAAAAAAAAAAAAAAAAAAAAc8P////////////8A////////////////xBgAAAAAAAAAAAAAAAAAGNj//////////////wD/////////////////tAQAAAAAAAAAAAAAAACo////////////////AP///////////////HAAAAAAAAAAAAAAAAAAAAB8//////////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB8/////////////wD/////////////wAAAAAAAAABk4P/UWAAAAAAAAATQ////////////AP////////////9UAAAAAAAAaP//////XAAAAAAAAGT///////////8A/////////////xgAAAAAAADg///////cAAAAAAAAJP///////////wD/////////////AAAAAAAAAP////////8AAAAAAAAA////////////AP////////////8AAAAAAAAA4P//////3AAAAAAAAAT///////////8A/////////////ygAAAAAAABg//////9cAAAAAAAALP///////////wD/////////////ZAAAAAAAAABY1P/cXAAAAAAAAABw////////////AP/////////////QAAAAAAAAAAAAAAAAAAAAAAAABNz///////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB0/////////////wD///////////////Q8AAAAAAAAAAAAAAAAAAAAUPz/////////////AP////////////////x4CAAAAAAAAAAAAAAAEIT8//////////////8A///////////////////smFQwGAAAABg0ZKT0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '9' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////ysYCwMAAAUNGiw/P//////////////////AP////////////////+4JAAAAAAAAAAAAAAkuP////////////////8A////////////////lAQAAAAAAAAAAAAAAAAAkP///////////////wD//////////////8AEAAAAAAAAAAAAAAAAAAAAqP//////////////AP/////////////8JAAAAAAAAAAAAAAAAAAAAAAQ7P////////////8A/////////////6wAAAAAAAAAfOz8vCwAAAAAAABw/////////////wD/////////////WAAAAAAAAHD/////7BgAAAAAAAz4////////////AP////////////8kAAAAAAAA1P//////hAAAAAAAALT///////////8A/////////////wAAAAAAAAD///////+4AAAAAAAAcP///////////wD/////////////AAAAAAAAAPz//////8AAAAAAAABI////////////AP////////////8UAAAAAAAAzP//////lAAAAAAAACT///////////8A/////////////0QAAAAAAABY//////gsAAAAAAAADP///////////wD/////////////kAAAAAAAAABw5P/IPAAAAAAAAAAA////////////AP/////////////wEAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////////+UAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////9wAAAAAAAAAAAAAFAAAAAAAAAU////////////AP////////////////+IBAAAAAAAAABw3AAAAAAAACj///////////8A///////////////////cdCwEABhcxP+8AAAAAAAATP///////////wD//////////////////////////////5AAAAAAAAB4////////////AP//////////////////////////////UAAAAAAAALj///////////8A//////////////+kgGxUQCAM2P///+AIAAAAAAAQ+P///////////wD//////////////0gAAAAAAAA42P/EKAAAAAAAAHD/////////////AP//////////////sAAAAAAAAAAAAAAAAAAAAAAQ6P////////////8A////////////////TAAAAAAAAAAAAAAAAAAAAKz//////////////wD////////////////oKAAAAAAAAAAAAAAAAASU////////////////AP/////////////////sUAAAAAAAAAAAAAAwxP////////////////8A////////////////////yHA0FAAADCxktP///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'A' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////+QAAAAAAAAAAAAAAOT/////////////////AP//////////////////kAAAAAAAAAAAAAAAkP////////////////8A//////////////////88AAAAAAAAAAAAAAA8/////////////////wD/////////////////5AAAAAAAAAAAAAAAAADk////////////////AP////////////////+QAAAAAAAAAAAAAAAAAJD///////////////8A/////////////////zwAAAAAAAAAAAAAAAAAPP///////////////wD////////////////kAAAAAAAAAAgAAAAAAAAA5P//////////////AP///////////////5AAAAAAAAAAgAAAAAAAAACQ//////////////8A////////////////PAAAAAAAAAz8HAAAAAAAADz//////////////wD//////////////+QAAAAAAAAAWP9kAAAAAAAAANz/////////////AP//////////////kAAAAAAAAACk/7wAAAAAAAAAhP////////////8A//////////////88AAAAAAAABOz//BQAAAAAAAAw/////////////wD/////////////4AAAAAAAAAA8////ZAAAAAAAAADc////////////AP////////////+EAAAAAAAAAIj///+8AAAAAAAAAIT///////////8A/////////////zAAAAAAAAAA2P////wQAAAAAAAAMP///////////wD////////////cAAAAAAAAACT//////1wAAAAAAAAA3P//////////AP///////////4QAAAAAAAAAAAAAAAAAAAAAAAAAAACE//////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAAAAAADD//////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANz/////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhP////////8A//////////8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/////////wD/////////3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc////////AP////////+EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIT///////8A/////////zAAAAAAAAAAhP///////////2QAAAAAAAAAMP///////wD////////cAAAAAAAAAADM////////////vAAAAAAAAAAA3P//////AP///////4QAAAAAAAAAHP/////////////4DAAAAAAAAACE//////8A////////MAAAAAAAAABk//////////////9cAAAAAAAAADD//////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'B' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAEDh83P///////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAEhP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAeP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAABY////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAABT///////////8A//////////8AAAAAAAAAAP/////4zEwAAAAAAAAAAP///////////wD//////////wAAAAAAAAAA////////7AAAAAAAAAAQ////////////AP//////////AAAAAAAAAAD////////sAAAAAAAAAEj///////////8A//////////8AAAAAAAAAAP/////4zEQAAAAAAAAAtP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAFz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAiA/P////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAIjPj//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAGKz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJT///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAABNz//////////wD//////////wAAAAAAAAAA///////sqCAAAAAAAAAAbP//////////AP//////////AAAAAAAAAAD/////////yAAAAAAAAAAs//////////8A//////////8AAAAAAAAAAP//////////AAAAAAAAAAT//////////wD//////////wAAAAAAAAAA/////////7wAAAAAAAAAAP//////////AP//////////AAAAAAAAAAD//////+ikGAAAAAAAAAAY//////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFT//////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsP//////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAADj///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAc6P///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAATOj/////////////AP//////////AAAAAAAAAAAAAAAAAAAEIEBkkNj///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'C' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////5JRULBAAAAgkTIDQ//////////////////8A////////////////1FAAAAAAAAAAAAAAAABAyP///////////////wD//////////////4gEAAAAAAAAAAAAAAAAAAAElP//////////////AP////////////9wAAAAAAAAAAAAAAAAAAAAAAAAlP////////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAEyP///////////wD//////////9wIAAAAAAAAAAAAAAAAAAAAAAAAAAAw////////////AP//////////WAAAAAAAAAAAWMz/8JwQAAAAAAAAAACw//////////8A/////////+wEAAAAAAAAAID//////9QMAAAAAAAAAET//////////wD/////////nAAAAAAAAAAo/P///////3wAAAAABDBspP//////////AP////////9gAAAAAAAAAIz/////////3BxQjMT0//////////////8A/////////zQAAAAAAAAAzP///////////////////////////////wD/////////GAAAAAAAAADo////////////////////////////////AP////////8AAAAAAAAAAP////////////////////////////////8A/////////wAAAAAAAAAA/////////////////////////////////wD/////////AAAAAAAAAAD/////////////////////////////////AP////////8cAAAAAAAAAOj///////////////////////////////8A/////////zgAAAAAAAAA0P/////////kIGio7P///////////////wD/////////bAAAAAAAAACg/////////5wAAAAAMHS49P//////////AP////////+oAAAAAAAAAEz/////////PAAAAAAAAAAc//////////8A//////////QIAAAAAAAAALz//////6QAAAAAAAAAAGT//////////wD//////////3AAAAAAAAAADIzo/+SEBAAAAAAAAAAAyP//////////AP//////////7BAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////rAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD/////////////fAAAAAAAAAAAAAAAAAAAAAAAAJz/////////////AP//////////////iAQAAAAAAAAAAAAAAAAAAASY//////////////8A////////////////yEAAAAAAAAAAAAAAAAA8yP///////////////wD//////////////////9yIUCwQAAAAIEB4yP//////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'D' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAADChQkOT/////////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAABGjw//////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAACDY/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAABjk////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKj//////////wD///////////8AAAAAAAAAAP///+isSAAAAAAAAAAANP//////////AP///////////wAAAAAAAAAA////////hAAAAAAAAAAA2P////////8A////////////AAAAAAAAAAD/////////MAAAAAAAAACQ/////////wD///////////8AAAAAAAAAAP////////+MAAAAAAAAAFj/////////AP///////////wAAAAAAAAAA/////////8gAAAAAAAAAMP////////8A////////////AAAAAAAAAAD/////////5AAAAAAAAAAY/////////wD///////////8AAAAAAAAAAP//////////AAAAAAAAAAD/////////AP///////////wAAAAAAAAAA//////////8AAAAAAAAAAP////////8A////////////AAAAAAAAAAD//////////wAAAAAAAAAA/////////wD///////////8AAAAAAAAAAP/////////wAAAAAAAAABD/////////AP///////////wAAAAAAAAAA/////////9QAAAAAAAAAJP////////8A////////////AAAAAAAAAAD/////////qAAAAAAAAABI/////////wD///////////8AAAAAAAAAAP////////9QAAAAAAAAAHj/////////AP///////////wAAAAAAAAAA////////uAAAAAAAAAAAvP////////8A////////////AAAAAAAAAAD////w0HwEAAAAAAAAACT8/////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAADz8//////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAY6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAKNz/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAACHT0//////////////8A////////////AAAAAAAAAAAAAAAAABg4bKj0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'E' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'F' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'G' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////MB8TCgQAAAACCA4YJzs////////////////AP///////////////JQcAAAAAAAAAAAAAAAAAAhw8P////////////8A/////////////9gwAAAAAAAAAAAAAAAAAAAAAAAk2P///////////wD////////////EDAAAAAAAAAAAAAAAAAAAAAAAAAAc7P//////////AP//////////2AwAAAAAAAAAAAAAAAAAAAAAAAAAAABY//////////8A//////////wwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQ/////////wD/////////kAAAAAAAAAAAEHzQ/P/gmCAAAAAAAAAAAFz/////////AP////////wcAAAAAAAAACjg////////8CwAAAAAAAAgWP////////8A////////vAAAAAAAAAAI2P//////////yBRAcJjI8P///////////wD///////94AAAAAAAAAGD/////////////////////////////////AP///////0AAAAAAAAAAsP////////////////////////////////8A////////IAAAAAAAAADc/////////////////////////////////wD///////8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAD/////////AP///////wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAP////////8A////////AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAA/////////wD///////8gAAAAAAAAAOD//////wAAAAAAAAAAAAAAAAD/////////AP///////0AAAAAAAAAAtP//////AAAAAAAAAAAAAAAAAP////////8A////////cAAAAAAAAABw//////8AAAAAAAAAAAAAAAAA/////////wD///////+8AAAAAAAAABDs////////////AAAAAAAAAAD/////////AP////////wYAAAAAAAAADz0//////////AAAAAAAAAAAP////////8A/////////5AAAAAAAAAAACCY4P//3KhcCAAAAAAAAAAA/////////wD/////////+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////AP//////////xAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIP////////8A////////////rAQAAAAAAAAAAAAAAAAAAAAAAAAAAGTw/////////wD/////////////vBQAAAAAAAAAAAAAAAAAAAAAADjI////////////AP//////////////8HAQAAAAAAAAAAAAAAAAAEiw//////////////8A//////////////////iwcEAgBAAABCA4aKDk/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'H' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'I' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'J' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAj//////////////wD//////////+zMrIxwUDAQ//////wAAAAAAAAAIP//////////////AP//////////DAAAAAAAAADo////2AAAAAAAAAA0//////////////8A//////////8wAAAAAAAAAKj///+YAAAAAAAAAFj//////////////wD//////////2gAAAAAAAAAIND/yBgAAAAAAAAAkP//////////////AP//////////vAAAAAAAAAAAAAAAAAAAAAAAAADc//////////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAUP///////////////wD////////////EBAAAAAAAAAAAAAAAAAAAABjk////////////////AP////////////+sBAAAAAAAAAAAAAAAAAAY2P////////////////8A///////////////EMAAAAAAAAAAAAAAAVOj//////////////////wD/////////////////vHBAIAAAABg8fNT/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'K' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////8AAAAAAAAAAP//////////wAQAAAAAAAAAAABw////////AP///////wAAAAAAAAAA/////////9AMAAAAAAAAAAAAcP////////8A////////AAAAAAAAAAD////////cGAAAAAAAAAAAAHD//////////wD///////8AAAAAAAAAAP//////6CgAAAAAAAAAAABs////////////AP///////wAAAAAAAAAA//////Q0AAAAAAAAAAAAVPz///////////8A////////AAAAAAAAAAD////8RAAAAAAAAAAAAFT8/////////////wD///////8AAAAAAAAAAP///1gAAAAAAAAAAABU/P//////////////AP///////wAAAAAAAAAA//9wAAAAAAAAAAAASPz///////////////8A////////AAAAAAAAAAD/jAAAAAAAAAAAADz0/////////////////wD///////8AAAAAAAAAAKQAAAAAAAAAAAA89P//////////////////AP///////wAAAAAAAAAABAAAAAAAAAAAFPT///////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAApP///////////////////wD///////8AAAAAAAAAAAAAAAAAAAAAAAAU8P//////////////////AP///////wAAAAAAAAAAAAAAAAAAAAAAAABk//////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAAAADE/////////////////wD///////8AAAAAAAAAAAAAAAAoEAAAAAAAACz8////////////////AP///////wAAAAAAAAAAAAAAGNiAAAAAAAAAAIj///////////////8A////////AAAAAAAAAAAAABjY//gYAAAAAAAACOD//////////////wD///////8AAAAAAAAAAAAY2P///5wAAAAAAAAASP//////////////AP///////wAAAAAAAAAAGNj//////CgAAAAAAAAAqP////////////8A////////AAAAAAAAAADI////////sAAAAAAAAAAc8P///////////wD///////8AAAAAAAAAAP//////////QAAAAAAAAABs////////////AP///////wAAAAAAAAAA///////////IAAAAAAAAAATI//////////8A////////AAAAAAAAAAD///////////9YAAAAAAAAADD8/////////wD///////8AAAAAAAAAAP///////////9wEAAAAAAAAAJD/////////AP///////wAAAAAAAAAA/////////////3AAAAAAAAAADOT///////8A////////AAAAAAAAAAD/////////////7BAAAAAAAAAAUP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'L' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'M' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////8AAAAAAAAAAAAAAHz//////3wAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAATP//////UAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAc//////8cAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAADw////8AAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAAALz////AAAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAAkP///5AAAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAABc////ZAAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAoAAAAADD///8wAAAAACQAAAAAAAAA////////AP//////AAAAAAAAAFwAAAAABPz//AgAAAAAXAAAAAAAAAD///////8A//////8AAAAAAAAAkAAAAAAA0P/UAAAAAACQAAAAAAAAAP///////wD//////wAAAAAAAADMAAAAAACg/6gAAAAAAMQAAAAAAAAA////////AP//////AAAAAAAAAPgEAAAAAHD/dAAAAAAE+AAAAAAAAAD///////8A//////8AAAAAAAAA/zQAAAAAQP9IAAAAADD/AAAAAAAAAP///////wD//////wAAAAAAAAD/bAAAAAAQ/xQAAAAAaP8AAAAAAAAA////////AP//////AAAAAAAAAP+gAAAAAADQAAAAAACc/wAAAAAAAAD///////8A//////8AAAAAAAAA/9QAAAAAAGgAAAAAAND/AAAAAAAAAP///////wD//////wAAAAAAAAD//wwAAAAAFAAAAAAM/P8AAAAAAAAA////////AP//////AAAAAAAAAP//RAAAAAAAAAAAADz//wAAAAAAAAD///////8A//////8AAAAAAAAA//94AAAAAAAAAAAAcP//AAAAAAAAAP///////wD//////wAAAAAAAAD//7AAAAAAAAAAAACo//8AAAAAAAAA////////AP//////AAAAAAAAAP//5AAAAAAAAAAAANz//wAAAAAAAAD///////8A//////8AAAAAAAAA////HAAAAAAAAAAQ////AAAAAAAAAP///////wD//////wAAAAAAAAD///9QAAAAAAAAAEz///8AAAAAAAAA////////AP//////AAAAAAAAAP///4gAAAAAAAAAfP///wAAAAAAAAD///////8A//////8AAAAAAAAA////vAAAAAAAAACw////AAAAAAAAAP///////wD//////wAAAAAAAAD////wAAAAAAAAAOz///8AAAAAAAAA////////AP//////AAAAAAAAAP////8sAAAAAAAc/////wAAAAAAAAD///////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'N' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAALD/////////////AAAAAAAAAP//////////AP////////8AAAAAAAAAFOj///////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAASP///////////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAkP//////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAI1P////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAw+P///////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAABw////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAC8//////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAABzs/////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAFD/////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAJz///8AAAAAAAAA//////////8A/////////wAAAAAAAAAUAAAAAAAADNz//wAAAAAAAAD//////////wD/////////AAAAAAAAALQAAAAAAAAANPz/AAAAAAAAAP//////////AP////////8AAAAAAAAA/2wAAAAAAAAAfP8AAAAAAAAA//////////8A/////////wAAAAAAAAD/+CwAAAAAAAAExAAAAAAAAAD//////////wD/////////AAAAAAAAAP//0AQAAAAAAAAgAAAAAAAAAP//////////AP////////8AAAAAAAAA////jAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////RAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP/////kFAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA//////+sAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD///////9kAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP////////QkAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA/////////8wEAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD//////////4QAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP///////////DwAAAAAAAAAAP//////////AP////////8AAAAAAAAA////////////4BAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////////////qAAAAAAAAAD//////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'O' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////0qGw4HAAAABw4aKT0/////////////////wD////////////////wcAwAAAAAAAAAAAAAAAho6P//////////////AP//////////////uBQAAAAAAAAAAAAAAAAAAAAMoP////////////8A/////////////6AEAAAAAAAAAAAAAAAAAAAAAAAAkP///////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP//////////8BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAM5P////////8A//////////9wAAAAAAAAAAAsrPD/7KQsAAAAAAAAAABg/////////wD/////////+BAAAAAAAAAAUPj///////hQAAAAAAAAAAjs////////AP////////+sAAAAAAAAABDw//////////AYAAAAAAAAAKD///////8A/////////2wAAAAAAAAAdP///////////3wAAAAAAAAAYP///////wD/////////OAAAAAAAAAC4////////////xAAAAAAAAAAw////////AP////////8cAAAAAAAAAOD////////////oAAAAAAAAABT///////8A/////////wAAAAAAAAAA//////////////8AAAAAAAAAAP///////wD/////////AAAAAAAAAAD//////////////wAAAAAAAAAA////////AP////////8AAAAAAAAAAP/////////////8AAAAAAAAAAD///////8A/////////xwAAAAAAAAA5P///////////+AAAAAAAAAAHP///////wD/////////NAAAAAAAAAC8////////////uAAAAAAAAAA4////////AP////////9oAAAAAAAAAHj///////////98AAAAAAAAAGT///////8A/////////6gAAAAAAAAAGPD/////////+BgAAAAAAAAApP///////wD/////////9AwAAAAAAAAAUPz///////xcAAAAAAAAAAjs////////AP//////////cAAAAAAAAAAALKjs//CwOAAAAAAAAAAAYP////////8A///////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzk/////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP////////////+QAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A//////////////+sEAAAAAAAAAAAAAAAAAAAAAyg/////////////wD////////////////oZAgAAAAAAAAAAAAAAARg4P//////////////AP//////////////////9KhsOCAAAAAUMFyc7P////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'P' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////wAAAAAAAAAAAAAAAAAACCxguP////////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAOOD//////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAGOD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAARP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAABo////////////AP///////////wAAAAAAAAAA////6JwMAAAAAAAAADD///////////8A////////////AAAAAAAAAAD//////6AAAAAAAAAADP///////////wD///////////8AAAAAAAAAAP//////9AAAAAAAAAAA////////////AP///////////wAAAAAAAAAA///////0AAAAAAAAAAD///////////8A////////////AAAAAAAAAAD//////5gAAAAAAAAAHP///////////wD///////////8AAAAAAAAAAP///9iICAAAAAAAAABI////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAIT/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAABU/P////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAIhPz//////////////wD///////////8AAAAAAAAAAAAAAAAABCRMkOz/////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Q' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////SoaDQcAAAAHDhoqPT///////////////////8A//////////////BwDAAAAAAAAAAAAAAACHDo/////////////////wD///////////+4FAAAAAAAAAAAAAAAAAAAABCo////////////////AP//////////nAQAAAAAAAAAAAAAAAAAAAAAAACQ//////////////8A/////////7gEAAAAAAAAAAAAAAAAAAAAAAAAAACg/////////////wD////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzo////////////AP///////3AAAAAAAAAAACyo8P/sqCwAAAAAAAAAAGT///////////8A///////4EAAAAAAAAABM+P///////FQAAAAAAAAACPT//////////wD//////7AAAAAAAAAAFPD/////////9BgAAAAAAAAApP//////////AP//////bAAAAAAAAAB4////////////fAAAAAAAAABk//////////8A//////84AAAAAAAAALz///////////+8AAAAAAAAADT//////////wD//////xwAAAAAAAAA6P///////////+QAAAAAAAAAHP//////////AP//////AAAAAAAAAAD//////////////wAAAAAAAAAA//////////8A//////8AAAAAAAAAAP//////////////AAAAAAAAAAD//////////wD//////wAAAAAAAAAA/P////////////8AAAAAAAAAAP//////////AP//////GAAAAAAAAADg////////////4AAAAAAAAAAc//////////8A//////84AAAAAAAAALT////MJHTo//+8AAAAAAAAADT//////////wD//////2wAAAAAAAAAdP///2AAABCg/3wAAAAAAAAAZP//////////AP//////rAAAAAAAAAAY9P/sCAAAAABMGAAAAAAAAACk//////////8A///////4EAAAAAAAAABU/P+0OAAAAAAAAAAAAAAACPT//////////wD///////94AAAAAAAAAAA4sPD/gAAAAAAAAAAAAABk////////////AP////////AcAAAAAAAAAAAAAAAAAAAAAAAAAAAADOT///////////8A/////////7wEAAAAAAAAAAAAAAAAAAAAAAAAAACQ/////////////wD//////////6wEAAAAAAAAAAAAAAAAAAAAAAAAABSs////////////AP///////////7gUAAAAAAAAAAAAAAAAAAAAAAAAAABAwP////////8A//////////////BwDAAAAAAAAAAAAAAABAgAAAAAAAA8/////////wD////////////////0qGg0GAAAABgwXJjkxBgAAAAAALD/////////AP//////////////////////////////////5DQAAAAk/P////////8A////////////////////////////////////+GwAAJD//////////wD//////////////////////////////////////8A49P//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'R' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////wAAAAAAAAAAAAAAAAAAAAQgOGSk+P///////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAcuP//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAEsP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ6P///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADD///////////8A/////////wAAAAAAAAAA///////svDgAAAAAAAAACP///////////wD/////////AAAAAAAAAAD/////////7AAAAAAAAAAA////////////AP////////8AAAAAAAAAAP/////////cAAAAAAAAABD///////////8A/////////wAAAAAAAAAA//////DQoCQAAAAAAAAAQP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACU////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIPj///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAzU/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAA02P//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAxctPz///////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAEDY/////////////////wD/////////AAAAAAAAAAD/9LAsAAAAAAAAAAzc////////////////AP////////8AAAAAAAAAAP///+wkAAAAAAAAADD8//////////////8A/////////wAAAAAAAAAA/////8QAAAAAAAAAAJD//////////////wD/////////AAAAAAAAAAD//////1QAAAAAAAAAFPD/////////////AP////////8AAAAAAAAAAP//////3AQAAAAAAAAAgP////////////8A/////////wAAAAAAAAAA////////aAAAAAAAAAAM6P///////////wD/////////AAAAAAAAAAD////////oCAAAAAAAAABs////////////AP////////8AAAAAAAAAAP////////+AAAAAAAAAAATc//////////8A/////////wAAAAAAAAAA//////////AUAAAAAAAAAFj//////////wD/////////AAAAAAAAAAD//////////5AAAAAAAAAAAND/////////AP////////8AAAAAAAAAAP//////////+CQAAAAAAAAAQP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'S' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////8vHBEIAgAAAQgQHC8/P////////////////8A////////////////pCQAAAAAAAAAAAAAAAAcoP///////////////wD//////////////FwAAAAAAAAAAAAAAAAAAAAAXP//////////////AP////////////9oAAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A////////////zAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////9cAAAAAAAAAAAAAAAAAAAAAAAAAACA////////////AP///////////xgAAAAAAAAAUOD/8KwkAAAAAAAAADj///////////8A////////////AAAAAAAAAAD0/////8wABCAgICxASP///////////wD///////////8MAAAAAAAAAMz/////////////////////////////AP///////////0AAAAAAAAAACFiQxPT///////////////////////8A////////////oAAAAAAAAAAAAAAAADBwtPT//////////////////wD////////////8QAAAAAAAAAAAAAAAAAAACFTA////////////////AP/////////////oOAAAAAAAAAAAAAAAAAAAAABM6P////////////8A///////////////4fAgAAAAAAAAAAAAAAAAAAAAY2P///////////wD/////////////////7IwwAAAAAAAAAAAAAAAAAAAo+P//////////AP/////////////////////koGw0BAAAAAAAAAAAAACU//////////8A///////////////////////////4uFgAAAAAAAAAADz//////////wD//////////2BgSEA0IBwA6P///////5QAAAAAAAAADP//////////AP//////////JAAAAAAAAACc/////////AAAAAAAAAAA//////////8A//////////9YAAAAAAAAACDo///////AAAAAAAAAABT//////////wD//////////6QAAAAAAAAAACCk7P/snBQAAAAAAAAAUP//////////AP//////////+BAAAAAAAAAAAAAAAAAAAAAAAAAAAACs//////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAAOP///////////wD////////////8RAAAAAAAAAAAAAAAAAAAAAAAABjc////////////AP/////////////0PAAAAAAAAAAAAAAAAAAAAAAg2P////////////8A///////////////8hBQAAAAAAAAAAAAAAAAMdPT//////////////wD/////////////////+LRwSCAMAAAAHDhoqPT/////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'T' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'U' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////JAAAAAAAAADk/////////+gAAAAAAAAAHP//////////AP////////9MAAAAAAAAAJz/////////nAAAAAAAAABE//////////8A/////////4gAAAAAAAAAHOj//////+ggAAAAAAAAAHz//////////wD/////////0AAAAAAAAAAAIJzs/+ykIAAAAAAAAAAA0P//////////AP//////////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A///////////IBAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAAAAJj/////////////AP////////////+UBAAAAAAAAAAAAAAAAAAAAASU//////////////8A///////////////IPAAAAAAAAAAAAAAAAAAwyP///////////////wD/////////////////0IxYOCAIAAAEIEiAyP//////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'V' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////zAAAAAAAAAAYP//////////////ZAAAAAAAAAAw////////AP//////kAAAAAAAAAAU/P////////////8UAAAAAAAAAJD///////8A///////oBAAAAAAAAADE////////////xAAAAAAAAAAE7P///////wD///////9MAAAAAAAAAHD///////////94AAAAAAAAAEz/////////AP///////6gAAAAAAAAAJP///////////yQAAAAAAAAArP////////8A////////+BAAAAAAAAAA1P/////////YAAAAAAAAABT4/////////wD/////////aAAAAAAAAACE/////////4QAAAAAAAAAbP//////////AP/////////EAAAAAAAAADT/////////OAAAAAAAAADM//////////8A//////////8kAAAAAAAAAOT//////+QAAAAAAAAAKP///////////wD//////////4QAAAAAAAAAmP//////nAAAAAAAAACI////////////AP//////////5AAAAAAAAABE//////9EAAAAAAAABOT///////////8A////////////QAAAAAAAAAT0////9AgAAAAAAABI/////////////wD///////////+gAAAAAAAAAKT///+kAAAAAAAAAKj/////////////AP////////////QIAAAAAAAAXP///1wAAAAAAAAM+P////////////8A/////////////1wAAAAAAAAM+P/8DAAAAAAAAGT//////////////wD/////////////vAAAAAAAAAC8/7wAAAAAAAAAxP//////////////AP//////////////HAAAAAAAAGj/aAAAAAAAACT///////////////8A//////////////94AAAAAAAAHP8cAAAAAAAAhP///////////////wD//////////////9gAAAAAAAAAkAAAAAAAAADk////////////////AP///////////////zgAAAAAAAAQAAAAAAAAQP////////////////8A////////////////lAAAAAAAAAAAAAAAAACg/////////////////wD////////////////sCAAAAAAAAAAAAAAADPT/////////////////AP////////////////9QAAAAAAAAAAAAAABg//////////////////8A/////////////////7AAAAAAAAAAAAAAAMD//////////////////wD//////////////////BQAAAAAAAAAAAAc////////////////////AP//////////////////cAAAAAAAAAAAAHz///////////////////8A///////////////////MAAAAAAAAAAAA3P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'W' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//8cAAAAAAAAALz/////4AAAAAAAAAAA6P////+8AAAAAAAAABz//wD//1QAAAAAAAAAjP////+gAAAAAAAAAACo/////4wAAAAAAAAAUP//AP//jAAAAAAAAABU/////2AAAAAAAAAAAGj/////VAAAAAAAAACM//8A///EAAAAAAAAACT/////IAAAAAAAAAAAKP////8kAAAAAAAAAMT//wD///gEAAAAAAAAAPD//+AAAAAAAAAAAAAA6P//8AAAAAAAAAAE9P//AP///zAAAAAAAAAAvP//oAAAAAAAAAAAAACo//+8AAAAAAAAADD///8A////bAAAAAAAAACM//9gAAAAAAAAAAAAAGT//4wAAAAAAAAAaP///wD///+kAAAAAAAAAFT//yAAAAAAAAAAAAAAIP//VAAAAAAAAACc////AP///9gAAAAAAAAAJP/gAAAAAAAAAAAAAAAA4P8kAAAAAAAAANT///8A/////xAAAAAAAAAA8KAAAAAAAAAAAAAAAACg8AAAAAAAAAAQ/////wD/////TAAAAAAAAAC8YAAAAAAAAAAAAAAAAGC8AAAAAAAAAET/////AP////+AAAAAAAAAAIwgAAAAAAAAAAAAAAAAIIwAAAAAAAAAfP////8A/////7gAAAAAAAAANAAAAAAAACwwAAAAAAAANAAAAAAAAACw/////wD/////8AAAAAAAAAAAAAAAAAAAdHgAAAAAAAAAAAAAAAAAAOz/////AP//////KAAAAAAAAAAAAAAAAAC4vAAAAAAAAAAAAAAAAAAg//////8A//////9gAAAAAAAAAAAAAAAACPj4CAAAAAAAAAAAAAAAAFj//////wD//////5QAAAAAAAAAAAAAAABE//9IAAAAAAAAAAAAAAAAkP//////AP//////0AAAAAAAAAAAAAAAAIj//4wAAAAAAAAAAAAAAADI//////8A///////8DAAAAAAAAAAAAAAAzP//1AAAAAAAAAAAAAAABPj//////wD///////88AAAAAAAAAAAAABT/////GAAAAAAAAAAAAAA0////////AP///////3QAAAAAAAAAAAAAWP////9gAAAAAAAAAAAAAHD///////8A////////sAAAAAAAAAAAAACg/////6QAAAAAAAAAAAAApP///////wD////////kAAAAAAAAAAAAAOT/////6AAAAAAAAAAAAADc////////AP////////8cAAAAAAAAAAAo////////MAAAAAAAAAAAEP////////8A/////////1QAAAAAAAAAAHD///////94AAAAAAAAAABM/////////wD/////////jAAAAAAAAAAAtP///////7wAAAAAAAAAAID/////////AP/////////EAAAAAAAAAAT0////////+AgAAAAAAAAAuP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'X' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////9UAAAAAAAAAKz///////////+sAAAAAAAAAFD/////////AP///////+QQAAAAAAAAFOT/////////8BwAAAAAAAAM5P////////8A/////////5gAAAAAAAAATP////////9kAAAAAAAAAJD//////////wD//////////0AAAAAAAAAAoP//////wAAAAAAAAAA0/P//////////AP//////////2AgAAAAAAAAQ4P////gkAAAAAAAABMz///////////8A////////////iAAAAAAAAABA////dAAAAAAAAABw/////////////wD////////////8MAAAAAAAAACU/9AEAAAAAAAAHPD/////////////AP/////////////IBAAAAAAAAAzYMAAAAAAAAACs//////////////8A//////////////90AAAAAAAAABAAAAAAAAAATP///////////////wD///////////////QgAAAAAAAAAAAAAAAAAAzg////////////////AP///////////////7wAAAAAAAAAAAAAAAAAjP////////////////8A/////////////////2AAAAAAAAAAAAAAADD8/////////////////wD/////////////////7BQAAAAAAAAAAAAEyP//////////////////AP/////////////////gDAAAAAAAAAAAAAjY//////////////////8A/////////////////0AAAAAAAAAAAAAAADj8/////////////////wD///////////////+UAAAAAAAAAAAAAAAAAJD/////////////////AP//////////////4AwAAAAAAAAAAAAAAAAADOD///////////////8A//////////////9AAAAAAAAAAAAAAAAAAAAAQP///////////////wD/////////////nAAAAAAAAAAAWAAAAAAAAAAAlP//////////////AP///////////+QQAAAAAAAAAGD/YAAAAAAAAAAM4P////////////8A////////////TAAAAAAAAAAs9P/0LAAAAAAAAABM/////////////wD//////////6AAAAAAAAAADNT////UDAAAAAAAAACg////////////AP/////////kEAAAAAAAAACg//////+gAAAAAAAAABDk//////////8A/////////0wAAAAAAAAAYP////////9gAAAAAAAAAEz//////////wD///////+oAAAAAAAAACz0//////////QsAAAAAAAAAKT/////////AP//////7BQAAAAAAAAM1P///////////9QMAAAAAAAAFOz///////8A//////9UAAAAAAAAAKD//////////////6AAAAAAAAAAVP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Y' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////1QAAAAAAAAAAGj//////////2gAAAAAAAAAAFT///////8A////////5BAAAAAAAAAAAMT////////EAAAAAAAAAAAQ5P///////wD/////////mAAAAAAAAAAAKPj/////+CgAAAAAAAAAAJj/////////AP//////////PAAAAAAAAAAAgP////+AAAAAAAAAAAA8//////////8A///////////YCAAAAAAAAAAE2P//2AQAAAAAAAAACNj//////////wD///////////+AAAAAAAAAAAA4//84AAAAAAAAAACA////////////AP////////////woAAAAAAAAAACUlAAAAAAAAAAAKPz///////////8A/////////////8gAAAAAAAAAABAQAAAAAAAAAADI/////////////wD//////////////2wAAAAAAAAAAAAAAAAAAAAAbP//////////////AP//////////////8BwAAAAAAAAAAAAAAAAAABzw//////////////8A////////////////tAAAAAAAAAAAAAAAAAAAtP///////////////wD/////////////////VAAAAAAAAAAAAAAAAFT/////////////////AP/////////////////oEAAAAAAAAAAAAAAQ6P////////////////8A//////////////////+cAAAAAAAAAAAAAJz//////////////////wD///////////////////9AAAAAAAAAAABA////////////////////AP///////////////////9gAAAAAAAAAANj///////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Z' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAQ//////////////8A/////////////////////////1AAAAAAAAAABLz//////////////wD///////////////////////98AAAAAAAAAACY////////////////AP//////////////////////pAAAAAAAAAAAaP////////////////8A/////////////////////8QIAAAAAAAAAET8/////////////////wD////////////////////gGAAAAAAAAAAo9P//////////////////AP//////////////////9CwAAAAAAAAAFNz///////////////////8A//////////////////xMAAAAAAAAAATA/////////////////////wD/////////////////eAAAAAAAAAAAnP//////////////////////AP///////////////5wAAAAAAAAAAHT///////////////////////8A///////////////ABAAAAAAAAABM/P///////////////////////wD/////////////3BQAAAAAAAAALPT/////////////////////////AP////////////QoAAAAAAAAABjg//////////////////////////8A///////////8SAAAAAAAAAAExP///////////////////////////wD//////////2wAAAAAAAAAAKD/////////////////////////////AP////////+YAAAAAAAAAAB8//////////////////////////////8A/////////wQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - ); - } -} diff --git a/install/update/new/phpbb/captcha/plugins/qa.php b/install/update/new/phpbb/captcha/plugins/qa.php deleted file mode 100644 index 966b8d3..0000000 --- a/install/update/new/phpbb/captcha/plugins/qa.php +++ /dev/null @@ -1,1040 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\captcha\plugins; - -/** -* And now to something completely different. Let's make a captcha without extending the abstract class. -* QA CAPTCHA sample implementation -*/ -class qa -{ - var $confirm_id; - var $answer; - var $question_ids = []; - var $question_text; - var $question_lang; - var $question_strict; - var $attempts = 0; - var $type; - // dirty trick: 0 is false, but can still encode that the captcha is not yet validated - var $solved = 0; - - protected $table_captcha_questions; - protected $table_captcha_answers; - protected $table_qa_confirm; - - /** - * @var string name of the service. - */ - protected $service_name; - - /** - * Constructor - * - * @param string $table_captcha_questions - * @param string $table_captcha_answers - * @param string $table_qa_confirm - */ - function __construct($table_captcha_questions, $table_captcha_answers, $table_qa_confirm) - { - $this->table_captcha_questions = $table_captcha_questions; - $this->table_captcha_answers = $table_captcha_answers; - $this->table_qa_confirm = $table_qa_confirm; - } - - /** - * @param int $type as per the CAPTCHA API docs, the type - */ - function init($type) - { - global $config, $db, $user, $request; - - // load our language file - $user->add_lang('captcha_qa'); - - // read input - $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; - - // we need all defined questions - shouldn't be too many, so we can just grab them - // try the user's lang first - $sql = 'SELECT question_id - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'"; - $result = $db->sql_query($sql, 3600); - - while ($row = $db->sql_fetchrow($result)) - { - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - - // fallback to the board default lang - if (!count($this->question_ids)) - { - $this->question_lang = $config['default_lang']; - - $sql = 'SELECT question_id - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query($sql, 7200); - - while ($row = $db->sql_fetchrow($result)) - { - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - } - - // final fallback to any language - 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'; - $result = $db->sql_query($sql, 7200); - - while ($row = $db->sql_fetchrow($result)) - { - if (empty($this->question_lang)) - { - $this->question_lang = $row['lang_iso']; - } - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - } - - // okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one - if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer())) - { - // we have no valid confirm ID, better get ready to ask something - $this->select_question(); - } - } - - /** - * See if the captcha has created its tables. - */ - public function is_installed() - { - global $phpbb_container; - - $db_tool = $phpbb_container->get('dbal.tools'); - - return $db_tool->sql_table_exists($this->table_captcha_questions); - } - - /** - * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang - */ - public function is_available() - { - global $config, $db, $user; - - // load language file for pretty display in the ACP dropdown - $user->add_lang('captcha_qa'); - - if (!$this->is_installed()) - { - return false; - } - - $sql = 'SELECT COUNT(question_id) AS question_count - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - return ((bool) $row['question_count']); - } - - /** - * API function - */ - function has_config() - { - return true; - } - - /** - * API function - */ - static public function get_name() - { - return 'CAPTCHA_QA'; - } - - /** - * @return string the name of the service corresponding to the plugin - */ - function get_service_name() - { - return $this->service_name; - } - - /** - * Set the name of the plugin - * - * @param string $name - */ - public function set_name($name) - { - $this->service_name = $name; - } - - /** - * API function - not needed as we don't display an image - */ - function execute_demo() - { - } - - /** - * API function - not needed as we don't display an image - */ - function execute() - { - } - - /** - * API function - send the question to the template - */ - function get_template() - { - global $phpbb_log, $template, $user; - - if ($this->is_solved()) - { - return false; - } - else if (empty($this->question_text) || !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'))); - return false; - } - else - { - $template->assign_vars(array( - 'QA_CONFIRM_QUESTION' => $this->question_text, - 'QA_CONFIRM_ID' => $this->confirm_id, - 'S_CONFIRM_CODE' => true, - 'S_TYPE' => $this->type, - )); - - return 'captcha_qa.html'; - } - } - - /** - * API function - we just display a mockup so that the captcha doesn't need to be installed - */ - function get_demo_template() - { - global $config, $db, $template; - - if ($this->is_available()) - { - $sql = 'SELECT question_text - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) - { - $template->assign_vars(array( - 'QA_CONFIRM_QUESTION' => $row['question_text'], - )); - } - $db->sql_freeresult($result); - } - return 'captcha_qa_acp_demo.html'; - } - - /** - * API function - */ - function get_hidden_fields() - { - $hidden_fields = array(); - - // this is required - otherwise we would forget about the captcha being already solved - if ($this->solved) - { - $hidden_fields['qa_answer'] = $this->answer; - } - $hidden_fields['qa_confirm_id'] = $this->confirm_id; - - return $hidden_fields; - } - - /** - * API function - */ - function garbage_collect($type = 0) - { - global $db; - - $sql = 'SELECT c.confirm_id - FROM ' . $this->table_qa_confirm . ' c - LEFT JOIN ' . SESSIONS_TABLE . ' s - ON (c.session_id = s.session_id) - WHERE s.session_id IS NULL' . - ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - - do - { - $sql_in[] = (string) $row['confirm_id']; - } - while ($row = $db->sql_fetchrow($result)); - - if (count($sql_in)) - { - $sql = 'DELETE FROM ' . $this->table_qa_confirm . ' - WHERE ' . $db->sql_in_set('confirm_id', $sql_in); - $db->sql_query($sql); - } - } - $db->sql_freeresult($result); - } - - /** - * API function - we don't drop the tables here, as that would cause the loss of all entered questions. - */ - function uninstall() - { - $this->garbage_collect(0); - } - - /** - * API function - set up shop - */ - function install() - { - global $phpbb_container; - - $db_tool = $phpbb_container->get('dbal.tools'); - $schemas = array( - $this->table_captcha_questions => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', null, 'auto_increment'), - 'strict' => array('BOOL', 0), - 'lang_id' => array('UINT', 0), - 'lang_iso' => array('VCHAR:30', ''), - 'question_text' => array('TEXT_UNI', ''), - ), - 'PRIMARY_KEY' => 'question_id', - 'KEYS' => array( - 'lang' => array('INDEX', 'lang_iso'), - ), - ), - $this->table_captcha_answers => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', 0), - 'answer_text' => array('STEXT_UNI', ''), - ), - 'KEYS' => array( - 'qid' => array('INDEX', 'question_id'), - ), - ), - $this->table_qa_confirm => array ( - 'COLUMNS' => array( - 'session_id' => array('CHAR:32', ''), - 'confirm_id' => array('CHAR:32', ''), - 'lang_iso' => array('VCHAR:30', ''), - 'question_id' => array('UINT', 0), - 'attempts' => array('UINT', 0), - 'confirm_type' => array('USINT', 0), - ), - 'KEYS' => array( - 'session_id' => array('INDEX', 'session_id'), - 'lookup' => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')), - ), - 'PRIMARY_KEY' => 'confirm_id', - ), - ); - - foreach ($schemas as $table => $schema) - { - if (!$db_tool->sql_table_exists($table)) - { - $db_tool->sql_create_table($table, $schema); - } - } - } - - /** - * API function - see what has to be done to validate - */ - function validate() - { - global $phpbb_log, $user; - - $error = ''; - - 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'))); - return $user->lang('CONFIRM_QUESTION_MISSING'); - } - - if (!$this->confirm_id) - { - $error = $user->lang['CONFIRM_QUESTION_WRONG']; - } - else - { - if ($this->check_answer()) - { - $this->solved = true; - } - else - { - $error = $user->lang['CONFIRM_QUESTION_WRONG']; - } - } - - if (strlen($error)) - { - // okay, incorrect answer. Let's ask a new question. - $this->new_attempt(); - $this->solved = false; - - return $error; - } - else - { - return false; - } - } - - /** - * Select a question - */ - function select_question() - { - global $db, $user; - - if (!count($this->question_ids)) - { - return; - } - $this->confirm_id = md5(unique_id($user->ip)); - $this->question = (int) array_rand($this->question_ids); - - $sql = 'INSERT INTO ' . $this->table_qa_confirm . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $this->confirm_id, - 'session_id' => (string) $user->session_id, - 'lang_iso' => (string) $this->question_lang, - 'confirm_type' => (int) $this->type, - 'question_id' => (int) $this->question, - )); - $db->sql_query($sql); - - $this->load_answer(); - } - - /** - * New Question, if desired. - */ - function reselect_question() - { - global $db, $user; - - if (!count($this->question_ids)) - { - return; - } - - $this->question = (int) array_rand($this->question_ids); - $this->solved = 0; - - $sql = 'UPDATE ' . $this->table_qa_confirm . ' - SET question_id = ' . (int) $this->question . " - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $db->sql_query($sql); - - $this->load_answer(); - } - - /** - * Wrong answer, so we increase the attempts and use a different question. - */ - function new_attempt() - { - global $db, $user; - - // yah, I would prefer a stronger rand, but this should work - $this->question = (int) array_rand($this->question_ids); - $this->solved = 0; - - $sql = 'UPDATE ' . $this->table_qa_confirm . ' - SET question_id = ' . (int) $this->question . ", - attempts = attempts + 1 - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $db->sql_query($sql); - - $this->load_answer(); - } - - - /** - * See if there is already an entry for the current session. - */ - function load_confirm_id() - { - global $db, $user; - - $sql = 'SELECT confirm_id - FROM ' . $this->table_qa_confirm . " - WHERE - session_id = '" . $db->sql_escape($user->session_id) . "' - AND lang_iso = '" . $db->sql_escape($this->question_lang) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->confirm_id = $row['confirm_id']; - return true; - } - return false; - } - - /** - * Look up everything we need and populate the instance variables. - */ - function load_answer() - { - global $db, $user; - - if (!strlen($this->confirm_id) || !count($this->question_ids)) - { - return false; - } - - $sql = 'SELECT con.question_id, attempts, question_text, strict - FROM ' . $this->table_qa_confirm . ' con, ' . $this->table_captcha_questions . " qes - WHERE con.question_id = qes.question_id - AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->question = $row['question_id']; - - $this->attempts = $row['attempts']; - $this->question_strict = $row['strict']; - $this->question_text = $row['question_text']; - - return true; - } - - return false; - } - - /** - * The actual validation - */ - function check_answer() - { - global $db, $request; - - $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 . ' - WHERE question_id = ' . (int) $this->question; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']); - - if ($solution === $answer) - { - $this->solved = true; - - break; - } - } - $db->sql_freeresult($result); - - return $this->solved; - } - - /** - * API function - */ - function get_attempt_count() - { - return $this->attempts; - } - - /** - * API function - */ - function reset() - { - global $db, $user; - - $sql = 'DELETE FROM ' . $this->table_qa_confirm . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . (int) $this->type; - $db->sql_query($sql); - - // we leave the class usable by generating a new question - $this->select_question(); - } - - /** - * API function - */ - function is_solved() - { - global $request; - - if ($request->variable('qa_answer', false) && $this->solved === 0) - { - $this->validate(); - } - - return (bool) $this->solved; - } - - /** - * API function - The ACP backend, this marks the end of the easy methods - */ - function acp_page($id, $module) - { - global $config, $request, $phpbb_log, $template, $user; - - $user->add_lang('acp/board'); - $user->add_lang('captcha_qa'); - - if (!self::is_installed()) - { - $this->install(); - } - - $module->tpl_name = 'captcha_qa_acp'; - $module->page_title = 'ACP_VC_SETTINGS'; - $form_key = 'acp_captcha'; - add_form_key($form_key); - - $submit = $request->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 . "&configure=1&select_captcha=" . $this->get_service_name(); - - $template->assign_vars(array( - 'U_ACTION' => $module->u_action, - 'QUESTION_ID' => $question_id , - 'CLASS' => $this->get_service_name(), - )); - - // show the list? - if (!$question_id && $action != 'add') - { - $this->acp_question_list($module); - } - else if ($question_id && $action == 'delete') - { - if ($this->get_service_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id)) - { - if (confirm_box(true)) - { - $this->acp_delete_question($question_id); - - trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'question_id' => $question_id, - 'action' => $action, - 'configure' => 1, - 'select_captcha' => $this->get_service_name(), - )) - ); - } - } - else - { - trigger_error($user->lang['QA_LAST_QUESTION'] . adm_back_link($list_url), E_USER_WARNING); - } - } - else - { - // okay, show the editor - $question_input = $this->acp_get_question_input(); - $langs = $this->get_languages(); - - foreach ($langs as $lang => $entry) - { - $template->assign_block_vars('langs', array( - 'ISO' => $lang, - 'NAME' => $entry['name'], - )); - } - - $template->assign_vars(array( - 'U_LIST' => $list_url, - )); - - if ($question_id) - { - if ($question = $this->acp_get_question_data($question_id)) - { - $template->assign_vars(array( - 'QUESTION_TEXT' => ($question_input['question_text']) ? $question_input['question_text'] : $question['question_text'], - 'LANG_ISO' => ($question_input['lang_iso']) ? $question_input['lang_iso'] : $question['lang_iso'], - 'STRICT' => (isset($_REQUEST['strict'])) ? $question_input['strict'] : $question['strict'], - 'ANSWERS' => implode("\n", $question['answers']), - )); - } - else - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); - } - } - else - { - $template->assign_vars(array( - 'QUESTION_TEXT' => $question_input['question_text'], - 'LANG_ISO' => $question_input['lang_iso'], - 'STRICT' => $question_input['strict'], - 'ANSWERS' => (is_array($question_input['answers'])) ? implode("\n", $question_input['answers']) : '', - )); - } - - if ($submit && check_form_key($form_key)) - { - if (!$this->validate_input($question_input)) - { - $template->assign_vars(array( - 'S_ERROR' => true, - )); - } - else - { - if ($question_id) - { - $this->acp_update_question($question_input, $question_id); - } - else - { - $this->acp_add_question($question_input); - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL'); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url)); - } - } - else if ($submit) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url), E_USER_WARNING); - } - } - } - - /** - * This handles the list overview - */ - function acp_question_list($module) - { - global $db, $template; - - $sql = 'SELECT * - FROM ' . $this->table_captcha_questions; - $result = $db->sql_query($sql); - - $template->assign_vars(array( - 'S_LIST' => true, - )); - - while ($row = $db->sql_fetchrow($result)) - { - $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_service_name() . '&'; - - $template->assign_block_vars('questions', array( - 'QUESTION_TEXT' => $row['question_text'], - 'QUESTION_ID' => $row['question_id'], - 'QUESTION_LANG' => $row['lang_iso'], - 'U_DELETE' => "{$url}action=delete", - 'U_EDIT' => "{$url}action=edit", - )); - } - $db->sql_freeresult($result); - } - - /** - * Grab a question and bring it into a format the editor understands - */ - function acp_get_question_data($question_id) - { - global $db; - - if ($question_id) - { - $sql = 'SELECT * - FROM ' . $this->table_captcha_questions . ' - WHERE question_id = ' . $question_id; - $result = $db->sql_query($sql); - $question = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$question) - { - return false; - } - - $question['answers'] = array(); - - $sql = 'SELECT * - FROM ' . $this->table_captcha_answers . ' - WHERE question_id = ' . $question_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $question['answers'][] = $row['answer_text']; - } - $db->sql_freeresult($result); - - return $question; - } - - return false; - } - - /** - * Grab a question from input and bring it into a format the editor understands - */ - function acp_get_question_input() - { - global $request; - - $answers = $request->variable('answers', '', true); - - // Convert answers into array and filter if answers are set - if (strlen($answers)) - { - $answers = array_filter(array_map('trim', explode("\n", $answers)), function ($value) { - return $value !== ''; - }); - } - - $question = array( - 'question_text' => $request->variable('question_text', '', true), - 'strict' => $request->variable('strict', false), - 'lang_iso' => $request->variable('lang_iso', ''), - 'answers' => $answers, - ); - return $question; - } - - /** - * Update a question. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_update_question($data, $question_id) - { - global $db, $cache; - - // easier to delete all answers than to figure out which to update - $sql = 'DELETE FROM ' . $this->table_captcha_answers . " WHERE question_id = $question_id"; - $db->sql_query($sql); - - $langs = $this->get_languages(); - $question_ary = $data; - $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id']; - unset($question_ary['answers']); - - $sql = 'UPDATE ' . $this->table_captcha_questions . ' - SET ' . $db->sql_build_array('UPDATE', $question_ary) . " - WHERE question_id = $question_id"; - $db->sql_query($sql); - - $this->acp_insert_answers($data, $question_id); - - $cache->destroy('sql', $this->table_captcha_questions); - } - - /** - * Insert a question. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_add_question($data) - { - global $db, $cache; - - $langs = $this->get_languages(); - $question_ary = $data; - - $question_ary['lang_id'] = $langs[$data['lang_iso']]['id']; - unset($question_ary['answers']); - - $sql = 'INSERT INTO ' . $this->table_captcha_questions . ' ' . $db->sql_build_array('INSERT', $question_ary); - $db->sql_query($sql); - - $question_id = $db->sql_nextid(); - - $this->acp_insert_answers($data, $question_id); - - $cache->destroy('sql', $this->table_captcha_questions); - } - - /** - * Insert the answers. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_insert_answers($data, $question_id) - { - global $db, $cache; - - foreach ($data['answers'] as $answer) - { - $answer_ary = array( - 'question_id' => $question_id, - 'answer_text' => $answer, - ); - - $sql = 'INSERT INTO ' . $this->table_captcha_answers . ' ' . $db->sql_build_array('INSERT', $answer_ary); - $db->sql_query($sql); - } - - $cache->destroy('sql', $this->table_captcha_answers); - } - - /** - * Delete a question. - */ - function acp_delete_question($question_id) - { - global $db, $cache; - - $tables = array($this->table_captcha_questions, $this->table_captcha_answers); - - foreach ($tables as $table) - { - $sql = "DELETE FROM $table - WHERE question_id = $question_id"; - $db->sql_query($sql); - } - - $cache->destroy('sql', $tables); - } - - /** - * Check if the entered data can be inserted/used - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function validate_input($question_data) - { - $langs = $this->get_languages(); - - if (!isset($question_data['lang_iso']) || - !isset($question_data['question_text']) || - !isset($question_data['strict']) || - !isset($question_data['answers'])) - { - return false; - } - - if (!isset($langs[$question_data['lang_iso']]) || - !strlen($question_data['question_text']) || - !count($question_data['answers']) || - !is_array($question_data['answers'])) - { - return false; - } - - return true; - } - - /** - * List the installed language packs - */ - function get_languages() - { - global $db; - - $sql = 'SELECT * - FROM ' . LANG_TABLE; - $result = $db->sql_query($sql); - - $langs = array(); - while ($row = $db->sql_fetchrow($result)) - { - $langs[$row['lang_iso']] = array( - 'name' => $row['lang_local_name'], - 'id' => (int) $row['lang_id'], - ); - } - $db->sql_freeresult($result); - - return $langs; - } - - - - /** - * See if there is a question other than the one we have - */ - function acp_is_last($question_id) - { - global $config, $db; - - if ($question_id) - { - $sql = 'SELECT question_id - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "' - AND question_id <> " . (int) $question_id; - $result = $db->sql_query_limit($sql, 1); - $question = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$question) - { - return true; - } - return false; - } - } -} diff --git a/install/update/new/phpbb/class_loader.php b/install/update/new/phpbb/class_loader.php deleted file mode 100644 index a4b6931..0000000 --- a/install/update/new/phpbb/class_loader.php +++ /dev/null @@ -1,164 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* The class loader resolves class names to file system paths and loads them if -* necessary. -* -* Classes have to be of the form phpbb_(dir_)*(classpart_)*, so directory names -* must never contain underscores. Example: phpbb_dir_subdir_class_name is a -* valid class name, while phpbb_dir_sub_dir_class_name is not. -* -* If every part of the class name is a directory, the last directory name is -* also used as the filename, e.g. phpbb_dir would resolve to dir/dir.php. -*/ -class class_loader -{ - private $namespace; - private $path; - private $php_ext; - private $cache; - - /** - * A map of looked up class names to paths relative to $this->path. - * This map is stored in cache and looked up if the cache is available. - * - * @var array - */ - private $cached_paths = array(); - - /** - * Creates a new \phpbb\class_loader, which loads files with the given - * file extension from the given path. - * - * @param string $namespace Required namespace for files to be loaded - * @param string $path Directory to load files from - * @param string $php_ext The file extension for PHP files - * @param \phpbb\cache\driver\driver_interface $cache An implementation of the phpBB cache interface. - */ - public function __construct($namespace, $path, $php_ext = 'php', \phpbb\cache\driver\driver_interface $cache = null) - { - if ($namespace[0] !== '\\') - { - $namespace = '\\' . $namespace; - } - - $this->namespace = $namespace; - $this->path = $path; - $this->php_ext = $php_ext; - - $this->set_cache($cache); - } - - /** - * Provide the class loader with a cache to store paths. If set to null, the - * the class loader will resolve paths by checking for the existence of every - * directory in the class name every time. - * - * @param \phpbb\cache\driver\driver_interface $cache An implementation of the phpBB cache interface. - */ - public function set_cache(\phpbb\cache\driver\driver_interface $cache = null) - { - if ($cache) - { - $this->cached_paths = $cache->get('class_loader_' . str_replace('\\', '__', $this->namespace)); - - if ($this->cached_paths === false) - { - $this->cached_paths = array(); - } - } - - $this->cache = $cache; - } - - /** - * Registers the class loader as an autoloader using SPL. - */ - public function register() - { - spl_autoload_register(array($this, 'load_class')); - } - - /** - * Removes the class loader from the SPL autoloader stack. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'load_class')); - } - - /** - * Resolves a phpBB class name to a relative path which can be included. - * - * @param string $class The class name to resolve, must be in the - * namespace the loader was constructed with. - * Has to begin with \ - * @return string|bool A relative path to the file containing the - * class or false if looking it up failed. - */ - public function resolve_path($class) - { - if (isset($this->cached_paths[$class])) - { - return $this->path . $this->cached_paths[$class] . '.' . $this->php_ext; - } - - if (!preg_match('/^' . preg_quote($this->namespace, '/') . '[a-zA-Z0-9_\\\\]+$/', $class)) - { - return false; - } - - $relative_path = str_replace('\\', '/', substr($class, strlen($this->namespace))); - - if (!file_exists($this->path . $relative_path . '.' . $this->php_ext)) - { - return false; - } - - if ($this->cache) - { - $this->cached_paths[$class] = $relative_path; - $this->cache->put('class_loader_' . str_replace('\\', '__', $this->namespace), $this->cached_paths); - } - - return $this->path . $relative_path . '.' . $this->php_ext; - } - - /** - * Resolves a class name to a path and then includes it. - * - * @param string $class The class name which is being loaded. - */ - public function load_class($class) - { - // In general $class is not supposed to contain a leading backslash, - // but sometimes it does. See tickets PHP-50731 and HHVM-1840. - if ($class[0] !== '\\') - { - $class = '\\' . $class; - } - - if (substr($class, 0, strlen($this->namespace)) === $this->namespace) - { - $path = $this->resolve_path($class); - - if ($path) - { - require $path; - } - } - } -} diff --git a/install/update/new/phpbb/config/config.php b/install/update/new/phpbb/config/config.php deleted file mode 100644 index c619cae..0000000 --- a/install/update/new/phpbb/config/config.php +++ /dev/null @@ -1,186 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\config; - -/** -* Configuration container class -*/ -class config implements \ArrayAccess, \IteratorAggregate, \Countable -{ - /** - * The configuration data - * @var array(string => string) - */ - protected $config; - - /** - * Creates a configuration container with a default set of values - * - * @param array(string => string) $config The configuration data. - */ - public function __construct(array $config) - { - $this->config = $config; - } - - /** - * Retrieves an ArrayIterator over the configuration values. - * - * @return \ArrayIterator An iterator over all config data - */ - public function getIterator() - { - return new \ArrayIterator($this->config); - } - - /** - * Checks if the specified config value exists. - * - * @param string $key The configuration option's name. - * @return bool Whether the configuration option exists. - */ - public function offsetExists($key) - { - return isset($this->config[$key]); - } - - /** - * Retrieves a configuration value. - * - * @param string $key The configuration option's name. - * @return string The configuration value - */ - public function offsetGet($key) - { - return (isset($this->config[$key])) ? $this->config[$key] : ''; - } - - /** - * Temporarily overwrites the value of a configuration variable. - * - * The configuration change will not persist. It will be lost - * after the request. - * - * @param string $key The configuration option's name. - * @param string $value The temporary value. - */ - public function offsetSet($key, $value) - { - $this->config[$key] = $value; - } - - /** - * Called when deleting a configuration value directly, triggers an error. - * - * @param string $key The configuration option's name. - */ - public function offsetUnset($key) - { - trigger_error('Config values have to be deleted explicitly with the \phpbb\config\config::delete($key) method.', E_USER_ERROR); - } - - /** - * Retrieves the number of configuration options currently set. - * - * @return int Number of config options - */ - public function count() - { - return count($this->config); - } - - /** - * Removes a configuration option - * - * @param String $key The configuration option's name - * @param bool $use_cache Whether this variable should be cached or if it - * changes too frequently to be efficiently cached - * @return null - */ - public function delete($key, $use_cache = true) - { - unset($this->config[$key]); - } - - /** - * Sets a configuration option's value - * - * @param string $key The configuration option's name - * @param string $value New configuration value - * @param bool $use_cache Whether this variable should be cached or if it - * changes too frequently to be efficiently cached. - */ - public function set($key, $value, $use_cache = true) - { - $this->config[$key] = $value; - } - - /** - * Sets a configuration option's value only if the old_value matches the - * current configuration value or the configuration value does not exist yet. - * - * @param string $key The configuration option's name - * @param string $old_value Current configuration value - * @param string $new_value New configuration value - * @param bool $use_cache Whether this variable should be cached or if it - * changes too frequently to be efficiently cached. - * @return bool True if the value was changed, false otherwise. - */ - public function set_atomic($key, $old_value, $new_value, $use_cache = true) - { - if (!isset($this->config[$key]) || $this->config[$key] == $old_value) - { - $this->config[$key] = $new_value; - return true; - } - return false; - } - - /** - * Checks configuration option's value only if the new_value matches the - * current configuration value and the configuration value does exist.Called - * only after set_atomic has been called. - * - * @param string $key The configuration option's name - * @param string $new_value New configuration value - * @throws \phpbb\exception\http_exception when config value is set and not equal to new_value. - * @return bool True if the value was changed, false otherwise. - */ - public function ensure_lock($key, $new_value) - { - if (isset($this->config[$key]) && $this->config[$key] == $new_value) - { - return true; - } - throw new \phpbb\exception\http_exception(500, 'Failure while aqcuiring locks.'); - } - - /** - * Increments an integer configuration value. - * - * @param string $key The configuration option's name - * @param int $increment Amount to increment by - * @param bool $use_cache Whether this variable should be cached or if it - * changes too frequently to be efficiently cached. - */ - function increment($key, $increment, $use_cache = true) - { - if (!isset($this->config[$key])) - { - $this->config[$key] = 0; - } - - $this->config[$key] += $increment; - } -} diff --git a/install/update/new/phpbb/config_php_file.php b/install/update/new/phpbb/config_php_file.php deleted file mode 100644 index e3f7357..0000000 --- a/install/update/new/phpbb/config_php_file.php +++ /dev/null @@ -1,166 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -class config_php_file -{ - /** @var string phpBB Root Path */ - protected $phpbb_root_path; - - /** @var string php file extension */ - protected $php_ext; - - /** - * Indicates whether the php config file has been loaded. - * - * @var bool - */ - protected $config_loaded = false; - - /** - * The content of the php config file - * - * @var array - */ - protected $config_data = array(); - - /** - * The path to the config file. (Default: $phpbb_root_path . 'config.' . $php_ext) - * - * @var string - */ - protected $config_file; - - private $defined_vars; - - /** - * Constructor - * - * @param string $phpbb_root_path phpBB Root Path - * @param string $php_ext php file extension - */ - function __construct($phpbb_root_path, $php_ext) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - $this->config_file = $this->phpbb_root_path . 'config.' . $this->php_ext; - } - - /** - * Set the path to the config file. - * - * @param string $config_file - */ - public function set_config_file($config_file) - { - $this->config_file = $config_file; - $this->config_loaded = false; - } - - /** - * Returns an associative array containing the variables defined by the config file. - * - * @return array Return the content of the config file or an empty array if the file does not exists. - */ - public function get_all() - { - $this->load_config_file(); - - return $this->config_data; - } - - /** - * Return the value of a variable defined into the config.php file or null if the variable does not exist. - * - * @param string $variable The name of the variable - * @return mixed Value of the variable or null if the variable is not defined. - */ - public function get($variable) - { - $this->load_config_file(); - - return isset($this->config_data[$variable]) ? $this->config_data[$variable] : null; - } - - /** - * Load the config file and store the information. - * - * @return null - */ - protected function load_config_file() - { - if (!$this->config_loaded && file_exists($this->config_file)) - { - $this->defined_vars = get_defined_vars(); - - require($this->config_file); - $this->config_data = array_diff_key(get_defined_vars(), $this->defined_vars); - - $this->config_loaded = true; - } - } - - /** - * Convert either 3.0 dbms or 3.1 db driver class name to 3.1 db driver class name. - * - * If $dbms is a valid 3.1 db driver class name, returns it unchanged. - * Otherwise prepends phpbb\db\driver\ to the dbms to convert a 3.0 dbms - * to 3.1 db driver class name. - * - * @param string $dbms dbms parameter - * @return string driver class - * @throws \RuntimeException - */ - public function convert_30_dbms_to_31($dbms) - { - // Note: this check is done first because mysqli extension - // supplies a mysqli class, and class_exists($dbms) would return - // true for mysqli class. - // However, per the docblock any valid 3.1 driver name should be - // recognized by this function, and have priority over 3.0 dbms. - if (strpos($dbms, 'phpbb\db\driver') === false && class_exists('phpbb\db\driver\\' . $dbms)) - { - return 'phpbb\db\driver\\' . $dbms; - } - - if (class_exists($dbms)) - { - // Additionally we could check that $dbms extends phpbb\db\driver\driver. - // http://php.net/manual/en/class.reflectionclass.php - // Beware of possible performance issues: - // http://stackoverflow.com/questions/294582/php-5-reflection-api-performance - // We could check for interface implementation in all paths or - // only when we do not prepend phpbb\db\driver\. - - /* - $reflection = new \ReflectionClass($dbms); - - if ($reflection->isSubclassOf('phpbb\db\driver\driver')) - { - return $dbms; - } - */ - - return $dbms; - } - - // Force use of mysqli when specifying mysql - if (preg_match('/(phpbb\\\db\\\driver\\\)?mysql$/i', $dbms)) - { - return 'phpbb\db\driver\mysqli'; - } - - throw new \RuntimeException("You have specified an invalid dbms driver: $dbms"); - } -} diff --git a/install/update/new/phpbb/console/command/cron/run.php b/install/update/new/phpbb/console/command/cron/run.php deleted file mode 100644 index 511c6bc..0000000 --- a/install/update/new/phpbb/console/command/cron/run.php +++ /dev/null @@ -1,173 +0,0 @@ - -* @license 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\cron; - -use phpbb\exception\runtime_exception; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Output\OutputInterface; - -class run extends \phpbb\console\command\command -{ - /** @var \phpbb\cron\manager */ - protected $cron_manager; - - /** @var \phpbb\lock\db */ - protected $lock_db; - - /** - * Construct method - * - * @param \phpbb\user $user The user object (used to get language information) - * @param \phpbb\cron\manager $cron_manager The cron manager containing - * the cron tasks to be executed. - * @param \phpbb\lock\db $lock_db The lock for accessing database. - */ - public function __construct(\phpbb\user $user, \phpbb\cron\manager $cron_manager, \phpbb\lock\db $lock_db) - { - $this->cron_manager = $cron_manager; - $this->lock_db = $lock_db; - parent::__construct($user); - } - - /** - * Sets the command name and description - * - * @return null - */ - protected function configure() - { - $this - ->setName('cron:run') - ->setDescription($this->user->lang('CLI_DESCRIPTION_CRON_RUN')) - ->setHelp($this->user->lang('CLI_HELP_CRON_RUN')) - ->addArgument('name', InputArgument::OPTIONAL, $this->user->lang('CLI_DESCRIPTION_CRON_RUN_ARGUMENT_1')) - ; - } - - /** - * Executes the command cron:run. - * - * Tries to acquire the cron lock, then if no argument has been given runs all ready cron tasks. - * If the cron lock can not be obtained, an error message is printed - * and the exit status is set to 1. - * If the verbose option is specified, each start of a task is printed. - * Otherwise there is no output. - * If an argument is given to the command, only the task whose name matches the - * argument will be started. If verbose option is specified, - * an info message containing the name of the task is printed. - * If no task matches the argument given, an error message is printed - * and the exit status is set to 2. - * - * @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 lock error occurred and 2 if no task matching the argument was found. - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - if ($this->lock_db->acquire()) - { - $task_name = $input->getArgument('name'); - if ($task_name) - { - $exit_status = $this->run_one($input, $output, $task_name); - } - else - { - $exit_status = $this->run_all($input, $output); - } - - $this->lock_db->release(); - return $exit_status; - } - else - { - throw new runtime_exception('CRON_LOCK_ERROR', array(), null, 1); - } - } - - /** - * Executes all ready cron tasks. - * - * If verbose mode is set, an info message will be printed if there is no task to - * be run, or else for each starting task. - * - * @see execute - * @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 - */ - protected function run_all(InputInterface $input, OutputInterface $output) - { - $run_tasks = $this->cron_manager->find_all_ready_tasks(); - - if ($run_tasks) - { - foreach ($run_tasks as $task) - { - if ($input->getOption('verbose')) - { - $output->writeln('' . $this->user->lang('RUNNING_TASK', $task->get_name()) . ''); - } - - $task->run(); - } - } - else - { - if ($input->getOption('verbose')) - { - $output->writeln('' . $this->user->lang('CRON_NO_TASK') . ''); - } - } - - return 0; - } - - /** - * Executes a given cron task, if it is ready. - * - * If there is a task whose name matches $task_name, it is run and 0 is returned. - * and if verbose mode is set, print an info message with the name of the task. - * If there is no task matching $task_name, the function prints an error message - * and returns with status 2. - * - * @see execute - * - * @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. - * @param string $task_name The name of the task that should be run. - * - * @return int 0 if all is well, 2 if no task matches $task_name. - */ - protected function run_one(InputInterface $input, OutputInterface $output, $task_name) - { - $task = $this->cron_manager->find_task($task_name); - if ($task) - { - if ($input->getOption('verbose')) - { - $output->writeln('' . $this->user->lang('RUNNING_TASK', $task_name) . ''); - } - - $task->run(); - return 0; - } - else - { - throw new runtime_exception('CRON_NO_SUCH_TASK', array( $task_name), null, 2); - } - } -} diff --git a/install/update/new/phpbb/console/command/extension/enable.php b/install/update/new/phpbb/console/command/extension/enable.php deleted file mode 100644 index 504b554..0000000 --- a/install/update/new/phpbb/console/command/extension/enable.php +++ /dev/null @@ -1,78 +0,0 @@ - -* @license 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\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 -{ - protected function configure() - { - $this - ->setName('extension:enable') - ->setDescription($this->user->lang('CLI_DESCRIPTION_ENABLE_EXTENSION')) - ->addArgument( - 'extension-name', - InputArgument::REQUIRED, - $this->user->lang('CLI_EXTENSION_NAME') - ) - ; - } - - 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 (($enableable = $extension->is_enableable()) !== true) - { - $message = !empty($enableable) ? $enableable : $this->user->lang('CLI_EXTENSION_NOT_ENABLEABLE', $name); - $message = is_array($message) ? implode(PHP_EOL, $message) : $message; - $io->error($message); - 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)); - $io->success($this->user->lang('CLI_EXTENSION_ENABLE_SUCCESS', $name)); - return 0; - } - else - { - $io->error($this->user->lang('CLI_EXTENSION_ENABLE_FAILURE', $name)); - return 1; - } - } -} diff --git a/install/update/new/phpbb/console/command/update/check.php b/install/update/new/phpbb/console/command/update/check.php deleted file mode 100644 index 4cd7d21..0000000 --- a/install/update/new/phpbb/console/command/update/check.php +++ /dev/null @@ -1,332 +0,0 @@ - -* @license 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 occurred. - * @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 string $stability Stability specifier string - * @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("%s", $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("%s", $metadata['version']); - $row[] = implode(', ', $versions); - } - else - { - $row[] = sprintf("%s", $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[] = '' . $exception_message . ''; - } - catch (\RuntimeException $e) - { - $row[] = '' . $e->getMessage() . ''; - } - - $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/install/update/new/phpbb/console/command/user/add.php b/install/update/new/phpbb/console/command/user/add.php deleted file mode 100644 index 303216a..0000000 --- a/install/update/new/phpbb/console/command/user/add.php +++ /dev/null @@ -1,334 +0,0 @@ - - * @license 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'], 0), - 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/install/update/new/phpbb/content_visibility.php b/install/update/new/phpbb/content_visibility.php deleted file mode 100644 index fbc56f3..0000000 --- a/install/update/new/phpbb/content_visibility.php +++ /dev/null @@ -1,899 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* phpbb_visibility -* Handle fetching and setting the visibility for topics and posts -*/ -class content_visibility -{ - /** - * Database object - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Auth object - * @var \phpbb\auth\auth - */ - protected $auth; - - /** - * config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * phpBB root path - * @var string - */ - protected $phpbb_root_path; - - /** - * PHP Extension - * @var string - */ - protected $php_ext; - - /** - * Constructor - * - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\user $user User object - * @param string $phpbb_root_path Root path - * @param string $php_ext PHP Extension - * @param string $forums_table Forums table name - * @param string $posts_table Posts table name - * @param string $topics_table Topics table name - * @param string $users_table Users table name - */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table) - { - $this->auth = $auth; - $this->config = $config; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->db = $db; - $this->user = $user; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - $this->forums_table = $forums_table; - $this->posts_table = $posts_table; - $this->topics_table = $topics_table; - $this->users_table = $users_table; - } - - /** - * Can the current logged-in user soft-delete posts? - * - * @param $forum_id int Forum ID whose permissions to check - * @param $poster_id int Poster ID of the post in question - * @param $post_locked bool Is the post locked? - * @return bool - */ - public function can_soft_delete($forum_id, $poster_id, $post_locked) - { - if ($this->auth->acl_get('m_softdelete', $forum_id)) - { - return true; - } - else if ($this->auth->acl_get('f_softdelete', $forum_id) && $poster_id == $this->user->data['user_id'] && !$post_locked) - { - return true; - } - - return false; - } - - /** - * Get the topics post count or the forums post/topic count based on permissions - * - * @param $mode string One of topic_posts, forum_posts or forum_topics - * @param $data array Array with the topic/forum data to calculate from - * @param $forum_id int The forum id is used for permission checks - * @return int Number of posts/topics the user can see in the topic/forum - */ - public function get_count($mode, $data, $forum_id) - { - if (!$this->auth->acl_get('m_approve', $forum_id)) - { - return (int) $data[$mode . '_approved']; - } - - 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) - { - $visibility = $data[$mode . '_visibility']; - $poster_key = ($mode === 'topic') ? 'topic_poster' : 'poster_id'; - $is_visible = ($visibility == ITEM_APPROVED) || - ($this->config['display_unapproved_posts'] && - ($this->user->data['user_id'] != ANONYMOUS) && - ($visibility == ITEM_UNAPPROVED || $visibility == ITEM_REAPPROVE) && - ($this->user->data['user_id'] == $data[$poster_key])) || - $this->auth->acl_get('m_approve', $forum_id); - - /** - * 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 - * - * 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 $table_alias string Table alias to prefix in SQL queries - * @return string The appropriate combination SQL logic for topic/post_visibility - */ - public function get_visibility_sql($mode, $forum_id, $table_alias = '') - { - $where_sql = ''; - - $get_visibility_sql_overwrite = false; - - /** - * Allow changing the result of calling get_visibility_sql - * - * @event core.phpbb_content_visibility_get_visibility_sql_before - * @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_id The forum id in which the search is made. - * @var string table_alias Table alias to prefix in SQL queries - * @var mixed get_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event - * If false, get_visibility_sql continues normally - * It must be either boolean or string - * @since 3.1.4-RC1 - */ - $vars = array( - 'where_sql', - 'mode', - 'forum_id', - 'table_alias', - 'get_visibility_sql_overwrite', - ); - extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_visibility_sql_before', compact($vars))); - - if ($get_visibility_sql_overwrite !== false) - { - return $get_visibility_sql_overwrite; - } - - if ($this->auth->acl_get('m_approve', $forum_id)) - { - $where_sql .= '1 = 1'; - } - else - { - $visibility_query = $table_alias . $mode . '_visibility = '; - - $where_sql .= '(' . $visibility_query . ITEM_APPROVED . ')'; - if ($this->config['display_unapproved_posts'] && ($this->user->data['user_id'] != ANONYMOUS)) - { - $poster_key = ($mode === 'topic') ? 'topic_poster' : 'poster_id'; - $where_sql .= ' OR ((' . $visibility_query . ITEM_UNAPPROVED . ' OR ' . $visibility_query . ITEM_REAPPROVE .')'; - $where_sql .= ' AND ' . $table_alias . $poster_key . ' = ' . ((int) $this->user->data['user_id']) . ')'; - } - } - return '(' . $where_sql . ')'; - } - - /** - * Create topic/post visibility SQL for a set of forums - * - * Note: Read permissions are not checked. Forums without read permissions - * should not be in $forum_ids - * - * @param $mode string Either "topic" or "post" - * @param $forum_ids array Array of forum ids which the posts/topics are limited to - * @param $table_alias string Table alias to prefix in SQL queries - * @return string The appropriate combination SQL logic for topic/post_visibility - */ - public function get_forums_visibility_sql($mode, $forum_ids = array(), $table_alias = '') - { - $where_sql = ''; - - $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 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 - * @var array approve_forums Array of forums where the user has m_approve permissions - * @var mixed get_forums_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event - * If false, get_forums_visibility_sql continues normally - * It must be either boolean or string - * @since 3.1.3-RC1 - */ - $vars = array( - 'where_sql', - 'mode', - 'forum_ids', - 'table_alias', - 'approve_forums', - 'get_forums_visibility_sql_overwrite', - ); - extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_forums_visibility_before', compact($vars))); - - if ($get_forums_visibility_sql_overwrite !== false) - { - return $get_forums_visibility_sql_overwrite; - } - - // 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, false, true) . '))'; - - return '(' . $where_sql . ')'; - } - - /** - * Create topic/post visibility SQL for all forums on the board - * - * Note: Read permissions are not checked. Forums without read permissions - * should be in $exclude_forum_ids - * - * @param $mode string Either "topic" or "post" - * @param $exclude_forum_ids array Array of forum ids which are excluded - * @param $table_alias string Table alias to prefix in SQL queries - * @return string The appropriate combination SQL logic for topic/post_visibility - */ - public function get_global_visibility_sql($mode, $exclude_forum_ids = array(), $table_alias = '') - { - $where_sqls = array(); - - $approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids); - - $visibility_sql_overwrite = null; - - /** - * Allow changing the result of calling get_global_visibility_sql - * - * @event core.phpbb_content_visibility_get_global_visibility_before - * @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 If not empty, forces the function to return visibility_sql_overwrite after executing the event - * @since 3.1.3-RC1 - */ - $vars = array( - 'where_sqls', - 'mode', - 'exclude_forum_ids', - 'table_alias', - 'approve_forums', - 'visibility_sql_overwrite', - ); - extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_global_visibility_before', compact($vars))); - - if ($visibility_sql_overwrite) - { - return $visibility_sql_overwrite; - } - - // 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 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) . ')'; - } - - /** - * Change visibility status of one post or all posts of a topic - * - * @param $visibility int Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @param $post_id mixed Post ID or array of post IDs to act on, - * if it is empty, all posts of topic_id will be modified - * @param $topic_id int Topic where $post_id is found - * @param $forum_id int Forum where $topic_id is found - * @param $user_id int User performing the action - * @param $time int Timestamp when the action is performed - * @param $reason string Reason why the visibility was changed. - * @param $is_starter bool Is this the first post of the topic changed? - * @param $is_latest bool Is this the last post of the topic changed? - * @param $limit_visibility mixed Limit updating per topic_id to a certain visibility - * @param $limit_delete_time mixed Limit updating per topic_id to a certain deletion time - * @return array Changed post data, empty array if an error occurred. - */ - public function set_post_visibility($visibility, $post_id, $topic_id, $forum_id, $user_id, $time, $reason, $is_starter, $is_latest, $limit_visibility = false, $limit_delete_time = false) - { - if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE))) - { - return array(); - } - - if ($post_id) - { - if (is_array($post_id)) - { - $where_sql = $this->db->sql_in_set('post_id', array_map('intval', $post_id)); - } - else - { - $where_sql = 'post_id = ' . (int) $post_id; - } - $where_sql .= ' AND topic_id = ' . (int) $topic_id; - } - else - { - $where_sql = 'topic_id = ' . (int) $topic_id; - - // Limit the posts to a certain visibility and deletion time - // This allows us to only restore posts, that were approved - // when the topic got soft deleted. So previous soft deleted - // and unapproved posts are still soft deleted/unapproved - if ($limit_visibility !== false) - { - $where_sql .= ' AND post_visibility = ' . (int) $limit_visibility; - } - - if ($limit_delete_time !== false) - { - $where_sql .= ' AND post_delete_time = ' . (int) $limit_delete_time; - } - } - - $sql = 'SELECT poster_id, post_id, post_postcount, post_visibility - FROM ' . $this->posts_table . ' - WHERE ' . $where_sql; - $result = $this->db->sql_query($sql); - - $post_ids = $poster_postcounts = $postcounts = $postcount_visibility = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $post_ids[] = (int) $row['post_id']; - - if ($row['post_visibility'] != $visibility) - { - if ($row['post_postcount'] && !isset($poster_postcounts[(int) $row['poster_id']])) - { - $poster_postcounts[(int) $row['poster_id']] = 1; - } - else if ($row['post_postcount']) - { - $poster_postcounts[(int) $row['poster_id']]++; - } - - if (!isset($postcount_visibility[$row['post_visibility']])) - { - $postcount_visibility[$row['post_visibility']] = 1; - } - else - { - $postcount_visibility[$row['post_visibility']]++; - } - } - } - $this->db->sql_freeresult($result); - - if (empty($post_ids)) - { - return array(); - } - - if (!function_exists('truncate_string')) - { - include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext); - } - - $data = array( - 'post_visibility' => (int) $visibility, - 'post_delete_user' => (int) $user_id, - 'post_delete_time' => ((int) $time) ?: time(), - 'post_delete_reason' => truncate_string($reason, 255, 255, false), - ); - /** - * Perform actions right before the query to change post visibility - * - * @event core.set_post_visibility_before_sql - * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @var array post_id Array containing all post IDs to be modified. If blank, all posts within the topic are modified. - * @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 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', - 'post_id', - 'topic_id', - 'forum_id', - 'user_id', - 'time', - 'reason', - 'is_starter', - 'is_latest', - 'data', - ); - extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_before_sql', compact($vars))); - $sql = 'UPDATE ' . $this->posts_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $data) . ' - WHERE ' . $this->db->sql_in_set('post_id', $post_ids); - $this->db->sql_query($sql); - - // Group the authors by post count, to reduce the number of queries - foreach ($poster_postcounts as $poster_id => $num_posts) - { - $postcounts[$num_posts][] = $poster_id; - } - - // Update users postcounts - foreach ($postcounts as $num_posts => $poster_ids) - { - if (in_array($visibility, array(ITEM_REAPPROVE, ITEM_DELETED))) - { - $sql = 'UPDATE ' . $this->users_table . ' - SET user_posts = 0 - WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . ' - AND user_posts < ' . $num_posts; - $this->db->sql_query($sql); - - $sql = 'UPDATE ' . $this->users_table . ' - SET user_posts = user_posts - ' . $num_posts . ' - WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . ' - AND user_posts >= ' . $num_posts; - $this->db->sql_query($sql); - } - else - { - $sql = 'UPDATE ' . $this->users_table . ' - SET user_posts = user_posts + ' . $num_posts . ' - WHERE ' . $this->db->sql_in_set('user_id', $poster_ids); - $this->db->sql_query($sql); - } - } - - $update_topic_postcount = true; - - // Sync the first/last topic information if needed - if (!$is_starter && $is_latest) - { - if (!function_exists('update_post_information')) - { - include($this->phpbb_root_path . 'includes/functions_posting.' . $this->php_ext); - } - - // update_post_information can only update the last post info ... - if ($topic_id) - { - update_post_information('topic', $topic_id, false); - } - if ($forum_id) - { - update_post_information('forum', $forum_id, false); - } - } - else if ($is_starter && $topic_id) - { - if (!function_exists('sync')) - { - include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext); - } - - // ... so we need to use sync, if the first post is changed. - // The forum is resynced recursive by sync() itself. - sync('topic', 'topic_id', $topic_id, true); - - // sync recalculates the topic replies and forum posts by itself, so we don't do that. - $update_topic_postcount = false; - } - - $topic_update_array = array(); - // Update the topic's reply count and the forum's post count - if ($update_topic_postcount) - { - $field_alias = array( - ITEM_APPROVED => 'posts_approved', - ITEM_UNAPPROVED => 'posts_unapproved', - ITEM_DELETED => 'posts_softdeleted', - ITEM_REAPPROVE => 'posts_unapproved', - ); - $cur_posts = array_fill_keys($field_alias, 0); - - foreach ($postcount_visibility as $post_visibility => $visibility_posts) - { - $cur_posts[$field_alias[(int) $post_visibility]] += $visibility_posts; - } - - $sql_ary = array(); - $recipient_field = $field_alias[$visibility]; - - foreach ($cur_posts as $field => $count) - { - // Decrease the count for the old statuses. - if ($count && $field != $recipient_field) - { - $sql_ary[$field] = " - $count"; - } - } - // Add up the count from all statuses excluding the recipient status. - $count_increase = array_sum(array_diff($cur_posts, array($recipient_field))); - - if ($count_increase) - { - $sql_ary[$recipient_field] = " + $count_increase"; - } - - if (count($sql_ary)) - { - $forum_sql = array(); - - foreach ($sql_ary as $field => $value_change) - { - $topic_update_array[] = 'topic_' . $field . ' = topic_' . $field . $value_change; - $forum_sql[] = 'forum_' . $field . ' = forum_' . $field . $value_change; - } - - $sql = 'UPDATE ' . $this->forums_table . ' - SET ' . implode(', ', $forum_sql) . ' - WHERE forum_id = ' . (int) $forum_id; - $this->db->sql_query($sql); - } - } - - if ($post_id) - { - $sql = 'SELECT 1 AS has_attachments - FROM ' . POSTS_TABLE . ' - WHERE topic_id = ' . (int) $topic_id . ' - AND post_attachment = 1 - AND post_visibility = ' . ITEM_APPROVED . ' - AND ' . $this->db->sql_in_set('post_id', $post_id, true); - $result = $this->db->sql_query_limit($sql, 1); - - $has_attachment = (bool) $this->db->sql_fetchfield('has_attachments'); - $this->db->sql_freeresult($result); - - if ($has_attachment && $visibility == ITEM_APPROVED) - { - $topic_update_array[] = 'topic_attachment = 1'; - } - else if (!$has_attachment && $visibility != ITEM_APPROVED) - { - $topic_update_array[] = 'topic_attachment = 0'; - } - } - - if (!empty($topic_update_array)) - { - // Update the number for replies and posts, and update the attachments flag - $sql = 'UPDATE ' . $this->topics_table . ' - SET ' . implode(', ', $topic_update_array) . ' - WHERE topic_id = ' . (int) $topic_id; - $this->db->sql_query($sql); - } - /** - * Perform actions after all steps to changing post visibility - * - * @event core.set_post_visibility_after - * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @var array post_id Array containing all post IDs to be modified. If blank, all posts within the topic are modified. - * @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 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', - 'post_id', - 'topic_id', - 'forum_id', - 'user_id', - 'time', - 'reason', - 'is_starter', - 'is_latest', - 'data', - ); - extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_after', compact($vars))); - return $data; - } - - /** - * Set topic visibility - * - * Allows approving (which is akin to undeleting/restore) or soft deleting an entire topic. - * Calls set_post_visibility as needed. - * - * Note: By default, when a soft deleted topic is restored. Only posts that - * were approved at the time of soft deleting, are being restored. - * Same applies to soft deleting. Only approved posts will be marked - * as soft deleted. - * If you want to update all posts, use the force option. - * - * @param $visibility int Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @param $topic_id mixed Topic ID to act on - * @param $forum_id int Forum where $topic_id is found - * @param $user_id int User performing the action - * @param $time int Timestamp when the action is performed - * @param $reason string Reason why the visibilty was changed. - * @param $force_update_all bool Force to update all posts within the topic - * @return array Changed topic data, empty array if an error occurred. - */ - public function set_topic_visibility($visibility, $topic_id, $forum_id, $user_id, $time, $reason, $force_update_all = false) - { - if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE))) - { - return array(); - } - - if (!$force_update_all) - { - $sql = 'SELECT topic_visibility, topic_delete_time - FROM ' . $this->topics_table . ' - WHERE topic_id = ' . (int) $topic_id; - $result = $this->db->sql_query($sql); - $original_topic_data = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if (!$original_topic_data) - { - // The topic does not exist... - return array(); - } - } - - if (!function_exists('truncate_string')) - { - include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext); - } - - // Note, we do not set a reason for the posts, just for the topic - $data = array( - 'topic_visibility' => (int) $visibility, - 'topic_delete_user' => (int) $user_id, - 'topic_delete_time' => ((int) $time) ?: time(), - 'topic_delete_reason' => truncate_string($reason, 255, 255, false), - ); - /** - * Perform actions right before the query to change topic visibility - * - * @event core.set_topic_visibility_before_sql - * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @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 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', - 'time', - 'reason', - 'force_update_all', - 'data', - ); - extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_before_sql', compact($vars))); - $sql = 'UPDATE ' . $this->topics_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $data) . ' - WHERE topic_id = ' . (int) $topic_id; - $this->db->sql_query($sql); - - if (!$this->db->sql_affectedrows()) - { - return array(); - } - - if (!$force_update_all && $original_topic_data['topic_delete_time'] && $original_topic_data['topic_visibility'] == ITEM_DELETED && $visibility == ITEM_APPROVED) - { - // If we're restoring a topic we only restore posts, that were soft deleted through the topic soft deletion. - $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility'], $original_topic_data['topic_delete_time']); - } - else if (!$force_update_all && $original_topic_data['topic_visibility'] == ITEM_APPROVED && $visibility == ITEM_DELETED) - { - // If we're soft deleting a topic we only mark approved posts as soft deleted. - $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility']); - } - else - { - $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true); - } - /** - * Perform actions after all steps to changing topic visibility - * - * @event core.set_topic_visibility_after - * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @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 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', - 'time', - 'reason', - 'force_update_all', - 'data', - ); - extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_after', compact($vars))); - return $data; - } - - /** - * Add post to topic and forum statistics - * - * @param $data array Contains information from the topics table about given topic - * @param &$sql_data array Populated with the SQL changes, may be empty at call time - * @return null - */ - public function add_post_to_statistic($data, &$sql_data) - { - $sql_data[$this->topics_table] = (($sql_data[$this->topics_table]) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved + 1'; - - $sql_data[$this->forums_table] = (($sql_data[$this->forums_table]) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved + 1'; - - if ($data['post_postcount']) - { - $sql_data[$this->users_table] = (($sql_data[$this->users_table]) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts + 1'; - } - - $this->config->increment('num_posts', 1, false); - } - - /** - * Remove post from topic and forum statistics - * - * @param $data array Contains information from the topics table about given topic - * @param &$sql_data array Populated with the SQL changes, may be empty at call time - * @return null - */ - public function remove_post_from_statistic($data, &$sql_data) - { - if ($data['post_visibility'] == ITEM_APPROVED) - { - $sql_data[$this->topics_table] = ((!empty($sql_data[$this->topics_table])) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved - 1'; - $sql_data[$this->forums_table] = ((!empty($sql_data[$this->forums_table])) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved - 1'; - - if ($data['post_postcount']) - { - $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1'; - } - - $this->config->increment('num_posts', -1, false); - } - else if ($data['post_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE) - { - $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_unapproved = forum_posts_unapproved - 1'; - $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_unapproved = topic_posts_unapproved - 1'; - } - else if ($data['post_visibility'] == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_softdeleted = forum_posts_softdeleted - 1'; - $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_softdeleted = topic_posts_softdeleted - 1'; - } - } - - /** - * Remove topic from forum statistics - * - * @param $data array Post and topic data - * @param &$sql_data array Populated with the SQL changes, may be empty at call time - * @return null - */ - public function remove_topic_from_statistic($data, &$sql_data) - { - if ($data['topic_visibility'] == ITEM_APPROVED) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_approved = forum_posts_approved - 1, forum_topics_approved = forum_topics_approved - 1'; - - if ($data['post_postcount']) - { - $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1'; - } - } - else if ($data['topic_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_unapproved = forum_posts_unapproved - 1, forum_topics_unapproved = forum_topics_unapproved - 1'; - } - else if ($data['topic_visibility'] == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_softdeleted = forum_posts_softdeleted - 1, forum_topics_softdeleted = forum_topics_softdeleted - 1'; - } - - } -} diff --git a/install/update/new/phpbb/controller/helper.php b/install/update/new/phpbb/controller/helper.php deleted file mode 100644 index 58a4a49..0000000 --- a/install/update/new/phpbb/controller/helper.php +++ /dev/null @@ -1,195 +0,0 @@ - -* @license 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\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; - -/** -* Controller helper class, contains methods that do things for controllers -*/ -class helper -{ - /** - * Template object - * @var \phpbb\template\template - */ - protected $template; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * config object - * @var \phpbb\config\config - */ - protected $config; - - /* @var \phpbb\symfony_request */ - protected $symfony_request; - - /* @var \phpbb\request\request_interface */ - protected $request; - - /** - * @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 - * @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->routing_helper = $routing_helper; - } - - /** - * 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 int $status_code The status code to be sent to the page header - * @param bool $display_online_list Do we display online users list - * @param int $item_id Restrict online users to item id - * @param string $item Restrict online users to a certain session item, e.g. forum for session_forum_id - * @param bool $send_headers Whether headers should be sent by page_header(). Defaults to false for controllers. - * - * @return Response object containing rendered page - */ - public function render($template_file, $page_title = '', $status_code = 200, $display_online_list = false, $item_id = 0, $item = 'forum', $send_headers = false) - { - page_header($page_title, $display_online_list, $item_id, $item, $send_headers); - - $this->template->set_filenames(array( - 'body' => $template_file, - )); - - page_footer(true, false, false); - - $headers = !empty($this->user->data['is_bot']) ? array('X-PHPBB-IS-BOT' => 'yes') : array(); - - return new Response($this->template->assign_display('body'), $status_code, $headers); - } - - /** - * 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 & (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) - { - return $this->routing_helper->route($route, $params, $is_amp, $session_id, $reference_type); - } - - /** - * Output an error, effectively the same thing as trigger_error - * - * @param string $message The error message - * @param int $code The error code (e.g. 404, 500, 503, etc.) - * @return Response A Response instance - * - * @deprecated 3.1.3 (To be removed: 4.0.0) Use exceptions instead. - */ - public function error($message, $code = 500) - { - return $this->message($message, array(), 'INFORMATION', $code); - } - - /** - * Output a message - * - * In case of an error, please throw an exception instead - * - * @param string $message The message to display (must be a language variable) - * @param array $parameters The parameters to use with the language var - * @param string $title Title for the message (must be a language variable) - * @param int $code The HTTP status code (e.g. 404, 500, 503, etc.) - * @return Response A Response instance - */ - public function message($message, array $parameters = array(), $title = 'INFORMATION', $code = 200) - { - array_unshift($parameters, $message); - $message_text = call_user_func_array(array($this->user, 'lang'), $parameters); - $message_title = $this->user->lang($title); - - if ($this->request->is_ajax()) - { - global $refresh_data; - - return new JsonResponse( - array( - 'MESSAGE_TITLE' => $message_title, - 'MESSAGE_TEXT' => $message_text, - 'S_USER_WARNING' => false, - 'S_USER_NOTICE' => false, - 'REFRESH_DATA' => (!empty($refresh_data)) ? $refresh_data : null - ), - $code - ); - } - - $this->template->assign_vars(array( - 'MESSAGE_TEXT' => $message_text, - 'MESSAGE_TITLE' => $message_title, - )); - - return $this->render('message_body.html', $message_title, $code); - } - - /** - * 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' => '', - )); - } - - /** - * Return the current url - * - * @return string - */ - public function get_current_url() - { - return generate_board_url(true) . $this->request->escape($this->symfony_request->getRequestUri(), true); - } -} diff --git a/install/update/new/phpbb/cron/controller/cron.php b/install/update/new/phpbb/cron/controller/cron.php deleted file mode 100644 index 6f0e35e..0000000 --- a/install/update/new/phpbb/cron/controller/cron.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @license 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\controller; - -use Symfony\Component\HttpFoundation\Response; - -/** - * Controller for running cron jobs - */ -class cron -{ - /** - * Handles CRON requests - * - * @param string $cron_type - * - * @return Response - */ - public function handle($cron_type) - { - $response = new Response(); - $response->headers->set('Cache-Control', 'no-cache'); - $response->headers->set('Content-type', 'image/gif'); - $response->headers->set('Content-length', '43'); - $response->setContent(base64_decode('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==')); - - return $response; - } -} diff --git a/install/update/new/phpbb/cron/event/cron_runner_listener.php b/install/update/new/phpbb/cron/event/cron_runner_listener.php deleted file mode 100644 index 9e9ecf0..0000000 --- a/install/update/new/phpbb/cron/event/cron_runner_listener.php +++ /dev/null @@ -1,103 +0,0 @@ - - * @license 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\event; - -use phpbb\cron\manager; -use phpbb\lock\db; -use phpbb\request\request_interface; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\HttpKernel\Event\PostResponseEvent; - -/** - * Event listener that executes cron tasks, after the response was served - */ -class cron_runner_listener implements EventSubscriberInterface -{ - /** - * @var \phpbb\lock\db - */ - private $cron_lock; - - /** - * @var \phpbb\cron\manager - */ - private $cron_manager; - - /** - * @var \phpbb\request\request_interface - */ - private $request; - - /** - * Constructor - * - * @param db $lock - * @param manager $manager - * @param request_interface $request - */ - public function __construct(db $lock, manager $manager, request_interface $request) - { - $this->cron_lock = $lock; - $this->cron_manager = $manager; - $this->request = $request; - } - - /** - * Runs the cron job after the response was sent - * - * @param PostResponseEvent $event The event - */ - public function on_kernel_terminate(PostResponseEvent $event) - { - $request = $event->getRequest(); - $controller_name = $request->get('_route'); - - if ($controller_name !== 'phpbb_cron_run') - { - return; - } - - $cron_type = $request->get('cron_type'); - - if ($this->cron_lock->acquire()) - { - $task = $this->cron_manager->find_task($cron_type); - if ($task) - { - if ($task->is_parametrized()) - { - $task->parse_parameters($this->request); - } - - if ($task->is_ready()) - { - $task->run(); - } - - $this->cron_lock->release(); - } - } - } - - /** - * {@inheritdoc} - */ - static public function getSubscribedEvents() - { - return array( - KernelEvents::TERMINATE => 'on_kernel_terminate', - ); - } -} diff --git a/install/update/new/phpbb/cron/manager.php b/install/update/new/phpbb/cron/manager.php deleted file mode 100644 index 59ee693..0000000 --- a/install/update/new/phpbb/cron/manager.php +++ /dev/null @@ -1,164 +0,0 @@ - -* @license 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; - -use phpbb\cron\task\wrapper; -use phpbb\routing\helper; - -/** -* Cron manager class. -* -* Finds installed cron tasks, stores task objects, provides task selection. -*/ -class manager -{ - /** - * @var helper - */ - protected $routing_helper; - - /** - * Set of \phpbb\cron\task\wrapper objects. - * Array holding all tasks that have been found. - * - * @var array - */ - protected $tasks = array(); - - /** - * @var string - */ - protected $phpbb_root_path; - - /** - * @var string - */ - protected $php_ext; - - /** - * Constructor. Loads all available tasks. - * - * @param array|\Traversable $tasks Provides an iterable set of task names - * @param helper $routing_helper Routing helper - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $php_ext PHP file extension - */ - public function __construct($tasks, helper $routing_helper, $phpbb_root_path, $php_ext) - { - $this->routing_helper = $routing_helper; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->load_tasks($tasks); - } - - /** - * Loads tasks given by name, wraps them - * and puts them into $this->tasks. - * - * @param array|\Traversable $tasks Array of instances of \phpbb\cron\task\task - * - * @return null - */ - public function load_tasks($tasks) - { - foreach ($tasks as $task) - { - $this->tasks[] = $this->wrap_task($task); - } - } - - /** - * Finds a task that is ready to run. - * - * If several tasks are ready, any one of them could be returned. - * - * If no tasks are ready, null is returned. - * - * @return \phpbb\cron\task\wrapper|null - */ - public function find_one_ready_task() - { - shuffle($this->tasks); - foreach ($this->tasks as $task) - { - if ($task->is_ready()) - { - return $task; - } - } - return null; - } - - /** - * Finds all tasks that are ready to run. - * - * @return array List of tasks which are ready to run (wrapped in \phpbb\cron\task\wrapper). - */ - public function find_all_ready_tasks() - { - $tasks = array(); - foreach ($this->tasks as $task) - { - if ($task->is_ready()) - { - $tasks[] = $task; - } - } - return $tasks; - } - - /** - * Finds a task by name. - * - * If there is no task with the specified name, null is returned. - * - * Web runner uses this method to resolve names to tasks. - * - * @param string $name Name of the task to look up. - * @return \phpbb\cron\task\wrapper A wrapped task corresponding to the given name, or null. - */ - public function find_task($name) - { - foreach ($this->tasks as $task) - { - if ($task->get_name() == $name) - { - return $task; - } - } - return null; - } - - /** - * Find all tasks and return them. - * - * @return array List of all tasks. - */ - public function get_tasks() - { - return $this->tasks; - } - - /** - * Wraps a task inside an instance of \phpbb\cron\task\wrapper. - * - * @param \phpbb\cron\task\task $task The task. - * @return \phpbb\cron\task\wrapper The wrapped task. - */ - public function wrap_task(\phpbb\cron\task\task $task) - { - return new wrapper($task, $this->routing_helper, $this->phpbb_root_path, $this->php_ext); - } -} diff --git a/install/update/new/phpbb/cron/task/core/update_hashes.php b/install/update/new/phpbb/cron/task/core/update_hashes.php deleted file mode 100644 index 9e938f7..0000000 --- a/install/update/new/phpbb/cron/task/core/update_hashes.php +++ /dev/null @@ -1,130 +0,0 @@ - - * @license 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\core; - -/** - * Update old hashes to the current default hashing algorithm - * - * It is intended to gradually update all "old" style hashes to the - * current default hashing algorithm. - */ -class update_hashes extends \phpbb\cron\task\base -{ - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\lock\db */ - protected $update_lock; - - /** @var \phpbb\passwords\manager */ - protected $passwords_manager; - - /** @var string Default hashing type */ - protected $default_type; - - /** - * Constructor. - * - * @param \phpbb\config\config $config - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\lock\db $update_lock - * @param \phpbb\passwords\manager $passwords_manager - * @param array $hashing_algorithms Hashing driver - * service collection - * @param array $defaults Default password types - */ - public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\lock\db $update_lock, \phpbb\passwords\manager $passwords_manager, $hashing_algorithms, $defaults) - { - $this->config = $config; - $this->db = $db; - $this->passwords_manager = $passwords_manager; - $this->update_lock = $update_lock; - - foreach ($defaults as $type) - { - if ($hashing_algorithms[$type]->is_supported() && !$hashing_algorithms[$type] instanceof \phpbb\passwords\driver\base_native) - { - $this->default_type = $type; - break; - } - } - } - - /** - * {@inheritdoc} - */ - public function is_runnable() - { - return !$this->config['use_system_cron']; - } - - /** - * {@inheritdoc} - */ - public function should_run() - { - if (!empty($this->config['update_hashes_lock'])) - { - $last_run = explode(' ', $this->config['update_hashes_lock']); - if ($last_run[0] + 60 >= time()) - { - return false; - } - } - - return $this->config['enable_update_hashes'] && $this->config['update_hashes_last_cron'] < (time() - 60); - } - - /** - * {@inheritdoc} - */ - public function run() - { - if ($this->update_lock->acquire()) - { - $sql = 'SELECT user_id, user_password - FROM ' . USERS_TABLE . ' - WHERE user_password ' . $this->db->sql_like_expression('$H$' . $this->db->get_any_char()) . ' - OR user_password ' . $this->db->sql_like_expression('$CP$' . $this->db->get_any_char()); - $result = $this->db->sql_query_limit($sql, 20); - - $affected_rows = 0; - - while ($row = $this->db->sql_fetchrow($result)) - { - $new_hash = $this->passwords_manager->hash($row['user_password'], array($this->default_type)); - - // 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']; - $this->db->sql_query($sql); - } - - $this->config->set('update_hashes_last_cron', time()); - $this->update_lock->release(); - - // Stop cron for good once all hashes are converted - if ($affected_rows === 0) - { - $this->config->set('enable_update_hashes', '0'); - } - } - } -} diff --git a/install/update/new/phpbb/cron/task/wrapper.php b/install/update/new/phpbb/cron/task/wrapper.php deleted file mode 100644 index 4dc3a7f..0000000 --- a/install/update/new/phpbb/cron/task/wrapper.php +++ /dev/null @@ -1,117 +0,0 @@ - -* @license 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; - -use phpbb\routing\helper; - -/** -* Cron task wrapper class. -* Enhances cron tasks with convenience methods that work identically for all tasks. -*/ -class wrapper -{ - /** - * @var helper - */ - protected $routing_helper; - - /** - * @var task - */ - protected $task; - - /** - * @var string - */ - protected $phpbb_root_path; - - /** - * @var string - */ - protected $php_ext; - - /** - * Constructor. - * - * Wraps a task $task, which must implement cron_task interface. - * - * @param task $task The cron task to wrap. - * @param helper $routing_helper Routing helper for route generation - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $php_ext PHP file extension - */ - public function __construct(task $task, helper $routing_helper, $phpbb_root_path, $php_ext) - { - $this->task = $task; - $this->routing_helper = $routing_helper; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - } - - /** - * Returns whether the wrapped task is parametrised. - * - * Parametrized tasks accept parameters during initialization and must - * normally be scheduled with parameters. - * - * @return bool Whether or not this task is parametrized. - */ - public function is_parametrized() - { - return $this->task instanceof parametrized; - } - - /** - * Returns whether the wrapped task is ready to run. - * - * A task is ready to run when it is runnable according to current configuration - * and enough time has passed since it was last run. - * - * @return bool Whether the wrapped task is ready to run. - */ - public function is_ready() - { - return $this->task->is_runnable() && $this->task->should_run(); - } - - /** - * Returns a url through which this task may be invoked via web. - * - * When system cron is not in use, running a cron task is accomplished - * by outputting an image with the url returned by this function as - * source. - * - * @return string URL through which this task may be invoked. - */ - public function get_url() - { - $params['cron_type'] = $this->get_name(); - if ($this->is_parametrized()) - { - $params = array_merge($params, $this->task->get_parameters()); - } - - return $this->routing_helper->route('phpbb_cron_run', $params); - } - - /** - * Forwards all other method calls to the wrapped task implementation. - * - * @return mixed - */ - public function __call($name, $args) - { - return call_user_func_array(array($this->task, $name), $args); - } -} diff --git a/install/update/new/phpbb/db/driver/driver.php b/install/update/new/phpbb/db/driver/driver.php deleted file mode 100644 index 93f0a74..0000000 --- a/install/update/new/phpbb/db/driver/driver.php +++ /dev/null @@ -1,1246 +0,0 @@ - -* @license 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; - -/** -* Database Abstraction Layer -*/ -abstract class driver implements driver_interface -{ - var $db_connect_id; - var $query_result; - var $return_on_error = false; - var $transaction = false; - var $sql_time = 0; - var $num_queries = array(); - var $open_queries = array(); - - var $curtime = 0; - var $query_hold = ''; - var $html_hold = ''; - var $sql_report = ''; - - var $persistency = false; - var $user = ''; - var $server = ''; - var $dbname = ''; - - // Set to true if error triggered - var $sql_error_triggered = false; - - // Holding the last sql query on sql error - var $sql_error_sql = ''; - // Holding the error information - only populated if sql_error_triggered is set - var $sql_error_returned = array(); - - // Holding transaction count - var $transactions = 0; - - // Supports multi inserts? - var $multi_insert = false; - - /** - * Current sql layer - */ - var $sql_layer = ''; - - /** - * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions - */ - var $any_char; - var $one_char; - - /** - * Exact version of the DBAL, directly queried - */ - var $sql_server_version = false; - - 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; - - /** - * @var bool - */ - protected $debug_load_time = false; - - /** - * @var bool - */ - protected $debug_sql_explain = false; - - /** - * Constructor - */ - function __construct() - { - $this->num_queries = array( - 'cached' => 0, - 'normal' => 0, - 'total' => 0, - ); - - // Fill default sql layer based on the class being called. - // This can be changed by the specified layer itself later if needed. - $this->sql_layer = substr(get_class($this), strlen('phpbb\db\driver\\')); - - // Do not change this please! This variable is used to easy the use of it - and is hardcoded. - $this->any_char = chr(0) . '%'; - $this->one_char = chr(0) . '_'; - } - - /** - * {@inheritdoc} - */ - public function set_debug_load_time($value) - { - $this->debug_load_time = $value; - } - - /** - * {@inheritdoc} - */ - public function set_debug_sql_explain($value) - { - $this->debug_sql_explain = $value; - } - - /** - * {@inheritdoc} - */ - public function get_sql_layer() - { - return $this->sql_layer; - } - - /** - * {@inheritdoc} - */ - public function get_db_name() - { - return $this->dbname; - } - - /** - * {@inheritdoc} - */ - public function get_any_char() - { - return $this->any_char; - } - - /** - * {@inheritdoc} - */ - public function get_one_char() - { - return $this->one_char; - } - - /** - * {@inheritdoc} - */ - public function get_db_connect_id() - { - return $this->db_connect_id; - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_triggered() - { - return $this->sql_error_triggered; - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_sql() - { - return $this->sql_error_sql; - } - - /** - * {@inheritdoc} - */ - public function get_transaction() - { - return $this->transaction; - } - - /** - * {@inheritdoc} - */ - public function get_sql_time() - { - return $this->sql_time; - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_returned() - { - return $this->sql_error_returned; - } - - /** - * {@inheritdoc} - */ - public function get_multi_insert() - { - return $this->multi_insert; - } - - /** - * {@inheritdoc} - */ - public function set_multi_insert($multi_insert) - { - $this->multi_insert = $multi_insert; - } - - /** - * {@inheritDoc} - */ - function sql_return_on_error($fail = false) - { - $this->sql_error_triggered = false; - $this->sql_error_sql = ''; - - $this->return_on_error = $fail; - } - - /** - * {@inheritDoc} - */ - function sql_num_queries($cached = false) - { - return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; - } - - /** - * {@inheritDoc} - */ - function sql_add_num_queries($cached = false) - { - $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; - $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; - $this->num_queries['total'] += 1; - } - - /** - * {@inheritDoc} - */ - function sql_close() - { - if (!$this->db_connect_id) - { - return false; - } - - if ($this->transaction) - { - do - { - $this->sql_transaction('commit'); - } - while ($this->transaction); - } - - foreach ($this->open_queries as $query_id) - { - $this->sql_freeresult($query_id); - } - - // Connection closed correctly. Set db_connect_id to false to prevent errors - if ($result = $this->_sql_close()) - { - $this->db_connect_id = false; - } - - return $result; - } - - /** - * {@inheritDoc} - */ - function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - if (empty($query)) - { - return false; - } - - // Never use a negative total or offset - $total = ($total < 0) ? 0 : $total; - $offset = ($offset < 0) ? 0 : $offset; - - return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); - } - - /** - * {@inheritDoc} - */ - function sql_fetchrowset($query_id = false) - { - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - $result = array(); - while ($row = $this->sql_fetchrow($query_id)) - { - $result[] = $row; - } - - return $result; - } - - return 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); - } - - if (!$query_id) - { - return false; - } - - $this->sql_freeresult($query_id); - $query_id = $this->sql_query($this->last_query_text); - - if (!$query_id) - { - return false; - } - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * {@inheritDoc} - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return (isset($row[$field])) ? $row[$field] : false; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_like_expression($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) . '\''); - } - - /** - * {@inheritDoc} - */ - function sql_not_like_expression($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) . '\''); - } - - /** - * {@inheritDoc} - */ - public function sql_case($condition, $action_true, $action_false = false) - { - $sql_case = 'CASE WHEN ' . $condition; - $sql_case .= ' THEN ' . $action_true; - $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; - $sql_case .= ' END'; - return $sql_case; - } - - /** - * {@inheritDoc} - */ - public function sql_concatenate($expr1, $expr2) - { - return $expr1 . ' || ' . $expr2; - } - - /** - * {@inheritDoc} - */ - function sql_buffer_nested_transactions() - { - return false; - } - - /** - * {@inheritDoc} - */ - function sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - // If we are within a transaction we will not open another one, but enclose the current one to not loose data (preventing auto commit) - if ($this->transaction) - { - $this->transactions++; - return true; - } - - $result = $this->_sql_transaction('begin'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = true; - break; - - case 'commit': - // If there was a previously opened transaction we do not commit yet... - // but count back the number of inner transactions - if ($this->transaction && $this->transactions) - { - $this->transactions--; - return true; - } - - // Check if there is a transaction (no transaction can happen if - // there was an error, with a combined rollback and error returning enabled) - // This implies we have transaction always set for autocommit db's - if (!$this->transaction) - { - return false; - } - - $result = $this->_sql_transaction('commit'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = false; - $this->transactions = 0; - break; - - case 'rollback': - $result = $this->_sql_transaction('rollback'); - $this->transaction = false; - $this->transactions = 0; - break; - - default: - $result = $this->_sql_transaction($status); - break; - } - - return $result; - } - - /** - * {@inheritDoc} - */ - function sql_build_array($query, $assoc_ary = false) - { - if (!is_array($assoc_ary)) - { - return false; - } - - $fields = $values = array(); - - if ($query == 'INSERT' || $query == 'INSERT_SELECT') - { - foreach ($assoc_ary as $key => $var) - { - $fields[] = $key; - - if (is_array($var) && is_string($var[0])) - { - // This is used for INSERT_SELECT(s) - $values[] = $var[0]; - } - else - { - $values[] = $this->_sql_validate_value($var); - } - } - - $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; - } - else if ($query == 'MULTI_INSERT') - { - trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); - } - else if ($query == 'UPDATE' || $query == 'SELECT' || $query == 'DELETE') - { - $values = array(); - foreach ($assoc_ary as $key => $var) - { - $values[] = "$key = " . $this->_sql_validate_value($var); - } - $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); - } - - return $query; - } - - /** - * {@inheritDoc} - */ - function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) - { - $array = (array) $array; - - if (!count($array)) - { - if (!$allow_empty_set) - { - // Print the backtrace to help identifying the location of the problematic code - $this->sql_error('No values specified for SQL IN comparison'); - } - else - { - // NOT IN () actually means everything so use a tautology - if ($negate) - { - return '1=1'; - } - // IN () actually means nothing so use a contradiction - else - { - return '1=0'; - } - } - } - - if (count($array) == 1) - { - @reset($array); - $var = current($array); - - return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); - } - else - { - return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; - } - } - - /** - * {@inheritDoc} - */ - function sql_bit_and($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_and')) - { - return $this->_sql_bit_and($column_name, $bit, $compare); - } - - return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * {@inheritDoc} - */ - function sql_bit_or($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_or')) - { - return $this->_sql_bit_or($column_name, $bit, $compare); - } - - return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * {@inheritDoc} - */ - function cast_expr_to_bigint($expression) - { - return $expression; - } - - /** - * {@inheritDoc} - */ - function cast_expr_to_string($expression) - { - return $expression; - } - - /** - * {@inheritDoc} - */ - function sql_lower_text($column_name) - { - return "LOWER($column_name)"; - } - - /** - * {@inheritDoc} - */ - function sql_multi_insert($table, $sql_ary) - { - if (!count($sql_ary)) - { - return false; - } - - if ($this->multi_insert) - { - $ary = array(); - foreach ($sql_ary as $id => $_sql_ary) - { - // If by accident the sql array is only one-dimensional we build a normal insert statement - if (!is_array($_sql_ary)) - { - return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); - } - - $values = array(); - foreach ($_sql_ary as $key => $var) - { - $values[] = $this->_sql_validate_value($var); - } - $ary[] = '(' . implode(', ', $values) . ')'; - } - - return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); - } - else - { - foreach ($sql_ary as $ary) - { - if (!is_array($ary)) - { - return false; - } - - $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); - - if (!$result) - { - return false; - } - } - } - - return true; - } - - /** - * Function for validating values - * @access private - */ - function _sql_validate_value($var) - { - if (is_null($var)) - { - return 'NULL'; - } - else if (is_string($var)) - { - return "'" . $this->sql_escape($var) . "'"; - } - else - { - return (is_bool($var)) ? intval($var) : $var; - } - } - - /** - * {@inheritDoc} - */ - function sql_build_query($query, $array) - { - $sql = ''; - switch ($query) - { - case 'SELECT': - case 'SELECT_DISTINCT'; - - $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; - - // Build table array. We also build an alias array for later checks. - $table_array = $aliases = array(); - $used_multi_alias = false; - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - $used_multi_alias = true; - - foreach ($alias as $multi_alias) - { - $table_array[] = $table_name . ' ' . $multi_alias; - $aliases[] = $multi_alias; - } - } - else - { - $table_array[] = $table_name . ' ' . $alias; - $aliases[] = $alias; - } - } - - // We run the following code to determine if we need to re-order the table array. ;) - // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. - // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. - if (!empty($array['LEFT_JOIN']) && count($array['FROM']) > 1 && $used_multi_alias !== false) - { - // Take first LEFT JOIN - $join = current($array['LEFT_JOIN']); - - // Determine the table used there (even if there are more than one used, we only want to have one - preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); - - // If there is a first join match, we need to make sure the table order is correct - if (!empty($matches[1])) - { - $first_join_match = trim($matches[1]); - $table_array = $last = array(); - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - foreach ($alias as $multi_alias) - { - ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; - } - } - else - { - ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; - } - } - - $table_array = array_merge($table_array, $last); - } - } - - $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); - - if (!empty($array['LEFT_JOIN'])) - { - foreach ($array['LEFT_JOIN'] as $join) - { - $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; - } - } - - if (!empty($array['WHERE'])) - { - $sql .= ' WHERE '; - - 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'])) - { - $sql .= ' GROUP BY ' . $array['GROUP_BY']; - } - - if (!empty($array['ORDER_BY'])) - { - $sql .= ' ORDER BY ' . $array['ORDER_BY']; - } - - break; - } - - 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} - */ - function sql_error($sql = '') - { - global $auth, $user, $config; - - // Set var to retrieve errored status - $this->sql_error_triggered = true; - $this->sql_error_sql = $sql; - - $this->sql_error_returned = $this->_sql_error(); - - if (!$this->return_on_error) - { - $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]

' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; - - // Show complete SQL error and path to administrators only - // Additionally show complete error on installation or if extended debug mode is enabled - // The DEBUG constant is for development only! - if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || $this->debug_sql_explain) - { - $message .= ($sql) ? '

SQL

' . htmlspecialchars($sql) : ''; - } - else - { - // If error occurs in initiating the session we need to use a pre-defined language string - // This could happen if the connection could not be established for example (then we are not able to grab the default language) - if (!isset($user->lang['SQL_ERROR_OCCURRED'])) - { - $message .= '

An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; - } - else - { - if (!empty($config['board_contact'])) - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - else - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - } - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - if (strlen($message) > 1024) - { - // We need to define $msg_long_text here to circumvent text stripping. - global $msg_long_text; - $msg_long_text = $message; - - trigger_error(false, E_USER_ERROR); - } - - trigger_error($message, E_USER_ERROR); - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - return $this->sql_error_returned; - } - - /** - * {@inheritDoc} - */ - function sql_report($mode, $query = '') - { - global $cache, $starttime, $phpbb_root_path, $phpbb_path_helper; - global $request; - - if (is_object($request) && !$request->variable('explain', false)) - { - return false; - } - - if (!$query && $this->query_hold != '') - { - $query = $this->query_hold; - } - - switch ($mode) - { - case 'display': - if (!empty($cache)) - { - $cache->unload(); - } - $this->sql_close(); - - $mtime = explode(' ', microtime()); - $totaltime = $mtime[0] + $mtime[1] - $starttime; - - echo ' - - - - - SQL Report - - - -
- -
-
-
- -
-

SQL Report

-
-

Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '

- -

Time spent on ' . $this->sql_layer . ' queries: ' . round($this->sql_time, 5) . 's | Time spent on PHP: ' . round($totaltime - $this->sql_time, 5) . 's

- -

- ' . $this->sql_report . ' -
- -
-
-
- -
- - '; - - exit_handler(); - - break; - - case 'stop': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $this->sql_report .= ' - - - - - - - - - - - - -
Query #' . $this->num_queries['total'] . '
- - ' . $this->html_hold . ' - -

- '; - - if ($this->query_result) - { - if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) - { - $this->sql_report .= 'Affected rows: ' . $this->sql_affectedrows() . ' | '; - } - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: ' . sprintf('%.5f', $endtime - $this->curtime) . 's'; - } - else - { - $error = $this->sql_error(); - $this->sql_report .= 'FAILED - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); - } - - $this->sql_report .= '



'; - - $this->sql_time += $endtime - $this->curtime; - break; - - case 'start': - $this->query_hold = $query; - $this->html_hold = ''; - - $this->_sql_report($mode, $query); - - $this->curtime = explode(' ', microtime()); - $this->curtime = $this->curtime[0] + $this->curtime[1]; - - break; - - case 'add_select_row': - - $html_table = func_get_arg(2); - $row = func_get_arg(3); - - if (!$html_table && count($row)) - { - $html_table = true; - $this->html_hold .= ''; - - foreach (array_keys($row) as $val) - { - $this->html_hold .= ''; - } - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - $class = 'row1'; - foreach (array_values($row) as $val) - { - $class = ($class == 'row1') ? 'row2' : 'row1'; - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - return $html_table; - - break; - - case 'fromcache': - - $this->_sql_report($mode, $query); - - break; - - case 'record_fromcache': - - $endtime = func_get_arg(2); - $splittime = func_get_arg(3); - - $time_cache = $endtime - $this->curtime; - $time_db = $splittime - $endtime; - $color = ($time_db > $time_cache) ? 'green' : 'red'; - - $this->sql_report .= '
' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '
' . (($val) ? $val : ' ') . '
'; - $this->sql_report .= '
Query results obtained from the cache
'; - $this->sql_report .= '

'; - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: ' . sprintf('%.5f', ($time_cache)) . 's | Elapsed [db]: ' . sprintf('%.5f', $time_db) . 's



'; - - // Pad the start time to not interfere with page timing - $starttime += $time_db; - - break; - - default: - - $this->_sql_report($mode, $query); - - break; - } - - return true; - } - - /** - * {@inheritDoc} - */ - function get_estimated_row_count($table_name) - { - return $this->get_row_count($table_name); - } - - /** - * {@inheritDoc} - */ - function get_row_count($table_name) - { - $sql = 'SELECT COUNT(*) AS rows_total - FROM ' . $this->sql_escape($table_name); - $result = $this->sql_query($sql); - $rows_total = $this->sql_fetchfield('rows_total'); - $this->sql_freeresult($result); - - return $rows_total; - } -} diff --git a/install/update/new/phpbb/db/driver/driver_interface.php b/install/update/new/phpbb/db/driver/driver_interface.php deleted file mode 100644 index 05ff5ef..0000000 --- a/install/update/new/phpbb/db/driver/driver_interface.php +++ /dev/null @@ -1,467 +0,0 @@ - -* @license 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; - -interface driver_interface -{ - /** - * Set value for load_time debug parameter - * - * @param bool $value - */ - public function set_debug_load_time($value); - - /** - * Set value for sql_explain debug parameter - * - * @param bool $value - */ - public function set_debug_sql_explain($value); - - /** - * Gets the name of the sql layer. - * - * @return string - */ - public function get_sql_layer(); - - /** - * Gets the name of the database. - * - * @return string - */ - public function get_db_name(); - - /** - * Wildcards for matching any (%) character within LIKE expressions - * - * @return string - */ - public function get_any_char(); - - /** - * Wildcards for matching exactly one (_) character within LIKE expressions - * - * @return string - */ - public function get_one_char(); - - /** - * Gets the time spent into the queries - * - * @return int - */ - public function get_sql_time(); - - /** - * Gets the connect ID. - * - * @return mixed - */ - public function get_db_connect_id(); - - /** - * Indicates if an error was triggered. - * - * @return bool - */ - public function get_sql_error_triggered(); - - /** - * Gets the last faulty query - * - * @return string - */ - public function get_sql_error_sql(); - - /** - * Indicates if we are in a transaction. - * - * @return bool - */ - public function get_transaction(); - - /** - * Gets the returned error. - * - * @return array - */ - public function get_sql_error_returned(); - - /** - * Indicates if multiple insertion can be used - * - * @return bool - */ - public function get_multi_insert(); - - /** - * Set if multiple insertion can be used - * - * @param bool $multi_insert - */ - public function set_multi_insert($multi_insert); - - /** - * Gets the exact number of rows in a specified table. - * - * @param string $table_name Table name - * @return string Exact number of rows in $table_name. - */ - public function get_row_count($table_name); - - /** - * Gets the estimated number of rows in a specified table. - * - * @param string $table_name Table name - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). - */ - public function get_estimated_row_count($table_name); - - /** - * Run LOWER() on DB column of type text (i.e. neither varchar nor char). - * - * @param string $column_name The column name to use - * @return string A SQL statement like "LOWER($column_name)" - */ - public function sql_lower_text($column_name); - - /** - * Display sql error page - * - * @param string $sql The SQL query causing the error - * @return mixed Returns the full error message, if $this->return_on_error - * is set, null otherwise - */ - public function sql_error($sql = ''); - - /** - * Returns whether results of a query need to be buffered to run a - * transaction while iterating over them. - * - * @return bool Whether buffering is required. - */ - public function sql_buffer_nested_transactions(); - - /** - * Run binary OR operator on DB column. - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the OR operator, - * will be converted to (1 << $bit). Is used by options, - * using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (e.g. "= 0") - * @return string A SQL statement like "$column | (1 << $bit) {$compare}" - */ - public function sql_bit_or($column_name, $bit, $compare = ''); - - /** - * Version information about used database - * - * @param bool $raw Only return the fetched sql_server_version - * @param bool $use_cache Is it safe to retrieve the value from the cache - * @return string sql server version - */ - public function sql_server_info($raw = false, $use_cache = true); - - /** - * Return on error or display error message - * - * @param bool $fail Should we return on errors, or stop - * @return null - */ - public function sql_return_on_error($fail = false); - - /** - * Build sql statement from an array - * - * @param string $query Should be on of the following strings: - * INSERT, INSERT_SELECT, UPDATE, SELECT, DELETE - * @param array $assoc_ary Array with "column => value" pairs - * @return string A SQL statement like "c1 = 'a' AND c2 = 'b'" - */ - public function sql_build_array($query, $assoc_ary = array()); - - /** - * Fetch all rows - * - * @param mixed $query_id Already executed query to get the rows from, - * if false, the last query will be used. - * @return mixed Nested array if the query had rows, false otherwise - */ - public function sql_fetchrowset($query_id = false); - - /** - * SQL Transaction - * - * @param string $status Should be one of the following strings: - * begin, commit, rollback - * @return mixed Buffered, seekable result handle, false on error - */ - public function sql_transaction($status = 'begin'); - - /** - * Build a concatenated expression - * - * @param string $expr1 Base SQL expression where we append the second one - * @param string $expr2 SQL expression that is appended to the first expression - * @return string Concatenated string - */ - public function sql_concatenate($expr1, $expr2); - - /** - * Build a case expression - * - * Note: The two statements action_true and action_false must have the same - * data type (int, vchar, ...) in the database! - * - * @param string $condition The condition which must be true, - * to use action_true rather then action_else - * @param string $action_true SQL expression that is used, if the condition is true - * @param mixed $action_false SQL expression that is used, if the condition is false - * @return string CASE expression including the condition and statements - */ - public function sql_case($condition, $action_true, $action_false = false); - - /** - * Build sql statement from array for select and select distinct statements - * - * Possible query values: SELECT, SELECT_DISTINCT - * - * @param string $query Should be one of: SELECT, SELECT_DISTINCT - * @param array $array Array with the query data: - * SELECT A comma imploded list of columns to select - * FROM Array with "table => alias" pairs, - * (alias can also be an array) - * Optional: LEFT_JOIN Array of join entries: - * FROM Table that should be joined - * ON Condition for the join - * Optional: WHERE Where SQL statement - * Optional: GROUP_BY Group by SQL statement - * Optional: ORDER_BY Order by SQL statement - * @return string A SQL statement ready for execution - */ - public function sql_build_query($query, $array); - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - * - * @param string $field Name of the column - * @param mixed $rownum Row number, if false the current row will be used - * and the row curser will point to the next row - * Note: $rownum is 0 based - * @param mixed $query_id Already executed query to get the rows from, - * if false, the last query will be used. - * @return mixed String value of the field in the selected row, - * false, if the row does not exist - */ - public function sql_fetchfield($field, $rownum = false, $query_id = false); - - /** - * Fetch current row - * - * @param mixed $query_id Already executed query to get the rows from, - * if false, the last query will be used. - * @return mixed Array with the current row, - * false, if the row does not exist - */ - public function sql_fetchrow($query_id = false); - - /** - * Returns SQL string to cast a string expression to an int. - * - * @param string $expression An expression evaluating to string - * @return string Expression returning an int - */ - public function cast_expr_to_bigint($expression); - - /** - * Get last inserted id after insert statement - * - * @return string Autoincrement value of the last inserted row - */ - public function sql_nextid(); - - /** - * Add to query count - * - * @param bool $cached Is this query cached? - * @return null - */ - public function sql_add_num_queries($cached = false); - - /** - * Build LIMIT query - * - * @param string $query The SQL query to execute - * @param int $total The number of rows to select - * @param int $offset - * @param int $cache_ttl Either 0 to avoid caching or - * the time in seconds which the result shall be kept in cache - * @return mixed Buffered, seekable result handle, false on error - */ - public function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0); - - /** - * Base query method - * - * @param string $query The SQL query to execute - * @param int $cache_ttl Either 0 to avoid caching or - * the time in seconds which the result shall be kept in cache - * @return mixed Buffered, seekable result handle, false on error - */ - public function sql_query($query = '', $cache_ttl = 0); - - /** - * Returns SQL string to cast an integer expression to a string. - * - * @param string $expression An expression evaluating to int - * @return string Expression returning a string - */ - public function cast_expr_to_string($expression); - - /** - * Connect to server - * - * @param string $sqlserver Address of the database server - * @param string $sqluser User name of the SQL user - * @param string $sqlpassword Password of the SQL user - * @param string $database Name of the database - * @param mixed $port Port of the database server - * @param bool $persistency - * @param bool $new_link Should a new connection be established - * @return mixed Connection ID on success, string error message otherwise - */ - public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false); - - /** - * Run binary AND operator on DB column. - * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the AND operator, - * will be converted to (1 << $bit). Is used by - * options, using the number schema: 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - * @return string A SQL statement like: "{$column} & (1 << {$bit}) {$compare}" - */ - public function sql_bit_and($column_name, $bit, $compare = ''); - - /** - * Free sql result - * - * @param mixed $query_id Already executed query result, - * if false, the last query will be used. - * @return null - */ - public function sql_freeresult($query_id = false); - - /** - * Return number of sql queries and cached sql queries used - * - * @param bool $cached Should we return the number of cached or normal queries? - * @return int Number of queries that have been executed - */ - public function sql_num_queries($cached = false); - - /** - * Run more than one insert statement. - * - * @param string $table Table name to run the statements on - * @param array $sql_ary Multi-dimensional array holding the statement data - * @return bool false if no statements were executed. - */ - public function sql_multi_insert($table, $sql_ary); - - /** - * Return number of affected rows - * - * @return mixed Number of the affected rows by the last query - * false if no query has been run before - */ - public function sql_affectedrows(); - - /** - * DBAL garbage collection, close SQL connection - * - * @return mixed False if no connection was opened before, - * Server response otherwise - */ - public function sql_close(); - - /** - * Seek to given row number - * - * @param mixed $rownum Row number the curser should point to - * Note: $rownum is 0 based - * @param mixed $query_id ID of the query to set the row cursor on - * if false, the last query will be used. - * $query_id will then be set correctly - * @return bool False if something went wrong - */ - public function sql_rowseek($rownum, &$query_id); - - /** - * Escape string used in sql query - * - * @param string $msg String to be escaped - * @return string Escaped version of $msg - */ - public function sql_escape($msg); - - /** - * Correctly adjust LIKE expression for special characters - * Some DBMS are handling them in a different way - * - * @param string $expression The expression to use. Every wildcard is - * escaped, except $this->any_char and $this->one_char - * @return string A SQL statement like: "LIKE 'bertie_%'" - */ - public function sql_like_expression($expression); - - /** - * Correctly adjust NOT LIKE expression for special characters - * Some DBMS are handling them in a different way - * - * @param string $expression The expression to use. Every wildcard is - * escaped, except $this->any_char and $this->one_char - * @return string A SQL statement like: "NOT LIKE 'bertie_%'" - */ - public function sql_not_like_expression($expression); - - /** - * Explain queries - * - * @param string $mode Available modes: display, start, stop, - * add_select_row, fromcache, record_fromcache - * @param string $query The Query that should be explained - * @return mixed Either a full HTML page, boolean or null - */ - public function sql_report($mode, $query = ''); - - /** - * Build IN or NOT IN sql comparison string, uses <> or = on single element - * arrays to improve comparison speed - * - * @param string $field Name of the sql column that shall be compared - * @param array $array Array of values that are (not) allowed - * @param bool $negate true for NOT IN (), false for IN () - * @param bool $allow_empty_set If true, allow $array to be empty, - * this function will return 1=1 or 1=0 then. - * @return string A SQL statement like: "IN (1, 2, 3, 4)" or "= 1" - */ - public function sql_in_set($field, $array, $negate = false, $allow_empty_set = false); -} diff --git a/install/update/new/phpbb/db/driver/factory.php b/install/update/new/phpbb/db/driver/factory.php deleted file mode 100644 index bb6e7a2..0000000 --- a/install/update/new/phpbb/db/driver/factory.php +++ /dev/null @@ -1,459 +0,0 @@ - -* @license 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; - -use \Symfony\Component\DependencyInjection\ContainerInterface; - -/** -* Database Abstraction Layer -*/ -class factory implements driver_interface -{ - /** - * @var driver_interface - */ - protected $driver = null; - - /** - * @var ContainerInterface - */ - protected $container; - - /** - * Constructor. - * - * @param ContainerInterface $container A ContainerInterface instance - */ - public function __construct(ContainerInterface $container) - { - $this->container = $container; - } - - /** - * Return the current driver (and retrieved it from the container if necessary) - * - * @return driver_interface - */ - protected function get_driver() - { - if ($this->driver === null) - { - $this->driver = $this->container->get('dbal.conn.driver'); - } - - return $this->driver; - } - - /** - * Set the current driver - * - * @param driver_interface $driver - */ - public function set_driver(driver_interface $driver) - { - $this->driver = $driver; - } - - /** - * {@inheritdoc} - */ - public function set_debug_load_time($value) - { - $this->get_driver()->set_debug_load_time($value); - } - - /** - * {@inheritdoc} - */ - public function set_debug_sql_explain($value) - { - $this->get_driver()->set_debug_sql_explain($value); - } - - /** - * {@inheritdoc} - */ - public function get_sql_layer() - { - return $this->get_driver()->get_sql_layer(); - } - - /** - * {@inheritdoc} - */ - public function get_db_name() - { - return $this->get_driver()->get_db_name(); - } - - /** - * {@inheritdoc} - */ - public function get_any_char() - { - return $this->get_driver()->get_any_char(); - } - - /** - * {@inheritdoc} - */ - public function get_one_char() - { - return $this->get_driver()->get_one_char(); - } - - /** - * {@inheritdoc} - */ - public function get_db_connect_id() - { - return $this->get_driver()->get_db_connect_id(); - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_triggered() - { - return $this->get_driver()->get_sql_error_triggered(); - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_sql() - { - return $this->get_driver()->get_sql_error_sql(); - } - - /** - * {@inheritdoc} - */ - public function get_transaction() - { - return $this->get_driver()->get_transaction(); - } - - /** - * {@inheritdoc} - */ - public function get_sql_time() - { - return $this->get_driver()->get_sql_time(); - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_returned() - { - return $this->get_driver()->get_sql_error_returned(); - } - - /** - * {@inheritdoc} - */ - public function get_multi_insert() - { - return $this->get_driver()->get_multi_insert(); - } - - /** - * {@inheritdoc} - */ - public function set_multi_insert($multi_insert) - { - $this->get_driver()->set_multi_insert($multi_insert); - } - - /** - * {@inheritdoc} - */ - public function get_row_count($table_name) - { - return $this->get_driver()->get_row_count($table_name); - } - - /** - * {@inheritdoc} - */ - public function get_estimated_row_count($table_name) - { - return $this->get_driver()->get_estimated_row_count($table_name); - } - - /** - * {@inheritdoc} - */ - public function sql_lower_text($column_name) - { - return $this->get_driver()->sql_lower_text($column_name); - } - - /** - * {@inheritdoc} - */ - public function sql_error($sql = '') - { - return $this->get_driver()->sql_error($sql); - } - - /** - * {@inheritdoc} - */ - public function sql_buffer_nested_transactions() - { - return $this->get_driver()->sql_buffer_nested_transactions(); - } - - /** - * {@inheritdoc} - */ - public function sql_bit_or($column_name, $bit, $compare = '') - { - return $this->get_driver()->sql_bit_or($column_name, $bit, $compare); - } - - /** - * {@inheritdoc} - */ - public function sql_server_info($raw = false, $use_cache = true) - { - return $this->get_driver()->sql_server_info($raw, $use_cache); - } - - /** - * {@inheritdoc} - */ - public function sql_return_on_error($fail = false) - { - return $this->get_driver()->sql_return_on_error($fail); - } - - /** - * {@inheritdoc} - */ - public function sql_build_array($query, $assoc_ary = array()) - { - return $this->get_driver()->sql_build_array($query, $assoc_ary); - } - - /** - * {@inheritdoc} - */ - public function sql_fetchrowset($query_id = false) - { - return $this->get_driver()->sql_fetchrowset($query_id); - } - - /** - * {@inheritdoc} - */ - public function sql_transaction($status = 'begin') - { - return $this->get_driver()->sql_transaction($status); - } - - /** - * {@inheritdoc} - */ - public function sql_concatenate($expr1, $expr2) - { - return $this->get_driver()->sql_concatenate($expr1, $expr2); - } - - /** - * {@inheritdoc} - */ - public function sql_case($condition, $action_true, $action_false = false) - { - return $this->get_driver()->sql_case($condition, $action_true, $action_false); - } - - /** - * {@inheritdoc} - */ - public function sql_build_query($query, $array) - { - return $this->get_driver()->sql_build_query($query, $array); - } - - /** - * {@inheritdoc} - */ - public function sql_fetchfield($field, $rownum = false, $query_id = false) - { - return $this->get_driver()->sql_fetchfield($field, $rownum, $query_id); - } - - /** - * {@inheritdoc} - */ - public function sql_fetchrow($query_id = false) - { - return $this->get_driver()->sql_fetchrow($query_id); - } - - /** - * {@inheritdoc} - */ - public function cast_expr_to_bigint($expression) - { - return $this->get_driver()->cast_expr_to_bigint($expression); - } - - /** - * {@inheritdoc} - */ - public function sql_nextid() - { - return $this->get_driver()->sql_nextid(); - } - - /** - * {@inheritdoc} - */ - public function sql_add_num_queries($cached = false) - { - return $this->get_driver()->sql_add_num_queries($cached); - } - - /** - * {@inheritdoc} - */ - public function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - return $this->get_driver()->sql_query_limit($query, $total, $offset, $cache_ttl); - } - - /** - * {@inheritdoc} - */ - public function sql_query($query = '', $cache_ttl = 0) - { - return $this->get_driver()->sql_query($query, $cache_ttl); - } - - /** - * {@inheritdoc} - */ - public function cast_expr_to_string($expression) - { - return $this->get_driver()->cast_expr_to_string($expression); - } - - /** - * {@inheritdoc} - */ - public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - throw new \Exception('Disabled method.'); - } - - /** - * {@inheritdoc} - */ - public function sql_bit_and($column_name, $bit, $compare = '') - { - return $this->get_driver()->sql_bit_and($column_name, $bit, $compare); - } - - /** - * {@inheritdoc} - */ - public function sql_freeresult($query_id = false) - { - return $this->get_driver()->sql_freeresult($query_id); - } - - /** - * {@inheritdoc} - */ - public function sql_num_queries($cached = false) - { - return $this->get_driver()->sql_num_queries($cached); - } - - /** - * {@inheritdoc} - */ - public function sql_multi_insert($table, $sql_ary) - { - return $this->get_driver()->sql_multi_insert($table, $sql_ary); - } - - /** - * {@inheritdoc} - */ - public function sql_affectedrows() - { - return $this->get_driver()->sql_affectedrows(); - } - - /** - * {@inheritdoc} - */ - public function sql_close() - { - return $this->get_driver()->sql_close(); - } - - /** - * {@inheritdoc} - */ - public function sql_rowseek($rownum, &$query_id) - { - return $this->get_driver()->sql_rowseek($rownum, $query_id); - } - - /** - * {@inheritdoc} - */ - public function sql_escape($msg) - { - return $this->get_driver()->sql_escape($msg); - } - - /** - * {@inheritdoc} - */ - public function sql_like_expression($expression) - { - return $this->get_driver()->sql_like_expression($expression); - } - - /** - * {@inheritdoc} - */ - public function sql_not_like_expression($expression) - { - return $this->get_driver()->sql_not_like_expression($expression); - } - - /** - * {@inheritdoc} - */ - public function sql_report($mode, $query = '') - { - return $this->get_driver()->sql_report($mode, $query); - } - - /** - * {@inheritdoc} - */ - public function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) - { - return $this->get_driver()->sql_in_set($field, $array, $negate, $allow_empty_set); - } -} diff --git a/install/update/new/phpbb/db/driver/mssql_odbc.php b/install/update/new/phpbb/db/driver/mssql_odbc.php deleted file mode 100644 index 06cdce7..0000000 --- a/install/update/new/phpbb/db/driver/mssql_odbc.php +++ /dev/null @@ -1,384 +0,0 @@ - -* @license 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; - -/** -* Unified ODBC functions -* Unified ODBC functions support any database having ODBC driver, for example Adabas D, IBM DB2, iODBC, Solid, Sybase SQL Anywhere... -* Here we only support MSSQL Server 2000+ because of the provided schema -* -* @note number of bytes returned for returning data depends on odbc.defaultlrl php.ini setting. -* If it is limited to 4K for example only 4K of data is returned max, resulting in incomplete theme data for example. -* @note odbc.defaultbinmode may affect UTF8 characters -*/ -class mssql_odbc extends \phpbb\db\driver\mssql_base -{ - var $last_query_text = ''; - 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->dbname = $database; - - $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; - $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); - - $max_size = @ini_get('odbc.defaultlrl'); - if (!empty($max_size)) - { - $unit = strtolower(substr($max_size, -1, 1)); - $max_size = (int) $max_size; - - if ($unit == 'k') - { - $max_size = floor($max_size / 1024); - } - else if ($unit == 'g') - { - $max_size *= 1024; - } - else if (is_numeric($unit)) - { - $max_size = floor((int) ($max_size . $unit) / 1048576); - } - $max_size = max(8, $max_size) . 'M'; - - @ini_set('odbc.defaultlrl', $max_size); - } - - if ($this->persistency) - { - if (!function_exists('odbc_pconnect')) - { - $this->connect_error = 'odbc_pconnect function does not exist, is odbc extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @odbc_pconnect($this->server, $this->user, $sqlpassword); - } - else - { - if (!function_exists('odbc_connect')) - { - $this->connect_error = 'odbc_connect function does not exist, is odbc extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @odbc_connect($this->server, $this->user, $sqlpassword); - } - - 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('mssqlodbc_version')) === false) - { - $result_id = @odbc_exec($this->db_connect_id, "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')"); - - $row = false; - if ($result_id) - { - $row = odbc_fetch_array($result_id); - odbc_free_result($result_id); - } - - $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0; - - if (!empty($cache) && $use_cache) - { - $cache->put('mssqlodbc_version', $this->sql_server_version); - } - } - - if ($raw) - { - return $this->sql_server_version; - } - - return ($this->sql_server_version) ? 'MSSQL (ODBC)
' . $this->sql_server_version : 'MSSQL (ODBC)'; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @odbc_exec($this->db_connect_id, 'BEGIN TRANSACTION'); - break; - - case 'commit': - return @odbc_exec($this->db_connect_id, 'COMMIT TRANSACTION'); - break; - - case 'rollback': - return @odbc_exec($this->db_connect_id, 'ROLLBACK TRANSACTION'); - break; - } - - return true; - } - - /** - * {@inheritDoc} - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - if ($this->debug_sql_explain) - { - $this->sql_report('start', $query); - } - else if ($this->debug_load_time) - { - $this->curtime = microtime(true); - } - - $this->last_query_text = $query; - $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 = @odbc_exec($this->db_connect_id, $query)) === false) - { - $this->sql_error($query); - } - - if ($this->debug_sql_explain) - { - $this->sql_report('stop', $query); - } - else if ($this->debug_load_time) - { - $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->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if ($this->debug_sql_explain) - { - $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) ? @odbc_num_rows($this->query_result) : 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) ? odbc_fetch_array($query_id) : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - $result_id = @odbc_exec($this->db_connect_id, 'SELECT @@IDENTITY'); - - if ($result_id) - { - if (odbc_fetch_array($result_id)) - { - $id = odbc_result($result_id, 1); - odbc_free_result($result_id); - return $id; - } - odbc_free_result($result_id); - } - - return false; - } - - /** - * {@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 odbc_free_result($query_id); - } - - return false; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('odbc_errormsg')) - { - $error = array( - 'message' => @odbc_errormsg(), - 'code' => @odbc_error(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @odbc_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @odbc_exec($this->db_connect_id, $query); - if ($result) - { - while ($void = odbc_fetch_array($result)) - { - // Take the time spent on parsing rows into account - } - odbc_free_result($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/install/update/new/phpbb/db/driver/mssqlnative.php b/install/update/new/phpbb/db/driver/mssqlnative.php deleted file mode 100644 index 30ef9d9..0000000 --- a/install/update/new/phpbb/db/driver/mssqlnative.php +++ /dev/null @@ -1,450 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* This is the MS SQL Server Native database abstraction layer. -* PHP mssql native driver required. -* @author Chris Pucci -* -*/ - -namespace phpbb\db\driver; - -class mssqlnative extends \phpbb\db\driver\mssql_base -{ - var $m_insert_id = null; - var $last_query_text = ''; - var $query_options = array(); - var $connect_error = ''; - - /** - * {@inheritDoc} - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - // Test for driver support, to avoid suppressed fatal error - if (!function_exists('sqlsrv_connect')) - { - $this->connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx'; - return $this->sql_error(''); - } - - //set up connection variables - $this->persistency = $persistency; - $this->user = $sqluser; - $this->dbname = $database; - $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; - $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); - - //connect to database - $this->db_connect_id = sqlsrv_connect($this->server, array( - 'Database' => $this->dbname, - 'UID' => $this->user, - 'PWD' => $sqlpassword, - 'CharacterSet' => 'UTF-8' - )); - - 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) - { - $arr_server_info = sqlsrv_server_info($this->db_connect_id); - $this->sql_server_version = $arr_server_info['SQLServerVersion']; - - if (!empty($cache) && $use_cache) - { - $cache->put('mssql_version', $this->sql_server_version); - } - } - - if ($raw) - { - return $this->sql_server_version; - } - - return ($this->sql_server_version) ? 'MSSQL
' . $this->sql_server_version : 'MSSQL'; - } - - /** - * {@inheritDoc} - */ - function sql_buffer_nested_transactions() - { - return true; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return sqlsrv_begin_transaction($this->db_connect_id); - break; - - case 'commit': - return sqlsrv_commit($this->db_connect_id); - break; - - case 'rollback': - return sqlsrv_rollback($this->db_connect_id); - break; - } - return true; - } - - /** - * {@inheritDoc} - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - if ($this->debug_sql_explain) - { - $this->sql_report('start', $query); - } - else if ($this->debug_load_time) - { - $this->curtime = microtime(true); - } - - $this->last_query_text = $query; - $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 = @sqlsrv_query($this->db_connect_id, $query, array(), $this->query_options)) === false) - { - $this->sql_error($query); - } - // reset options for next query - $this->query_options = array(); - - if ($this->debug_sql_explain) - { - $this->sql_report('stop', $query); - } - else if ($this->debug_load_time) - { - $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->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if ($this->debug_sql_explain) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // total == 0 means all results - not zero results - if ($offset == 0 && $total !== 0) - { - if (strpos($query, "SELECT") === false) - { - $query = "TOP {$total} " . $query; - } - else - { - $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query); - } - } - else if ($offset > 0) - { - $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query); - $query = 'SELECT * - FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3 - FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3'; - - if ($total > 0) - { - $query .= ' WHERE line3 BETWEEN ' . ($offset+1) . ' AND ' . ($offset + $total); - } - else - { - $query .= ' WHERE line3 > ' . $offset; - } - } - - $result = $this->sql_query($query, $cache_ttl); - - return $result; - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @sqlsrv_rows_affected($this->query_result) : 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) - { - return false; - } - - $row = sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC); - - if ($row) - { - foreach ($row as $key => $value) - { - $row[$key] = ($value === ' ' || $value === null) ? '' : $value; - } - - // remove helper values from LIMIT queries - if (isset($row['line2'])) - { - unset($row['line2'], $row['line3']); - } - } - return ($row !== null) ? $row : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - $result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY'); - - if ($result_id) - { - $row = sqlsrv_fetch_array($result_id); - $id = $row[0]; - sqlsrv_free_stmt($result_id); - return $id; - } - else - { - 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 sqlsrv_free_stmt($query_id); - } - - return false; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('sqlsrv_errors')) - { - $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); - $error_message = ''; - $code = 0; - - if ($errors != null) - { - foreach ($errors as $error) - { - $error_message .= "SQLSTATE: " . $error['SQLSTATE'] . "\n"; - $error_message .= "code: " . $error['code'] . "\n"; - $code = $error['code']; - $error_message .= "message: " . $error['message'] . "\n"; - } - $this->last_error_result = $error_message; - $error = $this->last_error_result; - } - else - { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); - } - - $error = array( - 'message' => $error, - 'code' => $code, - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @sqlsrv_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - $html_table = false; - @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;'); - if ($result = @sqlsrv_query($this->db_connect_id, $query)) - { - sqlsrv_next_result($result); - while ($row = sqlsrv_fetch_array($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - sqlsrv_free_stmt($result); - } - @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;'); - - if ($html_table) - { - $this->html_hold .= ''; - } - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @sqlsrv_query($this->db_connect_id, $query); - if ($result) - { - while ($void = sqlsrv_fetch_array($result)) - { - // Take the time spent on parsing rows into account - } - sqlsrv_free_stmt($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } - - /** - * Utility method used to retrieve number of rows - * Emulates mysql_num_rows - * Used in acp_database.php -> write_data_mssqlnative() - * Requires a static or keyset cursor to be definde via - * mssqlnative_set_query_options() - */ - function mssqlnative_num_rows($res) - { - if ($res !== false) - { - return sqlsrv_num_rows($res); - } - else - { - return false; - } - } - - /** - * Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter. - */ - function mssqlnative_set_query_options($options) - { - $this->query_options = $options; - } -} diff --git a/install/update/new/phpbb/db/driver/mysqli.php b/install/update/new/phpbb/db/driver/mysqli.php deleted file mode 100644 index 0c1c063..0000000 --- a/install/update/new/phpbb/db/driver/mysqli.php +++ /dev/null @@ -1,492 +0,0 @@ - -* @license 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; - -/** -* MySQLi Database Abstraction Layer -* mysqli-extension has to be compiled with: -* MySQL 4.1+ or MySQL 5.0+ -*/ -class mysqli extends \phpbb\db\driver\mysql_base -{ - var $multi_insert = true; - var $connect_error = ''; - - /** - * {@inheritDoc} - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - if (!function_exists('mysqli_connect')) - { - $this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?'; - return $this->sql_error(''); - } - - $this->persistency = $persistency; - $this->user = $sqluser; - - // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix - $this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver; - - $this->dbname = $database; - $port = (!$port) ? null : $port; - - // If port is set and it is not numeric, most likely mysqli socket is set. - // Try to map it to the $socket parameter. - $socket = null; - if ($port) - { - if (is_numeric($port)) - { - $port = (int) $port; - } - else - { - $socket = $port; - $port = null; - } - } - - $this->db_connect_id = mysqli_init(); - - if (!@mysqli_real_connect($this->db_connect_id, $this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket, MYSQLI_CLIENT_FOUND_ROWS)) - { - $this->db_connect_id = ''; - } - - 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) - { - $row = mysqli_fetch_assoc($result); - mysqli_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)) - { - if (!in_array('STRICT_ALL_TABLES', $modes)) - { - $modes[] = 'STRICT_ALL_TABLES'; - } - - if (!in_array('STRICT_TRANS_TABLES', $modes)) - { - $modes[] = 'STRICT_TRANS_TABLES'; - } - } - - $mode = implode(',', $modes); - @mysqli_query($this->db_connect_id, "SET SESSION sql_mode='{$mode}'"); - } - return $this->db_connect_id; - } - - return $this->sql_error(''); - } - - /** - * {@inheritDoc} - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false) - { - $result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version'); - if ($result) - { - $row = mysqli_fetch_assoc($result); - mysqli_free_result($result); - - $this->sql_server_version = $row['version']; - - if (!empty($cache) && $use_cache) - { - $cache->put('mysqli_version', $this->sql_server_version); - } - } - } - - return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @mysqli_autocommit($this->db_connect_id, false); - break; - - case 'commit': - $result = @mysqli_commit($this->db_connect_id); - @mysqli_autocommit($this->db_connect_id, true); - return $result; - break; - - case 'rollback': - $result = @mysqli_rollback($this->db_connect_id); - @mysqli_autocommit($this->db_connect_id, true); - return $result; - break; - } - - return true; - } - - /** - * {@inheritDoc} - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - if ($this->debug_sql_explain) - { - $this->sql_report('start', $query); - } - else if ($this->debug_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 = @mysqli_query($this->db_connect_id, $query)) === false) - { - $this->sql_error($query); - } - - if ($this->debug_sql_explain) - { - $this->sql_report('stop', $query); - } - else if ($this->debug_load_time) - { - $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); - } - } - else if ($this->debug_sql_explain) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @mysqli_affected_rows($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 && !is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchrow($query_id); - } - - if ($query_id) - { - $result = mysqli_fetch_assoc($query_id); - return $result !== null ? $result : false; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_rowseek($rownum, &$query_id) - { - 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_rowseek($rownum, $query_id); - } - - return ($query_id) ? @mysqli_data_seek($query_id, $rownum) : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - return ($this->db_connect_id) ? @mysqli_insert_id($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); - } - - if (!$query_id) - { - return false; - } - - if ($query_id === true) - { - return true; - } - - return mysqli_free_result($query_id); - } - - /** - * {@inheritDoc} - */ - function sql_escape($msg) - { - return @mysqli_real_escape_string($this->db_connect_id, $msg); - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if ($this->db_connect_id) - { - $error = array( - 'message' => @mysqli_error($this->db_connect_id), - 'code' => @mysqli_errno($this->db_connect_id) - ); - } - else if (function_exists('mysqli_connect_error')) - { - $error = array( - 'message' => @mysqli_connect_error(), - 'code' => @mysqli_connect_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @mysqli_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - static $test_prof; - - // current detection method, might just switch to see the existence of INFORMATION_SCHEMA.PROFILING - if ($test_prof === null) - { - $test_prof = false; - if (strpos(mysqli_get_server_info($this->db_connect_id), 'community') !== false) - { - $ver = mysqli_get_server_version($this->db_connect_id); - if ($ver >= 50037 && $ver < 50100) - { - $test_prof = true; - } - } - } - - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - // begin profiling - if ($test_prof) - { - @mysqli_query($this->db_connect_id, 'SET profiling = 1;'); - } - - if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query")) - { - while ($row = mysqli_fetch_assoc($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - mysqli_free_result($result); - } - - if ($html_table) - { - $this->html_hold .= ''; - } - - if ($test_prof) - { - $html_table = false; - - // get the last profile - if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;')) - { - $this->html_hold .= '
'; - while ($row = mysqli_fetch_assoc($result)) - { - // make HTML safe - if (!empty($row['Source_function'])) - { - $row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']); - } - - // remove unsupported features - foreach ($row as $key => $val) - { - if ($val === null) - { - unset($row[$key]); - } - } - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - mysqli_free_result($result); - } - - if ($html_table) - { - $this->html_hold .= ''; - } - - @mysqli_query($this->db_connect_id, 'SET profiling = 0;'); - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @mysqli_query($this->db_connect_id, $query); - if ($result) - { - while ($void = mysqli_fetch_assoc($result)) - { - // Take the time spent on parsing rows into account - } - mysqli_free_result($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/install/update/new/phpbb/db/driver/oracle.php b/install/update/new/phpbb/db/driver/oracle.php deleted file mode 100644 index f2a0bb5..0000000 --- a/install/update/new/phpbb/db/driver/oracle.php +++ /dev/null @@ -1,821 +0,0 @@ - -* @license 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; - -/** -* Oracle Database Abstraction Layer -*/ -class oracle extends \phpbb\db\driver\driver -{ - var $last_query_text = ''; - 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; - - $connect = $database; - - // support for "easy connect naming" - if ($sqlserver !== '' && $sqlserver !== '/') - { - if (substr($sqlserver, -1, 1) == '/') - { - $sqlserver == substr($sqlserver, 0, -1); - } - $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database; - } - - if ($new_link) - { - if (!function_exists('ocinlogon')) - { - $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - else if ($this->persistency) - { - if (!function_exists('ociplogon')) - { - $this->connect_error = 'ociplogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - else - { - if (!function_exists('ocilogon')) - { - $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - - return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); - } - - /** - * {@inheritDoc} - */ - function sql_server_info($raw = false, $use_cache = true) - { - /** - * force $use_cache false. I didn't research why the caching code below is commented out - * but I assume its because the Oracle extension provides a direct method to access it - * without a query. - */ -/* - global $cache; - - if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false) - { - $result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\''); - @ociexecute($result, OCI_DEFAULT); - @ocicommit($this->db_connect_id); - - $row = array(); - @ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS); - @ocifreestatement($result); - $this->sql_server_version = trim($row['BANNER']); - - $cache->put('oracle_version', $this->sql_server_version); - } -*/ - $this->sql_server_version = @ociserverversion($this->db_connect_id); - - return $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return true; - break; - - case 'commit': - return @ocicommit($this->db_connect_id); - break; - - case 'rollback': - return @ocirollback($this->db_connect_id); - break; - } - - return true; - } - - /** - * Oracle specific code to handle the fact that it does not compare columns properly - * @access private - */ - function _rewrite_col_compare($args) - { - if (count($args) == 4) - { - if ($args[2] == '=') - { - return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))'; - } - else if ($args[2] == '<>') - { - // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P - return '(' . $args[0] . ' OR ((' . $args[1] . ' is NULL AND ' . $args[3] . ' is NOT NULL) OR (' . $args[1] . ' is NOT NULL AND ' . $args[3] . ' is NULL)))'; - } - } - else - { - return $this->_rewrite_where($args[0]); - } - } - - /** - * Oracle specific code to handle it's lack of sanity - * @access private - */ - function _rewrite_where($where_clause) - { - preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER); - $out = ''; - foreach ($result as $val) - { - if (!isset($val[5])) - { - if ($val[4] !== "''") - { - $out .= $val[0]; - } - else - { - $out .= ' ' . $val[1] . ' ' . $val[2]; - if ($val[3] == '=') - { - $out .= ' is NULL'; - } - else if ($val[3] == '<>') - { - $out .= ' is NOT NULL'; - } - } - } - else - { - $in_clause = array(); - $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1); - $extra = false; - preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER); - $i = 0; - foreach ($sub_vals[0] as $sub_val) - { - // two things: - // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison - // 2) This fixes the 1000 list limit that Oracle has (ORA-01795) - if ($sub_val !== "''") - { - $in_clause[(int) $i++/1000][] = $sub_val; - } - else - { - $extra = true; - } - } - if (!$extra && $i < 1000) - { - $out .= $val[0]; - } - else - { - $out .= ' ' . $val[1] . '('; - $in_array = array(); - - // constuct each IN() clause - foreach ($in_clause as $in_values) - { - $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')'; - } - - // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway) - $out .= implode(' OR ', $in_array); - - // handle the empty string case - if ($extra) - { - $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL'; - } - $out .= ')'; - - unset($in_array, $in_clause); - } - } - } - - return $out; - } - - /** - * {@inheritDoc} - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - if ($this->debug_sql_explain) - { - $this->sql_report('start', $query); - } - else if ($this->debug_load_time) - { - $this->curtime = microtime(true); - } - - $this->last_query_text = $query; - $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - $in_transaction = false; - if (!$this->transaction) - { - $this->sql_transaction('begin'); - } - else - { - $in_transaction = true; - } - - $array = array(); - - // We overcome Oracle's 4000 char limit by binding vars - if (strlen($query) > 4000) - { - if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs)) - { - if (strlen($regs[3]) > 4000) - { - $cols = explode(', ', $regs[2]); - - preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); - -/* The code inside this comment block breaks clob handling, but does allow the - database restore script to work. If you want to allow no posts longer than 4KB - and/or need the db restore script, uncomment this. - - - if (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]); - $_vals = explode(', ', $regs[3]); - - $vals = array(); - $is_in_val = false; - $i = 0; - $string = ''; - - foreach ($_vals as $value) - { - if (strpos($value, "'") === false && !$is_in_val) - { - $vals[$i++] = $value; - continue; - } - - if (substr($value, -1) === "'") - { - $vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value; - $string = ''; - $is_in_val = false; - - if ($vals[$i][0] !== "'") - { - $vals[$i] = "''" . $vals[$i]; - } - $i++; - continue; - } - else - { - $string .= (($is_in_val) ? ', ' : '') . $value; - $is_in_val = true; - } - } - - if ($string) - { - // New value if cols != value - $vals[(count($cols) !== count($vals)) ? $i : $i - 1] .= $string; - } - - $vals = array(0 => $vals); - } -*/ - - $inserts = $vals[0]; - unset($vals); - - foreach ($inserts as $key => $value) - { - if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2 - { - $inserts[$key] = ':' . strtoupper($cols[$key]); - $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1)); - } - } - - $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')'; - } - } - else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER)) - { - if (strlen($data[0][2]) > 4000) - { - $update = $data[0][1]; - $where = $data[0][3]; - preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER); - unset($data); - - $cols = array(); - foreach ($temp as $value) - { - if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2 - { - $cols[] = $value[1] . '=:' . strtoupper($value[1]); - $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1)); - } - else - { - $cols[] = $value[1] . '=' . $value[2]; - } - } - - $query = $update . implode(', ', $cols) . ' ' . $where; - unset($cols); - } - } - } - - switch (substr($query, 0, 6)) - { - case 'DELETE': - if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs)) - { - $query = $regs[1] . $this->_rewrite_where($regs[2]); - unset($regs); - } - break; - - case 'UPDATE': - if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs)) - { - $query = $regs[1] . $this->_rewrite_where($regs[2]); - unset($regs); - } - break; - - case 'SELECT': - $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query); - break; - } - - $this->query_result = @ociparse($this->db_connect_id, $query); - - foreach ($array as $key => $value) - { - @ocibindbyname($this->query_result, $key, $array[$key], -1); - } - - $success = @ociexecute($this->query_result, OCI_DEFAULT); - - if (!$success) - { - $this->sql_error($query); - $this->query_result = false; - } - else - { - if (!$in_transaction) - { - $this->sql_transaction('commit'); - } - } - - if ($this->debug_sql_explain) - { - $this->sql_report('stop', $query); - } - else if ($this->debug_load_time) - { - $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->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if ($this->debug_sql_explain) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset; - - return $this->sql_query($query, $cache_ttl); - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - return ($this->query_result) ? @ocirowcount($this->query_result) : 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) - { - $row = array(); - $result = ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS); - - if (!$result || !$row) - { - return false; - } - - $result_row = array(); - foreach ($row as $key => $value) - { - // Oracle treats empty strings as null - if (is_null($value)) - { - $value = ''; - } - - // OCI->CLOB? - if (is_object($value)) - { - $value = $value->load(); - } - - $result_row[strtolower($key)] = $value; - } - - return $result_row; - } - - return false; - } - - /** - * {@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); - } - - if (!$query_id) - { - return false; - } - - // Reset internal pointer - @ociexecute($query_id, OCI_DEFAULT); - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - $query_id = $this->query_result; - - if ($query_id !== false && $this->last_query_text != '') - { - if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename)) - { - $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL'; - $stmt = @ociparse($this->db_connect_id, $query); - if ($stmt) - { - $success = @ociexecute($stmt, OCI_DEFAULT); - - 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; - } - } - } - } - } - - 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 ocifreestatement($query_id); - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_escape($msg) - { - return str_replace(array("'", "\0"), array("''", ''), $msg); - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - /** - * Build NOT LIKE expression - * @access private - */ - function _sql_not_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - function _sql_custom_build($stage, $data) - { - return $data; - } - - function _sql_bit_and($column_name, $bit, $compare = '') - { - return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); - } - - function _sql_bit_or($column_name, $bit, $compare = '') - { - return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('ocierror')) - { - $error = @ocierror(); - $error = (!$error) ? @ocierror($this->query_result) : $error; - $error = (!$error) ? @ocierror($this->db_connect_id) : $error; - - if ($error) - { - $this->last_error_result = $error; - } - else - { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); - } - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @ocilogoff($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $html_table = false; - - // Grab a plan table, any will do - $sql = "SELECT table_name - FROM USER_TABLES - WHERE table_name LIKE '%PLAN_TABLE%'"; - $stmt = ociparse($this->db_connect_id, $sql); - ociexecute($stmt); - $result = array(); - - if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS)) - { - $table = $result['TABLE_NAME']; - - // This is the statement_id that will allow us to track the plan - $statement_id = substr(md5($query), 0, 30); - - // Remove any stale plans - $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); - ociexecute($stmt2); - ocifreestatement($stmt2); - - // Explain the plan - $sql = "EXPLAIN PLAN - SET STATEMENT_ID = '$statement_id' - FOR $query"; - $stmt2 = ociparse($this->db_connect_id, $sql); - ociexecute($stmt2); - ocifreestatement($stmt2); - - // Get the data from the plan - $sql = "SELECT operation, options, object_name, object_type, cardinality, cost - FROM plan_table - START WITH id = 0 AND statement_id = '$statement_id' - CONNECT BY PRIOR id = parent_id - AND statement_id = '$statement_id'"; - $stmt2 = ociparse($this->db_connect_id, $sql); - ociexecute($stmt2); - - $row = array(); - while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - - ocifreestatement($stmt2); - - // Remove the plan we just made, we delete them on request anyway - $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); - ociexecute($stmt2); - ocifreestatement($stmt2); - } - - ocifreestatement($stmt); - - if ($html_table) - { - $this->html_hold .= ''; - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @ociparse($this->db_connect_id, $query); - if ($result) - { - $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); - } - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/install/update/new/phpbb/db/driver/postgres.php b/install/update/new/phpbb/db/driver/postgres.php deleted file mode 100644 index ed330bc..0000000 --- a/install/update/new/phpbb/db/driver/postgres.php +++ /dev/null @@ -1,500 +0,0 @@ - -* @license 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; - -/** -* PostgreSQL Database Abstraction Layer -* Minimum Requirement is Version 8.3+ -*/ -class postgres extends \phpbb\db\driver\driver -{ - var $multi_insert = true; - var $last_query_text = ''; - var $connect_error = ''; - - /** - * {@inheritDoc} - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $connect_string = ''; - - if ($sqluser) - { - $connect_string .= "user=$sqluser "; - } - - if ($sqlpassword) - { - $connect_string .= "password=$sqlpassword "; - } - - if ($sqlserver) - { - // $sqlserver can carry a port separated by : for compatibility reasons - // If $sqlserver has more than one : it's probably an IPv6 address. - // In this case we only allow passing a port via the $port variable. - if (substr_count($sqlserver, ':') === 1) - { - list($sqlserver, $port) = explode(':', $sqlserver); - } - - if ($sqlserver !== 'localhost') - { - $connect_string .= "host=$sqlserver "; - } - - if ($port) - { - $connect_string .= "port=$port "; - } - } - - $schema = ''; - - if ($database) - { - $this->dbname = $database; - if (strpos($database, '.') !== false) - { - list($database, $schema) = explode('.', $database); - } - $connect_string .= "dbname=$database"; - } - - $this->persistency = $persistency; - - if ($this->persistency) - { - if (!function_exists('pg_pconnect')) - { - $this->connect_error = 'pg_pconnect function does not exist, is pgsql extension installed?'; - return $this->sql_error(''); - } - $collector = new \phpbb\error_collector; - $collector->install(); - $this->db_connect_id = (!$new_link) ? @pg_pconnect($connect_string) : @pg_pconnect($connect_string, PGSQL_CONNECT_FORCE_NEW); - } - else - { - if (!function_exists('pg_connect')) - { - $this->connect_error = 'pg_connect function does not exist, is pgsql extension installed?'; - return $this->sql_error(''); - } - $collector = new \phpbb\error_collector; - $collector->install(); - $this->db_connect_id = (!$new_link) ? @pg_connect($connect_string) : @pg_connect($connect_string, PGSQL_CONNECT_FORCE_NEW); - } - - $collector->uninstall(); - - if ($this->db_connect_id) - { - if ($schema !== '') - { - @pg_query($this->db_connect_id, 'SET search_path TO ' . $schema); - } - return $this->db_connect_id; - } - - $this->connect_error = $collector->format_errors(); - return $this->sql_error(''); - } - - /** - * {@inheritDoc} - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('pgsql_version')) === false) - { - $query_id = @pg_query($this->db_connect_id, 'SELECT VERSION() AS version'); - 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; - - if (!empty($cache) && $use_cache) - { - $cache->put('pgsql_version', $this->sql_server_version); - } - } - } - - return ($raw) ? $this->sql_server_version : 'PostgreSQL ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @pg_query($this->db_connect_id, 'BEGIN'); - break; - - case 'commit': - return @pg_query($this->db_connect_id, 'COMMIT'); - break; - - case 'rollback': - return @pg_query($this->db_connect_id, 'ROLLBACK'); - break; - } - - return true; - } - - /** - * {@inheritDoc} - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - if ($this->debug_sql_explain) - { - $this->sql_report('start', $query); - } - else if ($this->debug_load_time) - { - $this->curtime = microtime(true); - } - - $this->last_query_text = $query; - $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 = @pg_query($this->db_connect_id, $query)) === false) - { - $this->sql_error($query); - } - - if ($this->debug_sql_explain) - { - $this->sql_report('stop', $query); - } - else if ($this->debug_load_time) - { - $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->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if ($this->debug_sql_explain) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) - { - $total = 'ALL'; - } - - $query .= "\n LIMIT $total OFFSET $offset"; - - return $this->sql_query($query, $cache_ttl); - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - return ($this->query_result) ? @pg_affected_rows($this->query_result) : 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) ? pg_fetch_assoc($query_id, null) : 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) ? @pg_result_seek($query_id, $rownum) : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - $query_id = $this->query_result; - - if ($query_id !== false && $this->last_query_text != '') - { - if (preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $this->last_query_text, $tablename)) - { - $query = "SELECT currval('" . $tablename[1] . "_seq') AS last_value"; - $temp_q_id = @pg_query($this->db_connect_id, $query); - - if (!$temp_q_id) - { - return false; - } - - $temp_result = pg_fetch_assoc($temp_q_id, null); - pg_free_result($query_id); - - return ($temp_result) ? $temp_result['last_value'] : false; - } - } - - return false; - } - - /** - * {@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 pg_free_result($query_id); - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_escape($msg) - { - return @pg_escape_string($msg); - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression; - } - - /** - * Build NOT LIKE expression - * @access private - */ - function _sql_not_like_expression($expression) - { - return $expression; - } - - /** - * {@inheritDoc} - */ - function cast_expr_to_bigint($expression) - { - return 'CAST(' . $expression . ' as DECIMAL(255, 0))'; - } - - /** - * {@inheritDoc} - */ - function cast_expr_to_string($expression) - { - return 'CAST(' . $expression . ' as VARCHAR(255))'; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - // pg_last_error only works when there is an established connection. - // Connection errors have to be tracked by us manually. - if ($this->db_connect_id) - { - $message = @pg_last_error($this->db_connect_id); - } - else - { - $message = $this->connect_error; - } - - return array( - 'message' => $message, - 'code' => '' - ); - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @pg_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - if ($result = @pg_query($this->db_connect_id, "EXPLAIN $explain_query")) - { - while ($row = pg_fetch_assoc($result, null)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - pg_free_result($result); - } - - if ($html_table) - { - $this->html_hold .= ''; - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @pg_query($this->db_connect_id, $query); - if ($result) - { - while ($void = pg_fetch_assoc($result, null)) - { - // Take the time spent on parsing rows into account - } - pg_free_result($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/install/update/new/phpbb/db/driver/sqlite3.php b/install/update/new/phpbb/db/driver/sqlite3.php deleted file mode 100644 index 43906f1..0000000 --- a/install/update/new/phpbb/db/driver/sqlite3.php +++ /dev/null @@ -1,430 +0,0 @@ - -* @license 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; - -/** -* SQLite3 Database Abstraction Layer -* Minimum Requirement: 3.6.15+ -*/ -class sqlite3 extends \phpbb\db\driver\driver -{ - /** - * @var string Stores errors during connection setup in case the driver is not available - */ - protected $connect_error = ''; - - /** - * @var \SQLite3 The SQLite3 database object to operate against - */ - protected $dbo = null; - - /** - * {@inheritDoc} - */ - public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $this->persistency = false; - $this->user = $sqluser; - $this->server = $sqlserver . (($port) ? ':' . $port : ''); - $this->dbname = $database; - - if (!class_exists('SQLite3', false)) - { - $this->connect_error = 'SQLite3 not found, is the extension installed?'; - return $this->sql_error(''); - } - - try - { - $this->dbo = new \SQLite3($this->server, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE); - $this->dbo->busyTimeout(60000); - $this->db_connect_id = true; - } - catch (\Exception $e) - { - $this->connect_error = $e->getMessage(); - return array('message' => $this->connect_error); - } - - return true; - } - - /** - * {@inheritDoc} - */ - public 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) - { - $version = \SQLite3::version(); - - $this->sql_server_version = $version['versionString']; - - 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 - * - * @param string $status Should be one of the following strings: - * begin, commit, rollback - * @return bool Success/failure of the transaction query - */ - protected function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return $this->dbo->exec('BEGIN IMMEDIATE'); - break; - - case 'commit': - return $this->dbo->exec('COMMIT'); - break; - - case 'rollback': - return @$this->dbo->exec('ROLLBACK'); - break; - } - - return true; - } - - /** - * {@inheritDoc} - */ - public function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - if ($this->debug_sql_explain) - { - $this->sql_report('start', $query); - } - else if ($this->debug_load_time) - { - $this->curtime = microtime(true); - } - - $this->last_query_text = $query; - $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->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) - { - // 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 ($this->debug_sql_explain) - { - $this->sql_report('stop', $query); - } - else if ($this->debug_load_time) - { - $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); - } - } - else if ($this->debug_sql_explain) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - * - * @param string $query The SQL query to execute - * @param int $total The number of rows to select - * @param int $offset - * @param int $cache_ttl Either 0 to avoid caching or - * the time in seconds which the result shall be kept in cache - * @return mixed Buffered, seekable result handle, false on error - */ - protected 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} - */ - public function sql_affectedrows() - { - return ($this->db_connect_id) ? $this->dbo->changes() : false; - } - - /** - * {@inheritDoc} - */ - public function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - /** @var \SQLite3Result $query_id */ - $query_id = $this->query_result; - } - - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchrow($query_id); - } - - return is_object($query_id) ? @$query_id->fetchArray(SQLITE3_ASSOC) : false; - } - - /** - * {@inheritDoc} - */ - public function sql_nextid() - { - return ($this->db_connect_id) ? $this->dbo->lastInsertRowID() : false; - } - - /** - * {@inheritDoc} - */ - public 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 ($query_id) - { - return @$query_id->finalize(); - } - } - - /** - * {@inheritDoc} - */ - public function sql_escape($msg) - { - return \SQLite3::escapeString($msg); - } - - /** - * {@inheritDoc} - * - * For SQLite an underscore is an unknown character. - */ - public 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 an unknown character. - */ - public 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 - * - * @return array - */ - protected function _sql_error() - { - if (class_exists('SQLite3', false) && isset($this->dbo)) - { - $error = array( - 'message' => $this->dbo->lastErrorMsg(), - 'code' => $this->dbo->lastErrorCode(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Build db-specific query data - * - * @param string $stage Available stages: FROM, WHERE - * @param mixed $data A string containing the CROSS JOIN query or an array of WHERE clauses - * - * @return string The db-specific query fragment - */ - protected function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * Close sql connection - * - * @return bool False if failure - */ - protected function _sql_close() - { - return $this->dbo->close(); - } - - /** - * Build db-specific report - * - * @param string $mode Available modes: display, start, stop, - * add_select_row, fromcache, record_fromcache - * @param string $query The Query that should be explained - * @return mixed Either a full HTML page, boolean or null - */ - protected function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - if ($result = $this->dbo->query("EXPLAIN QUERY PLAN $explain_query")) - { - while ($row = $result->fetchArray(SQLITE3_ASSOC)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - - if ($html_table) - { - $this->html_hold .= ''; - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = $this->dbo->query($query); - if ($result) - { - while ($void = $result->fetchArray(SQLITE3_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/install/update/new/phpbb/db/extractor/mysql_extractor.php b/install/update/new/phpbb/db/extractor/mysql_extractor.php deleted file mode 100644 index f3cb0db..0000000 --- a/install/update/new/phpbb/db/extractor/mysql_extractor.php +++ /dev/null @@ -1,301 +0,0 @@ - -* @license 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(); - } - - $this->write_data_mysqli($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 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 versions 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/install/update/new/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php b/install/update/new/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php deleted file mode 100644 index 247ccc7..0000000 --- a/install/update/new/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php +++ /dev/null @@ -1,129 +0,0 @@ - -* @license 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\v30x; - -class release_3_0_4_rc1 extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return phpbb_version_compare($this->config['version'], '3.0.4-RC1', '>='); - } - - static public function depends_on() - { - return array('\phpbb\db\migration\data\v30x\release_3_0_3'); - } - - public function update_schema() - { - return array( - 'add_columns' => array( - $this->table_prefix . 'profile_fields' => array( - 'field_show_profile' => array('BOOL', 0), - ), - ), - 'change_columns' => array( - $this->table_prefix . 'styles' => array( - 'style_id' => array('UINT', NULL, 'auto_increment'), - 'template_id' => array('UINT', 0), - 'theme_id' => array('UINT', 0), - 'imageset_id' => array('UINT', 0), - ), - $this->table_prefix . 'styles_imageset' => array( - 'imageset_id' => array('UINT', NULL, 'auto_increment'), - ), - $this->table_prefix . 'styles_imageset_data' => array( - 'image_id' => array('UINT', NULL, 'auto_increment'), - 'imageset_id' => array('UINT', 0), - ), - $this->table_prefix . 'styles_theme' => array( - 'theme_id' => array('UINT', NULL, 'auto_increment'), - ), - $this->table_prefix . 'styles_template' => array( - 'template_id' => array('UINT', NULL, 'auto_increment'), - ), - $this->table_prefix . 'styles_template_data' => array( - 'template_id' => array('UINT', 0), - ), - $this->table_prefix . 'forums' => array( - 'forum_style' => array('UINT', 0), - ), - $this->table_prefix . 'users' => array( - 'user_style' => array('UINT', 0), - ), - ), - ); - } - - public function revert_schema() - { - return array( - 'drop_columns' => array( - $this->table_prefix . 'profile_fields' => array( - 'field_show_profile', - ), - ), - ); - } - - public function update_data() - { - return array( - array('custom', array(array(&$this, 'update_custom_profile_fields'))), - - array('config.update', array('version', '3.0.4-RC1')), - ); - } - - public function update_custom_profile_fields() - { - // Update the Custom Profile Fields based on previous settings to the new \format - $sql = 'SELECT field_id, field_required, field_show_on_reg, field_hide - FROM ' . PROFILE_FIELDS_TABLE; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - $sql_ary = array( - 'field_required' => 0, - 'field_show_on_reg' => 0, - 'field_hide' => 0, - 'field_show_profile'=> 0, - ); - - if ($row['field_required']) - { - $sql_ary['field_required'] = $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1; - } - else if ($row['field_show_on_reg']) - { - $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1; - } - else if ($row['field_hide']) - { - // Only administrators and moderators can see this CPF, if the view is enabled, they can see it, otherwise just admins in the acp_users module - $sql_ary['field_hide'] = 1; - } - else - { - // equivalent to "none", which is the "Display in user control panel" option - $sql_ary['field_show_profile'] = 1; - } - - $this->sql_query('UPDATE ' . $this->table_prefix . 'profile_fields SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE field_id = ' . $row['field_id'], $errored, $error_ary); - } - - $this->db->sql_freeresult($result); - } -} diff --git a/install/update/new/phpbb/db/migration/data/v310/softdelete_p1.php b/install/update/new/phpbb/db/migration/data/v310/softdelete_p1.php deleted file mode 100644 index 877cdc2..0000000 --- a/install/update/new/phpbb/db/migration/data/v310/softdelete_p1.php +++ /dev/null @@ -1,211 +0,0 @@ - -* @license 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\v310; - -class softdelete_p1 extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return $this->db_tools->sql_column_exists($this->table_prefix . 'posts', 'post_visibility'); - } - - static public function depends_on() - { - return array('\phpbb\db\migration\data\v310\dev'); - } - - public function update_schema() - { - return array( - 'add_columns' => array( - $this->table_prefix . 'forums' => array( - 'forum_posts_approved' => array('UINT', 0), - 'forum_posts_unapproved' => array('UINT', 0), - 'forum_posts_softdeleted' => array('UINT', 0), - 'forum_topics_approved' => array('UINT', 0), - 'forum_topics_unapproved' => array('UINT', 0), - 'forum_topics_softdeleted' => array('UINT', 0), - ), - $this->table_prefix . 'posts' => array( - 'post_visibility' => array('TINT:3', 0), - 'post_delete_time' => array('TIMESTAMP', 0), - 'post_delete_reason' => array('STEXT_UNI', ''), - 'post_delete_user' => array('UINT', 0), - ), - $this->table_prefix . 'topics' => array( - 'topic_visibility' => array('TINT:3', 0), - 'topic_delete_time' => array('TIMESTAMP', 0), - 'topic_delete_reason' => array('STEXT_UNI', ''), - 'topic_delete_user' => array('UINT', 0), - 'topic_posts_approved' => array('UINT', 0), - 'topic_posts_unapproved' => array('UINT', 0), - 'topic_posts_softdeleted' => array('UINT', 0), - ), - ), - 'add_index' => array( - $this->table_prefix . 'posts' => array( - 'post_visibility' => array('post_visibility'), - ), - $this->table_prefix . 'topics' => array( - 'topic_visibility' => array('topic_visibility'), - 'forum_vis_last' => array('forum_id', 'topic_visibility', 'topic_last_post_id'), - ), - ), - ); - } - - public function revert_schema() - { - return array( - 'drop_columns' => array( - $this->table_prefix . 'forums' => array( - 'forum_posts_approved', - 'forum_posts_unapproved', - 'forum_posts_softdeleted', - 'forum_topics_approved', - 'forum_topics_unapproved', - 'forum_topics_softdeleted', - ), - $this->table_prefix . 'posts' => array( - 'post_visibility', - 'post_delete_time', - 'post_delete_reason', - 'post_delete_user', - ), - $this->table_prefix . 'topics' => array( - 'topic_visibility', - 'topic_delete_time', - 'topic_delete_reason', - 'topic_delete_user', - 'topic_posts_approved', - 'topic_posts_unapproved', - 'topic_posts_softdeleted', - ), - ), - 'drop_keys' => array( - $this->table_prefix . 'posts' => array('post_visibility'), - $this->table_prefix . 'topics' => array('topic_visibility', 'forum_vis_last'), - ), - ); - } - - public function update_data() - { - return array( - array('custom', array(array($this, 'update_post_visibility'))), - array('custom', array(array($this, 'update_topic_visibility'))), - array('custom', array(array($this, 'update_topics_post_counts'))), - array('custom', array(array($this, 'update_forums_topic_and_post_counts'))), - - array('permission.add', array('f_softdelete', false)), - array('permission.add', array('m_softdelete', false)), - ); - } - - public function update_post_visibility() - { - $sql = 'UPDATE ' . $this->table_prefix . 'posts - SET post_visibility = post_approved'; - $this->sql_query($sql); - } - - public function update_topic_visibility() - { - $sql = 'UPDATE ' . $this->table_prefix . 'topics - SET topic_visibility = topic_approved'; - $this->sql_query($sql); - } - - public function update_topics_post_counts() - { - /* - * Using sql_case here to avoid "BIGINT UNSIGNED value is out of range" errors. - * As we update all topics in 2 queries, one broken topic would stop the conversion - * for all topics and the suppressed error will cause the admin to not even notice it. - */ - $sql = 'UPDATE ' . $this->table_prefix . 'topics - SET topic_posts_approved = topic_replies + 1, - topic_posts_unapproved = ' . $this->db->sql_case('topic_replies_real > topic_replies', 'topic_replies_real - topic_replies', '0') . ' - WHERE topic_visibility = ' . ITEM_APPROVED; - $this->sql_query($sql); - - $sql = 'UPDATE ' . $this->table_prefix . 'topics - SET topic_posts_approved = 0, - topic_posts_unapproved = (' . $this->db->sql_case('topic_replies_real > topic_replies', 'topic_replies_real - topic_replies', '0') . ') + 1 - WHERE topic_visibility = ' . ITEM_UNAPPROVED; - $this->sql_query($sql); - } - - public function update_forums_topic_and_post_counts($start) - { - $start = (int) $start; - $limit = 10; - $converted_forums = 0; - - if (!$start) - { - // Preserve the forum_posts value for link forums as it represents redirects. - $sql = 'UPDATE ' . $this->table_prefix . 'forums - SET forum_posts_approved = forum_posts - WHERE forum_type = ' . FORUM_LINK; - $this->db->sql_query($sql); - } - - $sql = 'SELECT forum_id, topic_visibility, COUNT(topic_id) AS sum_topics, SUM(topic_posts_approved) AS sum_posts_approved, SUM(topic_posts_unapproved) AS sum_posts_unapproved - FROM ' . $this->table_prefix . 'topics - GROUP BY forum_id, topic_visibility - ORDER BY forum_id, topic_visibility'; - $result = $this->db->sql_query_limit($sql, $limit, $start); - - $update_forums = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $converted_forums++; - - $forum_id = (int) $row['forum_id']; - if (!isset($update_forums[$forum_id])) - { - $update_forums[$forum_id] = array( - 'forum_posts_approved' => 0, - 'forum_posts_unapproved' => 0, - 'forum_topics_approved' => 0, - 'forum_topics_unapproved' => 0, - ); - } - - $update_forums[$forum_id]['forum_posts_approved'] += (int) $row['sum_posts_approved']; - $update_forums[$forum_id]['forum_posts_unapproved'] += (int) $row['sum_posts_unapproved']; - - $update_forums[$forum_id][(($row['topic_visibility'] == ITEM_APPROVED) ? 'forum_topics_approved' : 'forum_topics_unapproved')] += (int) $row['sum_topics']; - } - $this->db->sql_freeresult($result); - - foreach ($update_forums as $forum_id => $forum_data) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . $this->db->sql_build_array('UPDATE', $forum_data) . ' - WHERE forum_id = ' . $forum_id; - $this->sql_query($sql); - } - - if ($converted_forums < $limit) - { - // There are no more topics, we are done - return; - } - - // There are still more topics to query, return the next start value - return $start + $limit; - } -} diff --git a/install/update/new/phpbb/db/migration/data/v32x/timezone_p3.php b/install/update/new/phpbb/db/migration/data/v32x/timezone_p3.php deleted file mode 100644 index 433f62a..0000000 --- a/install/update/new/phpbb/db/migration/data/v32x/timezone_p3.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @license 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/install/update/new/phpbb/db/migration/data/v32x/user_emoji_permission.php b/install/update/new/phpbb/db/migration/data/v32x/user_emoji_permission.php deleted file mode 100644 index 98759c7..0000000 --- a/install/update/new/phpbb/db/migration/data/v32x/user_emoji_permission.php +++ /dev/null @@ -1,44 +0,0 @@ - -* @license 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/install/update/new/phpbb/db/migration/data/v32x/v328.php b/install/update/new/phpbb/db/migration/data/v32x/v328.php deleted file mode 100644 index 28ff2c7..0000000 --- a/install/update/new/phpbb/db/migration/data/v32x/v328.php +++ /dev/null @@ -1,36 +0,0 @@ - -* @license 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/install/update/new/phpbb/db/migration/data/v32x/v328rc1.php b/install/update/new/phpbb/db/migration/data/v32x/v328rc1.php deleted file mode 100644 index fa43cf3..0000000 --- a/install/update/new/phpbb/db/migration/data/v32x/v328rc1.php +++ /dev/null @@ -1,37 +0,0 @@ - -* @license 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/install/update/new/phpbb/db/migration/data/v32x/v329.php b/install/update/new/phpbb/db/migration/data/v32x/v329.php deleted file mode 100644 index e88e264..0000000 --- a/install/update/new/phpbb/db/migration/data/v32x/v329.php +++ /dev/null @@ -1,37 +0,0 @@ - -* @license 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/install/update/new/phpbb/db/migration/data/v32x/v329rc1.php b/install/update/new/phpbb/db/migration/data/v32x/v329rc1.php deleted file mode 100644 index 271bf62..0000000 --- a/install/update/new/phpbb/db/migration/data/v32x/v329rc1.php +++ /dev/null @@ -1,36 +0,0 @@ - -* @license 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/install/update/new/phpbb/db/migration/data/v330/add_display_unapproved_posts_config.php b/install/update/new/phpbb/db/migration/data/v330/add_display_unapproved_posts_config.php deleted file mode 100644 index 209aba3..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/add_display_unapproved_posts_config.php +++ /dev/null @@ -1,34 +0,0 @@ - -* @license 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\v330; - -class add_display_unapproved_posts_config extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return $this->config->offsetExists('display_unapproved_posts'); - } - - public static function depends_on() - { - return ['\phpbb\db\migration\data\v330\dev',]; - } - - public function update_data() - { - return [ - ['config.add', ['display_unapproved_posts', 1]], - ]; - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/dev.php b/install/update/new/phpbb/db/migration/data/v330/dev.php deleted file mode 100644 index 209f9fc..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/dev.php +++ /dev/null @@ -1,36 +0,0 @@ - -* @license 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\v330; - -class dev extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return version_compare($this->config['version'], '3.3.0-dev', '>='); - } - - static public function depends_on() - { - return array( - '\phpbb\db\migration\data\v32x\v327', - ); - } - - public function update_data() - { - return array( - array('config.update', array('version', '3.3.0-dev')), - ); - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/forums_legend_limit.php b/install/update/new/phpbb/db/migration/data/v330/forums_legend_limit.php deleted file mode 100644 index c5a4bee..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/forums_legend_limit.php +++ /dev/null @@ -1,49 +0,0 @@ - -* @license 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\v330; - -class forums_legend_limit extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return $this->db_tools->sql_column_exists($this->table_prefix . 'forums', 'display_subforum_limit'); - } - - static public function depends_on() - { - return ['\phpbb\db\migration\data\v330\v330b1']; - } - - public function update_schema() - { - return [ - 'add_columns' => [ - $this->table_prefix . 'forums' => [ - 'display_subforum_limit' => ['BOOL', 0, 'after' => 'display_subforum_list'], - ], - ], - ]; - } - - public function revert_schema() - { - return [ - 'drop_columns' => [ - $this->table_prefix . 'forums' => [ - 'display_subforum_limit', - ], - ], - ]; - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/jquery_update.php b/install/update/new/phpbb/db/migration/data/v330/jquery_update.php deleted file mode 100644 index f1ac6cd..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/jquery_update.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @license 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\v330; - -class jquery_update extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return $this->config['load_jquery_url'] === '//ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js'; - } - - static public function depends_on() - { - return array( - '\phpbb\db\migration\data\v330\dev', - ); - } - - public function update_data() - { - return array( - array('config.update', array('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js')), - ); - } - -} diff --git a/install/update/new/phpbb/db/migration/data/v330/remove_attachment_flash.php b/install/update/new/phpbb/db/migration/data/v330/remove_attachment_flash.php deleted file mode 100644 index c136960..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/remove_attachment_flash.php +++ /dev/null @@ -1,89 +0,0 @@ - -* @license 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\v330; - -class remove_attachment_flash extends \phpbb\db\migration\migration -{ - // Following constants were deprecated in 3.3 - // and moved from constants.php to compatibility_globals.php, - // thus define them as class constants - const ATTACHMENT_CATEGORY_FLASH = 5; - - protected $cat_id = array( - self::ATTACHMENT_CATEGORY_FLASH, - ); - - public static function depends_on() - { - return ['\phpbb\db\migration\data\v330\dev',]; - } - - public function update_data() - { - return array( - array('custom', array(array($this, 'remove_flash_group'))), - ); - } - - public function remove_flash_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/install/update/new/phpbb/db/migration/data/v330/remove_email_hash.php b/install/update/new/phpbb/db/migration/data/v330/remove_email_hash.php deleted file mode 100644 index 8ac8f4e..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/remove_email_hash.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @license 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\v330; - -class remove_email_hash extends \phpbb\db\migration\migration -{ - static public function depends_on() - { - return ['\phpbb\db\migration\data\v30x\release_3_0_0']; - } - - public function update_schema() - { - return [ - 'add_index' => [ - $this->table_prefix . 'users' => [ - 'user_email' => ['user_email'], - ], - ], - 'drop_keys' => [ - $this->table_prefix . 'users' => [ - 'user_email_hash', - ], - ], - 'drop_columns' => [ - $this->table_prefix . 'users' => ['user_email_hash'], - ], - ]; - } - - public function revert_schema() - { - return [ - 'add_columns' => [ - $this->table_prefix . 'users' => [ - 'user_email_hash' => ['BINT', 0], - ], - ], - 'add_index' => [ - $this->table_prefix . 'users' => [ - 'user_email_hash', - ], - ], - 'drop_keys' => [ - $this->table_prefix . 'users' => [ - 'user_email' => ['user_email'], - ], - ], - ]; - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/remove_max_pass_chars.php b/install/update/new/phpbb/db/migration/data/v330/remove_max_pass_chars.php deleted file mode 100644 index 10e5ee3..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/remove_max_pass_chars.php +++ /dev/null @@ -1,43 +0,0 @@ - - * @license 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\v330; - -class remove_max_pass_chars extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return !$this->config->offsetExists('max_pass_chars'); - } - - public static function depends_on() - { - return [ - '\phpbb\db\migration\data\v330\dev', - ]; - } - - public function update_data() - { - return [ - ['config.remove', ['max_pass_chars']], - ]; - } - - public function revert_data() - { - return [ - ['config.add', ['max_pass_chars', 100]], - ]; - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/reset_password.php b/install/update/new/phpbb/db/migration/data/v330/reset_password.php deleted file mode 100644 index 953d478..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/reset_password.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @license 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\v330; - -class reset_password extends \phpbb\db\migration\migration -{ - static public function depends_on() - { - return [ - '\phpbb\db\migration\data\v330\dev', - ]; - } - - public function update_schema() - { - return [ - 'add_columns' => [ - $this->table_prefix . 'users' => [ - 'reset_token' => ['VCHAR:64', '', 'after' => 'user_actkey'], - 'reset_token_expiration' => ['TIMESTAMP', 0, 'after' => 'reset_token'], - ], - ], - ]; - } - - public function revert_schema() - { - return [ - 'drop_columns' => [ - $this->table_prefix . 'users' => [ - 'reset_token', - 'reset_token_expiration', - ], - ], - ]; - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/v330.php b/install/update/new/phpbb/db/migration/data/v330/v330.php deleted file mode 100644 index 05baffb..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/v330.php +++ /dev/null @@ -1,37 +0,0 @@ - -* @license 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\v330; - -class v330 extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return version_compare($this->config['version'], '3.3.0', '>='); - } - - static public function depends_on() - { - return array( - '\phpbb\db\migration\data\v32x\v329', - '\phpbb\db\migration\data\v330\v330rc1', - ); - } - - public function update_data() - { - return array( - array('config.update', array('version', '3.3.0')), - ); - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/v330b1.php b/install/update/new/phpbb/db/migration/data/v330/v330b1.php deleted file mode 100644 index 3df4450..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/v330b1.php +++ /dev/null @@ -1,41 +0,0 @@ - -* @license 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\v330; - -class v330b1 extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return version_compare($this->config['version'], '3.3.0-b1', '>='); - } - - static public function depends_on() - { - return array( - '\phpbb\db\migration\data\v330\jquery_update', - '\phpbb\db\migration\data\v330\reset_password', - '\phpbb\db\migration\data\v330\remove_attachment_flash', - '\phpbb\db\migration\data\v330\remove_max_pass_chars', - '\phpbb\db\migration\data\v32x\v328', - '\phpbb\db\migration\data\v330\dev', - ); - } - - public function update_data() - { - return array( - array('config.update', array('version', '3.3.0-b1')), - ); - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/v330b2.php b/install/update/new/phpbb/db/migration/data/v330/v330b2.php deleted file mode 100644 index cb2198a..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/v330b2.php +++ /dev/null @@ -1,39 +0,0 @@ - -* @license 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\v330; - -class v330b2 extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return version_compare($this->config['version'], '3.3.0-b2', '>='); - } - - static public function depends_on() - { - return array( - '\phpbb\db\migration\data\v330\add_display_unapproved_posts_config', - '\phpbb\db\migration\data\v330\forums_legend_limit', - '\phpbb\db\migration\data\v330\remove_email_hash', - '\phpbb\db\migration\data\v330\v330b1', - ); - } - - public function update_data() - { - return array( - array('config.update', array('version', '3.3.0-b2')), - ); - } -} diff --git a/install/update/new/phpbb/db/migration/data/v330/v330rc1.php b/install/update/new/phpbb/db/migration/data/v330/v330rc1.php deleted file mode 100644 index 5219375..0000000 --- a/install/update/new/phpbb/db/migration/data/v330/v330rc1.php +++ /dev/null @@ -1,36 +0,0 @@ - -* @license 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\v330; - -class v330rc1 extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return version_compare($this->config['version'], '3.3.0-RC1', '>='); - } - - static public function depends_on() - { - return array( - '\phpbb\db\migration\data\v330\v330b2', - ); - } - - public function update_data() - { - return array( - array('config.update', array('version', '3.3.0-RC1')), - ); - } -} diff --git a/install/update/new/phpbb/db/migration/tool/module.php b/install/update/new/phpbb/db/migration/tool/module.php deleted file mode 100644 index 93c3384..0000000 --- a/install/update/new/phpbb/db/migration/tool/module.php +++ /dev/null @@ -1,556 +0,0 @@ - -* @license 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\tool; - -use phpbb\module\exception\module_exception; - -/** -* Migration module management tool -*/ -class module implements \phpbb\db\migration\tool\tool_interface -{ - /** @var \phpbb\cache\service */ - protected $cache; - - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\user */ - protected $user; - - /** @var \phpbb\module\module_manager */ - protected $module_manager; - - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - - /** @var string */ - protected $modules_table; - - /** @var array */ - protected $module_categories = array(); - - /** - * Constructor - * - * @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\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; - } - - /** - * {@inheritdoc} - */ - public function get_name() - { - return 'module'; - } - - /** - * Module Exists - * - * Check if a module exists - * - * @param string $class The module class(acp|mcp|ucp) - * @param int|string|bool $parent The parent module_id|module_langname (0 for no parent). - * 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 - * @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, $lazy = false) - { - // the main root directory should return true - if (!$module) - { - return true; - } - - $parent_sqls = []; - if ($parent !== false) - { - $parents = $this->get_parent_module_id($parent, $module, false); - if ($parents === false) - { - return false; - } - - foreach ((array) $parents as $parent_id) - { - $parent_sqls[] = 'AND parent_id = ' . (int) $parent_id; - } - } - else - { - $parent_sqls[] = ''; - } - - foreach ($parent_sqls as $parent_sql) - { - $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; - } - } - - // Returns true, if modules exist in all parents and false otherwise - return !$lazy; - } - - /** - * Module Add - * - * Add a new module - * - * @param string $class The module class(acp|mcp|ucp) - * @param int|string $parent The parent module_id|module_langname (0 for no parent) - * @param array $data an array of the data on the new \module. - * This can be setup in two different ways. - * 1. The "manual" way. For inserting a category or one at a time. - * It will be merged with the base array shown a bit below, - * but at the least requires 'module_langname' to be sent, and, - * if you want to create a module (instead of just a category) you must - * send module_basename and module_mode. - * array( - * 'module_enabled' => 1, - * 'module_display' => 1, - * 'module_basename' => '', - * 'module_class' => $class, - * 'parent_id' => (int) $parent, - * 'module_langname' => '', - * 'module_mode' => '', - * 'module_auth' => '', - * ) - * 2. The "automatic" way. For inserting multiple at a time based on the - * specs in the info file for the module(s). For this to work the - * modules must be correctly setup in the info file. - * An example follows (this would insert the settings, log, and flag - * modes from the includes/acp/info/acp_asacp.php file): - * array( - * 'module_basename' => 'asacp', - * 'modes' => array('settings', 'log', 'flag'), - * ) - * Optionally you may not send 'modes' and it will insert all of the - * modules in that info file. - * path, specify that here - * @return null - * @throws \phpbb\db\migration\exception - */ - 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); - } - - $parents = (array) $this->get_parent_module_id($parent, $data); - - if (!isset($data['module_langname'])) - { - // The "automatic" way - $basename = (isset($data['module_basename'])) ? $data['module_basename'] : ''; - $module = $this->get_module_info($class, $basename); - - foreach ($module['modes'] as $mode => $module_info) - { - if (!isset($data['modes']) || in_array($mode, $data['modes'])) - { - $new_module = array( - 'module_basename' => $basename, - 'module_langname' => $module_info['title'], - 'module_mode' => $mode, - 'module_auth' => $module_info['auth'], - 'module_display' => (isset($module_info['display'])) ? $module_info['display'] : true, - 'before' => (isset($module_info['before'])) ? $module_info['before'] : false, - 'after' => (isset($module_info['after'])) ? $module_info['after'] : false, - ); - - // Run the "manual" way with the data we've collected. - foreach ($parents as $parent) - { - $this->add($class, $parent, $new_module); - } - } - } - - return; - } - - foreach ($parents as $parent) - { - $data['parent_id'] = $parent; - - // The "manual" way - if (!$this->exists($class, false, $parent)) - { - throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent); - } - - if ($this->exists($class, $parent, $data['module_langname'])) - { - throw new \phpbb\db\migration\exception('MODULE_EXISTS', $data['module_langname']); - } - - $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 - { - $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($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 . " - 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); - - $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']) - { - $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($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 . " - 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); - - $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); - } - } - catch (module_exception $e) - { - // Error - throw new \phpbb\db\migration\exception('MODULE_ERROR', $e->getMessage()); - } - } - - // Clear the Modules Cache - $this->module_manager->remove_cache_file($class); - } - - /** - * Module Remove - * - * Remove a module - * - * @param string $class The module class(acp|mcp|ucp) - * @param int|string|bool $parent The parent module_id|module_langname(0 for no parent). - * Use false to ignore the parent check and check class wide. - * @param int|string $module The module id|module_langname - * specify that here - * @return null - * @throws \phpbb\db\migration\exception - */ - public function remove($class, $parent = 0, $module = '') - { - // Imitation of module_add's "automatic" and "manual" method so the uninstaller works from the same set of instructions for umil_auto - if (is_array($module)) - { - if (isset($module['module_langname'])) - { - // Manual Method - return $this->remove($class, $parent, $module['module_langname']); - } - - // Failed. - if (!isset($module['module_basename'])) - { - throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST'); - } - - // Automatic method - $basename = $module['module_basename']; - $module_info = $this->get_module_info($class, $basename); - - foreach ($module_info['modes'] as $mode => $info) - { - if (!isset($module['modes']) || in_array($mode, $module['modes'])) - { - $this->remove($class, $parent, $info['title']); - } - } - } - else - { - if (!$this->exists($class, $parent, $module, true)) - { - return; - } - - $parent_sql = ''; - if ($parent !== false) - { - $parents = (array) $this->get_parent_module_id($parent, $module); - $parent_sql = 'AND ' . $this->db->sql_in_set('parent_id', $parents); - } - - $module_ids = array(); - if (!is_numeric($module)) - { - $sql = 'SELECT module_id - FROM ' . $this->modules_table . " - WHERE module_langname = '" . $this->db->sql_escape($module) . "' - AND module_class = '" . $this->db->sql_escape($class) . "' - $parent_sql"; - $result = $this->db->sql_query($sql); - while ($module_id = $this->db->sql_fetchfield('module_id')) - { - $module_ids[] = (int) $module_id; - } - $this->db->sql_freeresult($result); - } - else - { - $module_ids[] = (int) $module; - } - - foreach ($module_ids as $module_id) - { - $this->module_manager->delete_module($module_id, $class); - } - - $this->module_manager->remove_cache_file($class); - } - } - - /** - * {@inheritdoc} - */ - public function reverse() - { - $arguments = func_get_args(); - $original_call = array_shift($arguments); - - $call = false; - switch ($original_call) - { - case 'add': - $call = 'remove'; - break; - - case 'remove': - $call = 'add'; - break; - - case 'reverse': - // Reversing a reverse is just the call itself - $call = array_shift($arguments); - break; - } - - if ($call) - { - return call_user_func_array(array(&$this, $call), $arguments); - } - } - - /** - * Wrapper for \acp_modules::get_module_infos() - * - * @param string $class Module Class - * @param string $basename Module Basename - * @return array Module Information - * @throws \phpbb\db\migration\exception - */ - protected function get_module_info($class, $basename) - { - $module = $this->module_manager->get_module_infos($class, $basename, true); - - if (empty($module)) - { - throw new \phpbb\db\migration\exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename); - } - - return array_pop($module); - } - - /** - * Get the list of installed module categories - * key - module_id - * value - module_langname - * - * @return null - */ - protected function get_categories_list() - { - // Select the top level categories - // and 2nd level [sub]categories - $sql = 'SELECT m2.module_id, m2.module_langname - FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2 - WHERE m1.parent_id = 0 - AND (m1.module_id = m2.module_id OR m2.parent_id = m1.module_id) - ORDER BY m1.module_id, m2.module_id ASC"; - - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $this->module_categories[(int) $row['module_id']] = $row['module_langname']; - } - $this->db->sql_freeresult($result); - } - - /** - * Get parent module id - * - * @param string|int $parent_id The parent module_id|module_langname - * @param int|string|array $data The module_id, module_langname for existence 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, 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) - { - // Allow '' to be sent as 0 - $parent_id = $parent_id ?: 0; - - if (!is_numeric($parent_id)) - { - // Refresh the $module_categories array - $this->get_categories_list(); - - // Search for the parent module_langname - $ids = array_keys($this->module_categories, $parent_id); - - switch (count($ids)) - { - // No parent with the given module_langname exist - case 0: - if ($throw_exception) - { - throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id); - } - - return false; - break; - - // Return the module id - case 1: - return (int) $ids[0]; - break; - - default: - // This represents the old behaviour of phpBB 3.0 - return $ids; - break; - } - } - - return $parent_id; - } -} diff --git a/install/update/new/phpbb/db/migrator.php b/install/update/new/phpbb/db/migrator.php deleted file mode 100644 index 3a1ee75..0000000 --- a/install/update/new/phpbb/db/migrator.php +++ /dev/null @@ -1,1037 +0,0 @@ - -* @license 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\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; - -/** -* The migrator is responsible for applying new migrations in the correct order. -*/ -class migrator -{ - /** - * @var ContainerInterface - */ - protected $container; - - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\db\tools\tools_interface */ - protected $db_tools; - - /** @var \phpbb\db\migration\helper */ - protected $helper; - - /** @var string */ - protected $table_prefix; - - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - - /** @var string */ - protected $migrations_table; - - /** - * State of all migrations - * - * (SELECT * FROM migrations table) - * - * @var array - */ - protected $migration_state = array(); - - /** - * Array of all migrations available to be run - * - * @var array - */ - protected $migrations = array(); - - /** - * Array of migrations that have been determined to be fulfillable - * - * @var array - */ - protected $fulfillable_migrations = array(); - - /** - * 'name,' 'class,' and 'state' of the last migration run - * - * 'effectively_installed' set and set to true if the migration was effectively_installed - * - * @var array - */ - protected $last_run_migration = false; - - /** - * The output handler. A null handler is configured by default. - * - * @var migrator_output_handler_interface - */ - protected $output_handler; - - /** - * Constructor of the database migrator - */ - 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; - $this->db = $db; - $this->db_tools = $db_tools; - $this->helper = $helper; - - $this->migrations_table = $migrations_table; - - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->table_prefix = $table_prefix; - - $this->output_handler = new null_migrator_output_handler(); - - foreach ($tools as $tool) - { - $this->tools[$tool->get_name()] = $tool; - } - - $this->tools['dbtools'] = $this->db_tools; - - $this->load_migration_state(); - } - - /** - * Set the output handler. - * - * @param migrator_output_handler_interface $handler The output handler - */ - public function set_output_handler(migrator_output_handler_interface $handler) - { - $this->output_handler = $handler; - } - - /** - * Loads all migrations and their application state from the database. - * - * @return null - */ - public function load_migration_state() - { - $this->migration_state = array(); - - // prevent errors in case the table does not exist yet - $this->db->sql_return_on_error(true); - - $sql = "SELECT * - FROM " . $this->migrations_table; - $result = $this->db->sql_query($sql); - - if (!$this->db->get_sql_error_triggered()) - { - while ($migration = $this->db->sql_fetchrow($result)) - { - $this->migration_state[$migration['migration_name']] = $migration; - - $this->migration_state[$migration['migration_name']]['migration_depends_on'] = unserialize($migration['migration_depends_on']); - $this->migration_state[$migration['migration_name']]['migration_data_state'] = !empty($migration['migration_data_state']) ? unserialize($migration['migration_data_state']) : ''; - } - } - - $this->db->sql_freeresult($result); - - $this->db->sql_return_on_error(false); - } - - /** - * Get an array with information about the last migration run. - * - * The array contains 'name', 'class' and 'state'. 'effectively_installed' is set - * and set to true if the last migration was effectively_installed. - * - * @return array - */ - public function get_last_run_migration() - { - return $this->last_run_migration; - } - - /** - * Sets the list of available migration class names to the given array. - * - * @param array $class_names An array of migration class names - * @return null - */ - 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 - * check if update() needs to be called again use the finished() method. - * - * @return null - */ - public function update() - { - $this->container->get('dispatcher')->disable(); - $this->update_do(); - $this->container->get('dispatcher')->enable(); - } - - /** - * Get a valid migration name from the migration state array in case the - * supplied name is not in the migration state list. - * - * @param string $name Migration name - * @return string Migration name - */ - protected function get_valid_name($name) - { - // Try falling back to a valid migration name with or without leading backslash - if (!isset($this->migration_state[$name])) - { - $prepended_name = ($name[0] == '\\' ? '' : '\\') . $name; - $prefixless_name = $name[0] == '\\' ? substr($name, 1) : $name; - - if (isset($this->migration_state[$prepended_name])) - { - $name = $prepended_name; - } - else if (isset($this->migration_state[$prefixless_name])) - { - $name = $prefixless_name; - } - } - - return $name; - } - - /** - * Effectively runs a single update step from the next migration to be applied. - * - * @return null - */ - protected function update_do() - { - foreach ($this->migrations as $name) - { - $name = $this->get_valid_name($name); - - if (!isset($this->migration_state[$name]) || - !$this->migration_state[$name]['migration_schema_done'] || - !$this->migration_state[$name]['migration_data_done']) - { - if (!$this->try_apply($name)) - { - continue; - } - else - { - return; - } - } - else - { - $this->output_handler->write(array('MIGRATION_EFFECTIVELY_INSTALLED', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); - } - } - } - - /** - * Attempts to apply a step of the given migration or one of its dependencies - * - * @param string $name The class name of the migration - * @return bool Whether any update step was successfully run - * @throws \phpbb\db\migration\exception - */ - protected function try_apply($name) - { - if (!class_exists($name)) - { - $this->output_handler->write(array('MIGRATION_NOT_VALID', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); - return false; - } - - $migration = $this->get_migration($name); - - $state = (isset($this->migration_state[$name])) ? - $this->migration_state[$name] : - array( - 'migration_depends_on' => $migration->depends_on(), - 'migration_schema_done' => false, - 'migration_data_done' => false, - 'migration_data_state' => '', - 'migration_start_time' => 0, - 'migration_end_time' => 0, - ); - - if (!empty($state['migration_depends_on'])) - { - $this->output_handler->write(array('MIGRATION_APPLY_DEPENDENCIES', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); - } - - foreach ($state['migration_depends_on'] as $depend) - { - $depend = $this->get_valid_name($depend); - - // Test all possible namings before throwing exception - if ($this->unfulfillable($depend) !== false) - { - throw new \phpbb\db\migration\exception('MIGRATION_NOT_FULFILLABLE', $name, $depend); - } - - if (!isset($this->migration_state[$depend]) || - !$this->migration_state[$depend]['migration_schema_done'] || - !$this->migration_state[$depend]['migration_data_done']) - { - return $this->try_apply($depend); - } - } - - $this->last_run_migration = array( - 'name' => $name, - 'class' => $migration, - 'state' => $state, - 'task' => '', - ); - - if (!isset($this->migration_state[$name])) - { - if ($state['migration_start_time'] == 0 && $migration->effectively_installed()) - { - $state = array( - 'migration_depends_on' => $migration->depends_on(), - 'migration_schema_done' => true, - 'migration_data_done' => true, - 'migration_data_state' => '', - 'migration_start_time' => 0, - 'migration_end_time' => 0, - ); - - $this->last_run_migration['effectively_installed'] = true; - - $this->output_handler->write(array('MIGRATION_EFFECTIVELY_INSTALLED', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); - } - else - { - $state['migration_start_time'] = time(); - } - } - - $this->set_migration_state($name, $state); - - 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_SCHEMA_RUNNING', $name), $verbosity); - - $this->last_run_migration['task'] = 'process_schema_step'; - - $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->update_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); - - if ($state['migration_schema_done']) - { - $this->output_handler->write(array('MIGRATION_SCHEMA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL); - } - else - { - $this->output_handler->write(array('MIGRATION_SCHEMA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE); - } - } - else if (!$state['migration_data_done']) - { - try - { - $verbosity = empty($state['migration_data_state']) ? - migrator_output_handler_interface::VERBOSITY_VERBOSE : migrator_output_handler_interface::VERBOSITY_DEBUG; - $this->output_handler->write(array('MIGRATION_DATA_RUNNING', $name), $verbosity); - - $this->last_run_migration['task'] = 'process_data_step'; - - $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); - - $result = $this->process_data_step($migration->update_data(), $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); - $state['migration_end_time'] = ($result === true) ? time() : 0; - - if ($state['migration_data_done']) - { - $this->output_handler->write(array('MIGRATION_DATA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL); - } - else - { - $this->output_handler->write(array('MIGRATION_DATA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE); - } - } - catch (\phpbb\db\migration\exception $e) - { - // Reset data state and revert the schema changes - $state['migration_data_state'] = ''; - $this->set_migration_state($name, $state); - - $this->revert_do($name); - - throw $e; - } - } - - $this->set_migration_state($name, $state); - - return true; - } - - /** - * Runs a single revert step from the last migration installed - * - * YOU MUST ADD/SET ALL MIGRATIONS THAT COULD BE DEPENDENT ON THE MIGRATION TO REVERT TO BEFORE CALLING THIS METHOD! - * The revert step can either be a schema or a (partial) data revert. To - * check if revert() needs to be called again use the migration_state() method. - * - * @param string $migration String migration name to revert (including any that depend on this migration) - */ - public function revert($migration) - { - $this->container->get('dispatcher')->disable(); - $this->revert_do($migration); - $this->container->get('dispatcher')->enable(); - } - - /** - * Effectively runs a single revert step from the last migration installed - * - * @param string $migration String migration name to revert (including any that depend on this migration) - * @return null - */ - protected function revert_do($migration) - { - if (!isset($this->migration_state[$migration])) - { - // Not installed - return; - } - - foreach ($this->migrations as $name) - { - $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; - } - } - - $this->try_revert($migration); - } - - /** - * Attempts to revert a step of the given migration or one of its dependencies - * - * @param string $name The class name of the migration - * @return bool Whether any update step was successfully run - */ - protected function try_revert($name) - { - if (!class_exists($name)) - { - return false; - } - - $migration = $this->get_migration($name); - - $state = $this->migration_state[$name]; - - $this->last_run_migration = array( - 'name' => $name, - 'class' => $migration, - 'task' => '', - ); - - 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; - - if (!$state['migration_schema_done']) - { - $sql = 'DELETE FROM ' . $this->migrations_table . " - WHERE migration_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - $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); - } - } - - return true; - } - - /** - * Process the data step of the migration - * - * @param array $steps The steps to run - * @param bool|string $state Current state of the migration - * @param bool $revert true to revert a data step - * @return bool|string migration state. True if completed, serialized array if not finished - * @throws \phpbb\db\migration\exception - */ - protected function process_data_step($steps, $state, $revert = false) - { - if (count($steps) === 0) - { - return true; - } - - $state = is_array($state) ? $state : false; - - // reverse order of steps if reverting - if ($revert === true) - { - $steps = array_reverse($steps); - } - - $step = $last_result = 0; - if ($state) - { - $step = $state['step']; - - // We send the result from last time to the callable function - $last_result = $state['result']; - } - - try - { - // 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 < count($steps)) - { - return array( - 'result' => $result, - // Move on if the last call finished - 'step' => ($result !== null && $result !== true) ? $step : $step + 1, - ); - } - } - catch (\phpbb\db\migration\exception $e) - { - // We should try rolling back here - foreach ($steps as $reverse_step_identifier => $reverse_step) - { - // If we've reached the current step we can break because we reversed everything that was run - if ($reverse_step_identifier == $step) - { - break; - } - - // Reverse the step that was run - $result = $this->run_step($reverse_step, false, !$revert); - } - - throw $e; - } - - return true; - } - - /** - * Run a single step - * - * An exception should be thrown if an error occurs - * - * @param mixed $step Data step from migration - * @param mixed $last_result Result to pass to the callable (only for 'custom' method) - * @param bool $reverse False to install, True to attempt uninstallation by reversing the call - * @return null - */ - protected function run_step($step, $last_result = 0, $reverse = false) - { - $callable_and_parameters = $this->get_callable_from_step($step, $last_result, $reverse); - - if ($callable_and_parameters === false) - { - return; - } - - $callable = $callable_and_parameters[0]; - $parameters = $callable_and_parameters[1]; - - return call_user_func_array($callable, $parameters); - } - - /** - * Get a callable statement from a data step - * - * @param array $step Data step from migration - * @param mixed $last_result Result to pass to the callable (only for 'custom' method) - * @param bool $reverse False to install, True to attempt uninstallation by reversing the call - * @return array Array with parameters for call_user_func_array(), 0 is the callable, 1 is parameters - * @throws \phpbb\db\migration\exception - */ - protected function get_callable_from_step(array $step, $last_result = 0, $reverse = false) - { - $type = $step[0]; - $parameters = $step[1]; - - $parts = explode('.', $type); - - $class = $parts[0]; - $method = false; - - if (isset($parts[1])) - { - $method = $parts[1]; - } - - switch ($class) - { - case 'if': - if (!isset($parameters[0])) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_MISSING_CONDITION', $step); - } - - if (!isset($parameters[1])) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_MISSING_STEP', $step); - } - - if ($reverse) - { - // We might get unexpected results when trying - // to revert this, so just avoid it - return false; - } - - $condition = $parameters[0]; - - if (!$condition || (is_array($condition) && !$this->run_step($condition, $last_result, $reverse))) - { - return false; - } - - $step = $parameters[1]; - - return $this->get_callable_from_step($step); - break; - - case 'custom': - if (!is_callable($parameters[0])) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_CUSTOM_NOT_CALLABLE', $step); - } - - if ($reverse) - { - return false; - } - else - { - return array( - $parameters[0], - isset($parameters[1]) ? array_merge($parameters[1], array($last_result)) : array($last_result), - ); - } - break; - - default: - if (!$method) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNKNOWN_TYPE', $step); - } - - if (!isset($this->tools[$class])) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNDEFINED_TOOL', $step); - } - - if (!method_exists(get_class($this->tools[$class]), $method)) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNDEFINED_METHOD', $step); - } - - // Attempt to reverse operations - if ($reverse) - { - array_unshift($parameters, $method); - - return array( - array($this->tools[$class], 'reverse'), - $parameters, - ); - } - - return array( - array($this->tools[$class], $method), - $parameters, - ); - break; - } - } - - /** - * Insert/Update migration row into the database - * - * @param string $name Name of the migration - * @param array $state - * @return null - */ - protected function set_migration_state($name, $state) - { - $migration_row = $state; - $migration_row['migration_depends_on'] = serialize($state['migration_depends_on']); - $migration_row['migration_data_state'] = !empty($state['migration_data_state']) ? serialize($state['migration_data_state']) : ''; - - if (isset($this->migration_state[$name])) - { - $sql = 'UPDATE ' . $this->migrations_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $migration_row) . " - WHERE migration_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - } - else - { - $migration_row['migration_name'] = $name; - $sql = 'INSERT INTO ' . $this->migrations_table . ' - ' . $this->db->sql_build_array('INSERT', $migration_row); - $this->db->sql_query($sql); - } - - $this->migration_state[$name] = $state; - - $this->last_run_migration['state'] = $state; - } - - /** - * Checks if a migration's dependencies can even theoretically be satisfied. - * - * @param string $name The class name of the migration - * @return bool|string False if fulfillable, string of missing migration name if unfulfillable - */ - public function unfulfillable($name) - { - $name = $this->get_valid_name($name); - - if (isset($this->migration_state[$name]) || isset($this->fulfillable_migrations[$name])) - { - return false; - } - - if (!class_exists($name)) - { - return $name; - } - - $migration = $this->get_migration($name); - $depends = $migration->depends_on(); - - foreach ($depends as $depend) - { - $depend = $this->get_valid_name($depend); - $unfulfillable = $this->unfulfillable($depend); - if ($unfulfillable !== false) - { - return $unfulfillable; - } - } - $this->fulfillable_migrations[$name] = true; - - return false; - } - - /** - * Checks whether all available, fulfillable migrations have been applied. - * - * @return bool Whether the migrations have been applied - */ - public function finished() - { - foreach ($this->migrations as $name) - { - if (!isset($this->migration_state[$name])) - { - // skip unfulfillable migrations, but fulfillables mean we - // are not finished yet - if ($this->unfulfillable($name) !== false) - { - continue; - } - - return false; - } - - $migration = $this->migration_state[$name]; - - if (!$migration['migration_schema_done'] || !$migration['migration_data_done']) - { - return false; - } - } - - return true; - } - - /** - * Gets a migration state (whether it is installed and to what extent) - * - * @param string $migration String migration name to check if it is installed - * @return bool|array False if the migration has not at all been installed, array - */ - public function migration_state($migration) - { - if (!isset($this->migration_state[$migration])) - { - return false; - } - - return $this->migration_state[$migration]; - } - - /** - * Helper to get a migration - * - * @param string $name Name of the migration - * @return \phpbb\db\migration\migration - */ - protected function get_migration($name) - { - $migration = new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix); - - if ($migration instanceof ContainerAwareInterface) - { - $migration->setContainer($this->container); - } - - return $migration; - } - - /** - * This function adds all migrations sent to it to the migrations table - * - * THIS SHOULD NOT GENERALLY BE USED! THIS IS FOR THE PHPBB INSTALLER. - * THIS WILL THROW ERRORS IF MIGRATIONS ALREADY EXIST IN THE TABLE, DO NOT CALL MORE THAN ONCE! - * - * @param array $migrations Array of migrations (names) to add to the migrations table - * @return null - */ - public function populate_migrations($migrations) - { - foreach ($migrations as $name) - { - if ($this->migration_state($name) === false) - { - $state = array( - 'migration_depends_on' => $name::depends_on(), - 'migration_schema_done' => true, - 'migration_data_done' => true, - 'migration_data_state' => '', - 'migration_start_time' => time(), - 'migration_end_time' => time(), - ); - $this->set_migration_state($name, $state); - } - } - } - - /** - * Creates the migrations table if it does not exist. - * @return null - */ - public function create_migrations_table() - { - // Make sure migrations have been installed. - if (!$this->db_tools->sql_table_exists($this->table_prefix . 'migrations')) - { - $this->db_tools->sql_create_table($this->table_prefix . 'migrations', array( - 'COLUMNS' => array( - 'migration_name' => array('VCHAR', ''), - 'migration_depends_on' => array('TEXT', ''), - 'migration_schema_done' => array('BOOL', 0), - 'migration_data_done' => array('BOOL', 0), - 'migration_data_state' => array('TEXT', ''), - 'migration_start_time' => array('TIMESTAMP', 0), - 'migration_end_time' => array('TIMESTAMP', 0), - ), - 'PRIMARY_KEY' => 'migration_name', - )); - } - } - - /** - * 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/install/update/new/phpbb/db/tools/mssql.php b/install/update/new/phpbb/db/tools/mssql.php deleted file mode 100644 index 29f816a..0000000 --- a/install/update/new/phpbb/db/tools/mssql.php +++ /dev/null @@ -1,880 +0,0 @@ - - * @license 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 existence 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/install/update/new/phpbb/db/tools/postgres.php b/install/update/new/phpbb/db/tools/postgres.php deleted file mode 100644 index 276ac13..0000000 --- a/install/update/new/phpbb/db/tools/postgres.php +++ /dev/null @@ -1,614 +0,0 @@ - - * @license 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 existence 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/install/update/new/phpbb/db/tools/tools.php b/install/update/new/phpbb/db/tools/tools.php deleted file mode 100644 index 1250a89..0000000 --- a/install/update/new/phpbb/db/tools/tools.php +++ /dev/null @@ -1,1879 +0,0 @@ - -* @license 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)', - ), - - '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 '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 '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 existence 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_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 '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_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_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_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_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_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_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_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_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_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_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_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(); - - $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_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_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_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_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_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/install/update/new/phpbb/di/container_builder.php b/install/update/new/phpbb/di/container_builder.php deleted file mode 100644 index 70ceb9b..0000000 --- a/install/update/new/phpbb/di/container_builder.php +++ /dev/null @@ -1,678 +0,0 @@ - -* @license 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 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\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 The environment to use. - */ - protected $environment; - - /** - * @var string phpBB Root Path - */ - protected $phpbb_root_path; - - /** - * @var string php file extension - */ - protected $php_ext; - - /** - * The container under construction - * - * @var ContainerBuilder - */ - protected $container; - - /** - * @var \phpbb\db\driver\driver_interface - */ - protected $dbal_connection = null; - - /** - * 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 - */ - protected $config_path = null; - - /** - * 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 if the container should be compiled automatically (default to true). - * - * @var bool - */ - protected $compile_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 = []; - - /** - * @var \phpbb\config_php_file - */ - protected $config_php_file; - - /** - * @var string - */ - protected $cache_dir; - - /** - * @var array - */ - private $container_extensions; - - /** @var \Exception */ - private $build_exception; - - /** - * 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->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 - */ - public function get_container() - { - try - { - $container_filename = $this->get_container_filename(); - $config_cache = new ConfigCache($container_filename, defined('DEBUG')); - if ($this->use_cache && $config_cache->isFresh()) - { - 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()); - } - - require($config_cache->getPath()); - $this->container = new \phpbb_cache_container(); - } - else - { - $this->container_extensions = [ - new extension\core($this->get_config_path()), - ]; - - if ($this->use_extensions) - { - $this->load_extensions(); - } - - // Add tables extension after all extensions - $this->container_extensions[] = new extension\tables(); - - // 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')); - - // Event listeners "Symfony style" - $this->container->addCompilerPass(new RegisterListenersPass('dispatcher')); - - if ($this->use_extensions) - { - $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_dbal_driver(); - - return $this->container; - } - catch (\Exception $e) - { - // Don't try to recover if we are in the development environment - if ($this->get_environment() === 'development') - { - throw $e; - } - - 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 - { - // Rethrow the original exception if it's still failing - throw $this->build_exception; - } - } - } - - /** - * Enable the extensions. - * - * @param string $environment The environment to use - * @return $this - */ - public function with_environment($environment) - { - $this->environment = $environment; - - return $this; - } - - /** - * Enable the extensions. - * - * @return $this - */ - public function with_extensions() - { - $this->use_extensions = true; - - return $this; - } - - /** - * Disable the extensions. - * - * @return $this - */ - public function without_extensions() - { - $this->use_extensions = false; - - return $this; - } - - /** - * 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_cache = true; - - return $this; - } - - /** - * Disable the caching of the container. - * - * @return $this - */ - public function without_cache() - { - $this->use_cache = false; - - return $this; - } - - /** - * Set the cache directory. - * - * @param string $cache_dir The cache directory. - * @return $this - */ - public function with_cache_dir($cache_dir) - { - $this->cache_dir = $cache_dir; - - return $this; - } - - /** - * Enable the compilation of the container. - * - * @return $this - */ - public function with_compiled_container() - { - $this->compile_container = true; - - return $this; - } - - /** - * Disable the compilation of the container. - * - * @return $this - */ - public function without_compiled_container() - { - $this->compile_container = false; - - return $this; - } - - /** - * 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 - * @return $this - */ - public function with_custom_parameters($custom_parameters) - { - $this->custom_parameters = $custom_parameters; - - return $this; - } - - /** - * 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) - { - $this->config_php_file = $config_php_file; - - return $this; - } - - /** - * Returns the path to the container configuration (default: root_path/config) - * - * @return string - */ - protected function get_config_path() - { - return $this->config_path ?: $this->phpbb_root_path . 'config'; - } - - /** - * Returns the path to the cache directory (default: root_path/cache/environment). - * - * @return string Path to the cache directory. - */ - protected function get_cache_dir() - { - return $this->cache_dir ?: $this->phpbb_root_path . 'cache/' . $this->get_environment() . '/'; - } - - /** - * Load the enabled extensions. - */ - protected function load_extensions() - { - if ($this->config_php_file !== null) - { - // 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 = ' $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); - - 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; - } - } - - /** - * Dump the container to the disk. - * - * @param ConfigCache $cache The config cache - */ - protected function dump_container($cache) - { - try - { - $dumper = new PhpDumper($this->container); - $proxy_dumper = new ProxyDumper(); - $dumper->setProxyDumper($proxy_dumper); - - $cached_container_dump = $dumper->dump(array( - 'class' => 'phpbb_cache_container', - 'base_class' => 'Symfony\\Component\\DependencyInjection\\Container', - )); - - $cache->write($cached_container_dump, $this->container->getResources()); - } - catch (IOException $e) - { - // Don't fail if the cache isn't writeable - } - } - - /** - * Create the ContainerBuilder object - * - * @param array $extensions Array of Container extension objects - * @return ContainerBuilder object - */ - protected function create_container(array $extensions) - { - $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); - $extensions_alias[] = $extension->getAlias(); - } - - $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions_alias)); - - return $container; - } - - /** - * Inject the customs parameters into the container - */ - protected function inject_custom_parameters() - { - foreach ($this->custom_parameters as $key => $value) - { - $this->container->setParameter($key, $value); - } - } - - /** - * Inject the dbal connection driver into container - */ - protected function inject_dbal_driver() - { - if (empty($this->config_php_file)) - { - 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 - */ - protected function get_container_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() . '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/install/update/new/phpbb/di/extension/container_configuration.php b/install/update/new/phpbb/di/extension/container_configuration.php deleted file mode 100644 index 57e7ef6..0000000 --- a/install/update/new/phpbb/di/extension/container_configuration.php +++ /dev/null @@ -1,63 +0,0 @@ - -* @license 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() - ->booleanNode('allow_install_dir')->defaultValue(false)->end() - ->arrayNode('debug') - ->addDefaultsIfNotSet() - ->children() - ->booleanNode('exceptions')->defaultValue(false)->end() - ->booleanNode('load_time')->defaultValue(false)->end() - ->booleanNode('sql_explain')->defaultValue(false)->end() - ->booleanNode('memory')->defaultValue(false)->end() - ->booleanNode('show_errors')->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() - ->arrayNode('session') - ->addDefaultsIfNotSet() - ->children() - ->booleanNode('log_errors')->defaultValue(false)->end() - ->end() - ->end() - ->end() - ; - return $treeBuilder; - } -} diff --git a/install/update/new/phpbb/di/extension/core.php b/install/update/new/phpbb/di/extension/core.php deleted file mode 100644 index 0497c90..0000000 --- a/install/update/new/phpbb/di/extension/core.php +++ /dev/null @@ -1,132 +0,0 @@ - -* @license 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\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 core extends Extension -{ - const TWIG_OPTIONS_POSITION = 7; - - /** - * Config path - * @var string - */ - protected $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 $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 - ); - } - } - - $container->setParameter('allow_install_dir', $config['allow_install_dir']); - - // 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); - } - - // Set the log options - foreach ($config['session'] as $name => $value) - { - $container->setParameter('session.' . $name, $value); - } - } - - /** - * {@inheritdoc} - */ - public function getConfiguration(array $config, ContainerBuilder $container) - { - $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 - */ - public function getAlias() - { - return 'core'; - } -} diff --git a/install/update/new/phpbb/di/extension/tables.php b/install/update/new/phpbb/di/extension/tables.php deleted file mode 100644 index 40684b6..0000000 --- a/install/update/new/phpbb/di/extension/tables.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @license 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; - -/** - * Container tables extension - */ -class tables extends Extension -{ - /** - * {@inheritDoc} - */ - public function load(array $configs, ContainerBuilder $container) - { - // Tables is a reserved parameter and will be overwritten at all times - $tables = []; - - // Add access via 'tables' parameter to acquire array with all tables - $parameterBag = $container->getParameterBag(); - $parameters = $parameterBag->all(); - foreach ($parameters as $parameter_name => $parameter_value) - { - if (!preg_match('/tables\.(.+)/', $parameter_name, $matches)) - { - continue; - } - - $tables[$matches[1]] = $parameter_value; - } - - $container->setParameter('tables', $tables); - } - - /** - * 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 'tables'; - } -} diff --git a/install/update/new/phpbb/di/service_collection.php b/install/update/new/phpbb/di/service_collection.php deleted file mode 100644 index 6298670..0000000 --- a/install/update/new/phpbb/di/service_collection.php +++ /dev/null @@ -1,122 +0,0 @@ - -* @license 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 to be configured at container compile time. -*/ -class service_collection extends \ArrayObject -{ - /** - * @var \Symfony\Component\DependencyInjection\ContainerInterface - */ - protected $container; - - /** - * @var array - */ - protected $service_classes; - - /** - * Constructor - * - * @param ContainerInterface $container Container object - */ - public function __construct(ContainerInterface $container) - { - $this->container = $container; - $this->service_classes = array(); - } - - /** - * {@inheritdoc} - */ - public function getIterator() - { - return new service_collection_iterator($this); - } - - /** - * {@inheritdoc} - */ - public function offsetGet($index) - { - return $this->container->get($index); - } - - /** - * Add a service to the collection - * - * @param string $name The service name - * @return void - */ - public function add($name) - { - $this->offsetSet($name, false); - } - - /** - * 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; - } - - /** - * Returns the service associated to a class - * - * @return mixed - * @throw \RuntimeException if the - */ - public function get_by_class($class) - { - $service_id = null; - - foreach ($this->service_classes as $id => $service_class) - { - if ($service_class === $class) - { - if ($service_id !== null) - { - throw new \RuntimeException('More than one service definitions found for class "'.$class.'" in collection.'); - } - - $service_id = $id; - } - } - - if ($service_id === null) - { - throw new \RuntimeException('No service found for class "'.$class.'" in collection.'); - } - - return $this->offsetGet($service_id); - } -} diff --git a/install/update/new/phpbb/event/md_exporter.php b/install/update/new/phpbb/event/md_exporter.php deleted file mode 100644 index 1a2d7c9..0000000 --- a/install/update/new/phpbb/event/md_exporter.php +++ /dev/null @@ -1,568 +0,0 @@ - -* @license 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; - -/** -* Crawls through a markdown file and grabs all events -*/ -class md_exporter -{ - /** @var string Path where we look for files*/ - protected $path; - - /** @var string phpBB Root Path */ - protected $root_path; - - /** @var string The minimum version for the events to return */ - protected $min_version; - - /** @var string The maximum version for the events to return */ - protected $max_version; - - /** @var string */ - protected $filter; - - /** @var string */ - protected $current_event; - - /** @var array */ - protected $events; - - /** - * @param string $phpbb_root_path - * @param mixed $extension String 'vendor/ext' to filter, null for phpBB core - * @param string $min_version - * @param string $max_version - */ - public function __construct($phpbb_root_path, $extension = null, $min_version = null, $max_version = null) - { - $this->root_path = $phpbb_root_path; - $this->path = $this->root_path; - if ($extension) - { - $this->path .= 'ext/' . $extension . '/'; - } - - $this->events = array(); - $this->events_by_file = array(); - $this->filter = $this->current_event = ''; - $this->min_version = $min_version; - $this->max_version = $max_version; - } - - /** - * Get the list of all events - * - * @return array Array with events: name => details - */ - public function get_events() - { - return $this->events; - } - - /** - * @param string $md_file Relative from phpBB root - * @return int Number of events found - * @throws \LogicException - */ - public function crawl_phpbb_directory_adm($md_file) - { - $this->crawl_eventsmd($md_file, 'adm'); - - $file_list = $this->get_recursive_file_list($this->path . 'adm/style/'); - foreach ($file_list as $file) - { - $file_name = 'adm/style/' . $file; - $this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name)); - } - - return count($this->events); - } - - /** - * @param string $md_file Relative from phpBB root - * @return int Number of events found - * @throws \LogicException - */ - public function crawl_phpbb_directory_styles($md_file) - { - $this->crawl_eventsmd($md_file, 'styles'); - - $styles = array('prosilver'); - foreach ($styles as $style) - { - $file_list = $this->get_recursive_file_list( - $this->path . 'styles/' . $style . '/template/' - ); - - foreach ($file_list as $file) - { - $file_name = 'styles/' . $style . '/template/' . $file; - $this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name)); - } - } - - return count($this->events); - } - - /** - * @param string $md_file Relative from phpBB root - * @param string $filter Should be 'styles' or 'adm' - * @return int Number of events found - * @throws \LogicException - */ - public function crawl_eventsmd($md_file, $filter) - { - if (!file_exists($this->path . $md_file)) - { - throw new \LogicException("The event docs file '{$md_file}' could not be found"); - } - - $file_content = file_get_contents($this->path . $md_file); - $this->filter = $filter; - - $events = explode("\n\n", $file_content); - foreach ($events as $event) - { - // Last row of the file - if (strpos($event, "\n===\n") === false) - { - continue; - } - - 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])) - { - 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)) - { - continue; - } - - list($file_details, $details) = explode("\n* Since: ", $details, 2); - - $changed_versions = array(); - if (strpos($details, "\n* Changed: ") !== false) - { - list($since, $details) = explode("\n* Changed: ", $details, 2); - while (strpos($details, "\n* Changed: ") !== false) - { - list($changed, $details) = explode("\n* Changed: ", $details, 2); - $changed_versions[] = $changed; - } - list($changed, $description) = explode("\n* Purpose: ", $details, 2); - $changed_versions[] = $changed; - } - else - { - list($since, $description) = explode("\n* Purpose: ", $details, 2); - $changed_versions = array(); - } - - $files = $this->validate_file_list($file_details); - $since = $this->validate_since($since); - $changes = array(); - foreach ($changed_versions as $changed) - { - list($changed_version, $changed_description) = $this->validate_changed($changed); - - if (isset($changes[$changed_version])) - { - throw new \LogicException("Duplicate change information found for event '{$this->current_event}'"); - } - - $changes[$changed_version] = $changed_description; - } - $description = trim($description, "\n") . "\n"; - - if (!$this->version_is_filtered($since)) - { - $is_filtered = false; - foreach ($changes as $version => $null) - { - if ($this->version_is_filtered($version)) - { - $is_filtered = true; - break; - } - } - - if (!$is_filtered) - { - continue; - } - } - - $this->events[$event_name] = array( - 'event' => $this->current_event, - 'files' => $files, - 'since' => $since, - 'changed' => $changes, - 'description' => $description, - ); - } - - return count($this->events); - } - - /** - * The version to check - * - * @param string $version - * @return bool - */ - protected function version_is_filtered($version) - { - return (!$this->min_version || phpbb_version_compare($this->min_version, $version, '<=')) - && (!$this->max_version || phpbb_version_compare($this->max_version, $version, '>=')); - } - - /** - * Format the php events as a wiki table - * - * @param string $action - * @return string Number of events found - */ - public function export_events_for_wiki($action = '') - { - if ($this->filter === 'adm') - { - if ($action === 'diff') - { - $wiki_page = '=== ACP Template Events ===' . "\n"; - } - else - { - $wiki_page = '= ACP Template Events =' . "\n"; - } - $wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n"; - $wiki_page .= '! Identifier !! Placement !! Added in Release !! Explanation' . "\n"; - } - else - { - if ($action === 'diff') - { - $wiki_page = '=== Template Events ===' . "\n"; - } - else - { - $wiki_page = '= Template Events =' . "\n"; - } - $wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n"; - $wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Added in Release !! Explanation' . "\n"; - } - - foreach ($this->events as $event_name => $event) - { - $wiki_page .= "|- id=\"{$event_name}\"\n"; - $wiki_page .= "| [[#{$event_name}|{$event_name}]] || "; - - if ($this->filter === 'adm') - { - $wiki_page .= implode(', ', $event['files']['adm']); - } - else - { - $wiki_page .= implode(', ', $event['files']['prosilver']); - } - - $wiki_page .= " || {$event['since']} || " . str_replace("\n", ' ', $event['description']) . "\n"; - } - $wiki_page .= '|}' . "\n"; - - return $wiki_page; - } - - /** - * Validates a template event name - * - * @param $event_name - * @return null - * @throws \LogicException - */ - public function validate_event_name($event_name) - { - if (!preg_match('#^([a-z][a-z0-9]*(?:_[a-z][a-z0-9]*)+)$#', $event_name)) - { - throw new \LogicException("Invalid event name '{$event_name}'"); - } - } - - /** - * Validate "Since" Information - * - * @param string $since - * @return string - * @throws \LogicException - */ - public function validate_since($since) - { - if (!$this->validate_version($since)) - { - throw new \LogicException("Invalid since information found for event '{$this->current_event}'"); - } - - return $since; - } - - /** - * Validate "Changed" Information - * - * @param string $changed - * @return string - * @throws \LogicException - */ - public function validate_changed($changed) - { - if (strpos($changed, ' ') !== false) - { - list($version, $description) = explode(' ', $changed, 2); - } - else - { - $version = $changed; - $description = ''; - } - - if (!$this->validate_version($version)) - { - throw new \LogicException("Invalid changed information found for event '{$this->current_event}'"); - } - - return array($version, $description); - } - - /** - * Validate "version" Information - * - * @param string $version - * @return bool True if valid, false otherwise - */ - public function validate_version($version) - { - return preg_match('#^\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?$#', $version); - } - - /** - * Validate the files list - * - * @param string $file_details - * @return array - * @throws \LogicException - */ - public function validate_file_list($file_details) - { - $files_list = array( - 'prosilver' => array(), - 'adm' => array(), - ); - - // Multi file list - if (strpos($file_details, "* Locations:\n + ") === 0) - { - $file_details = substr($file_details, strlen("* Locations:\n + ")); - $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}'", 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, '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}'", 3); - } - - $this->events_by_file[$file][] = $this->current_event; - } - } - else if ($this->filter == 'adm') - { - $file = substr($file_details, strlen('* Location: ')); - if (!file_exists($this->path . $file) || substr($file, -5) !== '.html') - { - throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 1); - } - - $files_list['adm'][] = substr($file, strlen('adm/style/')); - - $this->events_by_file[$file][] = $this->current_event; - } - else - { - throw new \LogicException("Invalid file list found for event '{$this->current_event}'", 1); - } - - return $files_list; - } - - /** - * Get all template events in a template file - * - * @param string $file - * @return array - * @throws \LogicException - */ - public function crawl_file_for_events($file) - { - if (!file_exists($this->path . $file)) - { - throw new \LogicException("File '{$file}' does not exist", 1); - } - - $event_list = array(); - $file_content = file_get_contents($this->path . $file); - - preg_match_all('/(?:{%|)/U', $file_content, $event_list); - - return $event_list[1]; - } - - /** - * Validates whether all events from $file are in the md file and vice-versa - * - * @param string $file - * @param array $events - * @return true - * @throws \LogicException - */ - public function validate_events_from_file($file, array $events) - { - if (empty($this->events_by_file[$file]) && empty($events)) - { - return true; - } - else if (empty($this->events_by_file[$file])) - { - $event_list = implode("', '", $events); - throw new \LogicException("File '{$file}' should not contain events, but contains: " - . "'{$event_list}'", 1); - } - else if (empty($events)) - { - $event_list = implode("', '", $this->events_by_file[$file]); - throw new \LogicException("File '{$file}' contains no events, but should contain: " - . "'{$event_list}'", 1); - } - - $missing_events_from_file = array(); - foreach ($this->events_by_file[$file] as $event) - { - if (!in_array($event, $events)) - { - $missing_events_from_file[] = $event; - } - } - - if (!empty($missing_events_from_file)) - { - $event_list = implode("', '", $missing_events_from_file); - throw new \LogicException("File '{$file}' does not contain events: '{$event_list}'", 2); - } - - $missing_events_from_md = array(); - foreach ($events as $event) - { - if (!in_array($event, $this->events_by_file[$file])) - { - $missing_events_from_md[] = $event; - } - } - - if (!empty($missing_events_from_md)) - { - $event_list = implode("', '", $missing_events_from_md); - throw new \LogicException("File '{$file}' contains additional events: '{$event_list}'", 3); - } - - return true; - } - - /** - * Returns a list of files in $dir - * - * Works recursive with any depth - * - * @param string $dir Directory to go through - * @return array List of files (including directories) - */ - public function get_recursive_file_list($dir) - { - try - { - $iterator = new \RecursiveIteratorIterator( - new \phpbb\recursive_dot_prefix_filter_iterator( - new \RecursiveDirectoryIterator( - $dir, - \FilesystemIterator::SKIP_DOTS - ) - ), - \RecursiveIteratorIterator::SELF_FIRST - ); - } - catch (\Exception $e) - { - return array(); - } - - $files = array(); - foreach ($iterator as $file_info) - { - /** @var \RecursiveDirectoryIterator $file_info */ - if ($file_info->isDir()) - { - continue; - } - - $relative_path = $iterator->getInnerIterator()->getSubPathname(); - - if (substr($relative_path, -5) == '.html') - { - $files[] = str_replace(DIRECTORY_SEPARATOR, '/', $relative_path); - } - } - - return $files; - } -} diff --git a/install/update/new/phpbb/extension/extension_interface.php b/install/update/new/phpbb/extension/extension_interface.php deleted file mode 100644 index 46072d4..0000000 --- a/install/update/new/phpbb/extension/extension_interface.php +++ /dev/null @@ -1,71 +0,0 @@ - -* @license 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; - -/** -* The interface extension meta classes have to implement to run custom code -* on enable/disable/purge. -*/ -interface extension_interface -{ - /** - * Indicate whether or not the extension can be enabled. - * - * @return bool|array True if extension is enableable, array of reasons - * if not, false for generic reason. - */ - public function is_enableable(); - - /** - * enable_step is executed on enabling an extension until it returns false. - * - * Calls to this function can be made in subsequent requests, when the - * function is invoked through a webserver with a too low max_execution_time. - * - * @param mixed $old_state The return value of the previous call - * of this method, or false on the first call - * @return mixed Returns false after last step, otherwise - * temporary state which is passed as an - * argument to the next step - */ - public function enable_step($old_state); - - /** - * Disables the extension. - * - * Calls to this function can be made in subsequent requests, when the - * function is invoked through a webserver with a too low max_execution_time. - * - * @param mixed $old_state The return value of the previous call - * of this method, or false on the first call - * @return mixed Returns false after last step, otherwise - * temporary state which is passed as an - * argument to the next step - */ - public function disable_step($old_state); - - /** - * purge_step is executed on purging an extension until it returns false. - * - * Calls to this function can be made in subsequent requests, when the - * function is invoked through a webserver with a too low max_execution_time. - * - * @param mixed $old_state The return value of the previous call - * of this method, or false on the first call - * @return mixed Returns false after last step, otherwise - * temporary state which is passed as an - * argument to the next step - */ - public function purge_step($old_state); -} diff --git a/install/update/new/phpbb/extension/manager.php b/install/update/new/phpbb/extension/manager.php deleted file mode 100644 index 1ce8425..0000000 --- a/install/update/new/phpbb/extension/manager.php +++ /dev/null @@ -1,591 +0,0 @@ - -* @license 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; - -use phpbb\exception\runtime_exception; -use phpbb\file_downloader; -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** -* The extension manager provides means to activate/deactivate extensions. -*/ -class manager -{ - /** @var ContainerInterface */ - protected $container; - - protected $db; - protected $config; - protected $cache; - protected $php_ext; - protected $extensions; - protected $extension_table; - protected $phpbb_root_path; - protected $cache_name; - - /** - * Creates a manager and loads information from database - * - * @param 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_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\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_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; - $this->config = $config; - $this->container = $container; - $this->db = $db; - $this->extension_table = $extension_table; - $this->filesystem = $filesystem; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false; - - if ($this->extensions === false) - { - $this->load_extensions(); - } - } - - /** - * Loads all extension information from the database - * - * @return null - */ - public function load_extensions() - { - $this->extensions = array(); - - // Do not try to load any extensions if the extension table - // does not exist or when installing or updating. - // Note: database updater invokes this code, and in 3.0 - // there is no extension table therefore the rest of this function - // fails - if (defined('IN_INSTALL') || version_compare($this->config['version'], '3.1.0-dev', '<')) - { - return; - } - - $sql = 'SELECT * - FROM ' . $this->extension_table; - - $result = $this->db->sql_query($sql); - $extensions = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - foreach ($extensions as $extension) - { - $extension['ext_path'] = $this->get_extension_path($extension['ext_name']); - $this->extensions[$extension['ext_name']] = $extension; - } - - ksort($this->extensions); - - if ($this->cache) - { - $this->cache->put($this->cache_name, $this->extensions); - } - } - - /** - * Generates the path to an extension - * - * @param string $name The name of the extension - * @param bool $phpbb_relative Whether the path should be relative to phpbb root - * @return string Path to an extension - */ - public function get_extension_path($name, $phpbb_relative = false) - { - $name = str_replace('.', '', $name); - - return (($phpbb_relative) ? $this->phpbb_root_path : '') . 'ext/' . $name . '/'; - } - - /** - * Instantiates the extension meta class for the extension with the given name - * - * @param string $name The extension name - * @return \phpbb\extension\extension_interface Instance of the extension meta class or - * \phpbb\extension\base if the class does not exist - */ - public function get_extension($name) - { - $extension_class_name = str_replace('/', '\\', $name) . '\\ext'; - - $migrator = $this->container->get('migrator'); - - if (class_exists($extension_class_name)) - { - return new $extension_class_name($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true)); - } - else - { - return new \phpbb\extension\base($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true)); - } - } - - /** - * Instantiates the metadata manager for the extension with the given name - * - * @param string $name The extension name - * @return \phpbb\extension\metadata_manager Instance of the metadata manager - */ - public function create_extension_metadata_manager($name) - { - 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']; - } - - /** - * Update the database entry for an extension - * - * @param string $name Extension name to update - * @param array $data Data to update in the database - * @param string $action Action to perform, by default 'update', may be also 'insert' or 'delete' - */ - protected function update_state($name, $data, $action = 'update') - { - switch ($action) - { - case 'insert': - $this->extensions[$name] = $data; - $this->extensions[$name]['ext_path'] = $this->get_extension_path($name); - ksort($this->extensions); - $sql = 'INSERT INTO ' . $this->extension_table . ' ' . $this->db->sql_build_array('INSERT', $data); - $this->db->sql_query($sql); - break; - - case 'update': - $this->extensions[$name] = array_merge($this->extensions[$name], $data); - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - break; - - case 'delete': - unset($this->extensions[$name]); - $sql = 'DELETE FROM ' . $this->extension_table . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - break; - } - - if ($this->cache) - { - $this->cache->purge(); - } - } - - /** - * Runs a step of the extension enabling process. - * - * Allows the exentension to enable in a long running script that works - * in multiple steps across requests. State is kept for the extension - * in the extensions table. - * - * @param string $name The extension's name - * @return bool False if enabling is finished, true otherwise - */ - public function enable_step($name) - { - // ignore extensions that are already enabled - if ($this->is_enabled($name)) - { - return false; - } - - $old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false; - - $extension = $this->get_extension($name); - - if (!$extension->is_enableable()) - { - return false; - } - - $state = $extension->enable_step($old_state); - - $active = ($state === false); - - $extension_data = array( - 'ext_name' => $name, - 'ext_active' => $active, - 'ext_state' => serialize($state), - ); - - $this->update_state($name, $extension_data, $this->is_configured($name) ? 'update' : 'insert'); - - if ($active) - { - $this->config->increment('assets_version', 1); - } - - return !$active; - } - - /** - * Enables an extension - * - * This method completely enables an extension. But it could be long running - * so never call this in a script that has a max_execution time. - * - * @param string $name The extension's name - * @return null - */ - public function enable($name) - { - // @codingStandardsIgnoreStart - while ($this->enable_step($name)); - // @codingStandardsIgnoreEnd - } - - /** - * Disables an extension - * - * Calls the disable method on the extension's meta class to allow it to - * process the event. - * - * @param string $name The extension's name - * @return bool False if disabling is finished, true otherwise - */ - public function disable_step($name) - { - // ignore extensions that are not enabled - if (!$this->is_enabled($name)) - { - return false; - } - - $old_state = unserialize($this->extensions[$name]['ext_state']); - - $extension = $this->get_extension($name); - $state = $extension->disable_step($old_state); - $active = ($state !== false); - - $extension_data = array( - 'ext_active' => $active, - 'ext_state' => serialize($state), - ); - $this->update_state($name, $extension_data); - - return $active; - } - - /** - * Disables an extension - * - * Disables an extension completely at once. This process could run for a - * while so never call this in a script that has a max_execution time. - * - * @param string $name The extension's name - * @return null - */ - public function disable($name) - { - // @codingStandardsIgnoreStart - while ($this->disable_step($name)); - // @codingStandardsIgnoreEnd - } - - /** - * Purge an extension - * - * Disables the extension first if active, and then calls purge on the - * extension's meta class to delete the extension's database content. - * - * @param string $name The extension's name - * @return bool False if purging is finished, true otherwise - */ - public function purge_step($name) - { - // ignore extensions that are not configured - if (!$this->is_configured($name)) - { - return false; - } - - // disable first if necessary - if ($this->extensions[$name]['ext_active']) - { - $this->disable($name); - } - - $old_state = unserialize($this->extensions[$name]['ext_state']); - - $extension = $this->get_extension($name); - $state = $extension->purge_step($old_state); - $purged = ($state === false); - - $extension_data = array( - 'ext_state' => serialize($state), - ); - - $this->update_state($name, $extension_data, $purged ? 'delete' : 'update'); - - // continue until the state is false - return !$purged; - } - - /** - * Purge an extension - * - * Purges an extension completely at once. This process could run for a while - * so never call this in a script that has a max_execution time. - * - * @param string $name The extension's name - * @return null - */ - public function purge($name) - { - // @codingStandardsIgnoreStart - while ($this->purge_step($name)); - // @codingStandardsIgnoreEnd - } - - /** - * Retrieves a list of all available extensions on the filesystem - * - * @return array An array with extension names as keys and paths to the - * extension as values - */ - public function all_available() - { - $available = array(); - if (!is_dir($this->phpbb_root_path . 'ext/')) - { - return $available; - } - - $iterator = new \RecursiveIteratorIterator( - new \phpbb\recursive_dot_prefix_filter_iterator( - new \RecursiveDirectoryIterator($this->phpbb_root_path . 'ext/', \FilesystemIterator::NEW_CURRENT_AND_KEY | \FilesystemIterator::FOLLOW_SYMLINKS) - ), - \RecursiveIteratorIterator::SELF_FIRST - ); - $iterator->setMaxDepth(2); - - foreach ($iterator as $file_info) - { - if ($file_info->isFile() && $file_info->getFilename() == 'composer.json') - { - $ext_name = $iterator->getInnerIterator()->getSubPath(); - $ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name); - if ($this->is_available($ext_name)) - { - $available[$ext_name] = $this->get_extension_path($ext_name, true); - } - } - } - ksort($available); - return $available; - } - - /** - * Retrieves all configured extensions. - * - * All enabled and disabled extensions are considered configured. A purged - * extension that is no longer in the database is not configured. - * - * @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($phpbb_relative = true) - { - $configured = array(); - foreach ($this->extensions as $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($phpbb_relative = true) - { - $enabled = array(); - foreach ($this->extensions as $name => $data) - { - if ($this->is_enabled($name)) - { - $enabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path']; - } - } - return $enabled; - } - - /** - * 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($phpbb_relative = true) - { - $disabled = array(); - foreach ($this->extensions as $name => $data) - { - if ($this->is_disabled($name)) - { - $disabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path']; - } - } - return $disabled; - } - - /** - * Check to see if a given extension is available on the filesystem - * - * @param string $name Extension name to check NOTE: Can be user input - * @return bool Depending on whether or not the extension is available - */ - public function is_available($name) - { - $md_manager = $this->create_extension_metadata_manager($name); - try - { - return $md_manager->get_metadata('all') && $md_manager->validate_enable(); - } - catch (\phpbb\extension\exception $e) - { - return false; - } - } - - /** - * Check to see if a given extension is enabled - * - * @param string $name Extension name to check - * @return bool Depending on whether or not the extension is enabled - */ - public function is_enabled($name) - { - return isset($this->extensions[$name]['ext_active']) && $this->extensions[$name]['ext_active']; - } - - /** - * Check to see if a given extension is disabled - * - * @param string $name Extension name to check - * @return bool Depending on whether or not the extension is disabled - */ - public function is_disabled($name) - { - return isset($this->extensions[$name]['ext_active']) && !$this->extensions[$name]['ext_active']; - } - - /** - * Check to see if a given extension is configured - * - * All enabled and disabled extensions are considered configured. A purged - * extension that is no longer in the database is not configured. - * - * @param string $name Extension name to check - * @return bool Depending on whether or not the extension is configured - */ - public function is_configured($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); - } - - /** - * Check to see if a given extension is purged - * - * An extension is purged if it is available, not enabled and not disabled. - * - * @param string $name Extension name to check - * @return bool Depending on whether or not the extension is purged - */ - public function is_purged($name) - { - return $this->is_available($name) && !$this->is_configured($name); - } - - /** - * Instantiates a \phpbb\finder. - * - * @param bool $use_all_available Should we load all extensions, or just enabled ones - * @return \phpbb\finder An extension finder instance - */ - public function get_finder($use_all_available = false) - { - $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder'); - if ($use_all_available) - { - $finder->set_extensions(array_keys($this->all_available())); - } - else - { - $finder->set_extensions(array_keys($this->all_enabled())); - } - return $finder; - } -} diff --git a/install/update/new/phpbb/feed/controller/feed.php b/install/update/new/phpbb/feed/controller/feed.php deleted file mode 100644 index 7826d19..0000000 --- a/install/update/new/phpbb/feed/controller/feed.php +++ /dev/null @@ -1,410 +0,0 @@ - -* @license 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 feed_interface feed Feed instance - * @var array row Array with feed data - * - * @since 3.1.10-RC1 - * @changed 3.3.0 Replace forum_id, mode, topic_id with feed instance - */ - $vars = array('feed', 'row'); - 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/install/update/new/phpbb/feed/topics_active.php b/install/update/new/phpbb/feed/topics_active.php deleted file mode 100644 index ee7fe17..0000000 --- a/install/update/new/phpbb/feed/topics_active.php +++ /dev/null @@ -1,147 +0,0 @@ - - * @license 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 within the last {$this->sort_days} days - * including the last post. - */ -class topics_active extends topic_base -{ - protected $sort_days = 7; - - /** - * {@inheritdoc} - */ - public function set_keys() - { - parent::set_keys(); - - $this->set('author_id', 'topic_last_poster_id'); - $this->set('creator', 'topic_last_poster_name'); - } - - /** - * {@inheritdoc} - */ - protected function get_sql() - { - $forum_ids_read = $this->get_readable_forums(); - if (empty($forum_ids_read)) - { - return false; - } - - $in_fid_ary = array_intersect($forum_ids_read, $this->get_forum_ids()); - $in_fid_ary = array_diff($in_fid_ary, $this->get_passworded_forums()); - if (empty($in_fid_ary)) - { - return false; - } - - // Search for topics in last X days - $last_post_time_sql = ($this->sort_days) ? ' AND topic_last_post_time > ' . (time() - ($this->sort_days * 24 * 3600)) : ''; - - // We really have to get the post ids first! - $sql = 'SELECT topic_last_post_id, topic_last_post_time - FROM ' . TOPICS_TABLE . ' - WHERE topic_moved_id = 0 - AND ' . $this->content_visibility->get_forums_visibility_sql('topic', $in_fid_ary) . ' - ' . $last_post_time_sql . ' - ORDER BY topic_last_post_time DESC, topic_last_post_id DESC'; - $result = $this->db->sql_query_limit($sql, $this->num_items); - - $post_ids = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $post_ids[] = (int) $row['topic_last_post_id']; - } - $this->db->sql_freeresult($result); - - if (empty($post_ids)) - { - return false; - } - - parent::fetch_attachments($post_ids); - - $this->sql = array( - 'SELECT' => 'f.forum_id, f.forum_name, - t.topic_id, t.topic_title, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_views, - t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_post_time, - p.post_id, p.post_time, p.post_edit_time, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, t.topic_visibility', - 'FROM' => array( - TOPICS_TABLE => 't', - POSTS_TABLE => 'p', - ), - 'LEFT_JOIN' => array( - array( - 'FROM' => array(FORUMS_TABLE => 'f'), - 'ON' => 'p.forum_id = f.forum_id', - ), - ), - 'WHERE' => 'p.topic_id = t.topic_id - AND ' . $this->db->sql_in_set('p.post_id', $post_ids), - 'ORDER_BY' => 'p.post_time DESC, p.post_id DESC', - ); - - return true; - } - - /** - * Returns the ids of the forums not excluded from the active list - * - * @return int[] - */ - private function get_forum_ids() - { - static $forum_ids; - - $cache_name = 'feed_topic_active_forum_ids'; - - if (!isset($forum_ids) && ($forum_ids = $this->cache->get('_' . $cache_name)) === false) - { - $sql = 'SELECT forum_id - 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', round(log(FORUM_FLAG_ACTIVE_TOPICS, 2)), '<> 0'); - $result = $this->db->sql_query($sql); - - $forum_ids = array(); - while ($forum_id = (int) $this->db->sql_fetchfield('forum_id')) - { - $forum_ids[$forum_id] = $forum_id; - } - $this->db->sql_freeresult($result); - - $this->cache->put('_' . $cache_name, $forum_ids, 180); - } - - return $forum_ids; - } - - /** - * {@inheritdoc} - */ - public function adjust_item(&$item_row, &$row) - { - parent::adjust_item($item_row, $row); - - $item_row['title'] = (isset($row['forum_name']) && $row['forum_name'] !== '') ? $row['forum_name'] . ' ' . $this->separator . ' ' . $item_row['title'] : $item_row['title']; - } -} diff --git a/install/update/new/phpbb/files/filespec.php b/install/update/new/phpbb/files/filespec.php deleted file mode 100644 index 1e6771a..0000000 --- a/install/update/new/phpbb/files/filespec.php +++ /dev/null @@ -1,584 +0,0 @@ - - * @license 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')) ? '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/install/update/new/phpbb/filesystem.php b/install/update/new/phpbb/filesystem.php deleted file mode 100644 index 6ac9459..0000000 --- a/install/update/new/phpbb/filesystem.php +++ /dev/null @@ -1,21 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** - * @deprecated 3.2.0-dev (To be removed 4.0.0) use \phpbb\filesystem\filesystem instead - */ -class filesystem extends \phpbb\filesystem\filesystem -{ -} diff --git a/install/update/new/phpbb/filesystem/filesystem.php b/install/update/new/phpbb/filesystem/filesystem.php deleted file mode 100644 index 9acead0..0000000 --- a/install/update/new/phpbb/filesystem/filesystem.php +++ /dev/null @@ -1,916 +0,0 @@ - - * @license 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('FILESYSTEM_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('FILESYSTEM_CANNOT_CHANGE_FILE_PERMISSIONS', $file, array()); - } - } - else if (is_file($file)) - { - if (true !== @chmod($file, $file_perm)) - { - throw new filesystem_exception('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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('FILESYSTEM_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/install/update/new/phpbb/filesystem/filesystem_interface.php b/install/update/new/phpbb/filesystem/filesystem_interface.php deleted file mode 100644 index 39ae0c3..0000000 --- a/install/update/new/phpbb/filesystem/filesystem_interface.php +++ /dev/null @@ -1,284 +0,0 @@ - - * @license 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 appropriate 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/install/update/new/phpbb/finder.php b/install/update/new/phpbb/finder.php deleted file mode 100644 index 0a2b67a..0000000 --- a/install/update/new/phpbb/finder.php +++ /dev/null @@ -1,547 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* The finder provides a simple way to locate files in the core and a set of extensions -*/ -class finder -{ - protected $extensions; - protected $filesystem; - protected $phpbb_root_path; - protected $cache; - protected $php_ext; - - /** - * The cache variable name used to store $this->cached_queries in $this->cache. - * - * Allows the use of multiple differently configured finders with the same cache. - * @var string - */ - protected $cache_name; - - /** - * An associative array, containing all search parameters set in methods. - * @var array - */ - protected $query; - - /** - * A map from md5 hashes of serialized queries to their previously retrieved - * results. - * @var array - */ - protected $cached_queries; - - /** - * Creates a new finder instance with its dependencies - * - * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem instance - * @param string $phpbb_root_path Path to the phpbb root directory - * @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_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; - $this->cache = $cache; - $this->php_ext = $php_ext; - $this->cache_name = $cache_name; - - $this->query = array( - 'core_path' => false, - 'core_suffix' => false, - 'core_prefix' => false, - 'core_directory' => false, - 'extension_suffix' => false, - 'extension_prefix' => false, - 'extension_directory' => false, - ); - $this->extensions = array(); - - $this->cached_queries = ($this->cache) ? $this->cache->get($this->cache_name) : false; - } - - /** - * Set the array of extensions - * - * @param array $extensions A list of extensions that should be searched as well - * @param bool $replace_list Should the list be emptied before adding the extensions - * @return \phpbb\finder This object for chaining calls - */ - public function set_extensions(array $extensions, $replace_list = true) - { - if ($replace_list) - { - $this->extensions = array(); - } - - foreach ($extensions as $ext_name) - { - $this->extensions[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; - } - return $this; - } - - /** - * Sets a core path to be searched in addition to extensions - * - * @param string $core_path The path relative to phpbb_root_path - * @return \phpbb\finder This object for chaining calls - */ - public function core_path($core_path) - { - $this->query['core_path'] = $core_path; - return $this; - } - - /** - * Sets the suffix all files found in extensions and core must match. - * - * There is no default file extension, so to find PHP files only, you will - * have to specify .php as a suffix. However when using get_classes, the .php - * file extension is automatically added to suffixes. - * - * @param string $suffix A filename suffix - * @return \phpbb\finder This object for chaining calls - */ - public function suffix($suffix) - { - $this->core_suffix($suffix); - $this->extension_suffix($suffix); - return $this; - } - - /** - * Sets a suffix all files found in extensions must match - * - * There is no default file extension, so to find PHP files only, you will - * have to specify .php as a suffix. However when using get_classes, the .php - * file extension is automatically added to suffixes. - * - * @param string $extension_suffix A filename suffix - * @return \phpbb\finder This object for chaining calls - */ - public function extension_suffix($extension_suffix) - { - $this->query['extension_suffix'] = $extension_suffix; - return $this; - } - - /** - * Sets a suffix all files found in the core path must match - * - * There is no default file extension, so to find PHP files only, you will - * have to specify .php as a suffix. However when using get_classes, the .php - * file extension is automatically added to suffixes. - * - * @param string $core_suffix A filename suffix - * @return \phpbb\finder This object for chaining calls - */ - public function core_suffix($core_suffix) - { - $this->query['core_suffix'] = $core_suffix; - return $this; - } - - /** - * Sets the prefix all files found in extensions and core must match - * - * @param string $prefix A filename prefix - * @return \phpbb\finder This object for chaining calls - */ - public function prefix($prefix) - { - $this->core_prefix($prefix); - $this->extension_prefix($prefix); - return $this; - } - - /** - * Sets a prefix all files found in extensions must match - * - * @param string $extension_prefix A filename prefix - * @return \phpbb\finder This object for chaining calls - */ - public function extension_prefix($extension_prefix) - { - $this->query['extension_prefix'] = $extension_prefix; - return $this; - } - - /** - * Sets a prefix all files found in the core path must match - * - * @param string $core_prefix A filename prefix - * @return \phpbb\finder This object for chaining calls - */ - public function core_prefix($core_prefix) - { - $this->query['core_prefix'] = $core_prefix; - return $this; - } - - /** - * Sets a directory all files found in extensions and core must be contained in - * - * Automatically sets the core_directory if its value does not differ from - * the current directory. - * - * @param string $directory - * @return \phpbb\finder This object for chaining calls - */ - public function directory($directory) - { - $this->core_directory($directory); - $this->extension_directory($directory); - return $this; - } - - /** - * Sets a directory all files found in extensions must be contained in - * - * @param string $extension_directory - * @return \phpbb\finder This object for chaining calls - */ - public function extension_directory($extension_directory) - { - $this->query['extension_directory'] = $this->sanitise_directory($extension_directory); - return $this; - } - - /** - * Sets a directory all files found in the core path must be contained in - * - * @param string $core_directory - * @return \phpbb\finder This object for chaining calls - */ - public function core_directory($core_directory) - { - $this->query['core_directory'] = $this->sanitise_directory($core_directory); - return $this; - } - - /** - * Removes occurrences of /./ and makes sure path ends without trailing slash - * - * @param string $directory A directory pattern - * @return string A cleaned up directory pattern - */ - protected function sanitise_directory($directory) - { - $directory = $this->filesystem->clean_path($directory); - $dir_len = strlen($directory); - - if ($dir_len > 1 && $directory[$dir_len - 1] === '/') - { - $directory = substr($directory, 0, -1); - } - - return $directory; - } - - /** - * Finds classes matching the configured options if they follow phpBB naming rules. - * - * The php file extension is automatically added to suffixes. - * - * Note: If a file is matched but contains a class name not following the - * phpBB naming rules an incorrect class name will be returned. - * - * @param bool $cache Whether the result should be cached - * @return array An array of found class names - */ - public function get_classes($cache = true) - { - $this->query['extension_suffix'] .= '.' . $this->php_ext; - $this->query['core_suffix'] .= '.' . $this->php_ext; - - $files = $this->find($cache, false); - - return $this->get_classes_from_files($files); - } - - /** - * Get class names from a list of files - * - * @param array $files Array of files (from find()) - * @return array Array of class names - */ - public function get_classes_from_files($files) - { - $classes = array(); - foreach ($files as $file => $ext_name) - { - $class = substr($file, 0, -strlen('.' . $this->php_ext)); - if ($ext_name === '/' && preg_match('#^includes/#', $file)) - { - $class = preg_replace('#^includes/#', '', $class); - $classes[] = 'phpbb_' . str_replace('/', '_', $class); - } - else - { - $class = preg_replace('#^ext/#', '', $class); - $classes[] = '\\' . str_replace('/', '\\', $class); - } - } - return $classes; - } - - /** - * Finds all directories matching the configured options - * - * @param bool $cache Whether the result should be cached - * @param bool $extension_keys Whether the result should have extension name as array key - * @return array An array of paths to found directories - */ - public function get_directories($cache = true, $extension_keys = false) - { - return $this->find_with_root_path($cache, true, $extension_keys); - } - - /** - * Finds all files matching the configured options. - * - * @param bool $cache Whether the result should be cached - * @return array An array of paths to found files - */ - public function get_files($cache = true) - { - return $this->find_with_root_path($cache, false); - } - - /** - * A wrapper around the general find which prepends a root path to results - * - * @param bool $cache Whether the result should be cached - * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @param bool $extension_keys If true, result will be associative array - * with extension name as key - * @return array An array of paths to found items - */ - protected function find_with_root_path($cache = true, $is_dir = false, $extension_keys = false) - { - $items = $this->find($cache, $is_dir); - - $result = array(); - foreach ($items as $item => $ext_name) - { - if ($extension_keys) - { - $result[$ext_name] = $this->phpbb_root_path . $item; - } - else - { - $result[] = $this->phpbb_root_path . $item; - } - } - - return $result; - } - - /** - * Finds all file system entries matching the configured options - * - * @param bool $cache Whether the result should be cached - * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @return array An array of paths to found items - */ - public function find($cache = true, $is_dir = false) - { - $extensions = $this->extensions; - if ($this->query['core_path']) - { - $extensions['/'] = $this->phpbb_root_path . $this->query['core_path']; - } - - $files = array(); - $file_list = $this->find_from_paths($extensions, $cache, $is_dir); - - foreach ($file_list as $file) - { - $files[$file['named_path']] = $file['ext_name']; - } - - return $files; - } - - /** - * Finds all file system entries matching the configured options for one - * specific extension - * - * @param string $extension_name Name of the extension - * @param string $extension_path Relative path to the extension root directory - * @param bool $cache Whether the result should be cached - * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @return array An array of paths to found items - */ - public function find_from_extension($extension_name, $extension_path, $cache = true, $is_dir = false) - { - $extensions = array( - $extension_name => $extension_path, - ); - - $files = array(); - $file_list = $this->find_from_paths($extensions, $cache, $is_dir); - - foreach ($file_list as $file) - { - $files[$file['named_path']] = $file['ext_name']; - } - - return $files; - } - - /** - * Finds all file system entries matching the configured options from - * an array of paths - * - * @param array $extensions Array of extensions (name => full relative path) - * @param bool $cache Whether the result should be cached - * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @return array An array of paths to found items - */ - public function find_from_paths($extensions, $cache = true, $is_dir = false) - { - $this->query['is_dir'] = $is_dir; - $query = md5(serialize($this->query) . serialize($extensions)); - - if (!defined('DEBUG') && $cache && isset($this->cached_queries[$query])) - { - return $this->cached_queries[$query]; - } - - $files = array(); - - foreach ($extensions as $name => $path) - { - $ext_name = $name; - - if (!file_exists($path)) - { - continue; - } - - if ($name === '/') - { - $location = $this->query['core_path']; - $name = ''; - $suffix = $this->query['core_suffix']; - $prefix = $this->query['core_prefix']; - $directory = $this->query['core_directory']; - } - else - { - $location = 'ext/'; - $name .= '/'; - $suffix = $this->query['extension_suffix']; - $prefix = $this->query['extension_prefix']; - $directory = $this->query['extension_directory']; - } - - // match only first directory if leading slash is given - if ($directory === '/') - { - $directory_pattern = '^' . preg_quote(DIRECTORY_SEPARATOR, '#'); - } - else if ($directory && $directory[0] === '/') - { - if (!$is_dir) - { - $path .= substr($directory, 1); - } - $directory_pattern = '^' . preg_quote(str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#'); - } - else - { - $directory_pattern = preg_quote(DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#'); - } - if ($is_dir) - { - $directory_pattern .= '$'; - } - $directory_pattern = '#' . $directory_pattern . '#'; - - if (is_dir($path)) - { - $iterator = new \RecursiveIteratorIterator( - new \phpbb\recursive_dot_prefix_filter_iterator( - new \RecursiveDirectoryIterator( - $path, - \FilesystemIterator::SKIP_DOTS - ) - ), - \RecursiveIteratorIterator::SELF_FIRST - ); - - foreach ($iterator as $file_info) - { - $filename = $file_info->getFilename(); - - if ($file_info->isDir() == $is_dir) - { - if ($is_dir) - { - $relative_path = $iterator->getInnerIterator()->getSubPath() . DIRECTORY_SEPARATOR . basename($filename) . DIRECTORY_SEPARATOR; - if ($relative_path[0] !== DIRECTORY_SEPARATOR) - { - $relative_path = DIRECTORY_SEPARATOR . $relative_path; - } - } - else - { - $relative_path = $iterator->getInnerIterator()->getSubPathname(); - if ($directory && $directory[0] === '/') - { - $relative_path = str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR . $relative_path; - } - else - { - $relative_path = DIRECTORY_SEPARATOR . $relative_path; - } - } - - if ((!$suffix || substr($relative_path, -strlen($suffix)) === $suffix) && - (!$prefix || substr($filename, 0, strlen($prefix)) === $prefix) && - (!$directory || preg_match($directory_pattern, $relative_path))) - { - $files[] = array( - 'named_path' => str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1)), - 'ext_name' => $ext_name, - 'path' => str_replace(array(DIRECTORY_SEPARATOR, $this->phpbb_root_path), array('/', ''), $file_info->getPath()) . '/', - 'filename' => $filename, - ); - } - } - } - } - } - - if ($cache && $this->cache) - { - $this->cached_queries[$query] = $files; - $this->cache->put($this->cache_name, $this->cached_queries); - } - - return $files; - } -} diff --git a/install/update/new/phpbb/group/helper.php b/install/update/new/phpbb/group/helper.php deleted file mode 100644 index aa3876b..0000000 --- a/install/update/new/phpbb/group/helper.php +++ /dev/null @@ -1,294 +0,0 @@ - - * @license 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&g={GROUP_ID}", - 'tpl_noprofile' => '{GROUP_NAME}', - 'tpl_noprofile_colour' => '{GROUP_NAME}', - 'tpl_profile' => '{GROUP_NAME}', - 'tpl_profile_colour' => '{GROUP_NAME}', - ); - } - - /** - * @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 &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 . '&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'])) ? '' . $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/install/update/new/phpbb/help/controller/bbcode.php b/install/update/new/phpbb/help/controller/bbcode.php deleted file mode 100644 index 560b0c0..0000000 --- a/install/update/new/phpbb/help/controller/bbcode.php +++ /dev/null @@ -1,90 +0,0 @@ - - * @license 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->template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $this->language->lang('BBCODE_GUIDE'), - 'U_BREADCRUMB' => $this->helper->route('phpbb_help_bbcode_controller'), - )); - - $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/install/update/new/phpbb/help/controller/faq.php b/install/update/new/phpbb/help/controller/faq.php deleted file mode 100644 index 0f63be5..0000000 --- a/install/update/new/phpbb/help/controller/faq.php +++ /dev/null @@ -1,170 +0,0 @@ - - * @license 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->template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $this->language->lang('FAQ_EXPLAIN'), - 'U_BREADCRUMB' => $this->helper->route('phpbb_help_faq_controller'), - )); - - $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/install/update/new/phpbb/install/controller/helper.php b/install/update/new/phpbb/install/controller/helper.php deleted file mode 100644 index f61c7de..0000000 --- a/install/update/new/phpbb/install/controller/helper.php +++ /dev/null @@ -1,413 +0,0 @@ - - * @license 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-3.4.1.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/install/update/new/phpbb/install/helper/container_factory.php b/install/update/new/phpbb/install/helper/container_factory.php deleted file mode 100644 index 6557602..0000000 --- a/install/update/new/phpbb/install/helper/container_factory.php +++ /dev/null @@ -1,191 +0,0 @@ - - * @license 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 compatibility 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/install/update/new/phpbb/install/helper/database.php b/install/update/new/phpbb/install/helper/database.php deleted file mode 100644 index 51fd18f..0000000 --- a/install/update/new/phpbb/install/helper/database.php +++ /dev/null @@ -1,421 +0,0 @@ - - * @license 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, - ), - '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_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 '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/install/update/new/phpbb/install/helper/iohandler/iohandler_interface.php b/install/update/new/phpbb/install/helper/iohandler/iohandler_interface.php deleted file mode 100644 index 3df9a91..0000000 --- a/install/update/new/phpbb/install/helper/iohandler/iohandler_interface.php +++ /dev/null @@ -1,222 +0,0 @@ - - * @license 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 parameter 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/install/update/new/phpbb/install/installer_configuration.php b/install/update/new/phpbb/install/installer_configuration.php deleted file mode 100644 index dfafc40..0000000 --- a/install/update/new/phpbb/install/installer_configuration.php +++ /dev/null @@ -1,146 +0,0 @@ - -* @license 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) - ->end() - ->scalarNode('script_path') - ->defaultValue('/') - ->cannotBeEmpty() - ->end() - ->end() - ->end() - ->arrayNode('extensions') - ->prototype('scalar')->end() - ->defaultValue([]) - ->end() - ->end() - ; - return $treeBuilder; - } -} diff --git a/install/update/new/phpbb/install/module/install_database/task/add_config_settings.php b/install/update/new/phpbb/install/module/install_database/task/add_config_settings.php deleted file mode 100644 index 91d7884..0000000 --- a/install/update/new/phpbb/install/module/install_database/task/add_config_settings.php +++ /dev/null @@ -1,367 +0,0 @@ - - * @license 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')) . "', - 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/install/update/new/phpbb/install/module/install_database/task/create_schema.php b/install/update/new/phpbb/install/module/install_database/task/create_schema.php deleted file mode 100644 index 983bb42..0000000 --- a/install/update/new/phpbb/install/module/install_database/task/create_schema.php +++ /dev/null @@ -1,227 +0,0 @@ - - * @license 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') - { - $schema_name .= '_41'; - } - - $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/install/update/new/phpbb/install/module/install_database/task/set_up_database.php b/install/update/new/phpbb/install/module/install_database/task/set_up_database.php deleted file mode 100644 index 4da5ece..0000000 --- a/install/update/new/phpbb/install/module/install_database/task/set_up_database.php +++ /dev/null @@ -1,157 +0,0 @@ - - * @license 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') - { - $schema_name .= '_41'; - } - - $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/install/update/new/phpbb/install/module/install_filesystem/task/create_config_file.php b/install/update/new/phpbb/install/module/install_filesystem/task/create_config_file.php deleted file mode 100644 index 900d5b9..0000000 --- a/install/update/new/phpbb/install/module/install_filesystem/task/create_config_file.php +++ /dev/null @@ -1,243 +0,0 @@ - - * @license 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 = "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"; - - 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/install/update/new/phpbb/install/module/requirements/task/check_server_environment.php b/install/update/new/phpbb/install/module/requirements/task/check_server_environment.php deleted file mode 100644 index 41aa826..0000000 --- a/install/update/new/phpbb/install/module/requirements/task/check_server_environment.php +++ /dev/null @@ -1,207 +0,0 @@ - - * @license 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() - { - if (version_compare(PHP_VERSION, '7.1.3', '<')) - { - $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/install/update/new/phpbb/install/module_base.php b/install/update/new/phpbb/install/module_base.php deleted file mode 100644 index 4464a89..0000000 --- a/install/update/new/phpbb/install/module_base.php +++ /dev/null @@ -1,213 +0,0 @@ - - * @license 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] ?? false); - } - 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/install/update/new/phpbb/language/language_file_loader.php b/install/update/new/phpbb/language/language_file_loader.php deleted file mode 100644 index 2910dd3..0000000 --- a/install/update/new/phpbb/language/language_file_loader.php +++ /dev/null @@ -1,207 +0,0 @@ - - * @license 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 - * @param array $locales Array containing language fallback options - * - * @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/install/update/new/phpbb/lock/db.php b/install/update/new/phpbb/lock/db.php deleted file mode 100644 index eea919f..0000000 --- a/install/update/new/phpbb/lock/db.php +++ /dev/null @@ -1,153 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\lock; - -/** -* Database locking class -*/ -class db -{ - /** - * Name of the config variable this lock uses - * @var string - */ - private $config_name; - - /** - * Unique identifier for this lock. - * - * @var string - */ - private $unique_id; - - /** - * Stores the state of this lock - * @var bool - */ - private $locked; - - /** - * The phpBB configuration - * @var \phpbb\config\config - */ - private $config; - - /** - * A database connection - * @var \phpbb\db\driver\driver_interface - */ - private $db; - - /** - * Creates a named released instance of the lock. - * - * You have to call acquire() to actually create the lock. - * - * @param string $config_name A config variable to be used for locking - * @param \phpbb\config\config $config The phpBB configuration - * @param \phpbb\db\driver\driver_interface $db A database connection - */ - public function __construct($config_name, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db) - { - $this->config_name = $config_name; - $this->config = $config; - $this->db = $db; - } - - /** - * Tries to acquire the lock by updating - * the configuration variable in the database. - * - * As a lock may only be held by one process at a time, lock - * acquisition may fail if another process is holding the lock - * or if another process obtained the lock but never released it. - * Locks are forcibly released after a timeout of 1 hour. - * - * @return bool true if lock was acquired - * false otherwise - */ - public function acquire() - { - if ($this->locked) - { - return false; - } - - if (!isset($this->config[$this->config_name])) - { - $this->config->set($this->config_name, '0', false); - } - $lock_value = $this->config[$this->config_name]; - - // make sure lock cannot be acquired by multiple processes - if ($lock_value) - { - // if the other process is running more than an hour already we have to assume it - // aborted without cleaning the lock - $time = explode(' ', $lock_value); - $time = $time[0]; - - if ($time + 3600 >= time()) - { - return false; - } - } - - $this->unique_id = time() . ' ' . unique_id(); - - // try to update the config value, if it was already modified by another - // process we failed to acquire the lock. - $this->locked = $this->config->set_atomic($this->config_name, $lock_value, $this->unique_id, false); - - if ($this->locked == true) - { - if ($this->config->ensure_lock($this->config_name, $this->unique_id)) - { - return true; - } - } - return $this->locked; - } - - /** - * Does this process own the lock? - * - * @return bool true if lock is owned - * false otherwise - */ - public function owns_lock() - { - return (bool) $this->locked; - } - - /** - * Releases the lock. - * - * The lock must have been previously obtained, that is, acquire() call - * was issued and returned true. - * - * Note: Attempting to release a lock that is already released, - * that is, calling release() multiple times, is harmless. - * - * @return null - */ - public function release() - { - if ($this->locked) - { - $this->config->set_atomic($this->config_name, $this->unique_id, '0', false); - $this->locked = false; - } - } -} diff --git a/install/update/new/phpbb/lock/flock.php b/install/update/new/phpbb/lock/flock.php deleted file mode 100644 index af051af..0000000 --- a/install/update/new/phpbb/lock/flock.php +++ /dev/null @@ -1,144 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\lock; - -/** -* File locking class -*/ -class flock -{ - /** - * Path to the file to which access is controlled - * - * @var string - */ - private $path; - - /** - * File pointer for the lock file - * @var string - */ - private $lock_fp; - - /** - * Constructor. - * - * You have to call acquire() to actually acquire the lock. - * - * @param string $path Path to the file to which access is controlled - */ - public function __construct($path) - { - $this->path = $path; - $this->lock_fp = null; - } - - /** - * Tries to acquire the lock. - * - * If the lock is already held by another process, this call will block - * until the other process releases the lock. If a lock is acquired and - * is not released before script finishes but the process continues to - * live (apache/fastcgi) then subsequent processes trying to acquire - * the same lock will be blocked forever. - * - * If the lock is already held by the same process via another instance - * of this class, this call will block forever. - * - * If flock function is disabled in php or fails to work, lock - * acquisition will fail and false will be returned. - * - * @return bool true if lock was acquired - * false otherwise - */ - public function acquire() - { - if ($this->lock_fp) - { - return false; - } - - // For systems that can't have two processes opening - // one file for writing simultaneously - if (file_exists($this->path . '.lock')) - { - $mode = 'rb'; - } - else - { - $mode = 'wb'; - } - - $this->lock_fp = @fopen($this->path . '.lock', $mode); - - if ($mode == 'wb') - { - if (!$this->lock_fp) - { - // Two processes may attempt to create lock file at the same time. - // Have the losing process try opening the lock file again for reading - // on the assumption that the winning process created it - $mode = 'rb'; - $this->lock_fp = @fopen($this->path . '.lock', $mode); - } - else - { - // Only need to set mode when the lock file is written - @chmod($this->path . '.lock', 0666); - } - } - - if ($this->lock_fp) - { - if (!@flock($this->lock_fp, LOCK_EX)) - { - throw new \phpbb\exception\http_exception(500, 'Failure while aqcuiring locks.'); - } - } - - return (bool) $this->lock_fp; - } - - /** - * Does this process own the lock? - * - * @return bool true if lock is owned - * false otherwise - */ - public function owns_lock() - { - return (bool) $this->lock_fp; - } - - /** - * Releases the lock. - * - * The lock must have been previously obtained, that is, acquire() call - * was issued and returned true. - * - * Note: Attempting to release a lock that is already released, - * that is, calling release() multiple times, is harmless. - * - * @return null - */ - public function release() - { - if ($this->lock_fp) - { - @flock($this->lock_fp, LOCK_UN); - fclose($this->lock_fp); - $this->lock_fp = null; - } - } -} diff --git a/install/update/new/phpbb/message/form.php b/install/update/new/phpbb/message/form.php deleted file mode 100644 index 6573a04..0000000 --- a/install/update/new/phpbb/message/form.php +++ /dev/null @@ -1,175 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\message; - -/** -* Abstract class form -*/ -abstract class form -{ - /** @var \phpbb\auth\auth */ - protected $auth; - /** @var \phpbb\config\config */ - protected $config; - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - /** @var \phpbb\message\message */ - protected $message; - /** @var \phpbb\user */ - protected $user; - - /** @var string */ - protected $phpbb_root_path; - /** @var string */ - protected $phpEx; - - /** @var array */ - protected $errors = array(); - /** @var bool */ - protected $cc_sender; - /** @var string */ - protected $body; - - /** - * Construct - * - * @param \phpbb\auth\auth $auth - * @param \phpbb\config\config $config - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\user $user - * @param string $phpbb_root_path - * @param string $phpEx - */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $phpEx) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->phpEx = $phpEx; - $this->user = $user; - $this->auth = $auth; - $this->config = $config; - $this->db = $db; - - $this->message = new message($config['server_name']); - $this->message->set_sender_from_user($this->user); - } - - /** - * Returns the title for the email form page - * - * @return string - */ - public function get_page_title() - { - return $this->user->lang['SEND_EMAIL']; - } - - /** - * Returns the file name of the form template - * - * @return string - */ - public function get_template_file() - { - return 'memberlist_email.html'; - } - - /** - * Checks whether the user is allowed to use the form - * - * @return false|string Error string if not allowed, false otherwise - */ - public function check_allow() - { - if (!$this->config['email_enable']) - { - return 'EMAIL_DISABLED'; - } - - if (time() - $this->user->data['user_emailtime'] < $this->config['flood_interval']) - { - return 'FLOOD_EMAIL_LIMIT'; - } - - return false; - } - - /** - * Get the return link after the message has been sent - * - * @return string - */ - public function get_return_message() - { - return sprintf($this->user->lang['RETURN_INDEX'], '', ''); - } - - /** - * Bind the values of the request to the form - * - * @param \phpbb\request\request_interface $request - * @return null - */ - public function bind(\phpbb\request\request_interface $request) - { - $this->cc_sender = $request->is_set_post('cc_sender'); - $this->body = $request->variable('message', '', true); - } - - /** - * Submit form, generate the email and send it - * - * @param \messenger $messenger - * @return null - */ - public function submit(\messenger $messenger) - { - if (!check_form_key('memberlist_email')) - { - $this->errors[] = $this->user->lang('FORM_INVALID'); - } - - if (!count($this->errors)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_emailtime = ' . time() . ' - WHERE user_id = ' . $this->user->data['user_id']; - $this->db->sql_query($sql); - - if ($this->cc_sender && $this->user->data['is_registered']) - { - $this->message->cc_sender(); - } - - $this->message->send($messenger, phpbb_get_board_contact($this->config, $this->phpEx)); - - meta_refresh(3, append_sid($this->phpbb_root_path . 'index.' . $this->phpEx)); - trigger_error($this->user->lang['EMAIL_SENT'] . '

' . $this->get_return_message()); - } - } - - /** - * Render the template of the form - * - * @param \phpbb\template\template $template - * @return null - */ - public function render(\phpbb\template\template $template) - { - add_form_key('memberlist_email'); - - $template->assign_vars(array( - 'ERROR_MESSAGE' => (count($this->errors)) ? implode('
', $this->errors) : '', - )); - } -} diff --git a/install/update/new/phpbb/mimetype/guesser.php b/install/update/new/phpbb/mimetype/guesser.php deleted file mode 100644 index f8cbffe..0000000 --- a/install/update/new/phpbb/mimetype/guesser.php +++ /dev/null @@ -1,156 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\mimetype; - -class guesser -{ - /** - * @const Default priority for mimetype guessers - */ - const PRIORITY_DEFAULT = 0; - - /** - * @var array guessers - */ - protected $guessers; - - /** - * Construct a mimetype guesser object - * - * @param array $mimetype_guessers Mimetype guesser service collection - */ - public function __construct($mimetype_guessers) - { - $this->register_guessers($mimetype_guessers); - } - - /** - * Register MimeTypeGuessers and sort them by priority - * - * @param array $mimetype_guessers Mimetype guesser service collection - * - * @throws \LogicException If incorrect or not mimetype guessers have - * been supplied to class - */ - protected function register_guessers($mimetype_guessers) - { - foreach ($mimetype_guessers as $guesser) - { - $is_supported = (method_exists($guesser, 'is_supported')) ? 'is_supported' : ''; - $is_supported = (method_exists($guesser, 'isSupported')) ? 'isSupported' : $is_supported; - - if (empty($is_supported)) - { - throw new \LogicException('Incorrect mimetype guesser supplied.'); - } - - if ($guesser->$is_supported()) - { - $this->guessers[] = $guesser; - } - } - - if (empty($this->guessers)) - { - throw new \LogicException('No mimetype guesser supplied.'); - } - - // Sort guessers by priority - usort($this->guessers, array($this, 'sort_priority')); - } - - /** - * Sort the priority of supplied guessers - * This is a compare function for usort. A guesser with higher priority - * should be used first and vice versa. usort() orders the array values - * from low to high depending on what the comparison function returns - * to it. Return value should be smaller than 0 if value a is smaller - * than value b. This has been reversed in the comparison function in - * order to sort the guessers from high to low. - * Method has been set to public in order to allow proper testing. - * - * @param object $guesser_a Mimetype guesser a - * @param object $guesser_b Mimetype guesser b - * - * @return int If both guessers have the same priority 0, bigger - * than 0 if first guesser has lower priority, and lower - * than 0 if first guesser has higher priority - */ - public function sort_priority($guesser_a, $guesser_b) - { - $priority_a = (int) (method_exists($guesser_a, 'get_priority')) ? $guesser_a->get_priority() : self::PRIORITY_DEFAULT; - $priority_b = (int) (method_exists($guesser_b, 'get_priority')) ? $guesser_b->get_priority() : self::PRIORITY_DEFAULT; - - return $priority_b - $priority_a; - } - - /** - * Guess mimetype of supplied file - * - * @param string $file Path to file - * @param string $file_name The real file name - * - * @return string Guess for mimetype of file - */ - public function guess($file, $file_name = '') - { - if (!is_file($file)) - { - return false; - } - - if (!is_readable($file)) - { - return false; - } - - $mimetype = 'application/octet-stream'; - - foreach ($this->guessers as $guesser) - { - $mimetype_guess = $guesser->guess($file, $file_name); - - $mimetype = $this->choose_mime_type($mimetype, $mimetype_guess); - } - // Return any mimetype if we got a result or the fallback value - return $mimetype; - } - - /** - * Choose the best mime type based on the current mime type and the guess - * If a guesser returns nulls or application/octet-stream, we will keep - * the current guess. Guesses with a slash inside them will be favored over - * already existing ones. However, any guess that will pass the first check - * will always overwrite the default application/octet-stream. - * - * @param string $mime_type The current mime type - * @param string $guess The current mime type guess - * - * @return string The best mime type based on current mime type and guess - */ - public function choose_mime_type($mime_type, $guess) - { - if ($guess === null || $guess == 'application/octet-stream') - { - return $mime_type; - } - - if ($mime_type == 'application/octet-stream' || strpos($guess, '/') !== false) - { - $mime_type = $guess; - } - - return $mime_type; - } -} diff --git a/install/update/new/phpbb/notification/type/approve_post.php b/install/update/new/phpbb/notification/type/approve_post.php deleted file mode 100644 index 139b5fa..0000000 --- a/install/update/new/phpbb/notification/type/approve_post.php +++ /dev/null @@ -1,146 +0,0 @@ - -* @license 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\type; - -/** -* Post approved notifications class -* This class handles notifications for posts when they are approved (to their authors) -*/ - -class approve_post extends \phpbb\notification\type\post -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type() - { - return 'notification.type.approve_post'; - } - - /** - * Language key used to output the text - * - * @var string - */ - protected $language_key = 'NOTIFICATION_POST_APPROVED'; - - /** - * Inherit notification read status from post. - * - * @var bool - */ - protected $inherit_read_status = false; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use it's default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - static public $notification_option = array( - 'id' => 'moderation_queue', - 'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE', - 'group' => 'NOTIFICATION_GROUP_POSTING', - ); - - /** - * Is available - */ - public function is_available() - { - return !$this->auth->acl_get('m_approve'); - } - - /** - * Find the users who want to receive notifications - * - * @param array $post Data from submit_post - * @param array $options Options for finding users for notification - * - * @return array - */ - public function find_users_for_notification($post, $options = array()) - { - $options = array_merge(array( - 'ignore_users' => array(), - ), $options); - - return $this->get_authorised_recipients(array($post['poster_id']), $post['forum_id'], array_merge($options, array( - 'item_type' => static::$notification_option['id'], - ))); - } - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $post Post data from submit_post - * @param array $notify_users Notify users list - * Formatted from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($post, $notify_users) - { - // In the parent class, this is used to check if the post is already - // read by a user and marks the notification read if it was marked read. - // Returning an empty array in effect, forces it to be marked as unread - // (and also saves a query) - return array(); - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($post, $pre_create_data = array()) - { - $this->set_data('post_subject', $post['post_subject']); - - 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; - } - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template() - { - return 'post_approved'; - } - - /** - * {inheritDoc} - */ - public function get_redirect_url() - { - return $this->get_url(); - } -} diff --git a/install/update/new/phpbb/notification/type/approve_topic.php b/install/update/new/phpbb/notification/type/approve_topic.php deleted file mode 100644 index 0c34364..0000000 --- a/install/update/new/phpbb/notification/type/approve_topic.php +++ /dev/null @@ -1,137 +0,0 @@ - -* @license 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\type; - -/** -* Topic approved notifications class -* This class handles notifications for topics when they are approved (for authors) -*/ - -class approve_topic extends \phpbb\notification\type\topic -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type() - { - return 'notification.type.approve_topic'; - } - - /** - * Language key used to output the text - * - * @var string - */ - protected $language_key = 'NOTIFICATION_TOPIC_APPROVED'; - - /** - * Inherit notification read status from topic. - * - * @var bool - */ - protected $inherit_read_status = false; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use it's default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - static public $notification_option = array( - 'id' => 'moderation_queue', - 'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE', - 'group' => 'NOTIFICATION_GROUP_POSTING', - ); - - /** - * Is available - */ - public function is_available() - { - return !$this->auth->acl_get('m_approve'); - } - - /** - * Find the users who want to receive notifications - * - * @param array $post Data from submit_post - * @param array $options Options for finding users for notification - * - * @return array - */ - public function find_users_for_notification($post, $options = array()) - { - $options = array_merge(array( - 'ignore_users' => array(), - ), $options); - - return $this->get_authorised_recipients(array($post['poster_id']), $post['forum_id'], array_merge($options, array( - 'item_type' => static::$notification_option['id'], - ))); - } - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $post Post data from submit_post - * @param array $notify_users Notify users list - * Formatted from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($post, $notify_users) - { - // In the parent class, this is used to check if the post is already - // read by a user and marks the notification read if it was marked read. - // Returning an empty array in effect, forces it to be marked as unread - // (and also saves a query) - return array(); - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($post, $pre_create_data = array()) - { - - 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; - } - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template() - { - return 'topic_approved'; - } -} diff --git a/install/update/new/phpbb/notification/type/base.php b/install/update/new/phpbb/notification/type/base.php deleted file mode 100644 index e4600ad..0000000 --- a/install/update/new/phpbb/notification/type/base.php +++ /dev/null @@ -1,577 +0,0 @@ - -* @license 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\type; - -/** -* Base notifications class -*/ -abstract class base implements \phpbb\notification\type\type_interface -{ - /** @var \phpbb\notification\manager */ - protected $notification_manager; - - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\language\language */ - protected $language; - - /** @var \phpbb\user */ - protected $user; - - /** @var \phpbb\auth\auth */ - protected $auth; - - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - - /** @var string */ - protected $user_notifications_table; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use its default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - static public $notification_option = false; - - /** - * The notification_type_id, set upon creation of the class - * This is the notification_type_id from the notification_types table - * - * @var int - */ - protected $notification_type_id; - - /** - * 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) - * user_id - * notification_read - * notification_time - * notification_data (special serialized field that each notification type can use to store stuff) - * - * @var array $data Notification row from the database - * This must be private, all interaction should use __get(), __set(), get_data(), set_data() - */ - private $data = array(); - - /** - * 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->db = $db; - $this->language = $language; - $this->user = $user; - $this->auth = $auth; - - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->user_notifications_table = $user_notifications_table; - } - - /** - * Set notification manager (required) - * - * @param \phpbb\notification\manager $notification_manager - */ - public function set_notification_manager(\phpbb\notification\manager $notification_manager) - { - $this->notification_manager = $notification_manager; - - $this->notification_type_id = $this->notification_manager->get_notification_type_id($this->get_type()); - } - - /** - * Set initial data from the database - * - * @param array $data Row directly from the database - */ - public function set_initial_data($data = array()) - { - // The row from the database (unless this is a new notification we're going to add) - $this->data = $data; - $this->data['notification_data'] = (isset($this->data['notification_data'])) ? unserialize($this->data['notification_data']) : array(); - } - - /** - * Magic method to get data from this notification - * - * @param mixed $name - * @return mixed - */ - public function __get($name) - { - return (!isset($this->data[$name])) ? null : $this->data[$name]; - } - - - /** - * Magic method to set data on this notification - * - * @param mixed $name - * @param mixed $value - * - * @return null - */ - public function __set($name, $value) - { - $this->data[$name] = $value; - } - - - /** - * Magic method to get a string of this notification - * - * Primarily for testing - * - * @return mixed - */ - public function __toString() - { - return (!empty($this->data)) ? var_export($this->data, true) : $this->get_type(); - } - - /** - * Get special data (only important for the classes that extend this) - * - * @param string $name Name of the variable to get - * @return mixed - */ - protected function get_data($name) - { - return ($name === false) ? $this->data['notification_data'] : ((isset($this->data['notification_data'][$name])) ? $this->data['notification_data'][$name] : null); - } - - /** - * Set special data (only important for the classes that extend this) - * - * @param string $name Name of the variable to set - * @param mixed $value Value to set to the variable - * @return mixed - */ - protected function set_data($name, $value) - { - $this->data['notification_data'][$name] = $value; - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($type_data, $pre_create_data = array()) - { - // Defaults - $this->data = array_merge(array( - 'item_id' => static::get_item_id($type_data), - 'notification_type_id' => $this->notification_type_id, - 'item_parent_id' => static::get_item_parent_id($type_data), - - 'notification_time' => time(), - 'notification_read' => false, - - 'notification_data' => array(), - ), $this->data); - } - - /** - * {@inheritdoc} - */ - public function get_insert_array() - { - $data = $this->data; - - $data['notification_data'] = serialize($data['notification_data']); - - return $data; - } - - /** - * Function for preparing the data for update in an SQL query - * (The service handles insertion) - * - * @param array $type_data Data unique to this notification type - * @return array Array of data ready to be updated in the database - */ - public function create_update_array($type_data) - { - $this->create_insert_array($type_data); - $data = $this->get_insert_array(); - - // Unset data unique to each row - unset( - $data['notification_time'], // Also unsetting time, since it always tries to change the time to current (if you actually need to change the time, over-ride this function) - $data['notification_id'], - $data['notification_read'], - $data['user_id'] - ); - - return $data; - } - - /** - * Mark this item read - * - * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False) - * @return string|null If $return is False, nothing will be returned, else the sql code to update this item - */ - public function mark_read($return = false) - { - return $this->mark(false, $return); - } - - /** - * Mark this item unread - * - * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False) - * @return string|null If $return is False, nothing will be returned, else the sql code to update this item - */ - public function mark_unread($return = false) - { - return $this->mark(true, $return); - } - - /** - * {inheritDoc} - */ - public function get_redirect_url() - { - return $this->get_url(); - } - - /** - * Prepare to output the notification to the template - * - * @return array Template variables - */ - public function prepare_for_display() - { - $mark_hash = generate_link_hash('mark_notification_read'); - - if ($this->get_url()) - { - $u_mark_read = append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'mark_notification=' . $this->notification_id . '&hash=' . $mark_hash); - } - else - { - $redirect = (($this->user->page['page_dir']) ? $this->user->page['page_dir'] . '/' : '') . $this->user->page['page_name'] . (($this->user->page['query_string']) ? '?' . $this->user->page['query_string'] : ''); - - $u_mark_read = append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'mark_notification=' . $this->notification_id . '&hash=' . $mark_hash . '&redirect=' . urlencode($redirect)); - } - - return array( - 'NOTIFICATION_ID' => $this->notification_id, - 'STYLING' => $this->get_style_class(), - 'AVATAR' => $this->get_avatar(), - 'FORMATTED_TITLE' => $this->get_title(), - 'REFERENCE' => $this->get_reference(), - 'FORUM' => $this->get_forum(), - 'REASON' => $this->get_reason(), - 'URL' => $this->get_url(), - 'TIME' => $this->user->format_date($this->notification_time), - 'UNREAD' => !$this->notification_read, - 'U_MARK_READ' => (!$this->notification_read) ? $u_mark_read : '', - ); - } - - /** - * -------------- Fall back functions ------------------- - */ - - /** - * 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) - { - return false; - } - - /** - * Get the CSS style class of the notification (fall back) - * - * @return string - */ - public function get_style_class() - { - return ''; - } - - /** - * Get the user's avatar (fall back) - * - * @return string - */ - public function get_avatar() - { - return ''; - } - - /** - * Get the reference of the notification (fall back) - * - * @return string - */ - public function get_reference() - { - return ''; - } - - /** - * Get the forum of the notification reference (fall back) - * - * @return string - */ - public function get_forum() - { - return ''; - } - - /** - * Get the reason for the notification (fall back) - * - * @return string - */ - public function get_reason() - { - return ''; - } - - /** - * Get the special items to load (fall back) - * - * @return array - */ - public function get_load_special() - { - return array(); - } - - /** - * Load the special items (fall back) - * - * @param array $data - * @param array $notifications - */ - public function load_special($data, $notifications) - { - return; - } - - /** - * Is available (fall back) - * - * @return bool - */ - public function is_available() - { - return true; - } - - /** - * 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(); - } - - /** - * -------------- Helper functions ------------------- - */ - - /** - * 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( - 'ignore_users' => array(), - 'item_type' => $this->get_type(), - 'item_id' => 0, // Global by default - ), $options); - - if ($user_ids === false) - { - $user_ids = array(); - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE user_id <> ' . ANONYMOUS . ' - AND user_type <> ' . USER_IGNORE; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $user_ids[] = $row['user_id']; - } - $this->db->sql_freeresult($result); - } - - if (empty($user_ids)) - { - return array(); - } - - $rowset = $output = array(); - - $sql = 'SELECT user_id, method, notify - FROM ' . $this->user_notifications_table . ' - WHERE ' . $this->db->sql_in_set('user_id', $user_ids) . " - AND item_type = '" . $this->db->sql_escape($options['item_type']) . "' - AND item_id = " . (int) $options['item_id']; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - if (isset($options['ignore_users'][$row['user_id']]) && in_array($row['method'], $options['ignore_users'][$row['user_id']])) - { - continue; - } - - if (!isset($rowset[$row['user_id']])) - { - $rowset[$row['user_id']] = array(); - } - $rowset[$row['user_id']][$row['method']] = $row['notify']; - - 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 (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 - { - 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 $output; - } - - /** - * Mark this item read/unread helper - * - * @param bool $unread Unread (True/False) (Default: False) - * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False) - * @return string|null If $return is False, nothing will be returned, else the sql code to update this item - */ - protected function mark($unread = true, $return = false) - { - $this->notification_read = (bool) !$unread; - - 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); - } - - return null; - } - - /** - * Get a list of users that are authorised to receive notifications - * - * @param array $users Array of users that have subscribed to a notification - * @param int $forum_id Forum ID of the forum - * @param array $options Array of notification options - * @param bool $sort Whether the users array should be sorted. Default: false - * @return array Array of users that are authorised recipients - */ - protected function get_authorised_recipients($users, $forum_id, $options, $sort = false) - { - if (empty($users)) - { - return array(); - } - - $users = array_unique($users); - - if ($sort) - { - sort($users); - } - - $auth_read = $this->auth->acl_get_list($users, 'f_read', $forum_id); - - if (empty($auth_read)) - { - return array(); - } - - return $this->check_user_notification_options($auth_read[$forum_id]['f_read'], $options); - } -} diff --git a/install/update/new/phpbb/notification/type/post.php b/install/update/new/phpbb/notification/type/post.php deleted file mode 100644 index f0e938d..0000000 --- a/install/update/new/phpbb/notification/type/post.php +++ /dev/null @@ -1,467 +0,0 @@ - -* @license 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\type; - -/** -* Post notifications class -* This class handles notifications for replies to a topic -*/ - -class post extends \phpbb\notification\type\base -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type() - { - return 'notification.type.post'; - } - - /** - * Language key used to output the text - * - * @var string - */ - protected $language_key = 'NOTIFICATION_POST'; - - /** - * Inherit notification read status from post. - * - * @var bool - */ - protected $inherit_read_status = true; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use it's default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - 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 - */ - public function is_available() - { - return $this->config['allow_topic_notify']; - } - - /** - * Get the id of the item - * - * @param array $post The data from the post - * @return int The post id - */ - static public function get_item_id($post) - { - return (int) $post['post_id']; - } - - /** - * Get the id of the parent - * - * @param array $post The data from the post - * @return int The topic id - */ - static public function get_item_parent_id($post) - { - return (int) $post['topic_id']; - } - - /** - * Find the users who want to receive notifications - * - * @param array $post Data from submit_post - * @param array $options Options for finding users for notification - * - * @return array - */ - public function find_users_for_notification($post, $options = array()) - { - $options = array_merge(array( - 'ignore_users' => array(), - ), $options); - - $users = array(); - - $sql = 'SELECT user_id - FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . (int) $post['topic_id'] . ' - AND notify_status = ' . NOTIFY_YES . ' - AND user_id <> ' . (int) $post['poster_id']; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $users[] = (int) $row['user_id']; - } - $this->db->sql_freeresult($result); - - $sql = 'SELECT user_id - FROM ' . FORUMS_WATCH_TABLE . ' - WHERE forum_id = ' . (int) $post['forum_id'] . ' - AND notify_status = ' . NOTIFY_YES . ' - AND user_id <> ' . (int) $post['poster_id']; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $users[] = (int) $row['user_id']; - } - $this->db->sql_freeresult($result); - - $notify_users = $this->get_authorised_recipients($users, $post['forum_id'], $options, true); - - if (empty($notify_users)) - { - return array(); - } - - // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications - $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) - { - unset($notify_users[$user]); - - /** @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)) - { - $this->notification_manager->update_notification($notification, $update_responders, array( - 'item_parent_id' => self::get_item_parent_id($post), - 'read' => 0, - 'user_id' => $user, - )); - } - } - - return $notify_users; - } - - /** - * Get the user's avatar - */ - public function get_avatar() - { - return $this->user_loader->get_avatar($this->get_data('poster_id'), false, true); - } - - /** - * Get the HTML formatted title of this notification - * - * @return string - */ - public function get_title() - { - $responders = $this->get_data('responders'); - $usernames = array(); - - if (!is_array($responders)) - { - $responders = array(); - } - - $responders = array_merge(array(array( - 'poster_id' => $this->get_data('poster_id'), - 'username' => $this->get_data('post_username'), - )), $responders); - - $responders_cnt = count($responders); - $responders = $this->trim_user_ary($responders); - $trimmed_responders_cnt = $responders_cnt - count($responders); - - foreach ($responders as $responder) - { - if ($responder['username']) - { - $usernames[] = $responder['username']; - } - else - { - $usernames[] = $this->user_loader->get_username($responder['poster_id'], 'no_profile'); - } - } - - if ($trimmed_responders_cnt > 20) - { - $usernames[] = $this->language->lang('NOTIFICATION_MANY_OTHERS'); - } - else if ($trimmed_responders_cnt) - { - $usernames[] = $this->language->lang('NOTIFICATION_X_OTHERS', $trimmed_responders_cnt); - } - - return $this->language->lang( - $this->language_key, - phpbb_generate_string_list($usernames, $this->user), - $responders_cnt - ); - } - - /** - * Get the HTML formatted reference of the notification - * - * @return string - */ - public function get_reference() - { - return $this->language->lang( - 'NOTIFICATION_REFERENCE', - censor_text($this->get_data('topic_title')) - ); - } - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template() - { - return 'topic_notify'; - } - - /** - * Get email template variables - * - * @return array - */ - public function get_email_template_variables() - { - if ($this->get_data('post_username')) - { - $username = $this->get_data('post_username'); - } - else - { - $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username'); - } - - return array( - 'AUTHOR_NAME' => htmlspecialchars_decode($username), - 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('post_subject'))), - 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('topic_title'))), - - 'U_VIEW_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?p={$this->item_id}#p{$this->item_id}", - 'U_NEWEST_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}&e=1&view=unread#unread", - 'U_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}", - 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}", - 'U_FORUM' => generate_board_url() . "/viewforum.{$this->php_ext}?f={$this->get_data('forum_id')}", - 'U_STOP_WATCHING_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?uid={$this->user_id}&f={$this->get_data('forum_id')}&t={$this->item_parent_id}&unwatch=topic", - ); - } - - /** - * Get the url to this item - * - * @return string URL - */ - public function get_url() - { - return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "p={$this->item_id}#p{$this->item_id}"); - } - - /** - * {inheritDoc} - */ - public function get_redirect_url() - { - return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "t={$this->item_parent_id}&view=unread#unread"); - } - - /** - * Users needed to query before this notification can be displayed - * - * @return array Array of user_ids - */ - public function users_to_query() - { - $responders = $this->get_data('responders'); - $users = array( - $this->get_data('poster_id'), - ); - - if (is_array($responders)) - { - foreach ($responders as $responder) - { - $users[] = $responder['poster_id']; - } - } - - return $this->trim_user_ary($users); - } - - /** - * Trim the user array passed down to 3 users if the array contains - * more than 4 users. - * - * @param array $users Array of users - * @return array Trimmed array of user_ids - */ - public function trim_user_ary($users) - { - if (count($users) > 4) - { - array_splice($users, 3); - } - return $users; - } - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $post Post data from submit_post - * @param array $notify_users Notify users list - * Formatted from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($post, $notify_users) - { - if (!count($notify_users) || !$this->inherit_read_status) - { - return array(); - } - - $tracking_data = array(); - $sql = 'SELECT user_id, mark_time FROM ' . TOPICS_TRACK_TABLE . ' - WHERE topic_id = ' . (int) $post['topic_id'] . ' - AND ' . $this->db->sql_in_set('user_id', array_keys($notify_users)); - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $tracking_data[$row['user_id']] = $row['mark_time']; - } - $this->db->sql_freeresult($result); - - return $tracking_data; - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($post, $pre_create_data = array()) - { - $this->set_data('poster_id', $post['poster_id']); - - $this->set_data('topic_title', $post['topic_title']); - - $this->set_data('post_subject', $post['post_subject']); - - $this->set_data('post_username', (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : '')); - - $this->set_data('forum_id', $post['forum_id']); - - $this->set_data('forum_name', $post['forum_name']); - - $this->notification_time = $post['post_time']; - - // Topics can be "read" before they are public (while awaiting approval). - // Make sure that if the user has read the topic, it's marked as read in the notification - if ($this->inherit_read_status && isset($pre_create_data[$this->user_id]) && $pre_create_data[$this->user_id] >= $this->notification_time) - { - $this->notification_read = true; - } - - 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) - { - // Do not add them as a responder if they were the original poster that created the notification - if ($this->get_data('poster_id') == $post['poster_id']) - { - return array(); - } - - $responders = $this->get_data('responders'); - - $responders = ($responders === null) ? array() : $responders; - - // 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 (count($responders) > 25) - { - return array(); - } - - foreach ($responders as $responder) - { - // Do not add them as a responder multiple times - if ($responder['poster_id'] == $post['poster_id']) - { - return array(); - } - } - - $responders[] = array( - 'poster_id' => $post['poster_id'], - 'username' => (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : ''), - ); - - $this->set_data('responders', $responders); - - $serialized_data = serialize($this->get_data(false)); - - // If the data is longer then 4000 characters, it would cause a SQL error. - // We don't add the username to the list if this is the case. - if (utf8_strlen($serialized_data) >= 4000) - { - return array(); - } - - $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/install/update/new/phpbb/notification/type/topic.php b/install/update/new/phpbb/notification/type/topic.php deleted file mode 100644 index 2535cda..0000000 --- a/install/update/new/phpbb/notification/type/topic.php +++ /dev/null @@ -1,307 +0,0 @@ - -* @license 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\type; - -/** -* Topic notifications class -* This class handles notifications for new topics -*/ - -class topic extends \phpbb\notification\type\base -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type() - { - return 'notification.type.topic'; - } - - /** - * Language key used to output the text - * - * @var string - */ - protected $language_key = 'NOTIFICATION_TOPIC'; - - /** - * Inherit notification read status from topic. - * - * @var bool - */ - protected $inherit_read_status = true; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use it's default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - 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 - */ - public function is_available() - { - return $this->config['allow_forum_notify']; - } - - /** - * Get the id of the item - * - * @param array $post The data from the post - * @return int The topic id - */ - static public function get_item_id($post) - { - return (int) $post['topic_id']; - } - - /** - * Get the id of the parent - * - * @param array $post The data from the post - * @return int The forum id - */ - static public function get_item_parent_id($post) - { - return (int) $post['forum_id']; - } - - /** - * Find the users who want to receive notifications - * - * @param array $topic Data from the topic - * @param array $options Options for finding users for notification - * - * @return array - */ - public function find_users_for_notification($topic, $options = array()) - { - $options = array_merge(array( - 'ignore_users' => array(), - ), $options); - - $users = array(); - - $sql = 'SELECT user_id - FROM ' . FORUMS_WATCH_TABLE . ' - WHERE forum_id = ' . (int) $topic['forum_id'] . ' - AND notify_status = ' . NOTIFY_YES . ' - AND user_id <> ' . (int) $topic['poster_id']; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $users[] = (int) $row['user_id']; - } - $this->db->sql_freeresult($result); - - return $this->get_authorised_recipients($users, $topic['forum_id'], $options); - } - - /** - * Get the user's avatar - */ - public function get_avatar() - { - return $this->user_loader->get_avatar($this->get_data('poster_id'), false, true); - } - - /** - * Get the HTML formatted title of this notification - * - * @return string - */ - public function get_title() - { - if ($this->get_data('post_username')) - { - $username = $this->get_data('post_username'); - } - else - { - $username = $this->user_loader->get_username($this->get_data('poster_id'), 'no_profile'); - } - - return $this->language->lang( - $this->language_key, - $username - ); - } - - /** - * Get the HTML formatted reference of the notification - * - * @return string - */ - public function get_reference() - { - return $this->language->lang( - 'NOTIFICATION_REFERENCE', - censor_text($this->get_data('topic_title')) - ); - } - - /** - * Get the forum of the notification reference - * - * @return string - */ - public function get_forum() - { - return $this->language->lang( - 'NOTIFICATION_FORUM', - $this->get_data('forum_name') - ); - } - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template() - { - return 'newtopic_notify'; - } - - /** - * Get email template variables - * - * @return array - */ - public function get_email_template_variables() - { - $board_url = generate_board_url(); - - if ($this->get_data('post_username')) - { - $username = $this->get_data('post_username'); - } - else - { - $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username'); - } - - return array( - 'AUTHOR_NAME' => htmlspecialchars_decode($username), - 'FORUM_NAME' => htmlspecialchars_decode($this->get_data('forum_name')), - 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('topic_title'))), - - 'U_TOPIC' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->item_parent_id}&t={$this->item_id}", - 'U_VIEW_TOPIC' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->item_parent_id}&t={$this->item_id}", - 'U_FORUM' => "{$board_url}/viewforum.{$this->php_ext}?f={$this->item_parent_id}", - 'U_STOP_WATCHING_FORUM' => "{$board_url}/viewforum.{$this->php_ext}?uid={$this->user_id}&f={$this->item_parent_id}&unwatch=forum", - ); - } - - /** - * Get the url to this item - * - * @return string URL - */ - public function get_url() - { - return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "f={$this->item_parent_id}&t={$this->item_id}"); - } - - /** - * Users needed to query before this notification can be displayed - * - * @return array Array of user_ids - */ - public function users_to_query() - { - return array($this->get_data('poster_id')); - } - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $post Post data from submit_post - * @param array $notify_users Notify users list - * Formatted from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($post, $notify_users) - { - if (!count($notify_users) || !$this->inherit_read_status) - { - return array(); - } - - $tracking_data = array(); - $sql = 'SELECT user_id, mark_time FROM ' . TOPICS_TRACK_TABLE . ' - WHERE topic_id = ' . (int) $post['topic_id'] . ' - AND ' . $this->db->sql_in_set('user_id', array_keys($notify_users)); - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $tracking_data[$row['user_id']] = $row['mark_time']; - } - $this->db->sql_freeresult($result); - - return $tracking_data; - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($post, $pre_create_data = array()) - { - $this->set_data('poster_id', $post['poster_id']); - - $this->set_data('topic_title', $post['topic_title']); - - $this->set_data('post_username', (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : '')); - - $this->set_data('forum_name', $post['forum_name']); - - $this->notification_time = $post['post_time']; - - // Topics can be "read" before they are public (while awaiting approval). - // Make sure that if the user has read the topic, it's marked as read in the notification - if ($this->inherit_read_status && isset($pre_create_data[$this->user_id]) && $pre_create_data[$this->user_id] >= $this->notification_time) - { - $this->notification_read = true; - } - - parent::create_insert_array($post, $pre_create_data); - } -} diff --git a/install/update/new/phpbb/notification/type/type_interface.php b/install/update/new/phpbb/notification/type/type_interface.php deleted file mode 100644 index ed77335..0000000 --- a/install/update/new/phpbb/notification/type/type_interface.php +++ /dev/null @@ -1,218 +0,0 @@ - -* @license 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\type; - -/** -* Base notifications interface -*/ -interface type_interface -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type(); - - /** - * Set initial data from the database - * - * @param array $data Row directly from the database - */ - public function set_initial_data($data); - - /** - * Get the id of the item - * - * @param array $type_data The type specific data - */ - static public function get_item_id($type_data); - - /** - * Get the id of the parent - * - * @param array $type_data The type specific 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) - * - * @return bool True/False whether or not this is available to the user - */ - public function is_available(); - - /** - * Find the users who want to receive notifications - * - * @param array $type_data The type specific data - * @param array $options Options for finding users for notification - * ignore_users => array of users and user types that should not receive notifications from this type because they've already been notified - * e.g.: array(2 => array(''), 3 => array('', 'email'), ...) - * - * @return array - */ - public function find_users_for_notification($type_data, $options); - - /** - * Users needed to query before this notification can be displayed - * - * @return array Array of user_ids - */ - public function users_to_query(); - - /** - * Get the special items to load - * - * @return array Data will be combined sent to load_special() so you can run a single query and get data required for this notification type - */ - public function get_load_special(); - - /** - * Load the special items - * - * @param array $data Data from get_load_special() - * @param array $notifications Array of notifications (key is notification_id, value is the notification objects) - */ - public function load_special($data, $notifications); - - /** - * Get the CSS style class of the notification - * - * @return string - */ - public function get_style_class(); - - /** - * Get the HTML formatted title of this notification - * - * @return string - */ - public function get_title(); - - /** - * Get the HTML formatted reference of the notification - * - * @return string - */ - public function get_reference(); - - /** - * Get the forum of the notification reference - * - * @return string - */ - public function get_forum(); - - /** - * Get the url to this item - * - * @return string URL - */ - public function get_url(); - - /** - * Get the url to redirect after the item has been marked as read - * - * @return string URL - */ - public function get_redirect_url(); - - /** - * URL to unsubscribe to this notification - * - * @param string|bool $method Method name to unsubscribe from (email|jabber|etc), False to unsubscribe from all notifications for this item - */ - public function get_unsubscribe_url($method); - - /** - * Get the user's avatar (the user who caused the notification typically) - * - * @return string - */ - public function get_avatar(); - - /** - * Prepare to output the notification to the template - */ - public function prepare_for_display(); - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template(); - - /** - * Get email template variables - * - * @return array - */ - public function get_email_template_variables(); - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $type_data The type specific data - * @param array $notify_users Notify users list - * Formatted from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($type_data, $notify_users); - - /** - * Function for preparing the data for insertion in an SQL query - * - * @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 get_insert_array(); - - /** - * Function for preparing the data for update in an SQL query - * (The service handles insertion) - * - * @param array $type_data Data unique to this notification type - * - * @return array Array of data ready to be updated in the database - */ - public function create_update_array($type_data); - - /** - * Mark this item read - * - * @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 = false); - - /** - * Mark this item unread - * - * @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 = false); -} diff --git a/install/update/new/phpbb/passwords/driver/argon2i.php b/install/update/new/phpbb/passwords/driver/argon2i.php deleted file mode 100644 index 03368f6..0000000 --- a/install/update/new/phpbb/passwords/driver/argon2i.php +++ /dev/null @@ -1,78 +0,0 @@ - -* @license 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; - -class argon2i extends base_native -{ - /** @var int Maximum memory (in bytes) that may be used to compute the Argon2 hash */ - protected $memory_cost; - - /** @var int Number of threads to use for computing the Argon2 hash */ - protected $threads; - - /** @var int Maximum amount of time it may take to compute the Argon2 hash */ - protected $time_cost; - - /** - * Constructor of passwords driver object - * - * @param \phpbb\config\config $config phpBB config - * @param \phpbb\passwords\driver\helper $helper Password driver helper - * @param int $memory_cost Maximum memory (optional) - * @param int $threads Number of threads to use (optional) - * @param int $time_cost Maximum amount of time (optional) - */ - public function __construct(\phpbb\config\config $config, helper $helper, $memory_cost = 1024, $threads = 2, $time_cost = 2) - { - parent::__construct($config, $helper); - - /** - * For Sodium implementation of argon2 algorithm (since PHP 7.4), set special value of 1 for "threads" cost factor - * See https://wiki.php.net/rfc/sodium.argon.hash and PHPBB3-16266 - * Don't allow cost factors to be below default settings where possible - */ - $this->memory_cost = max($memory_cost, defined('PASSWORD_ARGON2_DEFAULT_MEMORY_COST') ? PASSWORD_ARGON2_DEFAULT_MEMORY_COST : 1024); - $this->time_cost = max($time_cost, defined('PASSWORD_ARGON2_DEFAULT_TIME_COST') ? PASSWORD_ARGON2_DEFAULT_TIME_COST : 2); - $this->threads = (defined('PASSWORD_ARGON2_PROVIDER') && PASSWORD_ARGON2_PROVIDER == 'sodium') ? - PASSWORD_ARGON2_DEFAULT_THREADS : max($threads, defined('PASSWORD_ARGON2_DEFAULT_THREADS') ? PASSWORD_ARGON2_DEFAULT_THREADS : 1); - } - - /** - * {@inheritdoc} - */ - public function get_algo_name() - { - return 'PASSWORD_ARGON2I'; - } - - /** - * {@inheritdoc} - */ - public function get_options() - { - return [ - 'memory_cost' => $this->memory_cost, - 'time_cost' => $this->time_cost, - 'threads' => $this->threads - ]; - } - - /** - * {@inheritdoc} - */ - public function get_prefix() - { - return '$argon2i$'; - } -} diff --git a/install/update/new/phpbb/passwords/driver/argon2id.php b/install/update/new/phpbb/passwords/driver/argon2id.php deleted file mode 100644 index 9e4b08b..0000000 --- a/install/update/new/phpbb/passwords/driver/argon2id.php +++ /dev/null @@ -1,33 +0,0 @@ - -* @license 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; - -class argon2id extends argon2i -{ - /** - * {@inheritdoc} - */ - public function get_algo_name() - { - return 'PASSWORD_ARGON2ID'; - } - - /** - * {@inheritdoc} - */ - public function get_prefix() - { - return '$argon2id$'; - } -} diff --git a/install/update/new/phpbb/passwords/driver/base_native.php b/install/update/new/phpbb/passwords/driver/base_native.php deleted file mode 100644 index 8749832..0000000 --- a/install/update/new/phpbb/passwords/driver/base_native.php +++ /dev/null @@ -1,75 +0,0 @@ - -* @license 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; - -abstract class base_native extends base -{ - /** - * Return the constant name for this driver's algorithm - * - * @link https://www.php.net/manual/en/password.constants.php - * - * @return string - */ - abstract public function get_algo_name(); - - /** - * Return the options set for this driver instance - * - * @return array - */ - abstract public function get_options(); - - /** - * {@inheritdoc} - */ - public function check($password, $hash, $user_row = []) - { - return password_verify($password, $hash); - } - - /** - * Return the value for this driver's algorithm - * - * @return integer - */ - public function get_algo_value() - { - return constant($this->get_algo_name()); - } - - /** - * {@inheritdoc} - */ - public function hash($password) - { - return password_hash($password, $this->get_algo_value(), $this->get_options()); - } - - /** - * {@inheritdoc} - */ - public function is_supported() - { - return defined($this->get_algo_name()) && function_exists('password_hash') && function_exists('password_needs_rehash') && function_exists('password_verify'); - } - - /** - * {@inheritdoc} - */ - public function needs_rehash($hash) - { - return password_needs_rehash($hash, $this->get_algo_value(), $this->get_options()); - } -} diff --git a/install/update/new/phpbb/passwords/manager.php b/install/update/new/phpbb/passwords/manager.php deleted file mode 100644 index 54e6dce..0000000 --- a/install/update/new/phpbb/passwords/manager.php +++ /dev/null @@ -1,407 +0,0 @@ - -* @license 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; - -class manager -{ - /** - * Default hashing method - */ - protected $type = false; - - /** - * Hashing algorithm type map - * Will be used to map hash prefix to type - */ - protected $type_map = false; - - /** - * Service collection of hashing algorithms - * Needs to be public for passwords helper - */ - public $algorithms = false; - - /** - * Password convert flag. Signals that password should be converted - */ - public $convert_flag = false; - - /** - * Passwords helper - * @var \phpbb\passwords\helper - */ - protected $helper; - - /** - * phpBB configuration - * @var \phpbb\config\config - */ - 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 - */ - 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; - } - - /** - * 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); - } - } - - /** - * Register default type - * Will register the first supported type from the list of default types - * - * @param array $defaults List of default types in order from first to - * use to last to use - */ - protected function register_default_type($defaults) - { - foreach ($defaults as $type) - { - if ($this->algorithms[$type]->is_supported()) - { - $this->type = $this->algorithms[$type]->get_prefix(); - break; - } - } - } - - /** - * Fill algorithm type map - * - * @param \phpbb\di\service_collection $hashing_algorithms - */ - protected function fill_type_map($hashing_algorithms) - { - foreach ($hashing_algorithms as $algorithm) - { - if (!isset($this->type_map[$algorithm->get_prefix()])) - { - $this->type_map[$algorithm->get_prefix()] = $algorithm; - } - } - $this->algorithms = $hashing_algorithms; - } - - /** - * Get the algorithm specified by a specific prefix - * - * @param string $prefix Password hash prefix - * - * @return object|bool The hash type object or false if prefix is not - * supported - */ - protected function get_algorithm($prefix) - { - if (isset($this->type_map[$prefix])) - { - return $this->type_map[$prefix]; - } - else - { - return false; - } - } - - /** - * Detect the hash type of the supplied hash - * - * @param string $hash Password hash that should be checked - * - * @return object|bool The hash type object or false if the specified - * type is not supported - */ - public function detect_algorithm($hash) - { - /* - * preg_match() will also show hashing algos like $2a\H$, which - * is a combination of bcrypt and phpass. Legacy algorithms - * like md5 will not be matched by this and need to be treated - * differently. - */ - if (!preg_match('#^\$([a-zA-Z0-9\\\]*?)\$#', $hash, $match)) - { - 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 && strpos($match[1], '\\') !== false) - { - $hash_types = explode('\\', $match[1]); - $return_ary = array(); - foreach ($hash_types as $type) - { - // we do not support the same hashing - // algorithm more than once - if (isset($return_ary[$type])) - { - return false; - } - - $return_ary[$type] = $this->get_algorithm('$' . $type . '$'); - - if (empty($return_ary[$type])) - { - return false; - } - } - return $return_ary; - } - - // get_algorithm() will automatically return false if prefix - // is not supported - return $this->get_algorithm($match[0]); - } - - /** - * Hash supplied password - * - * @param string $password Password that should be hashed - * @param string $type Hash type. Will default to standard hash type if - * none is supplied - * @return string|bool Password hash of supplied password or false if - * if something went wrong during hashing - */ - public function hash($password, $type = '') - { - if (strlen($password) > 4096) - { - // If the password is too huge, we will simply reject it - // and not let the server try to hash it. - 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])) - { - $type = $this->algorithms[$type]->get_prefix(); - } - - $type = ($type === '') ? $this->type : $type; - - if (is_array($type)) - { - return $this->combined_hash_password($password, $type); - } - - if (isset($this->type_map[$type])) - { - $hashing_algorithm = $this->type_map[$type]; - } - else - { - return false; - } - - return $hashing_algorithm->hash($password); - } - - /** - * Check supplied password against hash and set convert_flag if password - * needs to be converted to different format (preferably newer one) - * - * @param string $password Password that should be checked - * @param string $hash Stored hash - * @param array $user_row User's row in users table - * @return string|bool True if password is correct, false if not - */ - public function check($password, $hash, $user_row = array()) - { - if (strlen($password) > 4096) - { - // If the password is too huge, we will simply reject it - // and not let the server try to hash it. - return false; - } - - // Empty hashes can't be checked - if (empty($hash)) - { - 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) - { - // Still check MD5 hashes as that is what the installer - // will default to for the admin user - return $this->get_algorithm('$H$')->check($password, $hash); - } - - // Multiple hash passes needed - if (is_array($stored_hash_type)) - { - $correct = $this->check_combined_hash($password, $stored_hash_type, $hash); - $this->convert_flag = ($correct === true) ? true : false; - return $correct; - } - - if ($stored_hash_type->get_prefix() !== $this->type) - { - $this->convert_flag = true; - } - else - { - 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$ - if ($stored_hash_type->get_prefix() === '$CP$') - { - // Remove $CP$ prefix for proper checking - $hash = substr($hash, 4); - - foreach ($this->type_map as $algorithm) - { - if ($algorithm->is_legacy() && $algorithm->check($password, $hash, $user_row) === true) - { - return true; - } - } - } - - return $stored_hash_type->check($password, $hash); - } - - /** - * Create combined hash from already hashed password - * - * @param string $password_hash Complete current password hash - * @param string $type Type of the hashing algorithm the password hash - * should be combined with - * @return string|bool Combined password hash if combined hashing was - * successful, else false - */ - public function combined_hash_password($password_hash, $type) - { - $this->initialize(); - - $data = array( - 'prefix' => '$', - 'settings' => '$', - ); - $hash_settings = $this->helper->get_combined_hash_settings($password_hash); - $hash = $hash_settings[0]; - - // Put settings of current hash into data array - $stored_hash_type = $this->detect_algorithm($password_hash); - $this->helper->combine_hash_output($data, 'prefix', $stored_hash_type->get_prefix()); - $this->helper->combine_hash_output($data, 'settings', $stored_hash_type->get_settings_only($password_hash)); - - // Hash current hash with the defined types - foreach ($type as $cur_type) - { - if (isset($this->algorithms[$cur_type])) - { - $new_hash_type = $this->algorithms[$cur_type]; - } - else - { - $new_hash_type = $this->get_algorithm($cur_type); - } - - if (!$new_hash_type) - { - return false; - } - - $new_hash = $new_hash_type->hash(str_replace($stored_hash_type->get_settings_only($password_hash), '', $hash)); - $this->helper->combine_hash_output($data, 'prefix', $new_hash_type->get_prefix()); - $this->helper->combine_hash_output($data, 'settings', substr(str_replace('$', '\\', $new_hash_type->get_settings_only($new_hash, true)), 0)); - $hash = str_replace($new_hash_type->get_settings_only($new_hash), '', $this->helper->obtain_hash_only($new_hash)); - } - return $this->helper->combine_hash_output($data, 'hash', $hash); - } - - /** - * Check combined password hash against the supplied password - * - * @param string $password Password entered by user - * @param array $stored_hash_type An array containing the hash types - * as described by stored password hash - * @param string $hash Stored password hash - * - * @return bool True if password is correct, false if not - */ - public function check_combined_hash($password, $stored_hash_type, $hash) - { - $i = 0; - $data = array( - 'prefix' => '$', - 'settings' => '$', - ); - $hash_settings = $this->helper->get_combined_hash_settings($hash); - foreach ($stored_hash_type as $key => $hash_type) - { - $rebuilt_hash = $this->helper->rebuild_hash($hash_type->get_prefix(), $hash_settings[$i]); - $this->helper->combine_hash_output($data, 'prefix', $key); - $this->helper->combine_hash_output($data, 'settings', $hash_settings[$i]); - $cur_hash = $hash_type->hash($password, $rebuilt_hash); - $password = str_replace($rebuilt_hash, '', $cur_hash); - $i++; - } - return ($hash === $this->helper->combine_hash_output($data, 'hash', $password)); - } -} diff --git a/install/update/new/phpbb/permissions.php b/install/update/new/phpbb/permissions.php deleted file mode 100644 index 236535c..0000000 --- a/install/update/new/phpbb/permissions.php +++ /dev/null @@ -1,365 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -class permissions -{ - /** - * Event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Constructor - * - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher - * @param \phpbb\user $user User Object - */ - public function __construct(\phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\user $user) - { - $this->dispatcher = $phpbb_dispatcher; - $this->user = $user; - - $categories = $this->categories; - $types = $this->types; - $permissions = $this->permissions; - - /** - * Allows to specify additional permission categories, types and permissions - * - * @event core.permissions - * @var array types Array with permission types (a_, u_, m_, etc.) - * @var array categories Array with permission categories (pm, post, settings, misc, etc.) - * @var array permissions Array with permissions. Each Permission has the following layout: - * '' => array( - * 'lang' => 'Language Key with a Short description', // Optional, if not set, - * // the permissions identifier '' is used with - * // all uppercase. - * 'cat' => 'Identifier of the category, the permission should be displayed in', - * ), - * Example: - * 'u_viewprofile' => array( - * 'lang' => 'ACL_U_VIEWPROFILE', - * 'cat' => 'profile', - * ), - * @since 3.1.0-a1 - */ - $vars = array('types', 'categories', 'permissions'); - extract($phpbb_dispatcher->trigger_event('core.permissions', compact($vars))); - - $this->categories = $categories; - $this->types = $types; - $this->permissions = $permissions; - } - - /** - * Returns an array with all the permission categories (pm, post, settings, misc, etc.) - * - * @return array Layout: cat-identifier => Language key - */ - public function get_categories() - { - return $this->categories; - } - - /** - * Returns the language string of a permission category - * - * @param string $category Identifier of the category - * @return string Language string - */ - public function get_category_lang($category) - { - return $this->user->lang($this->categories[$category]); - } - - /** - * Returns an array with all the permission types (a_, u_, m_, etc.) - * - * @return array Layout: type-identifier => Language key - */ - public function get_types() - { - return $this->types; - } - - /** - * Returns the language string of a permission type - * - * @param string $type Identifier of the type - * @param mixed $scope Scope of the type (should be 'global', 'local' or false) - * @return string Language string - */ - public function get_type_lang($type, $scope = false) - { - if ($scope && isset($this->types[$scope][$type])) - { - $lang_key = $this->types[$scope][$type]; - } - else if (isset($this->types[$type])) - { - $lang_key = $this->types[$type]; - } - else - { - $lang_key = 'ACL_TYPE_' . strtoupper(($scope) ? $scope . '_' . $type : $type); - } - - return $this->user->lang($lang_key); - } - - /** - * Returns an array with all the permissions. - * Each Permission has the following layout: - * '' => array( - * 'lang' => 'Language Key with a Short description', // Optional, if not set, - * // the permissions identifier '' is used with - * // all uppercase. - * 'cat' => 'Identifier of the category, the permission should be displayed in', - * ), - * Example: - * 'u_viewprofile' => array( - * 'lang' => 'ACL_U_VIEWPROFILE', - * 'cat' => 'profile', - * ), - * - * @return array - */ - public function get_permissions() - { - return $this->permissions; - } - - /** - * Returns the category of a permission - * - * @param string $permission Identifier of the permission - * @return string Returns the category identifier of the permission - */ - public function get_permission_category($permission) - { - return (isset($this->permissions[$permission]['cat'])) ? $this->permissions[$permission]['cat'] : 'misc'; - } - - /** - * Checks if a category has been defined - * - * @param string $category Identifier of the category - * @return bool True if the category is defined, false otherwise - */ - public function category_defined($category) - { - return isset($this->categories[$category]); - } - - /** - * Checks if a permission has been defined - * - * @param string $permission Identifier of the permission - * @return bool True if the permission is defined, false otherwise - */ - public function permission_defined($permission) - { - return isset($this->permissions[$permission]); - } - - /** - * Returns the language string of a permission - * - * @param string $permission Identifier of the permission - * @return string Language string - */ - public function get_permission_lang($permission) - { - return (isset($this->permissions[$permission]['lang'])) ? $this->user->lang($this->permissions[$permission]['lang']) : $this->user->lang('ACL_' . strtoupper($permission)); - } - - protected $types = array( - 'u_' => 'ACL_TYPE_U_', - 'a_' => 'ACL_TYPE_A_', - 'm_' => 'ACL_TYPE_M_', - 'f_' => 'ACL_TYPE_F_', - 'global' => array( - 'm_' => 'ACL_TYPE_GLOBAL_M_', - ), - ); - - protected $categories = array( - 'actions' => 'ACL_CAT_ACTIONS', - 'content' => 'ACL_CAT_CONTENT', - 'forums' => 'ACL_CAT_FORUMS', - 'misc' => 'ACL_CAT_MISC', - 'permissions' => 'ACL_CAT_PERMISSIONS', - 'pm' => 'ACL_CAT_PM', - 'polls' => 'ACL_CAT_POLLS', - 'post' => 'ACL_CAT_POST', - 'post_actions' => 'ACL_CAT_POST_ACTIONS', - 'posting' => 'ACL_CAT_POSTING', - 'profile' => 'ACL_CAT_PROFILE', - 'settings' => 'ACL_CAT_SETTINGS', - 'topic_actions' => 'ACL_CAT_TOPIC_ACTIONS', - 'user_group' => 'ACL_CAT_USER_GROUP', - ); - - protected $permissions = array( - // User Permissions - 'u_viewprofile' => array('lang' => 'ACL_U_VIEWPROFILE', 'cat' => 'profile'), - 'u_chgname' => array('lang' => 'ACL_U_CHGNAME', 'cat' => 'profile'), - 'u_chgpasswd' => array('lang' => 'ACL_U_CHGPASSWD', 'cat' => 'profile'), - 'u_chgemail' => array('lang' => 'ACL_U_CHGEMAIL', 'cat' => 'profile'), - 'u_chgavatar' => array('lang' => 'ACL_U_CHGAVATAR', 'cat' => 'profile'), - 'u_chggrp' => array('lang' => 'ACL_U_CHGGRP', 'cat' => 'profile'), - 'u_chgprofileinfo' => array('lang' => 'ACL_U_CHGPROFILEINFO', 'cat' => 'profile'), - - 'u_attach' => array('lang' => 'ACL_U_ATTACH', 'cat' => 'post'), - 'u_download' => array('lang' => 'ACL_U_DOWNLOAD', 'cat' => 'post'), - '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'), - 'u_masspm_group'=> array('lang' => 'ACL_U_MASSPM_GROUP', 'cat' => 'pm'), - 'u_readpm' => array('lang' => 'ACL_U_READPM', 'cat' => 'pm'), - 'u_pm_edit' => array('lang' => 'ACL_U_PM_EDIT', 'cat' => 'pm'), - 'u_pm_delete' => array('lang' => 'ACL_U_PM_DELETE', 'cat' => 'pm'), - 'u_pm_forward' => array('lang' => 'ACL_U_PM_FORWARD', 'cat' => 'pm'), - 'u_pm_emailpm' => array('lang' => 'ACL_U_PM_EMAILPM', 'cat' => 'pm'), - 'u_pm_printpm' => array('lang' => 'ACL_U_PM_PRINTPM', 'cat' => 'pm'), - 'u_pm_attach' => array('lang' => 'ACL_U_PM_ATTACH', 'cat' => 'pm'), - 'u_pm_download' => array('lang' => 'ACL_U_PM_DOWNLOAD', 'cat' => 'pm'), - 'u_pm_bbcode' => array('lang' => 'ACL_U_PM_BBCODE', 'cat' => 'pm'), - 'u_pm_smilies' => array('lang' => 'ACL_U_PM_SMILIES', 'cat' => 'pm'), - 'u_pm_img' => array('lang' => 'ACL_U_PM_IMG', 'cat' => 'pm'), - 'u_pm_flash' => array('lang' => 'ACL_U_PM_FLASH', 'cat' => 'pm'), - - 'u_sendemail' => array('lang' => 'ACL_U_SENDEMAIL', 'cat' => 'misc'), - 'u_sendim' => array('lang' => 'ACL_U_SENDIM', 'cat' => 'misc'), - 'u_ignoreflood' => array('lang' => 'ACL_U_IGNOREFLOOD', 'cat' => 'misc'), - 'u_hideonline' => array('lang' => 'ACL_U_HIDEONLINE', 'cat' => 'misc'), - 'u_viewonline' => array('lang' => 'ACL_U_VIEWONLINE', 'cat' => 'misc'), - 'u_search' => array('lang' => 'ACL_U_SEARCH', 'cat' => 'misc'), - - // 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'), - 'f_print' => array('lang' => 'ACL_F_PRINT', 'cat' => 'actions'), - 'f_email' => array('lang' => 'ACL_F_EMAIL', 'cat' => 'actions'), - 'f_bump' => array('lang' => 'ACL_F_BUMP', 'cat' => 'actions'), - 'f_user_lock' => array('lang' => 'ACL_F_USER_LOCK', 'cat' => 'actions'), - 'f_download' => array('lang' => 'ACL_F_DOWNLOAD', 'cat' => 'actions'), - 'f_report' => array('lang' => 'ACL_F_REPORT', 'cat' => 'actions'), - - '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'), - 'f_softdelete' => array('lang' => 'ACL_F_SOFTDELETE', 'cat' => 'post'), - 'f_ignoreflood' => array('lang' => 'ACL_F_IGNOREFLOOD', 'cat' => 'post'), - 'f_postcount' => array('lang' => 'ACL_F_POSTCOUNT', 'cat' => 'post'), - 'f_noapprove' => array('lang' => 'ACL_F_NOAPPROVE', 'cat' => 'post'), - - 'f_attach' => array('lang' => 'ACL_F_ATTACH', 'cat' => 'content'), - 'f_icons' => array('lang' => 'ACL_F_ICONS', 'cat' => 'content'), - 'f_bbcode' => array('lang' => 'ACL_F_BBCODE', 'cat' => 'content'), - 'f_flash' => array('lang' => 'ACL_F_FLASH', 'cat' => 'content'), - 'f_img' => array('lang' => 'ACL_F_IMG', 'cat' => 'content'), - 'f_sigs' => array('lang' => 'ACL_F_SIGS', 'cat' => 'content'), - 'f_smilies' => array('lang' => 'ACL_F_SMILIES', 'cat' => 'content'), - - 'f_poll' => array('lang' => 'ACL_F_POLL', 'cat' => 'polls'), - 'f_vote' => array('lang' => 'ACL_F_VOTE', 'cat' => 'polls'), - 'f_votechg' => array('lang' => 'ACL_F_VOTECHG', 'cat' => 'polls'), - - // Moderator Permissions - 'm_edit' => array('lang' => 'ACL_M_EDIT', 'cat' => 'post_actions'), - 'm_delete' => array('lang' => 'ACL_M_DELETE', 'cat' => 'post_actions'), - 'm_approve' => array('lang' => 'ACL_M_APPROVE', 'cat' => 'post_actions'), - 'm_report' => array('lang' => 'ACL_M_REPORT', 'cat' => 'post_actions'), - 'm_chgposter' => array('lang' => 'ACL_M_CHGPOSTER', 'cat' => 'post_actions'), - 'm_info' => array('lang' => 'ACL_M_INFO', 'cat' => 'post_actions'), - 'm_softdelete' => array('lang' => 'ACL_M_SOFTDELETE', 'cat' => 'post_actions'), - - 'm_move' => array('lang' => 'ACL_M_MOVE', 'cat' => 'topic_actions'), - 'm_lock' => array('lang' => 'ACL_M_LOCK', 'cat' => 'topic_actions'), - 'm_split' => array('lang' => 'ACL_M_SPLIT', 'cat' => 'topic_actions'), - 'm_merge' => array('lang' => 'ACL_M_MERGE', 'cat' => 'topic_actions'), - - 'm_warn' => array('lang' => 'ACL_M_WARN', 'cat' => 'misc'), - 'm_pm_report' => array('lang' => 'ACL_M_PM_REPORT', 'cat' => 'misc'), - 'm_ban' => array('lang' => 'ACL_M_BAN', 'cat' => 'misc'), - - // Admin Permissions - 'a_board' => array('lang' => 'ACL_A_BOARD', 'cat' => 'settings'), - 'a_server' => array('lang' => 'ACL_A_SERVER', 'cat' => 'settings'), - 'a_jabber' => array('lang' => 'ACL_A_JABBER', 'cat' => 'settings'), - 'a_phpinfo' => array('lang' => 'ACL_A_PHPINFO', 'cat' => 'settings'), - - 'a_forum' => array('lang' => 'ACL_A_FORUM', 'cat' => 'forums'), - 'a_forumadd' => array('lang' => 'ACL_A_FORUMADD', 'cat' => 'forums'), - 'a_forumdel' => array('lang' => 'ACL_A_FORUMDEL', 'cat' => 'forums'), - 'a_prune' => array('lang' => 'ACL_A_PRUNE', 'cat' => 'forums'), - - 'a_icons' => array('lang' => 'ACL_A_ICONS', 'cat' => 'posting'), - 'a_words' => array('lang' => 'ACL_A_WORDS', 'cat' => 'posting'), - 'a_bbcode' => array('lang' => 'ACL_A_BBCODE', 'cat' => 'posting'), - 'a_attach' => array('lang' => 'ACL_A_ATTACH', 'cat' => 'posting'), - - 'a_user' => array('lang' => 'ACL_A_USER', 'cat' => 'user_group'), - 'a_userdel' => array('lang' => 'ACL_A_USERDEL', 'cat' => 'user_group'), - 'a_group' => array('lang' => 'ACL_A_GROUP', 'cat' => 'user_group'), - 'a_groupadd' => array('lang' => 'ACL_A_GROUPADD', 'cat' => 'user_group'), - 'a_groupdel' => array('lang' => 'ACL_A_GROUPDEL', 'cat' => 'user_group'), - 'a_ranks' => array('lang' => 'ACL_A_RANKS', 'cat' => 'user_group'), - 'a_profile' => array('lang' => 'ACL_A_PROFILE', 'cat' => 'user_group'), - 'a_names' => array('lang' => 'ACL_A_NAMES', 'cat' => 'user_group'), - 'a_ban' => array('lang' => 'ACL_A_BAN', 'cat' => 'user_group'), - - 'a_viewauth' => array('lang' => 'ACL_A_VIEWAUTH', 'cat' => 'permissions'), - 'a_authgroups' => array('lang' => 'ACL_A_AUTHGROUPS', 'cat' => 'permissions'), - 'a_authusers' => array('lang' => 'ACL_A_AUTHUSERS', 'cat' => 'permissions'), - 'a_fauth' => array('lang' => 'ACL_A_FAUTH', 'cat' => 'permissions'), - 'a_mauth' => array('lang' => 'ACL_A_MAUTH', 'cat' => 'permissions'), - 'a_aauth' => array('lang' => 'ACL_A_AAUTH', 'cat' => 'permissions'), - 'a_uauth' => array('lang' => 'ACL_A_UAUTH', 'cat' => 'permissions'), - 'a_roles' => array('lang' => 'ACL_A_ROLES', 'cat' => 'permissions'), - 'a_switchperm' => array('lang' => 'ACL_A_SWITCHPERM', 'cat' => 'permissions'), - - 'a_styles' => array('lang' => 'ACL_A_STYLES', 'cat' => 'misc'), - 'a_extensions' => array('lang' => 'ACL_A_EXTENSIONS', 'cat' => 'misc'), - 'a_viewlogs' => array('lang' => 'ACL_A_VIEWLOGS', 'cat' => 'misc'), - 'a_clearlogs' => array('lang' => 'ACL_A_CLEARLOGS', 'cat' => 'misc'), - 'a_modules' => array('lang' => 'ACL_A_MODULES', 'cat' => 'misc'), - 'a_language' => array('lang' => 'ACL_A_LANGUAGE', 'cat' => 'misc'), - 'a_email' => array('lang' => 'ACL_A_EMAIL', 'cat' => 'misc'), - 'a_bots' => array('lang' => 'ACL_A_BOTS', 'cat' => 'misc'), - 'a_reasons' => array('lang' => 'ACL_A_REASONS', 'cat' => 'misc'), - 'a_backup' => array('lang' => 'ACL_A_BACKUP', 'cat' => 'misc'), - 'a_search' => array('lang' => 'ACL_A_SEARCH', 'cat' => 'misc'), - ); -} diff --git a/install/update/new/phpbb/plupload/plupload.php b/install/update/new/phpbb/plupload/plupload.php deleted file mode 100644 index 80d7e91..0000000 --- a/install/update/new/phpbb/plupload/plupload.php +++ /dev/null @@ -1,417 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\plupload; - -/** -* This class handles all server-side plupload functions -*/ -class plupload -{ - /** - * @var string - */ - protected $phpbb_root_path; - - /** - * @var \phpbb\config\config - */ - protected $config; - - /** - * @var \phpbb\request\request_interface - */ - protected $request; - - /** - * @var \phpbb\user - */ - protected $user; - - /** - * @var \bantu\IniGetWrapper\IniGetWrapper - */ - protected $php_ini; - - /** - * @var \phpbb\mimetype\guesser - */ - protected $mimetype_guesser; - - /** - * Final destination for uploaded files, i.e. the "files" directory. - * @var string - */ - protected $upload_directory; - - /** - * Temporary upload directory for plupload uploads. - * @var string - */ - protected $temporary_directory; - - /** - * Constructor. - * - * @param string $phpbb_root_path - * @param \phpbb\config\config $config - * @param \phpbb\request\request_interface $request - * @param \phpbb\user $user - * @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, \bantu\IniGetWrapper\IniGetWrapper $php_ini, \phpbb\mimetype\guesser $mimetype_guesser) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->config = $config; - $this->request = $request; - $this->user = $user; - $this->php_ini = $php_ini; - $this->mimetype_guesser = $mimetype_guesser; - - $this->set_default_directories(); - } - - /** - * Plupload allows for chunking so we must check for that and assemble - * the whole file first before performing any checks on it. - * - * @param string $form_name The name of the file element in the upload form - * - * @return array|null null if there are no chunks to piece together - * otherwise array containing the path to the - * pieced-together file and its size - */ - public function handle_upload($form_name) - { - $chunks_expected = $this->request->variable('chunks', 0); - - // If chunking is disabled or we are not using plupload, just return - // and handle the file as usual - if ($chunks_expected < 2) - { - return; - } - - $file_name = $this->request->variable('name', ''); - $chunk = $this->request->variable('chunk', 0); - - $this->user->add_lang('plupload'); - $this->prepare_temporary_directory(); - - $file_path = $this->temporary_filepath($file_name); - $this->integrate_uploaded_file($form_name, $chunk, $file_path); - - // If we are done with all the chunks, strip the .part suffix and then - // handle the resulting file as normal, otherwise die and await the - // next chunk. - if ($chunk == $chunks_expected - 1) - { - rename("{$file_path}.part", $file_path); - - // Reset upload directories to defaults once completed - $this->set_default_directories(); - - // Need to modify some of the $_FILES values to reflect the new file - return array( - 'tmp_name' => $file_path, - 'name' => $this->request->variable('real_filename', '', true), - 'size' => filesize($file_path), - 'type' => $this->mimetype_guesser->guess($file_path, $file_name), - ); - } - else - { - $json_response = new \phpbb\json_response(); - $json_response->send(array( - 'jsonrpc' => '2.0', - 'id' => 'id', - 'result' => null, - )); - } - } - - /** - * Fill in the plupload configuration options in the template - * - * @param \phpbb\cache\service $cache - * @param \phpbb\template\template $template - * @param string $s_action The URL to submit the POST data to - * @param int $forum_id The ID of the forum - * @param int $max_files Maximum number of files allowed. 0 for unlimited. - * - * @return null - */ - public function configure(\phpbb\cache\service $cache, \phpbb\template\template $template, $s_action, $forum_id, $max_files) - { - $filters = $this->generate_filter_string($cache, $forum_id); - $chunk_size = $this->get_chunk_size(); - $resize = $this->generate_resize_string(); - - $template->assign_vars(array( - 'S_RESIZE' => $resize, - 'S_PLUPLOAD' => true, - 'FILTERS' => $filters, - 'CHUNK_SIZE' => $chunk_size, - 'S_PLUPLOAD_URL' => htmlspecialchars_decode($s_action), - 'MAX_ATTACHMENTS' => $max_files, - 'ATTACH_ORDER' => ($this->config['display_order']) ? 'asc' : 'desc', - 'L_TOO_MANY_ATTACHMENTS' => $this->user->lang('TOO_MANY_ATTACHMENTS', $max_files), - )); - - $this->user->add_lang('plupload'); - } - - /** - * Checks whether the page request was sent by plupload or not - * - * @return bool - */ - public function is_active() - { - return $this->request->header('X-PHPBB-USING-PLUPLOAD', false); - } - - /** - * Returns whether the current HTTP request is a multipart request. - * - * @return bool - */ - public function is_multipart() - { - $content_type = $this->request->server('CONTENT_TYPE'); - - return strpos($content_type, 'multipart') === 0; - } - - /** - * Sends an error message back to the client via JSON response - * - * @param int $code The error code - * @param string $msg The translation string of the message to be sent - * - * @return null - */ - public function emit_error($code, $msg) - { - $json_response = new \phpbb\json_response(); - $json_response->send(array( - 'jsonrpc' => '2.0', - 'id' => 'id', - 'error' => array( - 'code' => $code, - 'message' => $this->user->lang($msg), - ), - )); - } - - /** - * 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_']); - - // Re-arrange the extension array to $groups[$group_name][] - foreach ($attach_extensions as $extension => $extension_info) - { - $groups[$extension_info['group_name']]['extensions'][] = $extension; - $groups[$extension_info['group_name']]['max_file_size'] = (int) $extension_info['max_filesize']; - } - - foreach ($groups as $group => $group_info) - { - $filters[] = sprintf( - "{title: '%s', extensions: '%s', max_file_size: %s}", - addslashes(ucfirst(strtolower($group))), - addslashes(implode(',', $group_info['extensions'])), - $group_info['max_file_size'] - ); - } - - return implode(',', $filters); - } - - /** - * Generates a string that is used to tell plupload to automatically resize - * files before uploading them. - * - * @return string - */ - public function generate_resize_string() - { - $resize = ''; - if ($this->config['img_max_height'] > 0 && $this->config['img_max_width'] > 0) - { - $resize = sprintf( - 'resize: {width: %d, height: %d, quality: 85},', - (int) $this->config['img_max_width'], - (int) $this->config['img_max_height'] - ); - } - - return $resize; - } - - /** - * 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 = 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; - } - } - - return floor($max / 2); - } - - protected function temporary_filepath($file_name) - { - // Must preserve the extension for plupload to work. - return sprintf( - '%s/%s_%s%s', - $this->temporary_directory, - $this->config['plupload_salt'], - md5($file_name), - \phpbb\files\filespec::get_extension($file_name) - ); - } - - /** - * Checks whether the chunk we are about to deal with was actually uploaded - * by PHP and actually exists, if not, it generates an error - * - * @param string $form_name The name of the file in the form data - * @param int $chunk Chunk number - * @param string $file_path File path - * - * @return null - */ - protected function integrate_uploaded_file($form_name, $chunk, $file_path) - { - $is_multipart = $this->is_multipart(); - $upload = $this->request->file($form_name); - if ($is_multipart && (!isset($upload['tmp_name']) || !is_uploaded_file($upload['tmp_name']))) - { - $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED'); - } - - $tmp_file = $this->temporary_filepath($upload['tmp_name']); - - if (!phpbb_is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file)) - { - $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED'); - } - - $out = fopen("{$file_path}.part", $chunk == 0 ? 'wb' : 'ab'); - if (!$out) - { - $this->emit_error(102, 'PLUPLOAD_ERR_OUTPUT'); - } - - $in = fopen(($is_multipart) ? $tmp_file : 'php://input', 'rb'); - if (!$in) - { - $this->emit_error(101, 'PLUPLOAD_ERR_INPUT'); - } - - while ($buf = fread($in, 4096)) - { - fwrite($out, $buf); - } - - fclose($in); - fclose($out); - - if ($is_multipart) - { - unlink($tmp_file); - } - } - - /** - * Creates the temporary directory if it does not already exist. - * - * @return null - */ - protected function prepare_temporary_directory() - { - if (!file_exists($this->temporary_directory)) - { - mkdir($this->temporary_directory); - - copy( - $this->upload_directory . '/index.htm', - $this->temporary_directory . '/index.htm' - ); - } - } - - /** - * Sets the default directories for uploads - * - * @return null - */ - protected function set_default_directories() - { - $this->upload_directory = $this->phpbb_root_path . $this->config['upload_path']; - $this->temporary_directory = $this->upload_directory . '/plupload'; - } - - /** - * Sets the upload directories to the specified paths - * - * @param string $upload_directory Upload directory - * @param string $temporary_directory Temporary directory - * - * @return null - */ - public function set_upload_directories($upload_directory, $temporary_directory) - { - $this->upload_directory = $upload_directory; - $this->temporary_directory = $temporary_directory; - } -} diff --git a/install/update/new/phpbb/report/report_handler.php b/install/update/new/phpbb/report/report_handler.php deleted file mode 100644 index 97acc17..0000000 --- a/install/update/new/phpbb/report/report_handler.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @license 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; - - /** - * Constructor - * - * @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/install/update/new/phpbb/request/request.php b/install/update/new/phpbb/request/request.php deleted file mode 100644 index 4d7bc9e..0000000 --- a/install/update/new/phpbb/request/request.php +++ /dev/null @@ -1,454 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\request; - -/** -* All application input is accessed through this class. -* -* It provides a method to disable access to input data through super globals. -* This should force MOD authors to read about data validation. -*/ -class request implements \phpbb\request\request_interface -{ - /** - * @var array The names of super global variables that this class should protect if super globals are disabled. - */ - protected $super_globals = array( - \phpbb\request\request_interface::POST => '_POST', - \phpbb\request\request_interface::GET => '_GET', - \phpbb\request\request_interface::REQUEST => '_REQUEST', - \phpbb\request\request_interface::COOKIE => '_COOKIE', - \phpbb\request\request_interface::SERVER => '_SERVER', - \phpbb\request\request_interface::FILES => '_FILES', - ); - - /** - * @var array Stores original contents of $_REQUEST array. - */ - protected $original_request = null; - - /** - * @var - */ - protected $super_globals_disabled = false; - - /** - * @var array An associative array that has the value of super global constants as keys and holds their data as values. - */ - protected $input; - - /** - * @var \phpbb\request\type_cast_helper_interface An instance of a type cast helper providing convenience methods for type conversions. - */ - protected $type_cast_helper; - - /** - * Initialises the request class, that means it stores all input data in {@link $input input} - * and then calls {@link \phpbb\request\deactivated_super_global \phpbb\request\deactivated_super_global} - */ - public function __construct(\phpbb\request\type_cast_helper_interface $type_cast_helper = null, $disable_super_globals = true) - { - if ($type_cast_helper) - { - $this->type_cast_helper = $type_cast_helper; - } - else - { - $this->type_cast_helper = new \phpbb\request\type_cast_helper(); - } - - foreach ($this->super_globals as $const => $super_global) - { - $this->input[$const] = isset($GLOBALS[$super_global]) ? $GLOBALS[$super_global] : array(); - } - - // simulate request_order = GP - $this->original_request = $this->input[\phpbb\request\request_interface::REQUEST]; - $this->input[\phpbb\request\request_interface::REQUEST] = $this->input[\phpbb\request\request_interface::POST] + $this->input[\phpbb\request\request_interface::GET]; - - if ($disable_super_globals) - { - $this->disable_super_globals(); - } - } - - /** - * Getter for $super_globals_disabled - * - * @return bool Whether super globals are disabled or not. - */ - public function super_globals_disabled() - { - return $this->super_globals_disabled; - } - - /** - * Disables access of super globals specified in $super_globals. - * This is achieved by overwriting the super globals with instances of {@link \phpbb\request\deactivated_super_global \phpbb\request\deactivated_super_global} - */ - public function disable_super_globals() - { - if (!$this->super_globals_disabled) - { - foreach ($this->super_globals as $const => $super_global) - { - unset($GLOBALS[$super_global]); - $GLOBALS[$super_global] = new \phpbb\request\deactivated_super_global($this, $super_global, $const); - } - - $this->super_globals_disabled = true; - } - } - - /** - * Enables access of super globals specified in $super_globals if they were disabled by {@link disable_super_globals disable_super_globals}. - * This is achieved by making the super globals point to the data stored within this class in {@link $input input}. - */ - public function enable_super_globals() - { - if ($this->super_globals_disabled) - { - foreach ($this->super_globals as $const => $super_global) - { - $GLOBALS[$super_global] = $this->input[$const]; - } - - $GLOBALS['_REQUEST'] = $this->original_request; - - $this->super_globals_disabled = false; - } - } - - /** - * This function allows overwriting or setting a value in one of the super global arrays. - * - * Changes which are performed on the super globals directly will not have any effect on the results of - * other methods this class provides. Using this function should be avoided if possible! It will - * consume twice the the amount of memory of the value - * - * @param string $var_name The name of the variable that shall be overwritten - * @param mixed $value The value which the variable shall contain. - * If this is null the variable will be unset. - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global shall be changed - */ - public function overwrite($var_name, $value, $super_global = \phpbb\request\request_interface::REQUEST) - { - if (!isset($this->super_globals[$super_global])) - { - return; - } - - // setting to null means unsetting - if ($value === null) - { - unset($this->input[$super_global][$var_name]); - if (!$this->super_globals_disabled()) - { - unset($GLOBALS[$this->super_globals[$super_global]][$var_name]); - } - } - else - { - $this->input[$super_global][$var_name] = $value; - if (!$this->super_globals_disabled()) - { - $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value; - } - } - } - - /** - * Central type safe input handling function. - * All variables in GET or POST requests should be retrieved through this function to maximise security. - * - * @param string|array $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global should be used - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ - public function variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST) - { - return $this->_variable($var_name, $default, $multibyte, $super_global, true); - } - - /** - * Get a variable, but without trimming strings. - * Same functionality as variable(), except does not run trim() on strings. - * This method should be used when handling passwords. - * - * @param string|array $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global should be used - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ - public function untrimmed_variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST) - { - return $this->_variable($var_name, $default, $multibyte, $super_global, false); - } - - /** - * {@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 - * whatever). - * - * @param string|array $var_name See \phpbb\request\request_interface::variable - * @param mixed $default See \phpbb\request\request_interface::variable - * - * @return mixed The server variable value. - */ - public function server($var_name, $default = '') - { - $multibyte = true; - - if ($this->is_set($var_name, \phpbb\request\request_interface::SERVER)) - { - return $this->variable($var_name, $default, $multibyte, \phpbb\request\request_interface::SERVER); - } - else - { - $var = getenv($var_name); - $this->type_cast_helper->recursive_set_var($var, $default, $multibyte); - return $var; - } - } - - /** - * Shortcut method to retrieve the value of client HTTP headers. - * - * @param string|array $header_name The name of the header to retrieve. - * @param mixed $default See \phpbb\request\request_interface::variable - * - * @return mixed The header value. - */ - public function header($header_name, $default = '') - { - $var_name = 'HTTP_' . str_replace('-', '_', strtoupper($header_name)); - return $this->server($var_name, $default); - } - - /** - * Shortcut method to retrieve $_FILES variables - * - * @param string $form_name The name of the file input form element - * - * @return array The uploaded file's information or an empty array if the - * variable does not exist in _FILES. - */ - public function file($form_name) - { - return $this->variable($form_name, array('name' => 'none'), true, \phpbb\request\request_interface::FILES); - } - - /** - * Checks whether a certain variable was sent via POST. - * To make sure that a request was sent using POST you should call this function - * on at least one variable. - * - * @param string $name The name of the form variable which should have a - * _p suffix to indicate the check in the code that creates the form too. - * - * @return bool True if the variable was set in a POST request, false otherwise. - */ - public function is_set_post($name) - { - return $this->is_set($name, \phpbb\request\request_interface::POST); - } - - /** - * Checks whether a certain variable is set in one of the super global - * arrays. - * - * @param string $var Name of the variable - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies the super global which shall be checked - * - * @return bool True if the variable was sent as input - */ - public function is_set($var, $super_global = \phpbb\request\request_interface::REQUEST) - { - return isset($this->input[$super_global][$var]); - } - - /** - * Checks whether the current request is an AJAX request (XMLHttpRequest) - * - * @return bool True if the current request is an ajax request - */ - public function is_ajax() - { - return $this->header('X-Requested-With') == 'XMLHttpRequest'; - } - - /** - * Checks if the current request is happening over HTTPS. - * - * @return bool True if the request is secure. - */ - public function is_secure() - { - $https = $this->server('HTTPS'); - $https = $this->server('HTTP_X_FORWARDED_PROTO') === 'https' ? 'on' : $https; - return !empty($https) && $https !== 'off'; - } - - /** - * Returns all variable names for a given super global - * - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * The super global from which names shall be taken - * - * @return array All variable names that are set for the super global. - * Pay attention when using these, they are unsanitised! - */ - public function variable_names($super_global = \phpbb\request\request_interface::REQUEST) - { - if (!isset($this->input[$super_global])) - { - return array(); - } - - return array_keys($this->input[$super_global]); - } - - /** - * Helper function used by variable() and untrimmed_variable(). - * - * @param string|array $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global should be used - * @param bool $trim Indicates whether trim() should be applied to string values. - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ - protected function _variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST, $trim = true) - { - $var = $this->raw_variable($var_name, $default, $super_global); - - // 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 $var; - } - - $this->type_cast_helper->recursive_set_var($var, $default, $multibyte, $trim); - - return $var; - } - - /** - * {@inheritdoc} - */ - public function get_super_global($super_global = \phpbb\request\request_interface::REQUEST) - { - return $this->input[$super_global]; - } - - /** - * {@inheritdoc} - */ - public function escape($var, $multibyte) - { - if (is_array($var)) - { - $result = array(); - foreach ($var as $key => $value) - { - $this->type_cast_helper->set_var($key, $key, gettype($key), $multibyte); - $result[$key] = $this->escape($value, $multibyte); - } - $var = $result; - } - else - { - $this->type_cast_helper->set_var($var, $var, 'string', $multibyte); - } - - return $var; - } -} diff --git a/install/update/new/phpbb/request/request_interface.php b/install/update/new/phpbb/request/request_interface.php deleted file mode 100644 index a1fbf0a..0000000 --- a/install/update/new/phpbb/request/request_interface.php +++ /dev/null @@ -1,177 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\request; - -/** -* An interface through which all application input can be accessed. -*/ -interface request_interface -{ - /**#@+ - * Constant identifying the super global with the same name. - */ - const POST = 0; - const GET = 1; - const REQUEST = 2; - const COOKIE = 3; - const SERVER = 4; - const FILES = 5; - /**#@-*/ - - /** - * This function allows overwriting or setting a value in one of the super global arrays. - * - * Changes which are performed on the super globals directly will not have any effect on the results of - * other methods this class provides. Using this function should be avoided if possible! It will - * consume twice the the amount of memory of the value - * - * @param string $var_name The name of the variable that shall be overwritten - * @param mixed $value The value which the variable shall contain. - * If this is null the variable will be unset. - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global shall be changed - */ - public function overwrite($var_name, $value, $super_global = \phpbb\request\request_interface::REQUEST); - - /** - * Central type safe input handling function. - * All variables in GET or POST requests should be retrieved through this function to maximise security. - * - * @param string|array $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global should be used - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ - public function variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\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 - * @param mixed $default See \phpbb\request\request_interface::variable - * - * @return mixed The server variable value. - */ - public function server($var_name, $default = ''); - - /** - * Shortcut method to retrieve the value of client HTTP headers. - * - * @param string|array $header_name The name of the header to retrieve. - * @param mixed $default See \phpbb\request\request_interface::variable - * - * @return mixed The header value. - */ - public function header($header_name, $default = ''); - - /** - * Checks whether a certain variable was sent via POST. - * To make sure that a request was sent using POST you should call this function - * on at least one variable. - * - * @param string $name The name of the form variable which should have a - * _p suffix to indicate the check in the code that creates the form too. - * - * @return bool True if the variable was set in a POST request, false otherwise. - */ - public function is_set_post($name); - - /** - * Checks whether a certain variable is set in one of the super global - * arrays. - * - * @param string $var Name of the variable - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies the super global which shall be checked - * - * @return bool True if the variable was sent as input - */ - public function is_set($var, $super_global = \phpbb\request\request_interface::REQUEST); - - /** - * Checks whether the current request is an AJAX request (XMLHttpRequest) - * - * @return bool True if the current request is an ajax request - */ - public function is_ajax(); - - /** - * Checks if the current request is happening over HTTPS. - * - * @return bool True if the request is secure. - */ - public function is_secure(); - - /** - * Returns all variable names for a given super global - * - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * The super global from which names shall be taken - * - * @return array All variable names that are set for the super global. - * Pay attention when using these, they are unsanitised! - */ - public function variable_names($super_global = \phpbb\request\request_interface::REQUEST); - - /** - * Returns the original array of the requested super global - * - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * The super global which will be returned - * - * @return array The original array of the requested super global. - */ - public function get_super_global($super_global = \phpbb\request\request_interface::REQUEST); - - /** - * Escape a string variable. - * - * @param mixed $value The contents to fill with - * @param bool $multibyte Indicates whether string values may contain UTF-8 characters. - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks. - * @return string|array - */ - public function escape($value, $multibyte); -} diff --git a/install/update/new/phpbb/request/type_cast_helper.php b/install/update/new/phpbb/request/type_cast_helper.php deleted file mode 100644 index 39d5908..0000000 --- a/install/update/new/phpbb/request/type_cast_helper.php +++ /dev/null @@ -1,125 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\request; - -/** -* A helper class that provides convenience methods for type casting. -*/ -class type_cast_helper implements \phpbb\request\type_cast_helper_interface -{ - /** - * Set variable $result to a particular type. - * - * @param mixed &$result The variable to fill - * @param mixed $var The contents to fill with - * @param mixed $type The variable type. Will be used with {@link settype()} - * @param bool $multibyte Indicates whether string values may contain UTF-8 characters. - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks. - * @param bool $trim Indicates whether trim() should be applied to string values. - * Default is true. - */ - public function set_var(&$result, $var, $type, $multibyte = false, $trim = true) - { - settype($var, $type); - $result = $var; - - if ($type == 'string') - { - $result = str_replace(array("\r\n", "\r", "\0"), array("\n", "\n", ''), $result); - - if ($trim) - { - $result = trim($result); - } - - $result = htmlspecialchars($result, ENT_COMPAT, 'UTF-8'); - - if ($multibyte) - { - $result = utf8_normalize_nfc($result); - } - - if (!empty($result)) - { - // Make sure multibyte characters are wellformed - if ($multibyte) - { - if (!preg_match('/^./u', $result)) - { - $result = ''; - } - } - else - { - // no multibyte, allow only ASCII (0-127) - $result = preg_replace('/[\x80-\xFF]/', '?', $result); - } - } - } - } - - /** - * Recursively sets a variable to a given type using {@link set_var set_var} - * - * @param string $var The value which shall be sanitised (passed by reference). - * @param mixed $default Specifies the type $var shall have. - * If it is an array and $var is not one, then an empty array is returned. - * Otherwise var is cast to the same type, and if $default is an array all - * keys and values are cast recursively using this function too. - * @param bool $multibyte Indicates whether string keys and values may contain UTF-8 characters. - * Default is false, causing all bytes outside the ASCII range (0-127) to - * be replaced with question marks. - * @param bool $trim Indicates whether trim() should be applied to string values. - * Default is true. - */ - public function recursive_set_var(&$var, $default, $multibyte, $trim = true) - { - if (is_array($var) !== is_array($default)) - { - $var = (is_array($default)) ? array() : $default; - return; - } - - if (!is_array($default)) - { - $type = gettype($default); - $this->set_var($var, $var, $type, $multibyte, $trim); - } - else - { - // make sure there is at least one key/value pair to use get the - // types from - if (empty($default)) - { - $var = array(); - return; - } - - $default_key = key($default); - $default_value = current($default); - $key_type = gettype($default_key); - - $_var = $var; - $var = array(); - - foreach ($_var as $k => $v) - { - $this->set_var($k, $k, $key_type, $multibyte); - - $this->recursive_set_var($v, $default_value, $multibyte, $trim); - $var[$k] = $v; - } - } - } -} diff --git a/install/update/new/phpbb/search/fulltext_mysql.php b/install/update/new/phpbb/search/fulltext_mysql.php deleted file mode 100644 index 42ac6ea..0000000 --- a/install/update/new/phpbb/search/fulltext_mysql.php +++ /dev/null @@ -1,1220 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\search; - -/** -* Fulltext search for MySQL -*/ -class fulltext_mysql extends \phpbb\search\base -{ - /** - * Associative array holding index stats - * @var array - */ - protected $stats = array(); - - /** - * Holds the words entered by user, obtained by splitting the entered query on whitespace - * @var array - */ - protected $split_words = array(); - - /** - * Config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Database connection - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Associative array stores the min and max word length to be searched - * @var array - */ - protected $word_length = array(); - - /** - * Contains tidied search query. - * Operators are prefixed in search query and common words excluded - * @var string - */ - protected $search_query; - - /** - * Contains common words. - * Common words are words with length less/more than min/max length - * @var array - */ - protected $common_words = array(); - - /** - * Constructor - * Creates a new \phpbb\search\fulltext_mysql, which is used as a search backend - * - * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $phpEx PHP file extension - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\user $user User object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - */ - public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) - { - $this->config = $config; - $this->db = $db; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->user = $user; - - $this->word_length = array('min' => $this->config['fulltext_mysql_min_word_len'], 'max' => $this->config['fulltext_mysql_max_word_len']); - - /** - * Load the UTF tools - */ - if (!function_exists('utf8_strlen')) - { - include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - } - - $error = false; - } - - /** - * Returns the name of this search backend to be displayed to administrators - * - * @return string Name - */ - public function get_name() - { - return 'MySQL Fulltext'; - } - - /** - * Returns the search_query - * - * @return string search query - */ - public function get_search_query() - { - return $this->search_query; - } - - /** - * Returns the common_words array - * - * @return array common words that are ignored by search backend - */ - public function get_common_words() - { - return $this->common_words; - } - - /** - * Returns the word_length array - * - * @return array min and max word length for searching - */ - public function get_word_length() - { - return $this->word_length; - } - - /** - * Checks for correct MySQL version and stores min/max word length in the config - * - * @return string|bool Language key of the error/incompatibility occurred - */ - public function init() - { - if ($this->db->get_sql_layer() != 'mysqli') - { - return $this->user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE']; - } - - $result = $this->db->sql_query('SHOW TABLE STATUS LIKE \'' . POSTS_TABLE . '\''); - $info = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - $engine = ''; - if (isset($info['Engine'])) - { - $engine = $info['Engine']; - } - else if (isset($info['Type'])) - { - $engine = $info['Type']; - } - - $fulltext_supported = - $engine === 'MyISAM' || - // FULLTEXT is supported on InnoDB since MySQL 5.6.4 according to - // http://dev.mysql.com/doc/refman/5.6/en/innodb-storage-engine.html - // We also require https://bugs.mysql.com/bug.php?id=67004 to be - // fixed for proper overall operation. Hence we require 5.6.8. - $engine === 'InnoDB' && - phpbb_version_compare($this->db->sql_server_info(true), '5.6.8', '>='); - - if (!$fulltext_supported) - { - return $this->user->lang['FULLTEXT_MYSQL_NOT_SUPPORTED']; - } - - $sql = 'SHOW VARIABLES - LIKE \'%ft\_%\''; - $result = $this->db->sql_query($sql); - - $mysql_info = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $mysql_info[$row['Variable_name']] = $row['Value']; - } - $this->db->sql_freeresult($result); - - 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; - } - - /** - * Splits keywords entered by a user into an array of words stored in $this->split_words - * Stores the tidied search query in $this->search_query - * - * @param string &$keywords Contains the keyword as entered by the user - * @param string $terms is either 'all' or 'any' - * @return bool false if no valid keywords were found and otherwise true - */ - public function split_keywords(&$keywords, $terms) - { - if ($terms == 'all') - { - $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#(^|\s)\+#', '#(^|\s)-#', '#(^|\s)\|#'); - $replace = array(' +', ' |', ' -', ' +', ' -', ' |'); - - $keywords = preg_replace($match, $replace, $keywords); - } - - // Filter out as above - $split_keywords = preg_replace("#[\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords))); - - // Split words - $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches); - $this->split_words = $matches[1]; - - // We limit the number of allowed keywords to minimize load on the database - if ($this->config['max_num_search_keywords'] && 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'], count($this->split_words))); - } - - // to allow phrase search, we need to concatenate quoted words - $tmp_split_words = array(); - $phrase = ''; - foreach ($this->split_words as $word) - { - if ($phrase) - { - $phrase .= ' ' . $word; - if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1) - { - $tmp_split_words[] = $phrase; - $phrase = ''; - } - } - else if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1) - { - $phrase = $word; - } - else - { - $tmp_split_words[] = $word; - } - } - if ($phrase) - { - $tmp_split_words[] = $phrase; - } - - $this->split_words = $tmp_split_words; - - unset($tmp_split_words); - unset($phrase); - - foreach ($this->split_words as $i => $word) - { - // Check for not allowed search queries for InnoDB. - // We assume similar restrictions for MyISAM, which is usually even - // slower but not as restrictive as InnoDB. - // InnoDB full-text search does not support the use of a leading - // plus sign with wildcard ('+*'), a plus and minus sign - // combination ('+-'), or leading a plus and minus sign combination. - // InnoDB full-text search only supports leading plus or minus signs. - // For example, InnoDB supports '+apple' but does not support 'apple+'. - // Specifying a trailing plus or minus sign causes InnoDB to report - // a syntax error. InnoDB full-text search does not support the use - // of multiple operators on a single search word, as in this example: - // '++apple'. Use of multiple operators on a single search word - // returns a syntax error to standard out. - // Also, ensure that the wildcard character is only used at the - // end of the line as it's intended by MySQL. - if (preg_match('#^(\+[+-]|\+\*|.+[+-]$|.+\*(?!$))#', $word)) - { - unset($this->split_words[$i]); - continue; - } - - $clean_word = preg_replace('#^[+\-|"]#', '', $word); - - // check word length - $clean_len = utf8_strlen(str_replace('*', '', $clean_word)); - if (($clean_len < $this->config['fulltext_mysql_min_word_len']) || ($clean_len > $this->config['fulltext_mysql_max_word_len'])) - { - $this->common_words[] = $word; - unset($this->split_words[$i]); - } - } - - if ($terms == 'any') - { - $this->search_query = ''; - foreach ($this->split_words as $word) - { - if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0)) - { - $word = substr($word, 1); - } - $this->search_query .= $word . ' '; - } - } - else - { - $this->search_query = ''; - foreach ($this->split_words as $word) - { - if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0)) - { - $this->search_query .= $word . ' '; - } - else if (strpos($word, '|') === 0) - { - $this->search_query .= substr($word, 1) . ' '; - } - else - { - $this->search_query .= '+' . $word . ' '; - } - } - } - - $this->search_query = utf8_htmlspecialchars($this->search_query); - - if ($this->search_query) - { - $this->split_words = array_values($this->split_words); - sort($this->split_words); - return true; - } - return false; - } - - /** - * Turns text into an array of words - * @param string $text contains post text/subject - */ - public function split_message($text) - { - // Split words - $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches); - $text = $matches[1]; - - // remove too short or too long words - $text = array_values($text); - for ($i = 0, $n = 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']) - { - unset($text[$i]); - } - } - - return array_values($text); - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No keywords? No posts - if (!$this->search_query) - { - return false; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - implode(', ', $this->split_words), - $type, - $fields, - $terms, - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary) - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_mysql_by_keyword_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var string fields Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') - * @var string terms Searching terms ('all', 'any') - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'fields', - 'terms', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_by_keyword_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - if ($start < 0) - { - $start = 0; - } - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - $join_topic = ($type == 'posts') ? false : true; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $join_topic = true; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - // Build some display specific sql strings - switch ($fields) - { - case 'titleonly': - $sql_match = 'p.post_subject'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - case 'msgonly': - $sql_match = 'p.post_text'; - $sql_match_where = ''; - break; - - case 'firstpost': - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - default: - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ''; - break; - } - - $search_query = $this->search_query; - - /** - * Allow changing the query used to search for posts using fulltext_mysql - * - * @event core.search_mysql_keywords_main_query_before - * @var string search_query The parsed keywords used for this search - * @var int result_count The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var bool join_topic Weather or not TOPICS_TABLE should be CROSS JOIN'ED - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on (!empty(author_ary) must be true, to be relevant) - * @var array ex_fid_ary Which forums not to search on - * @var int topic_id Limit the search to this topic_id only - * @var string sql_sort_table Extra tables to include in the SQL query. - * Used in conjunction with sql_sort_join - * @var string sql_sort_join SQL conditions to join all the tables used together. - * Used in conjunction with sql_sort_table - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sql_match Which columns to do the search on. - * @var string sql_match_where Extra conditions to use to properly filter the matching process - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'search_query', - 'result_count', - 'join_topic', - 'author_ary', - 'author_name', - 'ex_fid_ary', - 'topic_id', - 'sql_sort_table', - 'sql_sort_join', - 'sort_days', - 'sql_match', - 'sql_match_where', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_keywords_main_query_before', compact($vars))); - - $sql_select = (!$result_count) ? 'SQL_CALC_FOUND_ROWS ' : ''; - $sql_select = ($type == 'posts') ? $sql_select . 'p.post_id' : 'DISTINCT ' . $sql_select . 't.topic_id'; - $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; - $field = ($type == 'posts') ? 'post_id' : 'topic_id'; - if (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 (count($author_ary)) - { - $sql_author = ' AND ' . $this->db->sql_in_set('p.poster_id', $author_ary); - } - else - { - $sql_author = ''; - } - - $sql_where_options = $sql_sort_join; - $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; - $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; - $sql_where_options .= (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; - - $sql = "SELECT $sql_select - FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p - WHERE MATCH ($sql_match) AGAINST ('" . $this->db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE) - $sql_where_options - ORDER BY $sql_sort"; - $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)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - - // if the total result count is not cached yet, retrieve it from the db - if (!$result_count && count($id_ary)) - { - $sql_found_rows = 'SELECT FOUND_ROWS() as result_count'; - $result = $this->db->sql_query($sql_found_rows); - $result_count = (int) $this->db->sql_fetchfield('result_count'); - $this->db->sql_freeresult($result); - - if (!$result_count) - { - return false; - } - } - - if ($start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - } - - // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page - $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $result_count; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No author? No posts - if (!count($author_ary)) - { - return 0; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - '', - $type, - ($firstpost_only) ? 'firstpost' : '', - '', - '', - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary), - $author_name, - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_mysql_by_author_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var boolean firstpost_only Flag indicating if only topic starting posts are considered - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name The username to search on - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'firstpost_only', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - 'author_name', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_by_author_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - if ($start < 0) - { - $start = 0; - } - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - // Create some display specific sql strings - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); - } - $sql_fora = (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' : ''; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; - $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - $m_approve_fid_sql = ' AND ' . $post_visibility; - - /** - * Allow changing the query used to search for posts by author in fulltext_mysql - * - * @event core.search_mysql_author_query_before - * @var int result_count The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var string sql_sort_table CROSS JOIN'ed table to allow doing the sort chosen - * @var string sql_sort_join Condition to define how to join the CROSS JOIN'ed table specifyed in sql_sort_table - * @var string type Either "posts" or "topics" specifying the type of search being made - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on - * @var string sql_author SQL WHERE condition for the post author ids - * @var int topic_id Limit the search to this topic_id only - * @var string sql_topic_id SQL of topic_id - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var string sort_days Time, in days, that the oldest post showing can have - * @var string sql_time The SQL to search on the time specifyed by sort_days - * @var bool firstpost_only Wether or not to search only on the first post of the topics - * @var string sql_firstpost The SQL with the conditions to join the tables when using firstpost_only - * @var array ex_fid_ary Forum ids that must not be searched on - * @var array sql_fora SQL query for ex_fid_ary - * @var string m_approve_fid_sql WHERE clause condition on post_visibility restrictions - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'result_count', - 'sql_sort_table', - 'sql_sort_join', - 'type', - 'author_ary', - 'author_name', - 'sql_author', - 'topic_id', - 'sql_topic_id', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'sort_days', - 'sql_time', - 'firstpost_only', - 'sql_firstpost', - 'ex_fid_ary', - 'sql_fora', - 'm_approve_fid_sql', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_author_query_before', compact($vars))); - - // If the cache was completely empty count the results - $calc_results = ($result_count) ? '' : 'SQL_CALC_FOUND_ROWS '; - - // Build the query for really selecting the post_ids - if ($type == 'posts') - { - $sql = "SELECT {$calc_results}p.post_id - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_sort_join - $sql_time - ORDER BY $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = "SELECT {$calc_results}t.topic_id - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id - ORDER BY $sql_sort"; - $field = 'topic_id'; - } - - // Only read one block of posts from the db and then cache it - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - // retrieve the total result count if needed - if (!$result_count) - { - $sql_found_rows = 'SELECT FOUND_ROWS() as result_count'; - $result = $this->db->sql_query($sql_found_rows); - $result_count = (int) $this->db->sql_fetchfield('result_count'); - $this->db->sql_freeresult($result); - - if (!$result_count) - { - return false; - } - } - - if ($start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - } - - if (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); - - return $result_count; - } - return false; - } - - /** - * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated - * - * @param string $mode contains the post mode: edit, post, reply, quote ... - * @param int $post_id contains the post id of the post to index - * @param string $message contains the post text of the post - * @param string $subject contains the subject of the post to index - * @param int $poster_id contains the user id of the poster - * @param int $forum_id contains the forum id of parent forum of the post - */ - public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - // Split old and new post/subject to obtain array of words - $split_text = $this->split_message($message); - $split_title = ($subject) ? $this->split_message($subject) : array(); - - $words = array_unique(array_merge($split_text, $split_title)); - - /** - * 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); - - // destroy cached search results containing any of the words removed or added - $this->destroy_cache($words, array($poster_id)); - - unset($words); - } - - /** - * Destroy cached results, that might be outdated after deleting a post - */ - public function index_remove($post_ids, $author_ids, $forum_ids) - { - $this->destroy_cache(array(), array_unique($author_ids)); - } - - /** - * Destroy old cache entries - */ - public function tidy() - { - // destroy too old cached search results - $this->destroy_cache(array()); - - $this->config->set('search_last_gc', time(), false); - } - - /** - * Create fulltext index - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function create_index($acp_module, $u_action) - { - // Make sure we can actually use MySQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $alter_list = array(); - - if (!isset($this->stats['post_subject'])) - { - $alter_entry = array(); - $alter_entry[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; - $alter_entry[] = 'ADD FULLTEXT (post_subject)'; - $alter_list[] = $alter_entry; - } - - if (!isset($this->stats['post_content'])) - { - $alter_entry = array(); - $alter_entry[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL'; - $alter_entry[] = 'ADD FULLTEXT post_content (post_text, post_subject)'; - $alter_list[] = $alter_entry; - } - - $sql_queries = []; - - foreach ($alter_list as $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); - - return false; - } - - /** - * Drop fulltext index - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function delete_index($acp_module, $u_action) - { - // Make sure we can actually use MySQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $alter = array(); - - if (isset($this->stats['post_subject'])) - { - $alter[] = 'DROP INDEX post_subject'; - } - - if (isset($this->stats['post_content'])) - { - $alter[] = 'DROP INDEX post_content'; - } - - if (isset($this->stats['post_text'])) - { - $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); - - return false; - } - - /** - * Returns true if both FULLTEXT indexes exist - */ - public function index_created() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return isset($this->stats['post_subject']) && isset($this->stats['post_content']) && isset($this->stats['post_text']); - } - - /** - * Returns an associative array containing information about the indexes - */ - public function index_stats() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return array( - $this->user->lang['FULLTEXT_MYSQL_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0, - ); - } - - /** - * Computes the stats and store them in the $this->stats associative array - */ - protected function get_stats() - { - if (strpos($this->db->get_sql_layer(), 'mysql') === false) - { - $this->stats = array(); - return; - } - - $sql = 'SHOW INDEX - FROM ' . POSTS_TABLE; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - // deal with older MySQL versions which didn't use Index_type - $index_type = (isset($row['Index_type'])) ? $row['Index_type'] : $row['Comment']; - - if ($index_type == 'FULLTEXT') - { - if ($row['Key_name'] == 'post_subject') - { - $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; - } - } - } - $this->db->sql_freeresult($result); - - $this->stats['total_posts'] = empty($this->stats) ? 0 : $this->db->get_estimated_row_count(POSTS_TABLE); - } - - /** - * Display a note, that UTF-8 support is not available with certain versions of PHP - * - * @return associative array containing template and config variables - */ - public function acp() - { - $tpl = ' -
-

' . $this->user->lang['FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN'] . '
-
' . $this->config['fulltext_mysql_min_word_len'] . '
-
-
-

' . $this->user->lang['FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN'] . '
-
' . $this->config['fulltext_mysql_max_word_len'] . '
-
- '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array() - ); - } -} diff --git a/install/update/new/phpbb/search/fulltext_native.php b/install/update/new/phpbb/search/fulltext_native.php deleted file mode 100644 index 23460d3..0000000 --- a/install/update/new/phpbb/search/fulltext_native.php +++ /dev/null @@ -1,2068 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\search; - -/** -* phpBB's own db driven fulltext search, version 2 -*/ -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 - */ - protected $stats = array(); - - /** - * Associative array stores the min and max word length to be searched - * @var array - */ - protected $word_length = array(); - - /** - * Contains tidied search query. - * Operators are prefixed in search query and common words excluded - * @var string - */ - protected $search_query; - - /** - * Contains common words. - * Common words are words with length less/more than min/max length - * @var array - */ - protected $common_words = array(); - - /** - * Post ids of posts containing words that are to be included - * @var array - */ - protected $must_contain_ids = array(); - - /** - * Post ids of posts containing words that should not be included - * @var array - */ - protected $must_not_contain_ids = array(); - - /** - * Post ids of posts containing at least one word that needs to be excluded - * @var array - */ - protected $must_exclude_one_ids = array(); - - /** - * Relative path to board root - * @var string - */ - protected $phpbb_root_path; - - /** - * PHP Extension - * @var string - */ - protected $php_ext; - - /** - * Config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Database connection - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * 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 string $phpbb_root_path phpBB root path - * @param string $phpEx PHP file extension - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\user $user User object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - */ - public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $phpEx; - $this->config = $config; - $this->db = $db; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->user = $user; - - $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 (!function_exists('utf8_decode_ncr')) - { - include($this->phpbb_root_path . 'includes/utf/utf_tools.' . $this->php_ext); - } - - $error = false; - } - - /** - * Returns the name of this search backend to be displayed to administrators - * - * @return string Name - */ - public function get_name() - { - return 'phpBB Native Fulltext'; - } - - /** - * Returns the search_query - * - * @return string search query - */ - public function get_search_query() - { - return $this->search_query; - } - - /** - * Returns the common_words array - * - * @return array common words that are ignored by search backend - */ - public function get_common_words() - { - return $this->common_words; - } - - /** - * Returns the word_length array - * - * @return array min and max word length for searching - */ - public function get_word_length() - { - return $this->word_length; - } - - /** - * This function fills $this->search_query with the cleaned user search query - * - * If $terms is 'any' then the words will be extracted from the search query - * and combined with | inside brackets. They will afterwards be treated like - * an standard search query. - * - * Then it analyses the query and fills the internal arrays $must_not_contain_ids, - * $must_contain_ids and $must_exclude_one_ids which are later used by keyword_search() - * - * @param string $keywords contains the search query string as entered by the user - * @param string $terms is either 'all' (use search query as entered, default words to 'must be contained in post') - * or 'any' (find all posts containing at least one of the given words) - * @return boolean false if no valid keywords were found and otherwise true - */ - public function split_keywords($keywords, $terms) - { - $tokens = '+-|()* '; - - $keywords = trim($this->cleanup($keywords, $tokens)); - - // allow word|word|word without brackets - if ((strpos($keywords, ' ') === false) && (strpos($keywords, '|') !== false) && (strpos($keywords, '(') === false)) - { - $keywords = '(' . $keywords . ')'; - } - - $open_bracket = $space = false; - for ($i = 0, $n = strlen($keywords); $i < $n; $i++) - { - if ($open_bracket !== false) - { - switch ($keywords[$i]) - { - case ')': - if ($open_bracket + 1 == $i) - { - $keywords[$i - 1] = '|'; - $keywords[$i] = '|'; - } - $open_bracket = false; - break; - case '(': - $keywords[$i] = '|'; - break; - case '+': - case '-': - case ' ': - $keywords[$i] = '|'; - break; - case '*': - // $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)) - { - $keywords[$i] = '|'; - } - break; - } - } - else - { - switch ($keywords[$i]) - { - case ')': - $keywords[$i] = ' '; - break; - case '(': - $open_bracket = $i; - $space = false; - break; - case '|': - $keywords[$i] = ' '; - break; - case '-': - case '+': - $space = $keywords[$i]; - break; - case ' ': - if ($space !== false) - { - $keywords[$i] = $space; - } - break; - default: - $space = false; - } - } - } - - if ($open_bracket !== false) - { - $keywords .= ')'; - } - - $match = array( - '# +#', - '#\|\|+#', - '#(\+|\-)(?:\+|\-)+#', - '#\(\|#', - '#\|\)#', - ); - $replace = array( - ' ', - '|', - '$1', - '(', - ')', - ); - - $keywords = preg_replace($match, $replace, $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']) - { - trigger_error($this->user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', (int) $this->config['max_num_search_keywords'], $num_keywords)); - } - - // $keywords input format: each word separated by a space, words in a bracket are not separated - - // the user wants to search for any word, convert the search query - if ($terms == 'any') - { - $words = array(); - - preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $words); - if (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; - - $exact_words = array(); - preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words); - $exact_words = $exact_words[1]; - - $common_ids = $words = array(); - - if (count($exact_words)) - { - $sql = 'SELECT word_id, word_text, word_common - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_text', $exact_words) . ' - ORDER BY word_count ASC'; - $result = $this->db->sql_query($sql); - - // store an array of words and ids, remove common words - while ($row = $this->db->sql_fetchrow($result)) - { - if ($row['word_common']) - { - $this->common_words[] = $row['word_text']; - $common_ids[$row['word_text']] = (int) $row['word_id']; - continue; - } - - $words[$row['word_text']] = (int) $row['word_id']; - } - $this->db->sql_freeresult($result); - } - - // Handle +, - without preceding whitespace character - $match = array('#(\S)\+#', '#(\S)-#'); - $replace = array('$1 +', '$1 +'); - - $keywords = preg_replace($match, $replace, $keywords); - - // now analyse the search query, first split it using the spaces - $query = explode(' ', $keywords); - - $this->must_contain_ids = array(); - $this->must_not_contain_ids = array(); - $this->must_exclude_one_ids = array(); - - foreach ($query as $word) - { - if (empty($word)) - { - continue; - } - - // words which should not be included - if ($word[0] == '-') - { - $word = substr($word, 1); - - // a group of which at least one may not be in the resulting posts - if ($word[0] == '(') - { - $word = array_unique(explode('|', substr($word, 1, -1))); - $mode = 'must_exclude_one'; - } - // one word which should not be in the resulting posts - else - { - $mode = 'must_not_contain'; - } - $ignore_no_id = true; - } - // words which have to be included - else - { - // no prefix is the same as a +prefix - if ($word[0] == '+') - { - $word = substr($word, 1); - } - - // a group of words of which at least one word should be in every resulting post - if ($word[0] == '(') - { - $word = array_unique(explode('|', substr($word, 1, -1))); - } - $ignore_no_id = false; - $mode = 'must_contain'; - } - - if (empty($word)) - { - continue; - } - - // if this is an array of words then retrieve an id for each - if (is_array($word)) - { - $non_common_words = array(); - $id_words = array(); - foreach ($word as $i => $word_part) - { - if (strpos($word_part, '*') !== false) - { - $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])) - { - $id_words[] = $words[$word_part]; - $non_common_words[] = $word_part; - } - else - { - $len = utf8_strlen($word_part); - if ($len < $this->word_length['min'] || $len > $this->word_length['max']) - { - $this->common_words[] = $word_part; - } - } - } - if (count($id_words)) - { - sort($id_words); - if (count($id_words) > 1) - { - $this->{$mode . '_ids'}[] = $id_words; - } - else - { - $mode = ($mode == 'must_exclude_one') ? 'must_not_contain' : $mode; - $this->{$mode . '_ids'}[] = $id_words[0]; - } - } - // throw an error if we shall not ignore unexistant words - else if (!$ignore_no_id && count($non_common_words)) - { - trigger_error(sprintf($this->user->lang['WORDS_IN_NO_POST'], implode($this->user->lang['COMMA_SEPARATOR'], $non_common_words))); - } - unset($non_common_words); - } - // else we only need one id - else if (($wildcard = strpos($word, '*') !== false) || isset($words[$word])) - { - if ($wildcard) - { - $len = utf8_strlen(str_replace('*', '', $word)); - if ($len >= $this->word_length['min'] && $len <= $this->word_length['max']) - { - $this->{$mode . '_ids'}[] = '\'' . $this->db->sql_escape(str_replace('*', '%', $word)) . '\''; - } - else - { - $this->common_words[] = $word; - } - } - else - { - $this->{$mode . '_ids'}[] = $words[$word]; - } - } - else - { - if (!isset($common_ids[$word])) - { - $len = utf8_strlen($word); - if ($len < $this->word_length['min'] || $len > $this->word_length['max']) - { - $this->common_words[] = $word; - } - } - } - } - - // Return true if all words are not common words - if (count($exact_words) - count($this->common_words) > 0) - { - return true; - } - return false; - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No keywords? No posts. - if (empty($this->search_query)) - { - return false; - } - - // we can't search for negatives only - if (empty($this->must_contain_ids)) - { - return false; - } - - $must_contain_ids = $this->must_contain_ids; - $must_not_contain_ids = $this->must_not_contain_ids; - $must_exclude_one_ids = $this->must_exclude_one_ids; - - sort($must_contain_ids); - sort($must_not_contain_ids); - sort($must_exclude_one_ids); - - // generate a search_key from all the options to identify the results - $search_key_array = array( - serialize($must_contain_ids), - serialize($must_not_contain_ids), - serialize($must_exclude_one_ids), - $type, - $fields, - $terms, - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary), - $author_name, - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_native_by_keyword_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var array must_contain_ids Array with post ids of posts containing words that are to be included - * @var array must_not_contain_ids Array with post ids of posts containing words that should not be included - * @var array must_exclude_one_ids Array with post ids of posts containing at least one word that needs to be excluded - * @var string type Searching type ('posts', 'topics') - * @var string fields Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') - * @var string terms Searching terms ('all', 'any') - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'must_contain_ids', - 'must_not_contain_ids', - 'must_exclude_one_ids', - 'type', - 'fields', - 'terms', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_native_by_keyword_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - // try reading the results from cache - $total_results = 0; - if ($this->obtain_ids($search_key, $total_results, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $total_results; - } - - $id_ary = array(); - - $sql_where = array(); - $m_num = 0; - $w_num = 0; - - $sql_array = array( - 'SELECT' => ($type == 'posts') ? 'p.post_id' : 'p.topic_id', - 'FROM' => array( - SEARCH_WORDMATCH_TABLE => array(), - SEARCH_WORDLIST_TABLE => array(), - ), - 'LEFT_JOIN' => array(array( - 'FROM' => array(POSTS_TABLE => 'p'), - 'ON' => 'm0.post_id = p.post_id', - )), - ); - - $title_match = ''; - $left_join_topics = false; - $group_by = true; - // Build some display specific sql strings - switch ($fields) - { - case 'titleonly': - $title_match = 'title_match = 1'; - $group_by = false; - // no break - case 'firstpost': - $left_join_topics = true; - $sql_where[] = 'p.post_id = t.topic_first_post_id'; - break; - - case 'msgonly': - $title_match = 'title_match = 0'; - $group_by = false; - break; - } - - if ($type == 'topics') - { - $left_join_topics = true; - $group_by = true; - } - - /** - * @todo Add a query optimizer (handle stuff like "+(4|3) +4") - */ - - foreach ($this->must_contain_ids as $subquery) - { - if (is_array($subquery)) - { - $group_by = true; - - $word_id_sql = array(); - $word_ids = array(); - foreach ($subquery as $id) - { - if (is_string($id)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $id" - ); - $word_ids[] = "w$w_num.word_id"; - - $w_num++; - } - else - { - $word_ids[] = $id; - } - } - - $sql_where[] = $this->db->sql_in_set("m$m_num.word_id", $word_ids); - - unset($word_id_sql); - unset($word_ids); - } - else if (is_string($subquery)) - { - $sql_array['FROM'][SEARCH_WORDLIST_TABLE][] = 'w' . $w_num; - - $sql_where[] = "w$w_num.word_text LIKE $subquery"; - $sql_where[] = "m$m_num.word_id = w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - else - { - $sql_where[] = "m$m_num.word_id = $subquery"; - } - - $sql_array['FROM'][SEARCH_WORDMATCH_TABLE][] = 'm' . $m_num; - - if ($title_match) - { - $sql_where[] = "m$m_num.$title_match"; - } - - if ($m_num != 0) - { - $sql_where[] = "m$m_num.post_id = m0.post_id"; - } - $m_num++; - } - - foreach ($this->must_not_contain_ids as $key => $subquery) - { - if (is_string($subquery)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $subquery" - ); - - $this->must_not_contain_ids[$key] = "w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - } - - if (count($this->must_not_contain_ids)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num), - 'ON' => $this->db->sql_in_set("m$m_num.word_id", $this->must_not_contain_ids) . (($title_match) ? " AND m$m_num.$title_match" : '') . " AND m$m_num.post_id = m0.post_id" - ); - - $sql_where[] = "m$m_num.word_id IS NULL"; - $m_num++; - } - - foreach ($this->must_exclude_one_ids as $ids) - { - $is_null_joins = array(); - foreach ($ids as $id) - { - if (is_string($id)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $id" - ); - $id = "w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num), - 'ON' => "m$m_num.word_id = $id AND m$m_num.post_id = m0.post_id" . (($title_match) ? " AND m$m_num.$title_match" : '') - ); - $is_null_joins[] = "m$m_num.word_id IS NULL"; - - $m_num++; - } - $sql_where[] = '(' . implode(' OR ', $is_null_joins) . ')'; - } - - $sql_where[] = $post_visibility; - - $search_query = $this->search_query; - $must_exclude_one_ids = $this->must_exclude_one_ids; - $must_not_contain_ids = $this->must_not_contain_ids; - $must_contain_ids = $this->must_contain_ids; - - $sql_sort_table = $sql_sort_join = $sql_match = $sql_match_where = $sql_sort = ''; - - /** - * Allow changing the query used for counting for posts using fulltext_native - * - * @event core.search_native_keywords_count_query_before - * @var string search_query The parsed keywords used for this search - * @var array must_not_contain_ids Ids that cannot be taken into account for the results - * @var array must_exclude_one_ids Ids that cannot be on the results - * @var array must_contain_ids Ids that must be on the results - * @var int total_results The previous result count for the format of the query - * Set to 0 to force a re-count - * @var array sql_array The data on how to search in the DB at this point - * @var bool left_join_topics Whether or not TOPICS_TABLE should be CROSS JOIN'ED - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on (!empty(author_ary) must be true, to be relevant) - * @var array ex_fid_ary Which forums not to search on - * @var int topic_id Limit the search to this topic_id only - * @var string sql_sort_table Extra tables to include in the SQL query. - * Used in conjunction with sql_sort_join - * @var string sql_sort_join SQL conditions to join all the tables used together. - * Used in conjunction with sql_sort_table - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sql_where An array of the current WHERE clause conditions - * @var string sql_match Which columns to do the search on - * @var string sql_match_where Extra conditions to use to properly filter the matching process - * @var bool group_by Whether or not the SQL query requires a GROUP BY for the elements in the SELECT clause - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'search_query', - 'must_not_contain_ids', - 'must_exclude_one_ids', - 'must_contain_ids', - 'total_results', - 'sql_array', - 'left_join_topics', - 'author_ary', - 'author_name', - 'ex_fid_ary', - 'topic_id', - 'sql_sort_table', - 'sql_sort_join', - 'sort_days', - 'sql_where', - 'sql_match', - 'sql_match_where', - 'group_by', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_native_keywords_count_query_before', compact($vars))); - - if ($topic_id) - { - $sql_where[] = 'p.topic_id = ' . $topic_id; - } - - if (count($author_ary)) - { - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); - } - $sql_where[] = $sql_author; - } - - if (count($ex_fid_ary)) - { - $sql_where[] = $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true); - } - - if ($sort_days) - { - $sql_where[] = 'p.post_time >= ' . (time() - ($sort_days * 86400)); - } - - $sql_array['WHERE'] = implode(' AND ', $sql_where); - - $is_mysql = false; - // if the total result count is not cached yet, retrieve it from the db - if (!$total_results) - { - $sql = ''; - $sql_array_count = $sql_array; - - if ($left_join_topics) - { - $sql_array_count['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_TABLE => 't'), - 'ON' => 'p.topic_id = t.topic_id' - ); - } - - switch ($this->db->get_sql_layer()) - { - case 'mysqli': - - // 3.x does not support SQL_CALC_FOUND_ROWS - // $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT']; - $is_mysql = true; - - break; - - case '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 - FROM (' . $this->db->sql_build_query('SELECT', $sql_array_count) . ')'; - - // no break - - default: - $sql_array_count['SELECT'] = ($type == 'posts') ? 'COUNT(DISTINCT p.post_id) AS total_results' : 'COUNT(DISTINCT p.topic_id) AS total_results'; - $sql = (!$sql) ? $this->db->sql_build_query('SELECT', $sql_array_count) : $sql; - - $result = $this->db->sql_query($sql); - $total_results = (int) $this->db->sql_fetchfield('total_results'); - $this->db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - break; - } - - unset($sql_array_count, $sql); - } - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - switch ($sql_sort[0]) - { - case 'u': - $sql_array['FROM'][USERS_TABLE] = 'u'; - $sql_where[] = 'u.user_id = p.poster_id '; - break; - - case 't': - $left_join_topics = true; - break; - - case 'f': - $sql_array['FROM'][FORUMS_TABLE] = 'f'; - $sql_where[] = 'f.forum_id = p.forum_id'; - break; - } - - if ($left_join_topics) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_TABLE => 't'), - 'ON' => 'p.topic_id = t.topic_id' - ); - } - - // if using mysql and the total result count is not calculated yet, get it from the db - if (!$total_results && $is_mysql) - { - // Also count rows for the query as if there was not LIMIT. Add SQL_CALC_FOUND_ROWS to SQL - $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT']; - } - - $sql_array['WHERE'] = implode(' AND ', $sql_where); - $sql_array['GROUP_BY'] = ($group_by) ? (($type == 'posts') ? 'p.post_id' : 'p.topic_id') . ', ' . $sort_by_sql[$sort_key] : ''; - $sql_array['ORDER_BY'] = $sql_sort; - - unset($sql_where, $sql_sort, $group_by); - - $sql = $this->db->sql_build_query('SELECT', $sql_array); - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[(($type == 'posts') ? 'post_id' : 'topic_id')]; - } - $this->db->sql_freeresult($result); - - if (!$total_results && $is_mysql) - { - // Get the number of results as calculated by MySQL - $sql_count = 'SELECT FOUND_ROWS() as total_results'; - $result = $this->db->sql_query($sql_count); - $total_results = (int) $this->db->sql_fetchfield('total_results'); - $this->db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - } - - if ($start >= $total_results) - { - $start = floor(($total_results - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[(($type == 'posts') ? 'post_id' : 'topic_id')]; - } - $this->db->sql_freeresult($result); - - } - - // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page - $this->save_ids($search_key, $this->search_query, $author_ary, $total_results, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $total_results; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No author? No posts - if (!count($author_ary)) - { - return 0; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - '', - $type, - ($firstpost_only) ? 'firstpost' : '', - '', - '', - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary), - $author_name, - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_native_by_author_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var boolean firstpost_only Flag indicating if only topic starting posts are considered - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name The username to search on - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'firstpost_only', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - 'author_name', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_native_by_author_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - // try reading the results from cache - $total_results = 0; - if ($this->obtain_ids($search_key, $total_results, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $total_results; - } - - $id_ary = array(); - - // Create some display specific sql strings - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); - } - $sql_fora = (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' : ''; - $post_visibility = ($post_visibility) ? ' AND ' . $post_visibility : ''; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ' AND u.user_id = p.poster_id '; - break; - - case 't': - $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; - $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - $select = ($type == 'posts') ? 'p.post_id' : 't.topic_id'; - $is_mysql = false; - - /** - * Allow changing the query used to search for posts by author in fulltext_native - * - * @event core.search_native_author_count_query_before - * @var int total_results The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var string type The type of search being made - * @var string select SQL SELECT clause for what to get - * @var string sql_sort_table CROSS JOIN'ed table to allow doing the sort chosen - * @var string sql_sort_join Condition to define how to join the CROSS JOIN'ed table specifyed in sql_sort_table - * @var array sql_author SQL WHERE condition for the post author ids - * @var int topic_id Limit the search to this topic_id only - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var string sort_days Time, in days, that the oldest post showing can have - * @var string sql_time The SQL to search on the time specifyed by sort_days - * @var bool firstpost_only Wether or not to search only on the first post of the topics - * @var string sql_firstpost The SQL used in the WHERE claused to filter by firstpost. - * @var array ex_fid_ary Forum ids that must not be searched on - * @var array sql_fora SQL query for ex_fid_ary - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'total_results', - 'type', - 'select', - 'sql_sort_table', - 'sql_sort_join', - 'sql_author', - 'topic_id', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'sort_days', - 'sql_time', - 'firstpost_only', - 'sql_firstpost', - 'ex_fid_ary', - 'sql_fora', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_native_author_count_query_before', compact($vars))); - - // If the cache was completely empty count the results - if (!$total_results) - { - switch ($this->db->get_sql_layer()) - { - case 'mysqli': -// $select = 'SQL_CALC_FOUND_ROWS ' . $select; - $is_mysql = true; - break; - - default: - if ($type == 'posts') - { - $sql = 'SELECT COUNT(p.post_id) as total_results - FROM ' . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $post_visibility - $sql_fora - $sql_time"; - } - else - { - if ($this->db->get_sql_layer() == 'sqlite3') - { - $sql = 'SELECT COUNT(topic_id) as total_results - FROM (SELECT DISTINCT t.topic_id'; - } - else - { - $sql = 'SELECT COUNT(DISTINCT t.topic_id) as total_results'; - } - - $sql .= ' FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $post_visibility - $sql_fora - AND t.topic_id = p.topic_id - $sql_time" . ($this->db->get_sql_layer() == 'sqlite3' ? ')' : ''); - } - $result = $this->db->sql_query($sql); - - $total_results = (int) $this->db->sql_fetchfield('total_results'); - $this->db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - break; - } - } - - // Build the query for really selecting the post_ids - if ($type == 'posts') - { - $sql = "SELECT $select - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t' : '') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $post_visibility - $sql_fora - $sql_sort_join - $sql_time - ORDER BY $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = "SELECT $select - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $post_visibility - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id, " . $sort_by_sql[$sort_key] . ' - ORDER BY ' . $sql_sort; - $field = 'topic_id'; - } - - // Only read one block of posts from the db and then cache it - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - if (!$total_results && $is_mysql) - { - // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it. - $sql_calc = str_replace('SELECT ' . $select, 'SELECT SQL_CALC_FOUND_ROWS ' . $select, $sql); - - $result = $this->db->sql_query($sql_calc); - $this->db->sql_freeresult($result); - - $sql_count = 'SELECT FOUND_ROWS() as total_results'; - $result = $this->db->sql_query($sql_count); - $total_results = (int) $this->db->sql_fetchfield('total_results'); - $this->db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - } - - if ($start >= $total_results) - { - $start = floor(($total_results - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - } - - if (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); - - return $total_results; - } - return false; - } - - /** - * Split a text into words of a given length - * - * The text is converted to UTF-8, cleaned up, and split. Then, words that - * conform to the defined length range are returned in an array. - * - * NOTE: duplicates are NOT removed from the return array - * - * @param string $text Text to split, encoded in UTF-8 - * @return array Array of UTF-8 words - */ - public function split_message($text) - { - $match = $words = array(); - - /** - * Taken from the original code - */ - // Do not index code - $match[] = '#\[code(?:=.*?)?(\:?[0-9a-z]{5,})\].*?\[\/code(\:?[0-9a-z]{5,})\]#is'; - // BBcode - $match[] = '#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?[0-9a-z]{5,})\]#'; - - $min = $this->word_length['min']; - - $isset_min = $min - 1; - - /** - * Clean up the string, remove HTML tags, remove BBCodes - */ - $word = strtok($this->cleanup(preg_replace($match, ' ', strip_tags($text)), -1), ' '); - - while (strlen($word)) - { - if (strlen($word) > 255 || strlen($word) <= $isset_min) - { - /** - * Words longer than 255 bytes are ignored. This will have to be - * changed whenever we change the length of search_wordlist.word_text - * - * Words shorter than $isset_min bytes are ignored, too - */ - $word = strtok(' '); - continue; - } - - $len = utf8_strlen($word); - - /** - * Test whether the word is too short to be indexed. - * - * Note that this limit does NOT apply to CJK and Hangul - */ - if ($len < $min) - { - /** - * Note: this could be optimized. If the codepoint is lower than Hangul's range - * we know that it will also be lower than CJK ranges - */ - if ((strncmp($word, 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; - } - } - - $words[] = $word; - $word = strtok(' '); - } - - return $words; - } - - /** - * Updates wordlist and wordmatch tables when a message is posted or changed - * - * @param string $mode Contains the post mode: edit, post, reply, quote - * @param int $post_id The id of the post which is modified/created - * @param string &$message New or updated post content - * @param string &$subject New or updated post subject - * @param int $poster_id Post author's user id - * @param int $forum_id The id of the forum in which the post is located - */ - public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - if (!$this->config['fulltext_native_load_upd']) - { - /** - * The search indexer is disabled, return - */ - return; - } - - // Split old and new post/subject to obtain array of 'words' - $split_text = $this->split_message($message); - $split_title = $this->split_message($subject); - - $cur_words = array('post' => array(), 'title' => array()); - - $words = array(); - if ($mode == 'edit') - { - $words['add']['post'] = array(); - $words['add']['title'] = array(); - $words['del']['post'] = array(); - $words['del']['title'] = array(); - - $sql = 'SELECT w.word_id, w.word_text, m.title_match - FROM ' . SEARCH_WORDLIST_TABLE . ' w, ' . SEARCH_WORDMATCH_TABLE . " m - WHERE m.post_id = $post_id - AND w.word_id = m.word_id"; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - $which = ($row['title_match']) ? 'title' : 'post'; - $cur_words[$which][$row['word_text']] = $row['word_id']; - } - $this->db->sql_freeresult($result); - - $words['add']['post'] = array_diff($split_text, array_keys($cur_words['post'])); - $words['add']['title'] = array_diff($split_title, array_keys($cur_words['title'])); - $words['del']['post'] = array_diff(array_keys($cur_words['post']), $split_text); - $words['del']['title'] = array_diff(array_keys($cur_words['title']), $split_title); - } - else - { - $words['add']['post'] = $split_text; - $words['add']['title'] = $split_title; - $words['del']['post'] = array(); - $words['del']['title'] = array(); - } - - /** - * 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); - - // Get unique words from the above arrays - $unique_add_words = array_unique(array_merge($words['add']['post'], $words['add']['title'])); - - // We now have unique arrays of all words to be added and removed and - // individual arrays of added and removed words for text and title. What - // we need to do now is add the new words (if they don't already exist) - // and then add (or remove) matches between the words and this post - if (count($unique_add_words)) - { - $sql = 'SELECT word_id, word_text - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_text', $unique_add_words); - $result = $this->db->sql_query($sql); - - $word_ids = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $word_ids[$row['word_text']] = $row['word_id']; - } - $this->db->sql_freeresult($result); - $new_words = array_diff($unique_add_words, array_keys($word_ids)); - - $this->db->sql_transaction('begin'); - if (count($new_words)) - { - $sql_ary = array(); - - foreach ($new_words as $word) - { - $sql_ary[] = array('word_text' => (string) $word, 'word_count' => 0); - } - $this->db->sql_return_on_error(true); - $this->db->sql_multi_insert(SEARCH_WORDLIST_TABLE, $sql_ary); - $this->db->sql_return_on_error(false); - } - unset($new_words, $sql_ary); - } - else - { - $this->db->sql_transaction('begin'); - } - - // now update the search match table, remove links to removed words and add links to new words - foreach ($words['del'] as $word_in => $word_ary) - { - $title_match = ($word_in == 'title') ? 1 : 0; - - if (count($word_ary)) - { - $sql_in = array(); - foreach ($word_ary as $word) - { - $sql_in[] = $cur_words[$word_in][$word]; - } - - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_id', $sql_in) . ' - AND post_id = ' . intval($post_id) . " - AND title_match = $title_match"; - $this->db->sql_query($sql); - - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $this->db->sql_in_set('word_id', $sql_in) . ' - AND word_count > 0'; - $this->db->sql_query($sql); - - unset($sql_in); - } - } - - $this->db->sql_return_on_error(true); - foreach ($words['add'] as $word_in => $word_ary) - { - $title_match = ($word_in == 'title') ? 1 : 0; - - if (count($word_ary)) - { - $sql = 'INSERT INTO ' . SEARCH_WORDMATCH_TABLE . ' (post_id, word_id, title_match) - SELECT ' . (int) $post_id . ', word_id, ' . (int) $title_match . ' - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_text', $word_ary); - $this->db->sql_query($sql); - - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count + 1 - WHERE ' . $this->db->sql_in_set('word_text', $word_ary); - $this->db->sql_query($sql); - } - } - $this->db->sql_return_on_error(false); - - $this->db->sql_transaction('commit'); - - // destroy cached search results containing any of the words removed or added - $this->destroy_cache(array_unique(array_merge($words['add']['post'], $words['add']['title'], $words['del']['post'], $words['del']['title'])), array($poster_id)); - - unset($unique_add_words); - unset($words); - unset($cur_words); - } - - /** - * Removes entries from the wordmatch table for the specified post_ids - */ - public function index_remove($post_ids, $author_ids, $forum_ids) - { - if (count($post_ids)) - { - $sql = 'SELECT w.word_id, w.word_text, m.title_match - FROM ' . SEARCH_WORDMATCH_TABLE . ' m, ' . SEARCH_WORDLIST_TABLE . ' w - WHERE ' . $this->db->sql_in_set('m.post_id', $post_ids) . ' - AND w.word_id = m.word_id'; - $result = $this->db->sql_query($sql); - - $message_word_ids = $title_word_ids = $word_texts = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - if ($row['title_match']) - { - $title_word_ids[] = $row['word_id']; - } - else - { - $message_word_ids[] = $row['word_id']; - } - $word_texts[] = $row['word_text']; - } - $this->db->sql_freeresult($result); - - if (count($title_word_ids)) - { - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $this->db->sql_in_set('word_id', $title_word_ids) . ' - AND word_count > 0'; - $this->db->sql_query($sql); - } - - if (count($message_word_ids)) - { - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $this->db->sql_in_set('word_id', $message_word_ids) . ' - AND word_count > 0'; - $this->db->sql_query($sql); - } - - unset($title_word_ids); - unset($message_word_ids); - - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $this->db->sql_in_set('post_id', $post_ids); - $this->db->sql_query($sql); - } - - $this->destroy_cache(array_unique($word_texts), array_unique($author_ids)); - } - - /** - * Tidy up indexes: Tag 'common words' and remove - * words no longer referenced in the match table - */ - public function tidy() - { - // Is the fulltext indexer disabled? If yes then we need not - // carry on ... it's okay ... I know when I'm not wanted boo hoo - if (!$this->config['fulltext_native_load_upd']) - { - $this->config->set('search_last_gc', time(), false); - return; - } - - $destroy_cache_words = array(); - - // Remove common words - if ($this->config['num_posts'] >= 100 && $this->config['fulltext_native_common_thres']) - { - $common_threshold = ((double) $this->config['fulltext_native_common_thres']) / 100.0; - // First, get the IDs of common words - $sql = 'SELECT word_id, word_text - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE word_count > ' . floor($this->config['num_posts'] * $common_threshold) . ' - OR word_common = 1'; - $result = $this->db->sql_query($sql); - - $sql_in = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $sql_in[] = $row['word_id']; - $destroy_cache_words[] = $row['word_text']; - } - $this->db->sql_freeresult($result); - - if (count($sql_in)) - { - // Flag the words - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_common = 1 - WHERE ' . $this->db->sql_in_set('word_id', $sql_in); - $this->db->sql_query($sql); - - // by setting search_last_gc to the new time here we make sure that if a user reloads because the - // following query takes too long, he won't run into it again - $this->config->set('search_last_gc', time(), false); - - // Delete the matches - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_id', $sql_in); - $this->db->sql_query($sql); - } - unset($sql_in); - } - - if (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)); - } - - $this->config->set('search_last_gc', time(), false); - } - - /** - * Deletes all words from the index - */ - public function delete_index($acp_module, $u_action) - { - $sql_queries = []; - - switch ($this->db->get_sql_layer()) - { - case 'sqlite3': - $sql_queries[] = 'DELETE FROM ' . SEARCH_WORDLIST_TABLE; - $sql_queries[] = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE; - $sql_queries[] = 'DELETE FROM ' . SEARCH_RESULTS_TABLE; - break; - - default: - $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); - } - } - - /** - * Returns true if both FULLTEXT indexes exist - */ - public function index_created() - { - if (!count($this->stats)) - { - $this->get_stats(); - } - - return ($this->stats['total_words'] && $this->stats['total_matches']) ? true : false; - } - - /** - * Returns an associative array containing information about the indexes - */ - public function index_stats() - { - if (!count($this->stats)) - { - $this->get_stats(); - } - - return array( - $this->user->lang['TOTAL_WORDS'] => $this->stats['total_words'], - $this->user->lang['TOTAL_MATCHES'] => $this->stats['total_matches']); - } - - protected function get_stats() - { - $this->stats['total_words'] = $this->db->get_estimated_row_count(SEARCH_WORDLIST_TABLE); - $this->stats['total_matches'] = $this->db->get_estimated_row_count(SEARCH_WORDMATCH_TABLE); - } - - /** - * Clean up a text to remove non-alphanumeric characters - * - * This method receives a UTF-8 string, normalizes and validates it, replaces all - * non-alphanumeric characters with strings then returns the result. - * - * Any number of "allowed chars" can be passed as a UTF-8 string in NFC. - * - * @param string $text Text to split, in UTF-8 (not normalized or sanitized) - * @param string $allowed_chars String of special chars to allow - * @param string $encoding Text encoding - * @return string Cleaned up text, only alphanumeric chars are left - */ - protected function cleanup($text, $allowed_chars = null, $encoding = 'utf-8') - { - static $conv = array(), $conv_loaded = array(); - $allow = array(); - - // Convert the text to UTF-8 - $encoding = strtolower($encoding); - if ($encoding != 'utf-8') - { - $text = utf8_recode($text, $encoding); - } - - $utf_len_mask = array( - "\xC0" => 2, - "\xD0" => 2, - "\xE0" => 3, - "\xF0" => 4 - ); - - /** - * Replace HTML entities and NCRs - */ - $text = htmlspecialchars_decode(utf8_decode_ncr($text), ENT_QUOTES); - - /** - * Normalize to NFC - */ - $text = \Normalizer::normalize($text); - - /** - * The first thing we do is: - * - * - convert ASCII-7 letters to lowercase - * - remove the ASCII-7 non-alpha characters - * - remove the bytes that should not appear in a valid UTF-8 string: 0xC0, - * 0xC1 and 0xF5-0xFF - * - * @todo in theory, the third one is already taken care of during normalization and those chars should have been replaced by Unicode replacement chars - */ - $sb_match = "ISTCPAMELRDOJBNHFGVWUQKYXZ\r\n\t!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\xC0\xC1\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"; - $sb_replace = 'istcpamelrdojbnhfgvwuqkyxz '; - - /** - * This is the list of legal ASCII chars, it is automatically extended - * with ASCII chars from $allowed_chars - */ - $legal_ascii = ' eaisntroludcpmghbfvq10xy2j9kw354867z'; - - /** - * Prepare an array containing the extra chars to allow - */ - if (isset($allowed_chars[0])) - { - $pos = 0; - $len = strlen($allowed_chars); - do - { - $c = $allowed_chars[$pos]; - - if ($c < "\x80") - { - /** - * ASCII char - */ - $sb_pos = strpos($sb_match, $c); - if (is_int($sb_pos)) - { - /** - * Remove the char from $sb_match and its corresponding - * replacement in $sb_replace - */ - $sb_match = substr($sb_match, 0, $sb_pos) . substr($sb_match, $sb_pos + 1); - $sb_replace = substr($sb_replace, 0, $sb_pos) . substr($sb_replace, $sb_pos + 1); - $legal_ascii .= $c; - } - - ++$pos; - } - else - { - /** - * UTF-8 char - */ - $utf_len = $utf_len_mask[$c & "\xF0"]; - $allow[substr($allowed_chars, $pos, $utf_len)] = 1; - $pos += $utf_len; - } - } - while ($pos < $len); - } - - $text = strtr($text, $sb_match, $sb_replace); - $ret = ''; - - $pos = 0; - $len = strlen($text); - - do - { - /** - * Do all consecutive ASCII chars at once - */ - if ($spn = strspn($text, $legal_ascii, $pos)) - { - $ret .= substr($text, $pos, $spn); - $pos += $spn; - } - - if ($pos >= $len) - { - return $ret; - } - - /** - * Capture the UTF char - */ - $utf_len = $utf_len_mask[$text[$pos] & "\xF0"]; - $utf_char = substr($text, $pos, $utf_len); - $pos += $utf_len; - - if (($utf_char >= 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 - * - * We separate them with a space in order to index each character - * individually - */ - $ret .= ' ' . $utf_char . ' '; - continue; - } - - if (isset($allow[$utf_char])) - { - /** - * The char is explicitly allowed - */ - $ret .= $utf_char; - continue; - } - - if (isset($conv[$utf_char])) - { - /** - * The char is mapped to something, maybe to itself actually - */ - $ret .= $conv[$utf_char]; - continue; - } - - /** - * The char isn't mapped, but did we load its conversion table? - * - * The search indexer table is split into blocks. The block number of - * each char is equal to its codepoint right-shifted for 11 bits. It - * means that out of the 11, 16 or 21 meaningful bits of a 2-, 3- or - * 4- byte sequence we only keep the leftmost 0, 5 or 10 bits. Thus, - * all UTF chars encoded in 2 bytes are in the same first block. - */ - if (isset($utf_char[2])) - { - if (isset($utf_char[3])) - { - /** - * 1111 0nnn 10nn nnnn 10nx xxxx 10xx xxxx - * 0000 0111 0011 1111 0010 0000 - */ - $idx = ((ord($utf_char[0]) & 0x07) << 7) | ((ord($utf_char[1]) & 0x3F) << 1) | ((ord($utf_char[2]) & 0x20) >> 5); - } - else - { - /** - * 1110 nnnn 10nx xxxx 10xx xxxx - * 0000 0111 0010 0000 - */ - $idx = ((ord($utf_char[0]) & 0x07) << 1) | ((ord($utf_char[1]) & 0x20) >> 5); - } - } - else - { - /** - * 110x xxxx 10xx xxxx - * 0000 0000 0000 0000 - */ - $idx = 0; - } - - /** - * Check if the required conv table has been loaded already - */ - if (!isset($conv_loaded[$idx])) - { - $conv_loaded[$idx] = 1; - $file = $this->phpbb_root_path . 'includes/utf/data/search_indexer_' . $idx . '.' . $this->php_ext; - - if (file_exists($file)) - { - $conv += include($file); - } - } - - if (isset($conv[$utf_char])) - { - $ret .= $conv[$utf_char]; - } - else - { - /** - * We add an entry to the conversion table so that we - * don't have to convert to codepoint and perform the checks - * that are above this block - */ - $conv[$utf_char] = ' '; - $ret .= ' '; - } - } - while (1); - - return $ret; - } - - /** - * Returns a list of options for the ACP to display - */ - public function acp() - { - /** - * if we need any options, copied from fulltext_native for now, will have to be adjusted or removed - */ - - $tpl = ' -
-

' . $this->user->lang['YES_SEARCH_UPDATE_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['MIN_SEARCH_CHARS_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['MAX_SEARCH_CHARS_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['COMMON_WORD_THRESHOLD_EXPLAIN'] . '
-
%
-
- '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array('fulltext_native_load_upd' => 'bool', 'fulltext_native_min_chars' => 'integer:0:255', 'fulltext_native_max_chars' => 'integer:0:255', 'fulltext_native_common_thres' => 'double:0:100') - ); - } -} diff --git a/install/update/new/phpbb/search/fulltext_postgres.php b/install/update/new/phpbb/search/fulltext_postgres.php deleted file mode 100644 index 6241f21..0000000 --- a/install/update/new/phpbb/search/fulltext_postgres.php +++ /dev/null @@ -1,1178 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\search; - -/** -* Fulltext search for PostgreSQL -*/ -class fulltext_postgres extends \phpbb\search\base -{ - /** - * Associative array holding index stats - * @var array - */ - protected $stats = array(); - - /** - * Holds the words entered by user, obtained by splitting the entered query on whitespace - * @var array - */ - protected $split_words = array(); - - /** - * Stores the tsearch query - * @var string - */ - protected $tsearch_query; - - /** - * True if phrase search is supported. - * PostgreSQL fulltext currently doesn't support it - * @var boolean - */ - protected $phrase_search = false; - - /** - * Config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Database connection - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Contains tidied search query. - * Operators are prefixed in search query and common words excluded - * @var string - */ - protected $search_query; - - /** - * Contains common words. - * Common words are words with length less/more than min/max length - * @var array - */ - protected $common_words = array(); - - /** - * Associative array stores the min and max word length to be searched - * @var array - */ - protected $word_length = array(); - - /** - * Constructor - * Creates a new \phpbb\search\fulltext_postgres, which is used as a search backend - * - * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $phpEx PHP file extension - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\db\driver\driver_interface Database object - * @param \phpbb\user $user User object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - */ - public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) - { - $this->config = $config; - $this->db = $db; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->user = $user; - - $this->word_length = array('min' => $this->config['fulltext_postgres_min_word_len'], 'max' => $this->config['fulltext_postgres_max_word_len']); - - /** - * Load the UTF tools - */ - if (!function_exists('utf8_strlen')) - { - include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - } - - $error = false; - } - - /** - * Returns the name of this search backend to be displayed to administrators - * - * @return string Name - */ - public function get_name() - { - return 'PostgreSQL Fulltext'; - } - - /** - * Returns the search_query - * - * @return string search query - */ - public function get_search_query() - { - return $this->search_query; - } - - /** - * Returns the common_words array - * - * @return array common words that are ignored by search backend - */ - public function get_common_words() - { - return $this->common_words; - } - - /** - * Returns the word_length array - * - * @return array min and max word length for searching - */ - public function get_word_length() - { - return $this->word_length; - } - - /** - * Returns if phrase search is supported or not - * - * @return bool - */ - public function supports_phrase_search() - { - return $this->phrase_search; - } - - /** - * Checks for correct PostgreSQL version and stores min/max word length in the config - * - * @return string|bool Language key of the error/incompatibility occurred - */ - public function init() - { - if ($this->db->get_sql_layer() != 'postgres') - { - return $this->user->lang['FULLTEXT_POSTGRES_INCOMPATIBLE_DATABASE']; - } - - return false; - } - - /** - * Splits keywords entered by a user into an array of words stored in $this->split_words - * Stores the tidied search query in $this->search_query - * - * @param string &$keywords Contains the keyword as entered by the user - * @param string $terms is either 'all' or 'any' - * @return bool false if no valid keywords were found and otherwise true - */ - public function split_keywords(&$keywords, $terms) - { - if ($terms == 'all') - { - $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#(^|\s)\+#', '#(^|\s)-#', '#(^|\s)\|#'); - $replace = array(' +', ' |', ' -', ' +', ' -', ' |'); - - $keywords = preg_replace($match, $replace, $keywords); - } - - // Filter out as above - $split_keywords = preg_replace("#[\"\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords))); - - // Split words - $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches); - $this->split_words = $matches[1]; - - foreach ($this->split_words as $i => $word) - { - $clean_word = preg_replace('#^[+\-|"]#', '', $word); - - // check word length - $clean_len = utf8_strlen(str_replace('*', '', $clean_word)); - if (($clean_len < $this->config['fulltext_postgres_min_word_len']) || ($clean_len > $this->config['fulltext_postgres_max_word_len'])) - { - $this->common_words[] = $word; - unset($this->split_words[$i]); - } - } - - if ($terms == 'any') - { - $this->search_query = ''; - $this->tsearch_query = ''; - foreach ($this->split_words as $word) - { - if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0)) - { - $word = substr($word, 1); - } - $this->search_query .= $word . ' '; - $this->tsearch_query .= '|' . $word . ' '; - } - } - else - { - $this->search_query = ''; - $this->tsearch_query = ''; - foreach ($this->split_words as $word) - { - if (strpos($word, '+') === 0) - { - $this->search_query .= $word . ' '; - $this->tsearch_query .= '&' . substr($word, 1) . ' '; - } - else if (strpos($word, '-') === 0) - { - $this->search_query .= $word . ' '; - $this->tsearch_query .= '&!' . substr($word, 1) . ' '; - } - else if (strpos($word, '|') === 0) - { - $this->search_query .= $word . ' '; - $this->tsearch_query .= '|' . substr($word, 1) . ' '; - } - else - { - $this->search_query .= '+' . $word . ' '; - $this->tsearch_query .= '&' . $word . ' '; - } - } - } - - $this->tsearch_query = substr($this->tsearch_query, 1); - $this->search_query = utf8_htmlspecialchars($this->search_query); - - if ($this->search_query) - { - $this->split_words = array_values($this->split_words); - sort($this->split_words); - return true; - } - return false; - } - - /** - * Turns text into an array of words - * @param string $text contains post text/subject - */ - public function split_message($text) - { - // Split words - $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches); - $text = $matches[1]; - - // remove too short or too long words - $text = array_values($text); - for ($i = 0, $n = 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']) - { - unset($text[$i]); - } - } - - return array_values($text); - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No keywords? No posts - if (!$this->search_query) - { - return false; - } - - // When search query contains queries like -foo - if (strpos($this->search_query, '+') === false) - { - return false; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - implode(', ', $this->split_words), - $type, - $fields, - $terms, - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary) - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_postgres_by_keyword_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var string fields Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') - * @var string terms Searching terms ('all', 'any') - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'fields', - 'terms', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_by_keyword_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - if ($start < 0) - { - $start = 0; - } - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - $join_topic = ($type == 'posts') ? false : true; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $join_topic = true; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - // Build some display specific sql strings - switch ($fields) - { - case 'titleonly': - $sql_match = 'p.post_subject'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - case 'msgonly': - $sql_match = 'p.post_text'; - $sql_match_where = ''; - break; - - case 'firstpost': - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - default: - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ''; - break; - } - - $tsearch_query = $this->tsearch_query; - - /** - * Allow changing the query used to search for posts using fulltext_postgres - * - * @event core.search_postgres_keywords_main_query_before - * @var string tsearch_query The parsed keywords used for this search - * @var int result_count The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var bool join_topic Weather or not TOPICS_TABLE should be CROSS JOIN'ED - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on (!empty(author_ary) must be true, to be relevant) - * @var array ex_fid_ary Which forums not to search on - * @var int topic_id Limit the search to this topic_id only - * @var string sql_sort_table Extra tables to include in the SQL query. - * Used in conjunction with sql_sort_join - * @var string sql_sort_join SQL conditions to join all the tables used together. - * Used in conjunction with sql_sort_table - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sql_match Which columns to do the search on. - * @var string sql_match_where Extra conditions to use to properly filter the matching process - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'tsearch_query', - 'result_count', - 'join_topic', - 'author_ary', - 'author_name', - 'ex_fid_ary', - 'topic_id', - 'sql_sort_table', - 'sql_sort_join', - 'sort_days', - 'sql_match', - 'sql_match_where', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'start', - ); - 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, ' . $sort_by_sql[$sort_key]; - $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; - $field = ($type == 'posts') ? 'post_id' : 'topic_id'; - - 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 (count($author_ary)) - { - $sql_author = ' AND ' . $this->db->sql_in_set('p.poster_id', $author_ary); - } - else - { - $sql_author = ''; - } - - $sql_where_options = $sql_sort_join; - $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; - $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; - $sql_where_options .= (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; - - $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) . "')"; - - $this->db->sql_transaction('begin'); - - $sql_from = "FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p"; - $sql_where = "WHERE (" . $tmp_sql_match . ") - $sql_where_options"; - $sql = "SELECT $sql_select - $sql_from - $sql_where - ORDER BY $sql_sort"; - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - - // if the total result count is not cached yet, retrieve it from the db - if (!$result_count) - { - $sql_count = "SELECT COUNT(*) as result_count - $sql_from - $sql_where"; - $result = $this->db->sql_query($sql_count); - $result_count = (int) $this->db->sql_fetchfield('result_count'); - $this->db->sql_freeresult($result); - - if (!$result_count) - { - return false; - } - } - - $this->db->sql_transaction('commit'); - - if ($start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - } - - // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page - $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $result_count; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No author? No posts - if (!count($author_ary)) - { - return 0; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - '', - $type, - ($firstpost_only) ? 'firstpost' : '', - '', - '', - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary), - $author_name, - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_postgres_by_author_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var boolean firstpost_only Flag indicating if only topic starting posts are considered - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name The username to search on - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'firstpost_only', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - 'author_name', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_by_author_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - if ($start < 0) - { - $start = 0; - } - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - // Create some display specific sql strings - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); - } - $sql_fora = (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' : ''; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; - $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - $m_approve_fid_sql = ' AND ' . $post_visibility; - - /** - * Allow changing the query used to search for posts by author in fulltext_postgres - * - * @event core.search_postgres_author_count_query_before - * @var int result_count The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var string sql_sort_table CROSS JOIN'ed table to allow doing the sort chosen - * @var string sql_sort_join Condition to define how to join the CROSS JOIN'ed table specifyed in sql_sort_table - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on - * @var string sql_author SQL WHERE condition for the post author ids - * @var int topic_id Limit the search to this topic_id only - * @var string sql_topic_id SQL of topic_id - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var string sort_days Time, in days, that the oldest post showing can have - * @var string sql_time The SQL to search on the time specifyed by sort_days - * @var bool firstpost_only Wether or not to search only on the first post of the topics - * @var array ex_fid_ary Forum ids that must not be searched on - * @var array sql_fora SQL query for ex_fid_ary - * @var string m_approve_fid_sql WHERE clause condition on post_visibility restrictions - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'result_count', - 'sql_sort_table', - 'sql_sort_join', - 'author_ary', - 'author_name', - 'sql_author', - 'topic_id', - 'sql_topic_id', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'sort_days', - 'sql_time', - 'firstpost_only', - 'ex_fid_ary', - 'sql_fora', - 'm_approve_fid_sql', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_author_count_query_before', compact($vars))); - - // Build the query for really selecting the post_ids - if ($type == 'posts') - { - $sql = "SELECT p.post_id - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_sort_join - $sql_time - ORDER BY $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = "SELECT t.topic_id - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id, $sort_by_sql[$sort_key] - ORDER BY $sql_sort"; - $field = 'topic_id'; - } - - $this->db->sql_transaction('begin'); - - // Only read one block of posts from the db and then cache it - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = $row[$field]; - } - $this->db->sql_freeresult($result); - - // retrieve the total result count if needed - if (!$result_count) - { - if ($type == 'posts') - { - $sql_count = "SELECT COUNT(*) as result_count - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_sort_join - $sql_time"; - } - else - { - $sql_count = "SELECT COUNT(*) as result_count - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id, $sort_by_sql[$sort_key]"; - } - - $this->db->sql_query($sql_count); - $result_count = (int) $this->db->sql_fetchfield('result_count'); - - if (!$result_count) - { - return false; - } - } - - $this->db->sql_transaction('commit'); - - if ($start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - } - - if (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); - - return $result_count; - } - return false; - } - - /** - * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated - * - * @param string $mode contains the post mode: edit, post, reply, quote ... - * @param int $post_id contains the post id of the post to index - * @param string $message contains the post text of the post - * @param string $subject contains the subject of the post to index - * @param int $poster_id contains the user id of the poster - * @param int $forum_id contains the forum id of parent forum of the post - */ - public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - // Split old and new post/subject to obtain array of words - $split_text = $this->split_message($message); - $split_title = ($subject) ? $this->split_message($subject) : array(); - - $words = array_unique(array_merge($split_text, $split_title)); - - /** - * 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); - - // destroy cached search results containing any of the words removed or added - $this->destroy_cache($words, array($poster_id)); - - unset($words); - } - - /** - * Destroy cached results, that might be outdated after deleting a post - */ - public function index_remove($post_ids, $author_ids, $forum_ids) - { - $this->destroy_cache(array(), $author_ids); - } - - /** - * Destroy old cache entries - */ - public function tidy() - { - // destroy too old cached search results - $this->destroy_cache(array()); - - $this->config->set('search_last_gc', time(), false); - } - - /** - * Create fulltext index - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function create_index($acp_module, $u_action) - { - // Make sure we can actually use PostgreSQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $sql_queries = []; - - if (!isset($this->stats['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'])) - { - $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); - - return false; - } - - /** - * Drop fulltext index - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function delete_index($acp_module, $u_action) - { - // Make sure we can actually use PostgreSQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $sql_queries = []; - - if (isset($this->stats['post_subject'])) - { - $sql_queries[] = 'DROP INDEX ' . $this->stats['post_subject']['relname']; - } - - if (isset($this->stats['post_content'])) - { - $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); - - return false; - } - - /** - * Returns true if both FULLTEXT indexes exist - */ - public function index_created() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return (isset($this->stats['post_subject']) && isset($this->stats['post_content'])) ? true : false; - } - - /** - * Returns an associative array containing information about the indexes - */ - public function index_stats() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return array( - $this->user->lang['FULLTEXT_POSTGRES_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0, - ); - } - - /** - * Computes the stats and store them in the $this->stats associative array - */ - protected function get_stats() - { - if ($this->db->get_sql_layer() != 'postgres') - { - $this->stats = array(); - return; - } - - $sql = "SELECT c2.relname, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) AS indexdef - FROM pg_catalog.pg_class c1, pg_catalog.pg_index i, pg_catalog.pg_class c2 - WHERE c1.relname = '" . POSTS_TABLE . "' - AND pg_catalog.pg_table_is_visible(c1.oid) - AND c1.oid = i.indrelid - AND i.indexrelid = c2.oid"; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - // deal with older PostgreSQL versions which didn't use Index_type - if (strpos($row['indexdef'], 'to_tsvector') !== false) - { - if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_subject' || $row['relname'] == POSTS_TABLE . '_post_subject') - { - $this->stats['post_subject'] = $row; - } - else if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_content' || $row['relname'] == POSTS_TABLE . '_post_content') - { - $this->stats['post_content'] = $row; - } - } - } - $this->db->sql_freeresult($result); - - $this->stats['total_posts'] = $this->config['num_posts']; - } - - /** - * Display various options that can be configured for the backend from the acp - * - * @return associative array containing template and config variables - */ - public function acp() - { - $tpl = ' -
-

' . $this->user->lang['FULLTEXT_POSTGRES_VERSION_CHECK_EXPLAIN'] . '
-
' . (($this->db->get_sql_layer() == 'postgres') ? $this->user->lang['YES'] : $this->user->lang['NO']) . '
-
-
-

' . $this->user->lang['FULLTEXT_POSTGRES_TS_NAME_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_POSTGRES_MIN_WORD_LEN_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_POSTGRES_MAX_WORD_LEN_EXPLAIN'] . '
-
-
- '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array('fulltext_postgres_ts_name' => 'string', 'fulltext_postgres_min_word_len' => 'integer:0:255', 'fulltext_postgres_max_word_len' => 'integer:0:255') - ); - } -} diff --git a/install/update/new/phpbb/search/fulltext_sphinx.php b/install/update/new/phpbb/search/fulltext_sphinx.php deleted file mode 100644 index d2e12fd..0000000 --- a/install/update/new/phpbb/search/fulltext_sphinx.php +++ /dev/null @@ -1,993 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\search; - -define('SPHINX_MAX_MATCHES', 20000); -define('SPHINX_CONNECT_RETRIES', 3); -define('SPHINX_CONNECT_WAIT_TIME', 300); - -/** -* Fulltext search based on the sphinx search daemon -*/ -class fulltext_sphinx -{ - /** - * Associative array holding index stats - * @var array - */ - protected $stats = array(); - - /** - * Holds the words entered by user, obtained by splitting the entered query on whitespace - * @var array - */ - protected $split_words = array(); - - /** - * Holds unique sphinx id - * @var string - */ - protected $id; - - /** - * Stores the names of both main and delta sphinx indexes - * separated by a semicolon - * @var string - */ - protected $indexes; - - /** - * Sphinx searchd client object - * @var SphinxClient - */ - protected $sphinx; - - /** - * Relative path to board root - * @var string - */ - protected $phpbb_root_path; - - /** - * PHP Extension - * @var string - */ - protected $php_ext; - - /** - * Auth object - * @var \phpbb\auth\auth - */ - protected $auth; - - /** - * Config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Database connection - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * Database Tools object - * @var \phpbb\db\tools\tools_interface - */ - protected $db_tools; - - /** - * Stores the database type if supported by sphinx - * @var string - */ - protected $dbtype; - - /** - * phpBB event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Stores the generated content of the sphinx config file - * @var string - */ - protected $config_file_data = ''; - - /** - * Contains tidied search query. - * Operators are prefixed in search query and common words excluded - * @var string - */ - protected $search_query; - - /** - * Constructor - * Creates a new \phpbb\search\fulltext_postgres, which is used as a search backend - * - * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $phpEx PHP file extension - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\db\driver\driver_interface Database object - * @param \phpbb\user $user User object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - */ - public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $phpEx; - $this->config = $config; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->user = $user; - $this->db = $db; - $this->auth = $auth; - - // 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']) - { - $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'; - - if (!class_exists('SphinxClient')) - { - require($this->phpbb_root_path . 'includes/sphinxapi.' . $this->php_ext); - } - - // Initialize sphinx client - $this->sphinx = new \SphinxClient(); - - $this->sphinx->SetServer(($this->config['fulltext_sphinx_host'] ? $this->config['fulltext_sphinx_host'] : 'localhost'), ($this->config['fulltext_sphinx_port'] ? (int) $this->config['fulltext_sphinx_port'] : 9312)); - - $error = false; - } - - /** - * Returns the name of this search backend to be displayed to administrators - * - * @return string Name - */ - public function get_name() - { - return 'Sphinx Fulltext'; - } - - /** - * Returns the search_query - * - * @return string search query - */ - public function get_search_query() - { - return $this->search_query; - } - - /** - * Returns false as there is no word_len array - * - * @return false - */ - public function get_word_length() - { - return false; - } - - /** - * Returns an empty array as there are no common_words - * - * @return array common words that are ignored by search backend - */ - public function get_common_words() - { - return array(); - } - - /** - * Checks permissions and paths, if everything is correct it generates the config file - * - * @return string|bool Language key of the error/incompatibility encountered, or false if successful - */ - public function init() - { - if ($this->db->get_sql_layer() != 'mysqli' && $this->db->get_sql_layer() != 'postgres') - { - return $this->user->lang['FULLTEXT_SPHINX_WRONG_DATABASE']; - } - - // Move delta to main index each hour - $this->config->set('search_gc', 3600); - - return false; - } - - /** - * Generates content of sphinx.conf - * - * @return bool True if sphinx.conf content is correctly generated, false otherwise - */ - protected function config_generate() - { - // Check if Database is supported by Sphinx - if ($this->db->get_sql_layer() == 'mysqli') - { - $this->dbtype = 'mysql'; - } - else if ($this->db->get_sql_layer() == 'postgres') - { - $this->dbtype = 'pgsql'; - } - else - { - $this->config_file_data = $this->user->lang('FULLTEXT_SPHINX_WRONG_DATABASE'); - return false; - } - - // Check if directory paths have been filled - if (!$this->config['fulltext_sphinx_data_path']) - { - $this->config_file_data = $this->user->lang('FULLTEXT_SPHINX_NO_CONFIG_DATA'); - return false; - } - - include($this->phpbb_root_path . 'config.' . $this->php_ext); - - /* Now that we're sure everything was entered correctly, - generate a config for the index. We use a config value - fulltext_sphinx_id for this, as it should be unique. */ - $config_object = new \phpbb\search\sphinx\config($this->config_file_data); - $config_data = array( - 'source source_phpbb_' . $this->id . '_main' => array( - array('type', $this->dbtype . ' # mysql or pgsql'), - // This config value sql_host needs to be changed incase sphinx and sql are on different servers - array('sql_host', $dbhost . ' # SQL server host sphinx connects to'), - array('sql_user', '[dbuser]'), - array('sql_pass', '[dbpassword]'), - array('sql_db', $dbname), - array('sql_port', $dbport . ' # optional, default is 3306 for mysql and 5432 for pgsql'), - array('sql_query_pre', 'SET NAMES \'utf8\''), - array('sql_query_pre', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = (SELECT MAX(post_id) FROM ' . POSTS_TABLE . ') WHERE counter_id = 1'), - array('sql_query_range', 'SELECT MIN(post_id), MAX(post_id) FROM ' . POSTS_TABLE . ''), - array('sql_range_step', '5000'), - array('sql_query', 'SELECT - p.post_id AS id, - p.forum_id, - p.topic_id, - p.poster_id, - p.post_visibility, - CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, - p.post_time, - p.post_subject, - p.post_subject as title, - p.post_text as data, - t.topic_last_post_time, - 0 as deleted - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t - WHERE - p.topic_id = t.topic_id - AND p.post_id >= $start AND p.post_id <= $end'), - array('sql_query_post', ''), - array('sql_query_post_index', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = $maxid WHERE counter_id = 1'), - array('sql_attr_uint', 'forum_id'), - array('sql_attr_uint', 'topic_id'), - array('sql_attr_uint', 'poster_id'), - array('sql_attr_uint', 'post_visibility'), - array('sql_attr_bool', 'topic_first_post'), - array('sql_attr_bool', 'deleted'), - array('sql_attr_timestamp', 'post_time'), - array('sql_attr_timestamp', 'topic_last_post_time'), - array('sql_attr_string', 'post_subject'), - ), - 'source source_phpbb_' . $this->id . '_delta : source_phpbb_' . $this->id . '_main' => array( - array('sql_query_pre', 'SET NAMES \'utf8\''), - array('sql_query_range', ''), - array('sql_range_step', ''), - array('sql_query', 'SELECT - p.post_id AS id, - p.forum_id, - p.topic_id, - p.poster_id, - p.post_visibility, - CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, - p.post_time, - p.post_subject, - p.post_subject as title, - p.post_text as data, - t.topic_last_post_time, - 0 as deleted - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t - WHERE - p.topic_id = t.topic_id - AND p.post_id >= ( SELECT max_doc_id FROM ' . SPHINX_TABLE . ' WHERE counter_id=1 )'), - 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'), - array('source', 'source_phpbb_' . $this->id . '_main'), - array('docinfo', 'extern'), - array('morphology', 'none'), - array('stopwords', ''), - array('min_word_len', '2'), - 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'), - array('source', 'source_phpbb_' . $this->id . '_delta'), - ), - 'indexer' => array( - array('mem_limit', $this->config['fulltext_sphinx_indexer_mem_limit'] . 'M'), - ), - 'searchd' => array( - 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('binlog_path', $this->config['fulltext_sphinx_data_path']), - ), - ); - - $non_unique = array('sql_query_pre' => true, 'sql_attr_uint' => true, 'sql_attr_timestamp' => true, 'sql_attr_str2ordinal' => true, 'sql_attr_bool' => true); - $delete = array('sql_group_column' => true, 'sql_date_column' => true, 'sql_str2ordinal_column' => true); - - /** - * Allow adding/changing the Sphinx configuration data - * - * @event core.search_sphinx_modify_config_data - * @var array config_data Array with the Sphinx configuration data - * @var array non_unique Array with the Sphinx non-unique variables to delete - * @var array delete Array with the Sphinx variables to delete - * @since 3.1.7-RC1 - */ - $vars = array( - 'config_data', - 'non_unique', - 'delete', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_sphinx_modify_config_data', compact($vars))); - - foreach ($config_data as $section_name => $section_data) - { - $section = $config_object->get_section_by_name($section_name); - if (!$section) - { - $section = $config_object->add_section($section_name); - } - - foreach ($delete as $key => $void) - { - $section->delete_variables_by_name($key); - } - - foreach ($non_unique as $key => $void) - { - $section->delete_variables_by_name($key); - } - - foreach ($section_data as $entry) - { - $key = $entry[0]; - $value = $entry[1]; - - if (!isset($non_unique[$key])) - { - $variable = $section->get_variable_by_name($key); - if (!$variable) - { - $section->create_variable($key, $value); - } - else - { - $variable->set_value($value); - } - } - else - { - $section->create_variable($key, $value); - } - } - } - $this->config_file_data = $config_object->get_data(); - - return true; - } - - /** - * Splits keywords entered by a user into an array of words stored in $this->split_words - * Stores the tidied search query in $this->search_query - * - * @param string $keywords Contains the keyword as entered by the user - * @param string $terms is either 'all' or 'any' - * @return false if no valid keywords were found and otherwise true - */ - public function split_keywords(&$keywords, $terms) - { - if ($terms == 'all') - { - $match = array('#\sand\s#i', '#\sor\s#i', '#\snot\s#i', '#\+#', '#-#', '#\|#', '#@#'); - $replace = array(' & ', ' | ', ' - ', ' +', ' -', ' |', ''); - - $keywords = preg_replace($match, $replace, $keywords); - $this->sphinx->SetMatchMode(SPH_MATCH_EXTENDED); - } - else - { - $this->sphinx->SetMatchMode(SPH_MATCH_ANY); - } - - // Keep quotes and new lines - $keywords = str_replace(array('"', "\n"), array('"', ' '), trim($keywords)); - - if (strlen($keywords) > 0) - { - $this->search_query = str_replace('"', '"', $keywords); - return true; - } - - return false; - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $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) && !count($author_ary)) - { - return false; - } - - $id_ary = array(); - - // Sorting - - if ($type == 'topics') - { - switch ($sort_key) - { - case 'a': - $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'poster_id ' . (($sort_dir == 'a') ? 'ASC' : 'DESC')); - break; - - case 'f': - $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'forum_id ' . (($sort_dir == 'a') ? 'ASC' : 'DESC')); - break; - - case 'i': - - case 's': - $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'post_subject ' . (($sort_dir == 'a') ? 'ASC' : 'DESC')); - break; - - case 't': - - default: - $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'topic_last_post_time ' . (($sort_dir == 'a') ? 'ASC' : 'DESC')); - break; - } - } - else - { - switch ($sort_key) - { - case 'a': - $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'poster_id'); - break; - - case 'f': - $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'forum_id'); - break; - - case 'i': - - case 's': - $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_subject'); - break; - - case 't': - - default: - $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_time'); - break; - } - } - - // Most narrow filters first - if ($topic_id) - { - $this->sphinx->SetFilter('topic_id', array($topic_id)); - } - - /** - * Allow modifying the Sphinx search options - * - * @event core.search_sphinx_keywords_modify_options - * @var string type Searching type ('posts', 'topics') - * @var string fields Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') - * @var string terms Searching terms ('all', 'any') - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name The username to search on - * @var object sphinx The Sphinx searchd client object - * @since 3.1.7-RC1 - */ - $sphinx = $this->sphinx; - $vars = array( - 'type', - 'fields', - 'terms', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - 'author_name', - 'sphinx', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_sphinx_keywords_modify_options', compact($vars))); - $this->sphinx = $sphinx; - unset($sphinx); - - $search_query_prefix = ''; - - switch ($fields) - { - case 'titleonly': - // Only search the title - if ($terms == 'all') - { - $search_query_prefix = '@title '; - } - // Weight for the title - $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); - // 1 is first_post, 0 is not first post - $this->sphinx->SetFilter('topic_first_post', array(1)); - break; - - case 'msgonly': - // Only search the body - if ($terms == 'all') - { - $search_query_prefix = '@data '; - } - // Weight for the body - $this->sphinx->SetFieldWeights(array("title" => 1, "data" => 5)); - break; - - case 'firstpost': - // More relative weight for the title, also search the body - $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); - // 1 is first_post, 0 is not first post - $this->sphinx->SetFilter('topic_first_post', array(1)); - break; - - default: - // More relative weight for the title, also search the body - $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); - break; - } - - if (count($author_ary)) - { - $this->sphinx->SetFilter('poster_id', $author_ary); - } - - // As this is not simply possible at the moment, we limit the result to approved posts. - // This will make it impossible for moderators to search unapproved and softdeleted posts, - // but at least it will also cause the same for normal users. - $this->sphinx->SetFilter('post_visibility', array(ITEM_APPROVED)); - - 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 (count($search_forums)) - { - $this->sphinx->SetFilter('forum_id', $search_forums); - } - } - - $this->sphinx->SetFilter('deleted', array(0)); - - $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('"', '"', $this->search_query)), $this->indexes); - - // Could be connection to localhost:9312 failed (errno=111, - // msg=Connection refused) during rotate, retry if so - $retries = SPHINX_CONNECT_RETRIES; - while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--) - { - usleep(SPHINX_CONNECT_WAIT_TIME); - $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); - } - - if ($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())); - } - else - { - trigger_error($this->user->lang('SPHINX_SEARCH_FAILED_LOG')); - } - } - - $result_count = $result['total_found']; - - if ($result_count && $start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $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('"', '"', $this->search_query)), $this->indexes); - - // Could be connection to localhost:9312 failed (errno=111, - // msg=Connection refused) during rotate, retry if so - $retries = SPHINX_CONNECT_RETRIES; - while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--) - { - usleep(SPHINX_CONNECT_WAIT_TIME); - $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); - } - } - - $id_ary = array(); - if (isset($result['matches'])) - { - if ($type == 'posts') - { - $id_ary = array_keys($result['matches']); - } - else - { - foreach ($result['matches'] as $key => $value) - { - $id_ary[] = $value['attrs']['topic_id']; - } - } - } - else - { - return false; - } - - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $result_count; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) - { - $this->search_query = ''; - - $this->sphinx->SetMatchMode(SPH_MATCH_FULLSCAN); - $fields = ($firstpost_only) ? 'firstpost' : 'all'; - $terms = 'all'; - return $this->keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, $id_ary, $start, $per_page); - } - - /** - * Updates wordlist and wordmatch tables when a message is posted or changed - * - * @param string $mode Contains the post mode: edit, post, reply, quote - * @param int $post_id The id of the post which is modified/created - * @param string &$message New or updated post content - * @param string &$subject New or updated post subject - * @param int $poster_id Post author's user id - * @param int $forum_id The id of the forum in which the post is located - */ - public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - /** - * 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))); - } - else if ($mode != 'post' && $post_id) - { - // Update topic_last_post_time for full topic - $sql_array = array( - 'SELECT' => 'p1.post_id', - 'FROM' => array( - POSTS_TABLE => 'p1', - ), - 'LEFT_JOIN' => array(array( - 'FROM' => array( - POSTS_TABLE => 'p2' - ), - 'ON' => 'p1.topic_id = p2.topic_id', - )), - 'WHERE' => 'p2.post_id = ' . ((int) $post_id), - ); - - $sql = $this->db->sql_build_query('SELECT', $sql_array); - $result = $this->db->sql_query($sql); - - $post_updates = array(); - $post_time = time(); - while ($row = $this->db->sql_fetchrow($result)) - { - $post_updates[(int) $row['post_id']] = array($post_time); - } - $this->db->sql_freeresult($result); - - if (count($post_updates)) - { - $this->sphinx->UpdateAttributes($this->indexes, array('topic_last_post_time'), $post_updates); - } - } - } - - /** - * Delete a post from the index after it was deleted - */ - public function index_remove($post_ids, $author_ids, $forum_ids) - { - $values = array(); - foreach ($post_ids as $post_id) - { - $values[$post_id] = array(1); - } - - $this->sphinx->UpdateAttributes($this->indexes, array('deleted'), $values); - } - - /** - * Nothing needs to be destroyed - */ - public function tidy($create = false) - { - $this->config->set('search_last_gc', time(), false); - } - - /** - * Create sphinx table - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function create_index($acp_module, $u_action) - { - if (!$this->index_created()) - { - $table_data = array( - 'COLUMNS' => array( - 'counter_id' => array('UINT', 0), - 'max_doc_id' => array('UINT', 0), - ), - 'PRIMARY_KEY' => 'counter_id', - ); - $this->db_tools->sql_create_table(SPHINX_TABLE, $table_data); - - $sql = 'TRUNCATE TABLE ' . SPHINX_TABLE; - $this->db->sql_query($sql); - - $data = array( - 'counter_id' => '1', - 'max_doc_id' => '0', - ); - $sql = 'INSERT INTO ' . SPHINX_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data); - $this->db->sql_query($sql); - } - - return false; - } - - /** - * Drop sphinx table - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function delete_index($acp_module, $u_action) - { - if (!$this->index_created()) - { - return false; - } - - $this->db_tools->sql_table_drop(SPHINX_TABLE); - - return false; - } - - /** - * Returns true if the sphinx table was created - * - * @return bool true if sphinx table was created - */ - public function index_created($allow_new_files = true) - { - $created = false; - - if ($this->db_tools->sql_table_exists(SPHINX_TABLE)) - { - $created = true; - } - - return $created; - } - - /** - * Returns an associative array containing information about the indexes - * - * @return string|bool Language string of error false otherwise - */ - public function index_stats() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return array( - $this->user->lang['FULLTEXT_SPHINX_MAIN_POSTS'] => ($this->index_created()) ? $this->stats['main_posts'] : 0, - $this->user->lang['FULLTEXT_SPHINX_DELTA_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] - $this->stats['main_posts'] : 0, - $this->user->lang['FULLTEXT_MYSQL_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0, - ); - } - - /** - * Collects stats that can be displayed on the index maintenance page - */ - protected function get_stats() - { - if ($this->index_created()) - { - $sql = 'SELECT COUNT(post_id) as total_posts - FROM ' . POSTS_TABLE; - $result = $this->db->sql_query($sql); - $this->stats['total_posts'] = (int) $this->db->sql_fetchfield('total_posts'); - $this->db->sql_freeresult($result); - - $sql = 'SELECT COUNT(p.post_id) as main_posts - FROM ' . POSTS_TABLE . ' p, ' . SPHINX_TABLE . ' m - WHERE p.post_id <= m.max_doc_id - AND m.counter_id = 1'; - $result = $this->db->sql_query($sql); - $this->stats['main_posts'] = (int) $this->db->sql_fetchfield('main_posts'); - $this->db->sql_freeresult($result); - } - } - - /** - * Returns a list of options for the ACP to display - * - * @return associative array containing template and config variables - */ - public function acp() - { - $config_vars = array( - 'fulltext_sphinx_data_path' => 'string', - 'fulltext_sphinx_host' => 'string', - 'fulltext_sphinx_port' => 'string', - 'fulltext_sphinx_indexer_mem_limit' => 'int', - ); - - $tpl = ' - ' . $this->user->lang['FULLTEXT_SPHINX_CONFIGURE']. ' -
-

' . $this->user->lang['FULLTEXT_SPHINX_DATA_PATH_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_SPHINX_HOST_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_SPHINX_PORT_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_SPHINX_INDEXER_MEM_LIMIT_EXPLAIN'] . '
-
' . $this->user->lang['MIB'] . '
-
-
-

' . $this->user->lang['FULLTEXT_SPHINX_CONFIG_FILE_EXPLAIN'] . '
-
' . (($this->config_generate()) ? '' : $this->config_file_data) . '
-
- '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => $config_vars - ); - } -} diff --git a/install/update/new/phpbb/session.php b/install/update/new/phpbb/session.php deleted file mode 100644 index 6851bc8..0000000 --- a/install/update/new/phpbb/session.php +++ /dev/null @@ -1,1667 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* Session class -*/ -class session -{ - var $cookie_data = array(); - var $page = array(); - var $data = array(); - var $browser = ''; - var $forwarded_for = ''; - var $host = ''; - var $session_id = ''; - var $ip = ''; - var $load = 0; - var $time_now = 0; - var $update_session_page = true; - - /** - * Extract current session page - * - * @param string $root_path current root path (phpbb_root_path) - * @return array - */ - static function extract_current_page($root_path) - { - global $request, $symfony_request, $phpbb_filesystem; - - $page_array = array(); - - // First of all, get the request uri... - $script_name = $request->escape($symfony_request->getScriptName(), true); - $args = $request->escape(explode('&', $symfony_request->getQueryString()), true); - - // If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support... - if (!$script_name) - { - $script_name = htmlspecialchars_decode($request->server('REQUEST_URI')); - $script_name = (($pos = strpos($script_name, '?')) !== false) ? substr($script_name, 0, $pos) : $script_name; - $page_array['failover'] = 1; - } - - // Replace backslashes and doubled slashes (could happen on some proxy setups) - $script_name = str_replace(array('\\', '//'), '/', $script_name); - - // Now, remove the sid and let us get a clean query string... - $use_args = array(); - - // Since some browser do not encode correctly we need to do this with some "special" characters... - // " -> %22, ' => %27, < -> %3C, > -> %3E - $find = array('"', "'", '<', '>', '"', '<', '>'); - $replace = array('%22', '%27', '%3C', '%3E', '%22', '%3C', '%3E'); - - foreach ($args as $key => $argument) - { - if (strpos($argument, 'sid=') === 0) - { - continue; - } - - $use_args[] = str_replace($find, $replace, $argument); - } - unset($args); - - // The following examples given are for an request uri of {path to the phpbb directory}/adm/index.php?i=10&b=2 - - // The current query string - $query_string = trim(implode('&', $use_args)); - - // basenamed page name (for example: index.php) - $page_name = (substr($script_name, -1, 1) == '/') ? '' : basename($script_name); - $page_name = urlencode(htmlspecialchars($page_name)); - - $symfony_request_path = $phpbb_filesystem->clean_path($symfony_request->getPathInfo()); - if ($symfony_request_path !== '/') - { - $page_name .= str_replace('%2F', '/', urlencode($symfony_request_path)); - } - - 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('../', count($root_dirs)) . implode('/', $page_dirs); - - if ($page_dir && substr($page_dir, -1, 1) == '/') - { - $page_dir = substr($page_dir, 0, -1); - } - - // Current page from phpBB root (for example: adm/index.php?i=10&b=2) - $page = (($page_dir) ? $page_dir . '/' : '') . $page_name; - if ($query_string) - { - $page .= '?' . $query_string; - } - - // The script path from the webroot to the current directory (for example: /phpBB3/adm/) : always prefixed with / and ends in / - $script_path = $symfony_request->getBasePath(); - - // The script path from the webroot to the phpBB root (for example: /phpBB3/) - $script_dirs = explode('/', $script_path); - 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) - { - $root_script_path = ($page_dir) ? str_replace($page_dir, '', $script_path) : $script_path; - } - - $script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/'; - $root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/'; - - $forum_id = $request->variable('f', 0); - // maximum forum id value is maximum value of mediumint unsigned column - $forum_id = ($forum_id > 0 && $forum_id < 16777215) ? $forum_id : 0; - - $page_array += array( - 'page_name' => $page_name, - 'page_dir' => $page_dir, - - 'query_string' => $query_string, - 'script_path' => str_replace(' ', '%20', htmlspecialchars($script_path)), - 'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)), - - 'page' => $page, - 'forum' => $forum_id, - ); - - return $page_array; - } - - /** - * Get valid hostname/port. HTTP_HOST is used, SERVER_NAME if HTTP_HOST not present. - */ - function extract_current_hostname() - { - global $config, $request; - - // Get hostname - $host = htmlspecialchars_decode($request->header('Host', $request->server('SERVER_NAME'))); - - // Should be a string and lowered - $host = (string) strtolower($host); - - // If host is equal the cookie domain or the server name (if config is set), then we assume it is valid - if ((isset($config['cookie_domain']) && $host === $config['cookie_domain']) || (isset($config['server_name']) && $host === $config['server_name'])) - { - return $host; - } - - // Is the host actually a IP? If so, we use the IP... (IPv4) - if (long2ip(ip2long($host)) === $host) - { - return $host; - } - - // Now return the hostname (this also removes any port definition). The http:// is prepended to construct a valid URL, hosts never have a scheme assigned - $host = @parse_url('http://' . $host); - $host = (!empty($host['host'])) ? $host['host'] : ''; - - // Remove any portions not removed by parse_url (#) - $host = str_replace('#', '', $host); - - // If, by any means, the host is now empty, we will use a "best approach" way to guess one - if (empty($host)) - { - if (!empty($config['server_name'])) - { - $host = $config['server_name']; - } - else if (!empty($config['cookie_domain'])) - { - $host = (strpos($config['cookie_domain'], '.') === 0) ? substr($config['cookie_domain'], 1) : $config['cookie_domain']; - } - else - { - // Set to OS hostname or localhost - $host = (function_exists('php_uname')) ? php_uname('n') : 'localhost'; - } - } - - // It may be still no valid host, but for sure only a hostname (we may further expand on the cookie domain... if set) - return $host; - } - - /** - * Start session management - * - * This is where all session activity begins. We gather various pieces of - * information from the client and server. We test to see if a session already - * exists. If it does, fine and dandy. If it doesn't we'll go on to create a - * new one ... pretty logical heh? We also examine the system load (if we're - * running on a system which makes such information readily available) and - * halt if it's above an admin definable limit. - * - * @param bool $update_session_page if true the session page gets updated. - * This can be set to circumvent certain scripts to update the users last visited page. - */ - function session_begin($update_session_page = true) - { - global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path; - global $request, $phpbb_container, $user, $phpbb_log, $phpbb_dispatcher; - - // Give us some basic information - $this->time_now = time(); - $this->cookie_data = array('u' => 0, 'k' => ''); - $this->update_session_page = $update_session_page; - $this->browser = $request->header('User-Agent'); - $this->referer = $request->header('Referer'); - $this->forwarded_for = $request->header('X-Forwarded-For'); - - $this->host = $this->extract_current_hostname(); - $this->page = $this->extract_current_page($phpbb_root_path); - - // if the forwarded for header shall be checked we have to validate its contents - if ($config['forwarded_for_check']) - { - $this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for)); - - // split the list of IPs - $ips = explode(' ', $this->forwarded_for); - foreach ($ips as $ip) - { - if (!filter_var($ip, FILTER_VALIDATE_IP)) - { - // contains invalid data, don't use the forwarded for header - $this->forwarded_for = ''; - break; - } - } - } - else - { - $this->forwarded_for = ''; - } - - if ($request->is_set($config['cookie_name'] . '_sid', \phpbb\request\request_interface::COOKIE) || $request->is_set($config['cookie_name'] . '_u', \phpbb\request\request_interface::COOKIE)) - { - $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->variable('sid', ''); - $SID = '?sid=' . $this->session_id; - $this->cookie_data = array('u' => 0, 'k' => ''); - } - } - else - { - $this->session_id = $_SID = $request->variable('sid', ''); - $SID = '?sid=' . $this->session_id; - } - - $_EXTRA_URL = array(); - - // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests - // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. - $ip = htmlspecialchars_decode($request->server('REMOTE_ADDR')); - $ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $ip)); - - /** - * Event to alter user IP address - * - * @event core.session_ip_after - * @var string ip REMOTE_ADDR - * @since 3.1.10-RC1 - */ - $vars = array('ip'); - extract($phpbb_dispatcher->trigger_event('core.session_ip_after', compact($vars))); - - // split the list of IPs - $ips = explode(' ', trim($ip)); - - // Default IP if REMOTE_ADDR is invalid - $this->ip = '127.0.0.1'; - - foreach ($ips as $ip) - { - // Normalise IP address - $ip = phpbb_ip_normalise($ip); - - if ($ip === false) - { - // IP address is invalid. - break; - } - - // IP address is valid. - $this->ip = $ip; - } - - $this->load = false; - - // Load limit check (if applicable) - if ($config['limit_load'] || $config['limit_search_load']) - { - if ((function_exists('sys_getloadavg') && $load = sys_getloadavg()) || ($load = explode(' ', @file_get_contents('/proc/loadavg')))) - { - $this->load = array_slice($load, 0, 1); - $this->load = floatval($this->load[0]); - } - else - { - $config->set('limit_load', '0'); - $config->set('limit_search_load', '0'); - } - } - - // if no session id is set, redirect to index.php - $session_id = $request->variable('sid', ''); - if (defined('NEED_SID') && (empty($session_id) || $this->session_id !== $session_id)) - { - send_status_line(401, 'Unauthorized'); - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - // if session id is set - if (!empty($this->session_id)) - { - $sql = 'SELECT u.*, s.* - FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u - WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "' - AND u.user_id = s.session_user_id"; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Did the session exist in the DB? - if (isset($this->data['user_id'])) - { - // Validate IP length according to admin ... enforces an IP - // check on bots if admin requires this -// $quadcheck = ($config['ip_check_bot'] && $this->data['user_type'] & USER_BOT) ? 4 : $config['ip_check']; - - if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false) - { - $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']); - $u_ip = short_ipv6($this->ip, $config['ip_check']); - } - else - { - $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); - $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); - } - - $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : ''; - $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : ''; - - $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; - $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; - - // referer checks - // The @ before $config['referer_validation'] suppresses notices present while running the updater - $check_referer_path = (@$config['referer_validation'] == REFERER_VALIDATE_PATH); - $referer_valid = true; - - // we assume HEAD and TRACE to be foul play and thus only whitelist GET - if (@$config['referer_validation'] && strtolower($request->server('REQUEST_METHOD')) !== 'get') - { - $referer_valid = $this->validate_referer($check_referer_path); - } - - if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for && $referer_valid) - { - $session_expired = false; - - // Check whether the session is still valid if we have one - /* @var $provider_collection \phpbb\auth\provider_collection */ - $provider_collection = $phpbb_container->get('auth.provider_collection'); - $provider = $provider_collection->get_provider(); - - if (!($provider instanceof \phpbb\auth\provider\provider_interface)) - { - throw new \RuntimeException($provider . ' must implement \phpbb\auth\provider\provider_interface'); - } - - $ret = $provider->validate_session($this->data); - if ($ret !== null && !$ret) - { - $session_expired = true; - } - - if (!$session_expired) - { - // Check the session length timeframe if autologin is not enabled. - // Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide. - if (!$this->data['session_autologin']) - { - if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60)) - { - $session_expired = true; - } - } - else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60)) - { - $session_expired = true; - } - } - - if (!$session_expired) - { - $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; - $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false; - $this->data['user_lang'] = basename($this->data['user_lang']); - - // Is user banned? Are they excluded? Won't return on ban, exists within method - $this->check_ban_for_current_session($config); - - return true; - } - } - else - { - // Added logging temporarily to help debug bugs... - if ($phpbb_container->getParameter('session.log_errors') && $this->data['user_id'] != ANONYMOUS) - { - if ($referer_valid) - { - $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 - { - $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_REFERER_INVALID', false, array($this->referer)); - } - } - } - } - } - - // If we reach here then no (valid) session exists. So we'll create a new one - return $this->session_create(); - } - - /** - * Create a new session - * - * If upon trying to start a session we discover there is nothing existing we - * jump here. Additionally this method is called directly during login to regenerate - * the session for the specific user. In this method we carry out a number of tasks; - * garbage collection, (search)bot checking, banned user comparison. Basically - * though this method will result in a new session for a specific user. - */ - function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true) - { - global $SID, $_SID, $db, $config, $cache, $phpbb_container, $phpbb_dispatcher; - - $this->data = array(); - - /* Garbage collection ... remove old sessions updating user information - // if necessary. It means (potentially) 11 queries but only infrequently - if ($this->time_now > $config['session_last_gc'] + $config['session_gc']) - { - $this->session_gc(); - }*/ - - // Do we allow autologin on this board? No? Then override anything - // that may be requested here - if (!$config['allow_autologin']) - { - $this->cookie_data['k'] = $persist_login = false; - } - - /** - * Here we do a bot check, oh er saucy! No, not that kind of bot - * check. We loop through the list of bots defined by the admin and - * see if we have any useragent and/or IP matches. If we do, this is a - * bot, act accordingly - */ - $bot = false; - $active_bots = $cache->obtain_bots(); - - foreach ($active_bots as $row) - { - if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser)) - { - $bot = $row['user_id']; - } - - // If ip is supplied, we will make sure the ip is matching too... - if ($row['bot_ip'] && ($bot || !$row['bot_agent'])) - { - // Set bot to false, then we only have to set it to true if it is matching - $bot = false; - - foreach (explode(',', $row['bot_ip']) as $bot_ip) - { - $bot_ip = trim($bot_ip); - - if (!$bot_ip) - { - continue; - } - - if (strpos($this->ip, $bot_ip) === 0) - { - $bot = (int) $row['user_id']; - break; - } - } - } - - if ($bot) - { - break; - } - } - - /* @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 && isset($this->data['user_id']) && $this->data['user_id'] != $user_id) - { - $this->data = array(); - } - - if (isset($this->data['user_id'])) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = $this->data['user_id']; - } - - // If we're presented with an autologin key we'll join against it. - // Else if we've been passed a user_id we'll grab data based on that - if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && empty($this->data)) - { - $sql = 'SELECT u.* - FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k - WHERE u.user_id = ' . (int) $this->cookie_data['u'] . ' - AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ") - AND k.user_id = u.user_id - AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; - $result = $db->sql_query($sql); - $user_data = $db->sql_fetchrow($result); - - if ($user_id === false || (isset($user_data['user_id']) && $user_id == $user_data['user_id'])) - { - $this->data = $user_data; - $bot = false; - } - - $db->sql_freeresult($result); - } - - if ($user_id !== false && empty($this->data)) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = $user_id; - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $this->cookie_data['u'] . ' - AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - $bot = false; - } - - // Bot user, if they have a SID in the Request URI we need to get rid of it - // otherwise they'll index this page with the SID, duplicate content oh my! - if ($bot && isset($_GET['sid'])) - { - send_status_line(301, 'Moved Permanently'); - redirect(build_url(array('sid'))); - } - - // If no data was returned one or more of the following occurred: - // Key didn't match one in the DB - // User does not exist - // User is inactive - // User is bot - if (!is_array($this->data) || !count($this->data)) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS; - - if (!$bot) - { - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $this->cookie_data['u']; - } - else - { - // We give bots always the same session if it is not yet expired. - $sql = 'SELECT u.*, s.* - FROM ' . USERS_TABLE . ' u - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) - WHERE u.user_id = ' . (int) $bot; - } - - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - if ($this->data['user_id'] != ANONYMOUS && !$bot) - { - $this->data['session_last_visit'] = (isset($this->data['session_time']) && $this->data['session_time']) ? $this->data['session_time'] : (($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : time()); - } - else - { - $this->data['session_last_visit'] = $this->time_now; - } - - // Force user id to be integer... - $this->data['user_id'] = (int) $this->data['user_id']; - - // At this stage we should have a filled data array, defined cookie u and k data. - // data array should contain recent session info if we're a real user and a recent - // session exists in which case session_id will also be set - - // Is user banned? Are they excluded? Won't return on ban, exists within method - $this->check_ban_for_current_session($config); - - $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; - $this->data['is_bot'] = ($bot) ? true : false; - - // If our friend is a bot, we re-assign a previously assigned session - if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id']) - { - // Only assign the current session if the ip, browser and forwarded_for match... - if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false) - { - $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']); - $u_ip = short_ipv6($this->ip, $config['ip_check']); - } - else - { - $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); - $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); - } - - $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : ''; - $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : ''; - - $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; - $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; - - if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for) - { - $this->session_id = $this->data['session_id']; - - // Only update session DB a minute or so after last update or if page changes - if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) - { - // Update the last visit time - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - } - - $SID = '?sid='; - $_SID = ''; - return true; - } - else - { - // If the ip and browser does not match make sure we only have one bot assigned to one session - $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']); - } - } - - $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false; - $set_admin = ($set_admin && $this->data['is_registered']) ? true : false; - - // Create or update the session - $sql_ary = array( - 'session_user_id' => (int) $this->data['user_id'], - 'session_start' => (int) $this->time_now, - 'session_last_visit' => (int) $this->data['session_last_visit'], - 'session_time' => (int) $this->time_now, - 'session_browser' => (string) trim(substr($this->browser, 0, 149)), - 'session_forwarded_for' => (string) $this->forwarded_for, - 'session_ip' => (string) $this->ip, - 'session_autologin' => ($session_autologin) ? 1 : 0, - 'session_admin' => ($set_admin) ? 1 : 0, - 'session_viewonline' => ($viewonline) ? 1 : 0, - ); - - if ($this->update_session_page) - { - $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - } - - $db->sql_return_on_error(true); - - $sql = 'DELETE - FROM ' . SESSIONS_TABLE . ' - WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\' - AND session_user_id = ' . ANONYMOUS; - - if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows())) - { - // Limit new sessions in 1 minute period (if required) - if (empty($this->data['session_time']) && $config['active_sessions']) - { -// $db->sql_return_on_error(false); - - $sql = 'SELECT COUNT(session_id) AS sessions - FROM ' . SESSIONS_TABLE . ' - WHERE session_time >= ' . ($this->time_now - 60); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ((int) $row['sessions'] > (int) $config['active_sessions']) - { - send_status_line(503, 'Service Unavailable'); - trigger_error('BOARD_UNAVAILABLE'); - } - } - } - - // Since we re-create the session id here, the inserted row must be unique. Therefore, we display potential errors. - // Commented out because it will not allow forums to update correctly -// $db->sql_return_on_error(false); - - // Something quite important: session_page always holds the *last* page visited, except for the *first* visit. - // We are not able to simply have an empty session_page btw, therefore we need to tell phpBB how to detect this special case. - // If the session id is empty, we have a completely new one and will set an "identifier" here. This identifier is able to be checked later. - if (empty($this->data['session_id'])) - { - // This is a temporary variable, only set for the very first visit - $this->data['session_created'] = true; - } - - $this->session_id = $this->data['session_id'] = md5(unique_id()); - - $sql_ary['session_id'] = (string) $this->session_id; - $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - - $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $db->sql_return_on_error(false); - - // Regenerate autologin/persistent login key - if ($session_autologin) - { - $this->set_login_key(); - } - - // refresh data - $SID = '?sid=' . $this->session_id; - $_SID = $this->session_id; - $this->data = array_merge($this->data, $sql_ary); - - if (!$bot) - { - $cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000); - - $this->set_cookie('u', $this->cookie_data['u'], $cookie_expire); - $this->set_cookie('k', $this->cookie_data['k'], $cookie_expire); - $this->set_cookie('sid', $this->session_id, $cookie_expire); - - unset($cookie_expire); - - $sql = 'SELECT COUNT(session_id) AS sessions - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . (int) $this->data['user_id'] . ' - AND session_time >= ' . (int) ($this->time_now - (max((int) $config['session_length'], (int) $config['form_token_lifetime']))); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ((int) $row['sessions'] <= 1 || empty($this->data['user_form_salt'])) - { - $this->data['user_form_salt'] = unique_id(); - // Update the form key - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - } - } - else - { - $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now; - - // Update the last visit time - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - - $SID = '?sid='; - $_SID = ''; - } - - $session_data = $sql_ary; - /** - * Event to send new session data to extension - * Read-only event - * - * @event core.session_create_after - * @var array session_data Associative array of session keys to be updated - * @since 3.1.6-RC1 - */ - $vars = array('session_data'); - extract($phpbb_dispatcher->trigger_event('core.session_create_after', compact($vars))); - unset($session_data); - - return true; - } - - /** - * Kills a session - * - * This method does what it says on the tin. It will delete a pre-existing session. - * It resets cookie information (destroying any autologin key within that cookie data) - * and update the users information from the relevant session data. It will then - * grab guest user information. - */ - function session_kill($new_session = true) - { - global $SID, $_SID, $db, $phpbb_container, $phpbb_dispatcher; - - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - WHERE session_id = '" . $db->sql_escape($this->session_id) . "' - AND session_user_id = " . (int) $this->data['user_id']; - $db->sql_query($sql); - - $user_id = (int) $this->data['user_id']; - $session_id = $this->session_id; - /** - * Event to send session kill information to extension - * Read-only event - * - * @event core.session_kill_after - * @var int user_id user_id of the session user. - * @var string session_id current user's session_id - * @var bool new_session should we create new session for user - * @since 3.1.6-RC1 - */ - $vars = array('user_id', 'session_id', 'new_session'); - extract($phpbb_dispatcher->trigger_event('core.session_kill_after', compact($vars))); - unset($user_id); - 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); - - if ($this->data['user_id'] != ANONYMOUS) - { - // Delete existing session, update last visit info first! - if (!isset($this->data['session_time'])) - { - $this->data['session_time'] = time(); - } - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - - if ($this->cookie_data['k']) - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $this->data['user_id'] . " - AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; - $db->sql_query($sql); - } - - // Reset the data array - $this->data = array(); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . ANONYMOUS; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - $cookie_expire = $this->time_now - 31536000; - $this->set_cookie('u', '', $cookie_expire); - $this->set_cookie('k', '', $cookie_expire); - $this->set_cookie('sid', '', $cookie_expire); - unset($cookie_expire); - - $SID = '?sid='; - $this->session_id = $_SID = ''; - - // To make sure a valid session is created we create one for the anonymous user - if ($new_session) - { - $this->session_create(ANONYMOUS); - } - - return true; - } - - /** - * Session garbage collection - * - * This looks a lot more complex than it really is. Effectively we are - * deleting any sessions older than an admin definable limit. Due to the - * way in which we maintain session data we have to ensure we update user - * data before those sessions are destroyed. In addition this method - * removes autologin key information that is older than an admin defined - * limit. - */ - function session_gc() - { - global $db, $config, $phpbb_container, $phpbb_dispatcher; - - if (!$this->time_now) - { - $this->time_now = time(); - } - - /** - * Get expired sessions for registered users, only most recent for each user - * Inner SELECT gets most recent expired sessions for unique session_user_id - * Outer SELECT gets data for them - */ - $sql_select = 'SELECT s1.session_page, s1.session_user_id, s1.session_time AS recent_time - FROM ' . SESSIONS_TABLE . ' AS s1 - INNER JOIN ( - SELECT session_user_id, MAX(session_time) AS recent_time - FROM ' . SESSIONS_TABLE . ' - WHERE session_time < ' . ($this->time_now - (int) $config['session_length']) . ' - AND session_user_id <> ' . ANONYMOUS . ' - GROUP BY session_user_id - ) AS s2 - ON s1.session_user_id = s2.session_user_id - AND s1.session_time = s2.recent_time'; - - switch ($db->get_sql_layer()) - { - case 'sqlite3': - if (phpbb_version_compare($db->sql_server_info(true), '3.8.3', '>=')) - { - // For SQLite versions 3.8.3+ which support Common Table Expressions (CTE) - $sql = "WITH s3 (session_page, session_user_id, session_time) AS ($sql_select) - UPDATE " . USERS_TABLE . ' - SET (user_lastpage, user_lastvisit) = (SELECT session_page, session_time FROM s3 WHERE session_user_id = user_id) - WHERE EXISTS (SELECT session_user_id FROM s3 WHERE session_user_id = user_id)'; - $db->sql_query($sql); - - break; - } - - // No break, for SQLite versions prior to 3.8.3 and Oracle - case 'oracle': - $result = $db->sql_query($sql_select); - while ($row = $db->sql_fetchrow($result)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $row['session_user_id']; - $db->sql_query($sql); - } - $db->sql_freeresult($result); - break; - - case 'mysqli': - $sql = 'UPDATE ' . USERS_TABLE . " u, - ($sql_select) s3 - SET u.user_lastvisit = s3.recent_time, u.user_lastpage = s3.session_page - WHERE u.user_id = s3.session_user_id"; - $db->sql_query($sql); - break; - - default: - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastvisit = s3.recent_time, user_lastpage = s3.session_page - FROM ($sql_select) s3 - WHERE user_id = s3.session_user_id"; - $db->sql_query($sql); - break; - } - - // Delete all expired sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE session_time < ' . ($this->time_now - (int) $config['session_length']); - $db->sql_query($sql); - - // Update gc timer - $config->set('session_last_gc', $this->time_now, false); - - if ($config['max_autologin_time']) - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); - $db->sql_query($sql); - } - - // only called from CRON; should be a safe workaround until the infrastructure gets going - /* @var \phpbb\captcha\factory $captcha_factory */ - $captcha_factory = $phpbb_container->get('captcha.factory'); - $captcha_factory->garbage_collect($config['captcha_plugin']); - - $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']); - $db->sql_query($sql); - - /** - * Event to trigger extension on session_gc - * - * @event core.session_gc_after - * @since 3.1.6-RC1 - */ - $phpbb_dispatcher->dispatch('core.session_gc_after'); - - return; - } - - /** - * Sets a cookie - * - * Sets a cookie of the given name with the specified data for the given length of time. If no time is specified, a session cookie will be set. - * - * @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then. - * @param string $cookiedata The data to hold within the cookie - * @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set. - * @param bool $httponly Use HttpOnly. Defaults to true. Use false to make cookie accessible by client-side scripts. - */ - function set_cookie($name, $cookiedata, $cookietime, $httponly = true) - { - 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); - $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == '127.0.0.1' || strpos($config['cookie_domain'], '.') === false) ? '' : '; domain=' . $config['cookie_domain']; - - header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . ';' . (($httponly) ? ' HttpOnly' : ''), false); - } - - /** - * Check for banned user - * - * Checks whether the supplied user is banned by id, ip or email. If no parameters - * are passed to the method pre-existing session data is used. - * - * @param int|false $user_id The user id - * @param mixed $user_ips Can contain a string with one IP or an array of multiple IPs - * @param string|false $user_email The user email - * @param bool $return If $return is false this routine does not return on finding a banned user, - * it outputs a relevant message and stops execution. - */ - function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false) - { - global $config, $db, $phpbb_dispatcher; - - if (defined('IN_CHECK_BAN') || defined('SKIP_CHECK_BAN')) - { - return; - } - - $banned = false; - $cache_ttl = 3600; - $where_sql = array(); - - $sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end - FROM ' . BANLIST_TABLE . ' - WHERE '; - - // Determine which entries to check, only return those - if ($user_email === false) - { - $where_sql[] = "ban_email = ''"; - } - - if ($user_ips === false) - { - $where_sql[] = "(ban_ip = '' OR ban_exclude = 1)"; - } - - if ($user_id === false) - { - $where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)'; - } - else - { - $cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0; - $_sql = '(ban_userid = ' . $user_id; - - if ($user_email !== false) - { - $_sql .= " OR ban_email <> ''"; - } - - if ($user_ips !== false) - { - $_sql .= " OR ban_ip <> ''"; - } - - $_sql .= ')'; - - $where_sql[] = $_sql; - } - - $sql .= (count($where_sql)) ? implode(' AND ', $where_sql) : ''; - $result = $db->sql_query($sql, $cache_ttl); - - $ban_triggered_by = 'user'; - while ($row = $db->sql_fetchrow($result)) - { - if ($row['ban_end'] && $row['ban_end'] < time()) - { - continue; - } - - $ip_banned = false; - if (!empty($row['ban_ip'])) - { - if (!is_array($user_ips)) - { - $ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips); - } - else - { - foreach ($user_ips as $user_ip) - { - if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip)) - { - $ip_banned = true; - break; - } - } - } - } - - if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) || - $ip_banned || - (!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email))) - { - if (!empty($row['ban_exclude'])) - { - $banned = false; - break; - } - else - { - $banned = true; - $ban_row = $row; - - if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) - { - $ban_triggered_by = 'user'; - } - else if ($ip_banned) - { - $ban_triggered_by = 'ip'; - } - else - { - $ban_triggered_by = 'email'; - } - - // Don't break. Check if there is an exclude rule for this user - } - } - } - $db->sql_freeresult($result); - - /** - * Event to set custom ban type - * - * @event core.session_set_custom_ban - * @var bool return If $return is false this routine does not return on finding a banned user, it outputs a relevant message and stops execution - * @var bool banned Check if user already banned - * @var array|false ban_row Ban data - * @var string ban_triggered_by Method that caused ban, can be your custom method - * @since 3.1.3-RC1 - */ - $ban_row = isset($ban_row) ? $ban_row : false; - $vars = array('return', 'banned', 'ban_row', 'ban_triggered_by'); - extract($phpbb_dispatcher->trigger_event('core.session_set_custom_ban', compact($vars))); - - if ($banned && !$return) - { - global $phpbb_root_path, $phpEx; - - // If the session is empty we need to create a valid one... - if (empty($this->session_id)) - { - // This seems to be no longer needed? - #14971 -// $this->session_create(ANONYMOUS); - } - - // Initiate environment ... since it won't be set at this stage - $this->setup(); - - // Logout the user, banned users are unable to use the normal 'logout' link - if ($this->data['user_id'] != ANONYMOUS) - { - $this->session_kill(); - } - - // We show a login box here to allow founders accessing the board if banned by IP - if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS) - { - $this->setup('ucp'); - $this->data['is_registered'] = $this->data['is_bot'] = false; - - // Set as a precaution to allow login_box() handling this case correctly as well as this function not being executed again. - define('IN_CHECK_BAN', 1); - - login_box("index.$phpEx"); - - // The false here is needed, else the user is able to circumvent the ban. - $this->session_kill(false); - } - - // Ok, we catch the case of an empty session id for the anonymous user... - // This can happen if the user is logging in, banned by username and the login_box() being called "again". - if (empty($this->session_id) && defined('IN_CHECK_BAN')) - { - $this->session_create(ANONYMOUS); - } - - // Determine which message to output - $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : ''; - $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM'; - - $contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx); - $message = sprintf($this->lang[$message], $till_date, '', ''); - $message .= ($ban_row['ban_give_reason']) ? '

' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : ''; - $message .= '

' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . ''; - - // A very special case... we are within the cron script which is not supposed to print out the ban message... show blank page - if (defined('IN_CRON')) - { - garbage_collection(); - exit_handler(); - exit; - } - - // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again - $this->session_kill(false); - - trigger_error($message); - } - - if (!empty($ban_row)) - { - $ban_row['ban_triggered_by'] = $ban_triggered_by; - } - - return ($banned && $ban_row) ? $ban_row : $banned; - } - - /** - * Check the current session for bans - * - * @return true if session user is banned. - */ - protected function check_ban_for_current_session($config) - { - if (!defined('SKIP_CHECK_BAN') && $this->data['user_type'] != USER_FOUNDER) - { - if (!$config['forwarded_for_check']) - { - $this->check_ban($this->data['user_id'], $this->ip); - } - else - { - $ips = explode(' ', $this->forwarded_for); - $ips[] = $this->ip; - $this->check_ban($this->data['user_id'], $ips); - } - } - } - - /** - * Check if ip is blacklisted - * This should be called only where absolutely necessary - * - * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups) - * - * @author satmd (from the php manual) - * @param string $mode register/post - spamcop for example is omitted for posting - * @param string|false $ip the IPv4 address to check - * - * @return false if ip is not blacklisted, else an array([checked server], [lookup]) - */ - function check_dnsbl($mode, $ip = false) - { - if ($ip === false) - { - $ip = $this->ip; - } - - // Neither Spamhaus nor Spamcop supports IPv6 addresses. - if (strpos($ip, ':') !== false) - { - return false; - } - - $dnsbl_check = array( - 'sbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=', - ); - - if ($mode == 'register') - { - $dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?'; - } - - if ($ip) - { - $quads = explode('.', $ip); - $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0]; - - // Need to be listed on all servers... - $listed = true; - $info = array(); - - foreach ($dnsbl_check as $dnsbl => $lookup) - { - if (checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true) - { - $info = array($dnsbl, $lookup . $ip); - } - else - { - $listed = false; - } - } - - if ($listed) - { - return $info; - } - } - - return false; - } - - /** - * Check if URI is blacklisted - * This should be called only where absolutely necessary, for example on the submitted website field - * This function is not in use at the moment and is only included for testing purposes, it may not work at all! - * This means it is untested at the moment and therefore commented out - * - * @param string $uri URI to check - * @return true if uri is on blacklist, else false. Only blacklist is checked (~zero FP), no grey lists - function check_uribl($uri) - { - // Normally parse_url() is not intended to parse uris - // We need to get the top-level domain name anyway... change. - $uri = parse_url($uri); - - if ($uri === false || empty($uri['host'])) - { - return false; - } - - $uri = trim($uri['host']); - - if ($uri) - { - // One problem here... the return parameter for the "windows" method is different from what - // we expect... this may render this check useless... - if (checkdnsrr($uri . '.multi.uribl.com.', 'A') === true) - { - return true; - } - } - - return false; - } - */ - - /** - * Set/Update a persistent login key - * - * This method creates or updates a persistent session key. When a user makes - * use of persistent (formerly auto-) logins a key is generated and stored in the - * DB. When they revisit with the same key it's automatically updated in both the - * DB and cookie. Multiple keys may exist for each user representing different - * browsers or locations. As with _any_ non-secure-socket no passphrase login this - * remains vulnerable to exploit. - */ - function set_login_key($user_id = false, $key = false, $user_ip = false) - { - global $db; - - $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id; - $user_ip = ($user_ip === false) ? $this->ip : $user_ip; - $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key; - - $key_id = unique_id(hexdec(substr($this->session_id, 0, 8))); - - $sql_ary = array( - 'key_id' => (string) md5($key_id), - 'last_ip' => (string) $user_ip, - 'last_login' => (int) time() - ); - - if (!$key) - { - $sql_ary += array( - 'user_id' => (int) $user_id - ); - } - - if ($key) - { - $sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . (int) $user_id . " - AND key_id = '" . $db->sql_escape(md5($key)) . "'"; - } - else - { - $sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - } - $db->sql_query($sql); - - $this->cookie_data['k'] = $key_id; - - return false; - } - - /** - * Reset all login keys for the specified user - * - * This method removes all current login keys for a specified (or the current) - * user. It will be called on password change to render old keys unusable - */ - function reset_login_keys($user_id = false) - { - global $db; - - $user_id = ($user_id === false) ? (int) $this->data['user_id'] : (int) $user_id; - - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $user_id; - $db->sql_query($sql); - - // If the user is logged in, update last visit info first before deleting sessions - $sql = 'SELECT session_time, session_page - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . (int) $user_id . ' - ORDER BY session_time DESC'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['session_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $user_id; - $db->sql_query($sql); - } - - // Let's also clear any current sessions for the specified user_id - // If it's the current user then we'll leave this session intact - $sql_where = 'session_user_id = ' . (int) $user_id; - $sql_where .= ($user_id === (int) $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : ''; - - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - WHERE $sql_where"; - $db->sql_query($sql); - - // We're changing the password of the current user and they have a key - // Lets regenerate it to be safe - if ($user_id === (int) $this->data['user_id'] && $this->cookie_data['k']) - { - $this->set_login_key($user_id); - } - } - - - /** - * Check if the request originated from the same page. - * @param bool $check_script_path If true, the path will be checked as well - */ - function validate_referer($check_script_path = false) - { - global $config, $request; - - // no referer - nothing to validate, user's fault for turning it off (we only check on POST; so meta can't be the reason) - if (empty($this->referer) || empty($this->host)) - { - return true; - } - - $host = htmlspecialchars($this->host); - $ref = substr($this->referer, strpos($this->referer, '://') + 3); - - if (!(stripos($ref, $host) === 0) && (!$config['force_server_vars'] || !(stripos($ref, $config['server_name']) === 0))) - { - return false; - } - else if ($check_script_path && rtrim($this->page['root_script_path'], '/') !== '') - { - $ref = substr($ref, strlen($host)); - $server_port = $request->server('SERVER_PORT', 0); - - if ($server_port !== 80 && $server_port !== 443 && stripos($ref, ":$server_port") === 0) - { - $ref = substr($ref, strlen(":$server_port")); - } - - if (!(stripos(rtrim($ref, '/'), rtrim($this->page['root_script_path'], '/')) === 0)) - { - return false; - } - } - - return true; - } - - - function unset_admin() - { - global $db; - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_admin = 0 - WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\''; - $db->sql_query($sql); - } - - /** - * Update the session data - * - * @param array $session_data associative array of session keys to be updated - * @param string $session_id optional session_id, defaults to current user's session_id - */ - public function update_session($session_data, $session_id = null) - { - global $db, $phpbb_dispatcher; - - $session_id = ($session_id) ? $session_id : $this->session_id; - - $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $session_data) . " - WHERE session_id = '" . $db->sql_escape($session_id) . "'"; - $db->sql_query($sql); - - /** - * Event to send update session information to extension - * Read-only event - * - * @event core.update_session_after - * @var array session_data Associative array of session keys to be updated - * @var string session_id current user's session_id - * @since 3.1.6-RC1 - */ - $vars = array('session_data', 'session_id'); - extract($phpbb_dispatcher->trigger_event('core.update_session_after', compact($vars))); - } - - public function update_session_infos() - { - global $config, $db, $request; - - // No need to update if it's a new session. Informations are already inserted by session_create() - if (isset($this->data['session_created']) && $this->data['session_created']) - { - 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 || $page_changed) - { - $sql_ary = array('session_time' => $this->time_now); - - if ($page_changed) - { - $sql_ary['session_page'] = substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - } - - $db->sql_return_on_error(true); - - $this->update_session($sql_ary); - - $db->sql_return_on_error(false); - - $this->data = array_merge($this->data, $sql_ary); - - if ($this->data['user_id'] != ANONYMOUS && isset($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts']) - { - $this->leave_newly_registered(); - } - } - } -} diff --git a/install/update/new/phpbb/template/asset.php b/install/update/new/phpbb/template/asset.php deleted file mode 100644 index d6b4623..0000000 --- a/install/update/new/phpbb/template/asset.php +++ /dev/null @@ -1,203 +0,0 @@ - -* @license 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 asset -{ - protected $components = array(); - - /** @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, \phpbb\filesystem\filesystem $filesystem) - { - $this->path_helper = $path_helper; - $this->filesystem = $filesystem; - - $this->set_url($url); - } - - /** - * Set URL - * - * @param string $url URL - */ - public function set_url($url) - { - $this->components = parse_url($url); - } - - /** - * Convert URL components into string - * - * @param array $components URL components - * @return string URL - */ - protected function join_url($components) - { - $path = ''; - if (isset($components['scheme'])) - { - $path = $components['scheme'] === '' ? '//' : $components['scheme'] . '://'; - } - - if (isset($components['user']) || isset($components['pass'])) - { - if ($path === '' && !isset($components['port'])) - { - $path = '//'; - } - $path .= $components['user']; - if (isset($components['pass'])) - { - $path .= ':' . $components['pass']; - } - $path .= '@'; - } - - if (isset($components['host'])) - { - if ($path === '' && !isset($components['port'])) - { - $path = '//'; - } - $path .= $components['host']; - if (isset($components['port'])) - { - $path .= ':' . $components['port']; - } - } - - if (isset($components['path'])) - { - $path .= $components['path']; - } - - if (isset($components['query'])) - { - $path .= '?' . $components['query']; - } - - if (isset($components['fragment'])) - { - $path .= '#' . $components['fragment']; - } - - return $path; - } - - /** - * Get URL - * - * @return string URL - */ - public function get_url() - { - return $this->path_helper->update_web_root_path($this->join_url($this->components)); - } - - /** - * Checks if URL is local and relative - * - * @return boolean True if URL is local and relative - */ - public function is_relative() - { - if (empty($this->components) || !isset($this->components['path'])) - { - // Invalid URL - return false; - } - return !isset($this->components['scheme']) && !isset($this->components['host']) && substr($this->components['path'], 0, 1) !== '/'; - } - - /** - * Get path component of current URL - * - * @return string Path - */ - public function get_path() - { - return isset($this->components['path']) ? $this->components['path'] : ''; - } - - /** - * Set path component - * - * @param string $path Path component - * @param boolean $urlencode If true, parts of path should be encoded with rawurlencode() - */ - 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. - $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 ($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 = $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))); - } - } - - if ($urlencode) - { - $paths = explode('/', $path); - foreach ($paths as &$dir) - { - $dir = rawurlencode($dir); - } - $path = implode('/', $paths); - } - - $this->components['path'] = $path; - } - - /** - * Add assets_version parameter to URL. - * Parameter will not be added if assets_version already exists in URL - * - * @param string $version Version - */ - public function add_assets_version($version) - { - if (!isset($this->components['query'])) - { - $this->components['query'] = 'assets_version=' . $version; - return; - } - $query = $this->components['query']; - if (!preg_match('/(^|[&;])assets_version=/', $query)) - { - $this->components['query'] = $query . '&assets_version=' . $version; - } - } -} diff --git a/install/update/new/phpbb/template/context.php b/install/update/new/phpbb/template/context.php deleted file mode 100644 index f059c32..0000000 --- a/install/update/new/phpbb/template/context.php +++ /dev/null @@ -1,631 +0,0 @@ - -* @license 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; - -/** -* Stores variables assigned to template. -*/ -class context -{ - /** - * variable that holds all the data we'll be substituting into - * the compiled templates. Takes form: - * --> $this->tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value - * if it's a root-level variable, it'll be like this: - * --> $this->tpldata[.][0][varname] == value - * - * @var array - */ - private $tpldata = array('.' => array(0 => array())); - - /** - * @var array Reference to template->tpldata['.'][0] - */ - private $rootref; - - /** - * @var bool - */ - private $num_rows_is_set; - - public function __construct() - { - $this->clear(); - } - - /** - * Clears template data set. - */ - public function clear() - { - $this->tpldata = array('.' => array(0 => array())); - $this->rootref = &$this->tpldata['.'][0]; - $this->num_rows_is_set = false; - } - - /** - * Assign a single scalar value to a single key. - * - * Value can be a string, an integer or a boolean. - * - * @param string $varname Variable name - * @param string $varval Value to assign to variable - * @return true - */ - public function assign_var($varname, $varval) - { - $this->rootref[$varname] = $varval; - - return true; - } - - /** - * Append text to the string value stored in a key. - * - * Text is appended using the string concatenation operator (.). - * - * @param string $varname Variable name - * @param string $varval Value to append to variable - * @return true - */ - public function append_var($varname, $varval) - { - $this->rootref[$varname] = (isset($this->rootref[$varname]) ? $this->rootref[$varname] : '') . $varval; - - return true; - } - - /** - * Retrieve 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. - * Users should alter template variables via functions in \phpbb\template\template. - * - * Note: modifying returned array will affect data stored in the context. - * - * @return array template data - */ - public function &get_data_ref() - { - // returning a reference directly is not - // something php is capable of doing - $ref = &$this->tpldata; - - if (!$this->num_rows_is_set) - { - /* - * We do not set S_NUM_ROWS while adding a row, to reduce the complexity - * If we would set it on adding, each subsequent adding would cause - * n modifications, resulting in a O(n!) complexity, rather then O(n) - */ - foreach ($ref as $loop_name => &$loop_data) - { - if ($loop_name === '.') - { - continue; - } - - $this->set_num_rows($loop_data); - } - $this->num_rows_is_set = true; - } - - return $ref; - } - - /** - * Set S_NUM_ROWS for each row in this template block - * - * @param array $loop_data - */ - protected function set_num_rows(&$loop_data) - { - $s_num_rows = count($loop_data); - foreach ($loop_data as &$mod_block) - { - foreach ($mod_block as $sub_block_name => &$sub_block) - { - // If the key name is lowercase and the data is an array, - // it could be a template loop. So we set the S_NUM_ROWS there - // as well. - if ($sub_block_name === strtolower($sub_block_name) && is_array($sub_block)) - { - $this->set_num_rows($sub_block); - } - } - - // Check whether we are inside a block before setting the variable - if (isset($mod_block['S_BLOCK_NAME'])) - { - $mod_block['S_NUM_ROWS'] = $s_num_rows; - } - } - } - - /** - * Returns a reference to template root scope. - * - * This function is public so that template renderer may invoke it. - * Users should not need to invoke this function. - * - * Note: modifying returned array will affect data stored in the context. - * - * @return array template data - */ - public function &get_root_ref() - { - // rootref is already a reference - return $this->rootref; - } - - /** - * Assign key variable pairs from an array to a specified block - * - * @param string $blockname Name of block to assign $vararray to - * @param array $vararray A hash of variable name => value pairs - * @return true - */ - public function assign_block_vars($blockname, array $vararray) - { - $this->num_rows_is_set = false; - - // 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]; - $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]; - } - - // $block = &$block[$blocks[$i]]; // Do not traverse the last block as it might be empty - $name = $blocks[$i]; - - // 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; - - // Assign S_FIRST_ROW - if (!$s_row_count) - { - $vararray['S_FIRST_ROW'] = true; - } - - // Assign S_BLOCK_NAME - $vararray['S_BLOCK_NAME'] = $name; - - // 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; - } - - /** - * Assign key variable pairs from an array to a whole specified block loop - * - * @param string $blockname Name of block to assign $block_vars_array to - * @param array $block_vars_array An array of hashes of variable name => value pairs - * @return true - */ - public function assign_block_vars_array($blockname, array $block_vars_array) - { - foreach ($block_vars_array as $vararray) - { - $this->assign_block_vars($blockname, $vararray); - } - - return true; - } - - /** - * Retrieve key variable pairs from the specified block - * - * @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 retrieve_block_vars($blockname, array $vararray) - { - // 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++) - { - if (($pos = strpos($blocks[$i], '[')) !== false) - { - $name = substr($blocks[$i], 0, $pos); - - if (empty($block[$name])) - { - return array(); - } - - if (strpos($blocks[$i], '[]') === $pos) - { - $index = count($block[$name]) - 1; - } - else - { - $index = min((int) substr($blocks[$i], $pos + 1, -1), count($block[$name]) - 1); - } - } - else - { - $name = $blocks[$i]; - 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; - } - - $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[$name][$index]; - } - - if (!isset($block[$blocks[$i]])) - { - return false; - } - $block = $block[$blocks[$i]]; // Traverse the last block - - // Change key to zero (change first position) if false and to last position if true - if (is_bool($key)) - { - return (!$key) ? 0 : count($block) - 1; - } - - // Get correct position if array given - if (is_array($key)) - { - // Search array to get correct position - list($search_key, $search_value) = @each($key); - foreach ($block as $i => $val_ary) - { - if ($val_ary[$search_key] === $search_value) - { - return $i; - } - } - } - - return (is_int($key) && ((0 <= $key) && ($key < count($block)))) ? $key : false; - } - - /** - * Change already assigned key variable pair (one-dimensional - single loop entry) - * - * An example of how to use this function: - * {@example alter_block_array.php} - * - * @param string $blockname the blockname, for example 'loop' - * @param array $vararray the var array to insert/add or merge - * @param mixed $key Key to search for - * - * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] - * - * int: Position [the position to change or insert at directly given] - * - * If key is false the position is set to 0 - * If key is true the position is set to the last entry - * - * @param string $mode Mode to execute (valid modes are 'insert', '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) - * - * @return bool false on error, true on success - */ - public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') - { - $this->num_rows_is_set = false; - - // 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++) - { - if (($pos = strpos($blocks[$i], '[')) !== false) - { - $name = substr($blocks[$i], 0, $pos); - - if (strpos($blocks[$i], '[]') === $pos) - { - $index = count($block[$name]) - 1; - } - else - { - $index = min((int) substr($blocks[$i], $pos + 1, -1), count($block[$name]) - 1); - } - } - else - { - $name = $blocks[$i]; - $index = count($block[$name]) - 1; - } - $block = &$block[$name]; - $block = &$block[$index]; - } - $name = $blocks[$i]; - - // If last block does not exist and we are inserting, and not searching for key, we create it empty; otherwise, nothing to do - if (!isset($block[$name])) - { - if ($mode != 'insert' || is_array($key)) - { - return false; - } - $block[$name] = array(); - } - - $block = &$block[$name]; // Now we can traverse the last block - - // Change key to zero (change first position) if false and to last position if true - if ($key === false || $key === true) - { - $key = ($key === false) ? 0 : count($block); - } - - // Get correct position if array given - if (is_array($key)) - { - // Search array to get correct position - list($search_key, $search_value) = @each($key); - - $key = null; - foreach ($block as $i => $val_ary) - { - if ($val_ary[$search_key] === $search_value) - { - $key = $i; - break; - } - } - - // key/value pair not found - if ($key === null) - { - return false; - } - } - - // Insert Block - if ($mode == 'insert') - { - // Make sure we are not exceeding the last iteration - if ($key >= count($block)) - { - $key = count($block); - unset($block[($key - 1)]['S_LAST_ROW']); - $vararray['S_LAST_ROW'] = true; - } - if ($key <= 0) - { - $key = 0; - unset($block[0]['S_FIRST_ROW']); - $vararray['S_FIRST_ROW'] = true; - } - - // Assign S_BLOCK_NAME - $vararray['S_BLOCK_NAME'] = $name; - - // Re-position template blocks - for ($i = count($block); $i > $key; $i--) - { - $block[$i] = $block[$i-1]; - - $block[$i]['S_ROW_COUNT'] = $block[$i]['S_ROW_NUM'] = $i; - } - - // Insert vararray at given position - $block[$key] = $vararray; - $block[$key]['S_ROW_COUNT'] = $block[$key]['S_ROW_NUM'] = $key; - - return true; - } - - // Which block to change? - if ($mode == 'change') - { - // If key is out of bounds, do not change anything - if ($key > count($block) || $key < 0) - { - return false; - } - - if ($key == count($block)) - { - $key--; - } - - $block[$key] = array_merge($block[$key], $vararray); - - 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; - } - - /** - * Reset/empty complete block - * - * @param string $blockname Name of block to destroy - * @return true - */ - public function destroy_block_vars($blockname) - { - $this->num_rows_is_set = false; - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = count($blocks) - 1; - - $str = &$this->tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - $str = &$str[$blocks[$i]]; - $str = &$str[count($str) - 1]; - } - - unset($str[$blocks[$blockcount]]); - } - else - { - // Top-level block. - unset($this->tpldata[$blockname]); - } - - return true; - } -} diff --git a/install/update/new/phpbb/template/template.php b/install/update/new/phpbb/template/template.php deleted file mode 100644 index 6634c28..0000000 --- a/install/update/new/phpbb/template/template.php +++ /dev/null @@ -1,224 +0,0 @@ - -* @license 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; - -interface template -{ - - /** - * Clear the cache - * - * @return \phpbb\template\template - */ - public function clear_cache(); - - /** - * Sets the template filenames for handles. - * - * @param array $filename_array Should be a hash of handle => filename pairs. - * @return \phpbb\template\template $this - */ - public function set_filenames(array $filename_array); - - /** - * Get the style tree of the style preferred by the current user - * - * @return array Style tree, most specific first - */ - public function get_user_style(); - - /** - * Set style location based on (current) user's chosen style. - * - * @param array $style_directories The directories to add style paths for - * E.g. array('ext/foo/bar/styles', 'styles') - * Default: array('styles') (phpBB's style directory) - * @return \phpbb\template\template $this - */ - public function set_style($style_directories = array('styles')); - - /** - * Set custom style location (able to use directory outside of phpBB). - * - * Note: Templates are still compiled to phpBB's cache directory. - * - * @param string|array $names Array of names or string of name of template(s) in inheritance tree order, used by extensions. - * @param string|array or string $paths Array of style paths, relative to current root directory - * @return \phpbb\template\template $this - */ - public function set_custom_style($names, $paths); - - /** - * Clears all variables and blocks assigned to this template. - * - * @return \phpbb\template\template $this - */ - public function destroy(); - - /** - * Reset/empty complete block - * - * @param string $blockname Name of block to destroy - * @return \phpbb\template\template $this - */ - public function destroy_block_vars($blockname); - - /** - * Display a template for provided handle. - * - * The template will be loaded and compiled, if necessary, first. - * - * This function calls hooks. - * - * @param string $handle Handle to display - * @return \phpbb\template\template $this - */ - public function display($handle); - - /** - * Display the handle and assign the output to a template variable - * or return the compiled result. - * - * @param string $handle Handle to operate on - * @param string $template_var Template variable to assign compiled handle to - * @param bool $return_content If true return compiled handle, otherwise assign to $template_var - * @return \phpbb\template\template|string if $return_content is true return string of the compiled handle, otherwise return $this - */ - public function assign_display($handle, $template_var = '', $return_content = true); - - /** - * Assign key variable pairs from an array - * - * @param array $vararray A hash of variable name => value pairs - * @return \phpbb\template\template $this - */ - public function assign_vars(array $vararray); - - /** - * Assign a single scalar value to a single key. - * - * Value can be a string, an integer or a boolean. - * - * @param string $varname Variable name - * @param string $varval Value to assign to variable - * @return \phpbb\template\template $this - */ - public function assign_var($varname, $varval); - - /** - * Append text to the string value stored in a key. - * - * Text is appended using the string concatenation operator (.). - * - * @param string $varname Variable name - * @param string $varval Value to append to variable - * @return \phpbb\template\template $this - */ - 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); - - /** - * Retrieve 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 - * @return \phpbb\template\template $this - */ - public function assign_block_vars($blockname, array $vararray); - - /** - * Assign key variable pairs from an array to a whole specified block loop - * @param string $blockname Name of block to assign $block_vars_array to - * @param array $block_vars_array An array of hashes of variable name => value pairs - * @return \phpbb\template\template $this - */ - 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: - * {@example alter_block_array.php} - * - * @param string $blockname the blockname, for example 'loop' - * @param array $vararray the var array to insert/add or merge - * @param mixed $key Key to search for - * - * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] - * - * int: Position [the position to change or insert at directly given] - * - * If key is false the position is set to 0 - * If key is true the position is set to the last entry - * - * @param string $mode Mode to execute (valid modes are 'insert', '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) - * - * @return bool false on error, true on success - */ - public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert'); - - /** - * 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); - - /** - * Get path to template for handle (required for BBCode parser) - * - * @param string $handle Handle to retrieve the source file - * @return string - */ - public function get_source_file_for_handle($handle); -} diff --git a/install/update/new/phpbb/template/twig/extension.php b/install/update/new/phpbb/template/twig/extension.php deleted file mode 100644 index 1131a7f..0000000 --- a/install/update/new/phpbb/template/twig/extension.php +++ /dev/null @@ -1,201 +0,0 @@ - -* @license 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; - -class extension extends \Twig_Extension -{ - /** @var \phpbb\template\context */ - protected $context; - - /** @var \phpbb\template\twig\environment */ - protected $environment; - - /** @var \phpbb\language\language */ - protected $language; - - /** - * Constructor - * - * @param \phpbb\template\context $context - * @param \phpbb\template\twig\environment $environment - * @param \phpbb\language\language $language - */ - public function __construct(\phpbb\template\context $context, \phpbb\template\twig\environment $environment, $language) - { - $this->context = $context; - $this->environment = $environment; - $this->language = $language; - } - - /** - * Get the name of this extension - * - * @return string - */ - public function getName() - { - return 'phpbb'; - } - - /** - * Returns the token parser instance to add to the existing list. - * - * @return array An array of Twig_TokenParser instances - */ - public function getTokenParsers() - { - return array( - new \phpbb\template\twig\tokenparser\defineparser, - new \phpbb\template\twig\tokenparser\includeparser, - new \phpbb\template\twig\tokenparser\includejs, - new \phpbb\template\twig\tokenparser\includecss, - new \phpbb\template\twig\tokenparser\event($this->environment), - new \phpbb\template\twig\tokenparser\includephp($this->environment), - new \phpbb\template\twig\tokenparser\php($this->environment), - ); - } - - /** - * Returns a list of filters to add to the existing list. - * - * @return array An array of filters - */ - public function getFilters() - { - 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'), - ); - } - - /** - * Returns a list of global functions to add to the existing list. - * - * @return array An array of global functions - */ - public function getFunctions() - { - return array( - new \Twig_SimpleFunction('lang', array($this, 'lang')), - new \Twig_SimpleFunction('lang_defined', array($this, 'lang_defined')), - new \Twig_SimpleFunction('get_class', 'get_class'), - ); - } - - /** - * Returns a list of operators to add to the existing list. - * - * @return array An array of operators - */ - public function getOperators() - { - return array( - array( - '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'), - ), - array( - // precedence settings are copied from similar operators in Twig core extension - '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - 'eq' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - 'ne' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'neq' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - '<>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - '===' => array('precedence' => 20, 'class' => '\phpbb\template\twig\node\expression\binary\equalequal', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - '!==' => array('precedence' => 20, 'class' => '\phpbb\template\twig\node\expression\binary\notequalequal', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - 'gt' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'gte' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'ge' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'lt' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'lte' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'le' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - 'mod' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - ), - ); - } - - /** - * Grabs a subset of a loop - * - * @param \Twig_Environment $env A Twig_Environment instance - * @param mixed $item A variable - * @param integer $start Start of the subset - * @param integer $end End of the subset - * @param Boolean $preserveKeys Whether to preserve key or not (when the input is an array) - * - * @return mixed The sliced variable - */ - public function loop_subset(\Twig_Environment $env, $item, $start, $end = null, $preserveKeys = false) - { - // We do almost the same thing as Twig's slice (array_slice), except when $end is positive - if ($end >= 1) - { - // When end is > 1, subset will end on the last item in an array with the specified $end - // This is different from slice in that it is the number we end on rather than the number - // of items to grab (length) - - // Start must always be the actual starting number for this calculation (not negative) - $start = ($start < 0) ? count($item) + $start : $start; - $end = $end - $start; - } - - // We always include the last element (this was the past design) - $end = ($end == -1 || $end === null) ? null : $end + 1; - - return twig_slice($env, $item, $start, $end, $preserveKeys); - } - - /** - * Get output for a language variable (L_FOO, LA_FOO) - * - * This function checks to see if the language var was outputted to $context - * (e.g. in the ACP, L_TITLE) - * If not, we return the result of $user->lang() - * - * @return string - */ - public function lang() - { - $args = func_get_args(); - $key = $args[0]; - - $context_vars = $this->context->get_root_ref(); - - if (is_string($key) && isset($context_vars['L_' . $key])) - { - return $context_vars['L_' . $key]; - } - - // LA_ is transformed into lang(\'$1\')|escape('js'), so we should not - // need to check for it - - return call_user_func_array(array($this->language, 'lang'), $args); - } - - /** - * Check if a language variable exists - * - * @return bool - */ - public function lang_defined($key) - { - return call_user_func_array([$this->language, 'is_set'], [$key]); - } -} diff --git a/install/update/new/phpbb/template/twig/extension/avatar.php b/install/update/new/phpbb/template/twig/extension/avatar.php deleted file mode 100644 index 7a17fd4..0000000 --- a/install/update/new/phpbb/template/twig/extension/avatar.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @license 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; - -class avatar extends \Twig_Extension -{ - /** - * Get the name of this extension - * - * @return string - */ - public function getName() - { - return 'avatar'; - } - - /** - * Returns a list of global functions to add to the existing list. - * - * @return array An array of global functions - */ - public function getFunctions() - { - return array( - new \Twig_SimpleFunction('avatar', array($this, 'get_avatar')), - ); - } - - /** - * Get avatar for placing into templates. - * - * How to use in a template: - * - {{ avatar('mode', row, alt, ignore_config, lazy) }} - * - * The mode and row (group_row or user_row) are required. - * The other fields (alt|ignore_config|lazy) are optional. - * - * @uses \phpbb_get_group_avatar() - * @uses \phpbb_get_user_avatar() - * - * @return string The avatar HTML for the specified mode - */ - public function get_avatar() - { - $args = func_get_args(); - - $mode = (string) $args[0]; - $row = (array) $args[1]; - $alt = isset($args[2]) ? (string) $args[2] : false; - $ignore_config = isset($args[3]) ? (bool) $args[3] : false; - $lazy = isset($args[4]) ? (bool) $args[4] : false; - - // To prevent having to redefine alt attribute ('USER_AVATAR'|'GROUP_AVATAR'), we check if an alternative has been provided - switch ($mode) - { - case 'group': - return $alt ? phpbb_get_group_avatar($row, $alt, $ignore_config, $lazy) : phpbb_get_group_avatar($row); - break; - - case 'user': - return $alt ? phpbb_get_user_avatar($row, $alt, $ignore_config, $lazy) : phpbb_get_user_avatar($row); - break; - - default: - return ''; - break; - } - } -} diff --git a/install/update/new/phpbb/template/twig/extension/config.php b/install/update/new/phpbb/template/twig/extension/config.php deleted file mode 100644 index cbf6e50..0000000 --- a/install/update/new/phpbb/template/twig/extension/config.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @license 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; - -class config extends \Twig_Extension -{ - /** @var \phpbb\config\config */ - protected $config; - - /** - * Constructor. - * - * @param \phpbb\config\config $config Configuration object - */ - public function __construct(\phpbb\config\config $config) - { - $this->config = $config; - } - - /** - * Get the name of this extension - * - * @return string - */ - public function getName() - { - return 'config'; - } - - /** - * Returns a list of global functions to add to the existing list. - * - * @return array An array of global functions - */ - public function getFunctions() - { - return array( - new \Twig_SimpleFunction('config', array($this, 'get_config')), - ); - } - - /** - * Retrieves a configuration value for use in templates. - * - * @return string The configuration value - */ - public function get_config() - { - $args = func_get_args(); - - return $this->config->offsetGet($args[0]); - } -} diff --git a/install/update/new/phpbb/template/twig/extension/username.php b/install/update/new/phpbb/template/twig/extension/username.php deleted file mode 100644 index ef14969..0000000 --- a/install/update/new/phpbb/template/twig/extension/username.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @license 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; - -class username extends \Twig_Extension -{ - /** - * Get the name of this extension - * - * @return string - */ - public function getName() - { - return 'username'; - } - - /** - * Returns a list of global functions to add to the existing list. - * - * @return array An array of global functions - */ - public function getFunctions() - { - return array( - new \Twig_SimpleFunction('username', array($this, 'get_username')), - ); - } - - /** - * Get username details for placing into templates. - * - * How to use in a template: - * - {{ username('mode', user_id, username, user_colour, guest_username, custom_profile_url) }} - * - {{ username('mode', user_row, guest_username, custom_profile_url) }} - * It's possible to provide the user identifier, name and colour separately, - * or provide the entire user row at once as an array. - * - * The mode, user_id and username are required (separately or through a user row). - * The other fields (user_colour|guest_username|custom_profile_url) are optional. - * - * @uses \get_username_string() - * - * @return string A string based on what is wanted depending on $mode - */ - public function get_username() - { - $args = func_get_args(); - - $mode = $args[0]; - $user = $args[1]; - - // If the entire user row is provided - if (is_array($user)) - { - $user_id = isset($user['user_id']) ? $user['user_id'] : ''; - $username = isset($user['username']) ? $user['username'] : ''; - $user_colour = isset($user['user_colour']) ? $user['user_colour'] : ''; - $guest_username = isset($args[2]) ? $args[2] : false; - $custom_profile_url = isset($args[3]) ? $args[3] : false; - } - else - { - // Options are provided separately - $user_id = $user; - $username = $args[2]; - $user_colour = isset($args[3]) ? $args[3] : ''; - $guest_username = isset($args[4]) ? $args[4] : false; - $custom_profile_url = isset($args[5]) ? $args[5] : false; - } - - return get_username_string($mode, $user_id, $username, $user_colour, $guest_username, $custom_profile_url); - } -} diff --git a/install/update/new/phpbb/template/twig/lexer.php b/install/update/new/phpbb/template/twig/lexer.php deleted file mode 100644 index 6615a46..0000000 --- a/install/update/new/phpbb/template/twig/lexer.php +++ /dev/null @@ -1,358 +0,0 @@ - -* @license 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; - -class lexer extends \Twig_Lexer -{ - public function tokenize(\Twig_Source $source) - { - $code = $source->getCode(); - $filename = $source->getName(); - - // Our phpBB tags - // Commented out tokens are handled separately from the main replace - $phpbb_tags = array( - /*'BEGIN', - 'BEGINELSE', - 'END', - 'IF', - 'ELSE', - 'ELSEIF', - 'ENDIF', - 'DEFINE', - 'UNDEFINE',*/ - 'ENDDEFINE', - 'INCLUDE', - 'INCLUDEPHP', - 'INCLUDEJS', - 'INCLUDECSS', - 'PHP', - 'ENDPHP', - 'EVENT', - ); - - // Twig tag masks - $twig_tags = array( - 'autoescape', - 'endautoescape', - 'if', - 'elseif', - 'else', - 'endif', - 'block', - 'endblock', - 'use', - 'extends', - 'embed', - 'filter', - 'endfilter', - 'flush', - 'for', - 'endfor', - 'macro', - 'endmacro', - 'import', - 'from', - 'sandbox', - 'endsandbox', - 'set', - 'endset', - 'spaceless', - 'endspaceless', - 'verbatim', - 'endverbatim', - ); - - // Fix tokens that may have inline variables (e.g. with Twig style, {% TOKEN %} - // This also strips outer parenthesis, becomes - $code = preg_replace('##', '{% $1 $2 %}', $code); - - // Replace all of our twig masks with Twig code (e.g. with {% block $1 %}) - $code = $this->replace_twig_tag_masks($code, $twig_tags); - - // Replace all of our language variables, {L_VARNAME}, with Twig style, {{ lang('NAME') }} - // 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')|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); - - // Tokenize \Twig_Source instance - return parent::tokenize(new \Twig_Source($code, $filename)); - } - - /** - * Strip surrounding quotes - * - * First step to fix tokens that may have inline variables - * E.g. #', '', $code); - } - - /** - * Fix tokens that may have inline variables - * - * Second step to fix tokens that may have inline variables - * E.g. "; - }; - - return preg_replace_callback('##', $callback, $code); - } - - /** - * Add surrounding quotes - * - * Last step to fix tokens that may have inline variables - * E.g. #', '', $code); - } - - /** - * Fix begin tokens (convert our BEGIN to Twig for) - * - * Not meant to be used outside of this context, public because the anonymous function calls this - * - * @param string $code - * @param array $parent_nodes (used in recursion) - * @return string - */ - public function fix_begin_tokens($code, $parent_nodes = array()) - { - // PHP 5.3 cannot use $this in an anonymous function, so use this as a work-around - $parent_class = $this; - $callback = function ($matches) use ($parent_class, $parent_nodes) - { - $hard_parents = explode('.', $matches[1]); - array_pop($hard_parents); // ends with . - if ($hard_parents) - { - $parent_nodes = array_merge($hard_parents, $parent_nodes); - } - - $name = $matches[2]; - $subset = trim(substr($matches[3], 1, -1)); // Remove parenthesis - $body = $matches[4]; - - // Replace - $body = str_replace('', '{% else %}', $body); - - // Is the designer wanting to call another loop in a loop? - // - // - // - // - // 'loop2' is actually on the same nesting level as 'loop' you assign - // variables to it with template->assign_block_vars('loop2', array(...)) - if (strpos($name, '!') === 0) - { - // Count the number if ! occurrences - $count = substr_count($name, '!'); - for ($i = 0; $i < $count; $i++) - { - array_pop($parent_nodes); - $name = substr($name, 1); - } - } - - // Remove all parent nodes, e.g. foo, bar from foo.bar.foobar.VAR - foreach ($parent_nodes as $node) - { - $body = preg_replace('#([^a-zA-Z0-9_])' . $node . '\.([a-zA-Z0-9_]+)\.#', '$1$2.', $body); - } - - // Add current node to list of parent nodes for child nodes - $parent_nodes[] = $name; - - // Recursive...fix any child nodes - $body = $parent_class->fix_begin_tokens($body, $parent_nodes); - - // Need the parent variable name - array_pop($parent_nodes); - $parent = (!empty($parent_nodes)) ? end($parent_nodes) . '.' : ''; - - if ($subset !== '') - { - $subset = '|subset(' . $subset . ')'; - } - - $parent = ($parent) ?: 'loops.'; - // Turn into a Twig for loop - return "{% for {$name} in {$parent}{$name}{$subset} %}{$body}{% endfor %}"; - }; - - return preg_replace_callback('#(.+?)#s', $callback, $code); - } - - /** - * Fix IF statements - * - * @param string $code - * @return string - */ - protected function fix_if_tokens($code) - { - // Replace ELSE IF with ELSEIF - $code = preg_replace('##', '', $code); - - // Replace our "div by" with Twig's divisibleby (Twig does not like test names with spaces) - $code = preg_replace('# div by ([0-9]+)#', ' divisibleby($1)', $code); - - $callback = function($matches) - { - $inner = $matches[2]; - // Replace $TEST with definition.TEST - $inner = preg_replace('#(\s\(*!?)\$([a-zA-Z_0-9]+)#', '$1definition.$2', $inner); - - // Replace .foo with loops.foo|length - $inner = preg_replace('#(\s\(*!?)\.([a-zA-Z_0-9]+)([^a-zA-Z_0-9\.])#', '$1loops.$2|length$3', $inner); - - // Replace .foo.bar with foo.bar|length - $inner = preg_replace('#(\s\(*!?)\.([a-zA-Z_0-9\.]+)([^a-zA-Z_0-9\.])#', '$1$2|length$3', $inner); - - return ""; - }; - - return preg_replace_callback('##', $callback, $code); - } - - /** - * Fix DEFINE statements and {$VARNAME} variables - * - * @param string $code - * @return string - */ - protected function fix_define_tokens($code) - { - /** - * Changing $VARNAME to definition.varname because set is only local - * context (e.g. DEFINE $TEST will only make $TEST available in current - * template and any child templates, but not any parent templates). - * - * DEFINE handles setting it properly to definition in its node, but the - * variables reading FROM it need to be altered to definition.VARNAME - * - * Setting up definition as a class in the array passed to Twig - * ($context) makes set definition.TEST available in the global context - */ - - // Replace #', '{% DEFINE $1 %}', $code); - - // Changing UNDEFINE NAME to DEFINE NAME = null to save from creating an extra token parser/node - $code = preg_replace('##', '{% DEFINE $1= null %}', $code); - - // Replace all of our variables, {$VARNAME}, with Twig style, {{ definition.VARNAME }} - $code = preg_replace('#{\$([a-zA-Z0-9_\.]+)}#', '{{ definition.$1 }}', $code); - - // Replace all of our variables, ~ $VARNAME ~, with Twig style, ~ definition.VARNAME ~ - $code = preg_replace('#~ \$([a-zA-Z0-9_\.]+) ~#', '~ definition.$1 ~', $code); - - return $code; - } - - /** - * Replace Twig tag masks with Twig tag calls - * - * E.g. with {% block foo %} - * - * @param string $code - * @param array $twig_tags All tags we want to create a mask for - * @return string - */ - protected function replace_twig_tag_masks($code, $twig_tags) - { - $callback = function ($matches) - { - $matches[1] = strtolower($matches[1]); - - return "{% {$matches[1]}{$matches[2]}%}"; - }; - - foreach ($twig_tags as &$tag) - { - $tag = strtoupper($tag); - } - - // twig_tags is an array of the twig tags, which are all lowercase, but we use all uppercase tags - $code = preg_replace_callback('##',$callback, $code); - - return $code; - } -} diff --git a/install/update/new/phpbb/template/twig/loader.php b/install/update/new/phpbb/template/twig/loader.php deleted file mode 100644 index 0f193db..0000000 --- a/install/update/new/phpbb/template/twig/loader.php +++ /dev/null @@ -1,176 +0,0 @@ - -* @license 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; - -/** -* Twig Template loader -*/ -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, __DIR__); - } - - /** - * Set safe directories - * - * @param array $directories Array of directories that are safe (empty to clear) - * @return \Twig_Loader_Filesystem - */ - public function setSafeDirectories($directories = array()) - { - $this->safe_directories = array(); - - if (!empty($directories)) - { - foreach ($directories as $directory) - { - $this->addSafeDirectory($directory); - } - } - - return $this; - } - - /** - * Add safe directory - * - * @param string $directory Directory that should be added - * @return \Twig_Loader_Filesystem - */ - public function addSafeDirectory($directory) - { - $directory = $this->filesystem->realpath($directory); - - if ($directory !== false) - { - $this->safe_directories[] = $directory; - } - - return $this; - } - - /** - * Get current safe directories - * - * @return array - */ - public function getSafeDirectories() - { - return $this->safe_directories; - } - - /** - * Override for parent::validateName() - * - * This is done because we added support for safe directories, and when Twig - * findTemplate() is called, validateName() is called first, which would - * always throw an exception if the file is outside of the configured - * template directories. - */ - protected function validateName($name) - { - return; - } - - /** - * 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 - * for loading from safe directories. - */ - protected function findTemplate($name, $throw = true) - { - $name = (string) $name; - - // normalize name - $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); - - // If this is in the cache we can skip the entire process below - // as it should have already been validated - if (isset($this->cache[$name])) - { - return $this->cache[$name]; - } - - // First, find the template name. The override above of validateName - // causes the validateName process to be skipped for this call - $file = parent::findTemplate($name, $throw); - - try - { - // Try validating the name (which may throw an exception) - $this->validateName($name); - } - catch (\Twig_Error_Loader $e) - { - if (strpos($e->getRawMessage(), 'Looks like you try to load a template outside configured directories') === 0) - { - // Ok, so outside of the configured template directories, we - // can now check if we're within a "safe" directory - - // Find the real path of the directory the file is in - $directory = $this->filesystem->realpath(dirname($file)); - - if ($directory === false) - { - // Some sort of error finding the actual path, must throw the exception - throw $e; - } - - foreach ($this->safe_directories as $safe_directory) - { - if (strpos($directory, $safe_directory) === 0) - { - // The directory being loaded is below a directory - // that is "safe". We're good to load it! - return $file; - } - } - } - - // Not within any safe directories - throw $e; - } - - // No exception from validateName, safe to load. - return $file; - } -} diff --git a/install/update/new/phpbb/template/twig/node/definenode.php b/install/update/new/phpbb/template/twig/node/definenode.php deleted file mode 100644 index 1c51596..0000000 --- a/install/update/new/phpbb/template/twig/node/definenode.php +++ /dev/null @@ -1,57 +0,0 @@ - -* @copyright Portions (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\node; - -class definenode extends \Twig_Node -{ - public function __construct($capture, \Twig_Node $name, \Twig_Node $value, $lineno, $tag = null) - { - parent::__construct(array('name' => $name, 'value' => $value), array('capture' => $capture, 'safe' => false), $lineno, $tag); - } - - /** - * Compiles the node to PHP. - * - * @param \Twig_Compiler A Twig_Compiler instance - */ - public function compile(\Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - if ($this->getAttribute('capture')) - { - $compiler - ->write("ob_start();\n") - ->subcompile($this->getNode('value')) - ; - - $compiler->write("\$value = ('' === \$value = ob_get_clean()) ? '' : new \Twig_Markup(\$value, \$this->env->getCharset());\n"); - } - else - { - $compiler - ->write("\$value = ") - ->subcompile($this->getNode('value')) - ->raw(";\n") - ; - } - - $compiler - ->write("\$context['definition']->set('") - ->raw($this->getNode('name')->getAttribute('name')) - ->raw("', \$value);\n") - ; - } -} diff --git a/install/update/new/phpbb/template/twig/node/includeasset.php b/install/update/new/phpbb/template/twig/node/includeasset.php deleted file mode 100644 index 69bfd58..0000000 --- a/install/update/new/phpbb/template/twig/node/includeasset.php +++ /dev/null @@ -1,65 +0,0 @@ - -* @license 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\node; - -abstract class includeasset extends \Twig_Node -{ - public function __construct(\Twig_Node_Expression $expr, $lineno, $tag = null) - { - parent::__construct(array('expr' => $expr), array(), $lineno, $tag); - } - - /** - * Compiles the node to PHP. - * - * @param \Twig_Compiler A Twig_Compiler instance - */ - public function compile(\Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - $compiler - ->write("\$asset_file = ") - ->subcompile($this->getNode('expr')) - ->raw(";\n") - ->write("\$asset = new \phpbb\\template\\asset(\$asset_file, \$this->env->get_path_helper(), \$this->env->get_filesystem());\n") - ->write("if (substr(\$asset_file, 0, 2) !== './' && \$asset->is_relative()) {\n") - ->indent() - ->write("\$asset_path = \$asset->get_path();") - ->write("\$local_file = \$this->env->get_phpbb_root_path() . \$asset_path;\n") - ->write("if (!file_exists(\$local_file)) {\n") - ->indent() - ->write("\$local_file = \$this->env->findTemplate(\$asset_path);\n") - ->write("\$asset->set_path(\$local_file, true);\n") - ->outdent() - ->write("}\n") - ->outdent() - ->write("}\n") - ->write("\n") - ->write("if (\$asset->is_relative()) {\n") - ->indent() - ->write("\$asset->add_assets_version(\$this->env->get_phpbb_config()['assets_version']);\n") - ->outdent() - ->write("}\n") - ->write("\$this->env->get_assets_bag()->add_{$this->get_setters_name()}(\$asset);") - ; - } - - /** - * Get the name of the assets bag setter - * - * @return string (e.g. 'script') - */ - abstract public function get_setters_name(); -} diff --git a/install/update/new/phpbb/template/twig/node/includephp.php b/install/update/new/phpbb/template/twig/node/includephp.php deleted file mode 100644 index 0cf95ab..0000000 --- a/install/update/new/phpbb/template/twig/node/includephp.php +++ /dev/null @@ -1,91 +0,0 @@ - -* Sections (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\node; - -class includephp extends \Twig_Node -{ - /** @var \Twig_Environment */ - protected $environment; - - public function __construct(\Twig_Node_Expression $expr, \phpbb\template\twig\environment $environment, $lineno, $ignoreMissing = false, $tag = null) - { - $this->environment = $environment; - - parent::__construct(array('expr' => $expr), array('ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag); - } - - /** - * Compiles the node to PHP. - * - * @param \Twig_Compiler A Twig_Compiler instance - */ - public function compile(\Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - $config = $this->environment->get_phpbb_config(); - - if (!$config['tpl_allow_php']) - { - $compiler - ->write("// INCLUDEPHP Disabled\n") - ; - - return; - } - - if ($this->getAttribute('ignore_missing')) - { - $compiler - ->write("try {\n") - ->indent() - ; - } - - $compiler - ->write("\$location = ") - ->subcompile($this->getNode('expr')) - ->raw(";\n") - ->write("if (phpbb_is_absolute(\$location)) {\n") - ->indent() - // Absolute path specified - ->write("require(\$location);\n") - ->outdent() - ->write("} else if (file_exists(\$this->env->get_phpbb_root_path() . \$location)) {\n") - ->indent() - // PHP file relative to phpbb_root_path - ->write("require(\$this->env->get_phpbb_root_path() . \$location);\n") - ->outdent() - ->write("} else {\n") - ->indent() - // Local path (behaves like INCLUDE) - ->write("require(\$this->env->getLoader()->getCacheKey(\$location));\n") - ->outdent() - ->write("}\n") - ; - - if ($this->getAttribute('ignore_missing')) - { - $compiler - ->outdent() - ->write("} catch (\Twig_Error_Loader \$e) {\n") - ->indent() - ->write("// ignore missing template\n") - ->outdent() - ->write("}\n\n") - ; - } - } -} diff --git a/install/update/new/phpbb/template/twig/tokenparser/defineparser.php b/install/update/new/phpbb/template/twig/tokenparser/defineparser.php deleted file mode 100644 index 6285091..0000000 --- a/install/update/new/phpbb/template/twig/tokenparser/defineparser.php +++ /dev/null @@ -1,76 +0,0 @@ - -* @copyright Portions (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\tokenparser; - -class defineparser extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_Node A Twig_Node instance - * @throws \Twig_Error_Syntax - * @throws \phpbb\template\twig\node\definenode - */ - public function parse(\Twig_Token $token) - { - $lineno = $token->getLine(); - $stream = $this->parser->getStream(); - $name = $this->parser->getExpressionParser()->parseExpression(); - - $capture = false; - if ($stream->test(\Twig_Token::OPERATOR_TYPE, '=')) - { - $stream->next(); - $value = $this->parser->getExpressionParser()->parseExpression(); - - if ($value instanceof \Twig_Node_Expression_Name) - { - // This would happen if someone improperly formed their DEFINE syntax - // e.g. - throw new \Twig_Error_Syntax('Invalid DEFINE', $token->getLine(), $this->parser->getStream()->getSourceContext()->getPath()); - } - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - } - else - { - $capture = true; - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - $value = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - } - - return new \phpbb\template\twig\node\definenode($capture, $name, $value, $lineno, $this->getTag()); - } - - public function decideBlockEnd(\Twig_Token $token) - { - return $token->test('ENDDEFINE'); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'DEFINE'; - } -} diff --git a/install/update/new/phpbb/template/twig/tokenparser/event.php b/install/update/new/phpbb/template/twig/tokenparser/event.php deleted file mode 100644 index 92ecff4..0000000 --- a/install/update/new/phpbb/template/twig/tokenparser/event.php +++ /dev/null @@ -1,57 +0,0 @@ - -* @license 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\tokenparser; - -class event extends \Twig_TokenParser -{ - /** @var \phpbb\template\twig\environment */ - protected $environment; - - /** - * Constructor - * - * @param \phpbb\template\twig\environment $environment - */ - public function __construct(\phpbb\template\twig\environment $environment) - { - $this->environment = $environment; - } - - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_Node A Twig_Node instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - $stream = $this->parser->getStream(); - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\event($expr, $this->environment, $token->getLine(), $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'EVENT'; - } -} diff --git a/install/update/new/phpbb/template/twig/tokenparser/includecss.php b/install/update/new/phpbb/template/twig/tokenparser/includecss.php deleted file mode 100644 index f7e55a4..0000000 --- a/install/update/new/phpbb/template/twig/tokenparser/includecss.php +++ /dev/null @@ -1,44 +0,0 @@ - -* @license 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\tokenparser; - -class includecss extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_Node A Twig_Node instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - $stream = $this->parser->getStream(); - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\includecss($expr, $token->getLine(), $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'INCLUDECSS'; - } -} diff --git a/install/update/new/phpbb/template/twig/tokenparser/includejs.php b/install/update/new/phpbb/template/twig/tokenparser/includejs.php deleted file mode 100644 index 598ea0a..0000000 --- a/install/update/new/phpbb/template/twig/tokenparser/includejs.php +++ /dev/null @@ -1,44 +0,0 @@ - -* @license 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\tokenparser; - -class includejs extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_Node A Twig_Node instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - $stream = $this->parser->getStream(); - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\includejs($expr, $token->getLine(), $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'INCLUDEJS'; - } -} diff --git a/install/update/new/phpbb/template/twig/tokenparser/includeparser.php b/install/update/new/phpbb/template/twig/tokenparser/includeparser.php deleted file mode 100644 index 2fba4ac..0000000 --- a/install/update/new/phpbb/template/twig/tokenparser/includeparser.php +++ /dev/null @@ -1,44 +0,0 @@ - -* @copyright Portions (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\tokenparser; - -class includeparser extends \Twig_TokenParser_Include -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_Node A Twig_Node instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - list($variables, $only, $ignoreMissing) = $this->parseArguments(); - - return new \phpbb\template\twig\node\includenode($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'INCLUDE'; - } -} diff --git a/install/update/new/phpbb/template/twig/tokenparser/includephp.php b/install/update/new/phpbb/template/twig/tokenparser/includephp.php deleted file mode 100644 index 2fdf396..0000000 --- a/install/update/new/phpbb/template/twig/tokenparser/includephp.php +++ /dev/null @@ -1,68 +0,0 @@ - -* @copyright Portions (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\tokenparser; - -class includephp extends \Twig_TokenParser -{ - /** @var \phpbb\template\twig\environment */ - protected $environment; - - /** - * Constructor - * - * @param \phpbb\template\twig\environment $environment - */ - public function __construct(\phpbb\template\twig\environment $environment) - { - $this->environment = $environment; - } - - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_Node A Twig_Node instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - $stream = $this->parser->getStream(); - - $ignoreMissing = false; - if ($stream->test(\Twig_Token::NAME_TYPE, 'ignore')) - { - $stream->next(); - $stream->expect(\Twig_Token::NAME_TYPE, 'missing'); - - $ignoreMissing = true; - } - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\includephp($expr, $this->environment, $token->getLine(), $ignoreMissing, $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'INCLUDEPHP'; - } -} diff --git a/install/update/new/phpbb/template/twig/tokenparser/php.php b/install/update/new/phpbb/template/twig/tokenparser/php.php deleted file mode 100644 index 3007912..0000000 --- a/install/update/new/phpbb/template/twig/tokenparser/php.php +++ /dev/null @@ -1,65 +0,0 @@ - -* @license 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\tokenparser; - -class php extends \Twig_TokenParser -{ - /** @var \phpbb\template\twig\environment */ - protected $environment; - - /** - * Constructor - * - * @param \phpbb\template\twig\environment $environment - */ - public function __construct(\phpbb\template\twig\environment $environment) - { - $this->environment = $environment; - } - - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_Node A Twig_Node instance - */ - public function parse(\Twig_Token $token) - { - $stream = $this->parser->getStream(); - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - $body = $this->parser->subparse(array($this, 'decideEnd'), true); - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\php($body, $this->environment, $token->getLine(), $this->getTag()); - } - - public function decideEnd(\Twig_Token $token) - { - return $token->test('ENDPHP'); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'PHP'; - } -} diff --git a/install/update/new/phpbb/textformatter/acp_utils_interface.php b/install/update/new/phpbb/textformatter/acp_utils_interface.php deleted file mode 100644 index cdee56f..0000000 --- a/install/update/new/phpbb/textformatter/acp_utils_interface.php +++ /dev/null @@ -1,54 +0,0 @@ - -* @license 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 acp_utils_interface -{ - /** - * There is an issue with the definition - */ - const BBCODE_STATUS_INVALID_DEFINITION = 'invalid_definition'; - - /** - * There is an issue with the template - */ - const BBCODE_STATUS_INVALID_TEMPLATE = 'invalid_template'; - - /** - * The BBCode is valid and can be safely used by anyone - */ - const BBCODE_STATUS_SAFE = 'safe'; - - /** - * The BBCode is valid but may be unsafe to use - */ - const BBCODE_STATUS_UNSAFE = 'unsafe'; - - /** - * Analyse given BBCode definition for issues and safeness - * - * Required elements in the return array: - * - status: see BBCODE_STATUS_* constants - * - * Optional elements in the return array: - * - name: Name of the BBCode based on the definition. Required if status is "safe". - * - error_text: Textual description of the issue in plain text or as a L_* string. - * - error_html: Visual description of the issue in HTML. - * - * @param string $definition BBCode definition, e.g. [b]{TEXT}[/b] - * @param string $template BBCode template, e.g. {TEXT} - * @return array - */ - public function analyse_bbcode(string $definition, string $template): array; -} diff --git a/install/update/new/phpbb/textformatter/s9e/acp_utils.php b/install/update/new/phpbb/textformatter/s9e/acp_utils.php deleted file mode 100644 index c4a6680..0000000 --- a/install/update/new/phpbb/textformatter/s9e/acp_utils.php +++ /dev/null @@ -1,67 +0,0 @@ - -* @license 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\acp_utils_interface; -use s9e\TextFormatter\Configurator\Exceptions\UnsafeTemplateException; - -class acp_utils implements acp_utils_interface -{ - /** - * @var factory $factory - */ - protected $factory; - - /** - * @param factory $factory - */ - public function __construct(factory $factory) - { - $this->factory = $factory; - } - - /** - * {@inheritdoc} - */ - public function analyse_bbcode(string $definition, string $template): array - { - $configurator = $this->factory->get_configurator(); - $return = ['status' => self::BBCODE_STATUS_SAFE]; - - // Capture and normalize the BBCode name manually because there's no easy way to retrieve - // it in TextFormatter <= 2.x - if (preg_match('(\\[([-\\w]++))', $definition, $m)) - { - $return['name'] = strtoupper($m[1]); - } - - try - { - $configurator->BBCodes->addCustom($definition, $template); - } - catch (UnsafeTemplateException $e) - { - $return['status'] = self::BBCODE_STATUS_UNSAFE; - $return['error_text'] = $e->getMessage(); - $return['error_html'] = $e->highlightNode(''); - } - catch (\Exception $e) - { - $return['status'] = (preg_match('(xml|xpath|xsl)i', $e->getMessage())) ? self::BBCODE_STATUS_INVALID_TEMPLATE : self::BBCODE_STATUS_INVALID_DEFINITION; - $return['error_text'] = $e->getMessage(); - } - - return $return; - } -} diff --git a/install/update/new/phpbb/textformatter/s9e/bbcode_merger.php b/install/update/new/phpbb/textformatter/s9e/bbcode_merger.php deleted file mode 100644 index d1bedb0..0000000 --- a/install/update/new/phpbb/textformatter/s9e/bbcode_merger.php +++ /dev/null @@ -1,199 +0,0 @@ - -* @license 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\TemplateLoader; -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 = TemplateLoader::load($template); - $dom->formatOutput = true; - $template = TemplateLoader::save($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 = '' . $with['tag']->template . '' . $without['tag']->template . ''; - - 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('()', '{$1}', $template); - - // Beautify the template - $template = $this->indent_template($template); - - return $template; - } -} diff --git a/install/update/new/phpbb/textformatter/s9e/factory.php b/install/update/new/phpbb/textformatter/s9e/factory.php deleted file mode 100644 index f82c7b0..0000000 --- a/install/update/new/phpbb/textformatter/s9e/factory.php +++ /dev/null @@ -1,678 +0,0 @@ - -* @license 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' => '', - 'i' => '', - 'u' => '', - 'img' => '{L_IMAGE}', - 'size' => 'font-size: %; line-height: normal', - 'color' => '', - 'email' => ' - - mailto: - - - ? - subject= - &body= - - - - ', - ); - - /** - * @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 = '' . $tag->template . ''; - } - - // 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'], - '{.}' - ); - } - - 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 = ' - - {.} - - - {.} - - '; - $tag->template = '' . str_replace('class="emoji"', 'class="emoji smilies"', $tag->template) . ''; - - /** - * 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 = ''; - - $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('#(.*?)#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'] . '' . $fragment; - } - } - } - - // Manually recompose and overwrite irregular templates - $templates['list'] = - ' - - ' . $fragments['ulist_open_default'] . '' . $fragments['ulist_close'] . ' - - - ' . $fragments['olist_open'] . '' . $fragments['olist_close'] . ' - - - ' . $fragments['ulist_open'] . '' . $fragments['ulist_close'] . ' - - '; - - $templates['li'] = $fragments['listitem'] . '' . $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'] . ' ia ia ' . $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 = ''; - foreach ($grouped_templates as $style_template => $exprs) - { - $template .= '' . $style_template . ''; - } - $template .= '' . $default_template . ''; - - return $template; - } -} diff --git a/install/update/new/phpbb/textformatter/s9e/link_helper.php b/install/update/new/phpbb/textformatter/s9e/link_helper.php deleted file mode 100644 index 1cd5dd2..0000000 --- a/install/update/new/phpbb/textformatter/s9e/link_helper.php +++ /dev/null @@ -1,115 +0,0 @@ - -* @license 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/install/update/new/phpbb/textformatter/s9e/parser.php b/install/update/new/phpbb/textformatter/s9e/parser.php deleted file mode 100644 index f7e4668..0000000 --- a/install/update/new/phpbb/textformatter/s9e/parser.php +++ /dev/null @@ -1,417 +0,0 @@ - -* @license 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/install/update/new/phpbb/textformatter/s9e/quote_helper.php b/install/update/new/phpbb/textformatter/s9e/quote_helper.php deleted file mode 100644 index 3011ec8..0000000 --- a/install/update/new/phpbb/textformatter/s9e/quote_helper.php +++ /dev/null @@ -1,87 +0,0 @@ - -* @license 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/install/update/new/phpbb/ucp/controller/reset_password.php b/install/update/new/phpbb/ucp/controller/reset_password.php deleted file mode 100644 index 5c27c4f..0000000 --- a/install/update/new/phpbb/ucp/controller/reset_password.php +++ /dev/null @@ -1,443 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\ucp\controller; - -use phpbb\auth\auth; -use phpbb\config\config; -use phpbb\controller\helper; -use phpbb\db\driver\driver_interface; -use phpbb\event\dispatcher; -use phpbb\exception\http_exception; -use phpbb\language\language; -use phpbb\log\log_interface; -use phpbb\passwords\manager; -use phpbb\request\request_interface; -use phpbb\template\template; -use phpbb\user; -use Symfony\Component\HttpFoundation\Response; - -/** -* Handling forgotten passwords via reset password functionality -*/ -class reset_password -{ - /** @var config */ - protected $config; - - /** @var driver_interface */ - protected $db; - - /** @var dispatcher */ - protected $dispatcher; - - /** @var helper */ - protected $helper; - - /** @var language */ - protected $language; - - /** @var log_interface */ - protected $log; - - /** @var manager */ - protected $passwords_manager; - - /** @var request_interface */ - protected $request; - - /** @var template */ - protected $template; - - /** @var user */ - protected $user; - - /** @var array phpBB DB table names */ - protected $users_table; - - /** @var string phpBB root path */ - protected $root_path; - - /** @var string PHP extension */ - protected $php_ext; - - /** - * Reset password controller constructor. - * - * @param config $config - * @param driver_interface $db - * @param dispatcher $dispatcher - * @param helper $helper - * @param language $language - * @param log_interface $log - * @param manager $passwords_manager - * @param request_interface $request - * @param template $template - * @param user $user - * @param string $users_table - * @param string $root_path - * @param string $php_ext - */ - public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, helper $helper, - language $language, log_interface $log, manager $passwords_manager, - request_interface $request, template $template, user $user, string $users_table, - string $root_path, string $php_ext) - { - $this->config = $config; - $this->db = $db; - $this->dispatcher = $dispatcher; - $this->helper = $helper; - $this->language = $language; - $this->log = $log; - $this->passwords_manager = $passwords_manager; - $this->request = $request; - $this->template = $template; - $this->user = $user; - $this->users_table = $users_table; - $this->root_path = $root_path; - $this->php_ext = $php_ext; - } - - /** - * Init controller - */ - protected function init_controller() - { - $this->language->add_lang('ucp'); - - if (!$this->config['allow_password_reset']) - { - throw new http_exception(Response::HTTP_OK, 'UCP_PASSWORD_RESET_DISABLED', [ - '', - '' - ]); - } - } - - /** - * Remove reset token for specified user - * - * @param int $user_id User ID - */ - protected function remove_reset_token(int $user_id) - { - $sql_ary = [ - 'reset_token' => '', - 'reset_token_expiration' => 0, - ]; - - $sql = 'UPDATE ' . $this->users_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . $user_id; - $this->db->sql_query($sql); - } - - /** - * Handle password reset request - * - * @return Response - */ - public function request() - { - $this->init_controller(); - - $submit = $this->request->is_set_post('submit'); - $username = $this->request->variable('username', '', true); - $email = strtolower($this->request->variable('email', '')); - - add_form_key('ucp_reset_password'); - - if ($submit) - { - if (!check_form_key('ucp_reset_password')) - { - throw new http_exception(Response::HTTP_UNAUTHORIZED, 'FORM_INVALID'); - } - - if (empty($email)) - { - return $this->helper->message('NO_EMAIL_USER'); - } - - $sql_array = [ - 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' - . ' user_lang, user_inactive_reason, reset_token, reset_token_expiration', - 'FROM' => [$this->users_table => 'u'], - 'WHERE' => "user_email = '" . $this->db->sql_escape($email) . "'" . - (!empty($username) ? " AND username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'" : ''), - ]; - - /** - * Change SQL query for fetching user data - * - * @event core.ucp_remind_modify_select_sql - * @var string email User's email from the form - * @var string username User's username from the form - * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE - * @since 3.1.11-RC1 - * @changed 3.3.0-b1 Moved to reset password controller - */ - $vars = [ - 'email', - 'username', - 'sql_array', - ]; - extract($this->dispatcher->trigger_event('core.ucp_remind_modify_select_sql', compact($vars))); - - $sql = $this->db->sql_build_query('SELECT', $sql_array); - $result = $this->db->sql_query_limit($sql, 2); // don't waste resources on more rows than we need - $rowset = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - if (count($rowset) > 1) - { - $this->template->assign_vars([ - 'USERNAME_REQUIRED' => true, - 'EMAIL' => $email, - ]); - } - else - { - $message = $this->language->lang('PASSWORD_RESET_LINK_SENT') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); - - if (empty($rowset)) - { - return $this->helper->message($message); - } - - $user_row = $rowset[0]; - - if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) - { - return $this->helper->message($message); - } - - // Do not create multiple valid reset tokens - if (!empty($user_row['reset_token']) && (int) $user_row['reset_token_expiration'] >= time()) - { - return $this->helper->message($message); - } - - // Check users permissions - $auth = new auth(); - $auth->acl($user_row); - - if (!$auth->acl_get('u_chgpasswd')) - { - return $this->helper->message($message); - } - - // Generate reset token - $reset_token = strtolower(gen_rand_string(32)); - - $sql_ary = [ - 'reset_token' => $reset_token, - 'reset_token_expiration' => strtotime('+1 day'), - ]; - - $sql = 'UPDATE ' . $this->users_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . $user_row['user_id']; - $this->db->sql_query($sql); - - if (!class_exists('messenger')) - { - include($this->root_path . 'includes/functions_messenger.' . $this->php_ext); - } - - /** @var \messenger $messenger */ - $messenger = new \messenger(false); - - $messenger->template('user_forgot_password', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($this->config, $this->user); - - $messenger->assign_vars([ - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_RESET_PASSWORD' => generate_board_url(true) . $this->helper->route('phpbb_ucp_reset_password_controller', [ - 'u' => $user_row['user_id'], - 'token' => $reset_token, - ], false) - ]); - - $messenger->send($user_row['user_notify_type']); - - return $this->helper->message($message); - } - } - - $this->template->assign_vars([ - 'USERNAME' => $username, - 'EMAIL' => $email, - 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), - ]); - - return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); - } - - /** - * Handle controller requests - * - * @return Response - */ - public function reset() - { - $this->init_controller(); - - $submit = $this->request->is_set_post('submit'); - $reset_token = $this->request->variable('token', ''); - $user_id = $this->request->variable('u', 0); - - if (empty($reset_token)) - { - return $this->helper->message('NO_RESET_TOKEN'); - } - - if (!$user_id) - { - return $this->helper->message('NO_USER'); - } - - add_form_key('ucp_reset_password'); - - $sql_array = [ - 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' - . ' user_lang, user_inactive_reason, reset_token, reset_token_expiration', - 'FROM' => [$this->users_table => 'u'], - 'WHERE' => 'user_id = ' . $user_id, - ]; - - /** - * Change SQL query for fetching user data - * - * @event core.ucp_reset_password_modify_select_sql - * @var int user_id User ID from the form - * @var string reset_token Reset token - * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE - * @since 3.3.0-b1 - */ - $vars = [ - 'user_id', - 'reset_token', - 'sql_array', - ]; - extract($this->dispatcher->trigger_event('core.ucp_reset_password_modify_select_sql', compact($vars))); - - $sql = $this->db->sql_build_query('SELECT', $sql_array); - $result = $this->db->sql_query_limit($sql, 1); - $user_row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - $message = $this->language->lang('RESET_TOKEN_EXPIRED_OR_INVALID') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); - - if (empty($user_row)) - { - return $this->helper->message($message); - } - - if (!hash_equals($reset_token, $user_row['reset_token'])) - { - return $this->helper->message($message); - } - - if ($user_row['reset_token_expiration'] < time()) - { - $this->remove_reset_token($user_id); - - return $this->helper->message($message); - } - - $errors = []; - - if ($submit) - { - if (!check_form_key('ucp_reset_password')) - { - return $this->helper->message('FORM_INVALID'); - } - - if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) - { - return $this->helper->message($message); - } - - // Check users permissions - $auth = new auth(); - $auth->acl($user_row); - - if (!$auth->acl_get('u_chgpasswd')) - { - return $this->helper->message($message); - } - - if (!function_exists('validate_data')) - { - include($this->root_path . 'includes/functions_user.' . $this->php_ext); - } - - $data = [ - 'new_password' => $this->request->untrimmed_variable('new_password', '', true), - 'password_confirm' => $this->request->untrimmed_variable('new_password_confirm', '', true), - ]; - $check_data = [ - 'new_password' => [ - ['string', false, $this->config['min_pass_chars'], 0], - ['password'], - ], - 'password_confirm' => ['string', true, $this->config['min_pass_chars'], 0], - ]; - $errors = array_merge($errors, validate_data($data, $check_data)); - if (strcmp($data['new_password'], $data['password_confirm']) !== 0) - { - $errors[] = $data['password_confirm'] ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; - } - if (empty($errors)) - { - $sql_ary = [ - 'user_password' => $this->passwords_manager->hash($data['new_password']), - 'user_login_attempts' => 0, - 'reset_token' => '', - 'reset_token_expiration' => 0, - ]; - $sql = 'UPDATE ' . $this->users_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . (int) $user_row['user_id']; - $this->db->sql_query($sql); - $this->log->add('user', $user_row['user_id'], $this->user->ip, 'LOG_USER_NEW_PASSWORD', false, [ - 'reportee_id' => $user_row['user_id'], - $user_row['username'] - ]); - meta_refresh(3, append_sid("{$this->root_path}index.{$this->php_ext}")); - return $this->helper->message($this->language->lang('PASSWORD_RESET')); - } - } - - if (!empty($errors)) - { - $this->template->assign_block_vars_array('PASSWORD_RESET_ERRORS', array_map([$this->language, 'lang'], $errors)); - } - - $this->template->assign_vars([ - 'S_IS_PASSWORD_RESET' => true, - 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), - 'S_HIDDEN_FIELDS' => build_hidden_fields([ - 'u' => $user_id, - 'token' => $reset_token, - ]), - ]); - - return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); - } -} diff --git a/install/update/new/phpbb/user.php b/install/update/new/phpbb/user.php deleted file mode 100644 index 21d156e..0000000 --- a/install/update/new/phpbb/user.php +++ /dev/null @@ -1,848 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* Base user class -* -* This is the overarching class which contains (through session extend) -* all methods utilised for user functionality during a session. -*/ -class user extends \phpbb\session -{ - /** - * @var \phpbb\language\language - */ - protected $language; - - var $style = array(); - var $date_format; - - /** - * DateTimeZone object holding the timezone of the user - */ - public $timezone; - - /** - * @var string Class name of datetime object - */ - protected $datetime; - - var $lang_name = false; - var $lang_id = false; - var $lang_path; - 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 \phpbb\language\language $lang phpBB's Language loader - * @param string $datetime_class Class name of 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; - } - - /** - * Returns whether user::setup was called - * - * @return bool - */ - public function is_setup() - { - return $this->is_setup_flag; - } - - /** - * 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') - { - return $this->language->get_lang_array(); - } - else if ($param_name === 'help') - { - $help_array = $this->language->get_lang_array(); - return $help_array['__help']; - } - - return array(); - } - - /** - * Setup basic user-specific items (style, language, ...) - */ - function setup($lang_set = false, $style_id = false) - { - global $db, $request, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache; - global $phpbb_dispatcher, $phpbb_container; - - $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']); - $user_date_format = $this->data['user_dateformat']; - $user_timezone = $this->data['user_timezone']; - } - else - { - $lang_override = $request->variable('language', ''); - if ($lang_override) - { - $this->set_cookie('lang', $lang_override, 0, false); - } - else - { - $lang_override = $request->variable($config['cookie_name'] . '_lang', '', true, \phpbb\request\request_interface::COOKIE); - } - - if ($lang_override) - { - $use_lang = basename($lang_override); - $user_lang_name = (file_exists($this->lang_path . $use_lang . "/common.$phpEx")) ? $use_lang : basename($config['default_lang']); - $this->data['user_lang'] = $user_lang_name; - } - else - { - $user_lang_name = basename($config['default_lang']); - } - - $user_date_format = $config['default_dateformat']; - $user_timezone = $config['board_timezone']; - - /** - * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language - * If re-enabled we need to make sure only those languages installed are checked - * Commented out so we do not loose the code. - - if ($request->header('Accept-Language')) - { - $accept_lang_ary = explode(',', $request->header('Accept-Language')); - - foreach ($accept_lang_ary as $accept_lang) - { - // Set correct format ... guess full xx_YY form - $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2)); - $accept_lang = basename($accept_lang); - - if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx")) - { - $user_lang_name = $config['default_lang'] = $accept_lang; - break; - } - else - { - // No match on xx_YY so try xx - $accept_lang = substr($accept_lang, 0, 2); - $accept_lang = basename($accept_lang); - - if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx")) - { - $user_lang_name = $config['default_lang'] = $accept_lang; - break; - } - } - } - } - */ - } - - $user_data = $this->data; - $lang_set_ext = array(); - - /** - * 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 - * @var string user_date_format User's date/time format - * @var string user_timezone User's timezone, should be one of - * http://www.php.net/manual/en/timezones.php - * @var mixed lang_set String or array of language files - * @var array lang_set_ext Array containing entries of format - * array( - * 'ext_name' => (string) [extension name], - * 'lang_set' => (string|array) [language files], - * ) - * For performance reasons, only load translations - * that are absolutely needed globally using this - * event. Use local events otherwise. - * @var mixed style_id Style we are going to display - * @since 3.1.0-a1 - */ - $vars = array( - 'user_data', - 'user_lang_name', - 'user_date_format', - 'user_timezone', - 'lang_set', - 'lang_set_ext', - 'style_id', - ); - extract($phpbb_dispatcher->trigger_event('core.user_setup', compact($vars))); - - $this->data = $user_data; - $this->lang_name = $user_lang_name; - $this->date_format = $user_date_format; - - $this->language->set_user_language($user_lang_name); - - try - { - $this->timezone = new \DateTimeZone($user_timezone); - } - catch (\Exception $e) - { - // If the timezone the user has selected is invalid, we fall back to UTC. - $this->timezone = new \DateTimeZone('UTC'); - } - - $this->add_lang($lang_set); - unset($lang_set); - - foreach ($lang_set_ext as $ext_lang_pair) - { - $this->add_lang_ext($ext_lang_pair['ext_name'], $ext_lang_pair['lang_set']); - } - unset($lang_set_ext); - - $style_request = $request->variable('style', 0); - if ($style_request && (!$config['override_user_style'] || $auth->acl_get('a_styles')) && !defined('ADMIN_START')) - { - global $SID, $_EXTRA_URL; - - $style_id = $style_request; - $SID .= '&style=' . $style_id; - $_EXTRA_URL = array('style=' . $style_id); - } - else - { - // Set up style - $style_id = ($style_id) ? $style_id : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']); - } - - $sql = 'SELECT * - FROM ' . STYLES_TABLE . " s - WHERE s.style_id = $style_id"; - $result = $db->sql_query($sql, 3600); - $this->style = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Fallback to user's standard style - if (!$this->style && $style_id != $this->data['user_style']) - { - $style_id = $this->data['user_style']; - - $sql = 'SELECT * - FROM ' . STYLES_TABLE . " s - WHERE s.style_id = $style_id"; - $result = $db->sql_query($sql, 3600); - $this->style = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - // Fallback to board's default style - if (!$this->style) - { - // 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($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 - $parsed_items = $cache->obtain_cfg_items($this->style); - - $check_for = array( - 'pagination_sep' => (string) ', ' - ); - - foreach ($check_for as $key => $default_value) - { - $this->style[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value; - settype($this->style[$key], gettype($default_value)); - - if (is_string($default_value)) - { - $this->style[$key] = htmlspecialchars($this->style[$key]); - } - } - - $template->set_style(); - - $this->img_lang = $this->lang_name; - - // Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes... - // After calling it we continue script execution... - phpbb_user_session_handler(); - - /** - * Execute code at the end of user setup - * - * @event core.user_setup_after - * @since 3.1.6-RC1 - */ - $phpbb_dispatcher->dispatch('core.user_setup_after'); - - // If this function got called from the error handler we are finished here. - if (defined('IN_ERROR_HANDLER')) - { - return; - } - - // Disable board if the install/ directory is still present - // For the brave development army we do not care about this, else we need to comment out this every time we develop locally - if (!$phpbb_container->getParameter('allow_install_dir') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) - { - // Adjust the message slightly according to the permissions - if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) - { - $message = 'REMOVE_INSTALL'; - } - else - { - $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; - } - trigger_error($message); - } - - // Is board disabled and user not an admin or moderator? - if ($config['board_disable'] && !defined('IN_INSTALL') && !defined('IN_LOGIN') && !defined('SKIP_CHECK_DISABLED') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) - { - if ($this->data['is_bot']) - { - send_status_line(503, 'Service Unavailable'); - } - - $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; - trigger_error($message); - } - - // Is load exceeded? - if ($config['limit_load'] && $this->load !== false) - { - if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN') && !defined('IN_ADMIN')) - { - // Set board disabled to true to let the admins/mods get the proper notification - $config['board_disable'] = '1'; - - if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) - { - if ($this->data['is_bot']) - { - send_status_line(503, 'Service Unavailable'); - } - trigger_error('BOARD_UNAVAILABLE'); - } - } - } - - if (isset($this->data['session_viewonline'])) - { - // Make sure the user is able to hide his session - if (!$this->data['session_viewonline']) - { - // Reset online status if not allowed to hide the session... - if (!$auth->acl_get('u_hideonline')) - { - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_viewonline = 1 - WHERE session_user_id = ' . $this->data['user_id']; - $db->sql_query($sql); - $this->data['session_viewonline'] = 1; - } - } - else if (!$this->data['user_allow_viewonline']) - { - // the user wants to hide and is allowed to -> cloaking device on. - if ($auth->acl_get('u_hideonline')) - { - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_viewonline = 0 - WHERE session_user_id = ' . $this->data['user_id']; - $db->sql_query($sql); - $this->data['session_viewonline'] = 0; - } - } - } - - // Does the user need to change their password? If so, redirect to the - // ucp profile reg_details page ... of course do not redirect if we're already in the ucp - if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && !empty($this->data['is_registered']) && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) - { - if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx") - { - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&mode=reg_details')); - } - } - - $this->is_setup_flag = true; - - return; - } - - /** - * More advanced language substitution - * Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms. - * Params are the language key and the parameters to be substituted. - * This function/functionality is inspired by SHS` and Ashe. - * - * Example call: $user->lang('NUM_POSTS_IN_QUEUE', 1); - * - * If the first parameter is an array, the elements are used as keys and subkeys to get the language entry: - * Example: $user->lang(array('datetime', 'AGO'), 1) 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(); - return call_user_func_array(array($this->language, 'lang'), $args); - } - - /** - * Determine which plural form we should use. - * For some languages this is not as simple as for English. - * - * @param $number int|float The number we want to get the plural case for. Float numbers are floored. - * @param $force_rule mixed False to use the plural rule of the language package - * or an integer to force a certain plural rule - * @return int|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: 4.0.0) - */ - function get_plural_form($number, $force_rule = false) - { - 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 @deprecated 3.2.0-dev (To be removed: 4.0.0) - * @param bool $use_help internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 4.0.0) - * @param string $ext_name The extension to load language from, or empty for core files - * - * Examples: - * - * $lang_set = array('posting', 'help' => 'faq'); - * $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq')) - * $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq')) - * $lang_set = 'posting' - * $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting')) - * - * - * 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: 4.0.0) - */ - function add_lang($lang_set, $use_db = false, $use_help = false, $ext_name = '') - { - if (is_array($lang_set)) - { - foreach ($lang_set as $key => $lang_file) - { - // Please do not delete this line. - // We have to force the type here, else [array] language inclusion will not work - $key = (string) $key; - - if ($key == 'db') - { - // This is never used - $this->add_lang($lang_file, true, $use_help, $ext_name); - } - else if ($key == 'help') - { - $this->add_lang($lang_file, $use_db, true, $ext_name); - } - else if (!is_array($lang_file)) - { - $this->set_lang($lang_file, $use_help, $ext_name); - } - else - { - $this->add_lang($lang_file, $use_db, $use_help, $ext_name); - } - } - unset($lang_set); - } - else if ($lang_set) - { - $this->set_lang($lang_set, $use_help, $ext_name); - } - } - - /** - * BC function for loading language files - * - * @deprecated 3.2.0-dev (To be removed: 4.0.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); - } - - /** - * Add Language Items from an extension - use_db and use_help are assigned where needed (only use them to force inclusion) - * - * @param string $ext_name The extension to load language from, or empty for core files - * @param mixed $lang_set specifies the language entries to include - * @param bool $use_db internal variable for recursion, do not use - * @param bool $use_help internal variable for recursion, do not use - * - * Note: $use_db and $use_help should be removed. Kept for BC purposes. - * - * @deprecated: 3.2.0-dev (To be removed: 4.0.0) - */ - function add_lang_ext($ext_name, $lang_set, $use_db = false, $use_help = false) - { - if ($ext_name === '/') - { - $ext_name = ''; - } - - $this->add_lang($lang_set, $use_db, $use_help, $ext_name); - } - - /** - * Format user date - * - * @param int $gmepoch unix timestamp - * @param string $format date format in date() notation. | used to indicate relative dates, for example |d m Y|, h:i is translated to Today, h:i. - * @param bool $forcedate force non-relative date format. - * - * @return mixed translated date - */ - function format_date($gmepoch, $format = false, $forcedate = false) - { - global $phpbb_dispatcher; - static $utc; - - if (!isset($utc)) - { - $utc = new \DateTimeZone('UTC'); - } - - $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))); - - 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; - } - } - - /** - * Create a \phpbb\datetime object in the context of the current user - * - * @since 3.1 - * @param string $time String in a format accepted by strtotime(). - * @param DateTimeZone $timezone Time zone of the time. - * @return \phpbb\datetime Date time object linked to the current users locale - */ - public function create_datetime($time = 'now', \DateTimeZone $timezone = null) - { - $timezone = $timezone ?: $this->timezone; - return new $this->datetime($this, $time, $timezone); - } - - /** - * Get the UNIX timestamp for a datetime in the users timezone, so we can store it in the database. - * - * @param string $format Format of the entered date/time - * @param string $time Date/time with the timezone applied - * @param DateTimeZone $timezone Timezone of the date/time, falls back to timezone of current user - * @return int Returns the unix timestamp - */ - public function get_timestamp_from_format($format, $time, \DateTimeZone $timezone = null) - { - $timezone = $timezone ?: $this->timezone; - $date = \DateTime::createFromFormat($format, $time, $timezone); - return ($date !== false) ? $date->format('U') : false; - } - - /** - * Get language id currently used by the user - */ - function get_iso_lang_id() - { - global $config, $db; - - if (!empty($this->lang_id)) - { - return $this->lang_id; - } - - if (!$this->lang_name) - { - $this->lang_name = $config['default_lang']; - } - - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'"; - $result = $db->sql_query($sql); - $this->lang_id = (int) $db->sql_fetchfield('lang_id'); - $db->sql_freeresult($result); - - return $this->lang_id; - } - - /** - * Get users profile fields - */ - function get_profile_fields($user_id) - { - global $db; - - if (isset($this->profile_fields)) - { - return; - } - - $sql = 'SELECT * - FROM ' . PROFILE_FIELDS_DATA_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query_limit($sql, 1); - $this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row; - $db->sql_freeresult($result); - } - - /** - * Specify/Get image - */ - function img($img, $alt = '') - { - $title = ''; - - if ($alt) - { - $alt = $this->language->lang($alt); - $title = ' title="' . $alt . '"'; - } - return '' . $alt . ''; - } - - /** - * Get option bit field from user options. - * - * @param int $key option key, as defined in $keyoptions property. - * @param int $data bit field value to use, or false to use $this->data['user_options'] - * @return bool true if the option is set in the bit field, false otherwise - */ - function optionget($key, $data = false) - { - $var = ($data !== false) ? $data : $this->data['user_options']; - return phpbb_optionget($this->keyoptions[$key], $var); - } - - /** - * Set option bit field for user options. - * - * @param int $key Option key, as defined in $keyoptions property. - * @param bool $value True to set the option, false to clear the option. - * @param int $data Current bit field value, or false to use $this->data['user_options'] - * @return int|bool If $data is false, the bit field is modified and - * written back to $this->data['user_options'], and - * return value is true if the bit field changed and - * false otherwise. If $data is not false, the new - * bitfield value is returned. - */ - function optionset($key, $value, $data = false) - { - $var = ($data !== false) ? $data : $this->data['user_options']; - - $new_var = phpbb_optionset($this->keyoptions[$key], $value, $var); - - if ($data === false) - { - if ($new_var != $var) - { - $this->data['user_options'] = $new_var; - return true; - } - else - { - return false; - } - } - else - { - return $new_var; - } - } - - /** - * Function to make the user leave the NEWLY_REGISTERED system group. - * @access public - */ - function leave_newly_registered() - { - if (empty($this->data['user_new'])) - { - return false; - } - - if (!function_exists('remove_newly_registered')) - { - global $phpbb_root_path, $phpEx; - - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - if ($group = remove_newly_registered($this->data['user_id'], $this->data)) - { - $this->data['group_id'] = $group; - - } - $this->data['user_permissions'] = ''; - $this->data['user_new'] = 0; - - return true; - } - - /** - * Returns all password protected forum ids the user is currently NOT authenticated for. - * - * @return array Array of forum ids - * @access public - */ - function get_passworded_forums() - { - global $db; - - $sql = 'SELECT f.forum_id, fa.user_id - FROM ' . FORUMS_TABLE . ' f - LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa - ON (fa.forum_id = f.forum_id - AND fa.session_id = '" . $db->sql_escape($this->session_id) . "') - WHERE f.forum_password <> ''"; - $result = $db->sql_query($sql); - - $forum_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_id = (int) $row['forum_id']; - - if ($row['user_id'] != $this->data['user_id']) - { - $forum_ids[$forum_id] = $forum_id; - } - } - $db->sql_freeresult($result); - - return $forum_ids; - } -} diff --git a/install/update/new/phpbb/user_loader.php b/install/update/new/phpbb/user_loader.php deleted file mode 100644 index 3dacf07..0000000 --- a/install/update/new/phpbb/user_loader.php +++ /dev/null @@ -1,238 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* User loader class -* -* This handles loading users from the database and -* storing in them in a temporary cache so we do not -* have to query the same user multiple times in -* different services. -*/ -class user_loader -{ - /** @var \phpbb\db\driver\driver_interface */ - protected $db = null; - - /** @var string */ - protected $phpbb_root_path = null; - - /** @var string */ - protected $php_ext = null; - - /** @var string */ - protected $users_table = null; - - /** - * Users loaded from the DB - * - * @var array Array of user data that we've loaded from the DB - */ - protected $users = array(); - - /** - * User loader constructor - * - * @param \phpbb\db\driver\driver_interface $db A database connection - * @param string $phpbb_root_path Path to the phpbb includes directory. - * @param string $php_ext php file extension - * @param string $users_table The name of the database table (phpbb_users) - */ - public function __construct(\phpbb\db\driver\driver_interface $db, $phpbb_root_path, $php_ext, $users_table) - { - $this->db = $db; - - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->users_table = $users_table; - } - - /** - * Load user helper - * - * @param array $user_ids - * @param array $ignore_types user types to ignore - */ - public function load_users(array $user_ids, array $ignore_types = array()) - { - $user_ids[] = ANONYMOUS; - - // Make user_ids unique and convert to integer. - $user_ids = array_map('intval', array_unique($user_ids)); - - // Do not load users we already have in $this->users - $user_ids = array_diff($user_ids, array_keys($this->users)); - - if (count($user_ids)) - { - $sql = 'SELECT * - FROM ' . $this->users_table . ' - 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)) - { - $this->users[$row['user_id']] = $row; - } - $this->db->sql_freeresult($result); - } - } - - /** - * Load a user by username - * - * Stores the full data in the user cache so they do not need to be loaded again - * Returns the user id so you may use get_user() from the returned value - * - * @param string $username Raw username to load (will be cleaned) - * @return int User ID for the username - */ - public function load_user_by_username($username) - { - $sql = 'SELECT * - FROM ' . $this->users_table . " - WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - $this->users[$row['user_id']] = $row; - - return $row['user_id']; - } - - return ANONYMOUS; - } - - /** - * Get a user row from our users cache - * - * @param int $user_id User ID of the user you want to retrieve - * @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() - * @return array|bool Row from the database of the user or Anonymous if the user wasn't loaded/does not exist - * or bool False if the anonymous user was not loaded - */ - public function get_user($user_id, $query = false) - { - if (isset($this->users[$user_id])) - { - return $this->users[$user_id]; - } - // Query them if we must (if ANONYMOUS is sent as the user_id and we have not loaded Anonymous yet, we must load Anonymous as a last resort) - else if ($query || $user_id == ANONYMOUS) - { - $this->load_users(array($user_id)); - - return $this->get_user($user_id); - } - - return $this->get_user(ANONYMOUS); - } - - /** - * Get username - * - * @param int $user_id User ID of the user you want to retrieve the username for - * @param string $mode The mode to load (same as get_username_string). One of the following: - * 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) - * no_profile (the same as full but forcing no profile link) - * @param string $guest_username Optional parameter to specify the guest username. It will be used in favor of the GUEST language variable then. - * @param string $custom_profile_url Optional parameter to specify a profile url. The user id get appended to this url as &u={user_id} - * @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() - * @return string - */ - public function get_username($user_id, $mode, $guest_username = false, $custom_profile_url = false, $query = false) - { - if (!($user = $this->get_user($user_id, $query))) - { - return ''; - } - - return get_username_string($mode, $user['user_id'], $user['username'], $user['user_colour'], $guest_username, $custom_profile_url); - } - - /** - * Get avatar - * - * @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() - * @param bool @lazy If true, will be lazy loaded (requires JS) - * @return string - */ - public function get_avatar($user_id, $query = false, $lazy = false) - { - if (!($user = $this->get_user($user_id, $query))) - { - return ''; - } - - $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); - } - - /** - * Get rank - * - * @param int $user_id User ID of the user you want to retrieve the rank 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() - * @return array Array with keys 'rank_title', 'rank_img', and 'rank_img_src' - */ - public function get_rank($user_id, $query = false) - { - if (!($user = $this->get_user($user_id, $query))) - { - return ''; - } - - if (!function_exists('phpbb_get_user_rank')) - { - include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext); - } - - $rank = array( - 'rank_title', - 'rank_img', - 'rank_img_src', - ); - - $user_rank_data = phpbb_get_user_rank($user, (($user['user_id'] == ANONYMOUS) ? false : $user['user_posts'])); - $rank['rank_title'] = $user_rank_data['title']; - $rank['rank_img'] = $user_rank_data['img']; - $rank['rank_img_src'] = $user_rank_data['img_src']; - - return $rank; - } -} diff --git a/install/update/new/posting.php b/install/update/new/posting.php deleted file mode 100644 index c4042e4..0000000 --- a/install/update/new/posting.php +++ /dev/null @@ -1,2041 +0,0 @@ - -* @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); -$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_posting.' . $phpEx); -include($phpbb_root_path . 'includes/functions_display.' . $phpEx); -include($phpbb_root_path . 'includes/message_parser.' . $phpEx); - - -// Start session management -$user->session_begin(); -$auth->acl($user->data); - - -// Grab only parameters needed here -$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; -$load = (isset($_POST['load'])) ? true : false; -$confirm = $request->is_set_post('confirm'); -$cancel = (isset($_POST['cancel']) && !isset($_POST['save'])) ? true : false; - -$refresh = (isset($_POST['add_file']) || isset($_POST['delete_file']) || $save || $load || $preview); -$submit = $request->is_set_post('post') && !$refresh && !$preview; -$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))) -{ - $mode = 'soft_delete'; -} - -$error = $post_data = array(); -$current_time = time(); - -/** -* This event allows you to alter the above parameters, such as submit and mode -* -* Note: $refresh must be true to retain previously submitted form data. -* -* Note: The template class will not work properly until $user->setup() is -* called, and it has not been called yet. Extensions requiring template -* assignments should use an event that comes later in this file. -* -* @event core.modify_posting_parameters -* @var int post_id ID of the post -* @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 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 -* @var bool load Whether or not a draft is being loaded -* @var bool cancel Whether or not to cancel the form (returns to -* viewtopic or viewforum depending on if the user -* is posting a new topic or editing a post) -* @var bool refresh Whether or not to retain previously submitted data -* @var string mode What action to take if the form has been submitted -* post|reply|quote|edit|delete|bump|smilies|popup -* @var array error Any error strings; a non-empty array aborts -* form submission. -* NOTE: Should be actual language strings, NOT -* 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', - 'submit', - 'preview', - 'save', - 'load', - 'cancel', - 'refresh', - 'mode', - 'error', -); -extract($phpbb_dispatcher->trigger_event('core.modify_posting_parameters', compact($vars))); - -// Was cancel pressed? If so then redirect to the appropriate page -if ($cancel) -{ - $f = ($forum_id) ? 'f=' . $forum_id . '&' : ''; - $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"))); - redirect($redirect); -} - -if (in_array($mode, array('post', 'reply', 'quote', 'edit', 'delete')) && !$forum_id) -{ - 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. -switch ($mode) -{ - case 'post': - $sql = 'SELECT * - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - break; - - case 'bump': - case 'reply': - if (!$topic_id) - { - trigger_error('NO_TOPIC'); - } - - // Force forum id - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $f_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - $forum_id = (!$f_id) ? $forum_id : $f_id; - - $sql = 'SELECT f.*, t.* - FROM ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . " f - WHERE t.topic_id = $topic_id - AND f.forum_id = t.forum_id - AND " . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'); - break; - - case 'quote': - case 'edit': - case 'delete': - case 'soft_delete': - if (!$post_id) - { - $user->setup('posting'); - trigger_error('NO_POST'); - } - - // Force forum id - $sql = 'SELECT forum_id - FROM ' . POSTS_TABLE . ' - WHERE post_id = ' . $post_id; - $result = $db->sql_query($sql); - $f_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - $forum_id = (!$f_id) ? $forum_id : $f_id; - - $sql = 'SELECT f.*, t.*, p.*, u.username, u.username_clean, u.user_sig, u.user_sig_bbcode_uid, u.user_sig_bbcode_bitfield - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . ' f, ' . USERS_TABLE . " u - WHERE p.post_id = $post_id - AND t.topic_id = p.topic_id - AND u.user_id = p.poster_id - AND f.forum_id = t.forum_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.'); - break; - - case 'smilies': - $sql = ''; - generate_smilies('window', $forum_id); - break; - - case 'popup': - if ($forum_id) - { - $sql = 'SELECT forum_style - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $forum_id; - } - else - { - phpbb_upload_popup(); - return; - } - break; - - default: - $sql = ''; - break; -} - -if (!$sql) -{ - $user->setup('posting'); - trigger_error('NO_POST_MODE'); -} - -$result = $db->sql_query($sql); -$post_data = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -if (!$post_data) -{ - if (!($mode == 'post' || $mode == 'bump' || $mode == 'reply')) - { - $user->setup('posting'); - } - 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))) -{ - trigger_error(($mode == 'reply' || $mode == 'bump') ? 'TOPIC_UNAPPROVED' : 'POST_UNAPPROVED'); -} - -if ($mode == 'popup') -{ - phpbb_upload_popup($post_data['forum_style']); - return; -} - -$user->setup(array('posting', 'mcp', 'viewtopic'), $post_data['forum_style']); - -// 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; -$post_id = (!empty($post_data['post_id'])) ? (int) $post_data['post_id'] : (int) $post_id; - -// Need to login to passworded forum first? -if ($post_data['forum_password']) -{ - login_forum_box(array( - 'forum_id' => $forum_id, - 'forum_name' => $post_data['forum_name'], - 'forum_password' => $post_data['forum_password']) - ); -} - -// Check permissions -if ($user->data['is_bot']) -{ - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); -} - -// Is the user able to read within this forum? -if (!$auth->acl_get('f_read', $forum_id)) -{ - if ($user->data['user_id'] != ANONYMOUS) - { - trigger_error('USER_CANNOT_READ'); - } - $message = $user->lang['LOGIN_EXPLAIN_POST']; - - if ($request->is_ajax()) - { - $json = new phpbb\json_response(); - $json->send(array( - 'title' => $user->lang['INFORMATION'], - 'message' => $message, - )); - } - - login_box('', $message); -} - -// Permission to do the action asked? -$is_authed = false; - -switch ($mode) -{ - case 'post': - if ($auth->acl_get('f_post', $forum_id)) - { - $is_authed = true; - } - break; - - case 'bump': - if ($auth->acl_get('f_bump', $forum_id)) - { - $is_authed = true; - } - break; - - case 'quote': - - $post_data['post_edit_locked'] = 0; - - // no break; - - case 'reply': - if ($auth->acl_get('f_reply', $forum_id)) - { - $is_authed = true; - } - break; - - case 'edit': - if ($user->data['is_registered'] && $auth->acl_gets('f_edit', 'm_edit', $forum_id)) - { - $is_authed = true; - } - break; - - case 'delete': - if ($user->data['is_registered'] && ($auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id)))) - { - $is_authed = true; - } - - // no break; - - case 'soft_delete': - if (!$is_authed && $user->data['is_registered'] && $phpbb_content_visibility->can_soft_delete($forum_id, $post_data['poster_id'], $post_data['post_edit_locked'])) - { - // Fall back to soft_delete if we have no permissions to delete posts but to soft delete them - $is_authed = true; - $mode = 'soft_delete'; - } - break; -} -/** -* This event allows you to do extra auth checks and verify if the user -* has the required permissions -* -* Extensions should only change the error and is_authed variables. -* -* @event core.modify_posting_auth -* @var int post_id ID of the post -* @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 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 -* @var bool load Whether or not a draft is being loaded -* @var bool refresh Whether or not to retain previously submitted data -* @var string mode What action to take if the form has been submitted -* post|reply|quote|edit|delete|bump|smilies|popup -* @var array error Any error strings; a non-empty array aborts -* form submission. -* NOTE: Should be actual language strings, NOT -* language keys. -* @var bool is_authed Does the user have the required permissions? -* @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', - 'submit', - 'preview', - 'save', - 'load', - 'refresh', - 'mode', - 'error', - 'is_authed', - 'post_data', -); -extract($phpbb_dispatcher->trigger_event('core.modify_posting_auth', compact($vars))); - -if (!$is_authed || !empty($error)) -{ - $check_auth = ($mode == 'quote') ? 'reply' : (($mode == 'soft_delete') ? 'delete' : $mode); - - if ($user->data['is_registered']) - { - trigger_error(empty($error) ? 'USER_CANNOT_' . strtoupper($check_auth) : implode('
', $error)); - } - $message = $user->lang['LOGIN_EXPLAIN_' . strtoupper($mode)]; - - if ($request->is_ajax()) - { - $json = new phpbb\json_response(); - $json->send(array( - 'title' => $user->lang['INFORMATION'], - 'message' => $message, - )); - } - - 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'))) -{ - trigger_error('USER_CANNOT_FORUM_POST'); -} - -// Forum/Topic locked? -if (($post_data['forum_status'] == ITEM_LOCKED || (isset($post_data['topic_status']) && $post_data['topic_status'] == ITEM_LOCKED)) && !$auth->acl_get('m_edit', $forum_id)) -{ - trigger_error(($post_data['forum_status'] == ITEM_LOCKED) ? 'FORUM_LOCKED' : 'TOPIC_LOCKED'); -} - -// Can we edit this post ... if we're a moderator with rights then always yes -// else it depends on editing times, lock status and if we're the correct user -if ($mode == 'edit' && !$auth->acl_get('m_edit', $forum_id)) -{ - $force_edit_allowed = false; - - $s_cannot_edit = $user->data['user_id'] != $post_data['poster_id']; - $s_cannot_edit_time = $config['edit_time'] && $post_data['post_time'] <= time() - ($config['edit_time'] * 60); - $s_cannot_edit_locked = $post_data['post_edit_locked']; - - /** - * This event allows you to modify the conditions for the "cannot edit post" checks - * - * @event core.posting_modify_cannot_edit_conditions - * @var array post_data Array with post data - * @var bool force_edit_allowed Allow the user to edit the post (all permissions and conditions are ignored) - * @var bool s_cannot_edit User can not edit the post because it's not his - * @var bool s_cannot_edit_locked User can not edit the post because it's locked - * @var bool s_cannot_edit_time User can not edit the post because edit_time has passed - * @since 3.1.0-b4 - */ - $vars = array( - 'post_data', - 'force_edit_allowed', - 's_cannot_edit', - 's_cannot_edit_locked', - 's_cannot_edit_time', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_cannot_edit_conditions', compact($vars))); - - if (!$force_edit_allowed) - { - if ($s_cannot_edit) - { - trigger_error('USER_CANNOT_EDIT'); - } - else if ($s_cannot_edit_time) - { - trigger_error('CANNOT_EDIT_TIME'); - } - else if ($s_cannot_edit_locked) - { - trigger_error('CANNOT_EDIT_POST_LOCKED'); - } - } -} - -// Handle delete mode... -if ($mode == 'delete' || $mode == 'soft_delete') -{ - if ($mode == 'soft_delete' && $post_data['post_visibility'] == ITEM_DELETED) - { - $user->setup('posting'); - trigger_error('NO_POST'); - } - - $delete_reason = $request->variable('delete_reason', '', true); - phpbb_handle_post_delete($forum_id, $topic_id, $post_id, $post_data, ($mode == 'soft_delete' && !$request->is_set_post('delete_permanent')), $delete_reason); - return; -} - -// Handle bump mode... -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->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); - $message = $user->lang['TOPIC_BUMPED']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('VIEW_MESSAGE', '', ''); - $message .= '

' . $user->lang('RETURN_FORUM', '', ''); - } - - trigger_error($message); - } - - trigger_error('BUMP_ERROR'); -} - -// Subject length limiting to 60 characters if first post... -if ($mode == 'post' || ($mode == 'edit' && $post_data['topic_first_post_id'] == $post_data['post_id'])) -{ - $template->assign_var('S_NEW_MESSAGE', true); -} - -// Determine some vars -if (isset($post_data['poster_id']) && $post_data['poster_id'] == ANONYMOUS) -{ - $post_data['quote_username'] = (!empty($post_data['post_username'])) ? $post_data['post_username'] : $user->lang['GUEST']; -} -else -{ - $post_data['quote_username'] = isset($post_data['username']) ? $post_data['username'] : ''; -} - -$post_data['post_edit_locked'] = (isset($post_data['post_edit_locked'])) ? (int) $post_data['post_edit_locked'] : 0; -$post_data['post_subject_md5'] = (isset($post_data['post_subject']) && $mode == 'edit') ? md5($post_data['post_subject']) : ''; -$post_data['post_subject'] = (in_array($mode, array('quote', 'edit'))) ? $post_data['post_subject'] : ((isset($post_data['topic_title'])) ? $post_data['topic_title'] : ''); -$post_data['topic_time_limit'] = (isset($post_data['topic_time_limit'])) ? (($post_data['topic_time_limit']) ? (int) $post_data['topic_time_limit'] / 86400 : (int) $post_data['topic_time_limit']) : 0; -$post_data['poll_length'] = (!empty($post_data['poll_length'])) ? (int) $post_data['poll_length'] / 86400 : 0; -$post_data['poll_start'] = (!empty($post_data['poll_start'])) ? (int) $post_data['poll_start'] : 0; -$post_data['icon_id'] = (!isset($post_data['icon_id']) || in_array($mode, array('quote', 'reply'))) ? 0 : (int) $post_data['icon_id']; -$post_data['poll_options'] = array(); - -// Get Poll Data -if ($post_data['poll_start']) -{ - $sql = 'SELECT poll_option_text - FROM ' . POLL_OPTIONS_TABLE . " - WHERE topic_id = $topic_id - ORDER BY poll_option_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_data['poll_options'][] = trim($row['poll_option_text']); - } - $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( - 'poll_title' => $post_data['poll_title'], - 'poll_length' => $post_data['poll_length'], - 'poll_max_options' => $post_data['poll_max_options'], - 'poll_option_text' => implode("\n", $post_data['poll_options']), - 'poll_start' => $post_data['poll_start'], - 'poll_last_vote' => $post_data['poll_last_vote'], - 'poll_vote_change' => $post_data['poll_vote_change'], - ); -} - -$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); - -if (isset($post_data['post_text'])) -{ - $message_parser->message = &$post_data['post_text']; - unset($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])) - { - $post_data[$var_name] = $default_value; - } -} -unset($uninit); - -// Always check if the submitted attachment data is valid and belongs to the user. -// Further down (especially in submit_post()) we do not check this again. -$message_parser->get_submitted_attachment_data($post_data['poster_id']); - -if ($post_data['post_attachment'] && !$submit && !$refresh && !$preview && $mode == 'edit') -{ - // Do not change to SELECT * - $sql = 'SELECT attach_id, is_orphan, attach_comment, real_filename, filesize - FROM ' . ATTACHMENTS_TABLE . " - WHERE post_msg_id = $post_id - AND in_message = 0 - AND is_orphan = 0 - ORDER BY attach_id DESC"; - $result = $db->sql_query($sql); - $message_parser->attachment_data = array_merge($message_parser->attachment_data, $db->sql_fetchrowset($result)); - $db->sql_freeresult($result); -} - -if ($post_data['poster_id'] == ANONYMOUS) -{ - $post_data['username'] = ($mode == 'quote' || $mode == 'edit') ? trim($post_data['post_username']) : ''; -} -else -{ - $post_data['username'] = ($mode == 'quote' || $mode == 'edit') ? trim($post_data['username']) : ''; -} - -$post_data['enable_urls'] = $post_data['enable_magic_url']; - -if ($mode != 'edit') -{ - $post_data['enable_sig'] = ($config['allow_sig'] && $user->optionget('attachsig')) ? true: false; - $post_data['enable_smilies'] = ($config['allow_smilies'] && $user->optionget('smilies')) ? true : false; - $post_data['enable_bbcode'] = ($config['allow_bbcode'] && $user->optionget('bbcode')) ? true : false; - $post_data['enable_urls'] = true; -} - -if ($mode == 'post') -{ - $post_data['topic_status'] = ($request->is_set_post('lock_topic') && $auth->acl_gets('m_lock', 'f_user_lock', $forum_id)) ? ITEM_LOCKED : ITEM_UNLOCKED; -} - -$post_data['enable_magic_url'] = $post_data['drafts'] = false; - -// User own some drafts? -if ($user->data['is_registered'] && $auth->acl_get('u_savedrafts') && ($mode == 'reply' || $mode == 'post' || $mode == 'quote')) -{ - $sql = 'SELECT draft_id - FROM ' . DRAFTS_TABLE . ' - WHERE user_id = ' . $user->data['user_id'] . - (($forum_id) ? ' AND forum_id = ' . (int) $forum_id : '') . - (($topic_id) ? ' AND topic_id = ' . (int) $topic_id : '') . - (($draft_id) ? " AND draft_id <> $draft_id" : ''); - $result = $db->sql_query_limit($sql, 1); - - if ($db->sql_fetchrow($result)) - { - $post_data['drafts'] = true; - } - $db->sql_freeresult($result); -} - -$check_value = (($post_data['enable_bbcode']+1) << 8) + (($post_data['enable_smilies']+1) << 4) + (($post_data['enable_urls']+1) << 2) + (($post_data['enable_sig']+1) << 1); - -// Check if user is watching this topic -if ($mode != 'post' && $config['allow_topic_notify'] && $user->data['is_registered']) -{ - $sql = 'SELECT topic_id - FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . $topic_id . ' - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $post_data['notify_set'] = (int) $db->sql_fetchfield('topic_id'); - $db->sql_freeresult($result); -} - -// Do we want to edit our post ? -if ($mode == 'edit' && $post_data['bbcode_uid']) -{ - $message_parser->bbcode_uid = $post_data['bbcode_uid']; -} - -// HTML, BBCode, Smilies, Images and Flash status -$bbcode_status = ($config['allow_bbcode'] && $auth->acl_get('f_bbcode', $forum_id)) ? true : false; -$smilies_status = ($config['allow_smilies'] && $auth->acl_get('f_smilies', $forum_id)) ? true : false; -$img_status = ($bbcode_status && $auth->acl_get('f_img', $forum_id)) ? true : false; -$url_status = ($config['allow_post_links']) ? true : false; -$flash_status = ($bbcode_status && $auth->acl_get('f_flash', $forum_id) && $config['allow_post_flash']) ? true : false; -$quote_status = true; - -// Save Draft -if ($save && $user->data['is_registered'] && $auth->acl_get('u_savedrafts') && ($mode == 'reply' || $mode == 'post' || $mode == 'quote')) -{ - $subject = $request->variable('subject', '', true); - $subject = (!$subject && $mode != 'post') ? $post_data['topic_title'] : $subject; - $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_parser->message) - ); - $db->sql_query($sql); - - $meta_info = ($mode == 'post') ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) : append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id"); - - meta_refresh(3, $meta_info); - - $message = $user->lang['DRAFT_SAVED'] . '

'; - $message .= ($mode != 'post') ? sprintf($user->lang['RETURN_TOPIC'], '', '') . '

' : ''; - $message .= sprintf($user->lang['RETURN_FORUM'], '', ''); - - trigger_error($message); - } - else - { - $s_hidden_fields = build_hidden_fields(array( - 'mode' => $mode, - 'save' => true, - 'f' => $forum_id, - 't' => $topic_id, - 'subject' => $subject, - 'message' => $message, - 'attachment_data' => $message_parser->attachment_data, - ) - ); - - $hidden_fields = array( - 'icon_id' => 0, - - 'disable_bbcode' => false, - 'disable_smilies' => false, - 'disable_magic_url' => false, - 'attach_sig' => true, - 'lock_topic' => false, - - 'topic_type' => POST_NORMAL, - 'topic_time_limit' => 0, - - 'poll_title' => '', - 'poll_option_text' => '', - 'poll_max_options' => 1, - 'poll_length' => 0, - 'poll_vote_change' => false, - ); - - foreach ($hidden_fields as $name => $default) - { - if (!isset($_POST[$name])) - { - // Don't include it, if its not available - unset($hidden_fields[$name]); - continue; - } - - if (is_bool($default)) - { - // Use the string representation - $hidden_fields[$name] = $request->variable($name, ''); - } - else - { - $hidden_fields[$name] = $request->variable($name, $default); - } - } - - $s_hidden_fields .= build_hidden_fields($hidden_fields); - - confirm_box(false, 'SAVE_DRAFT', $s_hidden_fields); - } - } - else - { - if (utf8_clean_string($subject) === '') - { - $error[] = $user->lang['EMPTY_SUBJECT']; - } - - if (utf8_clean_string($message) === '') - { - $error[] = $user->lang['TOO_FEW_CHARS']; - } - } - unset($subject, $message); -} - -// Load requested Draft -if ($draft_id && ($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $user->data['is_registered'] && $auth->acl_get('u_savedrafts')) -{ - $sql = 'SELECT draft_subject, draft_message - FROM ' . DRAFTS_TABLE . " - WHERE draft_id = $draft_id - AND user_id = " . $user->data['user_id']; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $post_data['post_subject'] = $row['draft_subject']; - $message_parser->message = $row['draft_message']; - - $template->assign_var('S_DRAFT_LOADED', true); - } - else - { - $draft_id = 0; - } -} - -// Load draft overview -if ($load && ($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_data['drafts']) -{ - 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->variable('topic_cur_post_id', 0); - $post_data['post_subject'] = $request->variable('subject', '', true); - $message_parser->message = $request->variable('message', '', 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->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->variable('icon', (int) $post_data['icon_id']); - } - - $post_data['enable_bbcode'] = (!$bbcode_status || isset($_POST['disable_bbcode'])) ? false : true; - $post_data['enable_smilies'] = (!$smilies_status || isset($_POST['disable_smilies'])) ? false : true; - $post_data['enable_urls'] = (isset($_POST['disable_magic_url'])) ? 0 : 1; - $post_data['enable_sig'] = (!$config['allow_sig'] || !$auth->acl_get('f_sigs', $forum_id) || !$auth->acl_get('u_sig')) ? false : ((isset($_POST['attach_sig']) && $user->data['is_registered']) ? true : false); - - if ($config['allow_topic_notify'] && $user->data['is_registered']) - { - $notify = (isset($_POST['notify'])) ? true : false; - } - else - { - $notify = false; - } - - $topic_lock = (isset($_POST['lock_topic'])) ? true : false; - $post_lock = (isset($_POST['lock_post'])) ? true : false; - $poll_delete = (isset($_POST['poll_delete'])) ? true : false; - - if ($submit) - { - $status_switch = (($post_data['enable_bbcode']+1) << 8) + (($post_data['enable_smilies']+1) << 4) + (($post_data['enable_urls']+1) << 2) + (($post_data['enable_sig']+1) << 1); - $status_switch = ($status_switch != $check_value); - } - else - { - $status_switch = 1; - } - - // Delete Poll - 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')) - { - $sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . POLL_VOTES_TABLE . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - $topic_sql = array( - 'poll_title' => '', - 'poll_start' => 0, - 'poll_length' => 0, - 'poll_last_vote' => 0, - 'poll_max_options' => 0, - 'poll_vote_change' => 0 - ); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $topic_sql) . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - } - - $post_data['poll_title'] = $post_data['poll_option_text'] = ''; - $post_data['poll_vote_change'] = $post_data['poll_max_options'] = $post_data['poll_length'] = 0; - } - else - { - $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; - } - - // If replying/quoting and last post id has changed - // give user option to continue submit or return to post - // notify and show user the post made between his request and the final submit - if (($mode == 'reply' || $mode == 'quote') && $post_data['topic_cur_post_id'] && $post_data['topic_cur_post_id'] != $post_data['topic_last_post_id']) - { - // Only do so if it is allowed forum-wide - if ($post_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) - { - if (topic_review($topic_id, $forum_id, 'post_review', $post_data['topic_cur_post_id'])) - { - $template->assign_var('S_POST_REVIEW', true); - } - - $submit = false; - $refresh = true; - } - } - - // Parse Attachments - before checksum is calculated - 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 - * - * @event core.posting_modify_message_text - * @var array post_data Array with post data - * @var string mode What action to take if the form is submitted - * post|reply|quote|edit|delete|bump|smilies|popup - * @var int post_id ID of the post - * @var int topic_id ID of the topic - * @var int forum_id ID of the forum - * @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 - * @var bool load Whether or not a draft is being loaded - * @var bool cancel Whether or not to cancel the form (returns to - * viewtopic or viewforum depending on if the user - * is posting a new topic or editing a post) - * @var bool refresh Whether or not to retain previously submitted data - * @var object message_parser The message parser object - * @var array error Array of errors - * @since 3.1.2-RC1 - * @changed 3.1.11-RC1 Added error - */ - $vars = array( - 'post_data', - 'mode', - 'post_id', - 'topic_id', - 'forum_id', - 'submit', - 'preview', - 'save', - 'load', - 'cancel', - 'refresh', - 'message_parser', - 'error', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_message_text', compact($vars))); - - // Grab md5 'checksum' of new message - $message_md5 = md5($message_parser->message); - - // If editing and checksum has changed we know the post was edited while we're editing - // Notify and show user the changed post - if ($mode == 'edit' && $post_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) - { - $edit_post_message_checksum = $request->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 - // $edit_post_message_checksum is the checksum of the post we're editing - // ... - - // We make sure nobody else made exactly the same change - // we're about to submit by also checking $message_md5 != $post_data['post_checksum'] - if ($edit_post_message_checksum !== '' && - $edit_post_message_checksum != $post_data['post_checksum'] && - $message_md5 != $post_data['post_checksum'] - || - $edit_post_subject_checksum !== '' && - $edit_post_subject_checksum != $post_data['post_subject_md5'] && - md5($post_data['post_subject']) != $post_data['post_subject_md5']) - { - if (topic_review($topic_id, $forum_id, 'post_review_edit', $post_id)) - { - $template->assign_vars(array( - 'S_POST_REVIEW' => true, - - 'L_POST_REVIEW' => $user->lang['POST_REVIEW_EDIT'], - 'L_POST_REVIEW_EXPLAIN' => $user->lang['POST_REVIEW_EDIT_EXPLAIN'], - )); - } - - $submit = false; - $refresh = true; - } - } - - // Check checksum ... don't re-parse message if the same - $update_message = ($mode != 'edit' || $message_md5 != $post_data['post_checksum'] || $status_switch || strlen($post_data['bbcode_uid']) < BBCODE_UID_LEN) ? true : false; - - // Also check if subject got updated... - $update_subject = $mode != 'edit' || ($post_data['post_subject_md5'] && $post_data['post_subject_md5'] != md5($post_data['post_subject'])); - - // Parse message - if ($update_message) - { - if (count($message_parser->warn_msg)) - { - $error[] = implode('
', $message_parser->warn_msg); - $message_parser->warn_msg = array(); - } - - if (!$preview || !empty($message_parser->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']); - } - - // On a refresh we do not care about message parsing errors - if (count($message_parser->warn_msg) && $refresh && !$preview) - { - $message_parser->warn_msg = array(); - } - } - else - { - $message_parser->bbcode_bitfield = $post_data['bbcode_bitfield']; - } - - $ignore_flood = $auth->acl_get('u_ignoreflood') ? true : $auth->acl_get('f_ignoreflood', $forum_id); - if ($mode != 'edit' && !$preview && !$refresh && $config['flood_interval'] && !$ignore_flood) - { - // Flood check - $last_post_time = 0; - - if ($user->data['is_registered']) - { - $last_post_time = $user->data['user_lastpost_time']; - } - else - { - $sql = 'SELECT post_time AS last_post_time - FROM ' . POSTS_TABLE . " - WHERE poster_ip = '" . $user->ip . "' - AND post_time > " . ($current_time - $config['flood_interval']); - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) - { - $last_post_time = $row['last_post_time']; - } - $db->sql_freeresult($result); - } - - if ($last_post_time && ($current_time - $last_post_time) < intval($config['flood_interval'])) - { - $error[] = $user->lang['FLOOD_ERROR']; - } - } - - // Validate username - if (($post_data['username'] && !$user->data['is_registered']) || ($mode == 'edit' && $post_data['poster_id'] == ANONYMOUS && $post_data['username'] && $post_data['post_username'] && $post_data['post_username'] != $post_data['username'])) - { - if (!function_exists('validate_username')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $user->add_lang('ucp'); - - if (($result = validate_username($post_data['username'], (!empty($post_data['post_username'])) ? $post_data['post_username'] : '')) !== false) - { - $error[] = $user->lang[$result . '_USERNAME']; - } - - if (($result = validate_string($post_data['username'], false, $config['min_name_chars'], $config['max_name_chars'])) !== false) - { - $min_max_amount = ($result == 'TOO_SHORT') ? $config['min_name_chars'] : $config['max_name_chars']; - $error[] = $user->lang('FIELD_' . $result, $min_max_amount, $user->lang['USERNAME']); - } - } - - if ($config['enable_post_confirm'] && !$user->data['is_registered'] && in_array($mode, array('quote', 'post', 'reply'))) - { - $captcha_data = array( - 'message' => $request->variable('message', '', true), - 'subject' => $request->variable('subject', '', true), - 'username' => $request->variable('username', '', true), - ); - $vc_response = $captcha->validate($captcha_data); - if ($vc_response) - { - $error[] = $vc_response; - } - } - - // check form - if (($submit || $preview) && !check_form_key('posting')) - { - $error[] = $user->lang['FORM_INVALID']; - } - - if ($submit && $mode == 'edit' && $post_data['post_visibility'] == ITEM_DELETED && !isset($_POST['soft_delete']) && $auth->acl_get('m_approve', $forum_id)) - { - $is_first_post = ($post_id == $post_data['topic_first_post_id'] || !$post_data['topic_posts_approved']); - $is_last_post = ($post_id == $post_data['topic_last_post_id'] || !$post_data['topic_posts_approved']); - $updated_post_data = $phpbb_content_visibility->set_post_visibility(ITEM_APPROVED, $post_id, $post_data['topic_id'], $post_data['forum_id'], $user->data['user_id'], time(), '', $is_first_post, $is_last_post); - - if (!empty($updated_post_data)) - { - // Update the post_data, so we don't need to refetch it. - $post_data = array_merge($post_data, $updated_post_data); - } - } - - // Parse subject - if (!$preview && !$refresh && utf8_clean_string($post_data['post_subject']) === '' && ($mode == 'post' || ($mode == 'edit' && $post_data['topic_first_post_id'] == $post_id))) - { - $error[] = $user->lang['EMPTY_SUBJECT']; - } - - /** - * 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')) - { - $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('
', $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; - - if ($post_data['poll_option_text'] && - ($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_post_id']/* && (!$post_data['poll_last_vote'] || $auth->acl_get('m_edit', $forum_id))*/)) - && $auth->acl_get('f_poll', $forum_id)) - { - $poll = array( - 'poll_title' => $post_data['poll_title'], - 'poll_length' => $post_data['poll_length'], - 'poll_max_options' => $post_data['poll_max_options'], - 'poll_option_text' => $post_data['poll_option_text'], - 'poll_start' => $post_data['poll_start'], - 'poll_last_vote' => $post_data['poll_last_vote'], - 'poll_vote_change' => $post_data['poll_vote_change'], - 'enable_bbcode' => $post_data['enable_bbcode'], - 'enable_urls' => $post_data['enable_urls'], - 'enable_smilies' => $post_data['enable_smilies'], - 'img_status' => $img_status - ); - - $message_parser->parse_poll($poll); - - $post_data['poll_options'] = (isset($poll['poll_options'])) ? $poll['poll_options'] : array(); - $post_data['poll_title'] = (isset($poll['poll_title'])) ? $poll['poll_title'] : ''; - - /* We reset votes, therefore also allow removing options - if ($post_data['poll_last_vote'] && ($poll['poll_options_size'] < $orig_poll_options_size)) - { - $message_parser->warn_msg[] = $user->lang['NO_DELETE_POLL_OPTIONS']; - }*/ - } - else if ($mode == 'edit' && $post_id == $post_data['topic_first_post_id'] && $auth->acl_get('f_poll', $forum_id)) - { - // The user removed all poll options, this is equal to deleting the poll. - $poll = array( - 'poll_title' => '', - 'poll_length' => 0, - 'poll_max_options' => 0, - 'poll_option_text' => '', - 'poll_start' => 0, - 'poll_last_vote' => 0, - 'poll_vote_change' => 0, - 'poll_options' => array(), - ); - - $post_data['poll_options'] = array(); - $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']) && !$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'], - 'enable_smilies' => $post_data['enable_smilies'], - 'img_status' => $img_status, - )); - - $message_parser->parse_poll($poll); - - $post_data['poll_options'] = (isset($poll['poll_options'])) ? $poll['poll_options'] : array(); - $post_data['poll_title'] = (isset($poll['poll_title'])) ? $poll['poll_title'] : ''; - } - else - { - $poll = array(); - } - - // Check topic type - if ($post_data['topic_type'] != POST_NORMAL && ($mode == 'post' || ($mode == 'edit' && $post_data['topic_first_post_id'] == $post_id))) - { - switch ($post_data['topic_type']) - { - case POST_GLOBAL: - $auth_option = 'f_announce_global'; - break; - - case POST_ANNOUNCE: - $auth_option = 'f_announce'; - break; - - case POST_STICKY: - $auth_option = 'f_sticky'; - break; - - default: - $auth_option = ''; - break; - } - - if ($auth_option != '' && !$auth->acl_get($auth_option, $forum_id)) - { - // There is a special case where a user edits his post whereby the topic type got changed by an admin/mod. - // Another case would be a mod not having sticky permissions for example but edit permissions. - if ($mode == 'edit') - { - // To prevent non-authed users messing around with the topic type we reset it to the original one. - $post_data['topic_type'] = $post_data['orig_topic_type']; - } - else - { - $error[] = $user->lang['CANNOT_POST_' . str_replace('F_', '', strtoupper($auth_option))]; - } - } - } - - if (count($message_parser->warn_msg)) - { - $error[] = implode('
', $message_parser->warn_msg); - } - - // DNSBL check - if ($config['check_dnsbl'] && !$refresh) - { - if (($dnsbl = $user->check_dnsbl('post')) !== false) - { - $error[] = sprintf($user->lang['IP_BLACKLISTED'], $user->ip, $dnsbl[1]); - } - } - - /** - * This event allows you to define errors before the post action is performed - * - * @event core.posting_modify_submission_errors - * @var array post_data Array with post data - * @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 int post_id ID of the post - * @var int topic_id ID of the topic - * @var int forum_id ID of the forum - * @var bool submit Whether or not the form has been submitted - * @var array error Any error strings; a non-empty array aborts form submission. - * 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', - 'post_id', - 'topic_id', - 'forum_id', - 'submit', - 'error', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_submission_errors', compact($vars))); - - // Store message, sync counters - if (!count($error) && $submit) - { - if ($submit) - { - // Lock/Unlock Topic - $change_topic_status = $post_data['topic_status']; - $perm_lock_unlock = ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && !empty($post_data['topic_poster']) && $user->data['user_id'] == $post_data['topic_poster'] && $post_data['topic_status'] == ITEM_UNLOCKED)) ? true : false; - - if ($post_data['topic_status'] == ITEM_LOCKED && !$topic_lock && $perm_lock_unlock) - { - $change_topic_status = ITEM_UNLOCKED; - } - else if ($post_data['topic_status'] == ITEM_UNLOCKED && $topic_lock && $perm_lock_unlock) - { - $change_topic_status = ITEM_LOCKED; - } - - if ($change_topic_status != $post_data['topic_status']) - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_status = $change_topic_status - WHERE topic_id = $topic_id - AND topic_moved_id = 0"; - $db->sql_query($sql); - - $user_lock = ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $post_data['topic_poster']) ? 'USER_' : ''; - - $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 - if ($mode == 'edit' && $post_data['post_edit_locked'] == ITEM_LOCKED && !$post_lock && $auth->acl_get('m_edit', $forum_id)) - { - $post_data['post_edit_locked'] = ITEM_UNLOCKED; - } - else if ($mode == 'edit' && $post_data['post_edit_locked'] == ITEM_UNLOCKED && $post_lock && $auth->acl_get('m_edit', $forum_id)) - { - $post_data['post_edit_locked'] = ITEM_LOCKED; - } - - $data = array( - 'topic_title' => (empty($post_data['topic_title'])) ? $post_data['post_subject'] : $post_data['topic_title'], - 'topic_first_post_id' => (isset($post_data['topic_first_post_id'])) ? (int) $post_data['topic_first_post_id'] : 0, - 'topic_last_post_id' => (isset($post_data['topic_last_post_id'])) ? (int) $post_data['topic_last_post_id'] : 0, - 'topic_time_limit' => (int) $post_data['topic_time_limit'], - 'topic_attachment' => (isset($post_data['topic_attachment'])) ? (int) $post_data['topic_attachment'] : 0, - 'post_id' => (int) $post_id, - 'topic_id' => (int) $topic_id, - 'forum_id' => (int) $forum_id, - 'icon_id' => (int) $post_data['icon_id'], - 'poster_id' => (int) $post_data['poster_id'], - 'enable_sig' => (bool) $post_data['enable_sig'], - 'enable_bbcode' => (bool) $post_data['enable_bbcode'], - 'enable_smilies' => (bool) $post_data['enable_smilies'], - 'enable_urls' => (bool) $post_data['enable_urls'], - 'enable_indexing' => (bool) $post_data['enable_indexing'], - 'message_md5' => (string) $message_md5, - 'post_checksum' => (isset($post_data['post_checksum'])) ? (string) $post_data['post_checksum'] : '', - 'post_edit_reason' => $post_data['post_edit_reason'], - 'post_edit_user' => ($mode == 'edit') ? $user->data['user_id'] : ((isset($post_data['post_edit_user'])) ? (int) $post_data['post_edit_user'] : 0), - 'forum_parents' => $post_data['forum_parents'], - 'forum_name' => $post_data['forum_name'], - 'notify' => $notify, - 'notify_set' => $post_data['notify_set'], - 'poster_ip' => (isset($post_data['poster_ip'])) ? $post_data['poster_ip'] : $user->ip, - 'post_edit_locked' => (int) $post_data['post_edit_locked'], - 'bbcode_bitfield' => $message_parser->bbcode_bitfield, - 'bbcode_uid' => $message_parser->bbcode_uid, - 'message' => $message_parser->message, - 'attachment_data' => $message_parser->attachment_data, - 'filename_data' => $message_parser->filename_data, - 'topic_status' => $post_data['topic_status'], - - 'topic_visibility' => (isset($post_data['topic_visibility'])) ? $post_data['topic_visibility'] : false, - 'post_visibility' => (isset($post_data['post_visibility'])) ? $post_data['post_visibility'] : false, - ); - - if ($mode == 'edit') - { - $data['topic_posts_approved'] = $post_data['topic_posts_approved']; - $data['topic_posts_unapproved'] = $post_data['topic_posts_unapproved']; - $data['topic_posts_softdeleted'] = $post_data['topic_posts_softdeleted']; - } - - // Only return the username when it is either a guest posting or we are editing a post and - // the username was supplied; otherwise post_data might hold the data of the post that is - // being quoted (which could result in the username being returned being that of the quoted - // post's poster, not the poster of the current post). See: PHPBB3-11769 for more information. - $post_author_name = ((!$user->data['is_registered'] || $mode == 'edit') && $post_data['username'] !== '') ? $post_data['username'] : ''; - - /** - * This event allows you to define errors before the post action is performed - * - * @event core.posting_modify_submit_post_before - * @var array post_data Array with post data - * @var array poll Array with poll data - * @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 int post_id ID of the post - * @var int topic_id ID of the topic - * @var int forum_id ID of the forum - * @var string post_author_name Author name for guest posts - * @var bool update_message Boolean if the post message was changed - * @var bool update_subject Boolean if the post subject was changed - * 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', - 'post_id', - 'topic_id', - 'forum_id', - 'post_author_name', - 'update_message', - 'update_subject', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_submit_post_before', compact($vars))); - - // The last parameter tells submit_post if search indexer has to be run - $redirect_url = submit_post($mode, $post_data['post_subject'], $post_author_name, $post_data['topic_type'], $poll, $data, $update_message, ($update_message || $update_subject) ? true : false); - - /** - * This event allows you to define errors after the post action is performed - * - * @event core.posting_modify_submit_post_after - * @var array post_data Array with post data - * @var array poll Array with poll data - * @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 int post_id ID of the post - * @var int topic_id ID of the topic - * @var int forum_id ID of the forum - * @var string post_author_name Author name for guest posts - * @var bool update_message Boolean if the post message was changed - * @var bool update_subject Boolean if the post subject was changed - * @var string redirect_url URL the user is going to be redirected to - * 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', - 'post_id', - 'topic_id', - 'forum_id', - 'post_author_name', - 'update_message', - 'update_subject', - 'redirect_url', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_submit_post_after', compact($vars))); - - if ($config['enable_post_confirm'] && !$user->data['is_registered'] && (isset($captcha) && $captcha->is_solved() === true) && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) - { - $captcha->reset(); - } - - // Handle delete mode... - if ($request->is_set_post('delete') || $request->is_set_post('delete_permanent')) - { - $delete_reason = $request->variable('delete_reason', '', true); - phpbb_handle_post_delete($forum_id, $topic_id, $post_id, $post_data, !$request->is_set_post('delete_permanent'), $delete_reason); - return; - } - - // Check the permissions for post approval. - // Moderators must go through post approval like ordinary users. - if ((!$auth->acl_get('f_noapprove', $data['forum_id']) && empty($data['force_approved_state'])) || (isset($data['force_approved_state']) && !$data['force_approved_state'])) - { - meta_refresh(10, $redirect_url); - $message = ($mode == 'edit') ? $user->lang['POST_EDITED_MOD'] : $user->lang['POST_STORED_MOD']; - $message .= (($user->data['user_id'] == ANONYMOUS) ? '' : ' '. $user->lang['POST_APPROVAL_NOTIFY']); - $message .= '

' . sprintf($user->lang['RETURN_FORUM'], '', ''); - trigger_error($message); - } - - redirect($redirect_url); - } - } -} - -// Preview -if (!count($error) && $preview) -{ - $post_data['post_time'] = ($mode == 'edit') ? $post_data['post_time'] : $current_time; - - $preview_message = $message_parser->format_display($post_data['enable_bbcode'], $post_data['enable_urls'], $post_data['enable_smilies'], false); - - $preview_signature = ($mode == 'edit') ? $post_data['user_sig'] : $user->data['user_sig']; - $preview_signature_uid = ($mode == 'edit') ? $post_data['user_sig_bbcode_uid'] : $user->data['user_sig_bbcode_uid']; - $preview_signature_bitfield = ($mode == 'edit') ? $post_data['user_sig_bbcode_bitfield'] : $user->data['user_sig_bbcode_bitfield']; - - // Signature - if ($post_data['enable_sig'] && $config['allow_sig'] && $preview_signature && $auth->acl_get('f_sigs', $forum_id)) - { - $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 - { - $preview_signature = ''; - } - - $preview_subject = censor_text($post_data['post_subject']); - - // Poll Preview - if (!$poll_delete && ($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_post_id']/* && (!$post_data['poll_last_vote'] || $auth->acl_get('m_edit', $forum_id))*/)) - && $auth->acl_get('f_poll', $forum_id)) - { - $parse_poll = new parse_message($post_data['poll_title']); - $parse_poll->bbcode_uid = $message_parser->bbcode_uid; - $parse_poll->bbcode_bitfield = $message_parser->bbcode_bitfield; - - $parse_poll->format_display($post_data['enable_bbcode'], $post_data['enable_urls'], $post_data['enable_smilies']); - - if ($post_data['poll_length']) - { - $poll_end = ($post_data['poll_length'] * 86400) + (($post_data['poll_start']) ? $post_data['poll_start'] : time()); - } - - $template->assign_vars(array( - '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, - - 'L_POLL_LENGTH' => ($post_data['poll_length']) ? sprintf($user->lang['POLL_RUN_TILL'], $user->format_date($poll_end)) : '', - 'L_MAX_VOTES' => $user->lang('MAX_OPTIONS_SELECT', (int) $post_data['poll_max_options']), - )); - - $preview_poll_options = array(); - foreach ($post_data['poll_options'] as $poll_option) - { - $parse_poll->message = $poll_option; - $parse_poll->format_display($post_data['enable_bbcode'], $post_data['enable_urls'], $post_data['enable_smilies']); - $preview_poll_options[] = $parse_poll->message; - } - unset($parse_poll); - - foreach ($preview_poll_options as $key => $option) - { - $template->assign_block_vars('poll_option', array( - 'POLL_OPTION_CAPTION' => $option, - 'POLL_OPTION_ID' => $key + 1) - ); - } - unset($preview_poll_options); - } - - // Attachment Preview - if (count($message_parser->attachment_data)) - { - $template->assign_var('S_HAS_ATTACHMENTS', true); - - $update_count = array(); - $attachment_data = $message_parser->attachment_data; - - parse_attachments($forum_id, $preview_message, $attachment_data, $update_count, true); - - foreach ($attachment_data as $i => $attachment) - { - $template->assign_block_vars('attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - unset($attachment_data); - } - - if (!count($error)) - { - $template->assign_vars(array( - 'PREVIEW_SUBJECT' => $preview_subject, - 'PREVIEW_MESSAGE' => $preview_message, - 'PREVIEW_SIGNATURE' => $preview_signature, - - 'S_DISPLAY_PREVIEW' => !empty($preview_message), - )); - } -} - -// Remove quotes that would become nested too deep before decoding the text -$generate_quote = ($mode == 'quote' && !$submit && !$preview && !$refresh); -if ($generate_quote && $config['max_quote_depth'] > 0) -{ - $tmp_bbcode_uid = $message_parser->bbcode_uid; - $message_parser->bbcode_uid = $post_data['bbcode_uid']; - $message_parser->remove_nested_quotes($config['max_quote_depth'] - 1); - $message_parser->bbcode_uid = $tmp_bbcode_uid; -} - -// Decode text for message display -$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) -{ - // 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); - - $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'], - ); - - /** - * 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 (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']; - - $message_parser->decode_message(); - $post_data['poll_title'] = $message_parser->message; - - $message_parser->message = implode("\n", $post_data['poll_options']); - $message_parser->decode_message(); - $post_data['poll_options'] = explode("\n", $message_parser->message); -} - -// MAIN POSTING PAGE BEGINS HERE - -// Forum moderators? -$moderators = array(); -if ($config['load_moderators']) -{ - get_moderators($moderators, $forum_id); -} - -// Generate smiley listing -generate_smilies('inline', $forum_id); - -// Generate inline attachment select box -posting_gen_inline_attachments($attachment_data); - -// Do show topic type selection only in first post. -$topic_type_toggle = false; - -if ($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_post_id'])) -{ - $topic_type_toggle = posting_gen_topic_types($forum_id, $post_data['topic_type']); -} - -$s_topic_icons = false; -if ($post_data['enable_icons'] && $auth->acl_get('f_icons', $forum_id)) -{ - $s_topic_icons = posting_gen_topic_icons($mode, $post_data['icon_id']); -} - -$bbcode_checked = (isset($post_data['enable_bbcode'])) ? !$post_data['enable_bbcode'] : (($config['allow_bbcode']) ? !$user->optionget('bbcode') : 1); -$smilies_checked = (isset($post_data['enable_smilies'])) ? !$post_data['enable_smilies'] : (($config['allow_smilies']) ? !$user->optionget('smilies') : 1); -$urls_checked = (isset($post_data['enable_urls'])) ? !$post_data['enable_urls'] : 0; -$sig_checked = $post_data['enable_sig']; -$lock_topic_checked = (isset($topic_lock) && $topic_lock) ? $topic_lock : (($post_data['topic_status'] == ITEM_LOCKED) ? 1 : 0); -$lock_post_checked = (isset($post_lock)) ? $post_lock : $post_data['post_edit_locked']; - -// If the user is replying or posting and not already watching this topic but set to always being notified we need to overwrite this setting -$notify_set = ($mode != 'edit' && $config['allow_topic_notify'] && $user->data['is_registered'] && !$post_data['notify_set']) ? $user->data['user_notify'] : $post_data['notify_set']; -$notify_checked = (isset($notify)) ? $notify : (($mode == 'post') ? $user->data['user_notify'] : $notify_set); - -// Page title & action URL -$s_action = append_sid("{$phpbb_root_path}posting.$phpEx", "mode=$mode&f=$forum_id"); -$s_action .= ($topic_id) ? "&t=$topic_id" : ''; -$s_action .= ($post_id) ? "&p=$post_id" : ''; - -switch ($mode) -{ - case 'post': - $page_title = $user->lang['POST_TOPIC']; - break; - - case 'quote': - case 'reply': - $page_title = $user->lang['POST_REPLY']; - break; - - case 'delete': - case 'edit': - $page_title = $user->lang['EDIT_POST']; - break; -} - -// Build Navigation Links -generate_forum_nav($post_data); - -// Build Forum Rules -generate_forum_rules($post_data); - -// Posting uses is_solved for legacy reasons. Plugins have to use is_solved to force themselves to be displayed. -if ($config['enable_post_confirm'] && !$user->data['is_registered'] && (isset($captcha) && $captcha->is_solved() === false) && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) -{ - - $template->assign_vars(array( - 'S_CONFIRM_CODE' => true, - 'CAPTCHA_TEMPLATE' => $captcha->get_template(), - )); -} - -$s_hidden_fields = ($mode == 'reply' || $mode == 'quote') ? '' : ''; -$s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '' : ''; - -if ($mode == 'edit') -{ - $s_hidden_fields .= build_hidden_fields(array( - 'edit_post_message_checksum' => $post_data['post_checksum'], - 'edit_post_subject_checksum' => $post_data['post_subject_md5'], - )); -} - -// Add the confirm id/code pair to the hidden fields, else an error is displayed on next submit/preview -if (isset($captcha) && $captcha->is_solved() !== false) -{ - $s_hidden_fields .= build_hidden_fields($captcha->get_hidden_fields()); -} - -$form_enctype = (@ini_get('file_uploads') == '0' || strtolower(@ini_get('file_uploads')) == 'off' || !$config['allow_attachments'] || !$auth->acl_get('u_attach') || !$auth->acl_get('f_attach', $forum_id)) ? '' : ' enctype="multipart/form-data"'; -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( - 'L_POST_A' => $page_title, - 'L_ICON' => ($mode == 'reply' || $mode == 'quote' || ($mode == 'edit' && $post_id != $post_data['topic_first_post_id'])) ? $user->lang['POST_ICON'] : $user->lang['TOPIC_ICON'], - 'L_MESSAGE_BODY_EXPLAIN' => $user->lang('MESSAGE_BODY_EXPLAIN', (int) $config['max_post_chars']), - 'L_DELETE_POST_PERMANENTLY' => $user->lang('DELETE_POST_PERMANENTLY', 1), - - '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' => (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' => $user->lang(($bbcode_status ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '', ''), - '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' => ($bbcode_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['POST']), - 'POST_DATE' => ($post_data['post_time']) ? $user->format_date($post_data['post_time']) : '', - 'ERROR' => (count($error)) ? implode('
', $error) : '', - 'TOPIC_TIME_LIMIT' => (int) $post_data['topic_time_limit'], - 'EDIT_REASON' => $request->variable('edit_reason', '', true), - 'SHOW_PANEL' => $request->variable('show_panel', ''), - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id"), - 'U_VIEW_TOPIC' => ($mode != 'post') ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id") : '', - 'U_PROGRESS_BAR' => append_sid("{$phpbb_root_path}posting.$phpEx", "f=$forum_id&mode=popup"), - 'UA_PROGRESS_BAR' => addslashes(append_sid("{$phpbb_root_path}posting.$phpEx", "f=$forum_id&mode=popup")), - - 'S_PRIVMSGS' => false, - 'S_CLOSE_PROGRESS_WINDOW' => (isset($_POST['add_file'])) ? true : false, - 'S_EDIT_POST' => ($mode == 'edit') ? true : false, - 'S_EDIT_REASON' => ($mode == 'edit' && $auth->acl_get('m_edit', $forum_id)) ? true : false, - 'S_DISPLAY_USERNAME' => (!$user->data['is_registered'] || ($mode == 'edit' && $post_data['poster_id'] == ANONYMOUS)) ? true : false, - 'S_SHOW_TOPIC_ICONS' => $s_topic_icons, - 'S_DELETE_ALLOWED' => ($mode == 'edit' && (($post_id == $post_data['topic_last_post_id'] && $post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time'])) || $auth->acl_get('m_delete', $forum_id))) ? true : false, - 'S_BBCODE_ALLOWED' => ($bbcode_status) ? 1 : 0, - 'S_BBCODE_CHECKED' => ($bbcode_checked) ? ' checked="checked"' : '', - 'S_SMILIES_ALLOWED' => $smilies_status, - 'S_SMILIES_CHECKED' => ($smilies_checked) ? ' checked="checked"' : '', - 'S_SIG_ALLOWED' => ($auth->acl_get('f_sigs', $forum_id) && $config['allow_sig'] && $user->data['is_registered']) ? true : false, - 'S_SIGNATURE_CHECKED' => ($sig_checked) ? ' checked="checked"' : '', - 'S_NOTIFY_ALLOWED' => (!$user->data['is_registered'] || ($mode == 'edit' && $user->data['user_id'] != $post_data['poster_id']) || !$config['allow_topic_notify'] || !$config['email_enable']) ? false : true, - 'S_NOTIFY_CHECKED' => ($notify_checked) ? ' checked="checked"' : '', - 'S_LOCK_TOPIC_ALLOWED' => (($mode == 'edit' || $mode == 'reply' || $mode == 'quote' || $mode == 'post') && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && !empty($post_data['topic_poster']) && $user->data['user_id'] == $post_data['topic_poster'] && $post_data['topic_status'] == ITEM_UNLOCKED))) ? true : false, - 'S_LOCK_TOPIC_CHECKED' => ($lock_topic_checked) ? ' checked="checked"' : '', - 'S_LOCK_POST_ALLOWED' => ($mode == 'edit' && $auth->acl_get('m_edit', $forum_id)) ? true : false, - 'S_LOCK_POST_CHECKED' => ($lock_post_checked) ? ' checked="checked"' : '', - 'S_SOFTDELETE_CHECKED' => ($mode == 'edit' && $post_data['post_visibility'] == ITEM_DELETED) ? ' checked="checked"' : '', - 'S_SOFTDELETE_ALLOWED' => ($mode == 'edit' && $phpbb_content_visibility->can_soft_delete($forum_id, $post_data['poster_id'], $lock_post_checked)) ? true : false, - 'S_RESTORE_ALLOWED' => $auth->acl_get('m_approve', $forum_id), - 'S_IS_DELETED' => ($mode == 'edit' && $post_data['post_visibility'] == ITEM_DELETED) ? true : false, - 'S_LINKS_ALLOWED' => $url_status, - 'S_MAGIC_URL_CHECKED' => ($urls_checked) ? ' checked="checked"' : '', - 'S_TYPE_TOGGLE' => $topic_type_toggle, - 'S_SAVE_ALLOWED' => ($auth->acl_get('u_savedrafts') && $user->data['is_registered'] && $mode != 'edit') ? true : false, - 'S_HAS_DRAFTS' => ($auth->acl_get('u_savedrafts') && $user->data['is_registered'] && $post_data['drafts']) ? true : false, - 'S_FORM_ENCTYPE' => $form_enctype, - - 'S_BBCODE_IMG' => $img_status, - 'S_BBCODE_URL' => $url_status, - 'S_BBCODE_FLASH' => $flash_status, - 'S_BBCODE_QUOTE' => $quote_status, - - 'S_POST_ACTION' => $s_action, - 'S_HIDDEN_FIELDS' => $s_hidden_fields, - 'S_ATTACH_DATA' => json_encode($message_parser->attachment_data), - 'S_IN_POSTING' => true, -); - -// Build custom bbcodes array -display_custom_bbcodes(); - -// Poll entry -if (($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_post_id']/* && (!$post_data['poll_last_vote'] || $auth->acl_get('m_edit', $forum_id))*/)) - && $auth->acl_get('f_poll', $forum_id)) -{ - $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' && 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']), - - 'VOTE_CHANGE_CHECKED' => (!empty($post_data['poll_vote_change'])) ? ' checked="checked"' : '', - 'POLL_TITLE' => (isset($post_data['poll_title'])) ? $post_data['poll_title'] : '', - 'POLL_OPTIONS' => (!empty($post_data['poll_options'])) ? implode("\n", $post_data['poll_options']) : '', - 'POLL_MAX_OPTIONS' => (isset($post_data['poll_max_options'])) ? (int) $post_data['poll_max_options'] : 1, - 'POLL_LENGTH' => $post_data['poll_length'], - ) - ); -} - -/** -* This event allows you to modify template variables for the posting screen -* -* @event core.posting_modify_template_vars -* @var array post_data Array with post data -* @var array moderators Array with forum moderators -* @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 bool s_topic_icons Whether or not to show the topic icons -* @var string form_enctype If attachments are allowed for this form -* "multipart/form-data" or empty string -* @var string s_action The URL to submit the POST data to -* @var string s_hidden_fields Concatenated hidden input tags of posting form -* @var int post_id ID of the post -* @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 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 -* @var bool load Whether or not a draft is being loaded -* @var bool cancel Whether or not to cancel the form (returns to -* viewtopic or viewforum depending on if the user -* is posting a new topic or editing a post) -* @var array error Any error strings; a non-empty array aborts -* form submission. -* NOTE: Should be actual language strings, NOT -* language keys. -* @var bool refresh Whether or not to retain previously submitted data -* @var array page_data Posting page data that should be passed to the -* posting page via $template->assign_vars() -* @var object message_parser The message parser object -* @since 3.1.0-a1 -* @changed 3.1.0-b3 Added vars post_data, moderators, mode, page_title, -* s_topic_icons, form_enctype, s_action, s_hidden_fields, -* post_id, topic_id, forum_id, submit, preview, save, load, -* delete, cancel, refresh, error, page_data, message_parser -* @changed 3.1.2-RC1 Removed 'delete' var as it does not exist -* @changed 3.1.5-RC1 Added poll variables to the page_data array -* @changed 3.1.6-RC1 Added 'draft_id' var -*/ -$vars = array( - 'post_data', - 'moderators', - 'mode', - 'page_title', - 's_topic_icons', - 'form_enctype', - 's_action', - 's_hidden_fields', - 'post_id', - 'topic_id', - 'forum_id', - 'draft_id', - 'submit', - 'preview', - 'save', - 'load', - 'cancel', - 'refresh', - 'error', - 'page_data', - 'message_parser', -); -extract($phpbb_dispatcher->trigger_event('core.posting_modify_template_vars', compact($vars))); - -// Start assigning vars for main posting page ... -$template->assign_vars($page_data); - -// Show attachment box for adding attachments if true -$allowed = ($auth->acl_get('f_attach', $forum_id) && $auth->acl_get('u_attach') && $config['allow_attachments'] && $form_enctype); - -if ($allowed) -{ - $max_files = ($auth->acl_get('a_') || $auth->acl_get('m_', $forum_id)) ? 0 : (int) $config['max_attachments']; - $plupload->configure($cache, $template, $s_action, $forum_id, $max_files); -} - -// Attachment entry -posting_gen_attachment_entry($attachment_data, $filename_data, $allowed); - -// Output page ... -page_header($page_title); - -$template->set_filenames(array( - 'body' => 'posting_body.html') -); - -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - -// Topic review -if ($mode == 'reply' || $mode == 'quote') -{ - if (topic_review($topic_id, $forum_id)) - { - $template->assign_var('S_DISPLAY_REVIEW', true); - } -} - -page_footer(); diff --git a/install/update/new/report.php b/install/update/new/report.php deleted file mode 100644 index d0d7b37..0000000 --- a/install/update/new/report.php +++ /dev/null @@ -1,41 +0,0 @@ - -* @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\HttpFoundation\RedirectResponse; - -/** -* @ignore -*/ -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); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); - -$post_id = $request->variable('p', 0); -$pm_id = $request->variable('pm', 0); - -$redirect_route_name = ($pm_id === 0) ? 'phpbb_report_post_controller' : 'phpbb_report_pm_controller'; - -/** @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, - ), false), - 301 -); -$response->send(); diff --git a/install/update/new/search.php b/install/update/new/search.php deleted file mode 100644 index 5d5e9f5..0000000 --- a/install/update/new/search.php +++ /dev/null @@ -1,1569 +0,0 @@ - -* @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); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -include($phpbb_root_path . 'common.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup('search'); - -// Define initial vars -$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->variable('terms', 'all'); -$search_fields = $request->variable('sf', 'all'); -$search_child = $request->variable('sc', true); - -$sort_days = $request->variable('st', 0); -$sort_key = $request->variable('sk', 't'); -$sort_dir = $request->variable('sd', 'd'); - -$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 - -switch ($search_id) -{ - // Egosearch is an author search - case 'egosearch': - $author_id = $user->data['user_id']; - if ($user->data['user_id'] == ANONYMOUS) - { - login_box('', $user->lang['LOGIN_EXPLAIN_EGOSEARCH']); - } - break; - - // Search for unread posts needs to be allowed and user to be logged in if topics tracking for guests is disabled - case 'unreadposts': - if (!$config['load_unreads_search']) - { - $template->assign_var('S_NO_SEARCH', true); - trigger_error('NO_SEARCH_UNREADS'); - } - else if (!$config['load_anon_lastread'] && !$user->data['is_registered']) - { - login_box('', $user->lang['LOGIN_EXPLAIN_UNREADSEARCH']); - } - break; - - // The "new posts" search uses user_lastvisit which is user based, so it should require user to log in. - case 'newposts': - if ($user->data['user_id'] == ANONYMOUS) - { - login_box('', $user->lang['LOGIN_EXPLAIN_NEWPOSTS']); - } - break; - - default: - // There's nothing to do here for now ;) - break; -} - -// Is user able to search? Has search been disabled? -if (!$auth->acl_get('u_search') || !$auth->acl_getf_global('f_search') || !$config['load_search']) -{ - $template->assign_var('S_NO_SEARCH', true); - trigger_error('NO_SEARCH'); -} - -// Check search load limit -if ($user->load && $config['limit_search_load'] && ($user->load > doubleval($config['limit_search_load']))) -{ - $template->assign_var('S_NO_SEARCH', true); - trigger_error('NO_SEARCH_LOAD'); -} - -// It is applicable if the configuration setting is non-zero, and the user cannot -// ignore the flood setting, and the search is a keyword search. -$interval = ($user->data['user_id'] == ANONYMOUS) ? $config['search_anonymous_interval'] : $config['search_interval']; -if ($interval && !in_array($search_id, array('unreadposts', 'unanswered', 'active_topics', 'egosearch')) && !$auth->acl_get('u_ignoreflood')) -{ - if ($user->data['user_last_search'] > time() - $interval) - { - $template->assign_var('S_NO_SEARCH', true); - trigger_error($user->lang('NO_SEARCH_TIME', (int) ($user->data['user_last_search'] + $interval - time()))); - } -} - -// Define some vars -$limit_days = array(0 => $user->lang['ALL_RESULTS'], 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_AUTHOR'], 't' => $user->lang['SORT_TIME'], 'f' => $user->lang['SORT_FORUM'], 'i' => $user->lang['SORT_TOPIC_TITLE'], 's' => $user->lang['SORT_POST_SUBJECT']); - -$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'); - -$template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $user->lang('SEARCH'), - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}search.$phpEx"), -)); - -/** -* This event allows you to alter the above parameters, such as keywords and submit -* -* @event core.search_modify_submit_parameters -* @var string keywords The search keywords -* @var string author Specifies the author match, when ANONYMOUS is also a search-match -* @var int author_id ID of the author to search by -* @var string search_id Predefined search type name -* @var bool submit Whether or not the form has been submitted -* @since 3.1.10-RC1 -*/ -$vars = array( - 'keywords', - 'author', - 'author_id', - 'search_id', - 'submit', -); -extract($phpbb_dispatcher->trigger_event('core.search_modify_submit_parameters', compact($vars))); - -if ($keywords || $author || $author_id || $search_id || $submit) -{ - // clear arrays - $id_ary = array(); - - // If we are looking for authors get their ids - $author_id_ary = array(); - $sql_author_match = ''; - if ($author_id) - { - $author_id_ary[] = $author_id; - } - else if ($author) - { - if ((strpos($author, '*') !== false) && (utf8_strlen(str_replace(array('*', '%'), '', $author)) < $config['min_search_author_chars'])) - { - trigger_error($user->lang('TOO_FEW_AUTHOR_CHARS', (int) $config['min_search_author_chars'])); - } - - $sql_where = (strpos($author, '*') !== false) ? ' username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " username_clean = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE $sql_where - AND user_type <> " . USER_IGNORE; - $result = $db->sql_query_limit($sql, 100); - - while ($row = $db->sql_fetchrow($result)) - { - $author_id_ary[] = (int) $row['user_id']; - } - $db->sql_freeresult($result); - - $sql_where = (strpos($author, '*') !== false) ? ' post_username ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " post_username = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; - - $sql = 'SELECT 1 as guest_post - FROM ' . POSTS_TABLE . " - WHERE $sql_where - AND poster_id = " . ANONYMOUS; - $result = $db->sql_query_limit($sql, 1); - $found_guest_post = $db->sql_fetchfield('guest_post'); - $db->sql_freeresult($result); - - if ($found_guest_post) - { - $author_id_ary[] = ANONYMOUS; - $sql_author_match = (strpos($author, '*') !== false) ? ' ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; - } - - if (!count($author_id_ary)) - { - trigger_error('NO_SEARCH_RESULTS'); - } - } - - // if we search in an existing search result just add the additional keywords. But we need to use "all search terms"-mode - // so we can keep the old keywords in their old mode, but add the new ones as required words - if ($add_keywords) - { - if ($search_terms == 'all') - { - $keywords .= ' ' . $add_keywords; - } - else - { - $search_terms = 'all'; - $keywords = implode(' |', explode(' ', preg_replace('#\s+#u', ' ', $keywords))) . ' ' .$add_keywords; - } - } - - // Which forums should not be searched? Author searches are also carried out in unindexed forums - if (empty($keywords) && count($author_id_ary)) - { - $ex_fid_ary = array_keys($auth->acl_getf('!f_read', true)); - } - else - { - $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 = (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 - LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id - AND fa.session_id = '" . $db->sql_escape($user->session_id) . "') - $not_in_fid - ORDER BY f.left_id"; - $result = $db->sql_query($sql); - - $right_id = 0; - $reset_search_forum = true; - while ($row = $db->sql_fetchrow($result)) - { - if ($row['forum_password'] && $row['user_id'] != $user->data['user_id']) - { - $ex_fid_ary[] = (int) $row['forum_id']; - continue; - } - - // Exclude forums from active topics - if (!($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) && ($search_id == 'active_topics')) - { - $ex_fid_ary[] = (int) $row['forum_id']; - continue; - } - - if (count($search_forum)) - { - if ($search_child) - { - if (in_array($row['forum_id'], $search_forum) && $row['right_id'] > $right_id) - { - $right_id = (int) $row['right_id']; - } - else if ($row['right_id'] < $right_id) - { - continue; - } - } - - if (!in_array($row['forum_id'], $search_forum)) - { - $ex_fid_ary[] = (int) $row['forum_id']; - $reset_search_forum = false; - } - } - } - $db->sql_freeresult($result); - - // find out in which forums the user is allowed to view posts - $m_approve_posts_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('post', $ex_fid_ary, 'p.'); - $m_approve_topics_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('topic', $ex_fid_ary, 't.'); - - if ($reset_search_forum) - { - $search_forum = array(); - } - - // Select which method we'll use to obtain the post_id or topic_id information - $search_type = $config['search_type']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - // We do some additional checks in the module to ensure it can actually be utilised - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if ($error) - { - trigger_error($error); - } - - // let the search module split up the keywords - if ($keywords) - { - $correct_query = $search->split_keywords($keywords, $search_terms); - $common_words = $search->get_common_words(); - if (!$correct_query || (!$search->get_search_query() && !count($author_id_ary) && !$search_id)) - { - $ignored = (count($common_words)) ? sprintf($user->lang['IGNORED_TERMS_EXPLAIN'], implode(' ', $common_words)) . '
' : ''; - $word_length = $search->get_word_length(); - if ($word_length) - { - trigger_error($ignored . $user->lang('NO_KEYWORDS', $user->lang('CHARACTERS', (int) $word_length['min']), $user->lang('CHARACTERS', (int) $word_length['max']))); - } - else - { - trigger_error($ignored); - } - } - } - - 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->variable('sr', ($search_id == 'egosearch') ? 'topics' : 'posts'); - $show_results = ($show_results == 'posts') ? 'posts' : 'topics'; - } - - // define some variables needed for retrieving post_id/topic_id information - $sort_by_sql = array('a' => 'u.username_clean', 't' => (($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time'), 'f' => 'f.forum_id', 'i' => 't.topic_title', 's' => (($show_results == 'posts') ? 'p.post_subject' : 't.topic_title')); - - /** - * Event to modify the SQL parameters before pre-made searches - * - * @event core.search_modify_param_before - * @var string keywords String of the specified keywords - * @var array sort_by_sql Array of SQL sorting instructions - * @var array ex_fid_ary Array of excluded forum ids - * @var array author_id_ary Array of exclusive author ids - * @var string search_id The id of the search request - * @var array id_ary Array of post or topic ids for search result - * @var string show_results 'posts' or 'topics' type of ids - * @since 3.1.3-RC1 - * @changed 3.1.10-RC1 Added id_ary, show_results - */ - $vars = array( - 'keywords', - 'sort_by_sql', - 'ex_fid_ary', - 'author_id_ary', - 'search_id', - 'id_ary', - 'show_results', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_param_before', compact($vars))); - - // pre-made searches - $sql = $field = $l_search_title = ''; - if ($search_id) - { - switch ($search_id) - { - // Oh holy Bob, bring us some activity... - case 'active_topics': - $l_search_title = $user->lang['SEARCH_ACTIVE_TOPICS']; - $show_results = 'topics'; - $sort_key = 't'; - $sort_dir = 'd'; - $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); - $s_sort_key = $s_sort_dir = ''; - - $last_post_time_sql = ($sort_days) ? ' AND t.topic_last_post_time > ' . (time() - ($sort_days * 24 * 3600)) : ''; - - $sql = 'SELECT t.topic_last_post_time, t.topic_id - FROM ' . TOPICS_TABLE . " t - WHERE t.topic_moved_id = 0 - $last_post_time_sql - AND " . $m_approve_topics_fid_sql . ' - ' . ((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->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'; - $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - $sort_join = ($sort_key == 'f') ? FORUMS_TABLE . ' f, ' : ''; - $sql_sort = ($sort_key == 'f') ? ' AND f.forum_id = p.forum_id ' . $sql_sort : $sql_sort; - - if ($sort_days) - { - $last_post_time = 'AND p.post_time > ' . (time() - ($sort_days * 24 * 3600)); - } - else - { - $last_post_time = ''; - } - - if ($sort_key == 'a') - { - $sort_join = USERS_TABLE . ' u, '; - $sql_sort = ' AND u.user_id = p.poster_id ' . $sql_sort; - } - if ($show_results == 'posts') - { - $sql = "SELECT p.post_id - FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t - WHERE t.topic_posts_approved = 1 - AND p.topic_id = t.topic_id - $last_post_time - AND $m_approve_posts_fid_sql - " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " - $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = 'SELECT DISTINCT ' . $sort_by_sql[$sort_key] . ", p.topic_id - FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t - WHERE t.topic_posts_approved = 1 - AND t.topic_moved_id = 0 - AND p.topic_id = t.topic_id - $last_post_time - AND $m_approve_topics_fid_sql - " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " - $sql_sort"; - $field = 'topic_id'; - } - break; - - case 'unreadposts': - $l_search_title = $user->lang['SEARCH_UNREAD']; - // force sorting - $show_results = 'topics'; - $sort_key = 't'; - $sort_by_sql['t'] = 't.topic_last_post_time'; - $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - $sql_where = 'AND t.topic_moved_id = 0 - AND ' . $m_approve_topics_fid_sql . ' - ' . ((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 = ''; - - $template->assign_var('U_MARK_ALL_READ', ($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()) : ''); - break; - - case 'newposts': - $l_search_title = $user->lang['SEARCH_NEW']; - // force sorting - $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'; - $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - 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 = ''; - - if ($show_results == 'posts') - { - $sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p - WHERE p.post_time > ' . $user->data['user_lastvisit'] . ' - AND ' . $m_approve_posts_fid_sql . ' - ' . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " - $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = 'SELECT t.topic_id - FROM ' . TOPICS_TABLE . ' t - WHERE t.topic_last_post_time > ' . $user->data['user_lastvisit'] . ' - AND t.topic_moved_id = 0 - AND ' . $m_approve_topics_fid_sql . ' - ' . ((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) - - Creates temporary table, query is far from optimized - - $sql = 'SELECT t.topic_id - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p - WHERE p.post_time > ' . $user->data['user_lastvisit'] . ' - AND t.topic_id = p.topic_id - AND t.topic_moved_id = 0 - AND ' . $m_approve_topics_fid_sql . " - GROUP BY t.topic_id - $sql_sort"; -*/ - $field = 'topic_id'; - } - break; - - case 'egosearch': - $l_search_title = $user->lang['SEARCH_SELF']; - break; - } - - $template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $l_search_title, - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}search.$phpEx", "search_id=$search_id"), - )); - } - - /** - * Event to modify data after pre-made searches - * - * @event core.search_modify_param_after - * @var string l_search_title The title of the search page - * @var string search_id Predefined search type name - * @var string show_results Display topics or posts - * @var string sql SQL query corresponding to the pre-made search id - * @since 3.1.7-RC1 - */ - $vars = array( - 'l_search_title', - 'search_id', - 'show_results', - 'sql', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_param_after', compact($vars))); - - // show_results should not change after this - $per_page = ($show_results == 'posts') ? $config['posts_per_page'] : $config['topics_per_page']; - $total_match_count = 0; - - // Set limit for the $total_match_count to reduce server load - $total_matches_limit = 1000; - $found_more_search_matches = false; - - if ($search_id) - { - if ($sql) - { - // Only return up to $total_matches_limit+1 ids (the last one will be removed later) - $result = $db->sql_query_limit($sql, $total_matches_limit + 1); - - while ($row = $db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $db->sql_freeresult($result); - } - else if ($search_id == 'unreadposts') - { - // Only return up to $total_matches_limit+1 ids (the last one will be removed later) - $id_ary = array_keys(get_unread_topics($user->data['user_id'], $sql_where, $sql_sort, $total_matches_limit + 1)); - } - else - { - $search_id = ''; - } - - $total_match_count = count($id_ary); - if ($total_match_count) - { - // Limit the number to $total_matches_limit for pre-made searches - if ($total_match_count > $total_matches_limit) - { - $found_more_search_matches = true; - $total_match_count = $total_matches_limit; - } - - // Make sure $start is set to the last page if it exceeds the amount - $start = $pagination->validate_start($start, $per_page, $total_match_count); - - $id_ary = array_slice($id_ary, $start, $per_page); - } - else - { - // Set $start to 0 if no matches were found - $start = 0; - } - } - - // make sure that some arrays are always in the same order - sort($ex_fid_ary); - sort($author_id_ary); - - if ($search->get_search_query()) - { - $total_match_count = $search->keyword_search($show_results, $search_fields, $search_terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page); - } - 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); - } - - /** - * Event to search otherwise than by keywords or author - * - * @event core.search_backend_search_after - * @var string show_results 'posts' or 'topics' type of ids - * @var string search_fields The data fields to search in - * @var string search_terms Is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @var array sort_by_sql Array of SQL sorting instructions - * @var string sort_key The sort key - * @var string sort_dir The sort direction - * @var int sort_days Limit the age of results - * @var array ex_fid_ary Array of excluded forum ids - * @var string m_approve_posts_fid_sql Specifies which types of posts the user can view in which forums - * @var int topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @var array author_id_ary Array of exclusive author ids - * @var string sql_author_match Specifies the author match, when ANONYMOUS is also a search-match - * @var array id_ary Array of post or topic ids for search result - * @var int start The starting id of the results - * @var int per_page Number of ids each page is supposed to contain - * @var int total_match_count The total number of search matches - * @since 3.1.10-RC1 - */ - $vars = array( - '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', - 'total_match_count', - ); - extract($phpbb_dispatcher->trigger_event('core.search_backend_search_after', compact($vars))); - - $sql_where = ''; - - if (count($id_ary)) - { - $sql_where .= $db->sql_in_set(($show_results == 'posts') ? 'p.post_id' : 't.topic_id', $id_ary); - $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); - } - - if ($show_results == 'posts') - { - include($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - } - else - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $user->add_lang('viewtopic'); - - // Grab icons - $icons = $cache->obtain_icons(); - - // define some vars for urls - // A single wildcard will make the search results look ugly - $hilit = phpbb_clean_search_string(str_replace(array('+', '-', '|', '(', ')', '"'), ' ', $keywords)); - $hilit = str_replace(' ', '|', $hilit); - - $u_hilit = urlencode(htmlspecialchars_decode(str_replace('|', ' ', $hilit))); - $u_show_results = '&sr=' . $show_results; - $u_search_forum = implode('&fid%5B%5D=', $search_forum); - - $u_search = append_sid("{$phpbb_root_path}search.$phpEx", $u_sort_param . $u_show_results); - $u_search .= ($search_id) ? '&search_id=' . $search_id : ''; - $u_search .= ($u_hilit) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; - $u_search .= ($search_terms != 'all') ? '&terms=' . $search_terms : ''; - $u_search .= ($topic_id) ? '&t=' . $topic_id : ''; - $u_search .= ($author) ? '&author=' . urlencode(htmlspecialchars_decode($author)) : ''; - $u_search .= ($author_id) ? '&author_id=' . $author_id : ''; - $u_search .= ($u_search_forum) ? '&fid%5B%5D=' . $u_search_forum : ''; - $u_search .= (!$search_child) ? '&sc=0' : ''; - $u_search .= ($search_fields != 'all') ? '&sf=' . $search_fields : ''; - $u_search .= ($return_chars != 300) ? '&ch=' . $return_chars : ''; - - /** - * Event to add or modify search URL parameters - * - * @event core.search_modify_url_parameters - * @var string u_search Search URL parameters string - * @var string search_id Predefined search type name - * @var string show_results String indicating the show results mode - * @var string sql_where The SQL WHERE string used by search to get topic data - * @var int total_match_count The total number of search matches - * @var array ex_fid_ary Array of excluded forum ids - * @since 3.1.7-RC1 - * @changed 3.1.10-RC1 Added show_results, sql_where, total_match_count - * @changed 3.1.11-RC1 Added ex_fid_ary - */ - $vars = array( - 'u_search', - 'search_id', - 'show_results', - 'sql_where', - 'total_match_count', - 'ex_fid_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_url_parameters', compact($vars))); - - if ($sql_where) - { - $zebra = []; - - if ($show_results == 'posts') - { - // @todo Joining this query to the one below? - $sql = 'SELECT zebra_id, friend, foe - FROM ' . ZEBRA_TABLE . ' - WHERE user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $zebra[($row['friend']) ? 'friend' : 'foe'][] = $row['zebra_id']; - } - $db->sql_freeresult($result); - - $sql_array = array( - 'SELECT' => 'p.*, f.forum_id, f.forum_name, t.*, u.username, u.username_clean, u.user_sig, u.user_sig_bbcode_uid, u.user_colour', - 'FROM' => array( - POSTS_TABLE => 'p', - ), - 'LEFT_JOIN' => array( - array( - 'FROM' => array(TOPICS_TABLE => 't'), - 'ON' => 'p.topic_id = t.topic_id', - ), - array( - 'FROM' => array(FORUMS_TABLE => 'f'), - 'ON' => 'p.forum_id = f.forum_id', - ), - array( - 'FROM' => array(USERS_TABLE => 'u'), - 'ON' => 'p.poster_id = u.user_id', - ), - ), - 'WHERE' => $sql_where, - 'ORDER_BY' => $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'), - ); - - /** - * Event to modify the SQL query before the posts data is retrieved - * - * @event core.search_get_posts_data - * @var array sql_array The SQL array - * @var array zebra Array of zebra data for the current user - * @var int total_match_count The total number of search matches - * @var string keywords String of the specified keywords - * @var array sort_by_sql Array of SQL sorting instructions - * @var string s_sort_dir The sort direction - * @var string s_sort_key The sort key - * @var string s_limit_days Limit the age of results - * @var array ex_fid_ary Array of excluded forum ids - * @var array author_id_ary Array of exclusive author ids - * @var string search_fields The data fields to search in - * @var int search_id The id of the search request - * @var int start The starting id of the results - * @since 3.1.0-b3 - */ - $vars = array( - 'sql_array', - 'zebra', - 'total_match_count', - 'keywords', - 'sort_by_sql', - 's_sort_dir', - 's_sort_key', - 's_limit_days', - 'ex_fid_ary', - 'author_id_ary', - 'search_fields', - 'search_id', - 'start', - ); - extract($phpbb_dispatcher->trigger_event('core.search_get_posts_data', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_array); - } - else - { - $sql_from = TOPICS_TABLE . ' t - LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = t.forum_id) - ' . (($sort_key == 'a') ? ' LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = t.topic_poster) ' : ''); - $sql_select = 't.*, f.forum_id, f.forum_name'; - - if ($user->data['is_registered']) - { - if ($config['load_db_track'] && $author_id !== $user->data['user_id']) - { - $sql_from .= ' LEFT JOIN ' . TOPICS_POSTED_TABLE . ' tp ON (tp.user_id = ' . $user->data['user_id'] . ' - AND t.topic_id = tp.topic_id)'; - $sql_select .= ', tp.topic_posted'; - } - - if ($config['load_db_lastread']) - { - $sql_from .= ' LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.user_id = ' . $user->data['user_id'] . ' - AND t.topic_id = tt.topic_id) - LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . ' - AND ft.forum_id = f.forum_id)'; - $sql_select .= ', tt.mark_time, ft.mark_time as f_mark_time'; - } - } - - if ($config['load_anon_lastread'] || ($user->data['is_registered'] && !$config['load_db_lastread'])) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - } - - $sql_order_by = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); - - /** - * Event to modify the SQL query before the topic data is retrieved - * - * @event core.search_get_topic_data - * @var string sql_select The SQL SELECT string used by search to get topic data - * @var string sql_from The SQL FROM string used by search to get topic data - * @var string sql_where The SQL WHERE string used by search to get topic data - * @var int total_match_count The total number of search matches - * @var array sort_by_sql Array of SQL sorting instructions - * @var string sort_dir The sorting direction - * @var string sort_key The sorting key - * @var string sql_order_by The SQL ORDER BY string used by search to get topic data - * @since 3.1.0-a1 - * @changed 3.1.0-RC5 Added total_match_count - * @changed 3.1.7-RC1 Added sort_by_sql, sort_dir, sort_key, sql_order_by - */ - $vars = array( - 'sql_select', - 'sql_from', - 'sql_where', - 'total_match_count', - 'sort_by_sql', - 'sort_dir', - 'sort_key', - 'sql_order_by', - ); - extract($phpbb_dispatcher->trigger_event('core.search_get_topic_data', compact($vars))); - - $sql = "SELECT $sql_select - FROM $sql_from - WHERE $sql_where - ORDER BY $sql_order_by"; - } - $result = $db->sql_query($sql); - $result_topic_id = 0; - - $rowset = $attachments = $topic_tracking_info = array(); - - if ($show_results == 'topics') - { - $forums = $rowset = $shadow_topic_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $row['forum_id'] = (int) $row['forum_id']; - $row['topic_id'] = (int) $row['topic_id']; - - if ($row['topic_status'] == ITEM_MOVED) - { - $shadow_topic_list[$row['topic_moved_id']] = $row['topic_id']; - } - - $rowset[$row['topic_id']] = $row; - - if (!isset($forums[$row['forum_id']]) && $user->data['is_registered'] && $config['load_db_lastread']) - { - $forums[$row['forum_id']]['mark_time'] = $row['f_mark_time']; - } - $forums[$row['forum_id']]['topic_list'][] = $row['topic_id']; - $forums[$row['forum_id']]['rowset'][$row['topic_id']] = &$rowset[$row['topic_id']]; - } - $db->sql_freeresult($result); - - // If we have some shadow topics, update the rowset to reflect their topic information - if (count($shadow_topic_list)) - { - $sql = 'SELECT * - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', array_keys($shadow_topic_list)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $orig_topic_id = $shadow_topic_list[$row['topic_id']]; - - // We want to retain some values - $row = array_merge($row, array( - 'topic_moved_id' => $rowset[$orig_topic_id]['topic_moved_id'], - 'topic_status' => $rowset[$orig_topic_id]['topic_status'], - 'forum_name' => $rowset[$orig_topic_id]['forum_name']) - ); - - $rowset[$orig_topic_id] = $row; - } - $db->sql_freeresult($result); - } - unset($shadow_topic_list); - - foreach ($forums as $forum_id => $forum) - { - if ($user->data['is_registered'] && $config['load_db_lastread']) - { - $topic_tracking_info[$forum_id] = get_topic_tracking($forum_id, $forum['topic_list'], $forum['rowset'], array($forum_id => $forum['mark_time'])); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $topic_tracking_info[$forum_id] = get_complete_topic_tracking($forum_id, $forum['topic_list']); - - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - } - } - unset($forums); - } - else - { - $text_only_message = ''; - $attach_list = array(); - - 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']); - - $text_only_message = $row['post_text']; - // make list items visible as such - if ($row['bbcode_uid']) - { - $text_only_message = str_replace('[*:' . $row['bbcode_uid'] . ']', '⋅ ', $text_only_message); - // no BBCode in text only message - strip_bbcode($text_only_message, $row['bbcode_uid']); - } - - if ($return_chars == -1 || utf8_strlen($text_only_message) < ($return_chars + 3)) - { - $row['display_text_only'] = false; - - // Does this post have an attachment? If so, add it to the list - if ($row['post_attachment'] && $config['allow_attachments']) - { - $attach_list[$row['forum_id']][] = $row['post_id']; - } - } - else - { - $row['post_text'] = $text_only_message; - $row['display_text_only'] = true; - } - - $rowset[] = $row; - } - $db->sql_freeresult($result); - - unset($text_only_message); - - // Pull attachment data - if (count($attach_list)) - { - $use_attach_list = $attach_list; - $attach_list = array(); - - foreach ($use_attach_list as $forum_id => $_list) - { - if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id)) - { - $attach_list = array_merge($attach_list, $_list); - } - } - } - - if (count($attach_list)) - { - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . ' - AND in_message = 0 - ORDER BY filetime DESC, post_msg_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $attachments[$row['post_msg_id']][] = $row; - } - $db->sql_freeresult($result); - } - } - - if ($hilit) - { - // Remove bad highlights - $hilit_array = array_filter(explode('|', $hilit), 'strlen'); - foreach ($hilit_array as $key => $value) - { - $hilit_array[$key] = phpbb_clean_search_string($value); - $hilit_array[$key] = str_replace('\*', '\w*?', preg_quote($hilit_array[$key], '#')); - $hilit_array[$key] = preg_replace('#(^|\s)\\\\w\*\?(\s|$)#', '$1\w+?$2', $hilit_array[$key]); - } - $hilit = implode('|', $hilit_array); - } - - /** - * Modify the rowset data - * - * @event core.search_modify_rowset - * @var array attachments Array with posts attachments data - * @var string hilit String to highlight - * @var array rowset Array with the search results data - * @var string show_results String indicating the show results mode - * @var array topic_tracking_info Array with the topics tracking 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.1.0-b4 - * @changed 3.1.0-b5 Added var show_results - */ - $vars = array( - 'attachments', - 'hilit', - 'rowset', - 'show_results', - 'topic_tracking_info', - 'u_hilit', - 'view', - 'zebra', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_rowset', compact($vars))); - - foreach ($rowset as $row) - { - $forum_id = $row['forum_id']; - $result_topic_id = $row['topic_id']; - $topic_title = censor_text($row['topic_title']); - $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1; - - $view_topic_url_params = "f=$forum_id&t=$result_topic_id" . (($u_hilit) ? "&hilit=$u_hilit" : ''); - $view_topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params); - - $folder_img = $folder_alt = $u_mcp_queue = ''; - $topic_type = $posts_unapproved = 0; - $unread_topic = $topic_unapproved = $topic_deleted = false; - - if ($show_results == 'topics') - { - if ($config['load_db_track'] && $author_id === $user->data['user_id']) - { - $row['topic_posted'] = 1; - } - - topic_status($row, $replies, (isset($topic_tracking_info[$forum_id][$row['topic_id']]) && $row['topic_last_post_time'] > $topic_tracking_info[$forum_id][$row['topic_id']]) ? true : false, $folder_img, $folder_alt, $topic_type); - - $unread_topic = (isset($topic_tracking_info[$forum_id][$row['topic_id']]) && $row['topic_last_post_time'] > $topic_tracking_info[$forum_id][$row['topic_id']]) ? true : false; - - $topic_unapproved = (($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $forum_id)) ? true : false; - $posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $forum_id)) ? true : false; - $topic_deleted = $row['topic_visibility'] == ITEM_DELETED; - $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . "&t=$result_topic_id", true, $user->session_id) : ''; - $u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&mode=deleted_topics&t=$result_topic_id", true, $user->session_id) : $u_mcp_queue; - - $row['topic_title'] = preg_replace('#(?!<.*)(?]*(?:)#isu', '$1', $row['topic_title']); - - $tpl_ary = array( - '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']), - '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']), - - 'TOPIC_TYPE' => $topic_type, - - 'TOPIC_IMG_STYLE' => $folder_img, - 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'TOPIC_FOLDER_IMG_ALT' => $user->lang[$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'] : '', - 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', - 'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '', - - 'S_TOPIC_TYPE' => $row['topic_type'], - 'S_USER_POSTED' => (!empty($row['topic_posted'])) ? true : false, - 'S_UNREAD_TOPIC' => $unread_topic, - - 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_get('m_report', $forum_id)) ? true : false, - 'S_TOPIC_UNAPPROVED' => $topic_unapproved, - 'S_POSTS_UNAPPROVED' => $posts_unapproved, - 'S_TOPIC_DELETED' => $topic_deleted, - 'S_HAS_POLL' => ($row['poll_start']) ? true : false, - - 'U_LAST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&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_TOPIC_AUTHOR' => get_username_string('profile', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), - 'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&view=unread') . '#unread', - 'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=reports&t=' . $result_topic_id, true, $user->session_id), - 'U_MCP_QUEUE' => $u_mcp_queue, - ); - } - else - { - if ((isset($zebra['foe']) && in_array($row['poster_id'], $zebra['foe'])) && (!$view || $view != 'show' || $post_id != $row['post_id'])) - { - $template->assign_block_vars('searchresults', array( - 'S_IGNORE_POST' => true, - - 'L_IGNORE_POST' => sprintf($user->lang['POST_BY_FOE'], $row['username'], "', '')) - ); - - continue; - } - - // Replace naughty words such as farty pants - $row['post_subject'] = censor_text($row['post_subject']); - - if ($row['display_text_only']) - { - // now find context for the searched words - $row['post_text'] = get_context($row['post_text'], array_filter(explode('|', $hilit), 'strlen'), $return_chars); - $row['post_text'] = bbcode_nl2br($row['post_text']); - } - else - { - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - $row['post_text'] = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); - - if (!empty($attachments[$row['post_id']])) - { - parse_attachments($forum_id, $row['post_text'], $attachments[$row['post_id']], $update_count); - - // we only display inline attachments - unset($attachments[$row['post_id']]); - } - } - - if ($hilit) - { - // post highlighting - $row['post_text'] = preg_replace('#(?!<.*)(?]*(?:)#isu', '$1', $row['post_text']); - $row['post_subject'] = preg_replace('#(?!<.*)(?]*(?:)#isu', '$1', $row['post_subject']); - } - - $tpl_ary = array( - 'POST_AUTHOR_FULL' => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - - 'POST_SUBJECT' => $row['post_subject'], - 'POST_DATE' => (!empty($row['post_time'])) ? $user->format_date($row['post_time']) : '', - 'MESSAGE' => $row['post_text'] - ); - } - - $tpl_ary = array_merge($tpl_ary, array( - 'FORUM_ID' => $forum_id, - 'TOPIC_ID' => $result_topic_id, - 'POST_ID' => ($show_results == 'posts') ? $row['post_id'] : false, - - 'FORUM_TITLE' => $row['forum_name'], - 'TOPIC_TITLE' => $topic_title, - 'TOPIC_REPLIES' => $replies, - 'TOPIC_VIEWS' => $row['topic_views'], - - 'U_VIEW_TOPIC' => $view_topic_url, - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id), - 'U_VIEW_POST' => (!empty($row['post_id'])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=" . $row['topic_id'] . '&p=' . $row['post_id'] . (($u_hilit) ? '&hilit=' . $u_hilit : '')) . '#p' . $row['post_id'] : '', - )); - - /** - * Modify the topic data before it is assigned to the template - * - * @event core.search_modify_tpl_ary - * @var array row Array with topic data - * @var array tpl_ary Template block array with topic data - * @var string show_results Display topics or posts - * @var string topic_title Cleaned topic title - * @var int replies The number of topic replies - * @var string view_topic_url The URL to the topic - * @var string folder_img The folder image of the topic - * @var string folder_alt The alt attribute of the topic folder img - * @var int topic_type The topic type - * @var bool unread_topic Whether the topic has unread posts - * @var bool topic_unapproved Whether the topic is unapproved - * @var int posts_unapproved The number of unapproved posts - * @var bool topic_deleted Whether the topic has been deleted - * @var string u_mcp_queue The URL to the corresponding MCP queue page - * @var array zebra The zebra data of the current user - * @var array attachments All the attachments of the search results - * @since 3.1.0-a1 - * @changed 3.1.0-b3 Added vars show_results, topic_title, replies, - * view_topic_url, folder_img, folder_alt, topic_type, unread_topic, - * topic_unapproved, posts_unapproved, topic_deleted, u_mcp_queue, - * zebra, attachments - */ - $vars = array( - 'row', - 'tpl_ary', - 'show_results', - 'topic_title', - 'replies', - 'view_topic_url', - 'folder_img', - 'folder_alt', - 'topic_type', - 'unread_topic', - 'topic_unapproved', - 'posts_unapproved', - 'topic_deleted', - 'u_mcp_queue', - 'zebra', - 'attachments', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_tpl_ary', compact($vars))); - - $template->assign_block_vars('searchresults', $tpl_ary); - - if ($show_results == 'topics') - { - $pagination->generate_template_pagination($view_topic_url, 'searchresults.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true); - } - } - - if ($topic_id && ($topic_id == $result_topic_id)) - { - $template->assign_vars(array( - 'SEARCH_TOPIC' => $topic_title, - 'L_RETURN_TO_TOPIC' => $user->lang('RETURN_TO', $topic_title), - 'U_SEARCH_TOPIC' => $view_topic_url - )); - } - } - unset($rowset); - - // Output header - if ($found_more_search_matches) - { - $l_search_matches = $user->lang('FOUND_MORE_SEARCH_MATCHES', (int) $total_match_count); - } - else - { - $l_search_matches = $user->lang('FOUND_SEARCH_MATCHES', (int) $total_match_count); - } - - // Check if search backend supports phrase search or not - $phrase_search_disabled = ''; - if (strpos(html_entity_decode($keywords), '"') !== false && method_exists($search, 'supports_phrase_search')) - { - $phrase_search_disabled = $search->supports_phrase_search() ? false : true; - } - - $pagination->generate_template_pagination($u_search, 'pagination', 'start', $total_match_count, $per_page, $start); - - $template->assign_vars(array( - 'SEARCH_TITLE' => $l_search_title, - 'SEARCH_MATCHES' => $l_search_matches, - 'SEARCH_WORDS' => $keywords, - 'SEARCHED_QUERY' => $search->get_search_query(), - 'IGNORED_WORDS' => (!empty($common_words)) ? implode(' ', $common_words) : '', - - 'PHRASE_SEARCH_DISABLED' => $phrase_search_disabled, - - 'TOTAL_MATCHES' => $total_match_count, - 'SEARCH_IN_RESULTS' => ($search_id) ? false : true, - - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_SEARCH_ACTION' => $u_search, - 'S_SHOW_TOPICS' => ($show_results == 'posts') ? false : true, - - 'GOTO_PAGE_IMG' => $user->img('icon_post_target', 'GOTO_PAGE'), - 'NEWEST_POST_IMG' => $user->img('icon_topic_newest', 'VIEW_NEWEST_POST'), - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'TOPIC_REPORTED'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPIC_UNAPPROVED'), - 'DELETED_IMG' => $user->img('icon_topic_deleted', 'TOPIC_DELETED'), - 'POLL_IMG' => $user->img('icon_topic_poll', 'TOPIC_POLL'), - 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), - - 'U_SEARCH_WORDS' => $u_search, - )); - - /** - * Modify the title and/or load data for the search results page - * - * @event core.search_results_modify_search_title - * @var int author_id ID of the author to search by - * @var string l_search_title The title of the search page - * @var string search_id Predefined search type name - * @var string show_results Search results output mode - topics or posts - * @var int start The starting id of the results - * @var int total_match_count The count of search results - * @var string keywords The search keywords - * @since 3.1.0-RC4 - * @changed 3.1.6-RC1 Added total_match_count and keywords - */ - $vars = array( - 'author_id', - 'l_search_title', - 'search_id', - 'show_results', - 'start', - 'total_match_count', - 'keywords', - ); - extract($phpbb_dispatcher->trigger_event('core.search_results_modify_search_title', compact($vars))); - - page_header(($l_search_title) ? $l_search_title : $user->lang['SEARCH']); - - $template->set_filenames(array( - 'body' => 'search_results.html') - ); - make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - - page_footer(); -} - -// Search forum -$rowset = array(); -$s_forums = ''; -$sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f.right_id, f.forum_password, f.enable_indexing, fa.user_id - FROM ' . FORUMS_TABLE . ' f - LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id - AND fa.session_id = '" . $db->sql_escape($user->session_id) . "') - ORDER BY f.left_id ASC"; -$result = $db->sql_query($sql); - -while ($row = $db->sql_fetchrow($result)) -{ - $rowset[(int) $row['forum_id']] = $row; -} -$db->sql_freeresult($result); - -$right = $cat_right = $padding_inc = 0; -$padding = $forum_list = $holding = ''; -$pad_store = array('0' => ''); - -/** -* Modify the forum select list for advanced search page -* -* @event core.search_modify_forum_select_list -* @var array rowset Array with the forums list data -* @since 3.1.10-RC1 -*/ -$vars = array('rowset'); -extract($phpbb_dispatcher->trigger_event('core.search_modify_forum_select_list', compact($vars))); - -foreach ($rowset as $row) -{ - if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) - { - // Non-postable forum with no subforums, don't display - continue; - } - - if ($row['forum_type'] == FORUM_POST && ($row['left_id'] + 1 == $row['right_id']) && !$row['enable_indexing']) - { - // Postable forum with no subforums and indexing disabled, don't display - continue; - } - - if ($row['forum_type'] == FORUM_LINK || ($row['forum_password'] && !$row['user_id'])) - { - // if this forum is a link or password protected (user has not entered the password yet) then skip to the next branch - continue; - } - - if ($row['left_id'] < $right) - { - $padding .= '   '; - $pad_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - if (isset($pad_store[$row['parent_id']])) - { - $padding = $pad_store[$row['parent_id']]; - } - else - { - continue; - } - } - - $right = $row['right_id']; - - if ($auth->acl_gets('!f_search', '!f_list', $row['forum_id'])) - { - // if the user does not have permissions to search or see this forum skip only this forum/category - continue; - } - - $selected = (in_array($row['forum_id'], $search_forum)) ? ' selected="selected"' : ''; - - if ($row['left_id'] > $cat_right) - { - // make sure we don't forget anything - $s_forums .= $holding; - $holding = ''; - } - - if ($row['right_id'] - $row['left_id'] > 1) - { - $cat_right = max($cat_right, $row['right_id']); - - $holding .= ''; - } - else - { - $s_forums .= $holding . ''; - $holding = ''; - } -} - -if ($holding) -{ - $s_forums .= $holding; -} - -unset($pad_store); -unset($rowset); - -if (!$s_forums) -{ - trigger_error('NO_SEARCH'); -} - -// Number of chars returned -$s_characters = ''; -$s_characters .= ''; -$s_characters .= ''; -$s_characters .= ''; - -for ($i = 100; $i <= 1000; $i += 100) -{ - $selected = ($i == 300) ? ' selected="selected"' : ''; - $s_characters .= ''; -} - -$s_hidden_fields = array('t' => $topic_id); - -if ($_SID) -{ - $s_hidden_fields['sid'] = $_SID; -} - -if (!empty($_EXTRA_URL)) -{ - foreach ($_EXTRA_URL as $url_param) - { - $url_param = explode('=', $url_param, 2); - $s_hidden_fields[$url_param[0]] = $url_param[1]; - } -} - -$template->assign_vars(array( - 'S_SEARCH_ACTION' => append_sid("{$phpbb_root_path}search.$phpEx", false, true, 0), // We force no ?sid= appending by using 0 - 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - 'S_CHARACTER_OPTIONS' => $s_characters, - 'S_FORUM_OPTIONS' => $s_forums, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_IN_SEARCH' => true, -)); - -// only show recent searches to search administrators -if ($auth->acl_get('a_search')) -{ - // Handle large objects differently for Oracle and MSSQL - switch ($db->get_sql_layer()) - { - case 'oracle': - $sql = 'SELECT search_time, search_keywords - FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE dbms_lob.getlength(search_keywords) > 0 - ORDER BY search_time DESC'; - break; - - case 'mssql_odbc': - case 'mssqlnative': - $sql = 'SELECT search_time, search_keywords - FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE DATALENGTH(search_keywords) > 0 - ORDER BY search_time DESC'; - break; - - default: - $sql = 'SELECT search_time, search_keywords - FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE search_keywords <> \'\' - ORDER BY search_time DESC'; - break; - } - $result = $db->sql_query_limit($sql, 5); - - while ($row = $db->sql_fetchrow($result)) - { - $keywords = $row['search_keywords']; - - $template->assign_block_vars('recentsearch', array( - 'KEYWORDS' => $keywords, - 'TIME' => $user->format_date($row['search_time']), - - 'U_KEYWORDS' => append_sid("{$phpbb_root_path}search.$phpEx", 'keywords=' . urlencode(htmlspecialchars_decode($keywords))) - )); - } - $db->sql_freeresult($result); -} - -// Output the basic page -page_header($user->lang['SEARCH']); - -$template->set_filenames(array( - 'body' => 'search_body.html') -); -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - -page_footer(); diff --git a/install/update/new/styles/prosilver/style.cfg b/install/update/new/styles/prosilver/style.cfg deleted file mode 100644 index 0c7eba6..0000000 --- a/install/update/new/styles/prosilver/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 -# @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 = prosilver -copyright = © phpBB Limited, 2007 -style_version = 3.3.0 -phpbb_version = 3.3.0 - -# Defining a different template bitfield -# template_bitfield = //g= - -# Parent style -# Set value to empty or to this style's name if this style does not have a parent style -parent = prosilver diff --git a/install/update/new/styles/prosilver/template/attachment.html b/install/update/new/styles/prosilver/template/attachment.html deleted file mode 100644 index 45b9dc2..0000000 --- a/install/update/new/styles/prosilver/template/attachment.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - -

[{_file.DENIED_MESSAGE}]

- - - - -
-
{% if _file.COMMENT %}{{ _file.COMMENT|e('html') }}{% else %}{{ _file.DOWNLOAD_NAME }}{% endif %}
-
{_file.COMMENT}
-
- - - -
-
{% if _file.COMMENT %}{{ _file.COMMENT|e('html') }}{% else %}{{ _file.DOWNLOAD_NAME }}{% endif %}
-
{_file.COMMENT}
-
{_file.DOWNLOAD_NAME} ({_file.FILESIZE} {_file.SIZE_LANG}) {_file.L_DOWNLOAD_COUNT}
-
- - - -
-
{_file.UPLOAD_ICON} {_file.DOWNLOAD_NAME}
-
{_file.COMMENT}
-
({_file.FILESIZE} {_file.SIZE_LANG}) {_file.L_DOWNLOAD_COUNT}
-
- - - - - - diff --git a/install/update/new/styles/prosilver/template/bbcode.html b/install/update/new/styles/prosilver/template/bbcode.html deleted file mode 100644 index b37ba23..0000000 --- a/install/update/new/styles/prosilver/template/bbcode.html +++ /dev/null @@ -1,79 +0,0 @@ -
    -
      -
    - -
      -
    - -
  • -
  • - -
    {USERNAME} {L_WROTE}{L_COLON} -
    -
    - -
    - - uncited - -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    -
    - -
    -
    - - -

    {L_CODE}{L_COLON} {L_SELECT_ALL_CODE}

    
    -
    - -
    -
    - - - - - - - - - - -{TEXT} - -{TEXT} - -{L_IMAGE} - -{DESCRIPTION} - -{DESCRIPTION} - - diff --git a/install/update/new/styles/prosilver/template/captcha_recaptcha.html b/install/update/new/styles/prosilver/template/captcha_recaptcha.html deleted file mode 100644 index 8fc7faa..0000000 --- a/install/update/new/styles/prosilver/template/captcha_recaptcha.html +++ /dev/null @@ -1,9 +0,0 @@ - - - {% INCLUDEJS RECAPTCHA_SERVER ~ '.js?onload=phpbbRecaptchaOnLoad&hl=' ~ lang('RECAPTCHA_LANG') %} -
    - -{L_RECAPTCHA_NOT_AVAILABLE} - diff --git a/install/update/new/styles/prosilver/template/forum_fn.js b/install/update/new/styles/prosilver/template/forum_fn.js deleted file mode 100644 index 2e39365..0000000 --- a/install/update/new/styles/prosilver/template/forum_fn.js +++ /dev/null @@ -1,937 +0,0 @@ -/* global phpbb */ - -/** -* phpBB3 forum functions -*/ - -/** -* Find a member -*/ -function find_username(url) { - 'use strict'; - - popup(url, 760, 570, '_usersearch'); - return false; -} - -/** -* Window popup -*/ -function popup(url, width, height, name) { - 'use strict'; - - if (!name) { - name = '_popup'; - } - - window.open(url.replace(/&/g, '&'), name, 'height=' + height + ',resizable=yes,scrollbars=yes, width=' + width); - return false; -} - -/** -* Jump to page -*/ -function pageJump(item) { - 'use strict'; - - var page = parseInt(item.val(), 10), - perPage = item.attr('data-per-page'), - baseUrl = item.attr('data-base-url'), - startName = item.attr('data-start-name'); - - if (page !== null && !isNaN(page) && page === Math.floor(page) && page > 0) { - if (baseUrl.indexOf('?') === -1) { - document.location.href = baseUrl + '?' + startName + '=' + ((page - 1) * perPage); - } else { - document.location.href = baseUrl.replace(/&/g, '&') + '&' + startName + '=' + ((page - 1) * perPage); - } - } -} - -/** -* Mark/unmark checklist -* id = ID of parent container, name = name prefix, state = state [true/false] -*/ -function marklist(id, name, state) { - 'use strict'; - - jQuery('#' + id + ' input[type=checkbox][name]').each(function() { - var $this = jQuery(this); - if ($this.attr('name').substr(0, name.length) === name && !$this.prop('disabled')) { - $this.prop('checked', state); - } - }); -} - -/** -* Resize viewable area for attached image or topic review panel (possibly others to come) -* e = element -*/ -function viewableArea(e, itself) { - 'use strict'; - - if (!e) { - return; - } - - if (!itself) { - e = e.parentNode; - } - - if (!e.vaHeight) { - // Store viewable area height before changing style to auto - e.vaHeight = e.offsetHeight; - e.vaMaxHeight = e.style.maxHeight; - e.style.height = 'auto'; - e.style.maxHeight = 'none'; - e.style.overflow = 'visible'; - } else { - // Restore viewable area height to the default - e.style.height = e.vaHeight + 'px'; - e.style.overflow = 'auto'; - e.style.maxHeight = e.vaMaxHeight; - e.vaHeight = false; - } -} - -/** -* Alternate display of subPanels -*/ -jQuery(function($) { - 'use strict'; - - $('.sub-panels').each(function() { - - var $childNodes = $('a[data-subpanel]', this), - panels = $childNodes.map(function () { - return this.getAttribute('data-subpanel'); - }), - showPanel = this.getAttribute('data-show-panel'); - - if (panels.length) { - activateSubPanel(showPanel, panels); - $childNodes.click(function () { - activateSubPanel(this.getAttribute('data-subpanel'), panels); - return false; - }); - } - }); -}); - -/** -* Activate specific subPanel -*/ -function activateSubPanel(p, panels) { - 'use strict'; - - var i, showPanel; - - if (typeof p === 'string') { - showPanel = p; - } - $('input[name="show_panel"]').val(showPanel); - - if (typeof panels === 'undefined') { - panels = jQuery('.sub-panels a[data-subpanel]').map(function() { - return this.getAttribute('data-subpanel'); - }); - } - - for (i = 0; i < panels.length; i++) { - jQuery('#' + panels[i]).css('display', panels[i] === showPanel ? 'block' : 'none'); - jQuery('#' + panels[i] + '-tab').toggleClass('activetab', panels[i] === showPanel); - } -} - -function selectCode(a) { - 'use strict'; - - // Get ID of code block - var e = a.parentNode.parentNode.getElementsByTagName('CODE')[0]; - var s, r; - - // Not IE and IE9+ - if (window.getSelection) { - s = window.getSelection(); - // Safari and Chrome - if (s.setBaseAndExtent) { - var l = (e.innerText.length > 1) ? e.innerText.length - 1 : 1; - try { - s.setBaseAndExtent(e, 0, e, l); - } catch (error) { - r = document.createRange(); - r.selectNodeContents(e); - s.removeAllRanges(); - s.addRange(r); - } - } - // Firefox and Opera - else { - // workaround for bug # 42885 - if (window.opera && e.innerHTML.substring(e.innerHTML.length - 4) === '
    ') { - e.innerHTML = e.innerHTML + ' '; - } - - r = document.createRange(); - r.selectNodeContents(e); - s.removeAllRanges(); - s.addRange(r); - } - } - // Some older browsers - else if (document.getSelection) { - s = document.getSelection(); - r = document.createRange(); - r.selectNodeContents(e); - s.removeAllRanges(); - s.addRange(r); - } - // IE - else if (document.selection) { - r = document.body.createTextRange(); - r.moveToElementText(e); - r.select(); - } -} - -var inAutocomplete = false; -var lastKeyEntered = ''; - -/** -* Check event key -*/ -function phpbbCheckKey(event) { - 'use strict'; - - // Keycode is array down or up? - if (event.keyCode && (event.keyCode === 40 || event.keyCode === 38)) { - inAutocomplete = true; - } - - // Make sure we are not within an "autocompletion" field - if (inAutocomplete) { - // If return pressed and key changed we reset the autocompletion - if (!lastKeyEntered || lastKeyEntered === event.which) { - inAutocomplete = false; - return true; - } - } - - // Keycode is not return, then return. ;) - if (event.which !== 13) { - lastKeyEntered = event.which; - return true; - } - - return false; -} - -/** -* Apply onkeypress event for forcing default submit button on ENTER key press -*/ -jQuery(function($) { - 'use strict'; - - $('form input[type=text], form input[type=password]').on('keypress', function (e) { - var defaultButton = $(this).parents('form').find('input[type=submit].default-submit-action'); - - if (!defaultButton || defaultButton.length <= 0) { - return true; - } - - if (phpbbCheckKey(e)) { - return true; - } - - if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) { - defaultButton.click(); - return false; - } - - return true; - }); -}); - -/** -* Functions for user search popup -*/ -function insertUser(formId, value) { - 'use strict'; - - var $form = jQuery(formId), - formName = $form.attr('data-form-name'), - fieldName = $form.attr('data-field-name'), - item = opener.document.forms[formName][fieldName]; - - if (item.value.length && item.type === 'textarea') { - value = item.value + '\n' + value; - } - - item.value = value; -} - -function insert_marked_users(formId, users) { - 'use strict'; - - $(users).filter(':checked').each(function() { - insertUser(formId, this.value); - }); - - window.close(); -} - -function insert_single_user(formId, user) { - 'use strict'; - - insertUser(formId, user); - window.close(); -} - -/** -* Parse document block -*/ -function parseDocument($container) { - 'use strict'; - - var test = document.createElement('div'), - oldBrowser = (typeof test.style.borderRadius === 'undefined'), - $body = $('body'); - - /** - * Reset avatar dimensions when changing URL or EMAIL - */ - $container.find('input[data-reset-on-edit]').on('keyup', function() { - $(this.getAttribute('data-reset-on-edit')).val(''); - }); - - /** - * Pagination - */ - $container.find('.pagination .page-jump-form :button').click(function() { - var $input = $(this).siblings('input.inputbox'); - pageJump($input); - }); - - $container.find('.pagination .page-jump-form input.inputbox').on('keypress', function(event) { - if (event.which === 13 || event.keyCode === 13) { - event.preventDefault(); - pageJump($(this)); - } - }); - - $container.find('.pagination .dropdown-trigger').click(function() { - var $dropdownContainer = $(this).parent(); - // Wait a little bit to make sure the dropdown has activated - setTimeout(function() { - if ($dropdownContainer.hasClass('dropdown-visible')) { - $dropdownContainer.find('input.inputbox').focus(); - } - }, 100); - }); - - /** - * 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'); - // } - - /** - * Resize navigation (breadcrumbs) block to keep all links on same line - */ - $container.find('.navlinks').each(function() { - var $this = $(this), - $left = $this.children().not('.rightside'), - $right = $this.children('.rightside'); - - if ($left.length !== 1 || !$right.length) { - return; - } - - function resize() { - var width = 0, - diff = $left.outerWidth(true) - $left.width(), - minWidth = Math.max($this.width() / 3, 240), - maxWidth; - - $right.each(function() { - var $this = $(this); - if ($this.is(':visible')) { - width += $this.outerWidth(true); - } - }); - - maxWidth = $this.width() - width - diff; - $left.css('max-width', Math.floor(Math.max(maxWidth, minWidth)) + 'px'); - } - - resize(); - $(window).resize(resize); - }); - - /** - * Makes breadcrumbs responsive - */ - $container.find('.breadcrumbs:not([data-skip-responsive])').each(function() { - var $this = $(this), - $links = $this.find('.crumb'), - length = $links.length, - classes = ['wrapped-max', 'wrapped-wide', 'wrapped-medium', 'wrapped-small', 'wrapped-tiny'], - classesLength = classes.length, - maxHeight = 0, - lastWidth = false, - wrapped = false; - - // Set tooltips - $this.find('a').each(function() { - var $link = $(this); - $link.attr('title', $link.text()); - }); - - // Function that checks breadcrumbs - function check() { - var height = $this.height(), - width; - - // Test max-width set in code for .navlinks above - width = parseInt($this.css('max-width'), 10); - if (!width) { - width = $body.width(); - } - - maxHeight = parseInt($this.css('line-height'), 10); - $links.each(function() { - if ($(this).height() > 0) { - maxHeight = Math.max(maxHeight, $(this).outerHeight(true)); - } - }); - - if (height <= maxHeight) { - if (!wrapped || lastWidth === false || lastWidth >= width) { - return; - } - } - lastWidth = width; - - if (wrapped) { - $this.removeClass('wrapped').find('.crumb.wrapped').removeClass('wrapped ' + classes.join(' ')); - if ($this.height() <= maxHeight) { - return; - } - } - - wrapped = true; - $this.addClass('wrapped'); - if ($this.height() <= maxHeight) { - return; - } - - for (var i = 0; i < classesLength; i++) { - for (var j = length - 1; j >= 0; j--) { - $links.eq(j).addClass('wrapped ' + classes[i]); - if ($this.height() <= maxHeight) { - return; - } - } - } - } - - // Run function and set event - check(); - $(window).resize(check); - }); - - /** - * Responsive link lists - */ - var selector = '.linklist:not(.navlinks, [data-skip-responsive]),' + - '.postbody .post-buttons:not([data-skip-responsive])'; - $container.find(selector).each(function() { - var $this = $(this), - filterSkip = '.breadcrumbs, [data-skip-responsive]', - filterLast = '.edit-icon, .quote-icon, [data-last-responsive]', - $linksAll = $this.children(), - $linksNotSkip = $linksAll.not(filterSkip), // All items that can potentially be hidden - $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 = '', - slack = 3; // Vertical slack space (in pixels). Determines how sensitive the script is in determining whether a line-break has occurred. - - // Add a hidden drop-down menu to each links list (except those that already have one) - if (!persistent) { - if ($linksNotSkip.is('.rightside')) { - $linksNotSkip.filter('.rightside:first').before(html); - $this.children('.responsive-menu').addClass('rightside'); - } else { - $this.append(html); - } - } - - // Set some object references and initial states - var $menu = $this.children('.responsive-menu'), - $menuContents = $menu.find('.dropdown-contents'), - persistentContent = $menuContents.find('li:not(.separator)').length, - lastWidth = false, - compact = false, - responsive1 = false, - responsive2 = false, - copied1 = false, - copied2 = false, - maxHeight = 0; - - // Find the tallest element in the list (we assume that all elements are roughly the same height) - $linksAll.each(function() { - if (!$(this).height()) { - return; - } - maxHeight = Math.max(maxHeight, $(this).outerHeight(true)); - }); - if (maxHeight < 1) { - return; // Shouldn't be possible, but just in case, abort - } else { - maxHeight = maxHeight + slack; - } - - function check() { - var width = $body.width(); - // We can't make it any smaller than this, so just skip - if (responsive2 && compact && (width <= lastWidth)) { - return; - } - lastWidth = width; - - // Reset responsive and compact layout - if (responsive1 || responsive2) { - $linksNotSkip.removeClass('hidden'); - $menuContents.children('.clone').addClass('hidden'); - responsive1 = responsive2 = false; - } - if (compact) { - $this.removeClass('compact'); - compact = false; - } - - // Unhide the quick-links menu if it has "persistent" content - if (persistent && persistentContent) { - $menu.removeClass('hidden'); - } else { - $menu.addClass('hidden'); - } - - // Nothing to resize if block's height is not bigger than tallest element's height - if ($this.height() <= maxHeight) { - return; - } - - // STEP 1: Compact - if (!compact) { - $this.addClass('compact'); - compact = true; - } - if ($this.height() <= maxHeight) { - return; - } - - // STEP 2: First responsive set - compact - if (compact) { - $this.removeClass('compact'); - compact = false; - } - // Copy the list items to the dropdown - if (!copied1) { - var $clones1 = $linksFirst.clone(); - $menuContents.prepend($clones1.addClass('clone clone-first').removeClass('leftside rightside')); - - if ($this.hasClass('post-buttons')) { - $('.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; - } - if (!responsive1) { - $linksFirst.addClass('hidden'); - responsive1 = true; - $menuContents.children('.clone-first').removeClass('hidden'); - $menu.removeClass('hidden'); - } - if ($this.height() <= maxHeight) { - return; - } - - // STEP 3: First responsive set + compact - if (!compact) { - $this.addClass('compact'); - compact = true; - } - if ($this.height() <= maxHeight) { - return; - } - - // STEP 4: Last responsive set - compact - if (!$linksLast.length) { - return; // No other links to hide, can't do more - } - if (compact) { - $this.removeClass('compact'); - compact = false; - } - // Copy the list items to the dropdown - if (!copied2) { - var $clones2 = $linksLast.clone(); - $menuContents.prepend($clones2.addClass('clone clone-last').removeClass('leftside rightside')); - copied2 = true; - } - if (!responsive2) { - $linksLast.addClass('hidden'); - responsive2 = true; - $menuContents.children('.clone-last').removeClass('hidden'); - } - if ($this.height() <= maxHeight) { - return; - } - - // STEP 5: Last responsive set + compact - if (!compact) { - $this.addClass('compact'); - compact = true; - } - } - - if (!persistent) { - 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).on('load', function() { - check(); - }); - }); - - check(); - $(window).resize(check); - }); - - /** - * Do not run functions below for old browsers - */ - if (oldBrowser) { - return; - } - - /** - * Adjust topiclist lists with check boxes - */ - $container.find('ul.topiclist dd.mark').siblings('dt').children('.list-inner').addClass('with-mark'); - - /** - * Appends contents of all extra columns to first column in - * .topiclist lists for mobile devices. Copies contents as is. - * - * To add that functionality to .topiclist list simply add - * responsive-show-all to list of classes - */ - $container.find('.topiclist.responsive-show-all > li > dl').each(function() { - var $this = $(this), - $block = $this.find('dt .responsive-show:last-child'), - first = true; - - // Create block that is visible only on mobile devices - if (!$block.length) { - $this.find('dt > .list-inner').append('
- -
-
- - - - -
-
- -
    - - - - - -
  • - -
    -
    - -
    - - - - - - {forumrow.FORUM_IMAGE} - - - {forumrow.FORUM_NAME} -
    {forumrow.FORUM_DESC} - -
    {forumrow.L_MODERATOR_STR}{L_COLON} {forumrow.MODERATORS} - - - -
    {forumrow.L_SUBFORUM_STR}{L_COLON} - - - {forumrow.subforum.SUBFORUM_NAME}{L_COMMA_SEPARATOR} - - - - - - - -
    -
    - -
    {L_REDIRECTS}{L_COLON} {forumrow.CLICKS}
    - -
    {forumrow.TOPICS} {L_TOPICS}
    -
    {forumrow.POSTS} {L_POSTS}
    -
    - - - - {L_TOPICS_UNAPPROVED} - - - - {L_POSTS_UNAPPROVED_FORUM} - - - - {L_LAST_POST} - - - {forumrow.LAST_POST_SUBJECT_TRUNCATED}
    - - {L_POST_BY_AUTHOR} {forumrow.LAST_POSTER_FULL} - - - {L_VIEW_LATEST_POST} - - -
    - - {% if forumrow.U_UNAPPROVED_TOPICS %} - {{ lang('TOPIC_UNAPPROVED_FORUM', forumrow.TOPICS) }} - {% else %} - {{ lang('NO_POSTS') }} - {% endif %} - -
    -
    - -
     
    - -
    - -
  • - - - - -
- -
-
- - - - -
-
- {L_NO_FORUMS} -
-
- diff --git a/install/update/new/styles/prosilver/template/mcp_forum.html b/install/update/new/styles/prosilver/template/mcp_forum.html deleted file mode 100644 index 82df5d5..0000000 --- a/install/update/new/styles/prosilver/template/mcp_forum.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - -

{L_FORUM}{L_COLON} {FORUM_NAME}

- -
- -
-
- -
- -
- - -
    -
  • -
    -
    {L_TOPICS}
    -
    {L_REPLIES}
    -
    {L_LAST_POST}
    -
    {L_MARK}
    -
    -
  • -
-
    - - -
  • -
    -
    style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"> - -
    - - [ {L_SELECT_MERGE} ]   - - {topicrow.TOPIC_TITLE} - - - - {L_TOPIC_UNAPPROVED} - - - - - {L_TOPIC_DELETED} - - - - - {L_TOPIC_REPORTED} - - -  [ {L_DELETE_SHADOW_TOPIC} ] -
    - - - - - - - - -
    - - {% EVENT topiclist_row_topic_by_author_before %} - {L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} » {topicrow.FIRST_POST_TIME} - {% EVENT topiclist_row_topic_by_author_after %} -
    - -
    -
    -
    {topicrow.REPLIES} {L_REPLIES}
    -
    {L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
    {topicrow.LAST_POST_TIME}
    - -
    - checked="checked" />  -
    - -
    -
  • - -
- -
    -
  • {L_NO_TOPICS}

  • -
- - -
- - - -
- -
-
- - -
- - - - - - {S_FORM_TOKEN} -
- -
- - diff --git a/install/update/new/styles/prosilver/template/mcp_move.html b/install/update/new/styles/prosilver/template/mcp_move.html deleted file mode 100644 index 63197ef..0000000 --- a/install/update/new/styles/prosilver/template/mcp_move.html +++ /dev/null @@ -1,73 +0,0 @@ - - -

{MESSAGE_TITLE}

-

{MESSAGE_TEXT}

- -

{ADDITIONAL_MSG}

- - - - - - - - - - - -
-   - -
- - - - - - - -
- -
-
- -
-

{MESSAGE_TITLE}

-

{ADDITIONAL_MSG}

- -
- {% EVENT mcp_move_destination_forum_before %} -
-
-
-
-
-
- {% EVENT mcp_move_destination_forum_after %} -
-
 
-
{MESSAGE_TEXT}
-
-
- -
- {S_HIDDEN_FIELDS}  - - {S_FORM_TOKEN} -
- -
- -
-
-
- - - diff --git a/install/update/new/styles/prosilver/template/mcp_topic.html b/install/update/new/styles/prosilver/template/mcp_topic.html deleted file mode 100644 index 889cab8..0000000 --- a/install/update/new/styles/prosilver/template/mcp_topic.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - -
- -
-
- -
-
-

{L_POSTS_PER_PAGE_EXPLAIN}
-
-
-
-
-
{S_SELECT_SORT_DAYS}  
-
-
- - -
-

{L_SPLIT_TOPIC_EXPLAIN}

- - -
-
-
-
-
- - - -
-
-
-
- -
-
-
-
-
- - - -
-

{L_MERGE_TOPIC_EXPLAIN}

-
-
-
- - {L_SELECT_TOPIC} -
-
{TO_TOPIC_INFO}
-
-
- - -
-
- -
-
- -

- {L_EXPAND_VIEW} - {L_TOPIC_REVIEW}{L_COLON} {TOPIC_TITLE} -

- -
- - -
-
- -
- - - -

{postrow.POST_SUBJECT}

- - - -

- - {postrow.MINI_POST} - {L_POSTED} {postrow.POST_DATE} {L_POST_BY_AUTHOR} {% EVENT mcp_topic_post_author_full_prepend %}{postrow.POST_AUTHOR_FULL}{% EVENT mcp_topic_post_author_full_append %} [ {L_POST_DETAILS} ] -

- - - -

- {L_POST_UNAPPROVED} -

- - - -

- {L_POST_DELETED} -

- - - -

- {L_POST_REPORTED} -

- - -
{postrow.MESSAGE}
- - - - -
-
{L_ATTACHMENTS}
- -
{postrow.attachment.DISPLAY_ATTACHMENT}
- -
- - - - -
- -
-
- -
- -
- -
- -
- -
-
- -
-   - - -{S_HIDDEN_FIELDS} -{S_FORM_TOKEN} -
- -
- - diff --git a/install/update/new/styles/prosilver/template/memberlist_body.html b/install/update/new/styles/prosilver/template/memberlist_body.html deleted file mode 100644 index b8ff092..0000000 --- a/install/update/new/styles/prosilver/template/memberlist_body.html +++ /dev/null @@ -1,190 +0,0 @@ - - - -
- - - - - - - - -{% EVENT memberlist_body_page_header_after %} - - - {% EVENT memberlist_body_group_name_before %} -

style="color:#{GROUP_COLOR};">{GROUP_NAME}

- {% EVENT memberlist_body_group_name_after %} - -

{L_MANAGE_GROUP}

- -

{GROUP_DESC} {GROUP_TYPE}

- - {% EVENT memberlist_body_group_desc_after %} - -

- {AVATAR_IMG} - {% 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 %} -

- - {% EVENT memberlist_body_page_title_before %} -

{PAGE_TITLE}{L_COLON} {SEARCH_WORDS}

- -
- - - -
- - - -
-
- - - - - - - - - - {% EVENT memberlist_body_memberlist_after %} - - - - - - - - - - - - - - -
{L_RANK}{L_GROUP_LEADER}{L_USERNAME}{L_POSTS}{L_COMMA_SEPARATOR} {custom_fields.PROFILE_FIELD_NAME}{L_JOINED}{L_LAST_ACTIVE}
 
- -
-
- -
-
- - - - - - - - - - - {% EVENT memberlist_body_leaders_set_after %} - - - - - - - {% EVENT memberlist_body_show_group_after %} - - - - - - - - - - - - - - - {% EVENT memberlist_body_memberrow_after %} - - - - - - - -
{L_RANK}{L_GROUP_MEMBERS}{L_USERNAME}{L_POSTS}{% for field in custom_fields %}{% if not loop.first %}{L_COMMA_SEPARATOR} {% endif %}{{ field.PROFILE_FIELD_NAME }}{% endfor %}{L_JOINED}{L_LAST_ACTIVE}{L_GROUP_MEMBERS}{L_POSTS}{L_COMMA_SEPARATOR} {custom_fields.PROFILE_FIELD_NAME}{L_JOINED}{L_LAST_ACTIVE}
{memberrow.RANK_IMG}{memberrow.RANK_TITLE} {memberrow.USERNAME_FULL} ({L_INACTIVE})
{L_SELECT} ]
{memberrow.POSTS}{memberrow.POSTS} - {%- for field in memberrow.custom_fields -%} - - {%- else -%} -   - {%- endfor -%} - {memberrow.JOINED}{memberrow.LAST_ACTIVE} 
{L_NO_MEMBERS}
- -
-
- - -
- - -
- - - -
-
- - - -
- - - -
- - -
- -
- -
- -{% EVENT memberlist_body_page_footer_before %} - - - - - - - diff --git a/install/update/new/styles/prosilver/template/memberlist_search.html b/install/update/new/styles/prosilver/template/memberlist_search.html deleted file mode 100644 index 34915eb..0000000 --- a/install/update/new/styles/prosilver/template/memberlist_search.html +++ /dev/null @@ -1,87 +0,0 @@ -

{L_FIND_USERNAME}

- -
-
-
- -

{L_FIND_USERNAME_EXPLAIN}

- - -
-
-
-
- - -
-
- -
-
-
-
- - -
-
-
-
- -
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- - -
- -
- -
- -
-   - - {S_FORM_TOKEN} -
- -
-
- -
diff --git a/install/update/new/styles/prosilver/template/navbar_header.html b/install/update/new/styles/prosilver/template/navbar_header.html deleted file mode 100644 index 4a1a436..0000000 --- a/install/update/new/styles/prosilver/template/navbar_header.html +++ /dev/null @@ -1,212 +0,0 @@ - diff --git a/install/update/new/styles/prosilver/template/overall_footer.html b/install/update/new/styles/prosilver/template/overall_footer.html deleted file mode 100644 index d1b8863..0000000 --- a/install/update/new/styles/prosilver/template/overall_footer.html +++ /dev/null @@ -1,120 +0,0 @@ - -
- - - - - -
- -
- - {RUN_CRON_TASK} -
- - - - - - - - - - - - - - - - - - -{$SCRIPTS} - - - - - diff --git a/install/update/new/styles/prosilver/template/overall_header.html b/install/update/new/styles/prosilver/template/overall_header.html deleted file mode 100644 index 2867802..0000000 --- a/install/update/new/styles/prosilver/template/overall_header.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - -{META} -<!-- 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 --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{$STYLESHEETS} - - - - - - - - -
- - - - - - -
- -
-
- {L_INFORMATION}{L_COLON} {L_BOARD_DISABLED} -
-
- - - diff --git a/install/update/new/styles/prosilver/template/plupload.html b/install/update/new/styles/prosilver/template/plupload.html deleted file mode 100644 index 9425b7d..0000000 --- a/install/update/new/styles/prosilver/template/plupload.html +++ /dev/null @@ -1,75 +0,0 @@ - - - diff --git a/install/update/new/styles/prosilver/template/posting_attach_body.html b/install/update/new/styles/prosilver/template/posting_attach_body.html deleted file mode 100644 index 0363fe0..0000000 --- a/install/update/new/styles/prosilver/template/posting_attach_body.html +++ /dev/null @@ -1,93 +0,0 @@ -
-
- -

{L_ADD_ATTACHMENT_EXPLAIN}

- -
-
-
-
- - -
-
-
-
-
-
-
- -
- -
- - {% EVENT posting_attach_body_file_list_before %} -
-
- - - - - - - - - - - - - - - - - {% EVENT posting_attach_body_attach_row_before %} - - {% EVENT posting_attach_body_attach_row_prepend %} - - - - - - - {% EVENT posting_attach_body_attach_row_append %} - - {% EVENT posting_attach_body_attach_row_after %} - -
{L_PLUPLOAD_FILENAME}{L_FILE_COMMENT}{L_PLUPLOAD_SIZE}{L_PLUPLOAD_STATUS}
- - - {% if S_BBCODE_ALLOWED %} {% endif %} - - - - - - - - - - - - -
- {attach_row.FILENAME} - {% EVENT posting_attach_body_attach_row_controls_prepend %} - - {% if S_BBCODE_ALLOWED and S_INLINE_ATTACHMENT_OPTIONS %} {% endif %} - - - {% EVENT posting_attach_body_attach_row_controls_append %} - - - - {attach_row.S_HIDDEN} - - {attach_row.FILESIZE} - - -
-
-
- {% EVENT posting_attach_body_file_list_after %} -
-
diff --git a/install/update/new/styles/prosilver/template/posting_buttons.html b/install/update/new/styles/prosilver/template/posting_buttons.html deleted file mode 100644 index 1564b5f..0000000 --- a/install/update/new/styles/prosilver/template/posting_buttons.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/install/update/new/styles/prosilver/template/posting_layout.html b/install/update/new/styles/prosilver/template/posting_layout.html deleted file mode 100644 index 7c9deb5..0000000 --- a/install/update/new/styles/prosilver/template/posting_layout.html +++ /dev/null @@ -1,65 +0,0 @@ - - - -

{TOPIC_TITLE}

- -

{FORUM_NAME}

- - - -
-
- - - {L_FORUM_RULES} - - {L_FORUM_RULES}
- {FORUM_RULES} - - -
-
- - -
- - -
-
- -

{L_INFORMATION}

-

{L_DRAFT_LOADED}

- -
-
- - - - - - - - -
-
- -

{L_POST_A}

- - - - - {S_FORM_TOKEN} -
-
- - - - - - - - - -
- - diff --git a/install/update/new/styles/prosilver/template/posting_poll_body.html b/install/update/new/styles/prosilver/template/posting_poll_body.html deleted file mode 100644 index 7956496..0000000 --- a/install/update/new/styles/prosilver/template/posting_poll_body.html +++ /dev/null @@ -1,53 +0,0 @@ -
-
- - -

{L_ADD_POLL_EXPLAIN}

- - -
- -
-
-
-
- - - -
-
-
-
-
-

{L_POLL_OPTIONS_EXPLAIN}
-
-
- -
- -
-
-
-
{L_POLL_MAX_OPTIONS_EXPLAIN}
-
-
-
-
-
{L_POLL_FOR_EXPLAIN}
-
- - -
- -
-
-
-
- - - - -
- -
-
diff --git a/install/update/new/styles/prosilver/template/posting_review.html b/install/update/new/styles/prosilver/template/posting_review.html deleted file mode 100644 index e5d285e..0000000 --- a/install/update/new/styles/prosilver/template/posting_review.html +++ /dev/null @@ -1,44 +0,0 @@ -

{L_POST_REVIEW}

- -

{L_POST_REVIEW_EXPLAIN}

- - - -
-
- {post_review_row.L_IGNORE_POST} - -
-
- - -
-

{post_review_row.POST_SUBJECT}

-

- - {post_review_row.MINI_POST} - - - {post_review_row.MINI_POST} - - - {L_POST_BY_AUTHOR} {post_review_row.POST_AUTHOR_FULL} » {post_review_row.POST_DATE} -

-
{post_review_row.MESSAGE}
- - -
-
{L_ATTACHMENTS}
- -
{post_review_row.attachment.DISPLAY_ATTACHMENT}
- -
- - -
- -
-
- - -
diff --git a/install/update/new/styles/prosilver/template/posting_topic_review.html b/install/update/new/styles/prosilver/template/posting_topic_review.html deleted file mode 100644 index 209dadf..0000000 --- a/install/update/new/styles/prosilver/template/posting_topic_review.html +++ /dev/null @@ -1,89 +0,0 @@ - -

- {L_EXPAND_VIEW} - {L_TOPIC_REVIEW}{L_COLON} {TOPIC_TITLE} -

- -
- - - - -
-
- {topic_review_row.L_IGNORE_POST} - -
-
- {topic_review_row.L_DELETE_POST} - -
-
- - -
-

{topic_review_row.POST_SUBJECT}

- - - - - - -

- - {topic_review_row.MINI_POST} - - - {topic_review_row.MINI_POST} - - - {L_POST_BY_AUTHOR} {topic_review_row.POST_AUTHOR_FULL} » {topic_review_row.POST_DATE} -

- - -
{topic_review_row.MESSAGE}
- - - - -
-
{L_ATTACHMENTS}
- -
{topic_review_row.attachment.DISPLAY_ATTACHMENT}
- -
- - - - - -
-
-
- -
- -
- -

- - {L_BACK_TO_TOP} - -

diff --git a/install/update/new/styles/prosilver/template/search_results.html b/install/update/new/styles/prosilver/template/search_results.html deleted file mode 100644 index 9ee13a4..0000000 --- a/install/update/new/styles/prosilver/template/search_results.html +++ /dev/null @@ -1,244 +0,0 @@ - - - - -

{SEARCH_TITLE}{SEARCH_MATCHES}{L_COLON} {SEARCH_WORDS}

-

{L_SEARCHED_QUERY}{L_COLON} {SEARCHED_QUERY}

-

{L_IGNORED_TERMS}{L_COLON} {IGNORED_WORDS}

-

{L_PHRASE_SEARCH_DISABLED}

- - - - - - - - - - -
- - - - - - - - -
- - - - - -
- -
-
    -
  • -
    -
    {L_TOPICS}
    -
    {L_REPLIES}
    -
    {L_VIEWS}
    -
    {L_LAST_POST}
    -
    -
  • -
- - -
-
- -
-
- {L_NO_SEARCH_RESULTS} -
-
- - - - - - -
-
- - -
- {searchresults.L_IGNORE_POST} -
- -
- -
{L_POST_BY_AUTHOR} {searchresults.POST_AUTHOR_FULL}
-
{searchresults.POST_DATE}
-
{L_FORUM}{L_COLON} {searchresults.FORUM_TITLE}
-
{L_TOPIC}{L_COLON} {searchresults.TOPIC_TITLE}
- -
{L_REPLIES}{L_COLON} {searchresults.TOPIC_REPLIES}
-
{L_VIEWS}{L_COLON} {searchresults.TOPIC_VIEWS}
- -
- -
-

{searchresults.POST_SUBJECT}

-
{searchresults.MESSAGE}
- -
- - - - - - -
-
- - -
-
- {L_NO_SEARCH_RESULTS} -
-
- - - -
- -
- -
- - - -
- - - - diff --git a/install/update/new/styles/prosilver/template/simple_footer.html b/install/update/new/styles/prosilver/template/simple_footer.html deleted file mode 100644 index fde162a..0000000 --- a/install/update/new/styles/prosilver/template/simple_footer.html +++ /dev/null @@ -1,40 +0,0 @@ -
- - - -
-
 
-
-
- -
- - - -

-
-
- - - -
-
-
- - - - - - - - - -{$SCRIPTS} - -{% EVENT simple_footer_body_after %} - - - diff --git a/install/update/new/styles/prosilver/template/ucp_agreement.html b/install/update/new/styles/prosilver/template/ucp_agreement.html deleted file mode 100644 index 7959925..0000000 --- a/install/update/new/styles/prosilver/template/ucp_agreement.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - -
-

- - {S_HIDDEN_FIELDS} -

-
- -
- - - -
- -
-
-
-

{SITENAME} - {L_REGISTRATION}

- -

{L_COPPA_BIRTHDAY}{L_TERMS_OF_USE}

- -
-
-
- -
-
-
- - - - -   - - - {S_HIDDEN_FIELDS} - {S_FORM_TOKEN} -
-
-
-
- - - -
-
-
-

{SITENAME} - {AGREEMENT_TITLE}

-

{AGREEMENT_TEXT}

-
-
-
- - - - diff --git a/install/update/new/styles/prosilver/template/ucp_attachments.html b/install/update/new/styles/prosilver/template/ucp_attachments.html deleted file mode 100644 index cfdbf9c..0000000 --- a/install/update/new/styles/prosilver/template/ucp_attachments.html +++ /dev/null @@ -1,83 +0,0 @@ - - -
- -

{L_TITLE}

- -
-
- -

{L_ATTACHMENTS_EXPLAIN}

- - -
- -
- - - - -
- - {S_FORM_TOKEN} - - -
- - -

{L_UCP_NO_ATTACHMENTS}

- - -
-
- - -
- - - {S_FORM_TOKEN} -
- -
- - diff --git a/install/update/new/styles/prosilver/template/ucp_avatar_options_upload.html b/install/update/new/styles/prosilver/template/ucp_avatar_options_upload.html deleted file mode 100644 index 666950e..0000000 --- a/install/update/new/styles/prosilver/template/ucp_avatar_options_upload.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
-
-
- - -
-

{L_UPLOAD_AVATAR_URL_EXPLAIN}
-
-
- diff --git a/install/update/new/styles/prosilver/template/ucp_groups_manage.html b/install/update/new/styles/prosilver/template/ucp_groups_manage.html deleted file mode 100644 index adc8c61..0000000 --- a/install/update/new/styles/prosilver/template/ucp_groups_manage.html +++ /dev/null @@ -1,247 +0,0 @@ - - - style="color:#{GROUP_COLOR};">{L_USERGROUPS} :: {GROUP_NAME}

0g=km}BV_+zW4k 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 N002ovPDHLkV1n_zTSEW< diff --git a/images/avatars/gallery/Flics/Flic_62.png b/images/avatars/gallery/Flics/Flic_62.png deleted file mode 100644 index 354fac55d7101dbb7f3ebe3d96714e2a7a62ecc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27674 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%0D840^jMWzA!vgp#{EvZ-A{F1Pqq%; z9t$hy82zqcX{2DKX=DOb>)YlUDB>tgL6hYW=r~zzKCu9qq)=)| z39M8u^Ctv0j#q)z0PC^hJTW4HyVH2O#>%&n3|OT>NqXkd&pHHmo+azKqe>f#>S}H) zYg4P>WzMI+i^Sp$JAJJ7q@`Jg=k&XVO+yQ18{_2w6Vs9dNzE!!+jFQ6OdVI~xK9RA z=eL=GvkH$q6R0dE$7F!L5!!!TQu>T&wD;3bJl z49k8l^rIJi!;h0~9p>%{E4JN!*RZ3JC>6kVs)}MyVzs&bbqgy4%-~@QIF94M@jTdW zj(?jOL@8JTTFQ%&!DDpkIJrQuN!Pb7T`0)~4v}oqoVL=y(#Tx2!&(>3s^>R!lj*); z_dwm<6neKkbEVWV30Tl>!*8|HY_~Lcsgov|lcfO4Ub$Z3n_jN?%RH4w<1pUh>ULjP z?(%HEYuMRPh*Ycj5+R#m6CEcXJ+UhGR9SMM0+MArJXDXF(}2m}0-QjUWFk+my#S^2 zMg3m&WkeUi$u@vZR{d~0VOci&po>DeqFqlQ^ZgEZO??#@lgu40%Q@|N`IorQiQM0# zoWUxc`c}Vd*wK)V*i4LN6-70+;PK9VIXL-Gy0QRd*|r8tpmJPKAHG50v^!<)7K@nT zu-{7>sL+imN*j|jIookyy9BRP*5E~9pkbRocUA+)@m?G!x%C`v&DLlJ~s_k-0ym?Miw3Lg0_#4 z&K8S_C9%nW>^%=!6z}mBTp0UkYVRE@I4HO_8h(tHGU#GC4cS$&c6k^Ef*?Q=MJRaA zyzAyZ4a0i1-(_8HSp6-kI3IXQAqI{VwZrW6(g$G4GUhiBBi|M

kAP9T}y%2uaR}XWg9Gsl3AQa_~ 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 diff --git a/images/avatars/gallery/Flics/Flic_21.png b/images/avatars/gallery/Flics/Flic_21.png deleted file mode 100644 index 261356c3ff26744eb71acf8b32ea3123109e3c9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28582 zcmaf3<69-r)~_bpc9U(}o-j4pKKW$Zn(Uf1**e)aPPUE7HNA81{R7@ldw*EZewNqT zzqO*ismP)r5+XuCK%mIWNvZ!k*C8MvA>d*E-2_m+;6p$-+RICcYkERnr253>EO`xY zU*}wNG~zXGHBT8%TCmIa2EwB|k-$Sj$;qL7|6P%Y{@wnwfEq#hSChhmsIIi_o6)EB zcj<~OP1{tNYD((zHHI3AfuSnpz2-P}K4?Hl?T#McqS@o9(!;9zKF@XQ*pKPDD8JYt?b7Suv6{Sr>DSjegLpL(1t-<`ef4t9(ooRxbm$dS zY;0Og>}qVR%TM;~BsCQdOHPh)`C)*J4F6ch)F>S-K_dad;a4*rs-hh8NlWvTgN0b9) zHTu<{&|*?czZw!8+|k!%Ox1=Od2#I#y#1vII@uU$1qL<53>3o)(jNv4%|o=IY(QOo z@d!d&$mwHAMRJ%i-tUqgcM^qj3f?p0Xnce=yO{^YnAp)Zk7-G!(OhEtT z3I-!{aYA_*@Diy}1})S3Wd}o@o=2*hb49{*KhAPPnc+bt_;SaKO`HLS6~gFA+^sQo zb&Xb~4pKd8NO>Be5kp^c96~};8SvT{>$byLtnNs(g2)phxx)b=!rKr#t76_9T9UJ@djSV;LzT%+P@+>^Dmd1FF?Tf8;xpm4EGs(hPPB z_JpsyT@D=K;M;T$A~F7%a_bLM3dCD4=diTXr*=YG5o73bfY~pO1*7O9kd8icd*XFM zwgiJYrcYTKlK)sfR?~7^T2}{fG zhRy_kbq^H#)c^WZuL^UM`1~l_9yAe*?>DqypI%#a1WRsRJZ;ROTO3iV!#NNi5k2AB zIE?z~@bLbiPyA7=HiboZNj}Qen6o}Z>NsE7)oqP@%fygDE2cgQ&rgn3KjYX%uQ5x! zoyYpH0#b0hDWkNSl0W|R_vN!G8fD=&S~F#LEhA{hp!8ncI;0#3t8(#uw}0+<#06gi z*P6ru{xBv%U)!}6OPyt@y_w* zs?TMjCo~A|IWpgXxq=RWehfTCh)WYiiPXb*g;=GF@)7?%x8zBTXtm|2E?7Q+#q{GRKfZc)5=;>&+g)g z7TA!7Evo|+gX?1xg0>;cdZ9g0-yt-Cc&iL<9jjVHYJVQSBIY*%WIdQ0CGrvzH19*u z#~P}pv>303AYo}aSV}(VwtRL3K}dG1u*?)d@a*)24@1yKc1lz-bMRb+ zf8>*a&tDXJdCZ^ch&B@@8{qWY%3R})E0AuXL-*-hZ#tHOH)W54GclEVbP}b$46%%+ zan23C)sSp+z6P z2lc%~Pu`Ye-F-fE;t#6sPRmuQ5ZUp!UCkZF_8ms#!vj7I2^AwqFExLHaVu1_=_t# zS*aw;AlsIc5H0{##tpn03z`Ce6G17vG5!;%k`>basVp5b%<4xK&ybU81wv*#X^9*b zkiy7$u+*DwgpC-fec;~kmrp<+KxCeIaeL#!uTx3+jbSyd3%uC7tEqS3pnt>UDdo`| zSCKvW$oEWqbM(Q;!Y*Sb8&umdT}2#Ingq~aXuzXMNDMA+qL=?UB*G8h4Jq=g<3MJS z*-}r{_6&vfks>cM$w-+<-wLEdfLHOGT1~^x3#puj1oKyo>k33S)GJWCOVcf6RV!E& znyB_!p34nW8XJ#%v#t7_{HrK(deV*>7$m4NC3S(IZ;>4Oz_MXy(hynHQMY;q#Xouq8AtJUH}`3jRFqR=R4b1QFs#`W@>9Z zT9Ccq)YlHUzxclT{~<5Sx-`6@o?RGCe{os02Jji|J(?DM4=KpBJhw)mFlhy{$&0q!FpoOpY7|DygDp8CvnWX?)v7$T+uGw&EG{Nf0jTayv$mrip8CureXZMRKaGyg zBDOHQmKfE_`@nx@Xyf0`U1YUMh&`_g%wXe>$#Zg%0;zk3pX@s;8?Q8|0{2-=+Pdq5t zfSP}pt)4^wZt>$()GW)G`Z5zNx|5~%^dr>)H_K3ZqGV&0de#~WvUqy$0+ zp!F^UXO|+J9-kwiEb8ec=yz?Ucd8wckc86cQeK!L_pp40ES&+Y(@XD@uZil`fBZgBFSOjG2gEfw~M5-ycGmIb>+U;);89=K} zjDOO1oNJoxD}Q@ZMMcGUF0|?`QkZ!Eh1<36yQ za`_{@nufOVnL=@l1440Jh^|Ur?k^Ib?Gjt`d6a?5-?jP*C?jcllXQUMpXalg_jo5G zdLHv0pB|iD&O7i~#N|*`kEP?C3Nv_bF2bySQ{qlso5(FeU)mi#NpV&It${s|WDai% z)*=qD4&tc}FTDHj^yD@m!r96xE=>8%^VPfNc#CUVvETRj(bhcOakPE;!Rii`cZz>pvA2E# zT$05604+nD!n_~Qot1XCzcS;7*gx%Wn0F4k1!SCm4r0H4cQI};Z*kLXjEtEaq{(DY z4l$yF`<=!b7OFu!np9r6t^tbhx7M=R>s!nxhm-s;p_GRh&5*o*t;_h9V)f}-% zE?Q9;NSRd)_4kVqJn5LvEl_t~bo)s@n4`48j+%Q+3Xl5dWY#JlA)Oso^!%GpFT{ zdLdl%5b7KWxfa8bQV~7%9vt-qoH7)xY`OHTk`}k7nQI>UcJq8qS4__GsgRNOlLa|` z(PFya-(V25Q(0c-3%~u2ZB2CNkIVi1vi&7#nv3>3Y#TT6Vq~J*S*9I zI=MJJ`0NUIOQB9xW1&etYPpA(&9+Y99r$ie)fU0QKjLVfOH7s^Rg+ zjDejIs6v}(?1-ai&RS+YRwny!g>X#5SPWxl5H@y2%$N!uipn|BS4jkVbmXg;@xWZf zs0wj_8nT{*Idu}HbQ%^jXHkz#qg^;B@s)XUm!>w@{e0Qr?~K=V*Y~9*q-=BE7=r=H zyqb>gr_SrQ_vs?(ozsmF;7K2~ud?WY`)yWD<+e}c`D8$!uiM7Gk_4Ft+uJdm;T1@4>25JU)Ff>(zqyFEPgKFrtIe{OA zmBKp|ZyI0S=}E`xFG@!&=~-wApfMs>2n6Ovdo28|HttvGC!O(}B5rvnKYQP4Cx>#$ z5D;_|P9Hs3?X&4hG=xOV7mM$Qdu4SaXTn3-6KAKJN8z7(D86!|Og9(0es^vA;NypH z{o8)5AeB=3`jd32{{gApL-?xv`mGK?RB9ofP|GPWc};0MylwV)^@e#x6;B9IJ_<1J zo_;4e!h3T?7hf2{w%#(XwwSnU32U+;Z~L-h9s-wWU5{&qfJ#QYeY9fhYl#obL>(KN zn4{?J|9*Z8E_3Q+-cA`o87RQYhNIm02sep#!U87@+GiXYhj-#thi$|p479bMguqgn z{lT-auC_pvxKi%zH2Au*j`-{};V&22*lr+uS#MEh-nF%J_}TyNdQ|e(V(oz;i^3BH zd!Ie2ohfSkm&If63slyzdupPYUR0|>h|S3x=?0t9gTEL$l)D2( zLwOorC=p8-8p1f{GjpIk>%xn^*dg+G`J^wk^&Wmmc7J}~MspxnGFk5y4RlU1Nmf4d zGB}1I&D$^aOF;S;jqlJ4a(PKA)@Ml?p^{+Dh**;1V*%@Bu$qyPxT`Bl%|0Dw(+S!h z)z@mRdd{ZS`Q5kU5N-E9n`_S->Ja7{?5l3xcPh)GLa^I6*R|i(ER5+B7;O^e!TR-> zL9%7BggW@FY>?6^21^WYMyuxj2`_NOPjJ3MB}*tn9kZ8#(xR!rH`&Tdq#8O zr21GYrRz=*LDsH=)dJOoXU#ZVJj**xJiCn(qVPg+c~=S zIe+efInXTs;A6W5`JOi&@f53ceHfOvd1)nZ!XvoX3U2At91W7lV^n0^f0R@~qv?{X zk5M992Xv;H@X;~*^vUSB+;ZJWY&Ux3GLAv^C*!LX5wsxPKKIo1haF$GcDnZY=e*<6 zvCwu5h>?O*$!_C&v`TouUePysc&e`bopdYo-IkEIE(1bjs-LF#&`xX2eATd%?#C#N z3$Mv+$b=O<1A+Xm!PCFv%4U6Hi_o&^WZeWU(It?+WHeXKYL+1j+TJW4ZW$sxd=2ls^#9mO+xWB>Y>AfIOsv<1vuQM@a05#)%Ka78$x`E_+} z#k$L>eX^@`B;R@2vTG3iL7Gj~vyZYd z$HgSbu~`m)JE|^b#znWqovk>J-CF%!N!SZoQG`tuNlxa!mZ;9VSIkOH=leCgH4=L5 z$WxcSDlD;U;=iC#?%%U}(jDo)r8tNCVWD94_g^mKI2<~uYLJ$AN%ch7^%a#weA$So zBr^ec+D9C*AN*7@C|KId_CU*5+?o?+yuXe(RkSk8pqU9tfRu%E)(` zrP(8+kRn!FpgMW&86Y`&M7Mp@>1T`FIjd$a>UKBVsBE*#*k{>EEb7gXSHb>46{lyc zutONgUBD2mMAVkpG8J+~(VyhqZ@)&wH->((cG**X3CM-R)9c-M5i~)sw%PO4y>N%h ztEoi#l1#jr{RMalM@>W0!hpGgt#lHC1DhlmMgE9*Sp!WZS-eBg61alWjKAc0Ar}h5 zEGRwK>n5nP{=WZ>V6NF%H6${}YbD_Al1c=>n-CQvWf8kI#Rt-TkbVg?QN~Ah=x!}bhq03chiD{g9dK9^<&Nwu$jpxIxubZ zU-GW0%wG|01A329v6f-6$T;RdAQ`r`E{0GXS6(Qe(eJJY*{r;~qQaS{Cdd0oxKCCv zV82QCgxmDhWq`!l(eXLMWfS~SQjZ|moawz(@{WZuX0_;T^_mG#yPLUXUf)%cSJi$B zo^ufkBf%NJg(`{D_H+jxm)k*=i_!OtaksOwG4kQ0)Vs#@^BnB7hNza$C1fEjq*;uF zhI+|T3VH9ct+)DEuT<~l)rOj^@F-2lFyzWGBnRbA-)vCISsL-_Rw3G-v|Y1FIuH(< zZjl7Rk*^Rd(Qpa6Wa6ic2KE2-UDSWaA6-Gf62r*|Wsih>@D~09Qh}!L(=1|uTNn3S z(^7gV=MbeqY2>^r;g4h+G3cd;0I1vjF@@5G3I=rYCCMLiTw?E1{(!O~D0N{` z%Y?Vw@eH}`PqLHc2q*TF4Tz&q6LV4?JS@70q@J6H^-IUPfo@T$gehAMoG^p@MjqF; z@Z=)o-aIyUGN@#p5b6F?kZf@JSG^CC*q(Y?FHT2VsscSNR-F{Igf>(u@aV}KU`N*> z#((h#7rbIQFpe9oKS0nH|D|m6tFLk!30zlRrT#a=*`e>Po+1Ayc9g*4CMrT(1k+JYl_fJ4jdTTdSSDF(44?t^9>3_+jo#k?DQf!Ac9diyEPo+C4J`D@*waMij%qqgr!_$oec-}TTr z-T#}3|5bVNzl1UyjBZeiyMV_S#x)0JXtdx|kKs~F7R54AoK$*H@hvPOVF zkB>ln*-41Zm<6j~fhusezub4+Bz(W-vY?;X12Te`+EN;||9OVJzhz^&?$lO}V4vmM zM9vfPn>m%x_u`IIK&;TQ)fw!bSeVceC>c*l>7hZf$vN`ql9g?1E0PsI5to}W z?De%swvMUdMu}Z)3mF6YL(dfYd#UghAsWLL(lk$M4!jnrhbudr@4=kx?U5~-sQ*0_ zm!YZ-4VN;JN7r>Gd^-Utr(Kw50DZ4MPbk^-+_y*qrO8qy0RWDr$#XED4*sj>(Hz$E z!%S{ptKmEU-#6FV{k>{JC4&eHLeJ5S-SA^LTQW-*0a8Xdx-xiOd`Lb_!5a^t*}TaF zXZ0>pzuIUI30QKt<(4S_FI%37EAh7HF3S6L`m{;WQsD$a9kSU*v#L38gA|#kc_!c) zLvw%|u&liU(^1pRrI39Z-*FWJ@3#R%>{7+KK7d!OoCQ7B!qk?RFr|X0$f@z%W%R-I zcgfKgwddxUo+UawZJ*NkY026ZE$(WIQm4lqEKQNyFY5V7@ctJs0Ar+d!pZxuVXZ== zQe4O1kZ5_27KCs)tgJwO=n0QpW39)|M(7}+!G@tc%3eC3!Nv@5qaHxhicf<8GESv#V(G= zcB;jtBgKM&4<|G$K4KX!jEhD--|p0#G-36SgFZ!(KnTPZ*Yl}JHUyWBJ4@~9!kR6A zZM71mvnd~8pX%lM4Am_5O{o~*Gg7*C>2)zkh|3`TzRW6IqVHI=D&DofCs63~_KG;Y za9dMtZ(Ot_K5*L0Ij49P-BvN1wI1-<@0w=$6tU3+c=;u z+ZCK;VfbZtU-Ho+0rGG0CBkBgpn!aC`|vzBQ~c8!e04B(3XQOPq{g@q7Qc;`+5g+R{|G<{Ep zFOVZ&qLhA@QCJ}I=dXrBT(t}mFKXxcY{H>TT54KmwUo4+<48?(59(pcH$CNK%80KC003Br{G=pffJ*sp+9Q zWcGt{6`07@H&buHITh*Z2O}P}eVMUdOYo1K^*(XQEu<^=d$K0B`Uz7d1t<3jU=$4+ z<1K1`ffLjER!0e17`#egvPX$VOyaDDX+en1XbE6xRXVWeE@@=8q=Ol&m#A5}s)l#g z9fZ%re#p`J&CzX^BKCDT8#oNnY?)229@?2$NA5s76B8LhLN5b56^~Q~ju}Z%j_cWD zLJ??C-9#14Ax)rtYQl)oaNQ3xTf!vO$r#o-%1plJW9N+3PmRQ`Uui#+ZLHpbnww4NTC zWO!MDI-4vxLi_osx6&Qiq6lA}+^HR4d+35qmr!wsSCbB=WbxJ%2J0bN`B{&g;Aui77U~W8{u`S2eMpZ86;0 z*pG-0O>qe{iWNi^W#dYWh-=%LV4)u;^K%K3@O9FtT(lYFwK^wHKj{}mu^cZ@V3UX} z?A5m=32kc~lK}a72?hRc)e6N}iQdX{tzQa*xeq)V%eg8_=r`J$JMHrXi2g|+VdG%w z?`~@R_Q3jn`L9U*77xmOIs1GkzfntChMnEF}6dRy{3C z#1DW^c)**N9eefOaF%_!Bi{oo%Vt{;cshS1tWsO85{wX~Xk}Bsl_&7H!Udg^2R4&* zK4k+A)s$_7w=6qCarm1Dejqs+pl!eIeh$Eq`H_`IOLv1W!R&+_(m_2O-@{qXd9e3v zm&y@yYxOVqE;GBS$Zpv=Sf-hrZ`a!;LQ#GLX)SPd?(@ zYu)n|b{7A;B|rL9j7l(J^dAihOu=o1`D#i@JrxP!^#11pQpo4CwbV#GIX6<}s z=)Ox25C>NjsgG|OV5GH`1JBWk;$XFScy8|2kDu*PUX&0UQyGrn*L8xQR>r7_^YaHb zHiSwQsqrQE)>Xgu_IT|=847=*8uCB!Y=M9n>FJKMT>_nG)EBYY2R471>I^u^h~u0qayEd9&>W3PzrUJViDWT!B6Y@3my_-`dyB%2XIV*4+Z0 ztIJL0`9EL{miKgDf)Y%-rL3}d+eFw$-he50Otel zQ$>gEj<@5_4tkWvW$5$IJ;=*-$Z<_3ax}3_Gs0JE3sYE)D>N;W>F?VjPs{0Zeo@V+ zq|Uh+a0%KsA>?u;F6pA!g*q11N3B_YXMNd_AYjG4uZ&spRNhRs~#BEbab44l1Y z1uL7z*QBYG?K)QzSd?N1{4pW=*YM%fNB=pUeX@#KMTSWpscz<`_QgrsYhi&EpKwaf z4>+XuJ+upu$Eap31Z@Dz)-|$N>lcU-&~*K^!!3{}oUdfa#Lm9fI|IzHp>bi4ftO4-*B zeH?Z6w)HI+Kl|Cf))J>LB1uc{WC&fMZ=zDzd#_JZNtm)oXUD6}+=x)Jh@Yvc+n!@` z^6@g(b{7}FZ``<~iTV%Q{UiL9=6akL`fLJR%iy6oW$Ep{GRHWH`R~sV3<77EuUKZP z!eL9Wr)!&n+|O~D5F2z^Dp?3URB$NIu!o*DCV)+~0VrT?2ep3y4z>ICQ@&yEDi-a{ zb0#OBh+u-u`YtD;d_{n&)8vM3!#?I4ulh} zTJ*lWP;n%WvaFxTMt>cR$~vk{oLizx%wj?>kVysI2x;-+3wvv_+m1 zTvFsLh;e?^{veu5D3zk_cQsuhw#;UkwdT%X=2~ZlDd}xf@aO=V;qcmV=NRa3fX#<2 zh@o;?=ARF(MEYQpHCUKYq#zoRHMsGERP+_klsB*?xn1xD)C+orcr=E5Eu!5dA&H^8 z@Bz$O>9|uW?S}?{#8(j`rX$1+Ja6*z?A$z!L|QlJi&G6GSB-_k`MPzIu?)=>z!B%9 z&S^L7rUa-B_{r2)>9QYvaWo8sK?$C}0N&2)iH;cgebyo@vkToH;N5g5EAq*}O%!X4 zmq4#M%)|+}ZOp~AGjU)y_SVk<80N~+>weD~%T4MsO=>d4aoM5Me*1YTSx!%T0u&sd zOEHM6Sgl1!K@EXHAfVLIJ+v12qQpo1=xE2F#1-juZz9 z#t60USCzgKYc2nw8!7JBGXL8^{QI&nqm&V6X-Y8+%5q!-ku)T@3Kwa#6rg#k-t#fU zx;uG`C0C}7ttod4!Z!9<-=SO%+{{-{W1Bvq-uO|wo6E?{mO3L5nq-=u=5VPtnRk4r zcVs_AFLrd2_X04?ed-ijq9?yBD{swV*{m-rz$zSW*kbpUpbAu-nxx{A=)Bo$z1^@& zzwIaDZsHFgM*I7Gn9pb}`q~yY6L2>0+|l!>TF>T6{BT%#Qnf81X6hCs;PACWnyjv^ z{0G3lK}2U=A`ewRbKK0?9aY$As!c`&thALx>SvoYGSw?jTuQ9tl%f$pG%M5+w1vV^r zn?t#Int+D~a*6|mhg{e}f^eE8cX-@VcB$q_Rof^hb9f;^G&;wgRUp?PE#Ep;@5d8n zGJN*rsg7lHKo}GwR^ZQI<7g7@5@M>TKo*+PWckccX3P&2F=*fy&Rpr+K?2SA{Jzhp z#?O%J_k;E4TgA$@P9_7L0n4JW`#xrN4Nz{ltjHao$Y%`NS{;%7M&2kyz1pIj$oR2(G7EB^`%P%{VnwctRe$t&TOe(Y^0wV_c0+OR5 z(e24)iQ@-#?d{Qt-%8q8c1N2e4No4pK=x7b!c)h-_~pppou=2Twe?ym;}CRX8KMZ~ z0>sQ%sL6Q9g?%@i0&@qGlfI+9eE#~-qZh@hB@H*$Y0Vq#$6tNwi?AhXF=fAc9^e|`>vN>$Lje&Pm2~>J{ zrPe_G?mOJ9sqfKTC?SFPG%&TH(9z-J)^5(JGb^FbU&ubWj#j&7dLA)r@&kw*S}Tba z_xb4EeX}7->Bo`n6xo#r#L`fy3NnuDt<6fHlKXCPOBoerp=z(C3%r7AbAC-Y9+g=+ zKc1=<_8P&Ei+kOT%@hbdl<{3v6>T-tfgtJJ`4U_(GFZHRPv-QG$%_0ca9}YK_pu;Q zQ6?{0IM+MJnl=BZ7^2M9=MhK%>jaYdX>Fx{Bsqeryqrs;tp?{BY#^0Mv-h1=osrHB z%`i={CP0DKjzvft#)7%S8-KWlG)$kCUxVc&1gax@bSDR#4J=iocoDtQK5euq45$iv zmE51s{!nt9Qg-;K&opREq`O%ZkCt#NsY3EP>Py)_2pr+5nA!ft&$FB+3m`cTcs0u) z=A4+$$6d*QVrzltEPfV(*_{QpgyGJpg=S7p?EDC~??s*R%p%_DRM;Pbp+?>+y%To-74;vO+T zI&93JkiY+i%n?S7FWUc5^@Ux^#JcGu1y#dt8pBvth9|o&qHW3!GU%o_M){yla1=a) zs<$y`@2OTaWv~*iMtTtW{TEiN3N?&m_tz|n5vj3{680BV-=Uh;2q8IB z*4JnZcydjYDUb(-`!5ixy8lx8f~Z)t8@I(>b zlOXrejAt>VrO77OnPcJ9zc5z#2+jH-lrbK)jwShy@dvUE03XeV}m9>+OC zjQ9LkQAm#Xj~d5dFrroQY+N)dOM(TqtM3&&TH0?@O-VPKw-OtXC9ohKtYf(hAa%2} zkpTbZsxax?P$~MJj6&Is@|BgQ!T8k=JKh_2(#evf_)NlayC)p3p<#HKjDBkL$Wu zH->(2QGWxwdXUJPMS!oo1a`Xv6>|pnc*_v^u^R}u)}aituf)st*~0y=mo8wl+N`6_ zONcWeVr;6Z<_mRH( z5GYeRV%XDIsEzJETe?R0Msg~4!ERPfz9y(@vl}sMjJAMSyk;8_OtmLUH2h8+(ew^% zYmUo5&{sIh7k^j2L=sxv-{3y~9W3sraVAld)uebUvlB?}kXb1%vh|q@mlI2~!EEb< z;$9g*xTfjnd-CotbGm+Pq}0Xe9$uShXTmLG{1I8Wu=f(?!RCpdz@NhrzW5tyWzSZB z;RBg|JAD{@0(|8@XrM1=0PLYFo7FMn$e8Iq%!=X}G&nY*Zywn1u_O#)TqjK|@_*e%(PK&y3=~?d)^bvDY64 zpb2-Iz}H5H^f)m4X<|pd_S-))4H=OdepT(%0V>gg5I$rRhLVW&SH_#Ts zzKr%D_u;oXh0sc=SULT(w=?Z4*ITzQ!rN9J9zP`OiWY3)+Q>10g%yQTWfLVZ0&v-v zJOThQ|4vj}R78l(-J;%084|7D)Xeu8U&_~#zC8S*9s^tp|cAfqiSPB9xXexuwu~ie)EG22BD6Zbtto(;%o_<&Hol zGMS1OfgVs7=Q1X<7bL*Cs zaS}X5Jfa(G%B^7#w5Fq0>Y9=gsGn#(X>`ti)@EPQYD3pU-HfP$RG?YU6U!FDBprm* zD_)6^@rbv)9>!ecLT*3AxQY2^ij_)*U)#7QW7b~;v;H@5u$!E4DFEUO&`?Y-I8%8L zxo3BoLYRM@PaMbUd*qCC{rA2XUycX;N=Q6g4VE)izte}_S@)CU*t5fodki zm*bnvYc@R>Oq#kOUaS+Ib&}@|Uq3r-l7Kp58>qDqEwDjom3=R_VI^;BqfJh_3H}Oz z2OH2JNOgYAW@P0)Z15(z@<`T@Tp6OAFhu0>jo)Em^Q`*uhm`RASZkOwT-}%%8fAu> zGNBf4_HS-IKW)5~tu7!&WwYB#8n^Au-A>1T%?J5@7sNUYAjrNFAIIapRfd8~Fy5v6 zjX)g#0+pDR=)?OdTs`mZ9YT1axzDqKOwuAL@+)0w!_YnNnsQ$yM5Yg(o# zfyW0N!8OcE4Ttv6v>ZxfCW&Lh{6tDx!0FOP)?zhOw4}|+_=b7FAFsVl}SL$Wkk6j4w zxh^4B=4L>xh0!8{>+$?KX1B1@c6~p6|0eq8umRDBL^<@9C?(${#h*q$R&T)=O(Lt3 z!#Ay_QmS5_m8E2BXuhSiw7A%r<;Cr2>7kJgSngoCuE`y=V$%8PHi5}JPU&_lB8Cp( zTr~69wS5fUH2wmBKtU%LJA)*1fBJkTnYn)R>IO>|mwgAv(4?CZ!V=F6>^y(f=ZR~E zRvD*VP(6;p&z$`Js8L<+`wDOu2`EvaBgxe^0xF)@WnJv_Dtoc_%}yLPhvc9 zZV!H~U+av52&r3JXoig+f#E{m>ok)OsXN7&zPeo-#C|8&Z7eOc5pbcd z35myr-klUM&t+d9zFC21LHW}tp5balV)pmx?3e^6AA7~nG!K0jS3%kr_{cR5WH*}@ zR~*4%k5xH-&MAU!)K!xt|Eh^`54-#=NS0r3aWXPVw@2DzLHc9}GyKF!9G?exw}hNo zE4C8><0(*OcwE;&yL!Ej^u&0qz;`l~!<7#PdVy*FT5Z_?5`=(qjkui{4@T zI)3xroRfK_)fKPf>Hw&) z>G-G;f9$z(J!DodD+FE=;rn2B-)dHNTQ){@hLzTH7migqoL%3lfI!B>c(V=7iK`in z%5qm6n6=zWeWJOCi7f5V(_@(Kihe^cC~+77E;gKR?fiBzdUU-Vw}@4Vt=#5*z!1tm zfAiU7^Do&xarcn&{b`(Cy!N-R;bLG+s$azImJ+rWrO0t1jmS7T5u~(00GN=n;%S5) z<0T+A8qS&FhC$>fG{~_xu&7ing5vszb!(Il~I1Fvh({6#VZpRj${DmK$D&1P@#RKse< z=(MM^fl<%M#CGF^mWIoIw&C)ViZo`^DkI$MXddQ*C^xnd-tzu>K?| zu!e0=Da2|Gl@8%`wC9CALA^Ym$1PL%14vs|7J|cY1w!T&6>eU(YfIgI>Hd_U#Qo&f z@u|~i*&iGsGd&+xM%h%B(3jYd4P2jHuE^`qDU8NS;XBf-{{d4}U+G+rPna)d#}Ks) zRNxO3(-7?u(hey<@f^idg#T5y>vqolNt%9h#<91YohQo6_Je85l zHzm+$B;&^5`?xD#?;tR*AMMC3m;ekf5j&q09Ut=u2(Q7;#$aIAxPfo8_46IpX0t&F zW7TH5(y6T4E48C{g@2Aeu2iAu1*i6=9vAZWGI&IJ$>GO2q2%jA)w_1V~Hg}g@8%Wik z!-S2^^h!+oyRYm!B$mnYVEOkTvZ9GYgv!Vb9N9UBU*Pi%C1E4K9@s)(UX&nZ?QQL^ zO$>ml7~LBobq<8*7shlp4v~tp%@d`J>2W6857_hni43p&vWAAydG6);`DbLM`+;Tf z)H5%D%8Akl{Dl7PhH~xj6z6x7z%2A=!#)F;5m(WA!ZK00Y%y=q^>v(EJ5v~*>U;8w#N&6m^qaZ%#xwp2 zTlkJZE&cki>IF8iH>4fvIOnT*7~+kt);%Uy81Xpoi=CgPHpb;m zQTL-A$zha(#19oGFqG}uOoDA3Lcyn|NmoTC02jhcO-vn21`O?ZO;`FZR85^qGH5z} zR7C2C{S+JkN4h>qv;-BVg8oEnurj9FE8k>Gb zbdv7>LzM=x88$U9d-fPmRq|fZJ?yt6oMW&&8x7Ib;KWCdg}&}T{)E-N__rYuJmZ(s?rFHhOByr78{4b(qh7jtVfH_2!gi^1 z_<&hpV|TKLw>oj4G__Z$Of#ZX*B0=Sv|&akp4j!#*s~pnp?hYN$T8??EkY5tXI^P` zLqgr?!YSF~yK8q24XWH=Jy2@@6|#FP-*4z#p-U%sYN_EBUwH}?b>2Wf+{2cUVJS-K z2=Crf0j$o3JSq`7`xsj3xGauSu}P!kDA%l}#qHMHwRs+LWJfm7I!)6;^0*#)Z`k9Y zHmlY27~{i^Uv!h@3CHF7ttTpdrT-eRtVl^0q)e<5)s3)gyOcv?y%#-ydB{yr$(<_^ z+k2X$mj`mMCewzSzR6S3R_KkVMo%a+zJ1d?Fr!SDQS~`TKH<>n)+|NpfbZl`C?Os{ z6w+@kUKZgd*sb2D`I+F0yJ=72lyiremKYaEbbFrDB2p}(p6i;=ImldefrIx(Jhr)Q(h`>H=v%8mqVP zdh!UG!|-&oK+2kiJx#(bp}#zaKF7?VKp~SEXZSJ=F$eFI8GN>CzUUXVHjm3a0sH0} zHe{#WJDXV5ScVk|knU7ciC1XO@dqcF2?uW+tN#%KV6!dr++*n>6&{8tw^|Kef8m9A z+Nk??Rxl6v)iNT6f9hHVSp)iE49Q+7x}V*DRX1R%;ASFzz`+-zqh)jRMj3L5!pV8v zaB)@2@NU$+yMS127*Fn?QCWYAhyDjjkM9${p~$1a2rBjscO4@}xyLw=IX9k{OF+$8 zBA(GnSyi>4{un;Jq@W57lHXy($-)}q^ZlM|-!)$(deh_jh{iXR(dlX)|6Nxy3kfR# z4H?Z8;PPwj8*Z#>cq4yJ$Fkjz7<{XEp0gIpSVl>0b{_Ws3m`Aw(2lN-E_QBj=AJw+ z0vC5{CNz#!D3vi?EGbYV#0^@K31kVI;P}>i$MDkIuhB)r8PMh;E6bF1rPHmj2~Qx7 z%xe|_izm`37N^wO6#5*$eqZuE5sPDjQ2zKA&nmY$bl?!3(gN-Mriv(yC#ZANT8OLq zY%UkBT!!e&wi@kgRuq|q6*<{;9OfeSey7GHbE44=i^7C*Q@(Z@&SLq8A6MA4=ww_vvedD}ZU3 zu;Zy4=FkmW2|9wyIgA;Du`PQR1oFF7F5%~|zl7;R9!Ktf2WWx8ZNXacr4r>DS)$6{(6 z5pRqRW?69smabPo_UVS%G{N262a_;o(;4;7!0;djM~2li_0Y+8kB#EZ<8Ld6d;H-? z(b3X^va=lEG>#Q;j!3PszCNYsV^PyZ9fuAIRK zFMW@N($%fNcdIqHV*&J-gVj%K?oFF6GBkP(LnGI)qi-AhvVXlhYZZ}6+NOy{)+R8> z{mDW>2~U2DyCn!h8(rJ-yhsa}RntI@P=akYQSw zm@eVs;4nXPNb=gI?hb73?nFABgl=2hh^D~K=cn=U+0*#o>?vHmHdKYq;yQG$*@7Pi zIQjAWd@hI2|HfnJ-LMg!<0{ab2~~-x;<(E7>tK^PWFHs$FT?dc#Mnp{3F&0wY~fmq zVr8PjjbYlAU##i=qtBpY^G=vueS6T>yA7LmKd6cp@gRQnqrXFLY!FUiT3yrXig^dc zHD-a?I`@XoZd{@xo$tSdySMZy0Y!BVCf^+jDjByM4$O)nS1h6Ac&dTP^CkiAY-`1t z3uo}`t1l`y5s2iT>$!9?9eta(;GW$Fu=B3%NN4C+TIJ|`$4BUg=x*=8mfkLmPfT-e z0XL&ScJdygatJeF5?1hfD~>$)F!s}#PZ7HJPk)Fj!&m8qzFLROr4xel{TK1i&;10S z|IFjqzHJ9W*HK_L6XNLNtaC#gd3bb0Ict-;k%l+9)?&EXQ2JoTQdwj=dhy`Xf5Edb z)U`ym9VY8-hU`u{4CUn-Q?0R&yB5N6`-@J-UGKs;#e!Td`%QK)UH}ie; zZQP3c58R8px88+hI*o|e+(HTYq6;_YqC8zj=!J;4#*ywyVatXtL>$)T{lZ8d`H_M; zI6Gq_mWjbm*{~8e(wy^C_dS4pyY}GJ`7`+7^hX#N8dQ6+=x~X60;7{-_`&l(#bXbD z1_yTUQ;nq=;KZrLy|s$ZRZU;MN2+f5VgZ(AH**d_^&D=?5XeF{v2tfrM zyYTdHehGKe%_54oIFUzgD90p3*YYS&mJxUXkAQBPb5Nct!=uxAWe?L=rxj>&Ptq%R zaHcEIIC%$w>l2Cqu|y1;H*LX=yYA+Gx=<_>)HlhoD5 zCu~z3C*ZubCalv|rIEb#-f>J!Pr+h?ZX(zz@Dt`cYb}VSM&P@Mr&_Ra*CFirjj!OI z&;5aNw)q%Yuo@8yx^dV2*tGXBE*$>_CI&Cy+&j-BBFWnA58WiQw9o@S_j&&EMeNO6x_(zFy4OmO-$#fm7_^G6y=uQP59ztpF<~| zbNuo(x>P~AmAIJbSJO4BGMA3(*2KlUTGO5nV0vLu@;A6nzIjjn1vR zG1h+yXWshR?GD^HGe6%=5wHMub$AFP<72Ah*I*NU1uU#bCyLuQz8kYl<#;v0dLA9e zbzrbwHOK7f>?UZxiH>9|hEENmG)^bvoRCUyl4@K28H7w&g*fI~- z=dnQ;9K)1*yb}>Tf7(SM@1b<9fK*o+om)EatTDp<(}H&tUhFr=e3LA#2u5G~Iqe9-_1{ z0j_8JL2TZ4guwkPuAV;5!>0(V-F;T8Ti-Ft99!rCo!zTYD&f*VKQ_`0YJ!qt%co0- z5XIG&qdHxgbQl3k#2BzP8@e~*!0vl+;-hy_ZDZVq!&oY0D+s65vJZtm2 z`ZO!wr>Bd^O%>6#XA_?M{1@T<^oI%%fh{Dg;?~#ky)h~^2rGN93u#P~xhY(}I-urn z5;O^cZGAf%YpqFBp&ssj;0bIwa0IPAeX8p!E}9H;sq+S;*or67)wdg&j$Z6P`V4;c zqyG)X>2Y-sUbzUjTu_}I3mn=yh#Ygcs)~jSl|4wOzew2b+jkI2ie3aRaD{x!@qK#zx$0GFwP=W^~G;mTD36IWACT6H?*h~mynaX%SD#%4)~sk7L9U>hEP z_$Xe8et|QWE^uzQ0?{JJ<_964_0_nw5SaT1uVQp^g3Vw_vSO!RpRh?&kz&MCS#)gP ziF-f)N3auVW{Qx7vpZ}PVJ??+>4IwFWEzit<8LdXVt2fB@->`)=LO_O2jP28Rfy|0 z1U8o$o9_W}sFCqe3h4^=?brjIB3JIlf38=7!ZMASy4L`)EdwQ|a!uULqyYEs*pIZ{ zf^#2^;8(AoM?OzSgScO)^sRspKm-atFVKph1vIH+(Qz=A%PAOZ07`abG73ORz4}}Y zLV;4;%HyZUd*YlSJH^$pah$(6fL%NLaR2THm9vdZjG^p0s)NrLa-5zYD7dfJNLQdr zQwq6PYiY2pJ7*KfMBmx2O-QwL;ep@!bHoUoY1!)R!@9jMCCr;#milK{*R{IszN0EX zeC40;@oPU&PACwr(-7DMiFsiYNE{0E^>>b;HPea>UETaGf)vqJge-!uIh$%aRS=?T ziA13CTqd1CYilPyI&n_H6OY-5@wo&)ZOc;MYXH^%7BS27;(7v+03(7<+BV`$c}5(| zWXf}16)piy+)|#G?*gCf#c@5v(=oJlWRb}vv3bJ=+`a9$@Xq_cMkJ0Z4mnSVZz@L@ zYv*^_uSr)M92vrup{q*;O=A5x8}}0UF47&n%E@*<^rZT%)gxM>lg*7)qhQ~oUscXG zIeZBhj{kxppkVa*JLVe2AhXQOF7%K^F%6Ae!;5deiZ330g3z@n2MAew$Mcb(;Oj$N zN<=3vQ#l|_9hh|gEq&eCzO@IIZ6eHhC|)Z-<5`+?M_rr@6>PP-@nj6S79)V!WO8PX zsQx}vfU3Ap#SPj zc7N3b_$T|kc%>h?d|oxDCB`Uoe60kanhW(18jO6Gh_No$#z*n-xid3$SVEMTKV(j>*oiJ7!obIt z{YS8A&tW>X&jy&l=DnY)l!}dUrDIi4}Ds}>*5iG5$hc)z*@GpLXR724Yhq09fz=$)pOE3JOXH2X2TkI zL7*H|)q{?nE9CLgTd!kibVU7LVw_|C-^`V>j|DtgH!PTT91lG8EyPk;~;S{FneA9eLtB7o+RknCYN6j_+ zumEL529Cdf0_kK54<5XaphfU0WV;?Vrhq2yCJxx$mPIBJSNDSOx?702MYO4|l-mDP z{}jBE$B8P!mcQkeM7dH_1wUpY)sjN0GX*Caxe0LwI&x>Rly|G*qtm6KKVtpF79&mv^^J^3ftaQ8ikr(3z# z>i!6s=<`;@>cckc@B_rsEvl=0?l1l;hR>hGN3Z^i+V~XR&T~raKDTU165?z_RX&>1 zia~%pI`$jKk15~|?AlA%xG#z?s^2T4C6z=+3xTsu1?9YT34la<0%qJqd9tk1ExCw% zkx2ze0pa=rwd?q*)-hW( zm)c&ceUpHBs*y;ec#}0a@$rWWw0dW6GEOqT&s;Gpk+nu)P<3G)Z5y{KHxswocIYU! z-FLKtUfpxIGH$7|XHJYEQ1$LSq*CIeSN|CkS1;h|>ElXZy56X>u6RgyomdKN5|(M9 z>^OMsS8pLj;8HtwA`zy0!^*~#tH~q9l2dUy{#BL}(bZh#WHr!GErK);aj>|39Uyr| z)*vZh9Xt81N@+d{zNOWji^2cG99WrSf5VoqO$?q^Z3`Paij4GeRPC)b6 zt!2LLZ5yyDlS09F5IW@<$m%y;`>!4})S%*6GFRNT=B$#<1UgQf`jF24D>a5Cjvg%$ zHQ+Vo^Ecya0!~zIKvpb)T@OEn_RTx6b^jwXP>G|hr&u?zh3uw=6~n&IeiixgA#B|J zpn@&*J)C^;yKqZ+EWv!5o|gGt=9idXUecJ*ymLS35p#0^6f z%4PU|h$0=c$nW`58M#skCC5dX4&=JNav`!`QO_hyu#A z{#d?i(16w87sdJ-@WTib(|HVyPhxyJhg`9w0Q3ET zbI|oDcoDsFA!=JhrOhR%dQGJ7lwF+dzp7j(n@S=G!X*_%=JENCOWX9( z8%v4JARdb?qtrZK-+PUY^z)^>r5hI0P)?TZ+Kl_Z^k+!5btB!@Gt0%IWvu8{hW6|m zC)auni!V|)=x{DdxykC42*-c=511YqP(?21CuTjnjEFP;9rM31t);#kQUu}zM<03w zzyF0NVUQr7>so3P5OE8r;%51xxLb)X=P1{cPX$dCxT=rM<17)!3eb{DVehsrNF`!i zu^hXoO$bKGaaz( zl<5L~6CGK5*U69nVC39;4+L&0p&Qncrnl)LWv7UDPP~Ke_AXeai9qJPi4dXrfru?! z_82zTVWxE0j)?+m5hyoYxE9K-4IQr?`z7A}@O{KAiza6*OZb6uwVi0+x(|U{K1k4h zmzUpX78;%c=WfZi!H&i67|Y$r-0eRLk4W#06e0=^4`ZnK%L;DUQT?If(It`DG=M<*q&-~>6DDXeM>7LJ`^R9geJ*W98nK9c$JZ8gj zJ-l=BT}(_)z%z&KHG}L8E*iaLap) zcpBUHK8SQGT@gqVA>v5dmMW;t&w=5qIR3$V2so*(H|LJGB4&U~rBqGicfF*gIrwZ) zzy9FY3OJLlWLt)MXQ|p3(30^4?%R71rX7PH1ogLnoB0_jUG0Ld8_EUkSbVL^v?}q5 zfK5WvbaZxYL_CqAfb2$(Y-B#c2d#jPmP)r^$F@DNc=*9=k=zi{fh|L)C{2X?t#dAe zqW$&9@8imq%ZQ11)(>wAFq7+TNhJ{{a8VUFX&BO&&RjT$^OrBoxU#`#Q*m3FQnSE$ zo=2y*arB`_ux(2pO0GY*1WD%KFuTGqR5i}Fw4--ppQ_!R7@ru}BuomcXTxS>vTcw9 zo)deSkIEO(lTQci?C3_{=50!h4W6F~5uinp8g#Izsz!@WP$(7g^07BCG&YKu6;onf zFA;_j*Q+Bdz!3`7FxXgzM~89Z;}dGX0$wd*wyE|w+XowmfF}Dt`p~E8Y6lQ-tSGvn zeo~AFn7?0ZSaM}O)o7*T69t=uoT*KxX>0GI!&SR_6eUmrt#jr? z4&1h5Xld(Iut^8!0eA7nQ?s7Z4b_pQ+uwcHPPDgnAfVgbI9jC}TO!0cI??!N^Zm<% zSMb9Z{uL)reV|~|_4Nf@jLw#f+j#%f`?xf42^O2g+zussGz}dK`A!f73d&F4e;A*- z_kQJqp6~I0t>R;iSFqc%WB;MGy=!wUo>=R0tZEqF{MKKs^%~YDL}ZC1GTBzcDVLt0 zQ2vsFsol5q>>p-PEEjZ9NyMvjU&IasW=Sd#@n8Kllb_`o{5Sso5ikE+<`(8!7HGx8TA9 z_Mq&PaQgfyfS@j(ZVQH;K?KHnG{;GS$s692yJL< zwJ4WM0%)4+ILwC+^3vCt-(^0>JjZlyS%Fq5K54M^F^@36!u%XhzoS$vz;`{&VvV|p z*x`ARUxJx#9ukzzy;})f85b{~SK<-jTBZS=pJ5Zg7>2=Nb(}o?A@YSho_ORawrtu0 zpTLC_sZ#SQhFWhdhAV>u`1z|Z;^NhQ#0j3Z*u31D&Kem6E(`|Xs)`DWFW0aUI)XHS)FcN6F|B9K#p_(BcVE!@l|3d}3lT3G23$%)1 zeDhm>wbpC66|sx?Rp#F?|C0G2#g!D%Oiqp}*P10Ze%E~$Mt+1M3ugcjl*G+ivaJNp zp*u|}H^?O83b@gTDgm#S!--=Vx}hBH?4|Q~_T}f%Pv8=< z_~M{dolWZCI6ff@5U_UQ()aJb7oR=+2%YgdXqjXJ-2^Re=@={nrwh`w7V0CFJtq@s zSX^J7b@D~@GLJGp#oWp)GKZPrsuXG!<4$%qQNKX;W#$)|_cB{*H#NGJ>lB&g=EPPF z5twCI*tu;d%HXpT$JPytOGO`1s< zMwoClxSZZxa2hrlKI@CKNAsTL{mlEAPcffoexLa+D)8MFai_s1M{1)2+3zu*X6|67 z<~|rvfTdzy30u?Wfn^?-@hP-qJcXUxcjL_YkJ!xvK58s$u`zb?La~4s-gsF7(6@05 z!XTXK_BZzbh(fj$sLBbkfD={$iP<&`!^GLk=kdzhZ=hH%s(F{QUK!7$gB{qt2Twfm z8N@lZ>v_u2Qt=pi1T@ox#`+3mqizM~g;NkQUg3x(=YI+=_BNq|)Zgm`OS&J9P3@K1U%_U>ZuN#rCrZ+c_a?n^@L6Rrb zK^PF$<@VSJQ~4sgyEYTFN7--^1kL4`A-~7a+ujP>vItHHi=~((JI{~m$axx!MV1?K z|LJTiI=gzSeXc2Pgw8SMv&`=>-(pT-oyMKuZ0*cL%&#)P%#_p87kkMmm*G<=BE}nn zq7Ur^!b~^xu?r2~7cqnsZcDZumSJFI+)nunAO$nO|Xkp1G-+mjnb6O}Sj8lSDVVT3rM! zJuq_Dpv~iMGLDEanQB3gu^l7VE}>YQQjWJA;M5!1@|TT_U}Fj z%e3I}T12qomW>_(&Atwr>_EPa(a~IfF`C$tY+Kwd2z{8kjfI@OLC7I?F#nAC+svOa z|B3kqb7;j2y3Dv8VcW`l43$pyD6@NMuWQPYL_iBZMd3tt3PHLH*4RZJeKe2T2yi}P zu@rhX+>No(e&lka>RCs^=oW-J~i7x^JM;fL~(%i1`BZ>RQ+Gc7aV)+lLBZ(zyl(Z2>Kl&f?yE zhp?r0EB6?}XJZl2EYn1HTMJV0nEE{%9H0#)GPFt$4HI6Rk*O-qp z-(-HD`BUb#wW{fQhs{O>vad3qVeVwM+}x0wa-zWZ7k`u@isE#)OgFUg%c4LmM5uIT z0j;xZD-4QpV*Dy!p?EZ7t?Rg?sDake)`H3-Ot*GsKgH2p(Kl68(UuJG+u9!;YK%**baq3xJqc)Be@|-`nN$U| zMoh^24y|d-BRqV-T+((UHYQ({H(DLwB+{t3+=I+NVg8@Y=b2}*%FwMB*gBbqn7_?@ zin(pICW@#4)jgYSp8}h1!q4`?$d9pY%e#v!NSspyna;E;hZ`BWgig9g6O+EtoWw0gwJ;$qAP znD;P$&HN|kbIg-cj@6iStzqk8ewO((Di*(GwI>XMpbA^_V$cM*L<@pc2aGAYo2EDQ zUIn-S@k9pQJ=-xh+K)nEf_K&ra22QbkV>R+aL+yH+p=9<^=qI-70^0cGH6LBA$~R= z1hOO9))@Vv6i{6H5*Ndl<$Qu5WP>tpRS7KSVN}3-1{L6b%zTIGtmH&%0h^pjFY^n` zuT(eMd#ff70-xP;iH%EOqdNuJ9_YCd1s|G(MT8keK4P&1f!l_$F$>dE*HjraZK-Np z*^sq)o{QF&cHDpPLG*NPK)~i8j$FGhyX?$n(4I*vH(ShYeBK^&HT7vNv7bl-3PN9< zkzrDrtLJQuLJmWKyAKszKF|EWP;otXB__C)u*qDTm|tRkgSm&^0@axjrI36--2(u#0PQM(>use73_m`^cZWPY1@ zj9JF=wx;4%z!qcP#eACihs@o~@xU?|@ zIB~O%j!gv5hEp!g3%v;2G!0~uNf^4`l+c$F;$Vq*5_k9QKr)$z>s@c&wYfUzXdNw? zS=SZ{gIgJ=t4;eF>$|*l$vlB-LTertb31b@D$xCa`TsKCVNNe+z}18;#oWbwlKFM! zepIYlyLI)t9?B{B=~Glu7*+b$Qpbq=in}G-U`$^_WavvCBZ?}n+S=N)V3Q1j5b>Ce z9h)~I9*Fn^c%W9E05?=eT#8n!g^0p=H(UuN!E%Sv4j4PoFT@cre}E~3*-_$|HA z3**Y|mg;Ub@kUWFudB^;cmn2ey>?*I6~h&;NH_LpYSr-B6jyt{HyJ(5Z!$m6e2MuZ=JQwtx|@Yf%9=q1vS*l& zGPkbarvCr-%Jnyns|@4MncH5xzBaKPH-R>dQyPRSP-y`PA<9RtACOw95{M7{Ur2ne zgb)&!wt^rK3QZIBmI~Cwz2PMGuCrcW_A+zk@VsZ%spD>3*E{1`ulI3Z?`FF`=bdw& z-}|JhC<>Wux{tYwWa7FWw4~c+jSl5{j+=U~G8`mTvPiUEl6}U@CCpAuz~l4i1MFMi zoY{;Nt`oBVZgQCMXacA2C+CrB?yuqToR0x?FR-3x{hReW*6&%XNaoiA^7?>m5(#8N z_;ai?{kb@Mg`EyBPg^7RB^pter{PS@!&_hGnlz^B+hw0ok~Z0!O?N??o1Ub>ozDeL zPS4}x-f1hmQCC=QDL5(((2^me30ur`Q=UKQuxZmwvtDGq%=!cCHY?is(ieqI zj&qjvEbCXS?;(LMeW#@@njs9^_VQG}U|6_Zgma59ei7cUe2Jo9%VS_^Q{a zOhK}KxmX}*Q}8|abCc9#Bk~PNvg_*(Hu%`SlkSw&I)sim6pI5ryL)Md^#j(oSifZb zhV=@I20?gGcgRzpWqk)pl6{voKIlodds-SDBZ|WG7VQETojMN_jKQnkg45oDah&v0 zPGDo-rVAfZp7N5K0@|6GDFg&da_p6@PntRxp05;V=~JJohefFlZeVh(Xof?r#LvstB! zHB-**H;8FwV~uB0h74WMih+-LCR)Mw_XW*mGjeKo+LC4ppYT)e%zBnJk$2~Z7B4K~X2D!;?Ve>wmTs-Xv&^NLk2IKE((7V}&}jgC_O+ z%11JmzPZ;8@??vwA0bJyr*WJi+YxUsX4>pb%4{}B;EEo393~ipUtNM~Z+3xGhc=z= zCR>_)%eqCT*;pyy``)P`yLq%olOg?f!@+x-3L%*cGD@?(+MR4eqUH{4F6&FIpR-N8wss;eRbmhh0;fahYK>!4C9(9{a?9@xC@KJRZSyis@1h!V(-G++3z zu@=}g-}>k=500e-wwGB?b>9z7X6G%XBN*33IJ=0rSb<+#f@(Jt;0{U-O{U`nwzMQk zRxT7!@cjosla4$>)nt&q(@?mv=`dA+!V#s}UTL16luB*N7^rCa}G~rEs~b@L^MdqX6#kczj?a$u>IH%*8~}A)}&*aCQ-K zp#s150aVyZQtlyFASon(NV>^;bOAZ66uPPAx;8B(xwf^!jg6#2&Z9z(X*TTg@^0Yh zGypS2(u~mPsk1PJF?cIC;cV9#Ep)i*?Q%&V9rvHg0&KzeP$?C85(WXct92Bv))hW( z35Kxnjg*~E2y6x>*8DvH$VoaG4PBZ+yikH)y#;suHWWWgQtnepuaZDo_YWIS0AmEL z6nJ*cTTKDYL7jmcC_4j2%2+1^Hu1Q|V9=IWU&VB}S3o%TBusG}UhPAus13*SXnbXv zO!_tqJ_VnjJ8}0JcEo3K4nT>dW7!QbGhW8FHn`DnaAQNE!?g;7oMr=YSLx~Gz?OFd zJ)0st%0V=94slRM>E1_hI~#;Uk|uGQO*RwT zS}n%XmVwJZ@CVq;isvF_2J_|)r4s|&!1{_H8K#Xlvw*wXZCw55>j*m`(=3S`Nu{w; z(bjI?34HA^LSwsSp?g@s86!}}@R^Q}f9)AO_Vjan-xgH!e)9d3-@>K_bV?phCkD2d zh91P56HxrXL#MTkS1$hpS6+V?p69_)32dhO9r;lYv@f_A3!{8#zhsmD8Fo52wR9K1 zKK&@po;!zTtC{zs@1ubojeY3^z?RJL*yy|)=_%KB;rjuu{OdBVU%djK|MpnBWqO&< zBO0K3cSRgU_?pcD!Py#3Z&xOVk*_>!K^@L&HR=>(nj;8EuhtXj2-SN{A*zOGsr zvXrD~9LM1B)~P+*Ri~O z8!?kq5^|)Y(a^&tRx+ICQiGIk0$O9eftXiN86Q8geP!s(&M!c@9`4*(vHzA{M#^48 z58J02oMe+!YqeTfS*c=n?hMX9v6u{mjMH~#{YM`?i&CkKYPE*7wRH>I2)OKZLSRz^ zlWGE**0BYx*=!;311v5+g^7tt=qSo`@0dUfWV3S%aFk==6W|(+4cpg9+3EzGuwtf3 zYQ%Xraz8!R*6v|*bBhL7hzQstr%&Ut^B35s$u!-xjtJTurlzM6h8+u-0C@NADz>(^ z;ks_#M>NzLe%R>mmLza{e0=wy#bV&ZnYjcRp`X%<_P??_VSkyEo+eDacoAd7U< zTBBU4V4kq;U0)Kd*=%8DWtF`|5A-%tdK#VT5l9kD>)3)Orrv92V`7`Y7cPDUlT*`~ zq+1k4ICXj!(^E4&*O#6)H@C35T4UPABj7TSoM<8MCbASgEN+JU(DgaN2Gr~8Xfzr$ zvFg!=LfGkGiXbdre2V=d)pRqlf#ImPY&16*p|DlEYs%K!iX07*qoM6N<$f@#zv)&Kwi diff --git a/images/avatars/gallery/Flics/Flic_22.png b/images/avatars/gallery/Flics/Flic_22.png deleted file mode 100644 index 82be618c4d07a7134f8aee0fcd80323aacc40184..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29062 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 JPDHLkV1mg2uXz9f diff --git a/images/avatars/gallery/Flics/Flic_25.png b/images/avatars/gallery/Flics/Flic_25.png deleted file mode 100644 index 830189068b534e8ee1437241aea05bf6c810153d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28908 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 LNkvXXu0mjfXo!-G diff --git a/images/avatars/gallery/Flics/Flic_27.png b/images/avatars/gallery/Flics/Flic_27.png deleted file mode 100644 index 1b6694c5aefff14101fdd57527e5ec691e7f7220..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26950 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 Rft~;W002ovPDHLkV1h6#zM}vD diff --git a/images/avatars/gallery/Flics/Flic_28.png b/images/avatars/gallery/Flics/Flic_28.png deleted file mode 100644 index 0f591fc41587b24f6d9420973cb5d44138dccbcf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29572 zcmV*2KzF~1P)E-g4NLiP4SqCNRrX$*M1jCV?0FffdPMiRa1jkVW|g2NEZiWKzP9CMi*(4vM5Kijqk27D@5g-RbVC`n|8ZdpWz@ zUC!>zboG$^$TwA6-Cgxn)%U(9mah6`I`827ByJ<<8Qf-F>dWU_=e(yMBtN2l$~C9()NXiZw4y0xLge3xGi&$uxXz@uLAnm0 zLWK(fmC!0wC;*kvDpV){mC!0wC;*kvDpV){mC!0wC;*kvDpV){mC!0wC;-0e04g+v z1>l|FO7I162YB3dP!*a-CA9KFkTJeVl6gYPkCE07V(eP*C*c2q8^K{P0gdZmD@>0{ zXr+Vb!_NSua~mpf;+)u;3?P9SC|}?(8>W8 z(PE?ZWpJ*w5YieG$2X$w2R#y^@m(J4N4t=cUvWZ&Y%*S zJ9yv<@M@#fU8MAC2yGQav|!v@<3%>^3Fzbf0kpTFy$$a^OsVKz1UKXFSJ3Xln}^|$ z6&#`xTA^TV7#7#f5Y=i*^ex7ykCHY^Ae8jEXkmI|YWTeg?M-NZ8$x>n+=l*3n3qMj z72N0g6fQ(mLhCGY*(?EXGf8qMDRl=#b}7WL81%**OSGb}NfBWFYb}XBi}?>giM!Em z#NW?@FM#iX8m#=T!>EMT8L+bqAbnS%U2Edx6A;%*B>j9a?4Y=&j>njlXjd9z?jWs? zW9|3AEf{~AQsM0fBT%_Myz>#2(Aotd`jEu)g`umEy!RrR*XSg<2K`<~;+hIv1QutG zdOfV{A;h#7V=v0%E(UlHpUL2t-B7kn^6gEcDRfLT?2950a2|&dkd0v z0hm5zVU<^0Q$bo9vl8t}w7-Ep>^G^?Z9{(}#&?3dz}R)L-G)kN&0__U?PgMHwb2lm z(jPHeFYR)1O$Qd;a!aE7P*4t_-Gx1F#n@(&@>R62Q6;*jPzh~vuwuBvF9dG}*P42C z2ZXf}3AdOU&us?c;x}WZC`#1ipBeiAS=j&z(ewU!V3+)3qheK#z z!6X~dGJgRMgPQVfR2V}gwDIT#`;jI$A)$T+?)5RF)TN}%T;xvJs$(Tu)6&8Dw0yyQ zN|YY=OknOPN$B)w#7W(8cNF-iji!UgPf!#mFsK==w-7OM5xNFv^s6|d_Yv<7@L7zl z2X}&}!O@OxqKi-oO^81H4jN;wLh`Id;;hked?PA$5B?5p!i&~jhD&@M34PVYOX+j> z+;00un{m@322y&w06PKJap-$=YP3$@{`a5K+Xs(Oe@|^THpI~nSZcG9g!wr7BRI1y zXg6Y^^&pGxD0s5t8!Is`RH1p`CEyh%N$y5=-;Sz$3&b@SiIJwh6~^n%`&|dwDV(oDtAVRg zu0L(!R#KlgMJ1E*s{6S6dqMDYS>ccfn2II`BpC zeK4XzeZF%zAB83%st3*J=$}y#4vmS6QLwNkB6YL`j;3wDf<+Iw0&-e`_EzZXchTQN zf}X2_oCn;UW&~B`PxE?q4XqoVXR9vPUMNuMqMx%(7bu?j1btSiP;G#H4 zMh}u7TrE6r2!B5co^%~pt2p0OHV8fr-auNBQHkq##sjKS+CXe^C9>&&A|!l2M0+3p z`kd=<+JW;)XuOxtgTHQF46Z>)=(4z34t6sZ8kH-o@__Hl^GF0f_qlLB0^Z^}tX6S8 z3GGhsQLuMxBtb$eZ7XD1pj0NbN@-I9Zq|5bH-Zm?L$2d$1?P*<7J^>`FCQDpT+Jkr z>)09~NTFg!iEJYzi9ZcDP0})b^ z2>hwuxDI?Aoa;K&*`V8nb`khx@bc+iG7*GkjC-+R`2>zOT#wzxQA*%`d=D8pWlHjc z2f)v`j&wHYW}&fz{SJ8Vv~O8gOG@Kv8iJ4F1iCi}$9+7d0iT5*oa>JIDRs4LT!%YT zbgR(#Hr9ZD0EXv$8%b?lO&iy7TXBs<5yfz}N@y9l=)ldGP2dLbtKb~hVb28JDzxR` zH^9Zseqi8gOqZ@EGDb;4T5H>{kRf+7bIxMOYWysCzw3}^f^HOAFZdXEYtvug0tFJA zVz`=nQ=^f3ObHxK%1UZhSYGC4rs>NW0)G#@(RKLEq8o+wDe$+zaHb!cgoUOYx>~w! z9dRh@XqC`x5e(pFa>l862ly~J&-E6XLAMF*8t|*&q8We57pfq#IB^zyuJ6$ZLW83T zXM!&g;OZjqXZ!VUf}aLG*V{Osgf;+v3B0|PNlYB!$2fB}7FQi&XGfD4y3TM9!uL}* z<2#u-2Eng^SGwNHxzJ5QyAOPjTCHAiHIuNbxyo`wBlXDkBofTbF2ULY(eUd+WF#bn z7PLCk_26S*znhIThi(zt4d7S6p_XQWn;4^sa#wQz>u3=A(Nm`>@I3Op*6PM=z&n?S zBY>N*nUEu`3m<#;WUF_LRx>6LTk;Eb6{m zNW)P?&u)8z{%ykxh~t!X)%geM-86-=3++bm3Gkx!Pi;u} zZL6p=1}FDu6w}VV2WbD%|a{Un+P*T`e@OP~Qaap>`Mf%+-i1x$isMVBkxHB53cC zqqKd`eyYJ?FJ3r^ai0{&*9NeQ^@af*hN%8$%d2p)EwpR@VJo_x&_SU=5fPqGq6YJk zZC|?&Tn26i4;H(z=}~5({XY0G*weWsaOpwl%+(m|CO!mzVtACc!EH_qkI;t~57FHI zUQ$ZaY`u-=?Wu*RCz>|x+)Y1RzY*vPZ3e{J4MM^2ow4#w*USA~VQ0T+|j%{nG@-rRNI>)42lV>8`>oMlylBu0MCo&jjYZTG`g9zw`1H%$=||6Q zrX70^*l~6-X9638!CAAL1)W}q7x*x^9z5cB(-vhD8XwRX!7pX~&cm>)`OaM}2a6$u z8=V{-rETx-qhqIrt+Nfy9k9;Ef@{=EY7&C_YN2(+S9b5EA3wL5*1x)whU*daVq7{G zSOydl>tBLomXhxXQi!?gS0 zVVcuZqh$-`BS!@U1+h^oG8SbRc(nJ(G5XIa>D9OQ!tpfqh9P+k44Od%x81WiF8K?B59j}qFkXFu(I{}`=UxPTVSokQE--A6xMzmcBVx}8pq zjKbM`2(x^9NDCRx7lpwAmV&+DGhpQE2ntW?Nx+%$aq!EO3a(girG*PnTqg?oI7Hzg zm}yqcpRtIPHuTc2J#_TsFkQN2h+cc=Jvs!p>kR{vqWHL*6&XYL`Pmlkv%Khi;B(;j zTpdFh9Bl~vEATp(K^PXBACPFXBb-SqafV_-UyOe|6@`=(AiiU#hw04&hbckKHHb{i zV2(96cnEb6pK6dBdNW8laX#H<7&6lvr-Ysb7*jCU*1%-OaZa2iwyQ0IM__H!XxPCTaUZ0v*(ZYnh6 zSZDMTaD%JG%OEtyR`5IEx4@d45RfWxH3e4_eSKCCERZ~D#t9~OBKtR`g38`WwVAtF zDk34WOyue=GSjwwQ7)ySKv-|Zw$nm`e>$;ekR633d$7vf?u;1GLR8iPS(sLU>}CNO z>De=Lh&RE%0pD>IKv{&wSNmh|li+Oa7iZ@%5%tM0z!UK4}N-4eM3(`STW^}WFRK? ztTEwCBAW4Yn`y;k+*bCcs*ahsfoz}l*NRb$J4n+g#$0vw?}S8jiXv5~x)*>U#hzy! z(0abf-M^#wIi+rrVuWtp~gtlwk=9J9 zHTCMq3T_U@A_)F(Fe6TwlCUK@O}>d9T>UZH$%D( zU8Ux;fDZ4Mf9PaTKji ze+>LfaF^?S<|wPsM!>%YceFAIUt)hKDGWR-tW;dCw^pGMEGib9fwtyAX#Efz_glQC z?}I;cy|+e`RcMT@;NOC$XY;XjGwiNE^zCI<`YJd0jwGt!yy!Ibs0d=i<%wB2+a~b4 z;0Lbv)QB<*O@sdoK0TX{t(!q};OVG_QV&yclBB*}bvgEYCRwi|Zf2 zmtF5=BFZc@#xd{-aPLe$Qd-*!>kGWuR>caAz|IyV33(&Kq=rYxjEs_rBBDe=i6#}> zc}cunGJo_;v7->0UGt7%4@XFU1!mMU4z!Mxll#&NQ4CSwaZP zTiK8xW(v2(3ucOE*}P_oO^t1L$~||3yW_NY@3>2&&_Z|y=O`r3&O`C^WZGxqDYy>& z4)_ds(slHcp&Nu&2fqvM0RISF3-;S5B1=dJ%-Bm&_HU*j&nCGr&8L<)%l*z&&Gea- z3pM;umi1N?HuO6F)A-01bBS+# zn#`+BW5u7Suk2efU4ox=2HB@}SWfX>y6-dRVj70|9CRlBCT{|lW`))m3(v#%i}SQ~ zNJ#vbdqge#Cmh!I@a}FZF}gu$jEK^zwGDg-d<4AGB#CDQ#!i-BOeVhc&c(EoS|N%C zhsm8{EKdxC5o3N9Ol$?CAQA&A2!<0#DU2(fJ;yi;3Nfi9$^@qEd;H8~-{TLvCX2~d z=5e;0_IX@-XA3Qjo1b}8>BS*rE+QxMk3%3Gc}V?NVaxodi-qo`WzjZXd?_rC#Sk?ij~=Y6|GOG5kq z?6ql-WZ7BX|J?oNT3LHnuhZLf_bklTGe|-MgFp*HVzFfj3y83Buz88#yB&P-C;NlL zVLJ%S2Oz?L4H1MvW@lI|kHo+*(l9fUMzi!xuhq40x!(2vyyxDVl~t9QRoz|P*_Ho( ztKZJdd(S=hJ?A{X_ZdJeP^|xrpI_ky{~YtPRKe8F4zBU=lizV4u$1EvlvbmTX1$6A zGw@qH!wjqh4oUT$*RyK^Q6l7ci&)$5%zmeJXw;Nq~`zBHJB!TcrWi%fseYrmB^aG-TWmHF$;mzh7o{AbJ~ z*-@LO34>iWBs{HVgIQMxUKg|YnZ^9=Q3L4Dq@agZIYGiuB~Wxmec{s|57 zPp>Y{o@}n&Fg0nlDNy2C55T$~Le4_l^uIWPF7R9M{U+9z7LfDf>!tG4e}HcO7Dp_{ zaTs?r)&mzt>G0`6*KkXr+-&=X%Wvswwq4as^Y1jvd^z%JkA#i&#5pt%np@%_ZJ*ZxKO`Wqnc?@Qr=c^eoioJTF**e~wA8&fpgtgKTC%3wkXRfw zYAd_-n6Oz_#cI@pzp;$_S<9w1F*fKL_7L1aUE8hoc3jrg<|i76cZfj=i9odl74LGQ z>So-1OuV&?$K6z#LZqj4spNNEeQMAR`EJ0VQ)~Q;qJSAuZ81N?QJwV!8!LNW#~{MgO>59K?0+Z` z8$2p46==qTwzXTw-E|hH55&FX$aw`8T|U$A*{1-bz#%lrclk`9lHVE|M)H|mOP*D8 zW@=RLR#I)(8w+?TSWz3aunk}ohV5}tT7MV@>YCik08PeqfSW#}#-*R?p1iM1zsMSi z*2ivkIIddL<{2cHQ{c3nMlAbbTDHCi)(%XVVcfTuAJB*cF3XdpMNxX1-9p<0D}xIu zJOYSmSukyzPGh!RCj%$}CIv;`geiNz4NvyH-RU!OGKhA_ITfGQAxZ|{yR~d>Q>2?; zHXSuv)Annr-LxS^;)ZfD3ZpjM3D^QF!4zjz_fv3#6kLu8Tft2mLfq~a z@n%Ws_b3HZxn|~&gw$`f&}`JzXBY$txaq#D#*|IZ7e=7~s-c)GEEbktIwfk%bI3lJ& zFYZ<%Zu{pZp7HHUH*?pNR{5=OqG@zAfDT*{7h{yg83~!!Y@*d@pw(LBA-x~GPGu?Q!ZBUBC@ zD+9}D3nPOn=7Glt3#oe$@iqgGdqTVQS^|;mwZ(nUm&>YQ1)hf{ffMjNrtf=nJ0GTD zf{+>Ig5wR-5tuTz~9d$lo6oquOXwdcTXACQ7782N0kTE#M1HkUbuyhTR zMF+O2BMf5%k>X3vZm6`W54wQ66gg%|zQpRMM$mNCE#u_EgSbyZ&LfOs(8CaI9!@#U zp^0GyP48S=%)gwa!(jIe9*}n5gm_n+w!-W)jqLoiLD#rnF|44u%zXAk*vgq2W{M_U zgRn*0j`cy@^AH!~QD7`*z+wa3*8k*J!r_pFIp_lJQW$BfkkgXZIF&b1Fm>Fl1z2r` zJlq(jrVUZwy#GV?+z%t=L&5 zdVrhN7V2IA*D|2%!)osLPlQnfKL{~ia4}Odc@{coY}+A|5WvQV3AABUmmE%>X>GqD zCl>Hjb&i-fTlAH@q#oK>*ZnjVD^s#AYpaQh$4mapxU`o=q$d;Kj~rorvq!BjjfPL{;O$J6o<*xh7mM59Ba2h0*qr@XtsPby#S}DD)@!(dlEnPo#!#T-oU%_t9W;A1y|;l zaD9FWORF2G*9l*>2}_INm?lhiV{tv~?8yJW2yv#6jwN8VxQ7yX*T#6cfFlzXoSd1! z!$+s^;U~`GnR5>z@_aV85Qbwbz~bJf#ZAT7px3vbF^r%IWW|01r1J_Oj%BK&4*7ed z;nA@)JXCgYs^a3q$H(A>F;*Ks7HbV$UE09gH&^(%ifeO=xJm%mt5s~&n=&EtjtPtK zWzY>9dU5)n>|N8B=H$cXdJ8!lhsH+eT4Ojxu+ASpgfoO|a(o2iqa~CHp3dFyn;xMI zVHyS^!dB&;4&_Gmh+zax-)&tY8aePBJF5ssoi+ap*kyfoX8COp7+u#e>gpKFm2hsn zh>t&V6c{OCqZ#1(+%n$2zKCyKp2Y_@=5d)hx4ep0%R|5}ucyyz@~Net{HXAS?P+*)!(NZK^bCi_?}iaHIUK9s01=WnTHZ|@ zZ7(6C49h~q@hx`gEX1LThK938CUN%oG(Pd%BZvrCJ&{!E~k51v-LxgH( z62}PDNT~pwjYi{rjcW0$I7=06AdOpkUfg zuuE`^&hgU0yWI@L`NCHFiiowGcTq0p`JmX6u0Exki_kQ7eNDij;7Be%=m`827gc}} zzJS+igf1X-F~4gzjhZ!}130Na=J?jyhN{ml7w-@>3WBvyjTBH}{os087GeSwD!76> zKONTWg`slyYz;jkyz`gcKQWA;$(nNg28f_?jtz^h7Vklt(&=r>hQW^B%~`ZmK-uIW z!Jz)JMJw?ZttG$-cSt_vn?Vo_!-VTt$sqo#udE}aE9OVbFzLXZpvjn6oHFmI>$&lY zsu6o|=}m#h9sehdCngA?WYtgB+W~{Nbt$(T@?M{tQ*SnR8*1IbYwo)kM$o7xB3)agw0o;DP^X)2cyR}sOhv6eySqVur(2fUVOK2B-ukT!3$@AZjB z!$V74jrHc$GjaP7aY%8Q8t;cb-)~uPbB=PyHW3}~HQ87+%T$+R&&wuh6V!%JJ~@|R zZFxMYUB+>OfG#Iad#fSyd3@Gm-CF-)li2zC0~^B#nsmZ)zX1`&ns*%~ym*)HA5*jr z9i~voL8tfv$~5Hhx0)VS=N2)$w2G@Y7jX5)0$RS0Q^#g-=J*VbOpT*Zp$ic@gMt(} z$8n?}h%(4BaFCfs;$rg7BdS0T)1!sWyc{j-mZIy z?Vz<&kVkuGi3@lZkVQE7_K*MCaI+ z_((f~Ai}#>XYtni*OD4v^#9r9aX328Ib+qVF55&>DHB0xrT9C4B5wGG0M zIEeyK1aBpR7vXsXSU}#Wy?`%#_G9q*y-5K3H4MWr=#aL8EFze-jhfQ4fcDjY_!hqL z-WAsCuxYSnJ#o4=Mp9c^pEMl#6!BY}Q`XQ61cPwPoZn(2`7gimd-&oHelI@t{Ik$G zsnpOblG$R^1+*Y(B7KGmXtL3*eO1SRVi-XaH*@+85OKK#!K9$PRQOql0CNOjgOL5! zi(kP@uYZd!V5v?Xry}h-Ck3|suBb)Rbh?hF#3^uzxMUu2D}m1Q6VgR<;%rjeU%&b$ zo_hEcW-4XnR5FptXT`bVE=}HX9JJ~!<#;MRA9L5|@amiIaGe(C)!QyC@6ZIIv^I-# z+ODa9w=F}t)q1^wR?Am4s%O|-EY>fdo93jURLHS;RPn#LPiG%GigU+j_?)-P@g#7| zXJ0=9MwmtB+T9k+y$JIcfA+@)UBfL!$gcZqzyBf@mRI3#gM?u)C$S4?B34s`qiuHh zEX3(*jb;kjTM954*J!mUkkk%4BqDRkeSt_EGMi3Ihl)#yV7GSfMCfS0Uc|@ZO&ue} zJl5z+Z+!a_j(+H=7R=pX``eBTb6Kq&Xc%}mxC_#yuED_^7ITvd>{wvLIB5-O#F zf}==B&J#{?<~$pYG?F~OOM{U;U83_YGUr#;REo2&RcolxiNx(JX&C9d3wamU7nbp7 zFa14^eg4yG|H7T;(%uwVZ_7*eWEaw`G>0P03nz~ax`tZ{k=Vcc>CfYRcI^N7Yrm_0 z>zg9ZF`q{QT=(aB(l*5?Lfh^^*)(7J%B%SDYu|)J;YB3Cc1%2T?ldMx%PCMs+uf4) ziwoMywK};KAex@1T%tjT2*Sj{8eY=%1ve3Sj$+Tbj{5G({G3OikZ~zz@R}YX&Lgnt zs!8Z=p$d!wT8m>$7IS585${}^#dD9G#mSi|Owt+030f(iQ*+CH8G7naoLu%nIdYs# zIXxz30@fSR@dLVh1B+fB`<(u=W0m&SaCgFRTP3gOyc@$5dKdtKQ?*5uu zOM`Wao113OW0DXz8yU3T_A5-)Sq@lKN=3{}czE>83Cu06V18*$35aos`LTY_iU4G+ z03%xHl!E}YB5p!4iE~PKKRPvz?|bHPJa+21>ek9(GWBmks(a`ZzWj-hBfe0e3!*S( zWK-}8Qod8hNR56-f!CXa!&M_&bQ4K=zn($T;Ry0uWbDz+Os?azAAJ_3Tn-MKgqn|Q ziPHrOSUz1PiX#QA%(>~f91w0UPwEploEaZgYk8FW@MnMf8eV(n1LaE6w4_n2tXJ_T zUw#D-9Y2gR8%94@L%M~#gr4S5ggNK}ZYM;vQ)3nU;?H~mUw`Woe*O3V0`tqOLc#Y_ zOh@}ZOR-t(z%CtVd)IYsQ@O!qrnuQN=S~r_#|ZTpS`=oz<+aBu-jE7ZO8{cD1c1|6sPNK6d}h;b`F-e2oyfY3v^|=ms}I~ z5KSi_Y6`gZS`Dk!n%YO(vJ*$8!`ocH!5XDLJ#8p4>y#QLWuB?Z2>#IvAHrCi|5dn8PS{5QKneWX@SCOaiKKTL0xKb!2?-xKhzFUYGWzMDunPUZLnOEy(1u67WV#5pQ zm{9^s>PQkT*05f!V|Am7YO|?8HQ8|F_eQM>i=Y(ffaPKl#hj~Va|vIb*JPZ`CJxr{ zJl133Qy+Q?)1wvq*(?8m`IR;G4ryMl)Y{A6If*!WlMO5GF$7yda|fZTyAcN(Gzsa@ zAOFbH+D5(k+7i38x&0ocCLWswN+fcc3HWEt{citN`)e($HrkONT?i&x!P!8*;&VE zsf0?Ypqw*`66f0<@;+H#i?HT6F5c!~o$HkE0%a=*Qm2(`x@r=u8#Sy|tNiYzE=wmf zEzB-0;*~ePj@gAd?un%!%ey(uOwHip6HmdcHA%)2#^_=r#exDX+4Df{*ToB`F*Z`d zAHV!HeC@4EcR8qZCerBJ?S4ag^*_GZ$M} zUBk_#71U~Vm;`6$D5AJoi1Hz=d;<;?2MNGA>`A zMWK)hKhP{1e{|i|aBh)+mjmk6k4VU{B|3Fe^y+Ajfz9%s>7l z4vmlYo&SD~g9w@&(-iX}^9PvU-)y#ypF4fR{g+?-A?;Ux_m6RXZkY#TqnoqI5tRx# zxQ?Cth?5y@!Z}*X!{O)6*(G%?dtRrD`M!@Ei_2K1lSS;<(2ef$)@{ni_J z=e=)I06s-ww%=2)d$@dK0V9V`;Pj(U;oUdBhNbIQ5cn-MM!*md#IZITYrqe~6f%v@*~InvCH0)RPmIKAM@A3f*!jm%WOE3@ z-=@Qde1|lqq^Xck&RJ(OsAJ;TNt_LQy#4ntp+;!M$ro4GF*81fsj*7C36%3WeC~x0 zqs6&$oF$HWIa+prT5^iJ1e>2$;CYO5-T&m{AH{QzJ)Bbd0JM7%q5!tTCcj2Y1?3QN+AS@1;T+-9D9Fl45zU5&<&|{>n6A!M z!`$*J=9gF0^W$`&Q)kY?9UDVfU4_F6D&;XOEG(ksdrAlL-Y|;c*e>*#E=m_UdG)ydp8NNxRVID8*IFg0OMFFvQFj1=@5(8;zEQP1t0N!hMrhPwb7vC zc(A!ngHSq_i?Q(uj2}OP+{m~B_Q}Ve!Z+W1jq8ltj%pY-oogDS+`HD|brk3;$4{KZ zwfEmaK;Xq4Z*ZNqWnzo~goImQE9PCCqq{kLSJ(qIIf@`)t<9!dV?SpL!jRh3Mn3z! zAHokm|EyZBapJ*{A&;{s+GzElXS!^sOOlG`%12v{;JNT~ir!n=D zKgqRv1k_NUuH#}_fGk*8d+$xc7ox=H&Ky6A7J;gBFXmU)aOLK_T6-avQ-GSL&4y*F zhS4*mR<0#y+v-T9)^4!L94*gxfAkX{ec=nA{n+0$S2y0^-Zuv=ygP}52wJ6A-6FuC z-o#@MpH#5@_y73^c=zfoyRA4|B0xE427Q5 z?DQt4>0qPfq7rUEw}|ORf``t@pFV#MPn|o58l8mQm`-MKoUP#W>g(`1R*HxMx+Fy{ z5SHj}0&$&SRtTOFU!R3ns|}1+`~;W|AS13LM@MlS8x77E$GQScoHuiE86L2CByWh} zc}?U@3l|@Gw37q17Kvu7soW}QKmqrQb8;Wctl8yzF3-+kk^3^rcNFNd;qJgv?mR@;dQq*BB+XqeLyjEx3*np5xjIrcB_SVX$tG z?`RVIQpwr^ntZoR1I1!afhO-Z2!?V$-Vf-8vL=}~agn5!kUtu&)~4ZWn|qKnppKdq zK(VT;$TeO#eM0R|nN7=N(~@$dK9FT~#$3nYBhzd$IV>!%fhM@4xroC*`}jE=J2Gwa zEWd-3KgP>H#C)0gpP7HROHaD*;vj-H#p5O( z=vHgy<^?*=k}mG6VRCX*K_KE50OYSuw_liFNu5OB;$-cY>{>VH;~o^*AjU^WHm^l{ z)4epG@k$9Z6Qh`0T7~RDXG;m#48+}^fBF%1Rz8~xLyCQfd6c=%d{u_x0EIs20&XLw znD%aiE^5!*(t}96mfj2em1xAaOfwXFYP+q-&X$(Q{tMu`o4R!I8t07^RrACL+(-mc?sj zOihoeYtbGXLaz{KZLpciI&NiOB0s<=o%YP}!vsv*QAd@{;IW5K;Ni36D%io27{hbS z$vZxXdmIPR(Mn8XF9SsYy655aktvL@17EEzBJbK58!4vl6f4MjIhr_`OYwRFKq?3k zuhs>G-Relhs1bNwK_xC$DCA(y@V~#jg6Jncd55?Se(vV z;o8G6!uQhiMxh0EQ<~1^xBUUM%L3 z&%3DCTc}oR{A|J}5F*e_Y~8@?6r=){^SiEvLO!SFbSW@#SP20_#MEl}>OF~YyN79- zFm!^}N7y3dexOLd5NC@yZgFXqYYE%?kkz{#oNQa9PSJsM@z|(iRNI;YGU%6v7-J>{&pv^M>f_a{4?LIt)sTnvtK8n2KphD4$ z;DfZ2D`EFGkv0$_K5-&RId6e0@IwMe=vp3pKTz{nmI<3ev~5$lmPx2H_Y$FGZrB+C zU9wuMqpxOD2=*fq*fivFE=BAp$7nV^Xq;bal?I`w4M?tK-;*Ygz!lvA>>>9mU&!P1 zi6eOFYu{A+^@HDi5idOR7(DJ}pj=+(J7cvs^?Fl*CUB>Fbc*>H^Z)J3hTMZVh@gp5 zzr_6K%#qy&YnqPr)pZnX2V>$}hP=N<$VBM9KvDvuu%j^Ew@pmelho`uiDRe@L0il{o6env%oFpyN2e!{=l*^A z`DgLtpZQ*BT;u%03N|)ssv#-&=e2sHiAr4J&T3hW>}v4#Z8Ppc97ND$r(a{f!Tc`t z@gwQX&1MTri)$$IK&Qq=Fj^|AC*o91(y;}cxUZe;6zTTw$sF?g*2E}6_kCXpOX}_Y zP6|}LOX`jLyWcGVhqg=It5AF8`8aWC5!{Jm zq_!qq&f|E;Za0HD<~#SS;C+aL2%1EV`G1gr)-~iXBX+~Zr8TrX4=%g*;mI-OY7%j3 zKH@0*5w|N;dCs;in5M4k?d`6Fq3tN`&VFDc5U3_b3EPBPchK_N=T<7^k*0Tw<;bdJVS{`=hdZA0G3sm^XVaj83(&QN#LrRsD7;<_pJ<(Aivs znPB%3v^xpIG$=5=uS?0jr0#s?(uj-zy)F&xK2v6#zl31}Y-y8c^@ zgACd-^F?gyY;tIFKr1U%G#ah+w;Zg2av=wu2b>92?hVq>48FVB@-Vxwq`G)F!AVHH zmSv!jr`WW?HirEQS!)mkY=-M-G`+6pAdN@Hl}ZKGWYS}6B5AS*Dh@Je5%X2%o1GWs zV5+qSR@S6bCcmXC=3I+nH4#UfZXg1VqG(_X5I3D)Ucq{`w(Hn@&Q+a#7~D)E;yFlj z@jPF-nyhPk4~gh%vgVO;0qPW!wXZTS54!$aje`uD#3kk{*$;tA4sT_31A!m%x44&d zMqPEp?I$S*7Y5-#3O7vybvo|c;)<%PpPT7iM?u_J-*n@H9J1D!5cza8S<}Ww9rb!c zo!92N)ku_zdBSEBI(0$*`&;JHpx1D#anM0qW4?>z08~U#h`SkF8 zXiB`=y(?P86|o^)zqx=K-8b(zaIEfbC6_GQL@w{#_WMNG+C5y~?)7lr!#Hh*8Umid z#zrG`HLcxXEXzb$+)Qh`*_+H?W)7x1-a#C6&?Lmw+8s_{Qrx76V;DN}IVS-P(7nyM+_-pl$V>y0LX z3%2Zo!G?u+OTDUp>Zia|R z#51?Jj4L|>k zuH0ZZ58$#17`p%@cSMj1y4wWAp=;LbOl-z^clkQIcL38c zVVma8nzp%-pyvC*Ej4m^PC&|FGA#oW6BUX(!quyDn4Mixjxspd;?&W$uBlOPsq5P~ zt26(Yd3iv^?n?{<=nbxOF)z7wA;0eUBWaBm! zwENz^x9@P~n)j|f|DUz?t~zz<)EVx%bw+31yG~W@;eFTpzRzzx%Z>Mtef|>18EAZP z{K;-G?VHNPB@RY{cb>yAo+~s!<_7_N50LfXXk3J87}Ts+NrULq83#Tp0tk>{Q%-Q8 zi9>ZdeYn;RJ$brKPoM5kr`wl(s8!2UtrTSsI-LQ4>u39Mfv{!gLec;;(D$#$SmOu{ zY2VEy2K1+(U72`h+!3{nI^J^0`mb$ZeV$S`zz_1-O7 zYd7TgNqlqNp6A1XddIr%M8N#q)=oEHQ$qd0ke)u<7UOg@Z1Qlr!k-x z#M-0*M&Y9U&YkYyru->rS12AJcUZLy%q(aDgdPOZj6e@6YI^X}VV4)|E-dU1o^I0S zPKOfAVdjvnwwv1?1U%c1@zu$dfD- zENV94rkW})w~gA^F}W#RRB#jE2DoSkxQ@AA@~5C(q1Zs)XJ)ulPdF2Zl9UDz7M;d%JqlZ|b9jEtdl2QKpZtM_QN)j&;&@Xqt5bM1Q;q->lFTGk{xP`5iE zt~5eJ@%>QTu0L?;*|XgoM3Q%BgQ4PihC^5Op;jwVrBV`^kK8eBZ+9t1O)}4U2c}@i z7`8?GrfL&OPWPpc?4EyN=NtNE7qFz@Q~3`5jxEb{q>DpXN-ov_oqGt_s+D2}-+}?y z(fII{T-0X`9-oE%Y;%_$KG}rBCS;j9y>f4zT8*mw=CA=?xm2KTZ-{wQbn?7bsUywY zNKxTdYTh6cxxTgC0aznSFbdPE#_=tjq30AV$1pSs0oUw7j=Zr5(YB0* zFEeNn-Z3o`S~#oFGRU@fyY%4kQ*`b~I`r+;6>2x?BJzod`MI^VCh3MwolZYM6YH-3GtUaOKogP`(n{ufr@1ILZ&FQqM&Bg>gRnHtP-zF~P5z;-Mf-Wv@ z5@_$>u)3CMG>{YoksRK%IpdJsaUig1aEe)&#O30Y0^DcN&K3%sLZ!U{{4xX0-hkeF z^hD<8?!3~d(e1UCJTdDO{GDN2Y1ajQcEF9DJ?f9#siX2Ud;Nioxz=h>x!_FU;`(`f zex^4VQg1YpX5wKD40sj5ynJho3|*rVU|n5lkOR2lT;MG9O1VhxXiS~%K;GHj?!tXd z0IDAXVHv?*%Ucje>}Yhz(fBtvmzn4yzqRy2E+K9bXb&LGU)MD4pW2RP^!g(RQlo06 zDBYZ$1@|Zh08tPeej8^V2BEkbyUZ*UrwN8^Fm&nu!zVO`tMGW$a*1BPyN-MMLYGLA ztc%xbWz?q;>J|}(VMsnF>hV0Eh5%>)04oI>AQ%G6q`ci;pEh>)C;%u7sA=i|s6h2f znOco%=28HPKiSD9!RuppYcwk4V*D`x_3*j9-J$jMX4ZVtvpW0H!DF(caj~E7Kn$~3EpI~E)V&aI&?Mb^l?%tE$5cS5#p3Xo4Xc4WRD9F(s$n^pO} zOxCzYt~m_jMH_)Xsx-uz*hId&yb3NaZW3r5444Mt+;BJ4KjxL=apHDZpsS6l*NJG=<6+p(0b{u4r;AvR&X{sC=+kjJQ z`1DzTaduzo=I*b-4dGTr1~g+&2IIA*Grx~o2482GD%Fy>@a|q;e)A{8Rwy`9*D@o; zSuAq*Y+WShlLv3yH<4RQE#Q(uz3c*(9Iz_-4OLa%(g0Z^BFj`Z5uUn#kcWbW9lUU3 zLLdV?iyWBekJA`spM5T_llNq0r9rJ`ja0bjaOlFJ`*L4dB5Ogwpv4Eq z24qSGK?HFMN6O**EYc)O7DD(u!8P-8R{`5ft0vd>cKhU^fgHPE^CfX3J7(W>IKBpu zdA`ZKJbt@fBge6_2A9QCiR79Cn!Ym#B=a5jD}rDmf-m2z=9KO&~g%?3+Z*cFJI3L3|6BLC>X zl{6ElijGPr7*5~^6h}w98o&N*YnMi@NB3^6(w+4TvSdk+O&Wtg_GQc?>&P81J!wIw zjLBRrI83SJP_H+nE>cxb2bvEDwtUsQ}Qb)3xNmorBMAd7F93 zag#y&0Qql`_YWF&H+>G-#z=Ck-%c?{vxYf^6T8Dudk>pkxgyKDIHibFqWnzTK8NR85<8 zGY%K|70R6LM#N19jpM%~{{`~Ffkng7juHX~--;mIu^&Phbm&OsRgZUHekP9N%te+(8iIviE*EH}Rigk6XK$~2th4geTn9tO&&{~g5wImxDi+AH zO!+<+|BvR*?7GKI2aQkgKO+A*%{ZH;YR7`c5wLirGatUkmjVcz?^}j`;#g-5MO8?* zba0j)DO`3v9W`(+GqU*=Sll=1dtx`KO_6+vZ2WU{!~$yj`uCeNjE6CFRa zLJHYkDHHERocw7R29+u$(lqT@7dbm@Y^`)GG?SX5Ad=rnl!&vP5&q93e;*m2!;W5B zd_RE3!L9heBHw~w9dzC@y6L}$fPQe%!z`K*LNSl%;C$b*45Uf!*vGRGnI@cP89G-c z%qrrhI^3jOD^mbR@i7;>20I;#o9`9M1%XXCP*h4#GXpv87%x`Jse{3i+9-qWjL^H3 zHO0qE*vTsux}WN#DG3?UK(eh}ZeP4I5g@<8f*pHfsDa+aazBo1>g+=-;2@4Df?xwb zpb+9QP2+%Yk_1ko8{}9P^@k(!gOF^1m(1*(IDq`0ldH1-F?9)is(>fW$4)R;jCt{e zG|bKOTaHCe=txccwx+27OeYnt%C(OAF5ESyVx>qb+zrDad1(-RKBlZe{?CJ$E^ZPS zBf#1sKvV|MnywzXx$L+MIlrT#HqJ8yyV)OHpe8OX^e=~Zsj80YWo>VI(TTXR+$`J# zAYUNM?Si%`bGn0yfZ_rOi&sAm0vfrV2z}nsSm>pqLpzacF`scBSjdf+a1#8 z(_MP{c$=O*-4R#e=PK1Al>i2(13(K!i>!i8IviNd;pauG*$;t?Va$NbpyPWHYV33e z^1W6qk*2DEIXSei445DI0x-XCVjc|*ARF`4@iy|;kndl%R?Z{z1UubH9OP}ez@NMGOVvtA1U2hw3LYpG3nE${04Mo9 z5ih>7@b7>3F%5?v?j_Ur#~z+d63HmcFbn~R=Z?_`GFM3PJkQPVJbHgapk_xaR|?c> z)u;@RI=emE-s;i-V6y9oE5gBcw!2vk43nlvlQ7}7EPmUD3j;WY&%!m!Hpzr5+W1|q zm*ltO*fJl_&9x6l9@bx!>+_IJBECt@mg=@~PFRim)^1Nb+4JG5`dBTAD$H ziXmh2oY^0AfhZE-I6{2y?+&TIH$;6J#Tdr|ByEh%uy7rmwyDcIV~C&Y_3_D#AdONA z2l({hq*h3-vt$JFZ$Wk2e*iohGkhaHON2zdOwP6J@; zy1vNGT;#vXo7-oRpQfzY{VMV|k(-w-it`HQNMCd#MQ7ZyGlxrY8Uv$3cSrZhO#I8P zd71Gp^0z31O`W~rKrAd&rcnew90_Q%!H#6ZB?=HHi=G{Tg}VpHc6Pc{C|dNHpZFLR z$e@Y=mtfsNtSnr4a88F20FA}PrW}jd(|l}pOn!zxS=<_+HXvwS2PgnfT!{a%bMn75 zpN5~O?E7Tgl${CBSrs&jW`PF&n0Dci?BoM>a5yHz7v%NM2hYWB#>o@# z{FY^j+b;kuK>iW(PmrHO{vc%z_s5qlg!2qGrw4IkF=!l$$PAy@FIOwk!{Ud@O2%}{ zeIKgC>uHiZ-n9+x8o!SGWn^upMMJpk5C*yE)GVgq$Q3aeaE>H*H5M>CAA@G%Sr)xF z9*a=f)f$aDt^dHQ*e7)Sp-+CtBfsy%Sz-ZBnGlr+zi-S}2!}d8(z%ax>VQ0an!}*X zxDOUUM!_VfRV1tCkcu_fY1TwGxAp*+Pa%K{7#@tk&`8_f^Egt=B5zE-dUZo@0S>M|S`q???>y z(2FK%1%vcTK;w=}!N8{^jO86=;&4k25jzs-WuLg9>VOIkR%jPVGj#zo0#xjZ>{>dU zks)I@V|Oc+isIzy0&)btC=t*mVW8ot*oy_v^M!3>@A8g%`7tq?kg#v5hMiXE+tCU| zAR{1~f<~w?=fZIj>H{{PFo!J{EI}8Lk z4igbhe>kFAwG1;-rb6P6TDg>MHj5LW30QcK9V&^lcT>QrC=hwoCbMKx=rV8~1^qFA zOAdgx4Dh7Bbbma}!CC;jS;^*Sk4xcD4Ale-hK%d>(I^-+6Yf-SY|<16C`}g5;|IR1 zQRYE&F^_g&UeW)D9ADZ=FCml}4j8I#>d3WcahbM~vfN8%4sY@-hkn*c8K@M8_@wYM z>1jyq@l$f*5tYILuJe8MviIe5%OLtH@=M4+KPyymH3%n&B0_T_*Bg`P`BW|y08>1D zj)gkiOhXfwa3E02HnVYXeK3TJg&|b{rD+*tmMzlZa8cb6*g`K9hhyj%08V9cw94c| zIU1^bC24-Js-}`=Y2u`233E9H98Akc%o;_%KcXS(YPD))04fb`XBe5Iu|wN%WPa`_ z$oO7}#v+XbY3Oil<48Gu2l?;mnu4b0_R&u*q%8okgS{Wu4;agFCZoT287W1IF2EI{ z5tWUeTy2dvNK2#3-lNmRedKQ;e|&yFEC|o!E)VfBT>Zh2iUpf(BD1p@p{vr-b+Rp! z>a{W)LKS!8>j|Feb_X;b2e?)rxG~h1mH0%mV5L4_&6pfKNcw$U|4g=(Zrs=!_ zAI1>SF^7_;X6pi%0gzSH!}CvI;5m66z1~pj;dLmvL$h<42ATtWotuP`ccDeW@5FGu zD9X-P+zjhh^10^1L;f4&*Dw2^pC>Y8Qi_4u1gKtOQzv&ZWzMlqiY0)Sg^JGSX$53a z3LL98-EkiPw&a*2yAr_#{yy>@N3)N=6=Apa+d`m0Hr zzBIXr?;;=*u!V8fBnE>KRVyVx#R5IJ`RPRI3!+eTs6TKi3|Z(3x!zbrUx52Doa`ji z*QZ0|QeHIV%(ZMAm3{Hx0$*cb27@t@-87K(Fi6}K%9zu#4RO3la6_3ijiX`$Vi<)} z;B~_gXPtcy&y8{GKVb!*JF+WWMx+@u43`J6`1^ynK|Qz@M@U)2;EL5Hn!>q)#*5%( zMM^f!6Z<6`wnBP}WriMUUJt9$u8Pb30j0_}3%2=EGAkJTGj*NZAP@+=u`i-61Dw;= z&BEj{iUo)EI_Q%cgOE81gX;l0zQ^Kcr^#l`fjQKWGPm5no=yRcF&={xp((I?jy+%M z<#~8MRm~uAoDA-C&bW>P?7(_3M;ygd@N}$g0x*Y)@9x-tJB*_LfS=K64?sCrAld3u z3T-rfRi{yE()$1`Yi7zJms@t6D`@kP;IJPTUJ-$4<31@{U!kb`1l>@-3QeyMu{?bJ zrQ5M(7#a(bgSBI7I_YQ#VH%5wha;Ct0Bu%WCj~!OD%p5<1Xqhi^!z?&1mX7jL%5tz zmSu{IGK{Lgp`jNka*cm8TMP{s#$ZJdd>BR)AfqUv81-?o+orjLscP1x`8R*BR*Ev- zyd$4BWc=I-HMl+J6f%q-pea4s*y@hl@y2Bz>f{g;r%q9!L7v*CM7IU7OmY_^ybA?w z;&QTZyF$_WCnzjz(%}AE6uJGm&VBKL>AiZn7{9c>qUD@Pzhlvx5EDbjavHiGp<9z7 z0z2Knse#~u_)p&b2DB7L#6`SbUJTJ+k0Iaxn6MT2P!3^8Cg{twceoEu91RfDH^=s zxNy*>ktU>9nq*Ylq!#P6_a~pDBpA!}OKg0jC)=HPwOI#Px;O?0AfT|Dnz$iW@aH51LEQR5>N8wEE~eTTg6aF}fDcIf5x6@a$y1ngcq1QnuQ25>NP zsZuUx;ya}~u(;XP>a{X;x_ycoxH6Am4><*?n=2Zb;z?u9LC~a91IyJZxHvJoxN^2bjRpN z3ePa&$CtjSg$qSJswQCZ;=Jn16ckqX;kyEHH9+IYPhV}^l`IZFpi=LC-ia;>wsc_V zdi3b&7TtfmL2tZrR{&!N;|eSY)(ZkTI)-fMdSnB}=Q&IkI*(N-*aBM@unh*TIK?C; z(47UoiMwVWDcQCK$SN{l2HDw!H*xL|>z<6EqbahJ!M)PnU^L$A^cXk;&vJ+CUyRC8 zQ=tvW%H-Bxo6*YE0BjOh2ei2umhM4(DHS{KUL0(SGOSgKaTqq}gRNaMAfyl7Sr;*} zxD0e}T~jGwmqTsCp-YWwSt@&;W94V#7*2z+8jUJoFa%CGpz=2z)(BUR;2{l%gP_Bua#N6Haa+6D)jVdoLJ`Tu0Y+BYzyF zr^E9*r-Y(nn}YH!3hgGPs(z&*13YOPfl z*uMS#W7079y|onxHYOYH;02+Gmx1W@hvYaGJ-4k*+0I-`1uTl9;R;|j_m73|34m$# zBh5(@_Yy}F8_U1XI-erXGPuhK9-rNe*A3Sq3v1SNE!_lUd)=O)s+v9Xcml}1r5_a5 z6X*r%S6`>ZKyxz+;%aBw_zR9J51PWA3IZHeUm>r2hgQZ6%WrSDW-Oj_5lNpTOA+S_gd0fNkjH!pRtpPJcj^N{NaETU_Vt8p?p17fr?y97~p} z9;|lOZ>H}ry8nV_fceE);b`21bZmkR&;~;{-rU*a$}H@KRLHJdEtk?etF2gB;_-y3 zN&)2hcDzoJ>g;Rdn#7d{Eejm4qEf6`v{`tWl(9-y?2#3XG9@l4FjCJpt+5X$W5J*+ z)7`Z;J$Sr9Z+-6pI=MotjXD)Ai^h0{-6F(iw>J=1V?m||)xL}-elGAlZ-j7h-V+t> z?x3keagsjS+@>&!EI57+SwfC&(aK6I-Hff!kC)T^Ov9jUwMoO&qC}>;`VKZ9*95fv zNC4bZ=M~bEfYwL%sTg)4aCKS3yQZ$YwrP?(_8_L1Y}=$eYc0UGMc=&th%{BBR<%q8 zGo;~oEOYk;L#mXER4x@Dw(BQ?lY(6=2m&;g1Wsm)qdnW&RYoIMLkMKtbaY+AUbV@v zZ2KD@gs(pwq}&G67hp{0Ty0gU)o`Sa>l)V%v@GBxs!1Egm#GqT$anh`1>KzG+$^zg|Ry?y^7ee(5Jse-QV;Td#xilSIttpE|8hpSy?u!FIi zajIxCHrCzkk7&2s<$D=qSTFDWYP%r~XXwWUw&e%V{+guF&Y30_C(|)rm5K%DI-1yl zxTc^H&W~ZUXveulky@wColWusU+%oXm~XsE-kn$NgdEeNk>>&$2nlo5t0fAk_hdlfW}QD0Wt2-l~3EYDZn0V?(B(!X@HQ|n&Nx2 z4%eww0Ypk{>d1Ax{vix=CeU^i#{hkDrsyl5zCLWXHm8;4@za5Nl< zraXV@Nc82u8Kml6-W1a`NYk`TNE0zNs?=`O(9H+*t%r|gejCqmJCERg9k^PY#3ImZ zANdm8kxRii5U2NEMq8S5q~NXVK8}>YCk5}jfpfGhTgKzxHzlsUqfLT^(O$VtjpiDD zo#}x7GW77#D1|#ASsNA(+t4#t~SIM|zHYJ`A{67hL@13%YJnoq_;vvLYW zYP43#Fm4uP95=+#W)_4FYuiQgypagvlu<+e44!T4L(yp6ec+X<2*M)m2%np9<^#|kzLFQ~ZWGTQ}ZMUdi zDGOwib@Gmfcu#&RbQ^y;H;$f9rDCZ}mhDifRJnHhb=tTwjy4HhH>loRfwQfWY1(v3 zcl#9bNB9eamdGpFdltYobp3z;VmweR*y3zDI`Q^ik2ZGp6$=g=y+s-pmSkONKa|YT z_%gn>aphx3?eI+47wm1V(VFhrO^zD}+9bH^R%=bTnsw44zKZ;d{Dq|y;cv_$$Zzty z7C z-~)1l0M1p!Jyq5kV^2*qF^0^tO!>Vi;#7LkBtC*{&d*h=w`gts9u*4Z%U=40#Ek`w zL(_CJEn8qaX8oT*eu{r6N=hL+S~>$-E)2)ANS(8$33%;hO@ND&n4ZDOI=vz3nnpnw z(bJ6`@*rGx#;Y0%+$xD;3fwX6bb9plcOOuKe=E%@HYjtO1j*}PZ8xc0DoP_;6ucvT zoWYjw*6Wlxn*_gCELEsnsi7emm%a20i>rJ3ONvHwm0ImvN8RR5`-`*t!0bfnL7+Gc zU6*b??~WosK(x}TQ3V1FBfzz}Oa0-93_~Z+_wjp&{4l(duyGSXe<2Uf`|#Noef_=n zNjEfFYd7Rxk~=qNt5KsytwJeancs)m5J!{2<>zb2Ta&qp#WLK`k?-G6arI9AJQfLe zDHbd9;^341IP%ZUUgRejv~ZJ0U@;bKOJHN@ym97ao(I_AhJA>6V{3=vB$j$EKNQk+je7k7eeIp^(RUv`rDDOM zJL@fhZx%8e>snuF!PPbSeNu>{r3d!^)6Lduxm>B|JN*3@SK-7jBs931Z5K!pkqbz# zBLB+l9`IF`5jz@xKj3QleRefX)ed!J{>h!bQYz4Dt4=!R8v(LM&$eiU8?_rLTXR9z5Noa>=2)fQ;*obC?)54Rzmw!#R#Uy?*q#*+xZ4 z{$0k1(V)z~R<6{31@rzQF5N*IlSBA^3GJ8v{y)C#8ZIn!-JnXfL2(>W82JAPmwt{f z&pwmj{2eu+wjLdNpOwLG#Da_BSOmK$ijE~Bb>V7Z6w`3zV!nt>h&u}5Xn3sv_qgcb zdKq{XFl}t^(igw>4sGsqs9GrkvbH$!EMy$)WX*bY`un)xb@7heAEearv9a93q(do= z?G!(zX~ti|1#WKlkRj4T@Qcj~+dtx4!i~8Vp@=;9ILrIJJoeljrSX9ws(&%8jWx*MM#4=3sg7L!1SeWb_tF1akaJ0e51K_H_xw+Go z-(x?ZkG}R2)oNu*AaE9THvZx9(xYz7g^~+fg|#S(D(^7t?5sn~x!dj2?p{}1Y#an| zUYpk24Jz99)UkMd{JmDG(CSK496ZTg?lkiYXvx9$#cPYO_L*SaHIZ;Q`dQ>7-qv4$H*PigAbmO>-qHNM_;9Sr6kUinUAvX2Kg8E zqsg^&cCHD0`~kR7C`E9rA;xF0*hTlc1M2k$)E|1}11<*1#Jb7_hgO<(D#OuY9!FdZ zkRhA(3aziS$T0M&%bg~atOS8=en&&>Rg&-3oICP@Udr>c$ZsRRiu^qCYx(c+Vx_bE zxJjTX`FdVO{t)uV^3S`JxtX^A=<)8LDR2V7^)N80u7zZ%Da5lca2AZtu4YY7x~9u&EYlEoQsGVv2Mbw;_;oE? z3fI7ZGGjp)30S+G9(8*|>W@ZpP23d^n0T)N_jGIvO~Sy~CTcSTtO;biD-7Rit0_(4 zc_5pB#_k`0wAmKMjUwWv6h~6?F<~M_7WzK{G8@^_H`7rDdRf37Mzr?~E*8AuCx z5BU?wpQ6mUTF3?+fGZ0TRC@BjDq!1Xw*4j;4Z8oF;zV`Q3e;^Q;&W%bCMKboD@6= zyV@h)q9$C;Q4@6QeVBM0b{5+LK%RT-SnMh+WEOs@Xp`#&)B|9{p)0PFiukk6f5>rX zU=#D^=sZqFN~m&<_3w|*VDdWFSDMtU*QU+k zc|ywz{Q7Q6U)xEtnv^-G!=6Wg?Wl%y-0;ZNJU@f{d&sXLe;fHZ+w79{VcpB{QHbm=o%Y zk*qU@t>9QRu9Wa@Kw%V92;dkxcDguDDB;AItlBi6OUe9H?Oo zYPln^a|26OeY|+ZJP*HjYo$%~T6y};^8^E>VE4b($sl7!^+Ttjh=10gX=^uGV;*+BTWf8qmP==X3`Qwy{!TZguWrHd7ecmgYhmciyzH>gJJ*7v zF_14Ie;N6=kZ&WufczrzPmu2-L%Jey)j+Et-$ecy%AAY8zk+OCRzd7)L%7;Q-=a4i zS59~$5f+OA0kMk&&wHi}7duXpjmG0JG#WdVnNA%u6#&`QQn&|0t?ah|cFFj3V9kQg z&=w00-3Da*8OIaPJbf@^=rQyiIN6s0**JpowWFWs^+jO-7$ZDqz9?w(!O(p&&%cd) z2l*xB?<2p8e7wxb&Jvdi8moo-UyU-LeiHd9k^pHSxJ%cNqf|;Iq4tBh1sYJKe+i)}szvJf~XBM(A0Wv>69qkX=v}9ETpR#iIAF7t5Ku%)h24y z0NL}`I(4#c=49b>K$bZ&gXRnLnJm(a+5#K7j{G^~&mgyuzlZ$a$S)%|kc0Cq;5CB1=su#&3}fT#UsVQgqp69tswA^#5Ymyq8<{%)S%qs-}oWly|p z&={ckn(SB0x}B8@iSYA;*~NR5HGEhOWm@I@yU4eZe~A17@-5_(Wli>?pz(I!LH;mhj>QGP zMp?%&&To(Y|Mtr6w~gb9;%8@OcljYwlw`|JY@|qF816$*v;kVAXwaq~K!Nn7PkrlS z|E~TYtrOX>9Xn21!%l6-ab(H*mMB@INQ&fgcY5y(DGP%9A&I+7XMLO_kqotSXXgIy zIiC2Uqezp(V{bN~`&pn=n|6E1i_oMROA=_@klfe|-YAF@Ls8OBRm!HmUU>96}&tXM#J+$3`>WVa~E zy3t7>dtOtw+d-i)W(JZ@Io4jFpY;7(^54l1$^Rl>CeM;Pyp^LoP#xiWohM?3)yFx2YR;3iCCdLUC=g6S#CE2#dR|Huw z1jrbyNJr=efdOt*lK&;jlP~oBDS3^26&5=Fy+v-l&VybB$r$-P^2g-A!lqa;Yj7PD zr`m2LaJN;!1;33mZUC2h#+8yr-DotA<}@20N3oDQ5oEXekSQ^&!hl|{YwB~PvLCz| z;=ca?HtGIGegq5L4EY``gq;`t@r!_Ym;51Ya{ZC~Q?i%#PDe?SVA}~L?(P3-JtKghSqSIF030bDxxN9w@qOXN>r0sAHST-v)DWieEdcCgg-upKI#CD1BP7cLDp z4S^`7bmQh7FO4Ce&(Z6nK}K7^le)(3^$6`AO;Dp zUGjDEE%JZJP5u(YRUv;&{tNk6+iv=65u1QIhS(0GVCKF*OE3km$K2q!0T3GkFdcw43A^ z2JN5ZkI3)9#^PHYL!54$9S!8rf`^(@z_hN>#Nu>ABI#z*i~g&W$51#zn(aYGNp@p3 zLL-O=vc2{CKWusYPRD*W2`fjw)c0rPIn{rm(yr{sAZ{5>F-@Ho;^Kjc$mGs0$Dqe*aa=rM#U!Q(KgN@>Qamh8AoSD6Bh8xO9NydvXE$*D3|c=JE!T{^jR1}(|1Dp zQEdaOEsYiO2Eo+|o>DaSc4Z7Sm~Is^J-grrYtRFf+G> zdtcp#q%(m#IMXCJf-DN~^F02Tbtk!hD=l+XECTU)`E>tAAZb;BerV3&tRQvpg9()#QbfO-1yFD5l8te5I!Z1P@g@~dE zv+H&I?$h7n{P}a}cDv@YQ4!Zmgwa5e<~Q#pE6Ubbf$dv{%`t;Mor_jVVYl7J&Fj~( zFh38^br1cXNw9vRiGeAhB-KAiwY;ZL%6q7c6);gMVzauAt23Wto}R1dxsKiF$cXEa zoM`6VThM;IqPrCiZ#$g^lv0_={@-uD#`oVpg3B<7lU;)zqy@?Ma|BxzGnfC3`6o|I za*h&gW@reNb{UB)bD(k0nTeW0^9`o?{cpd;y*qbo)6x5(u0dwFYPA}^xO^FN1e@>s z)ZC+T)%Fb18gyxCR8BwHO;gh)4H~bfl)|I$9^%%`FA-4!@%y;Ma5b9^%zS?`6Xs8 z)kG1}4mq7I&aw*{JBiEYBx^NVn18&8R&y8S@;JszleBg+oyP09t_$DGV|ig6OHWr) zgN?Ur63q;`Y>}2Z(D-`!qWQw(zHI4AblM#QS!1UK$dT02SwHYpX=lgyACC1nmYzF`ZRh?O%T1$vzT^RvsSJ=>uMvq!CUghFu) zV}){Jsm6_+^YeQ(EI(bt!rT&VUz<9U6tDL-(K4bv&|(rlJBl?ghS~fC~>#&^oJz`-M}PooZ_?KM9ZT1WOHd3k;=v`1;cwFhXgh6 z#@Z$po-9L0HaQQMHfvWZQwDyDXdi&AY*B8 z3);(Iw&^agwXtnpzkl&PQ#%ieVQa8f2G#sO7U}ruXiZ}I00000NkvXXu0mjfToWpK diff --git a/images/avatars/gallery/Flics/Flic_30.png b/images/avatars/gallery/Flics/Flic_30.png deleted file mode 100644 index ffc3aa29becae7d531ac4cb5c061927f9cbdcf15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26073 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

- -
- -
-
- - -
-

{ERROR_MSG}

-
- - -

{L_GROUPS_EXPLAIN}

- - -

{L_GROUP_DETAILS}

- -
-
-
-
style="color: #{GROUP_COLOUR};">{GROUP_NAME} -
-
-
-
-
-
  
-
- -
-

{L_GROUP_TYPE_EXPLAIN}
-
- - - - -
-
- - - -
- -
-
- -
-
-

{L_GROUP_SETTINGS_SAVE}

- -
-
-

{L_GROUP_COLOR_EXPLAIN}
-
- -     - [ {L_COLOUR_SWATCH} ] - -
-
-
-
-
-
-
- -
-
- - - -
- {S_HIDDEN_FIELDS} -   - - {S_FORM_TOKEN} -
- - - - - - - - - - - - - - - - - - - - - - - - - -
{L_GROUP_LEAD}{L_GROUP_DEFAULT}{L_POSTS}{L_JOINED}{L_MARK}
{leader.USERNAME_FULL}{L_YES}{L_NO}{leader.USER_POSTS}{leader.JOINED} 
- - - - - - - - - - - - - - - - - - -
{L_GROUP_PENDING}{L_GROUP_DEFAULT}{L_POSTS}{L_JOINED}{L_MARK}
- - - - - - - - - - - - - - - - - - - - - - -
{L_GROUP_APPROVED}{L_GROUP_DEFAULT}{L_POSTS}{L_JOINED}{L_MARK}
{member.USERNAME_FULL}{L_YES}{L_NO}{member.USER_POSTS}{member.JOINED}
- - - - - - - - - - - -
{L_MEMBERS}
{L_GROUPS_NO_MEMBERS}
- - -
- -
- - - - - -
- - - -
- -
-
- -

{L_ADD_USERS}

- -

{L_ADD_USERS_UCP_EXPLAIN}

- -
-
-

{L_USER_GROUP_DEFAULT_EXPLAIN}
-
- - -
-
-
-

{L_USERNAMES_EXPLAIN}
-
-
{L_FIND_USERNAME}
-
-
- -
-
- -
- - {S_FORM_TOKEN} -
- - - - -
    -
  • -
    -
    {L_GROUP_LEADER}
    -
    {L_OPTIONS}
    -
    -
  • -
- - -

{L_NO_LEADERS}

- - - - - - -
- - diff --git a/install/update/new/styles/prosilver/template/ucp_pm_history.html b/install/update/new/styles/prosilver/template/ucp_pm_history.html deleted file mode 100644 index b53eb0c..0000000 --- a/install/update/new/styles/prosilver/template/ucp_pm_history.html +++ /dev/null @@ -1,56 +0,0 @@ - -

- {L_EXPAND_VIEW} - {L_MESSAGE_HISTORY}{L_COLON} -

- - -
- - -
-
- -
-

class="current">{history_row.SUBJECT}

- - - - - - - - -

- {history_row.MINI_POST} {L_SENT_AT}{L_COLON} {history_row.SENT_DATE} -
- {L_MESSAGE_BY_AUTHOR} {history_row.MESSAGE_AUTHOR_FULL} -

-
{history_row.MESSAGE}{L_MESSAGE_REMOVED_FROM_OUTBOX}
- -
- -
-
- -
- - -
-

- - {L_BACK_TO_TOP} - -

diff --git a/install/update/new/styles/prosilver/template/ucp_pm_viewmessage_print.html b/install/update/new/styles/prosilver/template/ucp_pm_viewmessage_print.html deleted file mode 100644 index 41ff5b8..0000000 --- a/install/update/new/styles/prosilver/template/ucp_pm_viewmessage_print.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - -{META} -{SITENAME} • {PAGE_TITLE} - - - - - - -
- - - - -
-
{PAGE_NUMBER}
-
-

{SUBJECT}

-
{L_SENT_AT} {SENT_DATE}
-
{L_PM_FROM} {MESSAGE_AUTHOR}
- -
{L_TO} {to_recipient.NAME} 
- - -
{L_BCC} {bcc_recipient.NAME} 
- -
-
{MESSAGE}
-
-
-
- - -
- - - diff --git a/install/update/new/styles/prosilver/template/ucp_profile_profile_info.html b/install/update/new/styles/prosilver/template/ucp_profile_profile_info.html deleted file mode 100644 index ac0cd15..0000000 --- a/install/update/new/styles/prosilver/template/ucp_profile_profile_info.html +++ /dev/null @@ -1,51 +0,0 @@ - - -
- -

{L_TITLE} [ {L_VIEW_PROFILE} ]

- -
-
-

{L_PROFILE_INFO_NOTICE}

- -
-

{ERROR}

- - -
-

{L_BIRTHDAY_EXPLAIN}
-
- - - -
-
- - -
-
-
-
- - -
-
for="{profile_fields.FIELD_ID}">{profile_fields.LANG_NAME}{L_COLON} * -
{profile_fields.LANG_EXPLAIN}
-
{profile_fields.ERROR}
-
{profile_fields.FIELD}
-
- - -
- -
-
- -
- {S_HIDDEN_FIELDS}  - - {S_FORM_TOKEN} -
-
- - diff --git a/install/update/new/styles/prosilver/template/ucp_register.html b/install/update/new/styles/prosilver/template/ucp_register.html deleted file mode 100644 index f44382f..0000000 --- a/install/update/new/styles/prosilver/template/ucp_register.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - -{% if PROVIDER_TEMPLATE_FILE %} -
-
- -

{{ SITENAME }} - {{ lang('OAUTH_REGISTRATION') }}

- - {% include PROVIDER_TEMPLATE_FILE %} -
-
-{% endif %} - -
- -
-
- -

{SITENAME} - {L_REGISTRATION}

- -
-
{ERROR}
- -
{L_REG_COND}
- - -
-

{L_USERNAME_EXPLAIN}
-
-
-
-
-
-
-
-

{L_PASSWORD_EXPLAIN}
-
-
-
-
-
-
- - -
- - -
-
-
-
- - - - - -
{L_ITEMS_REQUIRED}
- - -
-
for="{profile_fields.FIELD_ID}">{profile_fields.LANG_NAME}{L_COLON} * -
{profile_fields.LANG_EXPLAIN} -
{profile_fields.ERROR}
-
{profile_fields.FIELD}
-
- - - - -
-
-
- - - - - - -
-
- -

{L_COPPA_COMPLIANCE}

- -

{L_COPPA_EXPLAIN}

-
-
- - - - -
-
- -
- {S_HIDDEN_FIELDS} -   - - {S_FORM_TOKEN} -
- -
-
-
- - diff --git a/install/update/new/styles/prosilver/template/ucp_reset_password.html b/install/update/new/styles/prosilver/template/ucp_reset_password.html deleted file mode 100644 index 0a05f69..0000000 --- a/install/update/new/styles/prosilver/template/ucp_reset_password.html +++ /dev/null @@ -1,49 +0,0 @@ - - -
- -
-
- -
-

{{ lang('RESET_PASSWORD') }}

- -
- {% if S_IS_PASSWORD_RESET %} - {% if PASSWORD_RESET_ERRORS %}

{{ PASSWORD_RESET_ERRORS | join('
') }}

{% endif %} -
-
-
-
-
-
-
-
- {% else %} - {% if USERNAME_REQUIRED %} -

{{ lang('EMAIL_NOT_UNIQUE') }}

- {% endif %} -
-

{{ lang('EMAIL_REMIND') }}
-
-
- {% if USERNAME_REQUIRED %} -
-
-
-
- {% endif %} - {% endif %} -
-
 
-
{{ S_HIDDEN_FIELDS }} 
-
- {{ S_FORM_TOKEN }} -
-
- -
-
-
- - diff --git a/install/update/new/styles/prosilver/template/viewforum_body.html b/install/update/new/styles/prosilver/template/viewforum_body.html deleted file mode 100644 index 40beb78..0000000 --- a/install/update/new/styles/prosilver/template/viewforum_body.html +++ /dev/null @@ -1,315 +0,0 @@ - - -

{FORUM_NAME}

- - -
- -
{FORUM_DESC}
-

{L_MODERATOR}{L_MODERATORS}{L_COLON} {MODERATORS}

-
- - - -
-
- - - {L_FORUM_RULES} - - {L_FORUM_RULES}
- {FORUM_RULES} - - -
-
- - - - - - - - - - -
- - - - - - - {L_BUTTON_FORUM_LOCKED} - - {L_BUTTON_NEW_TOPIC} - - - - - - - - - - - -
- - - - -
-
- {L_NO_READ_ACCESS} -
-
- - - -
- -
-
- -
-

{L_LOGIN_LOGOUT}  •  {L_REGISTER}

- -
-
-
-
-
-
-
-
-
-
-
-
-
 
-
-
- {S_LOGIN_REDIRECT} - {S_FORM_TOKEN_LOGIN} -
-
- -
-
- -
- - - - - - - - - - - - - - - - -
-
-
    -
  • -
    - id="active_topics">
    {L_ACTIVE_TOPICS}{L_ANNOUNCEMENTS}{L_TOPICS}
    -
    {L_REPLIES}
    -
    {L_VIEWS}
    -
    {L_LAST_POST}
    -
    -
  • -
- -
-
- - - - -
-
- {L_NO_TOPICS} -
-
- -
-
- {L_NO_FORUMS_IN_CATEGORY} -
-
- - - - -
- - - - - - {L_BUTTON_FORUM_LOCKED} - - {L_BUTTON_NEW_TOPIC} - - - - - - - -
- -
- - - -
- - - - - -
-

{L_WHO_IS_ONLINE}

-

{LOGGED_IN_USER_LIST}

-
- - - -
-

{L_FORUM_PERMISSIONS}

-

{rules.RULE}

-
- - - diff --git a/install/update/new/styles/prosilver/template/viewtopic_body.html b/install/update/new/styles/prosilver/template/viewtopic_body.html deleted file mode 100644 index 6af33f2..0000000 --- a/install/update/new/styles/prosilver/template/viewtopic_body.html +++ /dev/null @@ -1,459 +0,0 @@ - - - -

{TOPIC_TITLE}

- - -
{FORUM_DESC}
- - -

- {L_MODERATOR}{L_MODERATORS}{L_COLON} {MODERATORS} -

- - - -
-
- - - {L_FORUM_RULES} - - {L_FORUM_RULES}
- {FORUM_RULES} - - -
-
- - -
- - - - - - {L_BUTTON_TOPIC_LOCKED} - - {L_BUTTON_POST_REPLY} - - - - - - - - - - - - - - - - -
- - - - -
- -
-
- -
-

{POLL_QUESTION}

-

{L_POLL_LENGTH}
{L_MAX_VOTES}

- -
- - -
title="{L_POLL_VOTED_OPTION}" data-alt-text="{L_POLL_VOTED_OPTION}" data-poll-option-id="{poll_option.POLL_OPTION_ID}"> -
{poll_option.POLL_OPTION_CAPTION}
-
checked="checked" /> checked="checked" />
-
{poll_option.POLL_OPTION_RESULT}
-
{L_NO_VOTES}{poll_option.POLL_OPTION_PERCENT}
-
- - - -
-
 
-
{L_TOTAL_VOTES}{L_COLON} {TOTAL_VOTES}
-
- - -
-
 
-
-
- - - -
-
 
-
{L_VIEW_RESULTS}
-
- -
- -
- -
- {S_FORM_TOKEN} - {S_HIDDEN_FIELDS} -
- -
-
- - - - - - - - data-url="{postrow.U_MINI_POST}"> - -
-
- -
style="display: none;"> -
-
- - - {postrow.POSTER_AVATAR}{postrow.POSTER_AVATAR} - - -
- - {postrow.POST_AUTHOR_FULL}{postrow.POST_AUTHOR_FULL} - -
- - -
{postrow.RANK_TITLE}
{postrow.RANK_IMG}
- - -
{L_POSTS}{L_COLON} {postrow.POSTER_POSTS}
-
{L_JOINED}{L_COLON} {postrow.POSTER_JOINED}
-
{L_WARNINGS}{L_COLON} {postrow.POSTER_WARNINGS}
- - - -
{postrow.PROFILE_FIELD1_NAME}{L_COLON} {postrow.PROFILE_FIELD1_VALUE}
- - - - - -
{postrow.custom_fields.PROFILE_FIELD_NAME}{L_COLON} {postrow.custom_fields.PROFILE_FIELD_VALUE}
- - - - - - -
- {L_CONTACT}{L_COLON} - -
- - - -
- -
- - -
- {postrow.L_POST_DELETED_MESSAGE}
- {postrow.L_POST_DISPLAY} -
- -
- {postrow.L_IGNORE_POST}
- {postrow.L_POST_DISPLAY} -
- - -
style="display: none;"> - - -

class="first">{postrow.POST_ICON_IMG_ALT} {postrow.POST_SUBJECT}

- - - - - - - - - - - -

- - {postrow.MINI_POST} - - - {postrow.MINI_POST} - - - {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} » -

- - - - -
-

- - {L_POST_UNAPPROVED_ACTION} - - - - {S_FORM_TOKEN} -

-
- -

- - {L_POST_UNAPPROVED_EXPLAIN} -

- - -
-

- {L_POST_DELETED_ACTION} - - - - - - {S_FORM_TOKEN} -

-
- - - -

- {L_POST_REPORTED} -

- - -
{postrow.MESSAGE}
- - - - -
-
- {L_ATTACHMENTS} -
- -
{postrow.attachment.DISPLAY_ATTACHMENT}
- -
- - - -
{L_DOWNLOAD_NOTICE}
- -
- {postrow.DELETED_MESSAGE} -
{L_REASON}{L_COLON} {postrow.DELETE_REASON} -
- -
- {postrow.EDITED_MESSAGE} -
{L_REASON}{L_COLON} {postrow.EDIT_REASON} -
- - -


{postrow.BUMPED_MESSAGE}
- -
{postrow.SIGNATURE}
- - -
- -
- - - - - -
-
- -
- - - - - - - - -
- - - - - - {L_BUTTON_TOPIC_LOCKED} - - {L_BUTTON_POST_REPLY} - - - - - - - - -
- -
- - - - - - - - - - - -
- - - - - -
-

{L_WHO_IS_ONLINE}

-

{LOGGED_IN_USER_LIST}

-
- - - diff --git a/install/update/new/styles/prosilver/template/viewtopic_print.html b/install/update/new/styles/prosilver/template/viewtopic_print.html deleted file mode 100644 index 658062f..0000000 --- a/install/update/new/styles/prosilver/template/viewtopic_print.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - -{META} -{SITENAME} • {PAGE_TITLE} - - - - - - -
- - - - -
-
{PAGE_NUMBER}
- -
-

{postrow.POST_SUBJECT}

-
{L_POSTED}{L_COLON} {postrow.POST_DATE}
-
{L_POST_BY_AUTHOR} {postrow.POST_AUTHOR}
-
{postrow.MESSAGE}
-
-
- -
- - -
- - - diff --git a/install/update/new/styles/prosilver/theme/colours.css b/install/update/new/styles/prosilver/theme/colours.css deleted file mode 100644 index 04a8958..0000000 --- a/install/update/new/styles/prosilver/theme/colours.css +++ /dev/null @@ -1,1168 +0,0 @@ -/* --------------------------------------------------------------- -Colours and backgrounds for common.css --------------------------------------------------------------- */ - -html, body { - color: #536482; - background-color: #F5F7FA; -} - -h1 { - color: #FFFFFF; -} - -h2 { - color: #28313F; -} - -h3 { - border-bottom-color: #CCCCCC; - color: #115098; -} - -hr { - border-color: #FFFFFF; - border-top-color: #CCCCCC; -} - -/* --------------------------------------------------------------- -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; -} - -.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 { - background-color: #FFF; - border-color: #E6E9ED; -} - -.headerbar { - color: #FFFFFF; -} - -.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: -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; -} - -.navbar { - background-color: #CADCEB; -} - -.panel { - background-color: #ECF1F3; - color: #28313F; -} - -.post:target .content { - color: #000000; -} - -.post:target h3 a { - color: #000000; -} - -.bg1 { - background-color: #ECF3F7; -} - -table.zebra-list tr:nth-child(odd) td, ul.zebra-list li:nth-child(odd) { - background-color: #ECF3F7; -} - -.bg2 { - background-color: #E1EBF2; -} - -table.zebra-list tr:nth-child(even) td, ul.zebra-list li:nth-child(even) { - background-color: #E1EBF2; -} - -.bg3 { - background-color: #CADCEB; -} - -.ucprowbg { - background-color: #DCDEE2; -} - -.fieldsbg { - background-color: #E7E8EA; -} - -.site_logo { - background-image: url("./images/site_logo.svg"); -} - -/* Horizontal lists -----------------------------------------*/ - -ul.navlinks { - border-top-color: #FFFFFF; -} - -/* Table styles -----------------------------------------*/ -table.table1 thead th { - color: #FFFFFF; -} - -table.table1 tbody tr { - border-color: #BFC1CF; -} - -table.table1 tbody tr:hover, table.table1 tbody tr.hover { - background-color: #CFE1F6; - color: #000; -} - -table.table1 td { - color: #536482; -} - -table.table1 tbody td { - border-top-color: #FAFAFA; -} - -table.table1 tbody th { - border-bottom-color: #000000; - color: #333333; - background-color: #FFFFFF; -} - -table.info tbody th { - color: #000000; -} - -/* Misc layout styles ----------------------------------------- */ -dl.details dt { - color: #000000; -} - -dl.details dd { - color: #536482; -} - -.sep { - color: #1198D9; -} - -/* Icon styles ----------------------------------------- */ -.icon.icon-blue, a:hover .icon.icon-blue { - color: #196db5; -} - -.icon.icon-green, a:hover .icon.icon-green{ - color: #1b9A1B; -} - -.icon.icon-red, a:hover .icon.icon-red{ - color: #BC2A4D; -} - -.icon.icon-orange, a:hover .icon.icon-orange{ - color: #FF6600; -} - -.icon.icon-bluegray, a:hover .icon.icon-bluegray{ - color: #536482; -} - -.icon.icon-gray, a:hover .icon.icon-gray{ - color: #777777; -} - -.icon.icon-lightgray, a:hover .icon.icon-lightgray{ - color: #999999; -} - -.icon.icon-black, a:hover .icon.icon-black{ - color: #333333; -} - -.alert_close .icon:before { - background-color: #FFFFFF; -} - -/* Jumpbox */ -.jumpbox .dropdown li { - border-top-color: #CCCCCC; -} - -.jumpbox-cat-link { - background-color: #0076b1; - border-top-color: #0076B1; - color: #FFFFFF; -} - -.jumpbox-cat-link:hover { - background-color: #12A3EB; - border-top-color: #12A3EB; - color: #FFFFFF; -} - -.jumpbox-forum-link { - background-color: #E1EBF2; -} - -.jumpbox-forum-link:hover { - background-color: #F6F4D0; -} - -.jumpbox .dropdown .pointer-inner { - border-color: #E1EBF2 transparent; -} - -.jumpbox-sub-link { - background-color: #E1EBF2; -} - -.jumpbox-sub-link:hover { - background-color: #F1F8FF; -} - -/* Miscellaneous styles ----------------------------------------- */ - -.copyright { - color: #555555; -} - -.error { - color: #BC2A4D; -} - -.reported { - background-color: #F7ECEF; -} - -li.reported:hover { - background-color: #ECD5D8 !important; -} -.sticky, .announce { - /* you can add a background for stickies and announcements*/ -} - -div.rules { - background-color: #ECD5D8; - color: #BC2A4D; -} - -p.post-notice { - background-color: #ECD5D8; - background-image: none; -} - -/* --------------------------------------------------------------- -Colours and backgrounds for content.css --------------------------------------------------------------- */ - -ul.forums { - 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 { - color: #4C5D77; -} - -ul.topiclist dd { - border-left-color: #FFFFFF; -} - -.rtl ul.topiclist dd { - border-right-color: #FFFFFF; - border-left-color: transparent; -} - -li.row { - border-top-color: #FFFFFF; - border-bottom-color: #00608F; -} - -li.row strong { - color: #000000; -} - -li.row:hover { - background-color: #F6F4D0; -} - -li.row:hover dd { - border-left-color: #CCCCCC; -} - -.rtl li.row:hover dd { - border-right-color: #CCCCCC; - border-left-color: transparent; -} - -li.header dt, li.header dd { - color: #FFFFFF; -} - -/* Post body styles -----------------------------------------*/ -.postbody { - color: #333333; -} - -/* Content container styles -----------------------------------------*/ -.content { - color: #333333; -} - -.content h2, .panel h2 { - color: #115098; - border-bottom-color: #CCCCCC; -} - -dl.faq dt { - color: #333333; -} - -.posthilit { - background-color: #F3BFCC; - color: #BC2A4D; -} - -.announce, .unreadpost { - /* Highlight the announcements & unread posts box */ -} - -/* Post signature */ -.signature { - border-top-color: #CCCCCC; -} - -/* Post noticies */ -.notice { - border-top-color: #CCCCCC; -} - -/* BB Code styles -----------------------------------------*/ -/* Quote block */ -blockquote { - background-color: #EBEADD; - border-color:#DBDBCE; -} - -blockquote blockquote { - /* Nested quotes */ - background-color:#EFEED9; -} - -blockquote blockquote blockquote { - /* Nested quotes */ - background-color: #EBEADD; -} - -/* Code block */ -.codebox { - background-color: #FFFFFF; - border-color: #C9D2D8; -} - -.codebox p { - border-bottom-color: #CCCCCC; -} - -.codebox code { - color: #2E8B57; -} - -/* Attachments -----------------------------------------*/ -.attachbox { - background-color: #FFFFFF; - border-color: #C9D2D8; -} - -.pm-message .attachbox { - background-color: #F2F3F3; -} - -.attachbox dd { - border-top-color: #C9D2D8; -} - -.attachbox p { - color: #666666; -} - -.attachbox p.stats { - color: #666666; -} - -.attach-image img { - border-color: #999999; -} - -/* Inline image thumbnails */ - -dl.file dd { - color: #666666; -} - -dl.thumbnail img { - border-color: #666666; - background-color: #FFFFFF; -} - -dl.thumbnail dd { - color: #666666; -} - -dl.thumbnail dt a:hover { - background-color: #EEEEEE; -} - -dl.thumbnail dt a:hover img { - border-color: #368AD2; -} - -/* Post poll styles -----------------------------------------*/ - -fieldset.polls dl { - border-top-color: #DCDEE2; - color: #666666; -} - -fieldset.polls dl.voted { - color: #000000; -} - -fieldset.polls dd div { - color: #FFFFFF; -} - -.rtl .pollbar1, .rtl .pollbar2, .rtl .pollbar3, .rtl .pollbar4, .rtl .pollbar5 { - border-right-color: transparent; -} - -.pollbar1 { - background-color: #AA2346; - border-bottom-color: #74162C; - border-right-color: #74162C; -} - -.rtl .pollbar1 { - border-left-color: #74162C; -} - -.pollbar2 { - background-color: #BE1E4A; - border-bottom-color: #8C1C38; - border-right-color: #8C1C38; -} - -.rtl .pollbar2 { - border-left-color: #8C1C38; -} - -.pollbar3 { - background-color: #D11A4E; - border-bottom-color: #AA2346; - border-right-color: #AA2346; -} - -.rtl .pollbar3 { - border-left-color: #AA2346; -} - -.pollbar4 { - background-color: #E41653; - border-bottom-color: #BE1E4A; - border-right-color: #BE1E4A; -} - -.rtl .pollbar4 { - border-left-color: #BE1E4A; -} - -.pollbar5 { - background-color: #F81157; - border-bottom-color: #D11A4E; - border-right-color: #D11A4E; -} - -.rtl .pollbar5 { - border-left-color: #D11A4E; -} - -/* Poster profile block -----------------------------------------*/ -.postprofile { - color: #666666; - border-color: #FFFFFF; -} - -.pm .postprofile { - border-color: #DDDDDD; -} - -.postprofile strong { - color: #000000; -} - -.online { - background-image: url("./en/icon_user_online.gif"); -} - -dd.profile-warnings { - color: #BC2A4D; -} - -/* --------------------------------------------------------------- -Colours and backgrounds for buttons.css --------------------------------------------------------------- */ -.button { - border-color: #C7C3BF; - 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; -} - -.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 .icon, -.button-secondary { - color: #8f8f8f; -} - -.button-secondary:focus, -.button-secondary:hover, -.button:focus .icon, -.button:hover .icon { - color: #0A8ED0; -} - -.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; -} - -.search-results li:hover, -.search-results li.active { - background-color: #CFE1F6; -} - -/* Icon images ----------------------------------------- */ - -.contact-icon { background-image: url("./images/icons_contact.png"); } - -/* Profile & navigation 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; } - -/* 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"); } -.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"); } - - -/* --------------------------------------------------------------- -Colours and backgrounds for cp.css --------------------------------------------------------------- */ - -/* Main CP box -----------------------------------------*/ - -.panel-container h3, .panel-container hr, .cp-menu hr { - border-color: #A4B3BF; -} - -.panel-container .panel li.row { - border-bottom-color: #B5C1CB; - border-top-color: #F9F9F9; -} - -ul.cplist { - border-top-color: #B5C1CB; -} - -.panel-container .panel li.header dd, .panel-container .panel li.header dt { - color: #000000; -} - -.panel-container table.table1 thead th { - color: #333333; - border-bottom-color: #333333; -} - -.cp-main .pm-message { - border-color: #DBDEE2; - background-color: #FFFFFF; -} - -/* CP tabbed menu -----------------------------------------*/ -.tabs .tab > a { - background: #BACCD9; - color: #536482; -} - -.tabs .tab > a:hover { - background: #DDEDFB; - color: #D31141; -} - -.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 { - color: #000000; -} - -/* Mini tabbed menu used in MCP -----------------------------------------*/ -.minitabs .tab > a { - background-color: #E1EBF2; -} - -.minitabs .activetab > a, -.minitabs .activetab > a:hover { - background-color: #F9F9F9; - color: #333333; -} - -/* Responsive tabs -----------------------------------------*/ -.responsive-tab .responsive-tab-link:before { - border-color: #536482; -} - -.responsive-tab .responsive-tab-link:hover:before { - border-color: #D31141; -} - -/* UCP navigation menu -----------------------------------------*/ - -/* Link styles for the sub-section links */ -.navigation a { - color: #333; - background: #CADCEB; /* Old browsers */ /* FF3.6+ */ - background: -webkit-linear-gradient(left, #B4C4D1 50%, #CADCEB 100%); - 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; /* 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 { - background: #AABAC6; - color: #BC2A4D; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -} - -.navigation .active-subsection a { - background: #F9F9F9; - color: #D31141; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -} - -.navigation .active-subsection a:hover { - color: #D31141; -} - -@media only screen and (max-width: 900px), only screen and (max-device-width: 900px) -{ - #navigation a, .rtl #navigation a { - background: #B2C2CF; - } -} - -/* Preferences pane layout -----------------------------------------*/ -.panel-container h2 { - color: #333333; -} - -.panel-container .panel { - background-color: #F9F9F9; -} - -.cp-main .pm { - background-color: #FFFFFF; -} - -/* Friends list */ -.cp-mini { - background-color: #EEF5F9; -} - -dl.mini dt { - color: #425067; -} - -/* PM Styles -----------------------------------------*/ -/* PM Message history */ -.current { - color: #000000 !important; -} - -/* PM marking colours */ -.pmlist li.pm_message_reported_colour, .pm_message_reported_colour { - border-left-color: #BC2A4D; - border-right-color: #BC2A4D; -} - -.pmlist li.pm_marked_colour, .pm_marked_colour { - border-color: #FF6600; -} - -.pmlist li.pm_replied_colour, .pm_replied_colour { - border-color: #A9B8C2; -} - -.pmlist li.pm_friend_colour, .pm_friend_colour { - border-color: #5D8FBD; -} - -.pmlist li.pm_foe_colour, .pm_foe_colour { - border-color: #000000; -} - -/* Avatar gallery */ -.gallery label { - background: #FFFFFF; - border-color: #CCC; -} - -.gallery label:hover { - background-color: #EEE; -} - -/* --------------------------------------------------------------- -Colours and backgrounds for forms.css --------------------------------------------------------------- */ - -/* General form styles -----------------------------------------*/ -select { - border-color: #666666; - background-color: #FAFAFA; - color: #000; -} - -label { - color: #425067; -} - -option.disabled-option { - color: graytext; -} - -/* Definition list layout for forms ----------------------------------------- */ -dd label { - color: #333; -} - -fieldset.fields1 { - background-color: transparent; -} - -/* Hover effects */ -fieldset dl:hover dt label { - color: #000000; -} - -fieldset.fields2 dl:hover dt label { - color: inherit; -} - -/* Quick-login on index page */ -fieldset.quick-login input.inputbox { - background-color: #F2F3F3; -} - -/* Posting page styles -----------------------------------------*/ - -.message-box textarea { - color: #333333; -} - -.message-box textarea.drag-n-drop { - outline-color: rgba(102, 102, 102, 0.5); -} - -.message-box textarea.drag-n-drop-highlight { - outline-color: rgba(17, 163, 234, 0.5); -} - -/* Input field styles ----------------------------------------- */ -.inputbox { - background-color: #FFFFFF; - border-color: #B4BAC0; - color: #333333; -} - -.inputbox:-moz-placeholder { - color: #333333; -} - -.inputbox::-webkit-input-placeholder { - color: #333333; -} - -.inputbox:hover { - border-color: #11A3EA; -} - -.inputbox:focus { - border-color: #11A3EA; -} - -.inputbox:focus:-moz-placeholder { - color: transparent; -} - -.inputbox:focus::-webkit-input-placeholder { - color: transparent; -} - - -/* Form button styles ----------------------------------------- */ - -a.button1, input.button1, input.button3, a.button2, input.button2 { - color: #000; - 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 { - border-color: #666666; -} - -input.button3 { - background-image: none; -} - -/* Alternative button */ -a.button2, input.button2, input.button3 { - border-color: #666666; -} - -/* button in the style of the form buttons */ -a.button1, a.button2 { - color: #000000; -} - -/* Hover states */ -a.button1:hover, input.button1:hover, a.button2:hover, input.button2:hover, input.button3:hover { - 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 */ -input.button1:focus, input.button2:focus, input.button3:focus { - border-color: #11A3EA; - color: #0F4987; -} - -input.disabled { - color: #666666; -} - -/* jQuery popups ----------------------------------------- */ -.phpbb_alert { - background-color: #FFFFFF; - border-color: #999999; -} -.darken { - background-color: #000000; -} - -.loading_indicator { - background-color: #000000; - background-image: url("./images/loading.gif"); -} - -.dropdown-extended ul li { - border-top-color: #B9B9B9; -} - -.dropdown-extended ul li:hover { - background-color: #CFE1F6; - color: #000000; -} - -.dropdown-extended .header, .dropdown-extended .footer { - border-color: #B9B9B9; - color: #000000; -} - -.dropdown-extended .footer { - border-top-style: solid; - border-top-width: 1px; -} - -.dropdown-extended .header { - 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 { - border-color: #B9B9B9 transparent; -} - -.dropdown .pointer-inner { - border-color: #FFF transparent; -} - -.dropdown-extended .pointer-inner { - border-color: #F1F8FF transparent; -} - -.dropdown .dropdown-contents { - background: #fff; - border-color: #B9B9B9; - box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2); -} - -.dropdown-up .dropdown-contents { - box-shadow: 1px 0 5px rgba(0, 0, 0, 0.2); -} - -.dropdown li, .dropdown li li { - border-color: #DCDCDC; -} - -.dropdown li.separator { - border-color: #DCDCDC; -} - -/* Notifications ----------------------------------------- */ - -.notification_list p.notification-time { - color: #4C5D77; -} - -li.notification-reported strong, li.notification-disapproved strong { - color: #D31141; -} - -.badge { - background-color: #D31141; - color: #ffffff; -} diff --git a/install/update/new/styles/prosilver/theme/common.css b/install/update/new/styles/prosilver/theme/common.css deleted file mode 100644 index eb04c66..0000000 --- a/install/update/new/styles/prosilver/theme/common.css +++ /dev/null @@ -1,1288 +0,0 @@ -/* General Markup Styles ----------------------------------------- */ -html { - font-size: 100%; - /* Always show a scrollbar for short pages - stops the jump when the scrollbar appears. non-IE browsers */ - height: 101%; -} - -body { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 10px; - line-height: normal; - margin: 0; - padding: 12px 0; - word-wrap: break-word; - -webkit-print-color-adjust: exact; -} - -h1 { - /* Forum name */ - font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; - margin-right: 200px; - margin-top: 15px; - font-weight: bold; - font-size: 2em; -} - -h2 { - /* Forum header titles */ - font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; - font-weight: normal; - font-size: 2em; - margin: 0.8em 0 0.2em 0; -} - -h2.solo { - margin-bottom: 1em; -} - -h3 { - /* Sub-headers (also used as post headers, but defined later) */ - font-family: Arial, Helvetica, sans-serif; - font-weight: bold; - text-transform: uppercase; - border-bottom: 1px solid transparent; - margin-bottom: 3px; - padding-bottom: 2px; - font-size: 1.05em; - margin-top: 20px; -} - -h4 { - /* Forum and topic list titles */ - font-family: "Trebuchet MS", Verdana, Helvetica, Arial, Sans-serif; - font-size: 1.3em; -} - -p { - line-height: 1.3em; - font-size: 1.1em; - margin-bottom: 1.5em; -} - -img { - border-width: 0; -} - -hr { - border: 0 solid transparent; - border-top-width: 1px; - height: 1px; - margin: 5px 0; - display: block; - clear: both; -} - -hr.dashed { - border-top-style: dashed; - margin: 10px 0; -} - -hr.divider { - display: none; -} - -p.right { - text-align: right; -} - -p.jumpbox-return { - margin-top: 10px; - margin-bottom: 0; - float: left; -} - -b, strong { - font-weight: bold; -} - -.text-strong { - font-weight: bold; -} - -i, em { - font-style: italic; -} - -.text-italics { - font-style: italic; -} - -u { - text-decoration: underline; -} - -ul { - list-style-type: disc; -} - -ol { - list-style-type: decimal; -} - -li { - display: list-item; -} - -ul ul, ol ul { - list-style-type: circle; -} - -ol ol ul, ol ul ul, ul ol ul, ul ul ul { - list-style-type: square; -} - -a:hover { text-decoration: underline; } - -/* Main blocks ----------------------------------------- */ -.wrap { - border: 1px solid transparent; - border-radius: 8px; - margin: 0 auto; - max-width: 1152px; - min-width: 625px; - padding: 15px; -} - -@media only screen and (max-width: 1220px), only screen and (max-device-width: 1220px) { - .wrap { - margin: 0 12px; - } -} - -.page-body { - margin: 4px 0; - clear: both; -} - -.page-footer { - clear: both; -} - -.page-footer h3 { - margin-top: 20px; -} - -.logo { - float: left; - width: auto; - padding: 10px 13px 0 10px; -} - -.logo:hover { - text-decoration: none; -} - -.site_logo { - background-repeat: no-repeat; - display: inline-block; - width: 149px; - height: 52px; -} - -/* Site description and logo */ -.site-description { - float: left; - width: 65%; -} - -.site-description h1 { - margin-right: 0; -} - -/* Round cornered boxes and backgrounds ----------------------------------------- */ -.headerbar { - margin-bottom: 4px; - padding: 5px; - border-radius: 7px; -} - -.navbar { - padding: 3px 10px; - border-radius: 7px; -} - -.forabg { - margin-bottom: 4px; - padding: 5px; - clear: both; - border-radius: 7px; -} - -.forumbg { - margin-bottom: 4px; - padding: 5px; - clear: both; - border-radius: 7px; -} - -.panel { - margin-bottom: 4px; - padding: 5px 10px; - border-radius: 7px; -} - -.post { - padding: 5px 10px; - margin-bottom: 4px; - background-repeat: no-repeat; - background-position: 100% 0; - border-radius: 7px; - position: relative; -} - -.rowbg { - margin: 5px 5px 2px 5px; -} - -/* Horizontal lists -----------------------------------------*/ -.navbar ul.linklist { - padding: 2px 0; - list-style-type: none; -} - -ul.linklist { - display: block; - margin: 0; -} - -.cp-main .panel { - padding: 5px 10px; -} - -ul.linklist > li { - float: left; - font-size: 1.1em; - line-height: 2.2em; - list-style-type: none; - margin-right: 7px; - padding-top: 1px; - width: auto; -} - -ul.linklist > li.rightside, p.rightside, a.rightside { - float: right; - margin-right: 0; - margin-left: 7px; - text-align: right; -} - -ul.navlinks { - border-top: 1px solid transparent; -} - -ul.leftside { - float: left; - margin-left: 0; - margin-right: 5px; - text-align: left; -} - -ul.rightside { - float: right; - margin-left: 5px; - margin-right: -5px; - text-align: right; -} - -ul.linklist li.responsive-menu { - position: relative; - margin: 0 5px 0 0; -} - -.hasjs ul.linklist.leftside, .hasjs ul.linklist.rightside { - max-width: 48%; -} - -.hasjs ul.linklist.fullwidth { - max-width: none; -} - -li.responsive-menu.dropdown-right .dropdown { - left: -9px; -} - -li.responsive-menu.dropdown-left .dropdown { - right: -6px; -} - -ul.linklist .dropdown { - top: 22px; -} - -ul.linklist .dropdown-up .dropdown { - bottom: 18px; - top: auto; -} - -/* Bulletin icons for list items -----------------------------------------*/ -ul.linklist.bulletin > li:before { - display: inline-block; - content: "\2022"; - font-size: inherit; - line-height: inherit; - padding-right: 4px; -} - -ul.linklist.bulletin > li:first-child:before, -ul.linklist.bulletin > li.rightside:last-child:before { - content: none; -} - -ul.linklist.bulletin > li.no-bulletin:before { - content: none; -} - -.responsive-menu:before { - display: none !important; -} - -/* Profile in overall_header.html */ -.header-profile { - display: inline-block; - vertical-align: top; -} - -a.header-avatar, -a.header-avatar:hover { - text-decoration: none; -} - -a.header-avatar img { - margin-bottom: 2px; - max-height: 20px; - vertical-align: middle; - width: auto; -} - -a.header-avatar span:after { - content: '\f0dd'; - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - padding-left: 6px; - padding-top: 2px; - vertical-align: top; -} - -/* Dropdown menu -----------------------------------------*/ -.dropdown-container { - position: relative; -} - -.dropdown-container-right { - float: right; -} - -.dropdown-container-left { - float: left; -} - -.nojs .dropdown-container:hover .dropdown { - display: block !important; -} - -.dropdown { - display: none; - position: absolute; - left: 0; - top: 1.2em; - z-index: 2; - border: 1px solid transparent; - border-radius: 5px; - padding: 9px 0 0; - margin-right: -500px; -} - -.dropdown.live-search { - top: auto; -} - -.dropdown-container.topic-tools { - float: left; -} - -.dropdown-up .dropdown { - top: auto; - bottom: 1.2em; - padding: 0 0 9px; -} - -.dropdown-left .dropdown, .nojs .rightside .dropdown { - left: auto; - right: 0; - margin-left: -500px; - margin-right: 0; -} - -.dropdown-button-control .dropdown { - top: 24px; -} - -.dropdown-button-control.dropdown-up .dropdown { - top: auto; - bottom: 24px; -} - -.dropdown .pointer, .dropdown .pointer-inner { - position: absolute; - width: 0; - height: 0; - border-top-width: 0; - border-bottom: 10px solid transparent; - border-left: 10px dashed transparent; - border-right: 10px dashed transparent; - -webkit-transform: rotate(360deg); /* better anti-aliasing in webkit */ - display: block; -} - -.dropdown-up .pointer, .dropdown-up .pointer-inner { - border-bottom-width: 0; - border-top: 10px solid transparent; -} - -.dropdown .pointer { - right: auto; - left: 10px; - top: -1px; - z-index: 3; -} - -.dropdown-up .pointer { - bottom: -1px; - top: auto; -} - -.dropdown-left .dropdown .pointer, .nojs .rightside .dropdown .pointer { - left: auto; - right: 10px; -} - -.dropdown .pointer-inner { - top: auto; - bottom: -11px; - left: -10px; -} - -.dropdown-up .pointer-inner { - bottom: auto; - top: -11px; -} - -.dropdown .dropdown-contents { - z-index: 2; - overflow: hidden; - overflow-y: auto; - border: 1px solid transparent; - border-radius: 5px; - padding: 5px; - position: relative; - max-height: 300px; -} - -.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; - white-space: nowrap; - text-align: left; -} - -.dropdown-contents > li { - padding-right: 15px; -} - -.dropdown-nonscroll > li { - padding-right: 0; -} - -.dropdown li:first-child, .dropdown li.separator + li, .dropdown li li { - border-top: 0; -} - -.dropdown li li:first-child { - margin-top: 4px; -} - -.dropdown li li:last-child { - padding-bottom: 0; -} - -.dropdown li li { - border-top: 1px dotted transparent; - padding-left: 18px; -} - -.wrap .dropdown li, .dropdown.wrap li, .dropdown-extended li { - white-space: normal; -} - -.dropdown li.separator { - border-top: 1px solid transparent; - padding: 0; -} - -.dropdown li.separator:first-child, .dropdown li.separator:last-child { - display: none !important; -} - -/* Responsive breadcrumbs -----------------------------------------*/ -.breadcrumbs .crumb { - float: left; - font-weight: bold; - word-wrap: normal; -} - -.breadcrumbs .crumb:before { - content: '\2039'; - font-weight: bold; - padding: 0 0.5em; -} - -.breadcrumbs .crumb:first-child:before { - content: none; -} - -.breadcrumbs .crumb a { - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: bottom; - overflow: hidden; -} - -.breadcrumbs.wrapped .crumb a { letter-spacing: -.3px; } -.breadcrumbs.wrapped .crumb.wrapped-medium a { letter-spacing: -.4px; } -.breadcrumbs.wrapped .crumb.wrapped-tiny a { letter-spacing: -.5px; } - -.breadcrumbs .crumb.wrapped-max a { max-width: 120px; } -.breadcrumbs .crumb.wrapped-wide a { max-width: 100px; } -.breadcrumbs .crumb.wrapped-medium a { max-width: 80px; } -.breadcrumbs .crumb.wrapped-small a { max-width: 60px; } -.breadcrumbs .crumb.wrapped-tiny a { max-width: 40px; } - -/* Table styles -----------------------------------------*/ -table.table1 { - width: 100%; -} - -.ucp-main table.table1 { - padding: 2px; -} - -table.table1 thead th { - font-weight: normal; - text-transform: uppercase; - line-height: 1.3em; - font-size: 1em; - padding: 0 0 4px 3px; -} - -table.table1 thead th span { - padding-left: 7px; -} - -table.table1 tbody tr { - border: 1px solid transparent; -} - -table.table1 td { - font-size: 1.1em; -} - -table.table1 tbody td { - padding: 5px; - border-top: 1px solid transparent; -} - -table.table1 tbody th { - padding: 5px; - border-bottom: 1px solid transparent; - text-align: left; -} - -/* Specific column styles */ -table.table1 .name { text-align: left; } -table.table1 .center { text-align: center; } -table.table1 .reportby { width: 15%; } -table.table1 .posts { text-align: center; width: 7%; } -table.table1 .joined { text-align: left; width: 15%; } -table.table1 .active { text-align: left; width: 15%; } -table.table1 .mark { text-align: center; width: 7%; } -table.table1 .info { text-align: left; width: 30%; } -table.table1 .info div { width: 100%; white-space: normal; overflow: hidden; } -table.table1 .autocol { line-height: 2em; white-space: nowrap; } -table.table1 thead .autocol { padding-left: 1em; } - -table.table1 span.rank-img { - float: right; - width: auto; -} - -table.info td { - padding: 3px; -} - -table.info tbody th { - padding: 3px; - text-align: right; - vertical-align: top; - font-weight: normal; -} - -.forumbg table.table1 { - margin: 0; -} - -.forumbg-table > .inner { - margin: 0 -1px; -} - -.color_palette_placeholder table { - border-collapse: separate; - border-spacing: 1px; -} - -/* Misc layout styles ----------------------------------------- */ -/* column[1-2] styles are containers for two column layouts */ -.column1 { - float: left; - clear: left; - width: 49%; -} - -.column2 { - float: right; - clear: right; - width: 49%; -} - -/* General classes for placing floating blocks */ -.left-box { - float: left; - width: auto; - text-align: left; - max-width: 100%; -} - -.left-box.profile-details { - width: 80%; -} - -.right-box { - float: right; - width: auto; - text-align: right; - max-width: 100%; -} - -dl.details { - /*font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif;*/ - font-size: 1.1em; -} - -dl.details dt { - float: left; - clear: left; - width: 30%; - text-align: right; - display: block; -} - -dl.details dd { - margin-left: 0; - padding-left: 5px; - margin-bottom: 5px; - float: left; - width: 65%; - overflow: hidden; - text-overflow: ellipsis; -} - -.clearfix, fieldset dl, ul.topiclist dl, dl.polls { - overflow: hidden; -} - -fieldset.fields1 ul.recipients { - list-style-type: none; - line-height: 1.8; - max-height: 150px; - overflow-y: auto; -} - -fieldset.fields1 dd.recipients { - clear: left; - margin-left: 1em; -} - -fieldset.fields1 ul.recipients input.button2{ - font-size: 0.8em; - margin-right: 0; - padding: 0; -} - -fieldset.fields1 dl.pmlist > dt { - width: auto !important; -} - -fieldset.fields1 dl.pmlist dd.recipients { - margin-left: 0 !important; -} - -/* Action-bars (container for post/reply buttons, pagination, etc.) ----------------------------------------- */ -.action-bar { - font-size: 11px; - margin: 4px 0; -} - -.forabg + .action-bar { - margin-top: 2em; -} - -.action-bar .button { - margin-right: 5px; - float: left; -} - -.action-bar .button-search { - margin-right: 0; -} - -/* Pagination ----------------------------------------- */ -.pagination { - float: right; - text-align: right; - width: auto; -} - -.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; - margin-left: 5px; -} - -.pagination > ul > li { - display: inline-block !important; - padding: 0; - font-size: 100%; - line-height: normal; - vertical-align: middle; -} - -.pagination li a, .pagination li span { - border-radius: 2px; - padding: 2px 5px; -} - -.pagination li.active span { - display: inline-block; - font-size: 13px; - font-weight: normal; - font-family: "Open Sans", "Droid Sans", Verdana, Arial, Helvetica; - line-height: 1.4; - text-align: center; - white-space: nowrap; - vertical-align: middle; - border: 1px solid transparent; -} - -.pagination li.ellipsis span { - border: none; - padding: 0; -} - -.pagination li.page-jump { - margin-right: 5px; -} - -.pagination li.page-jump a { - padding: 0 8px; -} - -.pagination li.page-jump a i { - font-size: 21px; -} - -.pagination .arrow a { - padding: 2px 0; -} - -/* Pagination in viewforum for multipage topics */ -.row .pagination { - display: block; - margin-top: 3px; - margin-bottom: 3px; -} - -.row .pagination > ul { - margin: 0; -} - -.row .pagination li a, .row .pagination li span { - border-radius: 2px; - padding: 1px 3px; - font-size: 9px; -} - -/* jQuery popups ----------------------------------------- */ -.phpbb_alert { - border: 1px solid transparent; - display: none; - left: 0; - padding: 0 25px 20px 25px; - position: fixed; - right: 0; - top: 150px; - z-index: 50; - width: 620px; - margin: 0 auto; -} - -@media only screen and (max-height: 500px), only screen and (max-device-width: 500px) -{ - .phpbb_alert { - top: 25px; - } -} - -.phpbb_alert .alert_close { - float: right; - margin-right: -36px; - margin-top: -8px; -} - -.phpbb_alert p { - margin: 8px 0; - padding-bottom: 8px; -} - -.phpbb_alert label { - display: block; - margin: 8px 0; - padding-bottom: 8px; -} - -.phpbb_alert div.alert_text > p, -.phpbb_alert div.alert_text > label, -.phpbb_alert div.alert_text > select, -.phpbb_alert div.alert_text > textarea, -.phpbb_alert div.alert_text > input { - font-size: 1.1em; -} - -.darkenwrapper { - display: none; - position: relative; - z-index: 44; -} - -.darken { - position: fixed; - left: 0; - top: 0; - width: 100%; - height: 100%; - opacity: 0.5; - z-index: 45; -} - -.loading_indicator { - background: center center no-repeat; - border-radius: 5px; - display: none; - opacity: 0.8; - margin-top: -50px; - margin-left: -50px; - height: 50px; - width: 50px; - position: fixed; - left: 50%; - top: 50%; - z-index: 51; -} - -/* Miscellaneous styles ----------------------------------------- */ -.copyright { - font-size: 10px; - text-align: center; - padding: 10px; -} - -.footer-row { - font-size: 10px; - line-height: 1.8; - margin: 0; -} - -.small { - font-size: 0.9em !important; -} - -.titlespace { - margin-bottom: 15px; -} - -.headerspace { - margin-top: 20px; -} - -.error { - font-weight: bold; - font-size: 1em; -} - -div.rules { - margin: 10px 0; - font-size: 1.1em; - padding: 5px 10px; - border-radius: 7px; -} - -div.rules ul, div.rules ol { - margin-left: 20px; -} - -p.post-notice { - position: relative; - padding: 5px; - min-height: 14px; - margin-bottom: 1em; -} - -form > p.post-notice strong { - line-height: 20px; -} - -.stat-block { - clear: both; -} - -.top-anchor { - display: block; - position: absolute; - top: -20px; -} - -.clear { - display: block; - clear: both; - font-size: 1px; - line-height: 1px; - background: transparent; -} - -/* Inner box-model clearing */ -.inner:after, -ul.linklist:after, -.action-bar:after, -.notification_text:after, -.tabs-container:after, -.tabs > ul:after, -.minitabs > ul:after, -.postprofile .avatar-container:after { - clear: both; - content: ''; - display: block; -} - -.emoji { - min-height: 18px; - min-width: 18px; - height: 1em; - width: 1em; -} - -.smilies { - vertical-align: text-bottom; -} - -.icon-notification { - position: relative; -} - -.member-search { - float: left; - margin: 0; - padding: 6px 10px; -} - -.member-search strong { - font-size: 0.95em; -} - -.dropdown-extended { - display: none; - z-index: 1; -} - -.dropdown-extended ul { - max-height: 350px; - overflow-y: auto; - overflow-x: hidden; - clear: both; -} - -.dropdown-extended ul li { - padding: 0; - margin: 0 !important; - float: none; - border-top: 1px solid; - list-style-type: none; - font-size: 0.95em; - clear: both; - position: relative; -} - -.dropdown-extended ul li:first-child { - border-top: none; -} - -.dropdown-extended ul li.no_notifications { - padding: 10px; -} - -.dropdown-extended .dropdown-contents { - max-height: none; - padding: 0; - position: absolute; - width: 340px; -} - -.nojs .dropdown-extended .dropdown-contents { - position: relative; -} - -.dropdown-extended .header { - padding: 0 10px; - font-family: Arial, "Helvetica Neue", Helvetica, Arial, sans-serif; - font-weight: bold; - text-align: left; - text-shadow: 1px 1px 1px white; - text-transform: uppercase; - line-height: 3em; - border-bottom: 1px solid; - border-radius: 5px 5px 0 0; -} - -.dropdown-extended .header .header_settings { - float: right; - font-weight: normal; - text-transform: none; -} - -.dropdown-extended .header .header_settings a { - display: inline-block; - padding: 0 5px; -} - -.dropdown-extended .header:after { - content: ''; - display: table; - clear: both; -} - -.dropdown-extended .footer { - text-align: center; - font-size: 1.1em; -} - -.dropdown-extended ul li a, .dropdown-extended ul li.no-url { - padding: 8px; -} - -.dropdown-extended .footer > a { - padding: 5px 0; -} - -.dropdown-extended ul li a, .notification_list dt > a, .dropdown-extended .footer > a { - display: block; - text-decoration: none; -} - -.notification_list ul li img { - float: left; - max-height: 50px; - max-width: 50px; - width: auto !important; - height: auto !important; - margin-right: 5px; -} - -.notification_list ul li p { - margin-bottom: 4px; - font-size: 1em; -} - -.notification_list p.notification-reference, -.notification_list p.notification-location, -.notification_list li a p.notification-reason { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.notification_list p.notification-time { - font-size: 0.9em; - margin: 0; - text-align: right; -} - -.notification_list div.notifications { - margin-left: 50px; - padding: 5px; -} - -.notification_list div.notifications a { - display: block; -} - -.notification_list p.notifications_title { - font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; - font-size: 1.2em !important; -} - -.notification_list p.notifications_title strong { - font-weight: bold; -} - -.notification_list p.notifications_time { - font-size: 0.9em !important; -} - -.notification_text { - margin-left: 58px; -} - -.badge { - border-radius: 10px; - opacity: 0.8; - text-align: center; - white-space: nowrap; - font-size: 10px; - line-height: 1; - float: right; - display: inline-block; - margin-left: 3px; - vertical-align: baseline; - position: relative; - top: 3px; - padding: 4px 6px; -} - -.badge.hidden { - display: none; -} - -/* Navbar specific list items -----------------------------------------*/ - -.linklist .quick-links { - margin: 0 7px 0 0; -} - -.linklist.compact .rightside > a > span { - display: none; -} - -.dropdown-page-jump .dropdown { - top: 20px; -} - -.dropdown-page-jump.dropdown-up .dropdown { - bottom: 20px; -} - -.dropdown-page-jump input.tiny { - width: 50px; -} - -.dropdown .clone.hidden { - display: none; -} - -.dropdown .clone.hidden + li.separator { - display: none; -} - -.dropdown .clone.hidden + li { - border-top: none; -} diff --git a/install/update/new/styles/prosilver/theme/forms.css b/install/update/new/styles/prosilver/theme/forms.css deleted file mode 100644 index 99c898f..0000000 --- a/install/update/new/styles/prosilver/theme/forms.css +++ /dev/null @@ -1,429 +0,0 @@ -/* Form Styles ----------------------------------------- */ - -/* General form styles -----------------------------------------*/ -fieldset { - border-width: 0; - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 1.1em; -} - -input { - font-weight: normal; - vertical-align: middle; - padding: 0 3px; - font-size: 1em; - font-family: Verdana, Helvetica, Arial, sans-serif; -} - -select { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-weight: normal; - cursor: pointer; - vertical-align: middle; - border: 1px solid transparent; - padding: 1px; - font-size: 1em; -} - -select:focus { - outline-style: none; -} - -option { - padding-right: 1em; -} - -select optgroup option { - padding-right: 1em; - font-family: Verdana, Helvetica, Arial, sans-serif; -} - -textarea { - font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; - width: 60%; - padding: 2px; - font-size: 1em; - line-height: 1.4em; -} - -label { - cursor: default; - padding-right: 5px; -} - -label input { - vertical-align: middle; -} - -label img { - vertical-align: middle; -} - -/* Definition list layout for forms ----------------------------------------- */ -fieldset dl { - padding: 4px 0; -} - -fieldset dt { - float: left; - width: 40%; - text-align: left; - display: block; -} - -fieldset dd { - margin-left: 41%; - vertical-align: top; - margin-bottom: 3px; -} - -/* Specific layout 1 */ -fieldset.fields1 dt { - width: 15em; - border-right-width: 0; -} - -fieldset.fields1 dd { - margin-left: 15em; - border-left-width: 0; -} - -fieldset.fields1 div { - margin-bottom: 3px; -} - -/* Set it back to 0px for the reCaptcha divs: PHPBB3-9587 */ -fieldset.fields1 .live-search div { - margin-bottom: 0; -} - -/* Specific layout 2 */ -fieldset.fields2 dt { - width: 15em; - border-right-width: 0; -} - -fieldset.fields2 dd { - margin-left: 16em; - border-left-width: 0; -} - -/* Form elements */ -dt label { - font-weight: bold; - text-align: left; -} - -dd label { - white-space: nowrap; -} - -dd input, dd textarea { - margin-right: 3px; -} - -dd select { - width: auto; -} - -dd select[multiple] { - width: 100%; -} - -dd textarea { - width: 85%; -} - -/* Hover effects */ -.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; -} - -fieldset.quick-login input { - width: auto; -} - -fieldset.quick-login input.inputbox { - width: 15%; - vertical-align: middle; - margin-right: 5px; -} - -fieldset.quick-login label { - white-space: nowrap; - padding-right: 2px; -} - -/* Display options on viewtopic/viewforum pages */ -fieldset.display-options { - text-align: center; - margin: 3px 0 5px 0; -} - -fieldset.display-options label { - white-space: nowrap; - padding-right: 2px; -} - -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; - line-height: 2em; - white-space: nowrap; - padding-right: 1em; -} - -fieldset.display-actions label { - white-space: nowrap; - padding-right: 2px; -} - -fieldset.sort-options { - line-height: 2em; -} - -/* MCP forum selection*/ -fieldset.forum-selection { - margin: 5px 0 3px 0; - float: right; -} - -fieldset.forum-selection2 { - margin: 13px 0 3px 0; - float: right; -} - -/* Submit button fieldset */ -fieldset.submit-buttons { - text-align: center; - vertical-align: middle; - margin: 5px 0; -} - -fieldset.submit-buttons input { - vertical-align: middle; -} - -/* Posting page styles -----------------------------------------*/ - -/* Buttons used in the editor */ -.format-buttons { - margin: 15px 0 2px 0; -} - -.format-buttons input, .format-buttons select { - vertical-align: middle; -} - -/* Main message box */ -.message-box { - width: 80%; -} - -.message-box textarea { - font-family: "Trebuchet MS", Verdana, Helvetica, Arial, sans-serif; - width: 450px; - height: 270px; - min-width: 100%; - max-width: 100%; - font-size: 1.2em; - resize: vertical; - outline: 3px dashed transparent; - outline-offset: -4px; - -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 { - width: 18%; - float: right; -} - -.smiley-box img { - margin: 3px; -} - -/* Input field styles ----------------------------------------- */ -.inputbox { - border: 1px solid transparent; - padding: 2px; -} - -.inputbox:hover, .inputbox:focus { - border: 1px solid transparent; - outline-style: none; -} - -input.inputbox { width: 85%; } -input.medium { width: 50%; } -input.narrow { width: 25%; } -input.tiny { width: 150px; } - -textarea.inputbox { - width: 85%; -} - -.autowidth { - width: auto !important; -} - -input[type="number"] { - -moz-padding-end: 0; -} - -input[type="search"] { - -webkit-appearance: textfield; - -webkit-box-sizing: content-box; -} - -input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-decoration { - display: none; -} - -input[type="search"]::-webkit-search-cancel-button { - cursor: pointer; -} - -/* Form button styles ----------------------------------------- */ -input.button1, input.button2 { - font-size: 1em; -} - -a.button1, input.button1, input.button3, a.button2, input.button2 { - width: auto !important; - padding-top: 1px; - 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 { - font-weight: bold; - border: 1px solid transparent; -} - -input.button3 { - padding: 0; - margin: 0; - line-height: 5px; - height: 12px; - background-image: none; - font-variant: small-caps; -} - -input[type="button"], input[type="submit"], input[type="reset"], input[type="checkbox"], input[type="radio"], .search-results li { - cursor: pointer; -} - -/* Alternative button */ -a.button2, input.button2, input.button3 { - border: 1px solid transparent; -} - -/* button in the style of the form buttons */ -a.button1, a.button2 { - text-decoration: none; - padding: 0 3px; - vertical-align: text-bottom; -} - -/* Hover states */ -a.button1:hover, input.button1:hover, a.button2:hover, input.button2:hover, input.button3:hover { - border: 1px solid transparent; -} - -input.disabled { - font-weight: normal; -} - -/* Focus states */ -input.button1:focus, input.button2:focus, input.button3:focus { - outline-style: none; -} - -/* Topic and forum Search */ -.search-box { - float: left; -} - -.search-box .inputbox { - background-image: none; - border-right-width: 0; - border-radius: 4px 0 0 4px; - float: left; - height: 24px; - padding: 3px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -/* Search box (header) ---------------------------------------------- */ -.search-header { - border-radius: 4px; - display: block; - float: right; - margin-right: 5px; - margin-top: 30px; -} - -.search-header .inputbox { border: 0; } - -.navbar .linklist > li.responsive-search { display: none; } - -input.search { - background-image: none; - background-repeat: no-repeat; - background-position: left 1px; - padding-left: 17px; -} - -.full { width: 95%; } -.medium { width: 50%;} -.narrow { width: 25%;} -.tiny { width: 10%;} diff --git a/install/update/new/styles/prosilver/theme/icons.css b/install/update/new/styles/prosilver/theme/icons.css deleted file mode 100644 index 3ac5984..0000000 --- a/install/update/new/styles/prosilver/theme/icons.css +++ /dev/null @@ -1,96 +0,0 @@ -/* -------------------------------------------------------------- - $Icons --------------------------------------------------------------- */ - -/* Global module setup ---------------------------------*/ - -/* Renamed version of .fa class for agnostic usage 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/install/update/new/styles/prosilver/theme/images/site_logo.svg b/install/update/new/styles/prosilver/theme/images/site_logo.svg deleted file mode 100644 index 4ce8903..0000000 --- a/install/update/new/styles/prosilver/theme/images/site_logo.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/install/update/new/styles/prosilver/theme/plupload.css b/install/update/new/styles/prosilver/theme/plupload.css deleted file mode 100644 index b1f3ae2..0000000 --- a/install/update/new/styles/prosilver/theme/plupload.css +++ /dev/null @@ -1,90 +0,0 @@ -.attach-panel-multi { - display: none; - margin-bottom: 1em; -} - -.attach-row-tpl { - display: none; -} - -.file-list td { - vertical-align: middle; -} - -.attach-name { - width: 50%; -} - -.attach-comment { - width: 30%; -} - -.attach-comment .inputbox { - resize: vertical; - width: 100%; -} - -.attach-filesize { - width: 15%; -} - -.attach-status { - width: 5%; -} - -.attach-filesize, .attach-status { - text-align: center; -} - -.attach-controls { - display: inline-block; - float: right; -} - -.nojs .file-inline-bbcode { - display: none; -} - -.file-total-progress { - height: 2px; - display: block; - position: relative; - margin: 4px -10px -6px -10px; -} - -.file-progress { - background-color: #CCCCCC; - display:inline-block; - height: 8px; - width: 50px; -} - -.file-progress-bar, .file-total-progress-bar { - background-color: green; - display: block; - height: 100%; - width: 0; -} - -.file-status.file-working { - background: url('./images/plupload/throbber.gif'); -} - -.file-status.file-uploaded { - background: url('./images/plupload/done.gif'); -} - -.file-status.file-error { - background: url('./images/plupload/error.gif'); -} - -.file-status { - display: inline-block; - height: 16px; - width: 16px; -} - -.file-name { - max-width: 65%; - vertical-align: bottom; -} diff --git a/install/update/new/styles/prosilver/theme/print.css b/install/update/new/styles/prosilver/theme/print.css deleted file mode 100644 index ee916dc..0000000 --- a/install/update/new/styles/prosilver/theme/print.css +++ /dev/null @@ -1,150 +0,0 @@ -/* Print Style Sheet ----------------------------------------- */ - - -/* Lots still TODO here! */ - -/* General markup styles */ -* { - padding: 0; - margin: 0; -} - -body { - font: 11pt Verdana, Arial, Helvetica, sans-serif; - color:#000000; -} - -a:link { color: #000000; text-decoration: none; } -a:visited { color: #000000; text-decoration: none; } -a:active { color: #000000; text-decoration: none; } - -img, .noprint, .navbar, .box1, .divider, .signature { display: none; } -/* Display smilies (Bug #47265) */ -.content img { - display: inline; -} - -/* Container for the main body */ -.wrap { - margin: 0 2em; -} - -p { font-size: 85%; } -.copyright { font-size: 75%; } -.page-number { float:right; width: auto; text-align: right; font-size: 75%; } - -h1, h2, h3, h1 a, h2 a, h3 a { - font-family: "Trebuchet MS",georgia,Verdana,Sans-serif; - color: #000000; - background: none; - text-decoration: none; - font-weight: bold; -} - -h1 { font-size: 20pt; } -h2 { font-size: 16pt; margin-top: 1em; } -h3 { font-size: 14pt; margin-top: 1em; } - -.content { - font-size: 11pt; - line-height: 14pt; - margin-bottom: 1em; - font-family: "Lucida Grande", "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; - overflow: hidden; -} - -/* CSS2 Print tip from: http://www.alistapart.com/articles/goingtoprint/ */ -.postbody a:link, .postbody a:visited, .postbody a:hover, .postbody a:active { - text-decoration: underline; - padding: 0.1em 0.2em; - margin: -0.1em -0.2em; - color: #666; - background: none; - font-size: 100%; -} - -html>body .postbody a:link:after, html>body .postbody a:visited:after { - content: " (" attr(href) ") "; - font-size: 90%; - text-decoration: none; -} - -hr { - height: 1px; - background-color: #999999; - border-width: 0; -} - -.author { - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 75%; - margin-bottom: 0.6em; -} - -.date { - font-family: Verdana, Arial, Helvetica, sans-serif; - float: right; - position: relative; - text-align: right; - font-size: 75%; -} - -/* Don't want to print url for names or titles in content area */ -.postbody .author a:link, .postbody .author a:visited, -html>body .postbody .author a:link:after, -html>body .postbody .author a:visited:after, -.postquote .quote-by a:link, .postquote .quote-by a:visited, -html>body .postquote .quote-by a:link:after, -html>body .postquote .quote-by a:visited:after, -html>body .postbody h1 a:link:after, html>body .postbody h2 a:link:after { - text-decoration: none; - content: ""; -} - -/* Poster profile */ -.postprofile { display: none; } -.grip-show { display:none; } - -/* Quote */ -.postquote, blockquote { - font-size: 85%; - margin: 1em 18% 1em 4%; - padding: 0.5em; - position: relative; - line-height: 1.5em; - border: 1px #999999 solid; -} - -.postquote img { display: none; } -.postquote span { display: block; } -.postquote span .postquote { font-size: 100%; } -.quote-by, blockquote cite { - color: black; - display : block; - font-weight: bold; -} - -/* List */ -ol, ul { - margin-left: 15pt -} - -/* 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/install/update/new/styles/prosilver/theme/stylesheet.css b/install/update/new/styles/prosilver/theme/stylesheet.css deleted file mode 100644 index c402d56..0000000 --- a/install/update/new/styles/prosilver/theme/stylesheet.css +++ /dev/null @@ -1,21 +0,0 @@ -/* phpBB3 Style Sheet - -------------------------------------------------------------- - Style name: prosilver (the default phpBB 3.3.x style) - Based on style: - Original author: Tom Beddard ( http://www.subblue.com/ ) - Modified by: phpBB Limited ( https://www.phpbb.com/ ) - -------------------------------------------------------------- -*/ - -@import url("normalize.css?v=3.3"); -@import url("base.css?v=3.3"); -@import url("utilities.css?v=3.3"); -@import url("common.css?v=3.3"); -@import url("links.css?v=3.3"); -@import url("content.css?v=3.3"); -@import url("buttons.css?v=3.3"); -@import url("cp.css?v=3.3"); -@import url("forms.css?v=3.3"); -@import url("icons.css?v=3.3"); -@import url("colours.css?v=3.3"); -@import url("responsive.css?v=3.3"); diff --git a/install/update/new/ucp.php b/install/update/new/ucp.php deleted file mode 100644 index 0992e3e..0000000 --- a/install/update/new/ucp.php +++ /dev/null @@ -1,413 +0,0 @@ - -* @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); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -require($phpbb_root_path . 'common.' . $phpEx); -require($phpbb_root_path . 'includes/functions_user.' . $phpEx); -require($phpbb_root_path . 'includes/functions_module.' . $phpEx); - -// Basic parameter data -$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); -$user->setup('ucp'); - -// Setting a variable to let the style designer know where he is... -$template->assign_var('S_IN_UCP', true); - -$module = new p_master(); -$default = false; - -// Basic "global" modes -switch ($mode) -{ - case 'activate': - $module->load('ucp', 'activate'); - $module->display($user->lang['UCP_ACTIVATE']); - - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - break; - - case 'resend_act': - $module->load('ucp', 'resend'); - $module->display($user->lang['UCP_RESEND']); - break; - - case 'sendpassword': - /** @var \phpbb\controller\helper $controller_helper */ - $controller_helper = $phpbb_container->get('controller.helper'); - - redirect($controller_helper->route('phpbb_ucp_forgot_password_controller')); - break; - - case 'register': - if ($user->data['is_registered'] || isset($_REQUEST['not_agreed'])) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - $module->load('ucp', 'register'); - $module->display($user->lang['REGISTER']); - break; - - case 'confirm': - $module->load('ucp', 'confirm'); - break; - - case 'login': - if ($user->data['is_registered']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - login_box($request->variable('redirect', "index.$phpEx")); - break; - - case 'login_link': - if ($user->data['is_registered']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - $module->load('ucp', 'login_link'); - $module->display($user->lang['UCP_LOGIN_LINK']); - break; - - case 'logout': - if ($user->data['user_id'] != ANONYMOUS && $request->is_set('sid') && $request->variable('sid', '') === $user->session_id) - { - $user->session_kill(); - } - else if ($user->data['user_id'] != ANONYMOUS) - { - meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx")); - - $message = $user->lang['LOGOUT_FAILED'] . '

' . sprintf($user->lang['RETURN_INDEX'], '
', ' '); - trigger_error($message); - } - - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - break; - - case 'terms': - case 'privacy': - - $message = ($mode == 'terms') ? 'TERMS_OF_USE_CONTENT' : 'PRIVACY_POLICY'; - $title = ($mode == 'terms') ? 'TERMS_USE' : 'PRIVACY'; - - if (empty($user->lang[$message])) - { - if ($user->data['is_registered']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - login_box(); - } - - $template->set_filenames(array( - 'body' => 'ucp_agreement.html') - ); - - // Disable online list - page_header($user->lang[$title]); - - $template->assign_vars(array( - 'S_AGREEMENT' => true, - '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_PREV'], - )); - - page_footer(); - - break; - - case 'delete_cookies': - - // Delete Cookies with dynamic names (do NOT delete poll cookies) - if (confirm_box(true)) - { - $set_time = time() - 31536000; - - foreach ($request->variable_names(\phpbb\request\request_interface::COOKIE) as $cookie_name) - { - $cookie_data = $request->variable($cookie_name, '', true, \phpbb\request\request_interface::COOKIE); - - // Only delete board cookies, no other ones... - if (strpos($cookie_name, $config['cookie_name'] . '_') !== 0) - { - continue; - } - - $cookie_name = str_replace($config['cookie_name'] . '_', '', $cookie_name); - - /** - * Event to save custom cookies from deletion - * - * @event core.ucp_delete_cookies - * @var string cookie_name Cookie name to checking - * @var bool retain_cookie Do we retain our cookie or not, true if retain - * @since 3.1.3-RC1 - */ - $retain_cookie = false; - $vars = array('cookie_name', 'retain_cookie'); - extract($phpbb_dispatcher->trigger_event('core.ucp_delete_cookies', compact($vars))); - if ($retain_cookie) - { - continue; - } - - // Polls are stored as {cookie_name}_poll_{topic_id}, cookie_name_ got removed, therefore checking for poll_ - if (strpos($cookie_name, 'poll_') !== 0) - { - $user->set_cookie($cookie_name, '', $set_time); - } - } - - $user->set_cookie('track', '', $set_time); - $user->set_cookie('u', '', $set_time); - $user->set_cookie('k', '', $set_time); - $user->set_cookie('sid', '', $set_time); - - // We destroy the session here, the user will be logged out nevertheless - $user->session_kill(); - $user->session_begin(); - - meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx")); - - $message = $user->lang['COOKIES_DELETED'] . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - trigger_error($message); - } - else - { - confirm_box(false, 'DELETE_COOKIES', ''); - } - - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - - break; - - case 'switch_perm': - - $user_id = $request->variable('u', 0); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $user_id; - $result = $db->sql_query($sql); - $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->variable('hash', ''), 'switchperm')) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - include($phpbb_root_path . 'includes/acp/auth.' . $phpEx); - - $auth_admin = new auth_admin(); - if (!$auth_admin->ghost_permissions($user_id, $user->data['user_id'])) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - $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']) . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - - /** - * Event to run code after permissions are switched - * - * @event core.ucp_switch_permissions - * @var int user_id User ID to switch permission to - * @var array user_row User data - * @var string message Success message - * @since 3.1.11-RC1 - */ - $vars = array('user_id', 'user_row', 'message'); - extract($phpbb_dispatcher->trigger_event('core.ucp_switch_permissions', compact($vars))); - - trigger_error($message); - - break; - - case 'restore_perm': - - if (!$user->data['user_perm_from'] || !$auth->acl_get('a_switchperm')) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - $auth->acl_cache($user->data); - - $sql = 'SELECT username - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user->data['user_perm_from']; - $result = $db->sql_query($sql); - $username = $db->sql_fetchfield('username'); - $db->sql_freeresult($result); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ACL_RESTORE_PERMISSIONS', false, array($username)); - - $message = $user->lang['PERMISSIONS_RESTORED'] . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - - /** - * Event to run code after permissions are restored - * - * @event core.ucp_restore_permissions - * @var string username User name - * @var string message Success message - * @since 3.1.11-RC1 - */ - $vars = array('username', 'message'); - extract($phpbb_dispatcher->trigger_event('core.ucp_restore_permissions', compact($vars))); - - trigger_error($message); - - break; - - default: - $default = true; - break; -} - -// We use this approach because it does not impose large code changes -if (!$default) -{ - return true; -} - -// Only registered users can go beyond this point -if (!$user->data['is_registered']) -{ - if ($user->data['is_bot']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - if ($id == 'pm' && $mode == 'view' && isset($_GET['p'])) - { - $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']); - } - - login_box('', $user->lang['LOGIN_EXPLAIN_UCP']); -} - -// Instantiate module system and generate list of available modules -$module->list_modules('ucp'); - -// Check if the zebra module is set -if ($module->is_active('zebra', 'friends')) -{ - // Output listing of friends online - $update_time = $config['load_online_time'] * 60; - - $sql_ary = array( - 'SELECT' => 'u.user_id, u.username, u.username_clean, u.user_colour, MAX(s.session_time) as online_time, MIN(s.session_viewonline) AS viewonline', - - 'FROM' => array( - USERS_TABLE => 'u', - ZEBRA_TABLE => 'z', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(SESSIONS_TABLE => 's'), - 'ON' => 's.session_user_id = z.zebra_id', - ), - ), - - 'WHERE' => 'z.user_id = ' . $user->data['user_id'] . ' - AND z.friend = 1 - AND u.user_id = z.zebra_id', - - 'GROUP_BY' => 'z.zebra_id, u.user_id, u.username_clean, u.user_colour, u.username', - - 'ORDER_BY' => 'u.username_clean ASC', - ); - - $sql = $db->sql_build_query('SELECT_DISTINCT', $sql_ary); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $which = (time() - $update_time < $row['online_time'] && ($row['viewonline'] || $auth->acl_get('u_viewonline'))) ? 'online' : 'offline'; - - $template->assign_block_vars("friends_{$which}", array( - 'USER_ID' => $row['user_id'], - - 'U_PROFILE' => get_username_string('profile', $row['user_id'], $row['username'], $row['user_colour']), - 'USER_COLOUR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'])) - ); - } - $db->sql_freeresult($result); -} - -// Do not display subscribed topics/forums if not allowed -if (!$config['allow_topic_notify'] && !$config['allow_forum_notify']) -{ - $module->set_display('main', 'subscribed', false); -} - -/** -* Use this event to enable and disable additional UCP modules -* -* @event core.ucp_display_module_before -* @var p_master module Object holding all modules and their status -* @var mixed id Active module category (can be the int or string) -* @var string mode Active module -* @since 3.1.0-a1 -*/ -$vars = array('module', 'id', 'mode'); -extract($phpbb_dispatcher->trigger_event('core.ucp_display_module_before', compact($vars))); - -$template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $user->lang('UCP'), - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}ucp.$phpEx"), -)); - -// Select the active module -$module->set_active($id, $mode); - -// Load and execute the relevant module -$module->load_active(); - -// Assign data to the template engine for the list of modules -$module->assign_tpl_vars(append_sid("{$phpbb_root_path}ucp.$phpEx")); - -// Generate the page, do not display/query online list -$module->display($module->get_page_title()); diff --git a/install/update/new/viewforum.php b/install/update/new/viewforum.php deleted file mode 100644 index eb6b37a..0000000 --- a/install/update/new/viewforum.php +++ /dev/null @@ -1,1064 +0,0 @@ - -* @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); -$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 -$user->session_begin(); -$auth->acl($user->data); - -// Start initial var setup -$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->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 -// If not give them a nice error page. -if (!$forum_id) -{ - trigger_error('NO_FORUM'); -} - -$sql_from = FORUMS_TABLE . ' f'; -$lastread_select = ''; - -// Grab appropriate forum data -if ($config['load_db_lastread'] && $user->data['is_registered']) -{ - $sql_from .= ' LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . ' - AND ft.forum_id = f.forum_id)'; - $lastread_select .= ', ft.mark_time'; -} - -if ($user->data['is_registered']) -{ - $sql_from .= ' LEFT JOIN ' . FORUMS_WATCH_TABLE . ' fw ON (fw.forum_id = f.forum_id AND fw.user_id = ' . $user->data['user_id'] . ')'; - $lastread_select .= ', fw.notify_status'; -} - -$sql = "SELECT f.* $lastread_select - FROM $sql_from - WHERE f.forum_id = $forum_id"; -$result = $db->sql_query($sql); -$forum_data = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -if (!$forum_data) -{ - trigger_error('NO_FORUM'); -} - - -// Configure style, language, etc. -$user->setup('viewforum', $forum_data['forum_style']); - -// Redirect to login upon emailed notification links -if (isset($_GET['e']) && !$user->data['is_registered']) -{ - login_box('', $user->lang['LOGIN_NOTIFY_FORUM']); -} - -// Permissions check -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'); - } - - login_box('', $user->lang['LOGIN_VIEWFORUM']); -} - -// Forum is passworded ... check whether access has been granted to this -// user this session, if not show login box -if ($forum_data['forum_password']) -{ - login_forum_box($forum_data); -} - -// Is this forum a link? ... User got here either because the -// number of clicks is being tracked or they guessed the id -if ($forum_data['forum_type'] == FORUM_LINK && $forum_data['forum_link']) -{ - // Does it have click tracking enabled? - if ($forum_data['forum_flags'] & FORUM_FLAG_LINK_TRACK) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_posts_approved = forum_posts_approved + 1 - WHERE forum_id = ' . $forum_id; - $db->sql_query($sql); - } - - // We redirect to the url. The third parameter indicates that external redirects are allowed. - redirect($forum_data['forum_link'], false, true); - return; -} - -// Build navigation links -generate_forum_nav($forum_data); - -// Forum Rules -if ($auth->acl_get('f_read', $forum_id)) -{ - generate_forum_rules($forum_data); -} - -// Do we have subforums? -$active_forum_ary = $moderators = array(); - -if ($forum_data['left_id'] != $forum_data['right_id'] - 1) -{ - list($active_forum_ary, $moderators) = display_forums($forum_data, $config['load_moderators'], $config['load_moderators']); -} -else -{ - $template->assign_var('S_HAS_SUBFORUM', false); - if ($config['load_moderators']) - { - get_moderators($moderators, $forum_id); - } -} - -// Is a forum specific topic count required? -if ($forum_data['forum_topics_per_page']) -{ - $config['topics_per_page'] = $forum_data['forum_topics_per_page']; -} - -/* @var $phpbb_content_visibility \phpbb\content_visibility */ -$phpbb_content_visibility = $phpbb_container->get('content.visibility'); - -// Dump out the page header and load viewforum template -$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_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') -); - -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_id); - -$template->assign_vars(array( - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . (($start == 0) ? '' : "&start=$start")), -)); - -// Not postable forum or showing active topics? -if (!($forum_data['forum_type'] == FORUM_POST || (($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) && $forum_data['forum_type'] == FORUM_CAT))) -{ - page_footer(); -} - -// 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_gets('f_read', 'f_list_topics', $forum_id)) -{ - $template->assign_vars(array( - 'S_NO_READ_ACCESS' => true, - )); - - page_footer(); -} - -// Handle marking posts -if ($mark_read == 'topics') -{ - $token = $request->variable('hash', ''); - if (check_link_hash($token, 'global')) - { - 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); - - if ($request->is_ajax()) - { - // Tell the ajax script what language vars and URL need to be replaced - $data = array( - 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'], - 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'], - 'U_MARK_TOPICS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . "&f=$forum_id&mark=topics&mark_time=" . time(), false) : '', - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $user->lang['TOPICS_MARKED'] - ); - $json_response = new \phpbb\json_response(); - $json_response->send($data); - } - - trigger_error($user->lang['TOPICS_MARKED'] . '

' . sprintf($user->lang['RETURN_FORUM'], '', '')); -} - -// 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'); - $task->set_forum_data($forum_data); - - if ($task->is_ready()) - { - $url = $task->get_url(); - $template->assign_var('RUN_CRON_TASK', 'cron'); - } - else - { - // See if we should prune the shadow topics instead - $task = $cron->find_task('cron.task.core.prune_shadow_topics'); - $task->set_forum_data($forum_data); - - if ($task->is_ready()) - { - $url = $task->get_url(); - $template->assign_var('RUN_CRON_TASK', 'cron'); - } - } -} - -// Forum rules and subscription info -$s_watching_forum = array( - 'link' => '', - 'link_toggle' => '', - 'title' => '', - 'title_toggle' => '', - 'is_watching' => false, -); - -if ($config['allow_forum_notify'] && $forum_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_subscribe', $forum_id) || $user->data['user_id'] == ANONYMOUS)) -{ - $notify_status = (isset($forum_data['notify_status'])) ? $forum_data['notify_status'] : NULL; - watch_topic_forum('forum', $s_watching_forum, $user->data['user_id'], $forum_id, 0, $notify_status, $start, $forum_data['forum_name']); -} - -$s_forum_rules = ''; -gen_forum_auth_level('forum', $forum_id, $forum_data['forum_status']); - -// Topic ordering options -$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'], '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); - -// Limit topics to certain time frame, obtain correct topic count -if ($sort_days) -{ - $min_post_time = time() - ($sort_days * 86400); - - $sql_array = array( - 'SELECT' => 'COUNT(t.topic_id) AS num_topics', - 'FROM' => array( - TOPICS_TABLE => 't', - ), - 'WHERE' => 't.forum_id = ' . $forum_id . ' - AND (t.topic_last_post_time >= ' . $min_post_time . ' - OR t.topic_type = ' . POST_ANNOUNCE . ' - OR t.topic_type = ' . POST_GLOBAL . ') - AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'), - ); - - /** - * Modify the sort data SQL query for getting additional fields if needed - * - * @event core.viewforum_modify_sort_data_sql - * @var int forum_id The forum_id whose topics are being listed - * @var int start Variable containing start for pagination - * @var int sort_days The oldest topic displayable in elapsed days - * @var string sort_key The sorting by. It is one of the first character of (in low case): - * Author, Post time, Replies, Subject, Views - * @var string sort_dir Either "a" for ascending or "d" for descending - * @var array sql_array The SQL array to get the data of all topics - * @since 3.1.9-RC1 - */ - $vars = array( - 'forum_id', - 'start', - 'sort_days', - 'sort_key', - 'sort_dir', - 'sql_array', - ); - extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_sort_data_sql', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_array)); - $topics_count = (int) $db->sql_fetchfield('num_topics'); - $db->sql_freeresult($result); - - if (isset($_POST['sort'])) - { - $start = 0; - } - $sql_limit_time = "AND t.topic_last_post_time >= $min_post_time"; - - // Make sure we have information about day selection ready - $template->assign_var('S_SORT_DAYS', true); -} -else -{ - $sql_limit_time = ''; -} - -// Basic pagewide vars -$post_alt = ($forum_data['forum_status'] == ITEM_LOCKED) ? $user->lang['FORUM_LOCKED'] : $user->lang['POST_NEW_TOPIC']; - -// Display active topics? -$s_display_active = ($forum_data['forum_type'] == FORUM_CAT && ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) ? true : false; - -$s_search_hidden_fields = array('fid' => array($forum_id)); -if ($_SID) -{ - $s_search_hidden_fields['sid'] = $_SID; -} - -if (!empty($_EXTRA_URL)) -{ - foreach ($_EXTRA_URL as $url_param) - { - $url_param = explode('=', $url_param, 2); - $s_search_hidden_fields[$url_param[0]] = $url_param[1]; - } -} - -$template->assign_vars(array( - 'MODERATORS' => (!empty($moderators[$forum_id])) ? implode($user->lang['COMMA_SEPARATOR'], $moderators[$forum_id]) : '', - - 'POST_IMG' => ($forum_data['forum_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', $post_alt) : $user->img('button_topic_new', $post_alt), - 'NEWEST_POST_IMG' => $user->img('icon_topic_newest', 'VIEW_NEWEST_POST'), - 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), - 'FOLDER_IMG' => $user->img('topic_read', 'NO_UNREAD_POSTS'), - 'FOLDER_UNREAD_IMG' => $user->img('topic_unread', 'UNREAD_POSTS'), - 'FOLDER_HOT_IMG' => $user->img('topic_read_hot', 'NO_UNREAD_POSTS_HOT'), - 'FOLDER_HOT_UNREAD_IMG' => $user->img('topic_unread_hot', 'UNREAD_POSTS_HOT'), - 'FOLDER_LOCKED_IMG' => $user->img('topic_read_locked', 'NO_UNREAD_POSTS_LOCKED'), - 'FOLDER_LOCKED_UNREAD_IMG' => $user->img('topic_unread_locked', 'UNREAD_POSTS_LOCKED'), - 'FOLDER_STICKY_IMG' => $user->img('sticky_read', 'POST_STICKY'), - 'FOLDER_STICKY_UNREAD_IMG' => $user->img('sticky_unread', 'POST_STICKY'), - 'FOLDER_ANNOUNCE_IMG' => $user->img('announce_read', 'POST_ANNOUNCEMENT'), - 'FOLDER_ANNOUNCE_UNREAD_IMG'=> $user->img('announce_unread', 'POST_ANNOUNCEMENT'), - 'FOLDER_MOVED_IMG' => $user->img('topic_moved', 'TOPIC_MOVED'), - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'TOPIC_REPORTED'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPIC_UNAPPROVED'), - 'DELETED_IMG' => $user->img('icon_topic_deleted', 'TOPIC_DELETED'), - 'POLL_IMG' => $user->img('icon_topic_poll', 'TOPIC_POLL'), - 'GOTO_PAGE_IMG' => $user->img('icon_post_target', 'GOTO_PAGE'), - - 'L_NO_TOPICS' => ($forum_data['forum_status'] == ITEM_LOCKED) ? $user->lang['POST_FORUM_LOCKED'] : $user->lang['NO_TOPICS'], - - 'S_DISPLAY_POST_INFO' => ($forum_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false, - - 'S_IS_POSTABLE' => ($forum_data['forum_type'] == FORUM_POST) ? true : false, - 'S_USER_CAN_POST' => ($auth->acl_get('f_post', $forum_id)) ? true : false, - 'S_DISPLAY_ACTIVE' => $s_display_active, - '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 && 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'], - 'S_WATCH_FORUM_TOGGLE' => $s_watching_forum['title_toggle'], - 'S_WATCHING_FORUM' => $s_watching_forum['is_watching'], - 'S_FORUM_ACTION' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . (($start == 0) ? '' : "&start=$start")), - '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]) && count($moderators[$forum_id]) > 1) ? false : true, - 'S_IS_LOCKED' => ($forum_data['forum_status'] == ITEM_LOCKED) ? true : false, - 'S_VIEWFORUM' => true, - - 'U_MCP' => ($auth->acl_get('m_', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "f=$forum_id&i=main&mode=forum_view", true, $user->session_id) : '', - 'U_POST_NEW_TOPIC' => ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=post&f=' . $forum_id) : '', - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($start == 0) ? '' : "&start=$start")), - 'U_CANONICAL' => generate_board_url() . '/' . append_sid("viewforum.$phpEx", "f=$forum_id" . (($start) ? "&start=$start" : ''), true, ''), - '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()) : '', -)); - -// Grab icons -$icons = $cache->obtain_icons(); - -// Grab all topic data -$rowset = $announcement_list = $topic_list = $global_announce_forums = array(); - -$sql_array = array( - 'SELECT' => 't.*', - 'FROM' => array( - TOPICS_TABLE => 't' - ), - 'LEFT_JOIN' => array(), -); - -/** -* Event to modify the SQL query before the topic data is retrieved -* -* It may also be used to override the above assigned template vars -* -* @event core.viewforum_get_topic_data -* @var array forum_data Array with forum data -* @var array sql_array The SQL array to get the data of all topics -* @var int forum_id The forum_id whose topics are being listed -* @var int topics_count The total number of topics for display -* @var int sort_days The oldest topic displayable in elapsed days -* @var string sort_key The sorting by. It is one of the first character of (in low case): -* Author, Post time, Replies, Subject, Views -* @var string sort_dir Either "a" for ascending or "d" for descending -* @since 3.1.0-a1 -* @changed 3.1.0-RC4 Added forum_data var -* @changed 3.1.4-RC1 Added forum_id, topics_count, sort_days, sort_key and sort_dir vars -* @changed 3.1.9-RC1 Fix types of properties -*/ -$vars = array( - 'forum_data', - 'sql_array', - 'forum_id', - 'topics_count', - 'sort_days', - 'sort_key', - 'sort_dir', -); -extract($phpbb_dispatcher->trigger_event('core.viewforum_get_topic_data', compact($vars))); - -$sql_approved = ' AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'); - -if ($user->data['is_registered']) -{ - if ($config['load_db_track']) - { - $sql_array['LEFT_JOIN'][] = array('FROM' => array(TOPICS_POSTED_TABLE => 'tp'), 'ON' => 'tp.topic_id = t.topic_id AND tp.user_id = ' . $user->data['user_id']); - $sql_array['SELECT'] .= ', tp.topic_posted'; - } - - if ($config['load_db_lastread']) - { - $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 && 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'; - } - } -} - -if ($forum_data['forum_type'] == FORUM_POST) -{ - // Get global announcement forums - $g_forum_ary = $auth->acl_getf('f_read', true); - $g_forum_ary = array_unique(array_keys($g_forum_ary)); - - $sql_anounce_array['LEFT_JOIN'] = $sql_array['LEFT_JOIN']; - $sql_anounce_array['LEFT_JOIN'][] = array('FROM' => array(FORUMS_TABLE => 'f'), 'ON' => 'f.forum_id = t.forum_id'); - $sql_anounce_array['SELECT'] = $sql_array['SELECT'] . ', f.forum_name'; - - // Obtain announcements ... removed sort ordering, sort by time in all cases - $sql_ary = array( - 'SELECT' => $sql_anounce_array['SELECT'], - 'FROM' => $sql_array['FROM'], - 'LEFT_JOIN' => $sql_anounce_array['LEFT_JOIN'], - - 'WHERE' => '(t.forum_id = ' . $forum_id . ' - AND t.topic_type = ' . POST_ANNOUNCE . ') OR - (' . $db->sql_in_set('t.forum_id', $g_forum_ary, false, true) . ' - AND t.topic_type = ' . POST_GLOBAL . ')', - - 'ORDER_BY' => 't.topic_time DESC', - ); - - /** - * Event to modify the SQL query before the announcement topic ids data is retrieved - * - * @event core.viewforum_get_announcement_topic_ids_data - * @var array forum_data Data about the forum - * @var array g_forum_ary Global announcement forums array - * @var array sql_anounce_array SQL announcement array - * @var array sql_ary SQL query array to get the announcement topic ids data - * @var int forum_id The forum ID - * - * @since 3.1.10-RC1 - */ - $vars = array( - 'forum_data', - 'g_forum_ary', - 'sql_anounce_array', - 'sql_ary', - 'forum_id', - ); - extract($phpbb_dispatcher->trigger_event('core.viewforum_get_announcement_topic_ids_data', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$phpbb_content_visibility->is_visible('topic', $row['forum_id'], $row)) - { - // Do not display announcements that are waiting for approval or soft deleted. - continue; - } - - $rowset[$row['topic_id']] = $row; - $announcement_list[] = $row['topic_id']; - - if ($forum_id != $row['forum_id']) - { - $topics_count++; - $global_announce_forums[] = $row['forum_id']; - } - } - $db->sql_freeresult($result); -} - -$forum_tracking_info = array(); - -if ($user->data['is_registered'] && $config['load_db_lastread']) -{ - $forum_tracking_info[$forum_id] = $forum_data['mark_time']; - - if (!empty($global_announce_forums)) - { - $sql = 'SELECT forum_id, mark_time - FROM ' . FORUMS_TRACK_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $global_announce_forums) . ' - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_tracking_info[$row['forum_id']] = $row['mark_time']; - } - $db->sql_freeresult($result); - } -} - -// If the user is trying to reach late pages, start searching from the end -$store_reverse = false; -$sql_limit = $config['topics_per_page']; -if ($start > $topics_count / 2) -{ - $store_reverse = true; - - // Select the sort order - $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC'); - - $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 -{ - // Select the sort order - $direction = (($sort_dir == 'd') ? 'DESC' : 'ASC'); - $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; -} -else -{ - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction; -} - -if ($forum_data['forum_type'] == FORUM_POST || !count($active_forum_ary)) -{ - $sql_where = 't.forum_id = ' . $forum_id; -} -else if (empty($active_forum_ary['exclude_forum_id'])) -{ - $sql_where = $db->sql_in_set('t.forum_id', $active_forum_ary['forum_id']); -} -else -{ - $get_forum_ids = array_diff($active_forum_ary['forum_id'], $active_forum_ary['exclude_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 -$sql_ary = array( - 'SELECT' => 't.topic_id', - 'FROM' => array( - TOPICS_TABLE => 't', - ), - 'WHERE' => "$sql_where - AND t.topic_type IN (" . POST_NORMAL . ', ' . POST_STICKY . ") - $sql_approved - $sql_limit_time", - 'ORDER_BY' => 't.topic_type ' . ((!$store_reverse) ? 'DESC' : 'ASC') . ', ' . $sql_sort_order, -); - -/** -* Event to modify the SQL query before the topic ids data is retrieved -* -* @event core.viewforum_get_topic_ids_data -* @var array forum_data Data about the forum -* @var array sql_ary SQL query array to get the topic ids data -* @var string sql_approved Topic visibility SQL string -* @var int sql_limit Number of records to select -* @var string sql_limit_time SQL string to limit topic_last_post_time data -* @var array sql_sort_order SQL sorting string -* @var int sql_start Offset point to start selection from -* @var string sql_where SQL WHERE clause string -* @var bool store_reverse Flag indicating if we select from the late pages -* -* @since 3.1.0-RC4 -* -* @changed 3.1.3 Added forum_data -*/ -$vars = array( - 'forum_data', - 'sql_ary', - 'sql_approved', - 'sql_limit', - 'sql_limit_time', - 'sql_sort_order', - 'sql_start', - 'sql_where', - 'store_reverse', -); -extract($phpbb_dispatcher->trigger_event('core.viewforum_get_topic_ids_data', compact($vars))); - -$sql = $db->sql_build_query('SELECT', $sql_ary); -$result = $db->sql_query_limit($sql, $sql_limit, $sql_start); - -while ($row = $db->sql_fetchrow($result)) -{ - $topic_list[] = (int) $row['topic_id']; -} -$db->sql_freeresult($result); - -// For storing shadow topics -$shadow_topic_list = array(); - -if (count($topic_list)) -{ - // SQL array for obtaining topics/stickies - $sql_array = array( - 'SELECT' => $sql_array['SELECT'], - 'FROM' => $sql_array['FROM'], - 'LEFT_JOIN' => $sql_array['LEFT_JOIN'], - - 'WHERE' => $db->sql_in_set('t.topic_id', $topic_list), - ); - - // If store_reverse, then first obtain topics, then stickies, else the other way around... - // Funnily enough you typically save one query if going from the last page to the middle (store_reverse) because - // the number of stickies are not known - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_status'] == ITEM_MOVED) - { - $shadow_topic_list[$row['topic_moved_id']] = $row['topic_id']; - } - - $rowset[$row['topic_id']] = $row; - } - $db->sql_freeresult($result); -} - -// If we have some shadow topics, update the rowset to reflect their topic information -if (count($shadow_topic_list)) -{ - // SQL array for obtaining shadow topics - $sql_array = array( - 'SELECT' => 't.*', - 'FROM' => array( - TOPICS_TABLE => 't' - ), - 'WHERE' => $db->sql_in_set('t.topic_id', array_keys($shadow_topic_list)), - ); - - /** - * Event to modify the SQL query before the shadowtopic data is retrieved - * - * @event core.viewforum_get_shadowtopic_data - * @var array sql_array SQL array to get the data of any shadowtopics - * @since 3.1.0-a1 - */ - $vars = array('sql_array'); - extract($phpbb_dispatcher->trigger_event('core.viewforum_get_shadowtopic_data', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $orig_topic_id = $shadow_topic_list[$row['topic_id']]; - - // If the shadow topic is already listed within the rowset (happens for active topics for example), then do not include it... - if (isset($rowset[$row['topic_id']])) - { - // We need to remove any trace regarding this topic. :) - unset($rowset[$orig_topic_id]); - unset($topic_list[array_search($orig_topic_id, $topic_list)]); - $topics_count--; - - continue; - } - - // Do not include those topics the user has no permission to access - 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]); - unset($topic_list[array_search($orig_topic_id, $topic_list)]); - $topics_count--; - - continue; - } - - // We want to retain some values - $row = array_merge($row, array( - 'topic_moved_id' => $rowset[$orig_topic_id]['topic_moved_id'], - 'topic_status' => $rowset[$orig_topic_id]['topic_status'], - 'topic_type' => $rowset[$orig_topic_id]['topic_type'], - 'topic_title' => $rowset[$orig_topic_id]['topic_title'], - )); - - // Shadow topics are never reported - $row['topic_reported'] = 0; - - $rowset[$orig_topic_id] = $row; - } - $db->sql_freeresult($result); -} -unset($shadow_topic_list); - -// Ok, adjust topics count for active topics list -if ($s_display_active) -{ - $topics_count = 1; -} - -// 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 - count($announcement_list); - -$base_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . ((strlen($u_sort_param)) ? "&$u_sort_param" : '')); -$pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_topic_count, $config['topics_per_page'], $start); - -$template->assign_vars(array( - 'TOTAL_TOPICS' => ($s_display_active) ? false : $user->lang('VIEW_FORUM_TOPICS', (int) $total_topic_count), -)); - -$topic_list = ($store_reverse) ? array_merge($announcement_list, array_reverse($topic_list)) : array_merge($announcement_list, $topic_list); -$topic_tracking_info = $tracking_topics = array(); - -/** -* Modify topics data before we display the viewforum page -* -* @event core.viewforum_modify_topics_data -* @var array topic_list Array with current viewforum page topic ids -* @var array rowset Array with topics data (in topic_id => topic_data format) -* @var int total_topic_count Forum's total topic count -* @var int forum_id Forum identifier -* @since 3.1.0-b3 -* @changed 3.1.11-RC1 Added forum_id -*/ -$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 (count($topic_list)) -{ - $mark_forum_read = true; - $mark_time_forum = 0; - - // Generate topic forum list... - $topic_forum_list = array(); - foreach ($rowset as $t_id => $row) - { - if (isset($forum_tracking_info[$row['forum_id']])) - { - $row['forum_mark_time'] = $forum_tracking_info[$row['forum_id']]; - } - - $topic_forum_list[$row['forum_id']]['forum_mark_time'] = ($config['load_db_lastread'] && $user->data['is_registered'] && isset($row['forum_mark_time'])) ? $row['forum_mark_time'] : 0; - $topic_forum_list[$row['forum_id']]['topics'][] = (int) $t_id; - } - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - foreach ($topic_forum_list as $f_id => $topic_row) - { - $topic_tracking_info += get_topic_tracking($f_id, $topic_row['topics'], $rowset, array($f_id => $topic_row['forum_mark_time'])); - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - foreach ($topic_forum_list as $f_id => $topic_row) - { - $topic_tracking_info += get_complete_topic_tracking($f_id, $topic_row['topics']); - } - } - - unset($topic_forum_list); - - if (!$s_display_active) - { - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $mark_time_forum = (!empty($forum_data['mark_time'])) ? $forum_data['mark_time'] : $user->data['user_lastmark']; - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - $mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark']; - } - } - - $s_type_switch = 0; - foreach ($topic_list as $topic_id) - { - $row = &$rowset[$topic_id]; - - $topic_forum_id = ($row['forum_id']) ? (int) $row['forum_id'] : $forum_id; - - // This will allow the style designer to output a different header - // or even separate the list of announcements from sticky and normal topics - $s_type_switch_test = ($row['topic_type'] == POST_ANNOUNCE || $row['topic_type'] == POST_GLOBAL) ? 1 : 0; - - // Replies - $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $topic_forum_id) - 1; - // Correction for case of unapproved topic visible to poster - if ($replies < 0) - { - $replies = 0; - } - - if ($row['topic_status'] == ITEM_MOVED) - { - $topic_id = $row['topic_moved_id']; - $unread_topic = false; - } - else - { - $unread_topic = (isset($topic_tracking_info[$topic_id]) && $row['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); - - // Generate all the URIs ... - $view_topic_url_params = 'f=' . $row['forum_id'] . '&t=' . $topic_id; - $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'])); - $topic_deleted = $row['topic_visibility'] == ITEM_DELETED; - - $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . "&t=$topic_id", true, $user->session_id) : ''; - $u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=deleted_topics&t=' . $topic_id, true, $user->session_id) : $u_mcp_queue; - - // Send vars to template - $topic_row = array( - 'FORUM_ID' => $row['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']), - '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']), - - 'REPLIES' => $replies, - 'VIEWS' => $row['topic_views'], - 'TOPIC_TITLE' => censor_text($row['topic_title']), - 'TOPIC_TYPE' => $topic_type, - 'FORUM_NAME' => (isset($row['forum_name'])) ? $row['forum_name'] : $forum_data['forum_name'], - - 'TOPIC_IMG_STYLE' => $folder_img, - 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'TOPIC_FOLDER_IMG_ALT' => $user->lang[$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'] : '', - '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']) : '', - 'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '', - - 'S_TOPIC_TYPE' => $row['topic_type'], - 'S_USER_POSTED' => (isset($row['topic_posted']) && $row['topic_posted']) ? true : false, - 'S_UNREAD_TOPIC' => $unread_topic, - 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_get('m_report', $row['forum_id'])) ? true : false, - 'S_TOPIC_UNAPPROVED' => $topic_unapproved, - 'S_POSTS_UNAPPROVED' => $posts_unapproved, - 'S_TOPIC_DELETED' => $topic_deleted, - 'S_HAS_POLL' => ($row['poll_start']) ? true : false, - 'S_POST_ANNOUNCE' => ($row['topic_type'] == POST_ANNOUNCE) ? true : false, - 'S_POST_GLOBAL' => ($row['topic_type'] == POST_GLOBAL) ? true : false, - 'S_POST_STICKY' => ($row['topic_type'] == POST_STICKY) ? true : false, - 'S_TOPIC_LOCKED' => ($row['topic_status'] == ITEM_LOCKED) ? true : false, - 'S_TOPIC_MOVED' => ($row['topic_status'] == ITEM_MOVED) ? true : false, - - 'U_NEWEST_POST' => $auth->acl_get('f_read', $forum_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&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 . '&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, - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), - 'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=reports&f=' . $row['forum_id'] . '&t=' . $topic_id, true, $user->session_id), - 'U_MCP_QUEUE' => $u_mcp_queue, - - 'S_TOPIC_TYPE_SWITCH' => ($s_type_switch == $s_type_switch_test) ? -1 : $s_type_switch_test, - ); - - /** - * Modify the topic data before it is assigned to the template - * - * @event core.viewforum_modify_topicrow - * @var array row Array with topic data - * @var array topic_row Template array with topic data - * @var bool s_type_switch Flag indicating if the topic type is [global] announcement - * @var bool s_type_switch_test Flag indicating if the test topic type is [global] announcement - * @since 3.1.0-a1 - * - * @changed 3.1.10-RC1 Added s_type_switch, s_type_switch_test - */ - $vars = array('row', 'topic_row', 's_type_switch', 's_type_switch_test'); - extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_topicrow', compact($vars))); - - $template->assign_block_vars('topicrow', $topic_row); - - $pagination->generate_template_pagination($view_topic_url, 'topicrow.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true); - - $s_type_switch = ($row['topic_type'] == POST_ANNOUNCE || $row['topic_type'] == POST_GLOBAL) ? 1 : 0; - - /** - * Event after the topic data has been assigned to the template - * - * @event core.viewforum_topic_row_after - * @var array row Array with the topic data - * @var array rowset Array with topics data (in topic_id => topic_data format) - * @var bool s_type_switch Flag indicating if the topic type is [global] announcement - * @var int topic_id The topic ID - * @var array topic_list Array with current viewforum page topic ids - * @var array topic_row Template array with topic data - * @since 3.1.3-RC1 - */ - $vars = array( - 'row', - 'rowset', - 's_type_switch', - 'topic_id', - 'topic_list', - 'topic_row', - ); - extract($phpbb_dispatcher->trigger_event('core.viewforum_topic_row_after', compact($vars))); - - if ($unread_topic) - { - $mark_forum_read = false; - } - - unset($rowset[$topic_id]); - } -} - -/** -* 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 && count($topic_list) && $mark_forum_read) -{ - update_forum_tracking_info($forum_id, $forum_data['forum_last_post_time'], false, $mark_time_forum); -} - -page_footer(); diff --git a/install/update/new/viewonline.php b/install/update/new/viewonline.php deleted file mode 100644 index 1b28750..0000000 --- a/install/update/new/viewonline.php +++ /dev/null @@ -1,522 +0,0 @@ - -* @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); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -include($phpbb_root_path . 'common.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup('memberlist'); - -// Get and set some variables -$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']); -$sort_key_sql = array('a' => 'u.username_clean', 'b' => 's.session_time', 'c' => 's.session_page'); - -// Sorting and order -if (!isset($sort_key_text[$sort_key])) -{ - $sort_key = 'b'; -} - -$order_by = $sort_key_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); - -// Whois requested -if ($mode == 'whois' && $auth->acl_get('a_') && $session_id) -{ - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $sql = 'SELECT u.user_id, u.username, u.user_type, s.session_ip - FROM ' . USERS_TABLE . ' u, ' . SESSIONS_TABLE . " s - WHERE s.session_id = '" . $db->sql_escape($session_id) . "' - AND u.user_id = s.session_user_id"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $template->assign_var('WHOIS', user_ipwhois($row['session_ip'])); - } - $db->sql_freeresult($result); - - // Output the page - page_header($user->lang['WHO_IS_ONLINE']); - - $template->set_filenames(array( - 'body' => 'viewonline_whois.html') - ); - make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - - page_footer(); -} - -$user->update_session_infos(); - -// Forum info -$sql_ary = array( - 'SELECT' => 'f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f.right_id', - 'FROM' => array( - FORUMS_TABLE => 'f', - ), - 'ORDER_BY' => 'f.left_id ASC', -); - -/** -* Modify the forum data SQL query for getting additional fields if needed -* -* @event core.viewonline_modify_forum_data_sql -* @var array sql_ary The SQL array -* @since 3.1.5-RC1 -*/ -$vars = array('sql_ary'); -extract($phpbb_dispatcher->trigger_event('core.viewonline_modify_forum_data_sql', compact($vars))); - -$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary), 600); -unset($sql_ary); - -$forum_data = array(); -while ($row = $db->sql_fetchrow($result)) -{ - $forum_data[$row['forum_id']] = $row; -} -$db->sql_freeresult($result); - -$guest_counter = 0; - -// Get number of online guests (if we do not display them) -if (!$show_guests) -{ - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $sql = 'SELECT COUNT(session_ip) as num_guests - FROM ( - SELECT DISTINCT session_ip - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . ANONYMOUS . ' - AND session_time >= ' . (time() - ($config['load_online_time'] * 60)) . - ')'; - break; - - default: - $sql = 'SELECT COUNT(DISTINCT session_ip) as num_guests - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . ANONYMOUS . ' - AND session_time >= ' . (time() - ($config['load_online_time'] * 60)); - break; - } - $result = $db->sql_query($sql); - $guest_counter = (int) $db->sql_fetchfield('num_guests'); - $db->sql_freeresult($result); -} - -// Get user list -$sql_ary = array( - 'SELECT' => 'u.user_id, u.username, u.username_clean, u.user_type, u.user_colour, s.session_id, s.session_time, s.session_page, s.session_ip, s.session_browser, s.session_viewonline, s.session_forum_id', - 'FROM' => array( - USERS_TABLE => 'u', - SESSIONS_TABLE => 's', - ), - 'WHERE' => 'u.user_id = s.session_user_id - AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) . - ((!$show_guests) ? ' AND s.session_user_id <> ' . ANONYMOUS : ''), - 'ORDER_BY' => $order_by, -); - -/** -* Modify the SQL query for getting the user data to display viewonline list -* -* @event core.viewonline_modify_sql -* @var array sql_ary The SQL array -* @var bool show_guests Do we display guests in the list -* @var int guest_counter Number of guests displayed -* @var array forum_data Array with forum data -* @since 3.1.0-a1 -* @changed 3.1.0-a2 Added vars guest_counter and forum_data -*/ -$vars = array('sql_ary', 'show_guests', 'guest_counter', 'forum_data'); -extract($phpbb_dispatcher->trigger_event('core.viewonline_modify_sql', compact($vars))); - -$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']])) - { - $view_online = $s_user_hidden = false; - $user_colour = ($row['user_colour']) ? ' style="color:#' . $row['user_colour'] . '" class="username-coloured"' : ''; - - $username_full = ($row['user_type'] != USER_IGNORE) ? get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']) : '' . $row['username'] . ''; - - if (!$row['session_viewonline']) - { - $view_online = ($auth->acl_get('u_viewonline') || $row['user_id'] === $user->data['user_id']) ? true : false; - $logged_hidden_online++; - - $username_full = '' . $username_full . ''; - $s_user_hidden = true; - } - else - { - $view_online = true; - $logged_visible_online++; - } - - $prev_id[$row['user_id']] = 1; - - if ($view_online) - { - $counter++; - } - - if (!$view_online || $counter > $start + $config['topics_per_page'] || $counter <= $start) - { - continue; - } - } - else if ($show_guests && $row['user_id'] == ANONYMOUS && !isset($prev_ip[$row['session_ip']])) - { - $prev_ip[$row['session_ip']] = 1; - $guest_counter++; - $counter++; - - if ($counter > $start + $config['topics_per_page'] || $counter <= $start) - { - continue; - } - - $s_user_hidden = false; - $username_full = get_username_string('full', $row['user_id'], $user->lang['GUEST']); - } - else - { - continue; - } - - $on_page = $viewonline_helper->get_user_page($row['session_page']); - - switch ($on_page[1]) - { - case 'index': - $location = $user->lang['INDEX']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case $phpbb_adm_relative_path . 'index': - $location = $user->lang['ACP']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case 'posting': - case 'viewforum': - case 'viewtopic': - $forum_id = $row['session_forum_id']; - - if ($forum_id && $auth->acl_get('f_list', $forum_id)) - { - $location = ''; - $location_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); - - if ($forum_data[$forum_id]['forum_type'] == FORUM_LINK) - { - $location = sprintf($user->lang['READING_LINK'], $forum_data[$forum_id]['forum_name']); - break; - } - - switch ($on_page[1]) - { - case 'posting': - preg_match('#mode=([a-z]+)#', $row['session_page'], $on_page); - $posting_mode = (!empty($on_page[1])) ? $on_page[1] : ''; - - switch ($posting_mode) - { - case 'reply': - case 'quote': - $location = sprintf($user->lang['REPLYING_MESSAGE'], $forum_data[$forum_id]['forum_name']); - break; - - default: - $location = sprintf($user->lang['POSTING_MESSAGE'], $forum_data[$forum_id]['forum_name']); - break; - } - break; - - case 'viewtopic': - $location = sprintf($user->lang['READING_TOPIC'], $forum_data[$forum_id]['forum_name']); - break; - - case 'viewforum': - $location = sprintf($user->lang['READING_FORUM'], $forum_data[$forum_id]['forum_name']); - break; - } - } - else - { - $location = $user->lang['INDEX']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - } - break; - - case 'search': - $location = $user->lang['SEARCHING_FORUMS']; - $location_url = append_sid("{$phpbb_root_path}search.$phpEx"); - break; - - case 'viewonline': - $location = $user->lang['VIEWING_ONLINE']; - $location_url = append_sid("{$phpbb_root_path}viewonline.$phpEx"); - break; - - case 'memberlist': - $location_url = append_sid("{$phpbb_root_path}memberlist.$phpEx"); - - if (strpos($row['session_page'], 'mode=viewprofile') !== false) - { - $location = $user->lang['VIEWING_MEMBER_PROFILE']; - } - else if (strpos($row['session_page'], 'mode=contactadmin') !== false) - { - $location = $user->lang['VIEWING_CONTACT_ADMIN']; - $location_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin'); - } - else - { - $location = $user->lang['VIEWING_MEMBERS']; - } - break; - - case 'mcp': - $location = $user->lang['VIEWING_MCP']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case 'ucp': - $location = $user->lang['VIEWING_UCP']; - - // Grab some common modules - $url_params = array( - 'mode=register' => 'VIEWING_REGISTER', - 'i=pm&mode=compose' => 'POSTING_PRIVATE_MESSAGE', - 'i=pm&' => 'VIEWING_PRIVATE_MESSAGES', - 'i=profile&' => 'CHANGING_PROFILE', - 'i=prefs&' => 'CHANGING_PREFERENCES', - ); - - foreach ($url_params as $param => $lang) - { - if (strpos($row['session_page'], $param) !== false) - { - $location = $user->lang[$lang]; - break; - } - } - - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case 'download/file': - $location = $user->lang['DOWNLOADING_FILE']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case 'report': - $location = $user->lang['REPORTING_POST']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - 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; - } - - /** - * Overwrite the location's name and URL, which are displayed in the list - * - * @event core.viewonline_overwrite_location - * @var array on_page File name and query string - * @var array row Array with the users sql row - * @var string location Page name to displayed in the list - * @var string location_url Page url to displayed in the list - * @var array forum_data Array with forum data - * @since 3.1.0-a1 - * @changed 3.1.0-a2 Added var forum_data - */ - $vars = array('on_page', 'row', 'location', 'location_url', 'forum_data'); - extract($phpbb_dispatcher->trigger_event('core.viewonline_overwrite_location', compact($vars))); - - $template_row = array( - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => $row['user_colour'], - 'USERNAME_FULL' => $username_full, - 'LASTUPDATE' => $user->format_date($row['session_time']), - 'FORUM_LOCATION' => $location, - 'USER_IP' => ($auth->acl_get('a_')) ? (($mode == 'lookup' && $session_id == $row['session_id']) ? gethostbyaddr($row['session_ip']) : $row['session_ip']) : '', - 'USER_BROWSER' => ($auth->acl_get('a_user')) ? $row['session_browser'] : '', - - 'U_USER_PROFILE' => ($row['user_type'] != USER_IGNORE) ? get_username_string('profile', $row['user_id'], '') : '', - 'U_USER_IP' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'mode=lookup' . (($mode != 'lookup' || $row['session_id'] != $session_id) ? '&s=' . $row['session_id'] : '') . "&sg=$show_guests&start=$start&sk=$sort_key&sd=$sort_dir"), - 'U_WHOIS' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'mode=whois&s=' . $row['session_id']), - 'U_FORUM_LOCATION' => $location_url, - - 'S_USER_HIDDEN' => $s_user_hidden, - 'S_GUEST' => ($row['user_id'] == ANONYMOUS) ? true : false, - 'S_USER_TYPE' => $row['user_type'], - ); - - /** - * Modify viewonline template data before it is displayed in the list - * - * @event core.viewonline_modify_user_row - * @var array on_page File name and query string - * @var array row Array with the users sql row - * @var array forum_data Array with forum data - * @var array template_row Array with template variables for the user row - * @since 3.1.0-RC4 - */ - $vars = array('on_page', 'row', 'forum_data', 'template_row'); - extract($phpbb_dispatcher->trigger_event('core.viewonline_modify_user_row', compact($vars))); - - $template->assign_block_vars('user_row', $template_row); -} -$db->sql_freeresult($result); -unset($prev_id, $prev_ip); - -$order_legend = ($config['legend_sort_groupname']) ? 'group_name' : 'group_legend'; -// Grab group details for legend display -if ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) -{ - $sql = 'SELECT group_id, group_name, group_colour, group_type, group_legend - FROM ' . GROUPS_TABLE . ' - WHERE group_legend > 0 - ORDER BY ' . $order_legend . ' ASC'; -} -else -{ - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, g.group_legend - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE g.group_legend > 0 - AND (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ') - ORDER BY g.' . $order_legend . ' ASC'; -} -$result = $db->sql_query($sql); - -$legend = ''; -while ($row = $db->sql_fetchrow($result)) -{ - if ($row['group_name'] == 'BOTS') - { - $legend .= (($legend != '') ? ', ' : '') . '' . $user->lang['G_BOTS'] . ''; - } - else - { - $legend .= (($legend != '') ? ', ' : '') . '' . $group_helper->get_name($row['group_name']) . ''; - } -} -$db->sql_freeresult($result); - -// Refreshing the page every 60 seconds... -meta_refresh(60, append_sid("{$phpbb_root_path}viewonline.$phpEx", "sg=$show_guests&sk=$sort_key&sd=$sort_dir&start=$start")); - -$start = $pagination->validate_start($start, $config['topics_per_page'], $counter); -$base_url = append_sid("{$phpbb_root_path}viewonline.$phpEx", "sg=$show_guests&sk=$sort_key&sd=$sort_dir"); -$pagination->generate_template_pagination($base_url, 'pagination', 'start', $counter, $config['topics_per_page'], $start); - -$template->assign_block_vars('navlinks', array( - 'BREADCRUMB_NAME' => $user->lang('WHO_IS_ONLINE'), - 'U_BREADCRUMB' => append_sid("{$phpbb_root_path}viewonline.$phpEx"), -)); - -// Send data to template -$template->assign_vars(array( - 'TOTAL_REGISTERED_USERS_ONLINE' => $user->lang('REG_USERS_ONLINE', (int) $logged_visible_online, $user->lang('HIDDEN_USERS_ONLINE', (int) $logged_hidden_online)), - 'TOTAL_GUEST_USERS_ONLINE' => $user->lang('GUEST_USERS_ONLINE', (int) $guest_counter), - 'LEGEND' => $legend, - - 'U_SORT_USERNAME' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'sk=a&sd=' . (($sort_key == 'a' && $sort_dir == 'a') ? 'd' : 'a') . '&sg=' . ((int) $show_guests)), - 'U_SORT_UPDATED' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'sk=b&sd=' . (($sort_key == 'b' && $sort_dir == 'a') ? 'd' : 'a') . '&sg=' . ((int) $show_guests)), - 'U_SORT_LOCATION' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'sk=c&sd=' . (($sort_key == 'c' && $sort_dir == 'a') ? 'd' : 'a') . '&sg=' . ((int) $show_guests)), - - 'U_SWITCH_GUEST_DISPLAY' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'sg=' . ((int) !$show_guests)), - 'L_SWITCH_GUEST_DISPLAY' => ($show_guests) ? $user->lang['HIDE_GUESTS'] : $user->lang['DISPLAY_GUESTS'], - 'S_SWITCH_GUEST_DISPLAY' => ($config['load_online_guests']) ? true : false, - 'S_VIEWONLINE' => true, -)); - -// We do not need to load the who is online box here. ;) -$config['load_online'] = false; - -// Output the page -page_header($user->lang['WHO_IS_ONLINE']); - -$template->set_filenames(array( - 'body' => 'viewonline_body.html') -); -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - -page_footer(); diff --git a/install/update/new/viewtopic.php b/install/update/new/viewtopic.php deleted file mode 100644 index df241a5..0000000 --- a/install/update/new/viewtopic.php +++ /dev/null @@ -1,2427 +0,0 @@ - -* @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); -$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); -include($phpbb_root_path . 'includes/bbcode.' . $phpEx); -include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); - -// Initial var setup -$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 = (count($voted_id) > 1) ? array_unique($voted_id) : $voted_id; - - -$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->variable('st', $default_sort_days); -$sort_key = $request->variable('sk', $default_sort_key); -$sort_dir = $request->variable('sd', $default_sort_dir); - -$update = $request->variable('update', false); - -/* @var $pagination \phpbb\pagination */ -$pagination = $phpbb_container->get('pagination'); - -$s_can_vote = false; -/** -* @todo normalize? -*/ -$hilit_words = $request->variable('hilit', '', true); - -// Do we have a topic or post id? -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 -if ($view && !$post_id) -{ - if (!$forum_id) - { - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . " - WHERE topic_id = $topic_id"; - $result = $db->sql_query($sql); - $forum_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - if (!$forum_id) - { - trigger_error('NO_TOPIC'); - } - } - - if ($view == 'unread') - { - // Get topic tracking info - $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id); - $topic_last_read = (isset($topic_tracking_info[$topic_id])) ? $topic_tracking_info[$topic_id] : 0; - - $sql = 'SELECT post_id, topic_id, forum_id - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . " - AND post_time > $topic_last_read - AND forum_id = $forum_id - ORDER BY post_time ASC, post_id ASC"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $sql = 'SELECT topic_last_post_id as post_id, topic_id, forum_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - if (!$row) - { - // Setup user environment so we can process lang string - $user->setup('viewtopic'); - - trigger_error('NO_TOPIC'); - } - - $post_id = $row['post_id']; - $topic_id = $row['topic_id']; - } - else if ($view == 'next' || $view == 'previous') - { - $sql_condition = ($view == 'next') ? '>' : '<'; - $sql_ordering = ($view == 'next') ? 'ASC' : 'DESC'; - - $sql = 'SELECT forum_id, topic_last_post_time - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $user->setup('viewtopic'); - // OK, the topic doesn't exist. This error message is not helpful, but technically correct. - trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS'); - } - else - { - $sql = 'SELECT topic_id, forum_id - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = ' . $row['forum_id'] . " - AND topic_moved_id = 0 - AND topic_last_post_time $sql_condition {$row['topic_last_post_time']} - AND " . $phpbb_content_visibility->get_visibility_sql('topic', $row['forum_id']) . " - ORDER BY topic_last_post_time $sql_ordering, topic_last_post_id $sql_ordering"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $sql = 'SELECT forum_style - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $forum_style = (int) $db->sql_fetchfield('forum_style'); - $db->sql_freeresult($result); - - $user->setup('viewtopic', $forum_style); - trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS'); - } - else - { - $topic_id = $row['topic_id']; - $forum_id = $row['forum_id']; - } - } - } - - if (isset($row) && $row['forum_id']) - { - $forum_id = $row['forum_id']; - } -} - -// This rather complex gaggle of code handles querying for topics but -// also allows for direct linking to a post (and the calculation of which -// page the post is on and the correct display of viewtopic) -$sql_array = array( - 'SELECT' => 't.*, f.*', - - 'FROM' => array(FORUMS_TABLE => 'f'), -); - -// The FROM-Order is quite important here, else t.* columns can not be correctly bound. -if ($post_id) -{ - $sql_array['SELECT'] .= ', p.post_visibility, p.post_time, p.post_id'; - $sql_array['FROM'][POSTS_TABLE] = 'p'; -} - -// Topics table need to be the last in the chain -$sql_array['FROM'][TOPICS_TABLE] = 't'; - -if ($user->data['is_registered']) -{ - $sql_array['SELECT'] .= ', tw.notify_status'; - $sql_array['LEFT_JOIN'] = array(); - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_WATCH_TABLE => 'tw'), - 'ON' => 'tw.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tw.topic_id' - ); - - if ($config['allow_bookmarks']) - { - $sql_array['SELECT'] .= ', bm.topic_id as bookmarked'; - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(BOOKMARKS_TABLE => 'bm'), - 'ON' => 'bm.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = bm.topic_id' - ); - } - - if ($config['load_db_lastread']) - { - $sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time'; - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_TRACK_TABLE => 'tt'), - 'ON' => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id' - ); - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(FORUMS_TRACK_TABLE => 'ft'), - 'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id' - ); - } -} - -if (!$post_id) -{ - $sql_array['WHERE'] = "t.topic_id = $topic_id"; -} -else -{ - $sql_array['WHERE'] = "p.post_id = $post_id AND t.topic_id = p.topic_id"; -} - -$sql_array['WHERE'] .= ' AND f.forum_id = t.forum_id'; - -$sql = $db->sql_build_query('SELECT', $sql_array); -$result = $db->sql_query($sql); -$topic_data = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -// link to unapproved post or incorrect link -if (!$topic_data) -{ - // If post_id was submitted, we try at least to display the topic as a last resort... - if ($post_id && $topic_id) - { - redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&f=$forum_id" : ''))); - } - - trigger_error('NO_TOPIC'); -} - -$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 (!$phpbb_content_visibility->is_visible('topic', $forum_id, $topic_data)) -{ - trigger_error('NO_TOPIC'); -} - -// This is for determining where we are (page) -if ($post_id) -{ - // are we where we are supposed to be? - if (($topic_data['post_visibility'] == ITEM_UNAPPROVED || $topic_data['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $topic_data['forum_id'])) - { - // If post_id was submitted, we try at least to display the topic as a last resort... - if ($topic_id) - { - redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&f=$forum_id" : ''))); - } - - trigger_error('NO_TOPIC'); - } - if ($post_id == $topic_data['topic_first_post_id'] || $post_id == $topic_data['topic_last_post_id']) - { - $check_sort = ($post_id == $topic_data['topic_first_post_id']) ? 'd' : 'a'; - - if ($sort_dir == $check_sort) - { - $topic_data['prev_posts'] = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1; - } - else - { - $topic_data['prev_posts'] = 0; - } - } - else - { - $sql = 'SELECT COUNT(p.post_id) AS prev_posts - FROM ' . POSTS_TABLE . " p - WHERE p.topic_id = {$topic_data['topic_id']} - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.'); - - if ($sort_dir == 'd') - { - $sql .= " AND (p.post_time > {$topic_data['post_time']} OR (p.post_time = {$topic_data['post_time']} AND p.post_id >= {$topic_data['post_id']}))"; - } - else - { - $sql .= " AND (p.post_time < {$topic_data['post_time']} OR (p.post_time = {$topic_data['post_time']} AND p.post_id <= {$topic_data['post_id']}))"; - } - - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $topic_data['prev_posts'] = $row['prev_posts'] - 1; - } -} - -$topic_id = (int) $topic_data['topic_id']; -$topic_replies = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1; - -// 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 - WHERE topic_id = ' . $topic_id; - $db->sql_query($sql); - - $topic_data['topic_type'] = POST_NORMAL; - $topic_data['topic_time_limit'] = 0; -} - -// 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; - -/** -* Event to apply extra permissions and to override original phpBB's f_read permission and forum password check -* on viewtopic access -* -* @event core.viewtopic_before_f_read_check -* @var int forum_id The forum id from where the topic belongs -* @var int topic_id The id of the topic the user tries to access -* @var int post_id The id of the post the user tries to start viewing at. -* It may be 0 for none given. -* @var array topic_data All the information from the topic and forum tables for this topic -* It includes posts information if post_id is not 0 -* @var bool overrides_f_read_check Set true to remove f_read check afterwards -* @var bool overrides_forum_password_check Set true to remove forum_password check afterwards -* @var array topic_tracking_info Information upon calling get_topic_tracking() -* Set it to NULL to allow auto-filling later. -* Set it to an array to override original data. -* @since 3.1.3-RC1 -*/ -$vars = array( - 'forum_id', - 'topic_id', - 'post_id', - 'topic_data', - 'overrides_f_read_check', - 'overrides_forum_password_check', - 'topic_tracking_info', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_before_f_read_check', compact($vars))); - -// Start auth check -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'); - } - - login_box('', $user->lang['LOGIN_VIEWFORUM']); -} - -// Forum is passworded ... check whether access has been granted to this -// user this session, if not show login box -if (!$overrides_forum_password_check && $topic_data['forum_password']) -{ - login_forum_box($topic_data); -} - -// Redirect to login upon emailed notification links if user is not logged in. -if (isset($_GET['e']) && $user->data['user_id'] == ANONYMOUS) -{ - login_box(build_url('e') . '#unread', $user->lang['LOGIN_NOTIFY_TOPIC']); -} - -// What is start equal to? -if ($post_id) -{ - $start = floor(($topic_data['prev_posts']) / $config['posts_per_page']) * $config['posts_per_page']; -} - -// Get topic tracking info -if (!isset($topic_tracking_info)) -{ - $topic_tracking_info = array(); - - // Get topic tracking info - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $tmp_topic_data = array($topic_id => $topic_data); - $topic_tracking_info = get_topic_tracking($forum_id, $topic_id, $tmp_topic_data, array($forum_id => $topic_data['forum_mark_time'])); - unset($tmp_topic_data); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id); - } -} - -// Post ordering options -$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' => array('u.username_clean', 'p.post_id'), 't' => array('p.post_time', 'p.post_id'), 's' => array('p.post_subject', 'p.post_id')); -$join_user_sql = array('a' => true, 't' => false, 's' => false); - -$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - -/** -* 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 -// requested anything different -if ($sort_days) -{ - $min_post_time = time() - ($sort_days * 86400); - - $sql = 'SELECT COUNT(post_id) AS num_posts - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND post_time >= $min_post_time - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id); - $result = $db->sql_query($sql); - $total_posts = (int) $db->sql_fetchfield('num_posts'); - $db->sql_freeresult($result); - - $limit_posts_time = "AND p.post_time >= $min_post_time "; - - if (isset($_POST['sort'])) - { - $start = 0; - } -} -else -{ - $total_posts = $topic_replies + 1; - $limit_posts_time = ''; -} - -// Was a highlight request part of the URI? -$highlight_match = $highlight = ''; -if ($hilit_words) -{ - $highlight_match = phpbb_clean_search_string($hilit_words); - $highlight = urlencode($highlight_match); - $highlight_match = str_replace('\*', '\w+?', preg_quote($highlight_match, '#')); - $highlight_match = preg_replace('#(?<=^|\s)\\\\w\*\?(?=\s|$)#', '\w+?', $highlight_match); - $highlight_match = str_replace(' ', '|', $highlight_match); -} - -// Make sure $start is set to the last page if it exceeds the amount -$start = $pagination->validate_start($start, $config['posts_per_page'], $total_posts); - -// General Viewtopic URL for return links -$viewtopic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($highlight_match) ? "&hilit=$highlight" : '')); - -// Are we watching this topic? -$s_watching_topic = array( - 'link' => '', - 'link_toggle' => '', - 'title' => '', - 'title_toggle' => '', - 'is_watching' => false, -); - -if ($config['allow_topic_notify']) -{ - $notify_status = (isset($topic_data['notify_status'])) ? $topic_data['notify_status'] : null; - watch_topic_forum('topic', $s_watching_topic, $user->data['user_id'], $forum_id, $topic_id, $notify_status, $start, $topic_data['topic_title']); - - // Reset forum notification if forum notify is set - if ($config['allow_forum_notify'] && $auth->acl_get('f_subscribe', $forum_id)) - { - $s_watching_forum = $s_watching_topic; - watch_topic_forum('forum', $s_watching_forum, $user->data['user_id'], $forum_id, 0); - } -} - -/** -* Event to modify highlight. -* -* @event core.viewtopic_highlight_modify -* @var string highlight String to be highlighted -* @var string highlight_match Highlight string to be used in preg_replace -* @var array topic_data Topic data -* @var int start Pagination start -* @var int total_posts Number of posts -* @var string viewtopic_url Current viewtopic URL -* @since 3.1.11-RC1 -*/ -$vars = array( - 'highlight', - 'highlight_match', - 'topic_data', - 'start', - 'total_posts', - 'viewtopic_url', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_highlight_modify', compact($vars))); - -// Bookmarks -if ($config['allow_bookmarks'] && $user->data['is_registered'] && $request->variable('bookmark', 0)) -{ - if (check_link_hash($request->variable('hash', ''), "topic_$topic_id")) - { - if (!$topic_data['bookmarked']) - { - $sql = 'INSERT INTO ' . BOOKMARKS_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'user_id' => $user->data['user_id'], - 'topic_id' => $topic_id, - )); - $db->sql_query($sql); - } - else - { - $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND topic_id = $topic_id"; - $db->sql_query($sql); - } - $message = (($topic_data['bookmarked']) ? $user->lang['BOOKMARK_REMOVED'] : $user->lang['BOOKMARK_ADDED']); - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_TOPIC', '', ''); - } - } - else - { - $message = $user->lang['BOOKMARK_ERR']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_TOPIC', '', ''); - } - } - meta_refresh(3, $viewtopic_url); - - trigger_error($message); -} - -// Grab ranks -$ranks = $cache->obtain_ranks(); - -// Grab icons -$icons = $cache->obtain_icons(); - -// Grab extensions -$extensions = array(); -if ($topic_data['topic_attachment']) -{ - $extensions = $cache->obtain_attach_extensions($forum_id); -} - -// Forum rules listing -$s_forum_rules = ''; -gen_forum_auth_level('topic', $forum_id, $topic_data['forum_status']); - -// Quick mod tools -$allow_change_type = ($auth->acl_get('m_', $forum_id) || ($user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'])) ? true : false; - -$s_quickmod_action = append_sid( - "{$phpbb_root_path}mcp.$phpEx", - array( - 'f' => $forum_id, - 't' => $topic_id, - 'start' => $start, - 'quickmod' => 1, - 'redirect' => urlencode(str_replace('&', '&', $viewtopic_url)), - ), - true, - $user->session_id -); - -$quickmod_array = array( -// 'key' => array('LANG_KEY', $userHasPermissions), - - 'lock' => array('LOCK_TOPIC', ($topic_data['topic_status'] == ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster']))), - 'unlock' => array('UNLOCK_TOPIC', ($topic_data['topic_status'] != ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id))), - 'delete_topic' => array('DELETE_TOPIC', ($auth->acl_get('m_delete', $forum_id) || (($topic_data['topic_visibility'] != ITEM_DELETED) && $auth->acl_get('m_softdelete', $forum_id)))), - 'restore_topic' => array('RESTORE_TOPIC', (($topic_data['topic_visibility'] == ITEM_DELETED) && $auth->acl_get('m_approve', $forum_id))), - 'move' => array('MOVE_TOPIC', $auth->acl_get('m_move', $forum_id) && $topic_data['topic_status'] != ITEM_MOVED), - 'split' => array('SPLIT_TOPIC', $auth->acl_get('m_split', $forum_id)), - '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', '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_global', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL)), - 'topic_logs' => array('VIEW_TOPIC_LOGS', $auth->acl_get('m_', $forum_id)), -); - -/** -* Event to modify data in the quickmod_array before it gets sent to the -* phpbb_add_quickmod_option function. -* -* @event core.viewtopic_add_quickmod_option_before -* @var int forum_id Forum ID -* @var int post_id Post ID -* @var array quickmod_array Array with quick moderation options data -* @var array topic_data Array with topic data -* @var int topic_id Topic ID -* @var array topic_tracking_info Array with topic tracking data -* @var string viewtopic_url URL to the topic page -* @var bool allow_change_type Topic change permissions check -* @since 3.1.9-RC1 -*/ -$vars = array( - 'forum_id', - 'post_id', - 'quickmod_array', - 'topic_data', - 'topic_id', - 'topic_tracking_info', - 'viewtopic_url', - 'allow_change_type', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_add_quickmod_option_before', compact($vars))); - -foreach ($quickmod_array as $option => $qm_ary) -{ - if (!empty($qm_ary[1])) - { - phpbb_add_quickmod_option($s_quickmod_action, $option, $qm_ary[0]); - } -} - -// Navigation links -generate_forum_nav($topic_data); - -// Forum Rules -generate_forum_rules($topic_data); - -// Moderators -$forum_moderators = array(); -if ($config['load_moderators']) -{ - get_moderators($forum_moderators, $forum_id); -} - -// This is only used for print view so ... -$server_path = (!$view) ? $phpbb_root_path : generate_board_url() . '/'; - -// Replace naughty words in title -$topic_data['topic_title'] = censor_text($topic_data['topic_title']); - -$s_search_hidden_fields = array( - 't' => $topic_id, - 'sf' => 'msgonly', -); -if ($_SID) -{ - $s_search_hidden_fields['sid'] = $_SID; -} - -if (!empty($_EXTRA_URL)) -{ - foreach ($_EXTRA_URL as $url_param) - { - $url_param = explode('=', $url_param, 2); - $s_search_hidden_fields[$url_param[0]] = $url_param[1]; - } -} - -// If we've got a hightlight set pass it on to pagination. -$base_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($highlight_match) ? "&hilit=$highlight" : '')); - -/** -* Event to modify data before template variables are being assigned -* -* @event core.viewtopic_assign_template_vars_before -* @var string base_url URL to be passed to generate pagination -* @var int forum_id Forum ID -* @var int post_id Post ID -* @var array quickmod_array Array with quick moderation options data -* @var int start Pagination information -* @var array topic_data Array with topic data -* @var int topic_id Topic ID -* @var array topic_tracking_info Array with topic tracking data -* @var int total_posts Topic total posts count -* @var string viewtopic_url URL to the topic page -* @since 3.1.0-RC4 -* @changed 3.1.2-RC1 Added viewtopic_url -*/ -$vars = array( - 'base_url', - 'forum_id', - 'post_id', - 'quickmod_array', - 'start', - 'topic_data', - 'topic_id', - 'topic_tracking_info', - 'total_posts', - 'viewtopic_url', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_assign_template_vars_before', compact($vars))); - -$pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_posts, $config['posts_per_page'], $start); - -// Send vars to template -$template->assign_vars(array( - 'FORUM_ID' => $forum_id, - 'FORUM_NAME' => $topic_data['forum_name'], - 'FORUM_DESC' => generate_text_for_display($topic_data['forum_desc'], $topic_data['forum_desc_uid'], $topic_data['forum_desc_bitfield'], $topic_data['forum_desc_options']), - 'TOPIC_ID' => $topic_id, - 'TOPIC_TITLE' => $topic_data['topic_title'], - 'TOPIC_POSTER' => $topic_data['topic_poster'], - - 'TOPIC_AUTHOR_FULL' => get_username_string('full', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']), - 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']), - 'TOPIC_AUTHOR' => get_username_string('username', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']), - - '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&mode=topic_view&f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . ((strlen($u_sort_param)) ? "&$u_sort_param" : ''), true, $user->session_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'), - 'REPLY_IMG' => ($topic_data['forum_status'] == ITEM_LOCKED || $topic_data['topic_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'TOPIC_LOCKED') : $user->img('button_topic_reply', 'REPLY_TO_TOPIC'), - 'EDIT_IMG' => $user->img('icon_post_edit', 'EDIT_POST'), - 'DELETE_IMG' => $user->img('icon_post_delete', 'DELETE_POST'), - 'DELETED_IMG' => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'), - 'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'), - 'PROFILE_IMG' => $user->img('icon_user_profile', 'READ_PROFILE'), - 'SEARCH_IMG' => $user->img('icon_user_search', 'SEARCH_USER_POSTS'), - 'PM_IMG' => $user->img('icon_contact_pm', 'SEND_PRIVATE_MESSAGE'), - 'EMAIL_IMG' => $user->img('icon_contact_email', 'SEND_EMAIL'), - 'JABBER_IMG' => $user->img('icon_contact_jabber', 'JABBER') , - 'REPORT_IMG' => $user->img('icon_post_report', 'REPORT_POST'), - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'), - 'WARN_IMG' => $user->img('icon_user_warn', 'WARN_USER'), - - 'S_IS_LOCKED' => ($topic_data['topic_status'] == ITEM_UNLOCKED && $topic_data['forum_status'] == ITEM_UNLOCKED) ? false : true, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - '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&t=$topic_id" . (($start == 0) ? '' : "&start=$start")), - 'S_MOD_ACTION' => $s_quickmod_action, - - 'L_RETURN_TO_FORUM' => $user->lang('RETURN_TO', $topic_data['forum_name']), - 'S_VIEWTOPIC' => true, - 'S_UNREAD_VIEW' => $view == 'unread', - '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_DISPLAY_POST_INFO' => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false, - 'S_DISPLAY_REPLY_INFO' => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false, - 'S_ENABLE_FEEDS_TOPIC' => ($config['feed_topic'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $topic_data['forum_options'])) ? true : false, - - 'U_TOPIC' => "{$server_path}viewtopic.$phpEx?f=$forum_id&t=$topic_id", - 'U_FORUM' => $server_path, - 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . (strlen($u_sort_param) ? "&$u_sort_param" : '')), - 'U_CANONICAL' => generate_board_url() . '/' . append_sid("viewtopic.$phpEx", "t=$topic_id" . (($start) ? "&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&t=$topic_id&view=previous"), - 'U_VIEW_NEWER_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=next"), - 'U_PRINT_TOPIC' => ($auth->acl_get('f_print', $forum_id)) ? $viewtopic_url . '&view=print' : '', - 'U_EMAIL_TOPIC' => ($auth->acl_get('f_email', $forum_id) && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&t=$topic_id") : '', - - 'U_WATCH_TOPIC' => $s_watching_topic['link'], - 'U_WATCH_TOPIC_TOGGLE' => $s_watching_topic['link_toggle'], - 'S_WATCH_TOPIC_TITLE' => $s_watching_topic['title'], - 'S_WATCH_TOPIC_TOGGLE' => $s_watching_topic['title_toggle'], - 'S_WATCHING_TOPIC' => $s_watching_topic['is_watching'], - - 'U_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks']) ? $viewtopic_url . '&bookmark=1&hash=' . generate_link_hash("topic_$topic_id") : '', - 'S_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], - 'S_BOOKMARK_TOGGLE' => (!$user->data['is_registered'] || !$config['allow_bookmarks'] || !$topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], - 'S_BOOKMARKED_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? true : false, - - 'U_POST_NEW_TOPIC' => ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=post&f=$forum_id") : '', - 'U_POST_REPLY_TOPIC' => ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&f=$forum_id&t=$topic_id") : '', - 'U_BUMP_TOPIC' => (bump_topic_allowed($forum_id, $topic_data['topic_bumped'], $topic_data['topic_last_post_time'], $topic_data['topic_poster'], $topic_data['topic_last_poster_id'])) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=bump&f=$forum_id&t=$topic_id&hash=" . generate_link_hash("topic_$topic_id")) : '') -); - -// Does this topic contain a poll? -if (!empty($topic_data['poll_start'])) -{ - $sql = 'SELECT o.*, p.bbcode_bitfield, p.bbcode_uid - FROM ' . POLL_OPTIONS_TABLE . ' o, ' . POSTS_TABLE . " p - WHERE o.topic_id = $topic_id - AND p.post_id = {$topic_data['topic_first_post_id']} - AND p.topic_id = o.topic_id - ORDER BY o.poll_option_id"; - $result = $db->sql_query($sql); - - $poll_info = $vote_counts = array(); - while ($row = $db->sql_fetchrow($result)) - { - $poll_info[] = $row; - $option_id = (int) $row['poll_option_id']; - $vote_counts[$option_id] = (int) $row['poll_option_total']; - } - $db->sql_freeresult($result); - - $cur_voted_id = array(); - if ($user->data['is_registered']) - { - $sql = 'SELECT poll_option_id - FROM ' . POLL_VOTES_TABLE . ' - WHERE topic_id = ' . $topic_id . ' - AND vote_user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $cur_voted_id[] = $row['poll_option_id']; - } - $db->sql_freeresult($result); - } - else - { - // Cookie based guest tracking ... I don't like this but hum ho - // it's oft requested. This relies on "nice" users who don't feel - // the need to delete cookies to mess with results. - if ($request->is_set($config['cookie_name'] . '_poll_' . $topic_id, \phpbb\request\request_interface::COOKIE)) - { - $cur_voted_id = explode(',', $request->variable($config['cookie_name'] . '_poll_' . $topic_id, '', true, \phpbb\request\request_interface::COOKIE)); - $cur_voted_id = array_map('intval', $cur_voted_id); - } - } - - // Can not vote at all if no vote permission - $s_can_vote = ($auth->acl_get('f_vote', $forum_id) && - (($topic_data['poll_length'] != 0 && $topic_data['poll_start'] + $topic_data['poll_length'] > time()) || $topic_data['poll_length'] == 0) && - $topic_data['topic_status'] != ITEM_LOCKED && - $topic_data['forum_status'] != ITEM_LOCKED && - (!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 && count($cur_voted_id)) || $view == 'viewpoll') ? true : false; - - /** - * Event to manipulate the poll data - * - * @event core.viewtopic_modify_poll_data - * @var array cur_voted_id Array with options' IDs current user has voted for - * @var int forum_id The topic's forum id - * @var array poll_info Array with the poll information - * @var bool s_can_vote Flag indicating if a user can vote - * @var bool s_display_results Flag indicating if results or poll options should be displayed - * @var int topic_id The id of the topic the user tries to access - * @var array topic_data All the information from the topic and forum tables for this topic - * @var string viewtopic_url URL to the topic page - * @var array vote_counts Array with the vote counts for every poll option - * @var array voted_id Array with updated options' IDs current user is voting for - * @since 3.1.5-RC1 - */ - $vars = array( - 'cur_voted_id', - 'forum_id', - 'poll_info', - 's_can_vote', - 's_display_results', - 'topic_id', - 'topic_data', - 'viewtopic_url', - 'vote_counts', - 'voted_id', - ); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_data', compact($vars))); - - if ($update && $s_can_vote) - { - - 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&t=$topic_id" . (($start == 0) ? '' : "&start=$start")); - - meta_refresh(5, $redirect_url); - if (!count($voted_id)) - { - $message = 'NO_VOTE_OPTION'; - } - else if (count($voted_id) > $topic_data['poll_max_options']) - { - $message = 'TOO_MANY_VOTE_OPTIONS'; - } - else if (in_array(VOTE_CONVERTED, $cur_voted_id)) - { - $message = 'VOTE_CONVERTED'; - } - else - { - $message = 'FORM_INVALID'; - } - - $message = $user->lang[$message] . '

' . sprintf($user->lang['RETURN_TOPIC'], '', ''); - trigger_error($message); - } - - foreach ($voted_id as $option) - { - if (in_array($option, $cur_voted_id)) - { - continue; - } - - $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . ' - SET poll_option_total = poll_option_total + 1 - WHERE poll_option_id = ' . (int) $option . ' - AND topic_id = ' . (int) $topic_id; - $db->sql_query($sql); - - $vote_counts[$option]++; - - if ($user->data['is_registered']) - { - $sql_ary = array( - 'topic_id' => (int) $topic_id, - 'poll_option_id' => (int) $option, - 'vote_user_id' => (int) $user->data['user_id'], - 'vote_user_ip' => (string) $user->ip, - ); - - $sql = 'INSERT INTO ' . POLL_VOTES_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - } - } - - foreach ($cur_voted_id as $option) - { - if (!in_array($option, $voted_id)) - { - $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . ' - SET poll_option_total = poll_option_total - 1 - WHERE poll_option_id = ' . (int) $option . ' - AND topic_id = ' . (int) $topic_id; - $db->sql_query($sql); - - $vote_counts[$option]--; - - if ($user->data['is_registered']) - { - $sql = 'DELETE FROM ' . POLL_VOTES_TABLE . ' - WHERE topic_id = ' . (int) $topic_id . ' - AND poll_option_id = ' . (int) $option . ' - AND vote_user_id = ' . (int) $user->data['user_id']; - $db->sql_query($sql); - } - } - } - - if ($user->data['user_id'] == ANONYMOUS && !$user->data['is_bot']) - { - $user->set_cookie('poll_' . $topic_id, implode(',', $voted_id), time() + 31536000); - } - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET poll_last_vote = ' . time() . " - WHERE topic_id = $topic_id"; - //, topic_last_post_time = ' . time() . " -- for bumping topics with new votes, ignore for now - $db->sql_query($sql); - - $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start")); - $message = $user->lang['VOTE_SUBMITTED'] . '

' . sprintf($user->lang['RETURN_TOPIC'], '', ''); - - if ($request->is_ajax()) - { - // Filter out invalid options - $valid_user_votes = array_intersect(array_keys($vote_counts), $voted_id); - - $data = array( - 'NO_VOTES' => $user->lang['NO_VOTES'], - 'success' => true, - 'user_votes' => array_flip($valid_user_votes), - 'vote_counts' => $vote_counts, - 'total_votes' => array_sum($vote_counts), - '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); - } - - meta_refresh(5, $redirect_url); - trigger_error($message); - } - - $poll_total = 0; - $poll_most = 0; - foreach ($poll_info as $poll_option) - { - $poll_total += $poll_option['poll_option_total']; - $poll_most = ($poll_option['poll_option_total'] >= $poll_most) ? $poll_option['poll_option_total'] : $poll_most; - } - - $parse_flags = ($poll_info[0]['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - - 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); - } - - $topic_data['poll_title'] = generate_text_for_display($topic_data['poll_title'], $poll_info[0]['bbcode_uid'], $poll_info[0]['bbcode_bitfield'], $parse_flags, true); - - $poll_template_data = $poll_options_template_data = array(); - foreach ($poll_info as $poll_option) - { - $option_pct = ($poll_total > 0) ? $poll_option['poll_option_total'] / $poll_total : 0; - $option_pct_txt = sprintf("%.1d%%", round($option_pct * 100)); - $option_pct_rel = ($poll_most > 0) ? $poll_option['poll_option_total'] / $poll_most : 0; - $option_pct_rel_txt = sprintf("%.1d%%", round($option_pct_rel * 100)); - $option_most_votes = ($poll_option['poll_option_total'] > 0 && $poll_option['poll_option_total'] == $poll_most) ? true : false; - - $poll_options_template_data[] = array( - 'POLL_OPTION_ID' => $poll_option['poll_option_id'], - 'POLL_OPTION_CAPTION' => $poll_option['poll_option_text'], - 'POLL_OPTION_RESULT' => $poll_option['poll_option_total'], - 'POLL_OPTION_PERCENT' => $option_pct_txt, - 'POLL_OPTION_PERCENT_REL' => $option_pct_rel_txt, - 'POLL_OPTION_PCT' => round($option_pct * 100), - 'POLL_OPTION_WIDTH' => round($option_pct * 250), - 'POLL_OPTION_VOTED' => (in_array($poll_option['poll_option_id'], $cur_voted_id)) ? true : false, - 'POLL_OPTION_MOST_VOTES' => $option_most_votes, - ); - } - - $poll_end = $topic_data['poll_length'] + $topic_data['poll_start']; - - $poll_template_data = array( - 'POLL_QUESTION' => $topic_data['poll_title'], - 'TOTAL_VOTES' => $poll_total, - 'POLL_LEFT_CAP_IMG' => $user->img('poll_left'), - 'POLL_RIGHT_CAP_IMG'=> $user->img('poll_right'), - - 'L_MAX_VOTES' => $user->lang('MAX_OPTIONS_SELECT', (int) $topic_data['poll_max_options']), - 'L_POLL_LENGTH' => ($topic_data['poll_length']) ? sprintf($user->lang[($poll_end > time()) ? 'POLL_RUN_TILL' : 'POLL_ENDED_AT'], $user->format_date($poll_end)) : '', - - 'S_HAS_POLL' => true, - 'S_CAN_VOTE' => $s_can_vote, - 'S_DISPLAY_RESULTS' => $s_display_results, - 'S_IS_MULTI_CHOICE' => ($topic_data['poll_max_options'] > 1) ? true : false, - 'S_POLL_ACTION' => $viewtopic_url, - - 'U_VIEW_RESULTS' => $viewtopic_url . '&view=viewpoll', - ); - - /** - * Event to add/modify poll template data - * - * @event core.viewtopic_modify_poll_template_data - * @var array cur_voted_id Array with options' IDs current user has voted for - * @var int poll_end The poll end time - * @var array poll_info Array with the poll information - * @var array poll_options_template_data Array with the poll options template data - * @var array poll_template_data Array with the common poll template data - * @var int poll_total Total poll votes count - * @var int poll_most Mostly voted option votes count - * @var array topic_data All the information from the topic and forum tables for this topic - * @var string viewtopic_url URL to the topic page - * @var array vote_counts Array with the vote counts for every poll option - * @var array voted_id Array with updated options' IDs current user is voting for - * @since 3.1.5-RC1 - */ - $vars = array( - 'cur_voted_id', - 'poll_end', - 'poll_info', - 'poll_options_template_data', - 'poll_template_data', - 'poll_total', - 'poll_most', - 'topic_data', - 'viewtopic_url', - 'vote_counts', - 'voted_id', - ); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_template_data', compact($vars))); - - $template->assign_block_vars_array('poll_option', $poll_options_template_data); - - $template->assign_vars($poll_template_data); - - unset($poll_end, $poll_info, $poll_options_template_data, $poll_template_data, $voted_id); -} - -// If the user is trying to reach the second half of the topic, fetch it starting from the end -$store_reverse = false; -$sql_limit = $config['posts_per_page']; -$sql_sort_order = $direction = ''; - -if ($start > $total_posts / 2) -{ - $store_reverse = true; - - // Select the sort order - $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC'); - - $sql_limit = $pagination->reverse_limit($start, $sql_limit, $total_posts); - $sql_start = $pagination->reverse_start($start, $sql_limit, $total_posts); -} -else -{ - // Select the sort order - $direction = (($sort_dir == 'd') ? 'DESC' : 'ASC'); - $sql_start = $start; -} - -if (is_array($sort_by_sql[$sort_key])) -{ - $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction; -} -else -{ - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction; -} - -// Container for user details, only process once -$post_list = $user_cache = $id_cache = $attachments = $attach_list = $rowset = $update_count = $post_edit_list = $post_delete_list = array(); -$has_unapproved_attachments = $has_approved_attachments = $display_notice = false; -$i = $i_total = 0; - -// Go ahead and pull all data for this topic -$sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p' . (($join_user_sql[$sort_key]) ? ', ' . USERS_TABLE . ' u': '') . " - WHERE p.topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . " - " . (($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; -while ($row = $db->sql_fetchrow($result)) -{ - $post_list[$i] = (int) $row['post_id']; - ($store_reverse) ? $i-- : $i++; -} -$db->sql_freeresult($result); - -if (!count($post_list)) -{ - if ($sort_days) - { - trigger_error('NO_POSTS_TIME_FRAME'); - } - else - { - trigger_error('NO_TOPIC'); - } -} - -// Holding maximum post time for marking topic read -// We need to grab it because we do reverse ordering sometimes -$max_post_time = 0; - -$sql_ary = array( - 'SELECT' => 'u.*, z.friend, z.foe, p.*', - - 'FROM' => array( - USERS_TABLE => 'u', - POSTS_TABLE => 'p', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ZEBRA_TABLE => 'z'), - 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id', - ), - ), - - 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . ' - AND u.user_id = p.poster_id', -); - -/** -* Event to modify the SQL query before the post and poster data is retrieved -* -* @event core.viewtopic_get_post_data -* @var int forum_id Forum ID -* @var int topic_id Topic ID -* @var array topic_data Array with topic data -* @var array post_list Array with post_ids we are going to retrieve -* @var int sort_days Display posts of previous x days -* @var string sort_key Key the posts are sorted by -* @var string sort_dir Direction the posts are sorted by -* @var int start Pagination information -* @var array sql_ary The SQL array to get the data of posts and posters -* @since 3.1.0-a1 -* @changed 3.1.0-a2 Added vars forum_id, topic_id, topic_data, post_list, sort_days, sort_key, sort_dir, start -*/ -$vars = array( - 'forum_id', - 'topic_id', - 'topic_data', - 'post_list', - 'sort_days', - 'sort_key', - 'sort_dir', - 'start', - 'sql_ary', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_get_post_data', compact($vars))); - -$sql = $db->sql_build_query('SELECT', $sql_ary); -$result = $db->sql_query($sql); - -$now = $user->create_datetime(); -$now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset()); - -// Posts are stored in the $rowset array while $attach_list, $user_cache -// and the global bbcode_bitfield are built -while ($row = $db->sql_fetchrow($result)) -{ - // Set max_post_time - if ($row['post_time'] > $max_post_time) - { - $max_post_time = $row['post_time']; - } - - $poster_id = (int) $row['poster_id']; - - // Does post have an attachment? If so, add it to the list - if ($row['post_attachment'] && $config['allow_attachments']) - { - $attach_list[] = (int) $row['post_id']; - - if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) - { - $has_unapproved_attachments = true; - } - else if ($row['post_visibility'] == ITEM_APPROVED) - { - $has_approved_attachments = true; - } - } - - $rowset_data = array( - 'hide_post' => (($row['foe'] || $row['post_visibility'] == ITEM_DELETED) && ($view != 'show' || $post_id != $row['post_id'])) ? true : false, - - 'post_id' => $row['post_id'], - 'post_time' => $row['post_time'], - 'user_id' => $row['user_id'], - 'username' => $row['username'], - 'user_colour' => $row['user_colour'], - 'topic_id' => $row['topic_id'], - 'forum_id' => $row['forum_id'], - 'post_subject' => $row['post_subject'], - 'post_edit_count' => $row['post_edit_count'], - 'post_edit_time' => $row['post_edit_time'], - 'post_edit_reason' => $row['post_edit_reason'], - 'post_edit_user' => $row['post_edit_user'], - 'post_edit_locked' => $row['post_edit_locked'], - 'post_delete_time' => $row['post_delete_time'], - 'post_delete_reason'=> $row['post_delete_reason'], - 'post_delete_user' => $row['post_delete_user'], - - // Make sure the icon actually exists - 'icon_id' => (isset($icons[$row['icon_id']]['img'], $icons[$row['icon_id']]['height'], $icons[$row['icon_id']]['width'])) ? $row['icon_id'] : 0, - 'post_attachment' => $row['post_attachment'], - 'post_visibility' => $row['post_visibility'], - 'post_reported' => $row['post_reported'], - 'post_username' => $row['post_username'], - 'post_text' => $row['post_text'], - 'bbcode_uid' => $row['bbcode_uid'], - 'bbcode_bitfield' => $row['bbcode_bitfield'], - 'enable_smilies' => $row['enable_smilies'], - 'enable_sig' => $row['enable_sig'], - 'friend' => $row['friend'], - 'foe' => $row['foe'], - ); - - /** - * Modify the post rowset containing data to be displayed with posts - * - * @event core.viewtopic_post_rowset_data - * @var array rowset_data Array with the rowset data for this post - * @var array row Array with original user and post data - * @since 3.1.0-a1 - */ - $vars = array('rowset_data', 'row'); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_rowset_data', compact($vars))); - - $rowset[$row['post_id']] = $rowset_data; - - // Cache various user specific data ... so we don't have to recompute - // this each time the same user appears on this page - if (!isset($user_cache[$poster_id])) - { - if ($poster_id == ANONYMOUS) - { - $user_cache_data = array( - 'user_type' => USER_IGNORE, - 'joined' => '', - 'posts' => '', - - 'sig' => '', - 'sig_bbcode_uid' => '', - 'sig_bbcode_bitfield' => '', - - 'online' => false, - 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '', - 'rank_title' => '', - 'rank_image' => '', - 'rank_image_src' => '', - 'pm' => '', - 'email' => '', - 'jabber' => '', - 'search' => '', - 'age' => '', - - 'username' => $row['username'], - 'user_colour' => $row['user_colour'], - 'contact_user' => '', - - 'warnings' => 0, - 'allow_pm' => 0, - ); - - /** - * Modify the guest user's data displayed with the posts - * - * @event core.viewtopic_cache_guest_data - * @var array user_cache_data Array with the user's data - * @var int poster_id Poster's user id - * @var array row Array with original user and post data - * @since 3.1.0-a1 - */ - $vars = array('user_cache_data', 'poster_id', 'row'); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_guest_data', compact($vars))); - - $user_cache[$poster_id] = $user_cache_data; - - $user_rank_data = phpbb_get_user_rank($row, false); - $user_cache[$poster_id]['rank_title'] = $user_rank_data['title']; - $user_cache[$poster_id]['rank_image'] = $user_rank_data['img']; - $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src']; - } - else - { - $user_sig = ''; - - // We add the signature to every posters entry because enable_sig is post dependent - if ($row['user_sig'] && $config['allow_sig'] && $user->optionget('viewsigs')) - { - $user_sig = $row['user_sig']; - } - - $id_cache[] = $poster_id; - - $user_cache_data = array( - 'user_type' => $row['user_type'], - 'user_inactive_reason' => $row['user_inactive_reason'], - - 'joined' => $user->format_date($row['user_regdate']), - 'posts' => $row['user_posts'], - 'warnings' => (isset($row['user_warnings'])) ? $row['user_warnings'] : 0, - - 'sig' => $user_sig, - 'sig_bbcode_uid' => (!empty($row['user_sig_bbcode_uid'])) ? $row['user_sig_bbcode_uid'] : '', - 'sig_bbcode_bitfield' => (!empty($row['user_sig_bbcode_bitfield'])) ? $row['user_sig_bbcode_bitfield'] : '', - - 'viewonline' => $row['user_allow_viewonline'], - 'allow_pm' => $row['user_allow_pm'], - - 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '', - 'age' => '', - - 'rank_title' => '', - 'rank_image' => '', - 'rank_image_src' => '', - - 'username' => $row['username'], - 'user_colour' => $row['user_colour'], - 'contact_user' => $user->lang('CONTACT_USER', get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['username'])), - - 'online' => false, - 'jabber' => ($config['jab_enable'] && $row['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=jabber&u=$poster_id") : '', - 'search' => ($config['load_search'] && $auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$poster_id&sr=posts") : '', - - 'author_full' => get_username_string('full', $poster_id, $row['username'], $row['user_colour']), - 'author_colour' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour']), - 'author_username' => get_username_string('username', $poster_id, $row['username'], $row['user_colour']), - 'author_profile' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour']), - ); - - /** - * Modify the users' data displayed with their posts - * - * @event core.viewtopic_cache_user_data - * @var array user_cache_data Array with the user's data - * @var int poster_id Poster's user id - * @var array row Array with original user and post data - * @since 3.1.0-a1 - */ - $vars = array('user_cache_data', 'poster_id', 'row'); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_user_data', compact($vars))); - - $user_cache[$poster_id] = $user_cache_data; - - $user_rank_data = phpbb_get_user_rank($row, $row['user_posts']); - $user_cache[$poster_id]['rank_title'] = $user_rank_data['title']; - $user_cache[$poster_id]['rank_image'] = $user_rank_data['img']; - $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src']; - - if ((!empty($row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email')) - { - $user_cache[$poster_id]['email'] = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&u=$poster_id") : (($config['board_hide_emails'] && !$auth->acl_get('a_email')) ? '' : 'mailto:' . $row['user_email']); - } - else - { - $user_cache[$poster_id]['email'] = ''; - } - - if ($config['allow_birthdays'] && !empty($row['user_birthday'])) - { - list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $row['user_birthday'])); - - if ($bday_year) - { - $diff = $now['mon'] - $bday_month; - if ($diff == 0) - { - $diff = ($now['mday'] - $bday_day < 0) ? 1 : 0; - } - else - { - $diff = ($diff < 0) ? 1 : 0; - } - - $user_cache[$poster_id]['age'] = (int) ($now['year'] - $bday_year - $diff); - } - } - } - } -} -$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 - $profile_fields_tmp = $cp->grab_profile_fields_data($id_cache); - - // filter out fields not to be displayed on viewtopic. Yes, it's a hack, but this shouldn't break any MODs. - $profile_fields_cache = array(); - foreach ($profile_fields_tmp as $profile_user_id => $profile_fields) - { - $profile_fields_cache[$profile_user_id] = array(); - foreach ($profile_fields as $used_ident => $profile_field) - { - if ($profile_field['data']['field_show_on_vt']) - { - $profile_fields_cache[$profile_user_id][$used_ident] = $profile_field; - } - } - } - unset($profile_fields_tmp); -} - -// Generate online information for user -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 . ' - WHERE ' . $db->sql_in_set('session_user_id', $id_cache) . ' - GROUP BY session_user_id'; - $result = $db->sql_query($sql); - - $update_time = $config['load_online_time'] * 60; - while ($row = $db->sql_fetchrow($result)) - { - $user_cache[$row['session_user_id']]['online'] = (time() - $update_time < $row['online_time'] && (($row['viewonline']) || $auth->acl_get('u_viewonline'))) ? true : false; - } - $db->sql_freeresult($result); -} -unset($id_cache); - -// Pull attachment data -if (count($attach_list)) -{ - if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id)) - { - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . ' - AND in_message = 0 - ORDER BY attach_id DESC, post_msg_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $attachments[$row['post_msg_id']][] = $row; - } - $db->sql_freeresult($result); - - // No attachments exist, but post table thinks they do so go ahead and reset post_attach flags - if (!count($attachments)) - { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_attachment = 0 - WHERE ' . $db->sql_in_set('post_id', $attach_list); - $db->sql_query($sql); - - // We need to update the topic indicator too if the complete topic is now without an attachment - 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 - FROM ' . ATTACHMENTS_TABLE . ' a, ' . POSTS_TABLE . " p - WHERE p.topic_id = $topic_id - AND p.post_visibility = " . ITEM_APPROVED . ' - AND p.topic_id = a.topic_id'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_attachment = 0 - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - } - } - else - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_attachment = 0 - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - } - } - else if ($has_approved_attachments && !$topic_data['topic_attachment']) - { - // Topic has approved attachments but its flag is wrong - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_attachment = 1 - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - $topic_data['topic_attachment'] = 1; - } - else if ($has_unapproved_attachments && !$topic_data['topic_attachment']) - { - // Topic has only unapproved attachments but we have the right to see and download them - $topic_data['topic_attachment'] = 1; - } - } - else - { - $display_notice = true; - } -} - -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); -} -else -{ - $can_receive_pm_list = array_keys($user_cache); - $permanently_banned_users = []; -} - -$i_total = count($rowset) - 1; -$prev_post_id = ''; - -$template->assign_vars(array( - 'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'], - 'S_NUM_POSTS' => count($post_list)) -); - -/** -* Event to modify the post, poster and attachment data before assigning the posts -* -* @event core.viewtopic_modify_post_data -* @var int forum_id Forum ID -* @var int topic_id Topic ID -* @var array topic_data Array with topic data -* @var array post_list Array with post_ids we are going to display -* @var array rowset Array with post_id => post data -* @var array user_cache Array with prepared user data -* @var int start Pagination information -* @var int sort_days Display posts of previous x days -* @var string sort_key Key the posts are sorted by -* @var string sort_dir Direction the posts are sorted by -* @var bool display_notice Shall we display a notice instead of attachments -* @var bool has_approved_attachments Does the topic have approved attachments -* @var array attachments List of attachments post_id => array of attachments -* @var array permanently_banned_users List of permanently banned users -* @var array can_receive_pm_list Array with posters that can receive pms -* @since 3.1.0-RC3 -*/ -$vars = array( - 'forum_id', - 'topic_id', - 'topic_data', - 'post_list', - 'rowset', - 'user_cache', - 'sort_days', - 'sort_key', - 'sort_dir', - 'start', - 'permanently_banned_users', - 'can_receive_pm_list', - 'display_notice', - 'has_approved_attachments', - 'attachments', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_data', compact($vars))); - -// Output the posts -$first_unread = $post_unread = false; -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. - if (!isset($rowset[$post_list[$i]])) - { - continue; - } - - $row = $rowset[$post_list[$i]]; - $poster_id = $row['user_id']; - - // End signature parsing, only if needed - if ($user_cache[$poster_id]['sig'] && $row['enable_sig'] && empty($user_cache[$poster_id]['sig_parsed'])) - { - $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 - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true); - - if (!empty($attachments[$row['post_id']])) - { - parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count); - } - - // Replace naughty words such as farty pants - $row['post_subject'] = censor_text($row['post_subject']); - - // Highlight active words (primarily for search) - if ($highlight_match) - { - $message = preg_replace('#(?!<.*)(?]*(?:)#is', '\1', $message); - $row['post_subject'] = preg_replace('#(?!<.*)(?]*(?:)#is', '\1', $row['post_subject']); - } - - // Editing information - if (($row['post_edit_count'] && $config['display_last_edited']) || $row['post_edit_reason']) - { - // Get usernames for all following posts if not already stored - 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); - - $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . ' - AND p.post_edit_count <> 0 - AND p.post_edit_user <> 0 - AND p.post_edit_user = u.user_id'; - $result2 = $db->sql_query($sql); - while ($user_edit_row = $db->sql_fetchrow($result2)) - { - $post_edit_list[$user_edit_row['user_id']] = $user_edit_row; - } - $db->sql_freeresult($result2); - - unset($post_storage_list); - } - - if ($row['post_edit_reason']) - { - // User having edited the post also being the post author? - if (!$row['post_edit_user'] || $row['post_edit_user'] == $poster_id) - { - $display_username = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); - } - else - { - $display_username = get_username_string('full', $row['post_edit_user'], $post_edit_list[$row['post_edit_user']]['username'], $post_edit_list[$row['post_edit_user']]['user_colour']); - } - - $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true)); - } - else - { - if ($row['post_edit_user'] && !isset($user_cache[$row['post_edit_user']])) - { - $user_cache[$row['post_edit_user']] = $post_edit_list[$row['post_edit_user']]; - } - - // User having edited the post also being the post author? - if (!$row['post_edit_user'] || $row['post_edit_user'] == $poster_id) - { - $display_username = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); - } - else - { - $display_username = get_username_string('full', $row['post_edit_user'], $user_cache[$row['post_edit_user']]['username'], $user_cache[$row['post_edit_user']]['user_colour']); - } - - $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true)); - } - } - else - { - $l_edited_by = ''; - } - - // Deleting information - if ($row['post_visibility'] == ITEM_DELETED && $row['post_delete_user']) - { - // Get usernames for all following posts if not already stored - 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); - - $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . ' - AND p.post_delete_user <> 0 - AND p.post_delete_user = u.user_id'; - $result2 = $db->sql_query($sql); - while ($user_delete_row = $db->sql_fetchrow($result2)) - { - $post_delete_list[$user_delete_row['user_id']] = $user_delete_row; - } - $db->sql_freeresult($result2); - - unset($post_storage_list); - } - - if ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']])) - { - $user_cache[$row['post_delete_user']] = $post_delete_list[$row['post_delete_user']]; - } - - $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); - - // User having deleted the post also being the post author? - if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id) - { - $display_username = $display_postername; - } - else - { - $display_username = get_username_string('full', $row['post_delete_user'], $user_cache[$row['post_delete_user']]['username'], $user_cache[$row['post_delete_user']]['user_colour']); - } - - if ($row['post_delete_reason']) - { - $l_deleted_message = $user->lang('POST_DELETED_BY_REASON', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true), $row['post_delete_reason']); - } - else - { - $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true)); - } - $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($row['post_delete_time'], false, true)); - } - else - { - $l_deleted_by = $l_deleted_message = ''; - } - - // Bump information - if ($topic_data['topic_bumped'] && $row['post_id'] == $topic_data['topic_last_post_id'] && isset($user_cache[$topic_data['topic_bumper']]) ) - { - // It is safe to grab the username from the user cache array, we are at the last - // post and only the topic poster and last poster are allowed to bump. - // Admins and mods are bound to the above rules too... - $l_bumped_by = sprintf($user->lang['BUMPED_BY'], $user_cache[$topic_data['topic_bumper']]['username'], $user->format_date($topic_data['topic_last_post_time'], false, true)); - } - else - { - $l_bumped_by = ''; - } - - $cp_row = array(); - - // - if ($config['load_cpf_viewtopic']) - { - $cp_row = (isset($profile_fields_cache[$poster_id])) ? $cp->generate_profile_fields_template_data($profile_fields_cache[$poster_id]) : array(); - } - - $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false; - - $s_first_unread = false; - if (!$first_unread && $post_unread) - { - $s_first_unread = $first_unread = true; - } - - $force_edit_allowed = $force_delete_allowed = $force_softdelete_allowed = false; - - $s_cannot_edit = !$auth->acl_get('f_edit', $forum_id) || $user->data['user_id'] != $poster_id; - $s_cannot_edit_time = $config['edit_time'] && $row['post_time'] <= time() - ($config['edit_time'] * 60); - $s_cannot_edit_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked']; - - $s_cannot_delete = $user->data['user_id'] != $poster_id || ( - !$auth->acl_get('f_delete', $forum_id) && - (!$auth->acl_get('f_softdelete', $forum_id) || $row['post_visibility'] == ITEM_DELETED) - ); - $s_cannot_delete_lastpost = $topic_data['topic_last_post_id'] != $row['post_id']; - $s_cannot_delete_time = $config['delete_time'] && $row['post_time'] <= time() - ($config['delete_time'] * 60); - // we do not want to allow removal of the last post if a moderator locked it! - $s_cannot_delete_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked']; - - /** - * This event allows you to modify the conditions for the "can edit post" and "can delete post" checks - * - * @event core.viewtopic_modify_post_action_conditions - * @var array row Array with post data - * @var array topic_data Array with topic data - * @var bool force_edit_allowed Allow the user to edit the post (all permissions and conditions are ignored) - * @var bool s_cannot_edit User can not edit the post because it's not his - * @var bool s_cannot_edit_locked User can not edit the post because it's locked - * @var bool s_cannot_edit_time User can not edit the post because edit_time has passed - * @var bool force_delete_allowed Allow the user to delete the post (all permissions and conditions are ignored) - * @var bool s_cannot_delete User can not delete the post because it's not his - * @var bool s_cannot_delete_lastpost User can not delete the post because it's not the last post of the topic - * @var bool s_cannot_delete_locked User can not delete the post because it's locked - * @var bool s_cannot_delete_time User can not delete the post because edit_time has passed - * @var bool force_softdelete_allowed Allow the user to ыoftdelete the post (all permissions and conditions are ignored) - * @since 3.1.0-b4 - * @changed 3.1.11-RC1 Added force_softdelete_allowed var - */ - $vars = array( - 'row', - 'topic_data', - 'force_edit_allowed', - 's_cannot_edit', - 's_cannot_edit_locked', - 's_cannot_edit_time', - 'force_delete_allowed', - 's_cannot_delete', - 's_cannot_delete_lastpost', - 's_cannot_delete_locked', - 's_cannot_delete_time', - 'force_softdelete_allowed', - ); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_action_conditions', compact($vars))); - - $edit_allowed = $force_edit_allowed || ($user->data['is_registered'] && ($auth->acl_get('m_edit', $forum_id) || ( - !$s_cannot_edit && - !$s_cannot_edit_time && - !$s_cannot_edit_locked - ))); - - $quote_allowed = $auth->acl_get('m_edit', $forum_id) || ($topic_data['topic_status'] != ITEM_LOCKED && - ($user->data['user_id'] == ANONYMOUS || $auth->acl_get('f_reply', $forum_id)) - ); - - // Only display the quote button if the post is quotable. Posts not approved are not quotable. - $quote_allowed = ($quote_allowed && $row['post_visibility'] == ITEM_APPROVED) ? true : false; - - $delete_allowed = $force_delete_allowed || ($user->data['is_registered'] && ( - ($auth->acl_get('m_delete', $forum_id) || ($auth->acl_get('m_softdelete', $forum_id) && $row['post_visibility'] != ITEM_DELETED)) || - (!$s_cannot_delete && !$s_cannot_delete_lastpost && !$s_cannot_delete_time && !$s_cannot_delete_locked) - )); - - $softdelete_allowed = $force_softdelete_allowed || (($auth->acl_get('m_softdelete', $forum_id) || - ($auth->acl_get('f_softdelete', $forum_id) && $user->data['user_id'] == $poster_id)) && ($row['post_visibility'] != ITEM_DELETED)); - - $permanent_delete_allowed = $force_delete_allowed || ($auth->acl_get('m_delete', $forum_id) || - ($auth->acl_get('f_delete', $forum_id) && $user->data['user_id'] == $poster_id)); - - // Can this user receive a Private Message? - $can_receive_pm = ( - // They must be a "normal" user - $user_cache[$poster_id]['user_type'] != USER_IGNORE && - - // They must not be deactivated by the administrator - ($user_cache[$poster_id]['user_type'] != USER_INACTIVE || $user_cache[$poster_id]['user_inactive_reason'] != INACTIVE_MANUAL) && - - // They must be able to read PMs - in_array($poster_id, $can_receive_pm_list) && - - // They must not be permanently banned - !in_array($poster_id, $permanently_banned_users) && - - // They must allow users to contact via PM - (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $user_cache[$poster_id]['allow_pm']) - ); - - $u_pm = ''; - - if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm) - { - $u_pm = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&action=quotepost&p=' . $row['post_id']); - } - - // - $post_row = array( - 'POST_AUTHOR_FULL' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_full'] : get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_colour'] : get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_username'] : get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_profile'] : get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - - 'RANK_TITLE' => $user_cache[$poster_id]['rank_title'], - 'RANK_IMG' => $user_cache[$poster_id]['rank_image'], - 'RANK_IMG_SRC' => $user_cache[$poster_id]['rank_image_src'], - 'POSTER_JOINED' => $user_cache[$poster_id]['joined'], - 'POSTER_POSTS' => $user_cache[$poster_id]['posts'], - 'POSTER_AVATAR' => $user_cache[$poster_id]['avatar'], - 'POSTER_WARNINGS' => $auth->acl_get('m_warn') ? $user_cache[$poster_id]['warnings'] : '', - 'POSTER_AGE' => $user_cache[$poster_id]['age'], - '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'] : '', - 'EDITED_MESSAGE' => $l_edited_by, - 'EDIT_REASON' => $row['post_edit_reason'], - 'DELETED_MESSAGE' => $l_deleted_by, - 'DELETE_REASON' => $row['post_delete_reason'], - 'BUMPED_MESSAGE' => $l_bumped_by, - - 'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'), - '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), - - 'U_EDIT' => ($edit_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&f=$forum_id&p={$row['post_id']}") : '', - 'U_QUOTE' => ($quote_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=quote&f=$forum_id&p={$row['post_id']}") : '', - 'U_INFO' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=post_details&f=$forum_id&p=" . $row['post_id'], true, $user->session_id) : '', - 'U_DELETE' => ($delete_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=' . (($softdelete_allowed) ? 'soft_delete' : 'delete') . "&f=$forum_id&p={$row['post_id']}") : '', - - 'U_SEARCH' => $user_cache[$poster_id]['search'], - 'U_PM' => $u_pm, - 'U_EMAIL' => $user_cache[$poster_id]['email'], - 'U_JABBER' => $user_cache[$poster_id]['jabber'], - - 'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&p={$row['post_id']}&f=$forum_id&redirect=" . urlencode(str_replace('&', '&', $viewtopic_url . '&p=' . $row['post_id'] . '#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&mode=report_details&f=' . $forum_id . '&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&mode=approve_details&f=' . $forum_id . '&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&mode=' . (($topic_data['topic_visibility'] != ITEM_DELETED) ? 'deleted_posts' : 'deleted_topics') . '&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', - 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'], - 'U_NEXT_POST_ID' => ($i < $i_total && isset($rowset[$post_list[$i + 1]])) ? $rowset[$post_list[$i + 1]]['post_id'] : '', - 'U_PREV_POST_ID' => $prev_post_id, - 'U_NOTES' => ($auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $poster_id, true, $user->session_id) : '', - 'U_WARN' => ($auth->acl_get('m_warn') && $poster_id != $user->data['user_id'] && $poster_id != ANONYMOUS) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_post&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', - - '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']]) && count($attachments[$row['post_id']]) > 1, - 'S_POST_UNAPPROVED' => ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) ? true : false, - 'S_CAN_APPROVE' => $auth->acl_get('m_approve', $forum_id), - 'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED) ? true : false, - 'L_POST_DELETED_MESSAGE' => $l_deleted_message, - 'S_POST_REPORTED' => ($row['post_reported'] && $auth->acl_get('m_report', $forum_id)) ? true : false, - 'S_DISPLAY_NOTICE' => $display_notice && $row['post_attachment'], - 'S_FRIEND' => ($row['friend']) ? true : false, - 'S_UNREAD_POST' => $post_unread, - 'S_FIRST_UNREAD' => $s_first_unread, - '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'])) : '', - 'S_POST_HIDDEN' => $row['hide_post'], - 'L_POST_DISPLAY' => ($row['hide_post']) ? $user->lang('POST_DISPLAY', '', '') : '', - 'S_DELETE_PERMANENT' => $permanent_delete_allowed, - ); - - $user_poster_data = $user_cache[$poster_id]; - - $current_row_number = $i; - - /** - * Modify the posts template block - * - * @event core.viewtopic_modify_post_row - * @var int start Start item of this page - * @var int current_row_number Number of the post on this page - * @var int end Number of posts on this page - * @var int total_posts Total posts count - * @var int poster_id Post author id - * @var array row Array with original post and user data - * @var array cp_row Custom profile field data of the poster - * @var array attachments List of attachments - * @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', - 'current_row_number', - 'end', - 'total_posts', - 'poster_id', - 'row', - 'cp_row', - 'attachments', - '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']) && count($cp_row['row'])) - { - $post_row = array_merge($post_row, $cp_row['row']); - } - - // Dump vars into template - $template->assign_block_vars('postrow', $post_row); - - $contact_fields = array( - array( - 'ID' => 'pm', - 'NAME' => $user->lang['SEND_PRIVATE_MESSAGE'], - 'U_CONTACT' => $post_row['U_PM'], - ), - array( - 'ID' => 'email', - 'NAME' => $user->lang['SEND_EMAIL'], - 'U_CONTACT' => $user_cache[$poster_id]['email'], - ), - array( - 'ID' => 'jabber', - 'NAME' => $user->lang['JABBER'], - 'U_CONTACT' => $user_cache[$poster_id]['jabber'], - ), - ); - - foreach ($contact_fields as $field) - { - if ($field['U_CONTACT']) - { - $template->assign_block_vars('postrow.contact', $field); - } - } - - if (!empty($cp_row['blockrow'])) - { - foreach ($cp_row['blockrow'] as $field_data) - { - $template->assign_block_vars('postrow.custom_fields', $field_data); - - if ($field_data['S_PROFILE_CONTACT']) - { - $template->assign_block_vars('postrow.contact', array( - 'ID' => $field_data['PROFILE_FIELD_IDENT'], - 'NAME' => $field_data['PROFILE_FIELD_NAME'], - 'U_CONTACT' => $field_data['PROFILE_FIELD_CONTACT'], - )); - } - } - } - - // Display not already displayed Attachments for this post, we already parsed them. ;) - if (!empty($attachments[$row['post_id']])) - { - foreach ($attachments[$row['post_id']] as $attachment) - { - $template->assign_block_vars('postrow.attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - } - - $current_row_number = $i; - - /** - * Event after the post data has been assigned to the template - * - * @event core.viewtopic_post_row_after - * @var int start Start item of this page - * @var int current_row_number Number of the post on this page - * @var int end Number of posts on this page - * @var int total_posts Total posts count - * @var array row Array with original post and user data - * @var array cp_row Custom profile field data of the poster - * @var array attachments List of attachments - * @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 - * @since 3.1.0-a3 - * @changed 3.1.0-b3 Added topic_data array, total_posts - */ - $vars = array( - 'start', - 'current_row_number', - 'end', - 'total_posts', - 'row', - 'cp_row', - 'attachments', - 'user_poster_data', - 'post_row', - 'topic_data', - ); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_row_after', compact($vars))); - - $i = $current_row_number; - - $prev_post_id = $row['post_id']; - - unset($rowset[$post_list[$i]]); - unset($attachments[$row['post_id']]); -} -unset($rowset, $user_cache); - -// Update topic view and if necessary attachment view counters ... but only for humans and if this is the first 'page view' -if (isset($user->data['session_page']) && !$user->data['is_bot'] && (strpos($user->data['session_page'], '&t=' . $topic_id) === false || isset($user->data['session_created']))) -{ - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_views = topic_views + 1, topic_last_view_time = ' . time() . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - // Update the attachment download counts - if (count($update_count)) - { - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET download_count = download_count + 1 - WHERE ' . $db->sql_in_set('attach_id', array_unique($update_count)); - $db->sql_query($sql); - } -} - -// Only mark topic if it's currently unread. Also make sure we do not set topic tracking back if earlier pages are viewed. -if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id] && $max_post_time > $topic_tracking_info[$topic_id]) -{ - markread('topic', $forum_id, $topic_id, $max_post_time); - - // Update forum info - $all_marked_read = update_forum_tracking_info($forum_id, $topic_data['forum_last_post_time'], (isset($topic_data['forum_mark_time'])) ? $topic_data['forum_mark_time'] : false, false); -} -else -{ - $all_marked_read = true; -} - -// If there are absolutely no more unread posts in this forum -// and unread posts shown, we can safely show the #unread link -if ($all_marked_read) -{ - if ($post_unread) - { - $template->assign_vars(array( - 'U_VIEW_UNREAD_POST' => '#unread', - )); - } - else if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id]) - { - $template->assign_vars(array( - 'U_VIEW_UNREAD_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=unread") . '#unread', - )); - } -} -else if (!$all_marked_read) -{ - $last_page = ((floor($start / $config['posts_per_page']) + 1) == max(ceil($total_posts / $config['posts_per_page']), 1)) ? true : false; - - // What can happen is that we are at the last displayed page. If so, we also display the #unread link based in $post_unread - if ($last_page && $post_unread) - { - $template->assign_vars(array( - 'U_VIEW_UNREAD_POST' => '#unread', - )); - } - else if (!$last_page) - { - $template->assign_vars(array( - 'U_VIEW_UNREAD_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=unread") . '#unread', - )); - } -} - -// let's set up quick_reply -$s_quick_reply = false; -if ($user->data['is_registered'] && $config['allow_quick_reply'] && ($topic_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) && $auth->acl_get('f_reply', $forum_id)) -{ - // Quick reply enabled forum - $s_quick_reply = (($topic_data['forum_status'] == ITEM_UNLOCKED && $topic_data['topic_status'] == ITEM_UNLOCKED) || $auth->acl_get('m_edit', $forum_id)) ? true : false; -} - -if ($s_can_vote || $s_quick_reply) -{ - add_form_key('posting'); - - if ($s_quick_reply) - { - $s_attach_sig = $config['allow_sig'] && $user->optionget('attachsig') && $auth->acl_get('f_sigs', $forum_id) && $auth->acl_get('u_sig'); - $s_smilies = $config['allow_smilies'] && $user->optionget('smilies') && $auth->acl_get('f_smilies', $forum_id); - $s_bbcode = $config['allow_bbcode'] && $user->optionget('bbcode') && $auth->acl_get('f_bbcode', $forum_id); - $s_notify = $config['allow_topic_notify'] && ($user->data['user_notify'] || $s_watching_topic['is_watching']); - - $qr_hidden_fields = array( - 'topic_cur_post_id' => (int) $topic_data['topic_last_post_id'], - 'topic_id' => (int) $topic_data['topic_id'], - 'forum_id' => (int) $forum_id, - ); - - // Originally we use checkboxes and check with isset(), so we only provide them if they would be checked - (!$s_bbcode) ? $qr_hidden_fields['disable_bbcode'] = 1 : true; - (!$s_smilies) ? $qr_hidden_fields['disable_smilies'] = 1 : true; - (!$config['allow_post_links']) ? $qr_hidden_fields['disable_magic_url'] = 1 : true; - ($s_attach_sig) ? $qr_hidden_fields['attach_sig'] = 1 : true; - ($s_notify) ? $qr_hidden_fields['notify'] = 1 : true; - ($topic_data['topic_status'] == ITEM_LOCKED) ? $qr_hidden_fields['lock_topic'] = 1 : true; - - $tpl_ary = [ - 'S_QUICK_REPLY' => true, - 'U_QR_ACTION' => append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&f=$forum_id&t=$topic_id"), - 'QR_HIDDEN_FIELDS' => build_hidden_fields($qr_hidden_fields), - 'SUBJECT' => 'Re: ' . censor_text($topic_data['topic_title']), - ]; - - /** - * 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 :( - - -// 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->variable('f', 0)) -{ - $request->overwrite('f', $forum_id); -} - -// We need to do the same with the topic_id. See #53025. -if (!$request->variable('t', 0) && !empty($topic_id)) -{ - $request->overwrite('t', $topic_id); -} - -$page_title = $topic_data['topic_title'] . ($start ? ' - ' . sprintf($user->lang['PAGE_TITLE_NUMBER'], $pagination->get_on_page($config['posts_per_page'], $start)) : ''); - -/** -* You can use this event to modify the page title of the viewtopic page -* -* @event core.viewtopic_modify_page_title -* @var string page_title Title of the viewtopic page -* @var array topic_data Array with topic data -* @var int forum_id Forum ID of the topic -* @var int start Start offset used to calculate the page -* @var array post_list Array with post_ids we are going to display -* @since 3.1.0-a1 -* @changed 3.1.0-RC4 Added post_list var -*/ -$vars = array('page_title', 'topic_data', 'forum_id', 'start', 'post_list'); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_page_title', compact($vars))); - -// Output the page -page_header($page_title, true, $forum_id); - -$template->set_filenames(array( - 'body' => ($view == 'print') ? 'viewtopic_print.html' : 'viewtopic_body.html') -); -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_id); - -page_footer(); diff --git a/install/update/old/.htaccess b/install/update/old/.htaccess deleted file mode 100644 index 53bce76..0000000 --- a/install/update/old/.htaccess +++ /dev/null @@ -1,85 +0,0 @@ - -RewriteEngine on - -# -# Uncomment the statement below if URL rewriting doesn't -# work properly. If you installed phpBB in a subdirectory -# of your site, properly set the argument for the statement. -# e.g.: if your domain is test.com and you installed phpBB -# in http://www.test.com/phpBB/index.php you have to set -# the statement RewriteBase /phpBB/ -# -#RewriteBase / - -# -# Uncomment the statement below if you want to make use of -# HTTP authentication and it does not already work. -# This could be required if you are for example using PHP via Apache CGI. -# -#RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] - -# -# The following 3 lines will rewrite URLs passed through the front controller -# to not require app.php in the actual URL. In other words, a controller is -# by default accessed at /app.php/my/controller, but can also be accessed at -# /my/controller -# -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule ^(.*)$ app.php [QSA,L] - -# -# If symbolic links are not already being followed, -# uncomment the line below. -# http://anothersysadmin.wordpress.com/2008/06/10/mod_rewrite-forbidden-403-with-apache-228/ -# -#Options +FollowSymLinks - - -# 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. - - - - Order Allow,Deny - Deny from All - - - Order Allow,Deny - Deny from All - - - = 2.4> - - Require all denied - - - Require all denied - - - - - - - Order Allow,Deny - Deny from All - - - Order Allow,Deny - Deny from All - - - - - Require all denied - - - Require all denied - - - diff --git a/install/update/old/adm/index.php b/install/update/old/adm/index.php deleted file mode 100644 index d27f56f..0000000 --- a/install/update/old/adm/index.php +++ /dev/null @@ -1,91 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -*/ -define('IN_PHPBB', true); -define('ADMIN_START', true); -define('NEED_SID', true); - -// Include files -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -require($phpbb_root_path . 'common.' . $phpEx); -require($phpbb_root_path . 'includes/functions_acp.' . $phpEx); -require($phpbb_root_path . 'includes/functions_admin.' . $phpEx); -require($phpbb_root_path . 'includes/functions_module.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup('acp/common'); -// End session management - -// Have they authenticated (again) as an admin for this session? -if (!isset($user->data['session_admin']) || !$user->data['session_admin']) -{ - login_box('', $user->lang['LOGIN_ADMIN_CONFIRM'], $user->lang['LOGIN_ADMIN_SUCCESS'], true, false); -} - -// Is user any type of admin? No, then stop here, each script needs to -// check specific permissions but this is a catchall -if (!$auth->acl_get('a_')) -{ - send_status_line(403, 'Forbidden'); - trigger_error('NO_ADMIN'); -} - -// We define the admin variables now, because the user is now able to use the admin related features... -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->variable('i', ''); -$mode = $request->variable('mode', ''); - -// Set custom style for admin area -$template->set_custom_style(array( - array( - 'name' => 'adm', - 'ext_path' => 'adm/style/', - ), -), $phpbb_admin_path . 'style'); - -$template->assign_var('T_ASSETS_PATH', $phpbb_root_path . 'assets'); -$template->assign_var('T_TEMPLATE_PATH', $phpbb_admin_path . 'style'); - -// Instantiate new module -$module = new p_master(); - -// Instantiate module system and generate list of available modules -$module->list_modules('acp'); - -// Select the active module -$module->set_active($module_id, $mode); - -// Assign data to the template engine for the list of modules -// We do this before loading the active module for correct menu display in trigger_error -$module->assign_tpl_vars(append_sid("{$phpbb_admin_path}index.$phpEx")); - -// Load and execute the relevant module -$module->load_active(); - -// Generate the page -adm_page_header($module->get_page_title()); - -$template->set_filenames(array( - 'body' => $module->get_tpl_name(), -)); - -adm_page_footer(); diff --git a/install/update/old/adm/style/acp_attachments.html b/install/update/old/adm/style/acp_attachments.html deleted file mode 100644 index 868e256..0000000 --- a/install/update/old/adm/style/acp_attachments.html +++ /dev/null @@ -1,487 +0,0 @@ - - - - - - « {L_BACK} - - -

{L_TITLE}

- -

{L_TITLE_EXPLAIN}

- - -
-

{L_WARNING}

-

{WARNING_MSG}

-
- - - -
-

{L_NOTIFY}

-

{NOTIFY_MSG}

-
- - - -

{L_UPLOADING_FILES}

- - - :: {upload.FILE_INFO}
- {upload.DENIED}{upload.ERROR_MSG}{L_SUCCESSFULLY_UPLOADED} -

- - - - - - -
- - - - - -
- {options.LEGEND} - - -
-

{options.TITLE_EXPLAIN}
-
{options.CONTENT}
-
- - - -
- -
- {L_SUBMIT} -   - -
- - -
-

{L_SECURE_DOWNLOAD_NOTICE}

-
- - -
- {L_SECURE_TITLE} -

{L_DOWNLOAD_ADD_IPS_EXPLAIN}

-
-
-
-
-
-

{L_EXCLUDE_ENTERED_IP}
-
-
-
- -

- -

-
- -
- {L_REMOVE_IPS} - -

{L_DOWNLOAD_REMOVE_IPS_EXPLAIN}

-
-
-
-
- -

- -

-
- - -

{L_NO_IPS_DEFINED}

- - {S_FORM_TOKEN} - -
- - - - - - -
-
- - - - {L_LEGEND} -
-
-
-
-
-

{L_SPECIAL_CATEGORY_EXPLAIN}
-
{S_CATEGORY_SELECT}
-
-
-
-
checked="checked" />
-
-
-
-
checked="checked" />
-
-
-
-
-
 src="{ROOT_PATH}images/spacer.gif"src="{UPLOAD_ICON_SRC}" id="image_upload_icon" alt="" title="" /> 
-
-
-
-
-
-
-
-
{ASSIGNED_EXTENSIONS}
[{L_GO_TO_EXTENSIONS} ]
-
-
-
-

{L_ALLOWED_FORUMS_EXPLAIN}
-
-
-
-
- -

-   - -

- {S_FORM_TOKEN} -
- -
- - -
-
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - -
{L_EXTENSION_GROUP}{L_SPECIAL_CATEGORY}{L_OPTIONS}
 
{groups.GROUP_NAME} -
» {L_NOT_ALLOWED_IN_PM} -
» {L_ONLY_ALLOWED_IN_PM} -
» {L_NOT_ALLOWED_IN_PM_POST} -
» {L_ALLOWED_IN_PM_POST} -
{groups.CATEGORY} {ICON_EDIT}  {ICON_DELETE} 
-

- {L_CREATE_GROUP}{L_COLON} - -

- {S_FORM_TOKEN} -
-
- - - - - -
-
- {L_ADD_EXTENSION} -
-
-
-
-
-
-
{GROUP_SELECT_OPTIONS}
-
- -

- -

- {S_FORM_TOKEN} -
-
- -
- -
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - -
{L_EXTENSION}{L_EXTENSION_GROUP}{L_DELETE}
 
{extensions.EXTENSION}{extensions.GROUP_OPTIONS}
- -

-   - -

- {S_FORM_TOKEN} -
-
- - - -
- -
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_FILENAME}{L_FILEDATE}{L_FILESIZE}{L_ATTACH_POST_ID}{L_ATTACH_TO_POST}{L_DELETE}
{orphan.REAL_FILENAME}{orphan.FILETIME}{orphan.FILESIZE}{L_ATTACH_ID}{L_COLON}
 {L_MARK_ALL} :: {L_UNMARK_ALL}{L_MARK_ALL} :: {L_UNMARK_ALL}
- -
-

{L_NO_ATTACHMENTS}

-
- - - - - - - -

-   - -

- - - {S_FORM_TOKEN} -
-
- - - -
- -
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - -
{L_FILENAME}{L_POSTED}{L_FILESIZE}{L_MARK}
- {L_EXTENSION_GROUP}{L_COLON} {attachments.EXT_GROUP_NAME}{L_NO_EXT_GROUP}
{attachments.L_DOWNLOAD_COUNT}
{L_IN} {L_PRIVATE_MESSAGE} - {attachments.REAL_FILENAME}
{attachments.COMMENT}
{attachments.L_DOWNLOAD_COUNT}
{L_TOPIC}{L_COLON} {attachments.TOPIC_TITLE} -
{attachments.FILETIME}
{L_POST_BY_AUTHOR} {attachments.ATTACHMENT_POSTER}
{attachments.FILESIZE}
- -
-

{L_NO_ATTACHMENTS}

-
- - - - - - -
- {L_DISPLAY_LOG}{L_COLON}  {S_LIMIT_DAYS} {L_SORT_BY}{L_COLON} {S_SORT_KEY} {S_SORT_DIR} - -
- -
- - -
-
-

- {L_MARK_ALL} • - {L_UNMARK_ALL} -

-
- - {S_FORM_TOKEN} -
-
- - -
- {L_RESYNC_STATS} -
-
-

{L_RESYNC_FILES_STATS_EXPLAIN}
-
-
-
-
- - - - diff --git a/install/update/old/adm/style/acp_avatar_options_upload.html b/install/update/old/adm/style/acp_avatar_options_upload.html deleted file mode 100644 index 63a734e..0000000 --- a/install/update/old/adm/style/acp_avatar_options_upload.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
-
-
- - -
-

{L_UPLOAD_AVATAR_URL_EXPLAIN}
-
-
- diff --git a/install/update/old/adm/style/acp_ban.html b/install/update/old/adm/style/acp_ban.html deleted file mode 100644 index f224994..0000000 --- a/install/update/old/adm/style/acp_ban.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - -

{L_ACP_BAN_EXPLAIN}

- -

{L_TITLE}

- -

{L_EXPLAIN}

- - - -
- -
- {L_TITLE} -
-
-
-
[ {L_FIND_USERNAME} ]
-
-
-
-
- -
-
-

{L_BAN_EXCLUDE_EXPLAIN}
-
-
-
-
-
-
-
-
-
-
-
- -

-   - -

-{S_FORM_TOKEN} -
-
- -

- -

{L_UNBAN_TITLE}

- -

{L_UNBAN_EXPLAIN}

- -
- -
- {L_UNBAN_TITLE} - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -

-   - -

- {S_FORM_TOKEN} -
- - - -

{L_NO_BAN_CELL}

- {S_FORM_TOKEN} - - - - -
- - diff --git a/install/update/old/adm/style/acp_contact.html b/install/update/old/adm/style/acp_contact.html deleted file mode 100644 index 828fd4b..0000000 --- a/install/update/old/adm/style/acp_contact.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - -

{L_ACP_CONTACT_SETTINGS}

- -

{L_ACP_CONTACT_SETTINGS_EXPLAIN}

- -
-
- {L_GENERAL_OPTIONS} -
-

{L_CONTACT_US_ENABLE_EXPLAIN}
-
- - -
-
-
- - -
- {L_CONTACT_US_INFO_PREVIEW} -

{CONTACT_US_INFO_PREVIEW}

-
- - -
- {L_CONTACT_US_INFO} -

{L_CONTACT_US_INFO_EXPLAIN}

- - - -
-
-
- -
- -
- -
- - - - - - - - - -
-
{L_OPTIONS}{L_COLON} {BBCODE_STATUS} :: {IMG_STATUS} :: {FLASH_STATUS} :: {URL_STATUS} :: {SMILIES_STATUS}
-
-
- -
-   - - {S_FORM_TOKEN} -
-
- - diff --git a/install/update/old/adm/style/acp_database.html b/install/update/old/adm/style/acp_database.html deleted file mode 100644 index ed0f4dd..0000000 --- a/install/update/old/adm/style/acp_database.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - -

{L_ACP_RESTORE}

- -

{L_ACP_RESTORE_EXPLAIN}

- - -
- -
- {L_RESTORE_OPTIONS} -
-
-
-
- -

-   -   -

- {S_FORM_TOKEN} -
-
- -
-

{L_ACP_NO_ITEMS}

-
- - - -

{L_ACP_BACKUP}

- -

{L_ACP_BACKUP_EXPLAIN}

- - - -
- -
- {L_BACKUP_OPTIONS} -
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
{L_SELECT_ALL} :: {L_DESELECT_ALL}
-
- -

-   - -

- {S_FORM_TOKEN} -
-
- - - - diff --git a/install/update/old/adm/style/acp_ext_list.html b/install/update/old/adm/style/acp_ext_list.html deleted file mode 100644 index 8e2c745..0000000 --- a/install/update/old/adm/style/acp_ext_list.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - -

{L_EXTENSIONS_ADMIN}

- -

{L_EXTENSIONS_EXPLAIN}

- -
- {L_BROWSE_EXTENSIONS_DATABASE}{L_VERSIONCHECK_FORCE_UPDATE_ALL}{L_SETTINGS} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_EXTENSION_NAME}{L_CURRENT_VERSION}{L_EXTENSION_OPTIONS}{L_EXTENSION_ACTIONS}
{L_EXTENSIONS_ENABLED}
{enabled.META_DISPLAY_NAME} - - {enabled.META_VERSION} - - - {enabled.META_VERSION} - - {L_DETAILS} - - title="{enabled.actions.L_ACTION_EXPLAIN}">{enabled.actions.L_ACTION} -  |  - -
{L_EXTENSIONS_DISABLED}
{disabled.META_DISPLAY_NAME} - - {disabled.META_VERSION} - - - {disabled.META_VERSION} - - - {L_DETAILS} - - - title="{disabled.actions.L_ACTION_EXPLAIN}">{disabled.actions.L_ACTION} -  |  - -
- - - - - - - - - - - - - - - - - - - - - -
{L_EXTENSION_INSTALL_HEADLINE}
{L_EXTENSION_INSTALL_EXPLAIN}
{L_EXTENSION_UPDATE_HEADLINE}
{L_EXTENSION_UPDATE_EXPLAIN}
{L_EXTENSION_REMOVE_HEADLINE}
{L_EXTENSION_REMOVE_EXPLAIN}
- - diff --git a/install/update/old/adm/style/acp_forums.html b/install/update/old/adm/style/acp_forums.html deleted file mode 100644 index 965438f..0000000 --- a/install/update/old/adm/style/acp_forums.html +++ /dev/null @@ -1,519 +0,0 @@ - - - - - - - - - « {L_BACK} - -

{L_TITLE} :: {FORUM_NAME}

- -

{L_FORUM_EDIT_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -
- -
- {L_FORUM_SETTINGS} - -
-
-
-
- -
-
-
-
-
-
-
- - - - -
-
-
-
- -
-

{L_COPY_PERMISSIONS_EXPLAIN}
-
-
- -
-
-
-
-
-

{L_FORUM_DESC_EXPLAIN}
-
-
- -
-
-
-

{L_FORUM_IMAGE_EXPLAIN}
-
- -
{L_FORUM_IMAGE}
- -
-
-

{L_FORUM_PASSWORD_EXPLAIN}
-
-
-
-

{L_FORUM_PASSWORD_CONFIRM_EXPLAIN}
-
-
- -
-

{L_FORUM_PASSWORD_UNSET_EXPLAIN}
-
-
- -
-
-
-
- -
- -
-
- {L_GENERAL_FORUM_SETTINGS} -
-

{L_DISPLAY_ACTIVE_TOPICS_EXPLAIN}
-
-
-
-
-
- -
-
- {L_GENERAL_FORUM_SETTINGS} - -
-
-
-
-
-

{L_LIST_SUBFORUMS_EXPLAIN}
-
-
-
-
-

{L_LIST_INDEX_EXPLAIN}
-
-
-
-
-

{L_ENABLE_POST_REVIEW_EXPLAIN}
-
-
-
-
-

{L_ENABLE_QUICK_REPLY_EXPLAIN}
-
-
-
-
-

{L_ENABLE_INDEXING_EXPLAIN}
-
-
-
-
-
-
-
-
-
-

{L_ENABLE_RECENT_EXPLAIN}
-
-
-
-
-

{L_FORUM_TOPICS_PAGE_EXPLAIN}
-
-
- -
- -
- {L_FORUM_PRUNE_SETTINGS} - -
-

{L_FORUM_AUTO_PRUNE_EXPLAIN}
-
-
-
-
-

{L_AUTO_PRUNE_FREQ_EXPLAIN}
-
{L_DAYS}
-
-
-

{L_AUTO_PRUNE_DAYS_EXPLAIN}
-
{L_DAYS}
-
-
-

{L_AUTO_PRUNE_VIEWED_EXPLAIN}
-
{L_DAYS}
-
-
-

{L_PRUNE_OLD_POLLS_EXPLAIN}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

{L_FORUM_PRUNE_SHADOW_EXPLAIN}
-
-
-
-
-

{L_AUTO_PRUNE_SHADOW_FREQ_EXPLAIN}
-
{L_DAYS}
-
-
-

{L_AUTO_PRUNE_SHADOW_DAYS_EXPLAIN}
-
{L_DAYS}
-
- -
-
- - - -
-
- {L_FORUM_RULES} - -
-

{L_FORUM_RULES_LINK_EXPLAIN}
-
-
- -
-
-
{FORUM_RULES_PREVIEW}
-
- -
-

{L_FORUM_RULES_EXPLAIN}
-
-
- -
-
- -
-
- - - -
- {L_SUBMIT} -   - - {S_FORM_TOKEN} -
-
- - - - « {L_BACK} - -

{L_FORUM_DELETE}

- -

{L_FORUM_DELETE_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -
- -
- {L_FORUM_DELETE} -
-
-
{FORUM_NAME}
-
- -
-
-
- -
- -
- - -
-
-
- -
- -
- - -

- -

- {S_FORM_TOKEN} -
-
- - - - - -

{L_FORUM_ADMIN}

- -

{L_FORUM_ADMIN_EXPLAIN}

- -

{L_PROGRESS_EXPLAIN}

- - - - - -

{L_FORUM_ADMIN}

- -

{L_FORUM_ADMIN_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - - - - -
-

{L_NOTIFY}

-

{L_FORUM_RESYNCED}

-
- - -

{NAVIGATION} [{L_EDIT} | {L_DELETE} | {L_RESYNC}]

- - - - - - - - - - - - - -
{forums.FOLDER_IMAGE} -
{forums.FORUM_IMAGE}
- {forums.FORUM_NAME}{forums.FORUM_NAME} -
{forums.FORUM_DESCRIPTION} -

{L_TOPICS}{L_COLON} {forums.FORUM_TOPICS} / {L_POSTS}{L_COLON} {forums.FORUM_POSTS} -
- - {ICON_MOVE_UP} - - {ICON_MOVE_DOWN} - {ICON_EDIT} - - {ICON_SYNC} - - {ICON_SYNC_DISABLED} - - {ICON_DELETE} -
- - -
- -
- {L_SELECT_FORUM}{L_COLON} - - - {S_FORM_TOKEN} -
-
- -
- -
- - - - - {S_FORM_TOKEN} -
-
- - - - diff --git a/install/update/old/adm/style/acp_groups.html b/install/update/old/adm/style/acp_groups.html deleted file mode 100644 index d009637..0000000 --- a/install/update/old/adm/style/acp_groups.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - « {L_BACK} - -

{L_ACP_GROUPS_MANAGE}

- -

{L_GROUP_EDIT_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -
- -
- {L_GROUP_DETAILS} -
-
for="group_name">{L_GROUP_NAME}{L_COLON}
-
{GROUP_NAME}
-
-
-
-
-
- -
-
- -
-

{L_GROUP_TYPE_EXPLAIN}
-
- - - - -
-
- - - - - -
-

{L_COPY_PERMISSIONS_EXPLAIN}
-
-
- -
- -
- {L_GROUP_OPTIONS_SAVE} - - -
-

{L_GROUP_FOUNDER_MANAGE_EXPLAIN}
-
-
- -
-

{L_GROUP_SKIP_AUTH_EXPLAIN}
-
-
-
-
-
-
-
-
-
-
-
-

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

{L_GROUP_MESSAGE_LIMIT_EXPLAIN}
-
-
-
-

{L_GROUP_MAX_RECIPIENTS_EXPLAIN}
-
-
-
-

{L_GROUP_COLOR_EXPLAIN}
-
- -        - [ {L_COLOUR_SWATCH} ] - -
-
-
-
-
-
-
- -
- {L_GROUP_AVATAR} -
-

{L_AVATAR_EXPLAIN}
-
{AVATAR}
-
-
-
-
-
-
-
- -
-

{avatar_drivers.L_EXPLAIN}

- {avatar_drivers.OUTPUT} -
- -
-
- -
- {L_SUBMIT} -   - - {S_FORM_TOKEN} -
-
- - - - « {L_BACK} - -

{L_GROUP_MEMBERS} :: {GROUP_NAME}

- -

{L_GROUP_MEMBERS_EXPLAIN}

- -
- -
- » {L_MAKE_DEFAULT_FOR_ALL} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_USERNAME}{L_GROUP_DEFAULT}{L_JOINED}{L_POSTS}{L_MARK}
{L_GROUP_LEAD}
{leader.USERNAME}{leader.USERNAME}{L_YES}{L_NO}{leader.JOINED}{leader.USER_POSTS}
{L_GROUPS_NO_MODS}
{L_GROUP_APPROVED}
{L_GROUP_PENDING}
{member.USERNAME}{member.USERNAME}{L_YES}{L_NO}{member.JOINED}{member.USER_POSTS}
{L_GROUPS_NO_MEMBERS}
- - -
- - -

{L_MARK_ALL}{L_UNMARK_ALL}

-
- -

{L_ADD_USERS}

- -

{L_ADD_USERS_EXPLAIN}

- -
- {L_ADD_USERS} -
-
-
-
-
-
-

{L_USER_GROUP_DEFAULT_EXPLAIN}
-
-
-
-
-

{L_USERNAMES_EXPLAIN}
-
-
[ {L_FIND_USERNAME} ]
-
- -

- -

- {S_FORM_TOKEN} -
-
- - - -

{L_ACP_GROUPS_MANAGE}

- -

{L_ACP_GROUPS_MANAGE_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -

{L_USER_DEF_GROUPS}

- -

{L_USER_DEF_GROUPS_EXPLAIN}

- -
- - - - - - - - - - - - - - - - - - - - - - -
{L_GROUP}{L_TOTAL_MEMBERS}{L_PENDING_MEMBERS}{L_OPTIONS}{L_ACTION}
{L_NO_GROUPS_CREATED}
- - -
- - {L_CREATE_GROUP}{L_COLON} - - - {S_FORM_TOKEN} -
-
- -

{L_SPECIAL_GROUPS}

- -

{L_SPECIAL_GROUPS_EXPLAIN}

- - - - - - - - - - - - - - - - - - - - - - - - - -
{L_GROUP}{L_TOTAL_MEMBERS}{L_PENDING_MEMBERS}{L_OPTIONS}{L_ACTION}
style="color: #{groups.GROUP_COLOR}">{groups.GROUP_NAME}{groups.TOTAL_MEMBERS}{groups.PENDING_MEMBERS}{L_SETTINGS}{L_MEMBERS}{L_DELETE}{L_DELETE}
- - - - diff --git a/install/update/old/adm/style/acp_help_phpbb.html b/install/update/old/adm/style/acp_help_phpbb.html deleted file mode 100644 index 478ecc1..0000000 --- a/install/update/old/adm/style/acp_help_phpbb.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - -

{L_ACP_HELP_PHPBB}

- -
-
- -
-

{L_SEND_STATISTICS}

-

{L_EXPLAIN_SEND_STATISTICS}

-
- -
-
- -
- {providers.NAME} - -
-
{providers.values.KEY}
-
{providers.values.VALUE}
-
- -
- -
-
-
-
-
- checked="checked" /> - -
-
{L_SEND_STATISTICS_LONG}
-
-
- -
-

- - - -

- {S_FORM_TOKEN} -
-
-
-
-
-

- - -

-
-
- - diff --git a/install/update/old/adm/style/acp_icons.html b/install/update/old/adm/style/acp_icons.html deleted file mode 100644 index 5493cbd..0000000 --- a/install/update/old/adm/style/acp_icons.html +++ /dev/null @@ -1,282 +0,0 @@ - - - - - - - - - « {L_BACK} - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- -
- {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_CONFIG}
{L_URL}{L_LOCATION}{L_SMILIES_CODE}{L_SMILIES_EMOTION}{L_WIDTH}{L_HEIGHT}{L_ALT_TEXT}{L_DISPLAY_ON_POSTING}{L_ORDER}{L_ADD} ({L_MARK_ALL})
{items.TEXT_ALT}[{items.IMG}] - - - - -
{L_ADD_SMILEY_CODE}
{L_NO_ICONS}
- -

-   - -

- {S_FORM_TOKEN} -
-
- - - - « {L_BACK} - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- -
- {L_IMPORT} - - -

{L_NO_PAK_OPTIONS}

- - -
-
-
-
-

{L_CURRENT_EXPLAIN}
-
- -
- - -

- -

- - {S_FORM_TOKEN} -
-
- - - -

{L_TITLE}

- -

{L_EXPLAIN}

- - -
-

{L_NOTIFY}

-

{NOTICE}

-
- - -
- - - -
- - {L_TITLE} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_TITLE}{L_CODE}{L_EMOTION}{L_OPTIONS}
{L_NOT_DISPLAYED}
{items.ALT_TEXT}{items.CODE}{items.EMOTION} - - {ICON_MOVE_UP} - - {ICON_MOVE_DOWN} - {ICON_EDIT} {ICON_DELETE} -
{L_ACP_NO_ITEMS}
- -

-     -

- {S_FORM_TOKEN} -
-
- - - - diff --git a/install/update/old/adm/style/acp_language.html b/install/update/old/adm/style/acp_language.html deleted file mode 100644 index 79fef94..0000000 --- a/install/update/old/adm/style/acp_language.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - « {L_BACK} - -

{L_LANGUAGE_PACK_DETAILS}

- -
- -
- {LANG_LOCAL_NAME} -
-
-
-
-
-
-
-
-
-
-
{LANG_ISO}
-
-
-
-
-
- -

- -

- {S_FORM_TOKEN} -
-
- - -

{L_MISSING_FILES}

- -
- {L_MISSING_LANG_FILES} - - » {missing_files.FILE_NAME}
- -
- - - -

{L_MISSING_VARS_EXPLAIN}

- -
- {L_MISSING_LANG_VARIABLES} - -
-
- -
{missing_varfile.variable.VAR_NAME}
- -
- -
- - - -

{L_ACP_LANGUAGE_PACKS}

- -

{L_ACP_LANGUAGE_PACKS_EXPLAIN}

- -
- {L_BROWSE_LANGUAGE_PACKS_DATABASE} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_LANGUAGE_PACK_NAME}{L_LANGUAGE_PACK_LOCALNAME}{L_LANGUAGE_PACK_ISO}{L_LANGUAGE_PACK_USED_BY}{L_OPTIONS}
{L_INSTALLED_LANGUAGE_PACKS}
{lang.ENGLISH_NAME} {lang.TAG}{lang.LOCAL_NAME}{lang.ISO}{lang.USED_BY}{L_DELETE}
{L_UNINSTALLED_LANGUAGE_PACKS}
{notinst.NAME}{notinst.LOCAL_NAME}{notinst.ISO}{L_INSTALL}
- - - - diff --git a/install/update/old/adm/style/acp_main.html b/install/update/old/adm/style/acp_main.html deleted file mode 100644 index 12477a4..0000000 --- a/install/update/old/adm/style/acp_main.html +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - -

{L_PERMISSIONS_TRANSFERRED}

- -

{L_PERMISSIONS_TRANSFERRED_EXPLAIN}

- - - -

{L_WELCOME_PHPBB}

- -

{L_ADMIN_INTRO}

- - -
-

{L_UPDATE_INCOMPLETE} {L_MORE_INFORMATION}

-
- -
-

{L_VERSIONCHECK_FAIL}

-

{VERSIONCHECK_FAIL_REASON}

-

{L_VERSIONCHECK_FORCE_UPDATE} · {L_MORE_INFORMATION}

-
- -
-

{L_VERSION_NOT_UP_TO_DATE_TITLE}

-

{L_VERSIONCHECK_FORCE_UPDATE} · {L_MORE_INFORMATION}

-
- - -
-

{UPGRADE_INSTRUCTIONS}

-
- - - -
-

{L_WARNING}

-

{L_NO_SEARCH_INDEX}

-
- - - -
-

{L_WARNING}

-

{L_REMOVE_INSTALL}

-
- - - - -
-

{L_ERROR_MBSTRING_FUNC_OVERLOAD}

-

{L_ERROR_MBSTRING_FUNC_OVERLOAD_EXPLAIN}

-
- - - -
-

{L_ERROR_MBSTRING_ENCODING_TRANSLATION}

-

{L_ERROR_MBSTRING_ENCODING_TRANSLATION_EXPLAIN}

-
- - - -
-

{L_ERROR_MBSTRING_HTTP_INPUT}

-

{L_ERROR_MBSTRING_HTTP_INPUT_EXPLAIN}

-
- - - -
-

{L_ERROR_MBSTRING_HTTP_OUTPUT}

-

{L_ERROR_MBSTRING_HTTP_OUTPUT_EXPLAIN}

-
- - - - -
-

{L_WRITABLE_CONFIG}

-
- - - -
-

{L_PHP_VERSION_OLD}

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_FORUM_STATS}
{L_STATISTIC}{L_VALUE}{L_STATISTIC}{L_VALUE}
{L_NUMBER_POSTS}{L_COLON} {TOTAL_POSTS}{L_POSTS_PER_DAY}{L_COLON} {POSTS_PER_DAY}
{L_NUMBER_TOPICS}{L_COLON} {TOTAL_TOPICS}{L_TOPICS_PER_DAY}{L_COLON} {TOPICS_PER_DAY}
{L_NUMBER_USERS}{L_COLON} {TOTAL_USERS}{L_USERS_PER_DAY}{L_COLON} {USERS_PER_DAY}
{L_NUMBER_FILES}{L_COLON} {TOTAL_FILES}{L_FILES_PER_DAY}{L_COLON} {FILES_PER_DAY}
{L_BOARD_STARTED}{L_COLON} {START_DATE}{L_AVATAR_DIR_SIZE}{L_COLON} {AVATAR_DIR_SIZE}
{L_DATABASE_SIZE}{L_COLON} {DBSIZE}{L_UPLOAD_DIR_SIZE}{L_COLON} {UPLOAD_DIR_SIZE}
{L_DATABASE_SERVER_INFO}{L_COLON} {DATABASE_INFO}{L_GZIP_COMPRESSION}{L_COLON} {GZIP_COMPRESSION}
{L_PHP_VERSION}{L_COLON} {PHP_VERSION_INFO}{L_NUMBER_ORPHAN}{L_COLON} - - {TOTAL_ORPHAN} - - {TOTAL_ORPHAN} - -   
{L_BOARD_VERSION}{L_COLON} - style="color: #228822;" style="color: #BC2A4D;" title="{L_MORE_INFORMATION}">{BOARD_VERSION}{L_VERSIONCHECK_FORCE_UPDATE} ] -   
- - -
- {L_STATISTIC_RESYNC_OPTIONS} - -
-
-

 
-
-
-
- -
-
-

 
-
-
-
- -
-
-

{L_RESYNC_STATS_EXPLAIN}
-
-
-
- -
-
-

{L_RESYNC_POSTCOUNTS_EXPLAIN}
-
-
-
- -
-
-

{L_RESYNC_POST_MARKING_EXPLAIN}
-
-
-
- - -
-
-

{L_PURGE_SESSIONS_EXPLAIN}
-
-
-
- - -
-
-

{L_PURGE_CACHE_EXPLAIN}
-
-
-
- - -
- - - -

{L_ADMIN_LOG}

- -

{L_ADMIN_LOG_INDEX_EXPLAIN}

- - - - - - - - - - - - - - - - - - - - - - -
{L_USERNAME}{L_IP}{L_TIME}{L_ACTION}
{log.USERNAME}{log.IP}{log.DATE}{log.ACTION}
- - - -

{L_INACTIVE_USERS}

- -

{L_INACTIVE_USERS_EXPLAIN_INDEX}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_USERNAME}{L_JOINED}{L_INACTIVE_DATE}{L_LAST_VISIT}{L_INACTIVE_REASON}
- {inactive.USERNAME_FULL} -
{L_POSTS}{L_COLON} {inactive.POSTS} [{L_SEARCH_USER_POSTS}] -
{inactive.JOINED}{inactive.INACTIVE_DATE}{inactive.LAST_VISIT} - {inactive.REASON} -
{inactive.REMINDED_EXPLAIN} -
{L_NO_INACTIVE_USERS}
- - - - - diff --git a/install/update/old/adm/style/acp_modules.html b/install/update/old/adm/style/acp_modules.html deleted file mode 100644 index 3c97706..0000000 --- a/install/update/old/adm/style/acp_modules.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - « {L_BACK} - -

{L_TITLE} :: {MODULENAME}

- -

{L_EDIT_MODULE_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - -
- -
- {L_GENERAL_OPTIONS} -
-

- {L_MODULE_LANGNAME_EXPLAIN}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
style="display: none;"> -
-

{L_MODULE_DISPLAYED_EXPLAIN}
-
-
-
-
-

- {L_CHOOSE_MODULE_EXPLAIN}
-
-
-
-

- {L_CHOOSE_MODE_EXPLAIN}
-
-
-
- -

- - - -   - -

- {S_FORM_TOKEN} -
-
- - - -

{L_ACP_MODULE_MANAGEMENT}

- -

{L_ACP_MODULE_MANAGEMENT_EXPLAIN}

- - -
-

{L_WARNING}

-

{ERROR_MSG}

-
- - - - - - - - -
{NAVIGATION} [{L_EDIT} | {L_DELETE} | {L_DISABLE}{L_ENABLE}]
- - - - - - - - - - - - - - -
{modules.MODULE_IMAGE}{modules.MODULE_TITLE} [{L_HIDDEN_MODULE}] {L_DISABLE}{L_ENABLE}  - - {ICON_MOVE_UP} - - {ICON_MOVE_DOWN} - {ICON_EDIT} - {ICON_DELETE} -
- - -
 
- -
- -
- - - - -
- -
- -
- -
- - - - - -
- -
- -
 

- -
-
- {L_SELECT_MODULE}{L_COLON} - - -
-
- - - - diff --git a/install/update/old/adm/style/acp_permission_roles.html b/install/update/old/adm/style/acp_permission_roles.html deleted file mode 100644 index b3137f1..0000000 --- a/install/update/old/adm/style/acp_permission_roles.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - « {L_BACK} - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- » {L_SET_ROLE_PERMISSIONS} - -
- -
- {L_ROLE_DETAILS} -
-
-
-
-
-

{L_ROLE_DESCRIPTION_EXPLAIN}
-
-
- -

- - {S_FORM_TOKEN} -

-
- - - -

{L_ROLE_ASSIGNED_TO}

- - - - - -

- - - - » {L_BACK_TO_TOP}
-

- -

- -

{L_ACL_TYPE}

- -
- -
-
- -
- -
style="display: none;"> -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
{L_ACL_SETTING}{L_ACL_YES}{L_ACL_NO}{L_ACL_NEVER}
{auth.mask.PERMISSION}
-
-
- -
- -
- -
- - {S_FORM_TOKEN} -
-
- - » {L_BACK_TO_TOP}
-
- - - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- - - - - - - - - - - - - - - - - - -
{L_ROLE_NAME}{L_OPTIONS}
{roles.ROLE_NAME} -
{roles.ROLE_DESCRIPTION} -
{L_VIEW_ASSIGNED_ITEMS}{L_VIEW_ASSIGNED_ITEMS} - - {ICON_MOVE_UP} - - {ICON_MOVE_DOWN} - {ICON_EDIT} - {ICON_DELETE} -
- -
- {L_CREATE_ROLE}{L_COLON}
- {S_FORM_TOKEN} -
-
- - - - - -

{L_ROLE_ASSIGNED_TO}

- - - - - - - - diff --git a/install/update/old/adm/style/acp_posting_buttons.html b/install/update/old/adm/style/acp_posting_buttons.html deleted file mode 100644 index c3c42f8..0000000 --- a/install/update/old/adm/style/acp_posting_buttons.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- diff --git a/install/update/old/adm/style/acp_ranks.html b/install/update/old/adm/style/acp_ranks.html deleted file mode 100644 index e67c9ac..0000000 --- a/install/update/old/adm/style/acp_ranks.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - « {L_BACK} - - - -

{L_ACP_MANAGE_RANKS}

- -

{L_ACP_RANKS_EXPLAIN}

- -
- -
- {L_ACP_RANKS} - - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
style="display: none;"> -
-
-
-
-
- - - -

- - -   - - {S_FORM_TOKEN} -

-
-
- - - -

{L_ACP_MANAGE_RANKS}

- -

{L_ACP_RANKS_EXPLAIN}

- -
-
- {L_ACP_MANAGE_RANKS} - - - - - - - - - - - - - - - - - - - - - - - - -
{L_RANK_IMAGE}{L_RANK_TITLE}{L_RANK_MINIMUM}{L_ACTION}
{ranks.RANK_TITLE}  -  {ranks.RANK_TITLE}  -  {ranks.MIN_POSTS}{ICON_EDIT} {ICON_DELETE}
- -

- - {S_FORM_TOKEN} -

-
-
- - - - diff --git a/install/update/old/adm/style/acp_search.html b/install/update/old/adm/style/acp_search.html deleted file mode 100644 index f7ad3c5..0000000 --- a/install/update/old/adm/style/acp_search.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - -

{L_ACP_SEARCH_SETTINGS}

- -

{L_ACP_SEARCH_SETTINGS_EXPLAIN}

- - - - - - - -

{L_ACP_SEARCH_INDEX}

- - -

{L_CONTINUE_EXPLAIN}

- -
-
- {L_SUBMIT} -   - - {S_FORM_TOKEN} -
-
- - -

{L_ACP_SEARCH_INDEX_EXPLAIN}

- - - - - -
- -
- - {backend.S_HIDDEN_FIELDS} - - {L_INDEX_STATS}{L_COLON} {backend.L_NAME} ({L_ACTIVE}) - - - - - - - - - - - - - - - - - - - - - - -
{backend.L_NAME} ({L_ACTIVE})
{L_STATISTIC}{L_VALUE}{L_STATISTIC}{L_VALUE}
{backend.data.STATISTIC_1}{L_COLON}{backend.data.VALUE_1}{backend.data.STATISTIC_2}{L_COLON}{backend.data.VALUE_2}
- - - -

- - - - - - - -

- {S_FORM_TOKEN} -
- -
- - - - - - - diff --git a/install/update/old/adm/style/acp_styles.html b/install/update/old/adm/style/acp_styles.html deleted file mode 100644 index 38bec5a..0000000 --- a/install/update/old/adm/style/acp_styles.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - « {L_BACK} - - - -
- -
-

{MESSAGE_TITLE}

-

{MESSAGE_TEXT}

- - - - - {S_HIDDEN_FIELDS} - -
-   - -
- -
- -
- - -

{L_TITLE}

- -

{L_EXPLAIN}

- -
- {L_BROWSE_STYLES_DATABASE} -
- -
-{S_HIDDEN_FIELDS} -{S_FORM_TOKEN} - - - -
-
-
-
-
-
-
-
{STYLE_PATH}
-
-
-
-
{STYLE_VERSION}
-
-
-
-
{STYLE_COPYRIGHT}
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- -
- -
- {L_SUBMIT} -   - - {S_FORM_TOKEN} -
- - - - - - - - - - - - {STYLES_LIST_EXTRA} - - - - - - - - - - - - - - - - - - {styles_list.EXTRA} - - - - -
{L_STYLE_NAME}{L_STYLE_PHPBB_VERSION}{L_STYLE_USED_BY}{L_ACTIONS} 
- - - - - {styles_list.STYLE_NAME} -
{styles_list.STYLE_COPYRIGHT}
- - {styles_list.STYLE_NAME} - - -
{styles_list.COMMENT}
- - -
{L_STYLE_PATH}{L_COLON} {styles_list.STYLE_PATH_FULL}
- -
{styles_list.STYLE_PHPBB_VERSION}{styles_list.USERS} - - | - - {styles_list.actions.L_ACTION} - - {styles_list.actions.HTML} - - - - - - -   - - - - -
- - - -
- - - -
- - -
- - - - diff --git a/install/update/old/adm/style/acp_users_overview.html b/install/update/old/adm/style/acp_users_overview.html deleted file mode 100644 index 506101c..0000000 --- a/install/update/old/adm/style/acp_users_overview.html +++ /dev/null @@ -1,169 +0,0 @@ -
- -
- {L_ACP_USER_OVERVIEW} -
-

{L_NAME_CHARS_EXPLAIN}
-
-
[ {L_USE_PERMISSIONS} ]
-
- -
-
-
{USER_INACTIVE_REASON}
-
- -
-
-
{USER_REGISTERED}
-
- -
-
-
{REGISTERED_IP}
-
[ {L_WHOIS} ]
-
- -
-
-
{USER_LASTACTIVE}
-
-
-
-
- - - {USER_POSTS} - - {USER_POSTS} - - - - ({L_POSTS_IN_QUEUE}) - - ({L_POSTS_IN_QUEUE}) - -
-
-
-
-
{USER_WARNINGS}
-
-
-

{L_FOUNDER_EXPLAIN}
-
-
-
-
-
-
-
-
-

{L_CHANGE_PASSWORD_EXPLAIN}
-
-
-
-

{L_CONFIRM_PASSWORD_EXPLAIN}
-
-
- - -

- - - {S_FORM_TOKEN} -

- -
-
- - - - - -
- -
- {L_USER_TOOLS} -
-
-
-
- - -

- - {S_FORM_TOKEN} -

- -
- -
- - -
-
- {L_DELETE_USER} -
-

{L_DELETE_USER_EXPLAIN}
-
- - - - {L_USER_NO_POSTS_TO_DELETE} - -
-
-

- - - {S_FORM_TOKEN} -

-
-
- - diff --git a/install/update/old/adm/style/acp_users_prefs.html b/install/update/old/adm/style/acp_users_prefs.html deleted file mode 100644 index 484c5b3..0000000 --- a/install/update/old/adm/style/acp_users_prefs.html +++ /dev/null @@ -1,151 +0,0 @@ - - -
- -
- {L_UCP_PREFS_PERSONAL} - -
-
-
-
-
-
-
-
-
-
-
-

{L_ALLOW_PM_EXPLAIN}
-
-
-
-
-
-
-
-
-
-

{L_NOTIFY_METHOD_EXPLAIN}
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-

{L_BOARD_DATE_FORMAT_EXPLAIN}
-
-
style="display:none;">
-
- -
- -
- {L_UCP_PREFS_POST} - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
- -
- {L_UCP_PREFS_VIEW} - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{S_TOPIC_SORT_DAYS}
-
-
-
-
{S_TOPIC_SORT_KEY}
-
-
-
-
{S_TOPIC_SORT_DIR}
-
-
-
-
{S_POST_SORT_DAYS}
-
-
-
-
{S_POST_SORT_KEY}
-
-
-
-
{S_POST_SORT_DIR}
-
- -
- -
- - {S_FORM_TOKEN} -
- -
diff --git a/install/update/old/adm/style/acp_users_signature.html b/install/update/old/adm/style/acp_users_signature.html deleted file mode 100644 index c7ec5cc..0000000 --- a/install/update/old/adm/style/acp_users_signature.html +++ /dev/null @@ -1,52 +0,0 @@ - - -
- - -
- {L_ADMIN_SIG_PREVIEW} -

{SIGNATURE_PREVIEW}

-
- - -
- {L_SIGNATURE} -

{L_SIGNATURE_EXPLAIN}

- - - -
-
-
-
-
- - - - - - - - - -
-
{L_OPTIONS}{L_COLON} {BBCODE_STATUS} :: {IMG_STATUS} :: {FLASH_STATUS} :: {URL_STATUS} :: {SMILIES_STATUS}
-
-
- -
-   - - {S_FORM_TOKEN} -
-
diff --git a/install/update/old/adm/style/admin.css b/install/update/old/adm/style/admin.css deleted file mode 100644 index 7cf6c22..0000000 --- a/install/update/old/adm/style/admin.css +++ /dev/null @@ -1,2720 +0,0 @@ -/* phpBB 3.2 Admin Style Sheet - ------------------------------------------------------------------------ - Original author: subBlue ( http://www.subblue.com/ ) - Copyright (c) phpBB Limited - - For full copyright and license information, please see - the docs/CREDITS.txt file. - ------------------------------------------------------------------------ -*/ - -/* General markup styles ----------------------------------------- */ -* { - /* Reset browsers default margin, padding and font sizes */ - margin: 0; - padding: 0; - font-size: 100%; -} - -abbr { - text-decoration: none; -} - -body, div, p, th, td, li, dd { - font-size: x-small; - voice-family: "\"}\""; - voice-family: inherit; - font-size: small; -} - -html>body, html>div, html>p, html>th, html>td, html>li, html>dd { - font-size: small; -} - -html { - color: #536482; - background: #DBD7D1; - /* Always show a scrollbar for short pages - stops the jump when the scrollbar appears. non-ie browsers */ - height: 100%; - margin-bottom: 1px; - word-wrap: break-word; -} - -body { - /* Text-Sizing with ems: http://www.clagnut.com/blog/348/ */ - font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; - color: #536482; - background: #DBD7D1; - font-size: 62.5%; /* This sets the default font size to be equivalent to 10px */ - margin: 10px 15px; -} - -code, samp { - font-size: 1.2em; -} - -img { - border: 0; -} - -h1 { - font-family: "Trebuchet MS", Helvetica, sans-serif; - font-size: 1.70em; - font-weight: normal; - color: #333333; -} - -h2, caption { - font-family: "Trebuchet MS", Helvetica, sans-serif; - font-size: 1.40em; - font-weight: normal; - color: #115098; - text-align: left; - margin-top: 25px; -} - -.rtl h2, .rtl caption { - text-align: right; -} - -h3, h4 { - font-family: "Trebuchet MS", Helvetica, sans-serif; - font-size: 1.20em; - text-decoration: none; - line-height: 1.20em; - margin-top: 25px; -} - -p { - margin-bottom: 0.7em; - line-height: 1.40em; - font-size: 0.90em; -} - -ul { - list-style: disc; - margin: 0 0 1em 2em; -} - -.rtl ul { - margin: 0 2em 1em 0; -} - -hr { - border: 0 none; - border-top: 1px dashed #999999; - margin-bottom: 5px; - padding-bottom: 5px; - height: 1px; -} - -.centered-text { - text-align: center; -} - -.search-box { - float: left; -} - -.rtl .search-box { - float: right; -} - -.small { - font-size: 0.85em; -} - -.hidden { - display: none; -} - -@media only screen and (max-width: 800px), only screen and (max-device-width: 800px) -{ - body { - margin: 5px 5px 0; - } -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - html, body { - height: auto; - margin: 0; - padding: 0; - } -} - - -/* General links */ -a:link, a:visited { - color: #105289; - text-decoration: none; -} - -a:hover { - color: #BC2A4D; - text-decoration: underline; -} - -a:active { - color: #368AD2; - text-decoration: none; -} - -.install-body p a { - font-weight: bold; -} - -a#maincontent, a#acl, a#assigned_to { - display: block; -} - -/* List items */ -ul, ol { - list-style-position: inside; - margin-left: 1em; -} - -li { - display: list-item; - list-style-type: inherit; -} - - -/* Main blocks ----------------------------------------- */ -#wrap { - padding: 0 0 15px 0; - min-width: 615px; -} - -#page-header { - text-align: right; - background: url("../images/phpbb_logo.png") top left no-repeat; - height: 54px; - font-size: 0.85em; - margin-bottom: 10px; -} - -.rtl #page-header { - text-align: left; - background: url("../images/phpbb_logo.png") top right no-repeat; -} - -#page-header h1 { - color: #767676; - font-family: "Trebuchet MS",Helvetica,sans-serif; - font-size: 1.70em; - padding-top: 10px; -} - -#page-header p { - font-size: 1.00em; -} - -#page-header p#skip { - display: none; -} - -#page-body { - min-width: 650px; -} - -.copyright { - font-size: 0.75em; - text-align: center; -} - -#content { - padding: 30px 10px 10px; - position: relative; -} - -#content h1 { - color: #115098; - line-height: 1.2em; - margin-bottom: 0; -} - -#main { - float: right; - width: 100%; - margin: 0 0 0 -210px; -} - -.rtl #main { - float: left; - margin: 0 -210px 0 0; -} - -.main { - margin-left: 210px; -} - -.rtl .main { - margin-left: 0; - margin-right: 210px; -} - -#page-body.simple-page-body { - padding: 0; - padding-right: 10px; - min-width: 0; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - #wrap, #page-body, #page-body.simple-page-body { - padding: 0; - min-width: 300px; - } - - #page-header { - margin: 5px; - padding-left: 160px; - height: auto; - min-height: 54px; - overflow: hidden; - } - - .rtl #page-header { - padding-right: 160px; - padding-left: 0; - } - - #page-header h1 { - font-size: 1.2em; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - #page-header fieldset { - margin-top: 5px; - } - - #main, .rtl #main, .main, .rtl .main { - float: none; - width: auto; - margin: 0; - } - - #content { - background: #F3F3F3 url("../images/innerbox_bg.gif") repeat-x top; - padding: 5px; - } - - #page-footer { - padding: 0 5px 5px; - } -} - -@media only screen and (max-width: 400px), only screen and (max-device-width: 400px) -{ - #page-header { - background-size: 76px 26.5px; - padding-left: 80px; - min-height: 30px; - } - - .rtl #page-header { - padding-right: 80px; - } - - #page-header h1 { - padding-top: 0; - font-size: 1.1em; - } -} - - -/* Tabbed menu -----------------------------------------*/ -#tabs { - font-family: Arial, Helvetica, sans-serif; - line-height: normal; - margin: 0 7px; - position: relative; - z-index: 2; -} - -#tabs > ul { - list-style: none; - margin: 0; - padding: 0; -} - -#tabs .tab { - display: inline-block; - float: left; - font-size: 0.85em; - font-weight: bold; - line-height: 14px; -} - -.rtl #tabs .tab { - float: right; -} - -#tabs .tab > a { - background: #D4D6DA; - background: -moz-linear-gradient(top, #CACBCF 0%, #D4D6DA 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #CACBCF), color-stop(100%, #D4D6DA)); - background: -webkit-linear-gradient(top, #CACBCF 0%, #D4D6DA 100%); - background: -o-linear-gradient(top, #CACBCF 0%, #D4D6DA 100%); - background: -ms-linear-gradient(top, #CACBCF 0%, #D4D6DA 100%); - background: linear-gradient(to bottom, #CACBCF 0%, #D4D6DA 100%); - border: 1px solid #BBB; - border-bottom-width: 0; - border-radius: 5px 5px 0 0; - color: #767676; - display: block; - font-weight: bold; - margin: 1px 1px 2px 0; - padding: 6px 9px 4px; - position: relative; - text-decoration: none; - text-transform: uppercase; - white-space: nowrap; - cursor: pointer; -} - -#tabs .tab > a:hover { - background: #F1F1EE; - border-color: #C0BFBB; - color: #BC2A4D; -} - -#tabs .activetab > a, -#tabs .activetab > a:hover { - background: #DCDEE2; - background: -moz-linear-gradient(top, #F2F2F2 0%, #DCDEE2 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F2F2F2), color-stop(100%, #DCDEE2)); - background: -webkit-linear-gradient(top, #F2F2F2 0%, #DCDEE2 100%); - background: -o-linear-gradient(top, #F2F2F2 0%, #DCDEE2 100%); - background: -ms-linear-gradient(top, #F2F2F2 0%, #DCDEE2 100%); - background: linear-gradient(to bottom, #F2F2F2 0%, #DCDEE2 100%); - border-color: #999; - border-bottom: 2px solid #DCDEE2; - box-shadow: 0 1px 1px #FFF inset; - color: #23649F; - margin: 0 1px 0 0; - padding: 7px 10px 4px; -} - -#tabs .activetab > a:hover { - color: #115098; -} - -/* Responsive tabs -----------------------------------------*/ -.responsive-tab { - position: relative; -} - -.responsive-tab > a.responsive-tab-link { - display: block; - font-size: 16px; - position: relative; - width: 16px; - line-height: 14px; - text-decoration: none; - padding-left: 9px !important; - padding-right: 9px !important; -} - -.responsive-tab .responsive-tab-link:before { - content: ''; - position: absolute; - left: 10px; - top: 7px; - height: .125em; - width: 14px; - border-bottom: 0.125em solid #767676; - border-top: 0.375em double #767676; -} - -.responsive-tab .responsive-tab-link:hover:before { - border-color: #BC2A4D; -} - -.responsive-tab.activetab .responsive-tab-link:before { - border-color: #23649F; -} - -.responsive-tab.activetab .responsive-tab-link:hover:before { - border-color: #115098; -} - -#tabs .dropdown, #minitabs .dropdown { - top: 20px; - margin-right: -2px; - font-weight: normal; -} - -#tabs .dropdown-right .dropdown { - margin-left: -2px; -} - -#tabs .dropdown-contents { - list-style: none; - margin: 0; -} - -#tabs .dropdown li { - border-bottom: 1px dotted #DCDCDC; -} - -#tabs .dropdown li:last-child { - border-bottom: none; -} - -#tabs .dropdown a { - display: block; - padding: 4px 8px; - text-align: right; -} - -/* Main Panel ----------------------------------------- */ -#acp { - position: relative; - top: -2px; - margin: 0 0 2px; - padding: 3px 1px; - min-width: 550px; - background: #F3F3F3 url("../images/innerbox_bg.gif") repeat-x top; - border: 1px #999999 solid; - border-radius: 5px; - box-shadow: #FFF 0 0 0 1px inset; -} - -#acp:first-child { - top: 0; -} - -.panel { - background: #F3F3F3 url("../images/innerbox_bg.gif") repeat-x top; - padding: 5px 0; - border-radius: 5px; - overflow: hidden; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - #acp { - min-width: 0; - min-height: 0; - border-radius: 0; - border-width: 1px 0; - background: #fff; - padding: 1px 0; - box-shadow: none; - } -} - -/* Sub-navigation Menu ----------------------------------------- */ - -/* Menu */ -#menu { - float: left; - width: 200px; - font-size: 1.00em; - padding: 0; - border-right: 1px solid #CCCFD3; - position: relative; -} - -.rtl #menu { - float: right; - border: none; - border-left: 1px solid #CCCFD3; -} - -#menu p { - font-size: 0.85em; -} - -#menu ul { - list-style: none; - margin: 0; - padding: 0; - word-wrap: normal; -} - -/* Default list state */ -#menu li, #menu .header { - padding: 0; - margin: 0; - font-size: 0.85em; - font-weight: bold; - display: block; -} - -/* Link styles for the sub-section links */ -#menu li span { - display: block; - padding: 3px 3px 3px 8px; - margin: 1px 0; - text-decoration: none; - font-weight: normal; - color: #138ECB; -} - -.rtl #menu li span { - padding: 3px 8px 3px 3px; -} - -#menu li a:hover, #menu li a:hover span { - text-decoration: none; - background-color: #FFFFFF; - color: #BC2A4D; -} - -#menu li a:active, #menu li a:active span { - color: #F632A0; -} - -#menu li#activemenu a span { - text-decoration: none; - font-weight: bold; - color: #1180B7; - background: transparent url("../images/arrow_right.gif") 0% 50% no-repeat; -} - -.rtl #menu li#activemenu a span { - background: transparent url("../images/arrow_left.gif") 100% 50% no-repeat; -} - -#menu li#activemenu a:hover span, #menu li#activemenu span { - text-decoration: none; - font-weight: bold; - color: #BC2A4D; - background: #FFFFFF url("../images/arrow_right.gif") 1% 50% no-repeat; -} - -.rtl #menu li#activemenu a:hover span, .rtl #menu li#activemenu span { - background: #FFFFFF url("../images/arrow_left.gif") 99% 50% no-repeat; -} - -#menu li a:active, #menu li a:active span, #menu li#activemenu a:active span { - color: #F632A0; -} - -#menu li span.completed { - text-decoration: none; - padding: 3px 3px 3px 12px; - background: url("../images/arrow_down.gif") 1% 50% no-repeat; -} - -.rtl #menu li span.completed { - text-decoration: none; - padding: 3px 12px 3px 3px; - background: url("../images/arrow_down.gif") 99% 50% no-repeat; -} - -#menu .header { - font-family: Tahoma, Helvetica, sans-serif; - display: block; - font-weight: bold; - color: #115098; - border-bottom: 1px solid #327AA5; - padding: 4px 0 2px; - margin-top: 15px; - text-transform: uppercase; - font-size: 0.75em; - text-decoration: none; - cursor: inherit; - outline-style: none; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - #menu, .rtl #menu { - float: none; - width: auto; - border-width: 0; - max-width: 200px; - margin: 0 auto 10px; - } - - #menu p { - text-align: center; - } - - #menu .menu-block.active { - margin: 0 -5px; - padding: 0 5px 3px; - background: rgba(255, 255, 255, .5); - border-radius: 5px; - } - - #menu .menu-block.no-header.active { - padding-top: 3px; - } - - #menu .menu-block .header { - margin-top: 5px; - cursor: pointer; - border-bottom-width: 0; - position: relative; - text-decoration: underline; - } - - #menu .menu-block .header:focus, #menu .menu-block.active .header { - color: #D31141; - text-decoration: none; - } - - #menu .menu-block ul { - display: none; - } - - .nojs #menu .menu-block:hover ul, #menu .menu-block.active ul, #menu .menu-block.no-header ul { - display: block; - } - - #menu .menu-block li:last-child { - border-bottom: 1px solid #327AA5; - } - - #menu .menu-block:last-child li:last-child, #menu .menu-block.active li:last-child { - border-bottom-width: 0; - } - - #menu .menu-block li a span { - border-radius: 2px; - } -} - - -/* Table styles ----------------------------------------- */ - -table { - width: 100%; - border: 1px solid #CCCFD3; - background-color: #FFFFFF; - padding: 1px; -} - -th { - padding: 3px 4px; - color: #FFFFFF; - background: #70AED3 url("../images/gradient2b.gif") bottom left repeat-x; - border-top: 1px solid #6DACD2; - border-bottom: 1px solid #327AA5; - text-align: left; - font-size: 0.75em; - text-transform: uppercase; -} - -td { - text-align: left; - font-size: 0.85em; - padding: 4px; - line-height: 1.20em; -} - -.rtl th, .rtl td { - text-align: right; -} - -.table1 { - border-collapse: separate; - border-spacing: 1px; - clear: both; -} - -dt#color_palette_placeholder table { - margin-right: 5px; - width: 80px; -} - -#color_palette_placeholder td { - padding: 0; -} - -table.type2 { - border: none; - background: none; - padding: 0; -} - -table.type2 th { - background: none; - border-top: none; - text-align: center; - color: #115098; - padding: 2px 0; -} - -table.type2 td { - padding: 0; - font-size: 1em; -} - -table.type2 td.name { - padding: 2px; - vertical-align: middle; -} - -table.type3 { - float: right; - width: 300px; - border: none; - background-color: transparent; - padding: 0; -} - -.rtl table.type3 { - float: left; -} - -table.type3 thead th { - background-color: transparent; - border-top: none; - text-align: center; - color: #115098; - padding: 0 3px; - font-size: 0.85em; - font-weight: normal; - text-transform: none; -} - -table.type3 tbody th { - border-top: none; - text-align: left; - text-transform: none; - padding: 0; - border: none; - font-size: 0.90em; - font-weight: normal; - width: 100%; -} - -.rtl table.type3 tbody th { - text-align: right; -} - -table.type3 td { - text-align: center; - padding: 1px; -} - -th.name { - text-align: left; - width: auto; -} - -.rtl th.name { - text-align: right; -} - -td.name { - text-align: left; - font-weight: bold; -} - -.rtl td.name { - text-align: right; -} - -.entry { - text-align: left; - font-weight: normal; -} - -.rtl .entry { - text-align: right; -} - -.row1 { - background-color: #F9F9F9; -} - -table.zebra-table tbody tr:nth-child(odd) { - background-color: #F9F9F9; -} - -.row2 { - word-break: break-all; - background-color: #DCEBFE; -} - -table.zebra-table tbody tr:nth-child(even) { - background-color: #DCEBFE; -} - -.row3 { background-color: #DBDFE2; } -.row4 { background-color: #E4E8EB; } -.col1 { background-color: #DCEBFE; } -.col2 { background-color: #F9F9F9; } - -/* 4 row background colours for trees */ -.row1a { background-color: #F9F9F9; } -.row1b { background-color: #F6F6F6; } -.row2a { background-color: #E7EEF4; } -.row2b { background-color: #E3EBF2; } - -tr.row-highlight:hover td { background-color: #DBDFE2; } - -.spacer { - background-color: #DBDFE2; - height: 1px; - line-height: 1px; -} - -/* Deactivated row */ -.row-inactive { - color: #999; -} -.row-inactive a, .row-inactive strong { - color: #888; -} -.row-inactive a:hover { - color: #BC2A4D; -} - -/* Specific tables */ -table.forums td.folder { - width: 27px; - text-align: center; -} - -table td.actions { - vertical-align: middle; - width: 100px; - text-align: center; - white-space: nowrap; -} - -table tr:first-child td.actions .up, table tr:last-child td.actions .down { - display: none; -} - -table tr:first-child td.actions .up-disabled, table tr:last-child td.actions .down-disabled { - display: inline !important; -} - -table.styles td.users, table td.mark { - text-align: center; -} - -table.fixed-width-table { - table-layout: fixed; - word-break: break-word; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - table.responsive, table.responsive tbody, table.responsive tr, table.responsive td { - display: block; - } - - table.responsive thead, table.responsive th, table.responsive colgroup { - display: none; - } - - table.responsive.show-header thead, table.responsive.show-header th:first-child, table.responsive caption { - display: block; - width: auto !important; - text-align: left !important; - margin: 0; - } - - table.responsive { - background: transparent none; - border-width: 0; - padding: 0; - } - - table.responsive caption { - padding: 3px 4px; - color: #FFFFFF; - background: #70AED3 url("../images/gradient2b.gif") bottom left repeat-x; - border-top: 1px solid #6DACD2; - border-bottom: 1px solid #327AA5; - text-align: left; - font-size: 0.75em; - font-weight: bold; - text-transform: uppercase; - } - - table.responsive.show-header th:first-child span.rank-img, table.responsive.no-caption caption, table.responsive.no-header thead { - display: none; - } - - table.responsive tr { - margin: 2px 0; - border: 1px solid #CCCFD3; - background-color: #FFFFFF; - padding: 1px 1px 0; - overflow: hidden; - } - - table.responsive tr.row1 td { background-color: #F9F9F9; } - table.responsive tr.row2 td { background-color: #DCEBFE; } - table.responsive tr.row3 td { background-color: #DBDFE2; } - table.responsive tr.row4 td { background-color: #E4E8EB; } - table.responsive tr.col1 td { background-color: #DCEBFE; } - table.responsive tr.col2 td { background-color: #F9F9F9; } - table.responsive tr.row1a td { background-color: #F9F9F9; } - table.responsive tr.row1b td { background-color: #F6F6F6; } - table.responsive tr.row2a td { background-color: #E7EEF4; } - table.responsive tr.row2b td { background-color: #E3EBF2; } - - table.responsive td { - width: auto !important; - text-align: left !important; - padding: 4px; - margin-bottom: 1px; - } - - .rtl table.responsive td { - text-align: right !important; - } - - table.responsive td.empty { - display: none !important; - } - - table.responsive td > dfn { - display: inline-block !important; - } - - table.responsive td > dfn:after { - content: ':'; - padding-right: 5px; - } - - table.responsive.two-columns td { - width: 50% !important; - float: left; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - - .rtl table.responsive.two-columns td { - float: right; - } - - table.responsive.two-columns td:nth-child(2n+1) { - clear: left; - } - - table.responsive span.rank-img { - float: none; - padding-right: 5px; - } - - table.responsive#memberlist td:first-child input[type="checkbox"] { - float: right; - } - - /* Specific tables */ - table.responsive.forums td.folder { - float: left; - width: 27px; - background: transparent; - } - .rtl table.responsive.forums td.folder { - float: right; - } - - table.responsive.forums td.forum-desc { - margin-left: 35px; - min-height: 27px; - background: transparent; - } - - .rtl table.responsive.forums td.forum-desc { - margin-left: 0; - margin-right: 35px; - } - - table.responsive td.actions { - clear: both; - text-align: right !important; - } - - .rtl table.responsive td.actions { - text-align: left !important; - } - - table.responsive.styles tr.responsive-style-row td:first-child { - padding-left: 4px !important; - padding-right: 4px !important; - } - - table.responsive.styles td:first-child > dfn, table.responsive td.actions > dfn { - display: none !important; - } - - .horizontal-palette td:nth-child(2n), .vertical-palette tr:nth-child(2n) { - display: none; - } - - .colour-palette a { - display: inline-block !important; - } -} - -/* General form styles -----------------------------------------*/ -fieldset { - margin: 15px 0; - padding: 10px; - border-top: 1px solid #D7D7D7; - border-right: 1px solid #CCCCCC; - border-bottom: 1px solid #CCCCCC; - border-left: 1px solid #D7D7D7; - background-color: #FFFFFF; - position: relative; - border-radius: 3px; -} - -fieldset h2 { - margin-top: 0; -} - -.rtl fieldset { - border-top: 1px solid #D7D7D7; - border-right: 1px solid #D7D7D7; - border-bottom: 1px solid #CCCCCC; - border-left: 1px solid #CCCCCC; -} - -fieldset p { - font-size: 0.85em; -} - -legend { - padding: 1px 0; - font-family: Tahoma,arial,Verdana,Sans-serif; - font-size: .9em; - font-weight: bold; - color: #115098; - margin-top: -.4em; - position: relative; - text-transform: none; - line-height: 1.2em; - top: -.2em; - vertical-align: middle; -} - -input, textarea { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 0.90em; - font-weight: normal; - vertical-align: middle; - padding: 2px; - color: #111111; - border-left: 1px solid #AFAEAA; - border-top: 1px solid #AFAEAA; - border-right: 1px solid #D5D5C8; - border-bottom: 1px solid #D5D5C8; - background-color: #E3DFD8; -} - -.rtl input, .rtl textarea { - border-left: 1px solid #D5D5C8; - border-top: 1px solid #AFAEAA; - border-right: 1px solid #AFAEAA; - border-bottom: 1px solid #D5D5C8; -} - -input:hover, textarea:hover { - border-left: 1px solid #AFAEAA; - border-top: 1px solid #AFAEAA; - border-right: 1px solid #AFAEAA; - border-bottom: 1px solid #AFAEAA; - background-color: #E9E9E2; -} - -input.langvalue, textarea.langvalue { - width: 90%; -} - -input[type="number"] { - width: 60px; - -moz-padding-end: 0; -} - -optgroup, select { - background-color: #FAFAFA; - border: 1px solid #666666; - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 0.85em; - font-weight: normal; - font-style: normal; - cursor: pointer; - padding: 1px; - vertical-align: middle; - width: auto; - color: #000; -} - -select:focus { - outline-style: none; -} - -optgroup { - font-size: 1.00em; - font-weight: bold; -} - -optgroup.disabled-options { - display: none; - background-color: gray; -} - -option { - padding: 0 1em 0 0; - color: #000; -} - -option.disabled-option { - color: graytext; -} - -.rtl option { - padding: 0 0 0 1em; -} - -.sep { - font-weight: bold; -} - -.username-coloured { - font-weight: bold; -} - -textarea { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 0.85em; - width: 60%; - padding: 2px; -} - -label { - cursor: pointer; - font-size: 0.85em; - padding: 0 5px 0 0; -} - -.rtl label { - padding: 0 0 0 5px; -} - -label input { - font-size: 1.00em; - vertical-align: middle; -} - -label img { - vertical-align: middle; -} - -fieldset.quick, p.quick { - margin: 0 0 5px; - padding: 5px 0 0; - border: none; - background-color: transparent; - text-align: right; -} - -.rtl fieldset.quick, .rtl p.quick { - text-align: left; -} - -fieldset.quick legend { - display: none; -} - -fieldset.tabulated { - background: none; - margin: 0; - margin-top: 5px; - padding: 0; - border: 0; -} - -fieldset.tabulated legend { - display: none; -} - -fieldset.nobg { - margin: 15px 0 0 0; - padding: 0; - border: none; - background-color: transparent; -} - -fieldset.display-options { - margin: 15px 0 2px 0; - padding: 0 0 4px 0; - border: none; - background-color: transparent; - text-align: center; - font-size: 0.85em; -} - -fieldset.display-options select, fieldset.display-options input, fieldset.display-options label { - font-size: 1.00em; - vertical-align: middle; -} - -select option.disabled { - background-color: #bbb; - color: #fff; -} - -/* Special case inputs */ -select#board_timezone, -select#full_folder_action { - width: 95%; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - fieldset { - padding: 5px; - } - - fieldset.quick, p.quick { - float: none !important; - text-align: center; - } - - fieldset.display-options { - clear: both; - } -} - -/* Definition list layout for forms - Other general def. list properties defined in prosilver_main.css ----------------------------------------- */ -dl { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 1.00em; -} - -dt { - float: left; - width: auto; -} - -.rtl dt { - float: right; -} - -dd { color: #666666;} -dd + dd { padding-top: 5px;} -dt span { padding: 0 5px 0 0;} -.rtl dt span { padding: 0 0 0 5px;} - -dt .explain { font-style: italic;} - -dt label { - font-size: 1.00em; - text-align: left; - font-weight: bold; - color: #4A5A73; -} - -.rtl dt label { - text-align: right; -} - -dd label { - font-size: 1.00em; - white-space: nowrap; - margin: 0 10px 0 0; - color: #4A5A73; -} - -.rtl dd label { - margin: 0 0 0 10px; -} - -html>body dd label input { vertical-align: text-bottom;} /* Tweak for Moz to align checkboxes/radio buttons nicely */ - -dd input { - font-size: 1.00em; - max-width: 100%; - margin: 2px 0; -} - -dd select { - font-size: 100%; - font-size: 1em; - width: auto; - max-width: 100%; - margin: 2px 0; -} - -dd textarea { - font-size: 0.90em; - width: 90%; -} - -fieldset dl { - margin-bottom: 10px; - font-size: 0.85em; -} - -fieldset dt { - width: 45%; - text-align: left; - border: none; - border-right: 1px solid #CCCCCC; - padding-top: 3px; -} - -.rtl fieldset dt { - text-align: right; - border: none; - border-left: 1px solid #CCCCCC; -} - -fieldset #color_palette_placeholder { - padding-top: 0; -} - -fieldset dd { - margin: 0 0 0 45%; - padding: 0 0 0 5px; - border: none; - border-left: 1px solid #CCCCCC; - vertical-align: top; - font-size: 1.00em; -} - -.rtl fieldset dd { - margin: 0 45% 0 0; - padding: 0 5px 0 0; - border: none; - border-right: 1px solid #CCCCCC; -} - -dd.full, .rtl dd.full { - margin: 0; - border: 0; - padding: 0; - padding-top: 3px; - text-align: center; - width: 95%; -} - -/* Hover highlights for form rows */ -fieldset dl:hover dt, fieldset dl:hover dd { - border-color: #666666; -} - -fieldset dl:hover dt label { - color: #000000; -} - -fieldset dl dd label:hover { - color: #BC2A4D; -} - -input:focus, textarea:focus { - border: 1px solid #BC2A4D; - background-color: #E9E9E2; - color: #BC2A4D; - outline-style: none; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - fieldset dl { - margin-bottom: 5px; - padding-bottom: 5px; - border-bottom: 1px solid #e8e8e8; - } - - fieldset > dl:last-child, fieldset > form:last-child > dl:last-child { - border-bottom-width: 0; - margin-bottom: 0; - } - - fieldset dt, .rtl fieldset dt, fieldset dd, .rtl fieldset dd { - border-width: 0; - margin-left: 0; - margin-right: 0; - float: none; - width: auto; - } - - fieldset .responsive-columns dt { - float: left; - } - - .ltr fieldset dd { - padding-left: 20px; - } - - .rtl fieldset dd { - padding-right: 20px; - } - - select, dd select, dd input { - max-width: 300px; - } - - input[type="number"], dd input[type="number"] { - max-width: 70px; - } -} - -@media only screen and (max-width: 400px), only screen and (max-device-width: 400px) -{ - select, dd select, dd input { - max-width: 240px; - } -} - -/* Submit button fieldset or paragraph ----------------------------------------- */ -fieldset.submit-buttons { - text-align: center; - border: none; - background-color: transparent; - margin: 0; - padding: 4px; - margin-top: -1px; -} - -p.submit-buttons { - text-align: center; - margin: 0; - padding: 4px; - margin-top: 10px; -} - -fieldset.submit-buttons input, p.submit-buttons input { - padding: 3px 2px; -} - -fieldset.submit-buttons legend { - display: none; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - p.submit-buttons { - margin-top: 0; - } -} - -/* Input field styles ----------------------------------------- */ - -input.radio, input.checkbox, input.permissions-checkbox { - width: auto !important; - background-color: transparent; - border: none; - cursor: pointer; -} - -input.full, -textarea.full { - width: 99%; -} - -input.medium { width: 50%;} -input.narrow { width: 25%;} -input.tiny { width: 10%;} -input.autowidth { width: auto !important;} -.box2 .inputbox { background-color: #E9E9E9;} - -/* Form button styles ----------------------------------------- */ -a.button1, input.button1, -a.button2, input.button2 { - width: auto !important; - padding: 1px 3px 0 3px; - font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; - color: #000; - font-size: 0.85em; - background: #EFEFEF url("../images/bg_button.gif") repeat-x top; - cursor: pointer; -} - -a.button1, input.button1 { - font-weight: bold; - border: 1px solid #666666; -} - -/* Alternative button */ -a.button2, input.button2 { - border: 1px solid #666666; -} - -/* 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 { - text-decoration: none; - color: #000000; - padding: 4px 8px; -} - -/* Hover states */ -a.button1:hover, input.button1:hover, -a.button2:hover, input.button2:hover { - border: 1px solid #BC2A4D; - background: #EFEFEF url("../images/bg_button.gif") repeat bottom; - color: #BC2A4D; -} - -input.disabled { - font-weight: normal; - color: #666666; -} - -/* Focus states */ -input.button1:focus, input.button2:focus { - outline-style: none; -} - -/* jQuery popups ----------------------------------------- */ -.phpbb_alert { - background-color: #FFFFFF; - border: 1px solid #999999; - position: fixed; - display: none; - top: 150px; - left: 0; - right: 0; - width: 620px; - margin: 0 auto; - z-index: 50; - padding: 25px; - padding: 0 25px 20px 25px; -} - -.phpbb_alert .alert_close { - display: block; - float: right; - width: 16px; - height: 16px; - overflow: hidden; - text-decoration: none !important; - background: transparent url("../images/alert_close.png") 0 0 no-repeat; - margin-top: -7px; - margin-right: -31px; -} -.phpbb_alert .alert_close:hover { - background-position: 0 -16px; -} - - -.phpbb_alert p { - margin: 8px 0; - padding-bottom: 8px; -} - -.phpbb_alert label { - display: block; - margin: 8px 0; - padding-bottom: 8px; -} - -.phpbb_alert div.alert_text > p, -.phpbb_alert div.alert_text > label, -.phpbb_alert div.alert_text > select, -.phpbb_alert div.alert_text > textarea, -.phpbb_alert div.alert_text > input { - font-size: 0.9em; -} - -#darkenwrapper { - display: none; - position: relative; - z-index: 44; -} - -#darken { - position: fixed; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-color: #000000; - opacity: 0.5; - z-index: 45; -} - -@media only screen and (max-height: 500px), only screen and (max-device-width: 500px) -{ - .phpbb_alert { - top: 25px; - } -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - .phpbb_alert { - width: auto; - margin: 0 25px; - } -} - -#loading_indicator { - background: #000000 url("../images/loading.gif") center center no-repeat; - border-radius: 5px; - display: none; - opacity: 0.8; - margin-top: -50px; - margin-left: -50px; - height: 50px; - width: 50px; - position: fixed; - left: 50%; - top: 50%; - z-index: 51; -} - -/* Pagination ----------------------------------------- */ -.pagination { - font-size: .85em; - height: 1%; /* IE tweak (holly hack) */ - width: auto; - text-align: right; - margin: 5px 0; -} - -.top-pagination { - float: right; - margin: 15px 0 5px 0; -} - -.rtl .pagination { - text-align: left; - float: left; -} - -li.pagination { - margin-top: 0; -} - -.pagination img { - vertical-align: middle; -} - -.pagination ul { - display: inline-block; - *display: inline; /* IE7 inline-block hack */ - *zoom: 1; - margin-left: 0; - margin-bottom: 0; -} - -li.pagination ul { - margin-top: -2px; - vertical-align: middle; -} - -.pagination ul li, dl .pagination ul li, dl.icon .pagination ul li { - display: inline; - padding: 0; - font-size: 100%; - line-height: normal; -} - -.pagination li a, .pagnation li span, li .pagination li a, li .pagnation li span, .pagination li.active span, .pagination li.ellipsis span { - font-weight: normal; - text-decoration: none; - padding: 0 2px; - border: 1px solid transparent; - font-size: 0.9em; - line-height: 1.5em; -} - -.pagination li a, .pagination li a:link, .pagination li a:visited { - color: #5C758C; - background-color: #ECEDEE; - border-color: #B4BAC0; -} - -.pagination li.ellipsis span { - background-color: transparent; - color: #000000; -} - -.pagination li.active span { - color: #FFFFFF; - background-color: #4692BF; - border-color: #4692BF; -} - -.pagination li a:hover, .pagination .active a:hover { - color: #FFFFFF; - background-color: #368AD2; - border-color: #368AD2; -} - -.pagination li a:active, .pagination li.active a:active { - color: #5C758C; - background-color: #ECEDEE; - border-color: #B4BAC0; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - .pagination, .rtl .pagination { - float: none; - text-align: center; - margin: 5px 0; - } - - .pagination li a, .pagination li span { - display: inline-block; - min-width: 10px; - } -} - -/* Action Highlighting ----------------------------------------- */ -.successbox, .errorbox, .warningbox { - padding: 8px; - margin: 10px 0; - color: #FFFFFF; - text-align: center; - clear: both; -} - -.success { - color: #228822; -} - -.error { - color: #BC2A4D; -} - -.successbox { - background-color: #228822; -} - -.errorbox { - background-color: #BC2A4D; -} - -.warningbox { - background-color: #fca600; -} - -.successbox h3, .errorbox h3 { - color: #FFFFFF; - margin: 0 0 0.5em; - font-size: 1.10em; - font-family: "Lucida Grande",Verdana,Helvetica,Arial,sans-serif; -} - -.successbox p, .errorbox p { - color: #FFFFFF; - font-size: 0.85em; - margin-bottom: 0; -} - -.errorbox a:link, .errorbox a:active, .errorbox a:visited, -.successbox a:link, .successbox a:active, .successbox a:visited { - color: #DBD7D1; - text-decoration: underline; - font-weight: bold; -} - -.errorbox a:hover, .successbox a:hover { - color: #FFFFFF; - text-decoration: none; - 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; - line-height: 6em; -} - -#errorpage #content { - padding-top: 10px; -} - -#errorpage #content h1 { - color: #DF075C; -} - -#errorpage #content h2 { - margin-top: 20px; - margin-bottom: 5px; - border-bottom: 1px solid #CCCCCC; - padding-bottom: 5px; - color: #333333; -} - -/* Tooltip for permission roles */ -.tooltip { - width: 200px; - color: #000; - text-align: center; - border: 1px solid #AAA; -} - -.tooltip span.top { - background: #EFEFEF; - font-weight: bold; - padding: 2px; -} - -.tooltip span.bottom { - padding: 5px; - color: #000000; - background: #FFFFFF; -} - -/* - Format Buttons for signature editor -*/ -#format-buttons { - margin: 15px 0 2px 0; -} - -#format-buttons input, #format-buttons select { - vertical-align: middle; -} - -.row, fieldset dl { - overflow: hidden; -} - -/* Syntax Highlighting ----------------------------------------- */ -.sourcenum { - color: gray; - font-family: Monaco, 'Courier New', monospace; - font-size: 1.25em; - font-weight: bold; - line-height: 1.20em; - text-align: right; - padding: 0; -} - -.rtl .sourcenum { - text-align: left; -} - -.source { - font-family: Monaco, 'Courier New', monospace; - font-size: 1.25em; - line-height: 1.20em; - padding: 0; -} - -.syntaxbg { - color: #FFFFFF; -} - -.syntaxcomment { - color: #FF8000; -} - -.syntaxdefault { - color: #0000BB; -} - -.syntaxhtml { - color: #000000; -} - -.syntaxkeyword { - color: #007700; -} - -.syntaxstring { - color: #DD0000; -} - -/* Permission interface ----------------------------------------- */ - -.column1, .column2 { - width: 48%; - float: left; -} - -.ltr .column2, .rtl .column1 { - float: right; -} - -fieldset.permissions legend { - text-transform: none; -} - -fieldset.permissions legend input{ - height: 1.1em; -} - -/* Permission sections */ -fieldset.permissions .permissions-simple { - text-align: left; - padding-top: 3px; -} - -.rtl fieldset.permissions .permissions-simple { - text-align: right; -} - -fieldset.permissions .permissions-advanced { - padding: 10px 0 0 5px; - vertical-align: top; - clear: right; -} - -.rtl fieldset.permissions .permissions-advanced { - padding: 10px 5px 0 0; - clear: left; -} - -fieldset.permissions .permissions-switch { - float: right; -} - -.rtl fieldset.permissions .permissions-switch { - float: left; -} - -fieldset.permissions .padding { -} - -.permissions-switch { - margin-top: -6px; - font-size: .9em; -} - -.permissions-switch a { - text-decoration: underline; -} - -.permissions-reset { - padding-bottom: 10px; -} - -.permissions-reset a { - font-size: .85em; -} - -/* Tabbed menu */ -.permissions-category { - line-height: normal; - margin: 0 0 -1px 7px; - min-width: 570px; - font-size: 0.85em; -} - -.rtl .permissions-category { - margin: 0 7px -1px 0; -} - -.permissions-category ul { - margin: 0; - padding: 0; - list-style: none; -} - -.permissions-category li { - display: inline; - margin: 0; - padding: 0; - font-size: 1em; - font-weight: bold; -} - -.permissions-category a { - float: left; - background: url("../images/bg_tabs_alt1.gif") no-repeat 0% -35px; - margin: 0 1px 0 0; - padding: 0 0 0 6px; - text-decoration: none; - position: relative; -} - -.rtl .permissions-category a { - float: right; -} - -.permissions-category a span.tabbg { - float: left; - display: block; - background: url("../images/bg_tabs_alt2.gif") no-repeat 100% -35px; - padding: 7px 12px 6px 6px; - color: #536482; - white-space: nowrap; -} - -.rtl .permissions-category a span.tabbg { - float: right; -} - -/* Commented Backslash Hack hides rule from IE5-Mac \*/ -.permissions-category a span.tabbg, .rtl .permissions-category a span.tabbg { float: none;} -/* End hack */ - -.permissions-category a:hover span.tabbg { - color: #DD6900; -} - -.permissions-category .activetab a { - background-position: 0 0; -} - -.permissions-category .activetab a span.tabbg { - background-position: 100% 0; - padding-bottom: 7px; - color: #333333; -} - -.permissions-category a:hover { - background-position: 0 -70px; -} - -.permissions-category a:hover span.tabbg { - background-position: 100% -70px; -} - -.permissions-category .activetab a:hover span.tabbg { - color: #333333; - background-position: 100% 0; -} - -.permissions-category .activetab a:hover { - background-position: 0 0; -} - -.permissions-category a span.colour { - border: 1px solid #536482; - display: block; - float: left; - width: 10px; - height: 10px; - margin: 0 5px 0 0; -} - -/* Most browsers will have to live with a left aligned icon in RTL mode, as (currently) only Firefox 3.0 Alpha 3 renders it correctly without destroying it -.rtl .permissions-category a span.colour { - float: right; - margin: 0 0 0 5px; -} -*/ - -.permissions-category .activetab span.colour { - border-color: #333333; -} - -.permissions-category a:hover span.colour { - border-color: #DD6900; -} - -.permissions-category .activetab a:hover span.colour { - border-color: #333333; -} - -/* Permission preset colours */ -.permissions-preset-yes span.colour, -.yes { - background-color: #86F786; -} - -.permissions-preset-custom span.colour { - background-color: #B2BBDD; -} - -.permissions-preset-never span.colour { - background-color: #DD0000; -} - -.permissions-preset-no span.colour, -.never { - background-color: #EFB0B2; -} - -/* Permission panel ----------------------------------------- */ -.permissions-panel { - float: left; - background-color: #CADCEB; - width: 100%; - border-radius: 5px; - overflow: hidden; - padding: 5px 0; -} - -.rtl .permissions-panel { - float: right; -} - -/* Permission table ----------------------------------------- */ -.permissions-panel .tablewrap { - margin: 0 10px; -} - -.permissions-panel table { - width: 100%; -} - -.permissions-panel th { - text-transform: none; -} - -.permissions-panel th.value { - text-align: center; -} - -.permissions-panel th.name { - text-align: left; - width: auto; - text-transform: none; -} - -.rtl .permissions-panel th.name { - text-align: right; -} - -.permissions-panel th.permissions-name { - border: none; - color: #536482; - font-weight: normal; -} - -.permissions-panel th.permissions-name a.trace { - display: inline; -} - -.permissions-panel th.row3 { - background-image: none; - background-color: #D1D7DC; - color: #536482; - border: none; -} - -.permissions-panel th.row4 { - background-image: none; - background-color: #E4E8EB; - color: #536482; - border: none; -} - -.permissions-panel th a:link, .permissions-panel th a:hover, .permissions-panel th a:visited { - display: block; - color: #FFFFFF; - text-decoration: underline; -} - -.permissions-panel td.permissions-yes label:hover { - background-color: #86F786; -} - -.permissions-panel td.permissions-no label:hover { - background-color: #EFB0B2; -} - -.permissions-panel td.permissions-never label:hover { - background-color: #DD0000; -} - -.permissions-panel td { - padding: 0; - text-align: center; - width: 10%; -} - -.permissions-panel td label { - display: block; - margin: 0; - padding: 0; -} - -@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) -{ - .column1, .column2 { - float: none !important; - width: auto; - } - - .permissions-simple { - clear: both; - } - - .permissions-simple td, .permissions-simple dd { - width: auto !important; - margin-left: 0 !important; - margin-right: 0 !important; - } - - .permissions-simple dd { - margin-top: 5px; - } - - .permissions-panel .tablewrap { - margin: 0 5px; - } - - .permissions-category { - min-width: 0; - margin: 0 !important; - } - - .permissions-category a, .permissions-category a span.tabbg { - display: block; - float: none !important; - background: transparent none; - } - - .permissions-category a { - background: #d9e5ee; - margin: 5px 0; - padding: 0 !important; - border-radius: 3px; - text-decoration: underline; - } - - .permissions-category .activetab a { - background-color: #dd6900; - color: #fff; - } - - .permissions-category a span.tabbg { - color: inherit !important; - padding-top: 6px !important; - padding-bottom: 6px !important; - } - - .permissions-category .activetab span.colour { - border-color: #fff; - } -} - -/* Avatars gallery ----------------------------------------- */ -#gallery { - display: block; - margin: 0 -5px; - padding: 0; - overflow: hidden; -} - -#gallery li { - display: block; - float: left; - border: 1px solid #ccc; - border-radius: 2px; - background: #fff; - padding: 5px; - margin: 5px; -} - -#gallery li:hover { - background-color: #eee; -} - -#gallery li label { - display: block; - text-align: center; - padding: 0; -} - -/* Dropdown menu -----------------------------------------*/ -.dropdown { - position: absolute; - left: 0; - top: 22px; - z-index: 2; - border: 1px solid transparent; - border-radius: 5px; - padding: 9px 0 0; -} - -.dropdown-up .dropdown { - top: auto; - bottom: 18px; - padding: 0 0 9px; -} - -.dropdown-left .dropdown { - left: auto; - right: 0; -} - -.dropdown .pointer, .dropdown .pointer-inner { - position: absolute; - width: 0; - height: 0; - border-top-width: 0; - border-bottom: 10px solid transparent; - border-left: 10px dashed transparent; - border-right: 10px dashed transparent; - -webkit-transform: rotate(360deg); /* better anti-aliasing in webkit */ - display: block; -} - -.dropdown-up .pointer, .dropdown-up .pointer-inner { - border-bottom-width: 0; - border-top: 10px solid transparent; -} - -.dropdown .pointer { - right: auto; - left: 10px; - top: 0; - z-index: 3; -} - -.dropdown-up .pointer { - bottom: 0; - top: auto; -} - -.dropdown-left .dropdown .pointer { - left: auto; - right: 10px; -} - -.dropdown .pointer-inner { - top: auto; - bottom: -11px; - left: -10px; -} - -.dropdown-up .pointer-inner { - bottom: auto; - top: -11px; -} - -.dropdown .pointer { - border-color: #B9B9B9 transparent; -} - -.dropdown .pointer-inner { - border-color: #FFF transparent; -} - -.dropdown .dropdown-contents { - z-index: 2; - overflow: hidden; - overflow-y: auto; - background: #fff; - border: 1px solid #b9b9b9; - border-radius: 5px; - padding: 5px; - position: relative; - min-width: 40px; - max-height: 200px; - box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2); - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.dropdown-up .dropdown-contents { - box-shadow: 1px 0 5px rgba(0, 0, 0, 0.2); -} - -.dropdown li { - float: none; - margin: 0; - white-space: nowrap; - text-align: left; -} - -.rtl .dropdown li { - text-align: right; -} -.wrap .dropdown li, .dropdown.wrap li { - white-space: normal; -} - -.dropdown li:before, .dropdown li:after { - 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%; - direction: ltr; -} - -.phpinfo td, .phpinfo th, .phpinfo h2, .phpinfo h1 { - text-align: left; -} - -.requirements_not_met { - padding: 5px; - background-color: #BC2A4D; -} - -.requirements_not_met dt label, .requirements_not_met dd p { - color: #FFFFFF; - font-size: 1.4em; -} - -@media only screen and (max-width: 700px), only screen and (max-device-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; } -} - -.clearfix { - overflow: hidden; -} - -.pagination:after, -#page-header:after, -#page-body:after, -#tabs:after, -#tabs > ul:after, -#tabs li:after, -#acp:after, -#content:after { - content: ''; - 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/install/update/old/adm/style/admin.js b/install/update/old/adm/style/admin.js deleted file mode 100644 index 551c78a..0000000 --- a/install/update/old/adm/style/admin.js +++ /dev/null @@ -1,258 +0,0 @@ -/** -* phpBB3 ACP functions -*/ - -/** -* Parse document block -*/ -function parse_document(container) -{ - var test = document.createElement('div'), - oldBrowser = (typeof test.style.borderRadius == 'undefined'); - - delete test; - - /** - * Navigation - */ - container.find('#menu').each(function() { - var menu = $(this), - blocks = menu.children('.menu-block'); - - if (!blocks.length) { - return; - } - - // Set onclick event - blocks.children('a.header').click(function() { - var parent = $(this).parent(); - if (!parent.hasClass('active')) { - parent.siblings().removeClass('active'); - } - parent.toggleClass('active'); - }); - - // Set active menu - menu.find('#activemenu').parents('.menu-block').addClass('active'); - - // Check if there is active menu - if (!blocks.filter('.active').length) { - blocks.filter(':first').addClass('active'); - } - }); - - /** - * Responsive tables - */ - container.find('table').not('.not-responsive').each(function() { - var $this = $(this), - th = $this.find('thead > tr > th'), - columns = th.length, - headers = [], - totalHeaders = 0, - i, headersLength; - - // Find columns - $this.find('colgroup:first').children().each(function(i) { - var column = $(this); - $this.find('td:nth-child(' + (i + 1) + ')').addClass(column.prop('className')); - }); - - // Styles table - if ($this.hasClass('styles')) { - $this.find('td:first-child[style]').each(function() { - var style = $(this).attr('style'); - if (style.length) { - $(this).parent('tr').attr('style', style.toLowerCase().replace('padding', 'margin')).addClass('responsive-style-row'); - } - }); - } - - // Find each header - if (!$this.data('no-responsive-header')) - { - th.each(function(column) { - var cell = $(this), - colspan = parseInt(cell.attr('colspan')), - dfn = cell.attr('data-dfn'), - text = dfn ? dfn : $.trim(cell.text()); - - if (text == ' ') text = ''; - colspan = isNaN(colspan) || colspan < 1 ? 1 : colspan; - - for (i=0; i - $this.addClass('responsive'); - - if (totalHeaders < 2) { - $this.addClass('show-header'); - return; - } - - $this.find('tbody > tr').each(function() { - var row = $(this), - cells = row.children('td'), - column = 0; - - if (cells.length == 1) { - row.addClass('big-column'); - return; - } - - cells.each(function() { - var cell = $(this), - colspan = parseInt(cell.attr('colspan')), - text = $.trim(cell.text()); - - if (headersLength <= column) { - return; - } - - if ((text.length && text !== '-') || cell.children().length) { - if (headers[column] != '') { - cell.prepend('' + headers[column] + ''); - } - } - else { - cell.addClass('empty'); - } - - colspan = isNaN(colspan) || colspan < 1 ? 1 : colspan; - column += colspan; - }); - }); - - // Remove in disabled extensions list - $this.find('tr.ext_disabled > .empty:nth-child(2) + .empty').siblings(':first-child').children('dfn').remove(); - }); - - /** - * Hide empty responsive tables - */ - container.find('table.responsive > tbody').each(function() { - var items = $(this).children('tr'); - if (items.length == 0) - { - $(this).parent('table:first').addClass('responsive-hide'); - } - }); - - /** - * Fieldsets with empty - */ - container.find('fieldset dt > span:last-child').each(function() { - var $this = $(this); - if ($this.html() == ' ') { - $this.addClass('responsive-hide'); - } - - }); - - /** - * Responsive tabs - */ - container.find('#tabs').not('[data-skip-responsive]').each(function() { - var $this = $(this), - $body = $('body'), - ul = $this.children(), - tabs = ul.children().not('[data-skip-responsive]'), - links = tabs.children('a'), - item = ul.append('').find('li.responsive-tab'), - menu = item.find('.dropdown-contents'), - maxHeight = 0, - lastWidth = false, - responsive = false; - - links.each(function() { - var link = $(this); - maxHeight = Math.max(maxHeight, Math.max(link.outerHeight(true), link.parent().outerHeight(true))); - }) - - function check() { - var width = $body.width(), - height = $this.height(); - - if (arguments.length == 0 && (!responsive || width <= lastWidth) && height <= maxHeight) { - return; - } - - tabs.show(); - item.hide(); - - lastWidth = width; - height = $this.height(); - if (height <= maxHeight) { - responsive = false; - if (item.hasClass('dropdown-visible')) { - phpbb.toggleDropdown.call(item.find('a.responsive-tab-link').get(0)); - } - return; - } - - responsive = true; - item.show(); - menu.html(''); - - var availableTabs = tabs.filter(':not(.activetab, .responsive-tab)'), - total = availableTabs.length, - i, tab; - - for (i = total - 1; i >= 0; i --) { - tab = availableTabs.eq(i); - menu.prepend(tab.clone(true).removeClass('tab')); - tab.hide(); - if ($this.height() <= maxHeight) { - menu.find('a').click(function() { check(true); }); - return; - } - } - menu.find('a').click(function() { check(true); }); - } - - phpbb.registerDropdown(item.find('a.responsive-tab-link'), item.find('.dropdown'), {visibleClass: 'activetab', verticalDirection: 'down'}); - - check(true); - $(window).resize(check); - }); -} - -/** -* Run onload functions -*/ -(function($) { - $(document).ready(function() { - // Swap .nojs and .hasjs - $('body.nojs').toggleClass('nojs hasjs'); - - // Focus forms - $('form[data-focus]:first').each(function() { - $('#' + this.getAttribute('data-focus')).focus(); - }); - - parse_document($('body')); - - $('#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/install/update/old/adm/style/ajax.js b/install/update/old/adm/style/ajax.js deleted file mode 100644 index 895bb05..0000000 --- a/install/update/old/adm/style/ajax.js +++ /dev/null @@ -1,332 +0,0 @@ -/* global phpbb */ - -(function($) { // Avoid conflicts with other libraries - -'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 = $('', { - 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('&', '&'), - 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 - * an item is moved up. It moves the row up or down, and deactivates / - * activates any up / down icons that require it (the ones at the top or bottom). - */ -phpbb.addAjaxCallback('row_down', function(res) { - if (typeof res.success === 'undefined' || !res.success) { - return; - } - - var $firstTr = $(this).parents('tr'), - $secondTr = $firstTr.next(); - - $firstTr.insertAfter($secondTr); -}); - -phpbb.addAjaxCallback('row_up', function(res) { - if (typeof res.success === 'undefined' || !res.success) { - return; - } - - var $secondTr = $(this).parents('tr'), - $firstTr = $secondTr.prev(); - - $secondTr.insertBefore($firstTr); -}); - -/** - * This callback replaces activate links with deactivate links and vice versa. - * It does this by replacing the text, and replacing all instances of "activate" - * in the href with "deactivate", and vice versa. - */ -phpbb.addAjaxCallback('activate_deactivate', function(res) { - var $this = $(this), - newHref = $this.attr('href'); - - $this.text(res.text); - - if (newHref.indexOf('deactivate') !== -1) { - newHref = newHref.replace('deactivate', 'activate'); - } else { - newHref = newHref.replace('activate', 'deactivate'); - } - - $this.attr('href', newHref); -}); - -/** - * The removes the parent row of the link or form that triggered the callback, - * and is good for stuff like the removal of forums. - */ -phpbb.addAjaxCallback('row_delete', function(res) { - if (res.SUCCESS !== false) { - $(this).parents('tr').remove(); - } -}); - -/** - * Handler for submitting permissions form in chunks - * This call will submit permissions forms in chunks of 5 fieldsets. - */ -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]; - - // Set proper start values for handling refresh of page - var permissionSubmitSize = 0, - permissionRequestCount = 0, - forumIds = [], - permissionSubmitFailed = false; - - if ($submitAllButton !== $submitButton) { - fieldsetList = $form.find('fieldset#' + $submitButton.closest('fieldset.permissions').id); - } - - $.each(fieldsetList, function (key, value) { - dataSetIndex = Math.floor(key / 5); - var $fieldset = $('fieldset#' + value.id); - if (key % 5 === 0) { - 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[dataSetIndex] += '&' + roleInput.attr('name') + '=' + - $fieldset.find('select[name="' + roleInput.attr('name') + '"]').val(); - } - }); - - permissionSubmitSize = formDataSets.length; - - // Add each forum ID to forum ID list to preserve selected forums - $.each($form.find('input[type=hidden][name^=forum_id]'), function (key, value) { - if (value.name.match(/^forum_id\[([0-9]+)\]$/)) { - forumIds.push(value.value); - } - }); - - /** - * Handler for submitted permissions form chunk - * - * @param {object} res Object returned by AJAX call - */ - function handlePermissionReturn(res) { - permissionRequestCount++; - var $dark = $('#darkenwrapper'); - - if (res.S_USER_WARNING) { - phpbb.alert(res.MESSAGE_TITLE, res.MESSAGE_TEXT); - permissionSubmitFailed = true; - } else if (!permissionSubmitFailed && res.S_USER_NOTICE) { - // Display success message at the end of submitting the form - if (permissionRequestCount >= permissionSubmitSize) { - var $alert = phpbb.alert(res.MESSAGE_TITLE, res.MESSAGE_TEXT); - var $alertBoxLink = $alert.find('p.alert_text > a'); - - // Create form to submit instead of normal "Back to previous page" link - if ($alertBoxLink) { - // Remove forum_id[] from URL - $alertBoxLink.attr('href', $alertBoxLink.attr('href').replace(/(&forum_id\[\]=[0-9]+)/g, '')); - var previousPageForm = '
'; - $.each(forumIds, function (key, value) { - previousPageForm += ''; - }); - previousPageForm += '
'; - - $alertBoxLink.on('click', function (e) { - var $previousPageForm = $(previousPageForm); - $('body').append($previousPageForm); - e.preventDefault(); - $previousPageForm.submit(); - }); - } - - // Do not allow closing alert - $dark.off('click'); - $alert.find('.alert_close').hide(); - - if (typeof res.REFRESH_DATA !== 'undefined') { - setTimeout(function () { - // Create forum to submit using POST. This will prevent - // exceeding the maximum length of URLs - var form = '
'; - $.each(forumIds, function (key, value) { - form += ''; - }); - form += '
'; - $form = $(form); - $('body').append($form); - - // Hide the alert even if we refresh the page, in case the user - // presses the back button. - $dark.fadeOut(phpbb.alertTime, function () { - if (typeof $alert !== 'undefined') { - $alert.hide(); - } - }); - - // Submit form - $form.submit(); - }, res.REFRESH_DATA.time * 1000); // Server specifies time in seconds - } - } - } - } - - // Create AJAX request for each form data set - $.each(formDataSets, function (key, formData) { - $.ajax({ - url: $form.action, - type: 'POST', - data: formData + '&' + $submitButton.name + '=' + encodeURIComponent($submitButton.value) + - '&creation_time=' + $form.find('input[type=hidden][name=creation_time]')[0].value + - '&form_token=' + $form.find('input[type=hidden][name=form_token]')[0].value + - '&' + $form.children('input[type=hidden]').serialize() + - '&' + $form.find('input[type=checkbox][name^=inherit]').serialize(), - success: handlePermissionReturn, - error: handlePermissionReturn - }); - }); -} - -$('[data-ajax]').each(function() { - var $this = $(this), - ajax = $this.attr('data-ajax'); - - if (ajax !== 'false') { - var fn = (ajax !== 'true') ? ajax : null; - phpbb.ajaxify({ - selector: this, - refresh: $this.attr('data-refresh') !== undefined, - callback: fn - }); - } -}); - -/** -* Automatically resize textarea -*/ -$(function() { - phpbb.resizeTextArea($('textarea:not(.no-auto-resize)'), {minHeight: 75}); - - var $setPermissionsForm = $('form#set-permissions'); - if ($setPermissionsForm.length) { - $setPermissionsForm.on('submit', function (e) { - submitPermissions(); - e.preventDefault(); - }); - $setPermissionsForm.find('input[type=submit]').click(function() { - $('input[type=submit]', $(this).parents($('form#set-permissions'))).removeAttr('data-clicked'); - $(this).attr('data-clicked', true); - }); - } - - if ($('#acp_help_phpbb')) { - phpbb.prepareSendStats(); - } -}); - - -})(jQuery); // Avoid conflicts with other libraries diff --git a/install/update/old/adm/style/captcha_recaptcha.html b/install/update/old/adm/style/captcha_recaptcha.html deleted file mode 100644 index 3f61c76..0000000 --- a/install/update/old/adm/style/captcha_recaptcha.html +++ /dev/null @@ -1,14 +0,0 @@ - -
-
- - - -
-
-
- -{L_RECAPTCHA_NOT_AVAILABLE} - diff --git a/install/update/old/adm/style/installer_footer.html b/install/update/old/adm/style/installer_footer.html deleted file mode 100644 index fefa8f6..0000000 --- a/install/update/old/adm/style/installer_footer.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - -{$SCRIPTS} - - - diff --git a/install/update/old/adm/style/overall_footer.html b/install/update/old/adm/style/overall_footer.html deleted file mode 100644 index 8745286..0000000 --- a/install/update/old/adm/style/overall_footer.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - -{$SCRIPTS} - - - diff --git a/install/update/old/adm/style/overall_header.html b/install/update/old/adm/style/overall_header.html deleted file mode 100644 index 8279ac3..0000000 --- a/install/update/old/adm/style/overall_header.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - -{META} -{PAGE_TITLE} - - - - - - - - -{$STYLESHEETS} - - - - - - - - - -
- - -
-
- -
- -
-
- - - -
- -
-
- {% if CONTAINER_EXCEPTION !== false %} -
-

{{ lang('CONTAINER_EXCEPTION') }}


-

{{ lang('EXCEPTION') }}{{ lang('COLON') }} {{ CONTAINER_EXCEPTION.getMessage() }}

-
{{ CONTAINER_EXCEPTION.getTraceAsString() }}
-
- {% endif %} diff --git a/install/update/old/adm/style/permission_forum_copy.html b/install/update/old/adm/style/permission_forum_copy.html deleted file mode 100644 index b1539af..0000000 --- a/install/update/old/adm/style/permission_forum_copy.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - -

{L_ACP_FORUM_PERMISSIONS_COPY}

- - {L_ACP_FORUM_PERMISSIONS_COPY_EXPLAIN} - -
- -
- {L_LOOK_UP_FORUM} - -
-

{L_COPY_PERMISSIONS_FORUM_FROM_EXPLAIN}
-
-
-
- -
- {L_LOOK_UP_FORUM} -

{L_LOOK_UP_FORUMS_EXPLAIN}

- -
-

{L_COPY_PERMISSIONS_FORUM_TO_EXPLAIN}
-
-
-
- -
- {L_SUBMIT} -   - - {S_HIDDEN_FIELDS} - {S_FORM_TOKEN} -
- -
- - diff --git a/install/update/old/adm/style/permission_mask.html b/install/update/old/adm/style/permission_mask.html deleted file mode 100644 index c556664..0000000 --- a/install/update/old/adm/style/permission_mask.html +++ /dev/null @@ -1,150 +0,0 @@ - - - - - -
-

{p_mask.NAME} [{p_mask.L_ACL_TYPE}]

- - -
-
- - - - - - {p_mask.f_mask.PADDING}{p_mask.f_mask.PADDING}{p_mask.f_mask.NAME} - - - -
-
- {% if p_mask.f_mask.role_options %} -
- -
- {% else %} -
{L_NO_ROLE_AVAILABLE}
- {% endif %} -
- - - - - -
- - - diff --git a/install/update/old/adm/style/permissions.js b/install/update/old/adm/style/permissions.js deleted file mode 100644 index 9178ada..0000000 --- a/install/update/old/adm/style/permissions.js +++ /dev/null @@ -1,300 +0,0 @@ -/** -* Hide and show all checkboxes -* status = true (show boxes), false (hide boxes) -*/ -function display_checkboxes(status) { - var form = document.getElementById('set-permissions'); - var cb = document.getElementsByTagName('input'); - var display; - - //show - if (status) { - display = 'inline'; - } - //hide - else { - display = 'none'; - } - - for (var i = 0; i < cb.length; i++ ) { - if (cb[i].className === 'permissions-checkbox') { - cb[i].style.display = display; - } - } -} - -/** -* Change opacity of element -* e = element -* value = 0 (hidden) till 10 (fully visible) -*/ -function set_opacity(e, value) { - e.style.opacity = value/10; - - //IE opacity currently turned off, because of its astronomical stupidity - //e.style.filter = 'alpha(opacity=' + value*10 + ')'; -} - -/** -* Reset the opacity and checkboxes -* block_id = id of the element that needs to be toggled -*/ -function toggle_opacity(block_id) { - var cb = document.getElementById('checkbox' + block_id); - var fs = document.getElementById('perm' + block_id); - - if (cb.checked) { - set_opacity(fs, 5); - } else { - set_opacity(fs, 10); - } -} - -/** -* Reset the opacity and checkboxes -* value = 0 (checked) and 1 (unchecked) -* except_id = id of the element not to hide -*/ -function reset_opacity(status, except_id) { - var perm = document.getElementById('set-permissions'); - var fs = perm.getElementsByTagName('fieldset'); - var opacity = 5; - - if (status) { - opacity = 10; - } - - for (var i = 0; i < fs.length; i++ ) { - if (fs[i].className !== 'quick') { - set_opacity(fs[i], opacity); - } - } - - if (typeof(except_id) !== 'undefined') { - set_opacity(document.getElementById('perm' + except_id), 10); - } - - //reset checkboxes too - marklist('set-permissions', 'inherit', !status); -} - -/** -* Check whether we have a full radiobutton row of true -* index = offset for the row of inputs (0 == first row, 1 == second, 2 == third), -* rb = array of radiobuttons -*/ -function get_radio_status(index, rb) { - for (var i = index; i < rb.length; i = i + 3 ) { - if (rb[i].checked !== true) { - if (i > index) { - //at least one is true, but not all (custom) - return 2; - } - //first one is not true - return 0; - } - } - - // all radiobuttons true - return 1; -} - -/** -* Set tab colours -* id = panel the tab needs to be set for, -* init = initialising on open, -* quick = If no calculation needed, this contains the colour -*/ -function set_colours(id, init, quick) { - var table = document.getElementById('table' + id); - var tab = document.getElementById('tab' + id); - - if (typeof(quick) !== 'undefined') { - tab.className = 'permissions-preset-' + quick + ' activetab'; - return; - } - - var rb = table.getElementsByTagName('input'); - var colour = 'custom'; - - var status = get_radio_status(0, rb); - - if (status === 1) { - colour = 'yes'; - } else if (status === 0) { - // We move on to No - status = get_radio_status(1, rb); - - if (status === 1) { - colour = 'no'; - } else if (status === 0) { - // We move on to Never - status = get_radio_status(2, rb); - - if (status === 1) { - colour = 'never'; - } - } - } - - if (init) { - tab.className = 'permissions-preset-' + colour; - } else { - tab.className = 'permissions-preset-' + colour + ' activetab'; - } -} - -/** -* Initialise advanced tab colours on first load -* block_id = block that is opened -*/ -function init_colours(block_id) { - var block = document.getElementById('advanced' + block_id); - var panels = block.getElementsByTagName('div'); - var tab = document.getElementById('tab' + id); - - for (var i = 0; i < panels.length; i++) { - if (panels[i].className === 'permissions-panel') { - set_colours(panels[i].id.replace(/options/, ''), true); - } - } - - tab.className = tab.className + ' activetab'; -} - -/** -* Show/hide option panels -* value = suffix for ID to show -* adv = we are opening advanced permissions -* view = called from view permissions -*/ -function swap_options(pmask, fmask, cat, adv, view) { - id = pmask + fmask + cat; - active_option = active_pmask + active_fmask + active_cat; - - var old_tab = document.getElementById('tab' + active_option); - var new_tab = document.getElementById('tab' + id); - var adv_block = document.getElementById('advanced' + pmask + fmask); - - if (adv_block.style.display === 'block' && adv === true) { - phpbb.toggleDisplay('advanced' + pmask + fmask, -1); - reset_opacity(1); - display_checkboxes(false); - return; - } - - // no need to set anything if we are clicking on the same tab again - if (new_tab === old_tab && !adv) { - return; - } - - // init colours - if (adv && (pmask + fmask) !== (active_pmask + active_fmask)) { - init_colours(pmask + fmask); - display_checkboxes(true); - reset_opacity(1); - } else if (adv) { - //Checkbox might have been clicked, but we need full visibility - display_checkboxes(true); - reset_opacity(1); - } - - // set active tab - old_tab.className = old_tab.className.replace(/\ activetab/g, ''); - new_tab.className = new_tab.className + ' activetab'; - - if (id === active_option && adv !== true) { - return; - } - - phpbb.toggleDisplay('options' + active_option, -1); - - //hiding and showing the checkbox - if (document.getElementById('checkbox' + active_pmask + active_fmask)) { - phpbb.toggleDisplay('checkbox' + pmask + fmask, -1); - - if ((pmask + fmask) !== (active_pmask + active_fmask)) { - document.getElementById('checkbox' + active_pmask + active_fmask).style.display = 'inline'; - } - } - - if (!view) { - phpbb.toggleDisplay('advanced' + active_pmask + active_fmask, -1); - } - - if (!view) { - phpbb.toggleDisplay('advanced' + pmask + fmask, 1); - } - phpbb.toggleDisplay('options' + id, 1); - - active_pmask = pmask; - active_fmask = fmask; - active_cat = cat; -} - -/** -* Mark all radio buttons in one panel -* id = table ID container, s = status ['y'/'u'/'n'] -*/ -function mark_options(id, s) { - var t = document.getElementById(id); - - if (!t) { - return; - } - - var rb = t.getElementsByTagName('input'); - - for (var r = 0; r < rb.length; r++) { - if (rb[r].id.substr(rb[r].id.length-1) === s) { - rb[r].checked = true; - } - } -} - -function mark_one_option(id, field_name, s) { - var t = document.getElementById(id); - - if (!t) { - return; - } - - var rb = t.getElementsByTagName('input'); - - for (var r = 0; r < rb.length; r++) { - if (rb[r].id.substr(rb[r].id.length-field_name.length-3, field_name.length) === field_name && rb[r].id.substr(rb[r].id.length-1) === s) { - rb[r].checked = true; - } - } -} - -/** -* Reset role dropdown field to Select role... if an option gets changed -*/ -function reset_role(id) { - var t = document.getElementById(id); - - if (!t) { - return; - } - - t.options[0].selected = true; -} - -/** -* Load role and set options accordingly -*/ -function set_role_settings(role_id, target_id) { - settings = role_options[role_id]; - - if (!settings) { - return; - } - - // Mark all options to no (unset) first... - mark_options(target_id, 'u'); - - for (var r in settings) { - mark_one_option(target_id, r, (settings[r] === 1) ? 'y' : 'n'); - } -} diff --git a/install/update/old/adm/style/progress_bar.html b/install/update/old/adm/style/progress_bar.html deleted file mode 100644 index 1822675..0000000 --- a/install/update/old/adm/style/progress_bar.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - -
-

{L_PROGRESS}

- {L_PROGRESS} -

{L_PROGRESS_EXPLAIN}

-
- - - - diff --git a/install/update/old/adm/style/simple_footer.html b/install/update/old/adm/style/simple_footer.html deleted file mode 100644 index 08ee0a7..0000000 --- a/install/update/old/adm/style/simple_footer.html +++ /dev/null @@ -1,27 +0,0 @@ - -

-
- - - - - - - - -{$SCRIPTS} - - - diff --git a/install/update/old/adm/style/simple_header.html b/install/update/old/adm/style/simple_header.html deleted file mode 100644 index 439645a..0000000 --- a/install/update/old/adm/style/simple_header.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - -{META} -{PAGE_TITLE} - - - - - -{$STYLESHEETS} - - - - - - - -
diff --git a/install/update/old/assets/cookieconsent/cookieconsent.min.css b/install/update/old/assets/cookieconsent/cookieconsent.min.css deleted file mode 100644 index 03c69fe..0000000 --- a/install/update/old/assets/cookieconsent/cookieconsent.min.css +++ /dev/null @@ -1,6 +0,0 @@ -.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/install/update/old/assets/cookieconsent/cookieconsent.min.js b/install/update/old/assets/cookieconsent/cookieconsent.min.js deleted file mode 100644 index 8e44bdd..0000000 --- a/install/update/old/assets/cookieconsent/cookieconsent.min.js +++ /dev/null @@ -1 +0,0 @@ -!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=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=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.clientYs&&(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:"❌"},elements:{header:'{{header}} ',message:'{{message}}',messagelink:'{{message}} {{link}}',dismiss:'{{dismiss}}',allow:'{{allow}}',deny:'{{deny}}',link:'{{link}}',close:'{{close}}'},window:'',revokeBtn:'
Cookie Policy
',compliance:{info:'
{{dismiss}}
',"opt-in":'
{{dismiss}}{{allow}}
',"opt-out":'
{{deny}}{{dismiss}}
'},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,'
'+i+"
");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;r3&&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=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/install/update/old/assets/javascript/core.js b/install/update/old/assets/javascript/core.js deleted file mode 100644 index 5218a8c..0000000 --- a/install/update/old/assets/javascript/core.js +++ /dev/null @@ -1,1684 +0,0 @@ -/* global bbfontstyle */ - -var phpbb = {}; -phpbb.alertTime = 100; - -(function($) { // Avoid conflicts with other libraries - -'use strict'; - -// define a couple constants for keydown functions. -var keymap = { - TAB: 9, - ENTER: 13, - ESC: 27 -}; - -var $dark = $('#darkenwrapper'); -var $loadingIndicator; -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 - * - * @returns {object} Returns loadingIndicator. - */ -phpbb.loadingIndicator = function() { - if (!$loadingIndicator) { - $loadingIndicator = $('
', { - 'id': 'loading_indicator', - 'class': 'loading_indicator' - }); - $loadingIndicator.appendTo('#page-footer'); - } - - if (!$loadingIndicator.is(':visible')) { - $loadingIndicator.fadeIn(phpbb.alertTime); - // Wait 60 seconds and display an error if nothing has been returned by then. - phpbb.clearLoadingTimeout(); - phpbbAlertTimer = setTimeout(function() { - phpbb.showTimeoutMessage(); - }, 60000); - } - - return $loadingIndicator; -}; - -/** - * Show timeout message - */ -phpbb.showTimeoutMessage = function () { - var $alert = $('#phpbb_alert'); - - if ($loadingIndicator.is(':visible')) { - phpbb.alert($alert.attr('data-l-err'), $alert.attr('data-l-timeout-processing-req')); - } -}; - -/** - * Clear loading alert timeout -*/ -phpbb.clearLoadingTimeout = function() { - if (phpbbAlertTimer !== null) { - clearTimeout(phpbbAlertTimer); - phpbbAlertTimer = null; - } -}; - - -/** -* Close popup alert after a specified delay -* -* @param {int} delay Delay in ms until darkenwrapper's click event is triggered -*/ -phpbb.closeDarkenWrapper = function(delay) { - phpbbAlertTimer = setTimeout(function() { - $('#darkenwrapper').trigger('click'); - }, delay); -}; - -/** - * Display a simple alert similar to JSs native alert(). - * - * You can only call one alert or confirm box at any one time. - * - * @param {string} title Title of the message, eg "Information" (HTML). - * @param {string} msg Message to display (HTML). - * - * @returns {object} Returns the div created. - */ -phpbb.alert = function(title, msg) { - var $alert = $('#phpbb_alert'); - $alert.find('.alert_title').html(title); - $alert.find('.alert_text').html(msg); - - $(document).on('keydown.phpbb.alert', function(e) { - if (e.keyCode === keymap.ENTER || e.keyCode === keymap.ESC) { - phpbb.alert.close($alert, true); - e.preventDefault(); - e.stopPropagation(); - } - }); - phpbb.alert.open($alert); - - return $alert; -}; - -/** -* Handler for opening an alert box. -* -* @param {jQuery} $alert jQuery object. -*/ -phpbb.alert.open = function($alert) { - if (!$dark.is(':visible')) { - $dark.fadeIn(phpbb.alertTime); - } - - if ($loadingIndicator && $loadingIndicator.is(':visible')) { - $loadingIndicator.fadeOut(phpbb.alertTime, function() { - $dark.append($alert); - $alert.fadeIn(phpbb.alertTime); - }); - } else if ($dark.is(':visible')) { - $dark.append($alert); - $alert.fadeIn(phpbb.alertTime); - } else { - $dark.append($alert); - $alert.show(); - $dark.fadeIn(phpbb.alertTime); - } - - $alert.on('click', function(e) { - e.stopPropagation(); - }); - - $dark.one('click', function(e) { - phpbb.alert.close($alert, true); - e.preventDefault(); - e.stopPropagation(); - }); - - $alert.find('.alert_close').one('click', function(e) { - phpbb.alert.close($alert, true); - e.preventDefault(); - }); -}; - -/** -* Handler for closing an alert box. -* -* @param {jQuery} $alert jQuery object. -* @param {bool} fadedark Whether to remove dark background. -*/ -phpbb.alert.close = function($alert, fadedark) { - var $fade = (fadedark) ? $dark : $alert; - - $fade.fadeOut(phpbb.alertTime, function() { - $alert.hide(); - }); - - $alert.find('.alert_close').off('click'); - $(document).off('keydown.phpbb.alert'); -}; - -/** - * Display a simple yes / no box to the user. - * - * You can only call one alert or confirm box at any one time. - * - * @param {string} msg Message to display (HTML). - * @param {function} callback Callback. Bool param, whether the user pressed - * yes or no (or whatever their language is). - * @param {bool} fadedark Remove the dark background when done? Defaults - * to yes. - * - * @returns {object} Returns the div created. - */ -phpbb.confirm = function(msg, callback, fadedark) { - var $confirmDiv = $('#phpbb_confirm'); - $confirmDiv.find('.alert_text').html(msg); - fadedark = typeof fadedark !== 'undefined' ? fadedark : true; - - $(document).on('keydown.phpbb.alert', function(e) { - if (e.keyCode === keymap.ENTER || e.keyCode === keymap.ESC) { - var name = (e.keyCode === keymap.ENTER) ? 'confirm' : 'cancel'; - - $('input[name="' + name + '"]').trigger('click'); - e.preventDefault(); - e.stopPropagation(); - } - }); - - $confirmDiv.find('input[type="button"]').one('click.phpbb.confirmbox', function(e) { - var confirmed = this.name === 'confirm'; - - callback(confirmed); - $confirmDiv.find('input[type="button"]').off('click.phpbb.confirmbox'); - phpbb.alert.close($confirmDiv, fadedark || !confirmed); - - e.preventDefault(); - e.stopPropagation(); - }); - - phpbb.alert.open($confirmDiv); - - return $confirmDiv; -}; - -/** - * Turn a querystring into an array. - * - * @argument {string} string The querystring to parse. - * @returns {object} The object created. - */ -phpbb.parseQuerystring = function(string) { - var params = {}, i, split; - - string = string.split('&'); - for (i = 0; i < string.length; i++) { - split = string[i].split('='); - params[split[0]] = decodeURIComponent(split[1]); - } - return params; -}; - - -/** - * Makes a link use AJAX instead of loading an entire page. - * - * This function will work for links (both standard links and links which - * invoke confirm_box) and forms. It will be called automatically for links - * and forms with the data-ajax attribute set, and will call the necessary - * callback. - * - * For more info, view the following page on the phpBB wiki: - * http://wiki.phpbb.com/JavaScript_Function.phpbb.ajaxify - * - * @param {object} options Options. - */ -phpbb.ajaxify = function(options) { - var $elements = $(options.selector), - refresh = options.refresh, - callback = options.callback, - overlay = (typeof options.overlay !== 'undefined') ? options.overlay : true, - isForm = $elements.is('form'), - isText = $elements.is('input[type="text"], textarea'), - eventName; - - if (isForm) { - eventName = 'submit'; - } else if (isText) { - eventName = 'keyup'; - } else { - eventName = 'click'; - } - - $elements.on(eventName, function(event) { - var action, method, data, submit, that = this, $this = $(this); - - if ($this.find('input[type="submit"][data-clicked]').attr('data-ajax') === 'false') { - 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 responseText, errorText = false; - try { - responseText = JSON.parse(jqXHR.responseText); - responseText = responseText.message; - } catch (e) {} - if (typeof responseText === 'string' && responseText.length > 0) { - errorText = responseText; - } else 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) { - var alert; - - phpbb.clearLoadingTimeout(); - - // Is a confirmation required? - if (typeof res.S_CONFIRM_ACTION === 'undefined') { - // If a confirmation is not required, display an alert and call the - // callbacks. - if (typeof res.MESSAGE_TITLE !== 'undefined') { - alert = phpbb.alert(res.MESSAGE_TITLE, res.MESSAGE_TEXT); - } else { - $dark.fadeOut(phpbb.alertTime); - - if ($loadingIndicator) { - $loadingIndicator.fadeOut(phpbb.alertTime); - } - } - - if (typeof phpbb.ajaxCallbacks[callback] === 'function') { - phpbb.ajaxCallbacks[callback].call(that, res); - } - - // If the server says to refresh the page, check whether the page should - // be refreshed and refresh page after specified time if required. - if (res.REFRESH_DATA) { - if (typeof refresh === 'function') { - refresh = refresh(res.REFRESH_DATA.url); - } else if (typeof refresh !== 'boolean') { - refresh = false; - } - - phpbbAlertTimer = setTimeout(function() { - if (refresh) { - window.location = res.REFRESH_DATA.url; - } - - // Hide the alert even if we refresh the page, in case the user - // presses the back button. - $dark.fadeOut(phpbb.alertTime, function() { - if (typeof alert !== 'undefined') { - alert.hide(); - } - }); - }, res.REFRESH_DATA.time * 1000); // Server specifies time in seconds - } - } else { - // If confirmation is required, display a dialog to the user. - phpbb.confirm(res.MESSAGE_BODY, function(del) { - if (!del) { - return; - } - - phpbb.loadingIndicator(); - data = $('
' + res.S_HIDDEN_FIELDS + '
').serialize(); - $.ajax({ - url: res.S_CONFIRM_ACTION, - type: 'POST', - data: data + '&confirm=' + res.YES_VALUE + '&' + $('form', '#phpbb_confirm').serialize(), - success: returnHandler, - error: errorHandler - }); - }, false); - } - } - - // If the element is a form, POST must be used and some extra data must - // be taken from the form. - var runFilter = (typeof options.filter === 'function'); - data = {}; - - if (isForm) { - action = $this.attr('action').replace('&', '&'); - data = $this.serializeArray(); - method = $this.attr('method') || 'GET'; - - if ($this.find('input[type="submit"][data-clicked]')) { - submit = $this.find('input[type="submit"][data-clicked]'); - data.push({ - name: submit.attr('name'), - value: submit.val() - }); - } - } else if (isText) { - var name = $this.attr('data-name') || this.name; - action = $this.attr('data-url').replace('&', '&'); - data[name] = this.value; - method = 'POST'; - } else { - action = this.href; - data = null; - method = 'GET'; - } - - var sendRequest = function() { - var dataOverlay = $this.attr('data-overlay'); - if (overlay && (typeof dataOverlay === 'undefined' || dataOverlay === 'true')) { - phpbb.loadingIndicator(); - } - - var request = $.ajax({ - url: action, - type: method, - data: data, - success: returnHandler, - error: errorHandler, - cache: false - }); - - request.always(function() { - if ($loadingIndicator && $loadingIndicator.is(':visible')) { - $loadingIndicator.fadeOut(phpbb.alertTime); - } - }); - }; - - // If filter function returns false, cancel the AJAX functionality, - // and return true (meaning that the HTTP request will be sent normally). - if (runFilter && !options.filter.call(this, data, event, sendRequest)) { - return; - } - - sendRequest(); - event.preventDefault(); - }); - - if (isForm) { - $elements.find('input:submit').click(function () { - var $this = $(this); - - // Remove data-clicked attribute from any submit button of form - $this.parents('form:first').find('input:submit[data-clicked]').removeAttr('data-clicked'); - - $this.attr('data-clicked', 'true'); - }); - } - - return this; -}; - -phpbb.search = { - cache: { - data: [] - }, - tpl: [], - container: [] -}; - -/** - * Get cached search data. - * - * @param {string} id Search ID. - * @returns {bool|object} Cached data object. Returns false if no data exists. - */ -phpbb.search.cache.get = function(id) { - if (this.data[id]) { - return this.data[id]; - } - return false; -}; - -/** - * Set search cache data value. - * - * @param {string} id Search ID. - * @param {string} key Data key. - * @param {string} value Data value. - */ -phpbb.search.cache.set = function(id, key, value) { - if (!this.data[id]) { - this.data[id] = { results: [] }; - } - this.data[id][key] = value; -}; - -/** - * Cache search result. - * - * @param {string} id Search ID. - * @param {string} keyword Keyword. - * @param {Array} results Search results. - */ -phpbb.search.cache.setResults = function(id, keyword, results) { - this.data[id].results[keyword] = results; -}; - -/** - * Trim spaces from keyword and lower its case. - * - * @param {string} keyword Search keyword to clean. - * @returns {string} Cleaned string. - */ -phpbb.search.cleanKeyword = function(keyword) { - return $.trim(keyword).toLowerCase(); -}; - -/** - * Get clean version of search keyword. If textarea supports several keywords - * (one per line), it fetches the current keyword based on the caret position. - * - * @param {jQuery} $input Search input|textarea. - * @param {string} keyword Input|textarea value. - * @param {bool} multiline Whether textarea supports multiple search keywords. - * - * @returns string Clean string. - */ -phpbb.search.getKeyword = function($input, keyword, multiline) { - if (multiline) { - var line = phpbb.search.getKeywordLine($input); - keyword = keyword.split('\n').splice(line, 1); - } - return phpbb.search.cleanKeyword(keyword); -}; - -/** - * Get the textarea line number on which the keyword resides - for textareas - * that support multiple keywords (one per line). - * - * @param {jQuery} $textarea Search textarea. - * @returns {int} The line number. - */ -phpbb.search.getKeywordLine = function ($textarea) { - var selectionStart = $textarea.get(0).selectionStart; - return $textarea.val().substr(0, selectionStart).split('\n').length - 1; -}; - -/** - * Set the value on the input|textarea. If textarea supports multiple - * keywords, only the active keyword is replaced. - * - * @param {jQuery} $input Search input|textarea. - * @param {string} value Value to set. - * @param {bool} multiline Whether textarea supports multiple search keywords. - */ -phpbb.search.setValue = function($input, value, multiline) { - if (multiline) { - var line = phpbb.search.getKeywordLine($input), - lines = $input.val().split('\n'); - lines[line] = value; - value = lines.join('\n'); - } - $input.val(value); -}; - -/** - * Sets the onclick event to set the value on the input|textarea to the - * selected search result. - * - * @param {jQuery} $input Search input|textarea. - * @param {object} value Result object. - * @param {jQuery} $row Result element. - * @param {jQuery} $container jQuery object for the search container. - */ -phpbb.search.setValueOnClick = function($input, value, $row, $container) { - $row.click(function() { - phpbb.search.setValue($input, value.result, $input.attr('data-multiline')); - $container.hide(); - }); -}; - -/** - * Runs before the AJAX search request is sent and determines whether - * there is a need to contact the server. If there are cached results - * already, those are displayed instead. Executes the AJAX request function - * itself due to the need to use a timeout to limit the number of requests. - * - * @param {Array} data Data to be sent to the server. - * @param {object} event Onkeyup event object. - * @param {function} sendRequest Function to execute AJAX request. - * - * @returns {bool} Returns false. - */ -phpbb.search.filter = function(data, event, sendRequest) { - var $this = $(this), - dataName = ($this.attr('data-name') !== undefined) ? $this.attr('data-name') : $this.attr('name'), - minLength = parseInt($this.attr('data-min-length'), 10), - searchID = $this.attr('data-results'), - keyword = phpbb.search.getKeyword($this, data[dataName], $this.attr('data-multiline')), - cache = phpbb.search.cache.get(searchID), - proceed = true; - data[dataName] = keyword; - - if (cache.timeout) { - clearTimeout(cache.timeout); - } - - var timeout = setTimeout(function() { - // Check min length and existence of cache. - if (minLength > keyword.length) { - proceed = false; - } else if (cache.lastSearch) { - // Has the keyword actually changed? - if (cache.lastSearch === keyword) { - proceed = false; - } else { - // Do we already have results for this? - if (cache.results[keyword]) { - var response = { - keyword: keyword, - results: cache.results[keyword] - }; - phpbb.search.handleResponse(response, $this, true); - proceed = false; - } - - // If the previous search didn't yield results and the string only had characters added to it, - // then we won't bother sending a request. - if (keyword.indexOf(cache.lastSearch) === 0 && cache.results[cache.lastSearch].length === 0) { - phpbb.search.cache.set(searchID, 'lastSearch', keyword); - phpbb.search.cache.setResults(searchID, keyword, []); - proceed = false; - } - } - } - - if (proceed) { - sendRequest.call(this); - } - }, 350); - phpbb.search.cache.set(searchID, 'timeout', timeout); - - return false; -}; - -/** - * Handle search result response. - * - * @param {object} res Data received from server. - * @param {jQuery} $input Search input|textarea. - * @param {bool} fromCache Whether the results are from the cache. - * @param {function} callback Optional callback to run when assigning each search result. - */ -phpbb.search.handleResponse = function(res, $input, fromCache, callback) { - if (typeof res !== 'object') { - return; - } - - var searchID = $input.attr('data-results'), - $container = $(searchID); - - if (this.cache.get(searchID).callback) { - callback = this.cache.get(searchID).callback; - } else if (typeof callback === 'function') { - this.cache.set(searchID, 'callback', callback); - } - - if (!fromCache) { - this.cache.setResults(searchID, res.keyword, res.results); - } - - this.cache.set(searchID, 'lastSearch', res.keyword); - this.showResults(res.results, $input, $container, callback); -}; - -/** - * Show search results. - * - * @param {Array} results Search results. - * @param {jQuery} $input Search input|textarea. - * @param {jQuery} $container Search results container element. - * @param {function} callback Optional callback to run when assigning each search result. - */ -phpbb.search.showResults = function(results, $input, $container, callback) { - var $resultContainer = $('.search-results', $container); - this.clearResults($resultContainer); - - if (!results.length) { - $container.hide(); - return; - } - - var searchID = $container.attr('id'), - tpl, - row; - - if (!this.tpl[searchID]) { - tpl = $('.search-result-tpl', $container); - this.tpl[searchID] = tpl.clone().removeClass('search-result-tpl'); - tpl.remove(); - } - tpl = this.tpl[searchID]; - - $.each(results, function(i, item) { - row = tpl.clone(); - row.find('.search-result').html(item.display); - - if (typeof callback === 'function') { - callback.call(this, $input, item, row, $container); - } - row.appendTo($resultContainer).show(); - }); - $container.show(); -}; - -/** - * Clear search results. - * - * @param {jQuery} $container Search results container. - */ -phpbb.search.clearResults = function($container) { - $container.children(':not(.search-result-tpl)').remove(); -}; - -$('#phpbb').click(function() { - var $this = $(this); - - if (!$this.is('.live-search') && !$this.parents().is('.live-search')) { - $('.live-search').hide(); - } -}); - -phpbb.history = {}; - -/** -* Check whether a method in the native history object is supported. -* -* @param {string} fn Method name. -* @returns {bool} Returns true if the method is supported. -*/ -phpbb.history.isSupported = function(fn) { - return !(typeof history === 'undefined' || typeof history[fn] === 'undefined'); -}; - -/** -* Wrapper for the pushState and replaceState methods of the -* native history object. -* -* @param {string} mode Mode. Either push or replace. -* @param {string} url New URL. -* @param {string} [title] Optional page title. -* @param {object} [obj] Optional state object. -*/ -phpbb.history.alterUrl = function(mode, url, title, obj) { - var fn = mode + 'State'; - - if (!url || !phpbb.history.isSupported(fn)) { - return; - } - if (!title) { - title = document.title; - } - if (!obj) { - obj = null; - } - - history[fn](obj, title, url); -}; - -/** -* Wrapper for the native history.replaceState method. -* -* @param {string} url New URL. -* @param {string} [title] Optional page title. -* @param {object} [obj] Optional state object. -*/ -phpbb.history.replaceUrl = function(url, title, obj) { - phpbb.history.alterUrl('replace', url, title, obj); -}; - -/** -* Wrapper for the native history.pushState method. -* -* @param {string} url New URL. -* @param {string} [title] Optional page title. -* @param {object} [obj] Optional state object. -*/ -phpbb.history.pushUrl = function(url, title, obj) { - phpbb.history.alterUrl('push', url, title, obj); -}; - -/** -* Hide the optgroups that are not the selected timezone -* -* @param {bool} keepSelection Shall we keep the value selected, or shall the -* user be forced to repick one. -*/ -phpbb.timezoneSwitchDate = function(keepSelection) { - var $timezoneCopy = $('#timezone_copy'); - var $timezone = $('#timezone'); - var $tzDate = $('#tz_date'); - var $tzSelectDateSuggest = $('#tz_select_date_suggest'); - - if ($timezoneCopy.length === 0) { - // We make a backup of the original dropdown, so we can remove optgroups - // instead of setting display to none, because IE and chrome will not - // hide options inside of optgroups and selects via css - $timezone.clone() - .attr('id', 'timezone_copy') - .css('display', 'none') - .attr('name', 'tz_copy') - .insertAfter('#timezone'); - } else { - // Copy the content of our backup, so we can remove all unneeded options - $timezone.html($timezoneCopy.html()); - } - - if ($tzDate.val() !== '') { - $timezone.children('optgroup').remove(':not([data-tz-value="' + $tzDate.val() + '"])'); - } - - if ($tzDate.val() === $tzSelectDateSuggest.attr('data-suggested-tz')) { - $tzSelectDateSuggest.css('display', 'none'); - } else { - $tzSelectDateSuggest.css('display', 'inline'); - } - - var $tzOptions = $timezone.children('optgroup[data-tz-value="' + $tzDate.val() + '"]').children('option'); - - if ($tzOptions.length === 1) { - // If there is only one timezone for the selected date, we just select that automatically. - $tzOptions.prop('selected', true); - keepSelection = true; - } - - if (typeof keepSelection !== 'undefined' && !keepSelection) { - var $timezoneOptions = $timezone.find('optgroup option'); - if ($timezoneOptions.filter(':selected').length <= 0) { - $timezoneOptions.filter(':first').prop('selected', true); - } - } -}; - -/** -* Display the date/time select -*/ -phpbb.timezoneEnableDateSelection = function() { - $('#tz_select_date').css('display', 'block'); -}; - -/** -* Preselect a date/time or suggest one, if it is not picked. -* -* @param {bool} forceSelector Shall we select the suggestion? -*/ -phpbb.timezonePreselectSelect = function(forceSelector) { - - // The offset returned here is in minutes and negated. - var offset = (new Date()).getTimezoneOffset(); - var sign = '-'; - - if (offset < 0) { - sign = '+'; - offset = -offset; - } - - var minutes = offset % 60; - var hours = (offset - minutes) / 60; - - if (hours < 10) { - hours = '0' + hours.toString(); - } else { - hours = hours.toString(); - } - - if (minutes < 10) { - minutes = '0' + minutes.toString(); - } else { - minutes = minutes.toString(); - } - - var prefix = 'UTC' + sign + hours + ':' + minutes; - var prefixLength = prefix.length; - var selectorOptions = $('option', '#tz_date'); - var i; - - var $tzSelectDateSuggest = $('#tz_select_date_suggest'); - - for (i = 0; i < selectorOptions.length; ++i) { - var option = selectorOptions[i]; - - if (option.value.substring(0, prefixLength) === prefix) { - if ($('#tz_date').val() !== option.value && !forceSelector) { - // We do not select the option for the user, but notify him, - // that we would suggest a different setting. - phpbb.timezoneSwitchDate(true); - $tzSelectDateSuggest.css('display', 'inline'); - } else { - option.selected = true; - phpbb.timezoneSwitchDate(!forceSelector); - $tzSelectDateSuggest.css('display', 'none'); - } - - var suggestion = $tzSelectDateSuggest.attr('data-l-suggestion'); - - $tzSelectDateSuggest.attr('title', suggestion.replace('%s', option.innerHTML)); - $tzSelectDateSuggest.attr('value', suggestion.replace('%s', option.innerHTML.substring(0, 9))); - $tzSelectDateSuggest.attr('data-suggested-tz', option.innerHTML); - - // Found the suggestion, there cannot be more, so return from here. - return; - } - } -}; - -phpbb.ajaxCallbacks = {}; - -/** - * Adds an AJAX callback to be used by phpbb.ajaxify. - * - * See the phpbb.ajaxify comments for information on stuff like parameters. - * - * @param {string} id The name of the callback. - * @param {function} callback The callback to be called. - */ -phpbb.addAjaxCallback = function(id, callback) { - if (typeof callback === 'function') { - phpbb.ajaxCallbacks[id] = callback; - } - return this; -}; - -/** - * This callback handles live member searches. - */ -phpbb.addAjaxCallback('member_search', function(res) { - phpbb.search.handleResponse(res, $(this), false, phpbb.getFunctionByName('phpbb.search.setValueOnClick')); -}); - -/** - * This callback alternates text - it replaces the current text with the text in - * the alt-text data attribute, and replaces the text in the attribute with the - * current text so that the process can be repeated. - */ -phpbb.addAjaxCallback('alt_text', function() { - var $anchor, - updateAll = $(this).data('update-all'), - altText; - - if (updateAll !== undefined && updateAll.length) { - $anchor = $(updateAll); - } else { - $anchor = $(this); - } - - $anchor.each(function() { - var $this = $(this); - altText = $this.attr('data-alt-text'); - $this.attr('data-alt-text', $.trim($this.text())); - $this.attr('title', altText); - $this.children('span').text(altText); - }); -}); - -/** - * This callback is based on the alt_text callback. - * - * It replaces the current text with the text in the alt-text data attribute, - * and replaces the text in the attribute with the current text so that the - * process can be repeated. - * Additionally it replaces the class of the link's parent - * and changes the link itself. - */ -phpbb.addAjaxCallback('toggle_link', function() { - var $anchor, - updateAll = $(this).data('update-all') , - toggleText, - toggleUrl, - toggleClass; - - if (updateAll !== undefined && updateAll.length) { - $anchor = $(updateAll); - } else { - $anchor = $(this); - } - - $anchor.each(function() { - var $this = $(this); - - // Toggle link url - toggleUrl = $this.attr('data-toggle-url'); - $this.attr('data-toggle-url', $this.attr('href')); - $this.attr('href', toggleUrl); - - // Toggle class of link parent - toggleClass = $this.attr('data-toggle-class'); - $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); - }); -}); - -/** -* Automatically resize textarea -* -* This function automatically resizes textarea elements when user -* types text. -* -* @param {jQuery} $items jQuery object(s) to resize -* @param {object} [options] Optional parameter that adjusts default -* configuration. See configuration variable -* -* Optional parameters: -* minWindowHeight {number} Minimum browser window height when textareas are resized. Default = 500 -* minHeight {number} Minimum height of textarea. Default = 200 -* maxHeight {number} Maximum height of textarea. Default = 500 -* heightDiff {number} Minimum difference between window and textarea height. Default = 200 -* resizeCallback {function} Function to call after resizing textarea -* resetCallback {function} Function to call when resize has been canceled - -* Callback function format: function(item) {} -* this points to DOM object -* item is a jQuery object, same as this -*/ -phpbb.resizeTextArea = function($items, options) { - // Configuration - var configuration = { - minWindowHeight: 500, - minHeight: 200, - maxHeight: 500, - heightDiff: 200, - resizeCallback: function() {}, - resetCallback: function() {} - }; - - if (phpbb.isTouch) { - return; - } - - if (arguments.length > 1) { - configuration = $.extend(configuration, options); - } - - function resetAutoResize(item) { - var $item = $(item); - if ($item.hasClass('auto-resized')) { - $(item) - .css({ height: '', resize: '' }) - .removeClass('auto-resized'); - configuration.resetCallback.call(item, $item); - } - } - - function autoResize(item) { - function setHeight(height) { - height += parseInt($item.css('height'), 10) - $item.innerHeight(); - $item - .css({ height: height + 'px', resize: 'none' }) - .addClass('auto-resized'); - configuration.resizeCallback.call(item, $item); - } - - var windowHeight = $(window).height(); - - if (windowHeight < configuration.minWindowHeight) { - resetAutoResize(item); - return; - } - - var maxHeight = Math.min( - Math.max(windowHeight - configuration.heightDiff, configuration.minHeight), - configuration.maxHeight - ), - $item = $(item), - height = parseInt($item.innerHeight(), 10), - scrollHeight = (item.scrollHeight) ? item.scrollHeight : 0; - - if (height < 0) { - return; - } - - if (height > maxHeight) { - setHeight(maxHeight); - } else if (scrollHeight > (height + 5)) { - setHeight(Math.min(maxHeight, scrollHeight)); - } - } - - $items.on('focus change keyup', function() { - $(this).each(function() { - autoResize(this); - }); - }).change(); - - $(window).resize(function() { - $items.each(function() { - if ($(this).hasClass('auto-resized')) { - autoResize(this); - } - }); - }); -}; - -/** -* Check if cursor in textarea is currently inside a bbcode tag -* -* @param {object} textarea Textarea DOM object -* @param {Array} startTags List of start tags to look for -* For example, Array('[code]', '[code=') -* @param {Array} endTags List of end tags to look for -* For example, Array('[/code]') -* -* @returns {boolean} True if cursor is in bbcode tag -*/ -phpbb.inBBCodeTag = function(textarea, startTags, endTags) { - var start = textarea.selectionStart, - lastEnd = -1, - lastStart = -1, - i, index, value; - - if (typeof start !== 'number') { - return false; - } - - value = textarea.value.toLowerCase(); - - for (i = 0; i < startTags.length; i++) { - var tagLength = startTags[i].length; - if (start >= tagLength) { - index = value.lastIndexOf(startTags[i], start - tagLength); - lastStart = Math.max(lastStart, index); - } - } - if (lastStart === -1) { - return false; - } - - if (start > 0) { - for (i = 0; i < endTags.length; i++) { - index = value.lastIndexOf(endTags[i], start - 1); - lastEnd = Math.max(lastEnd, index); - } - } - - return (lastEnd < lastStart); -}; - - -/** -* Adjust textarea to manage code bbcode -* -* This function allows to use tab characters when typing code -* and keeps indentation of previous line of code when adding new -* line while typing code. -* -* Editor's functionality is changed only when cursor is between -* [code] and [/code] bbcode tags. -* -* @param {object} textarea Textarea DOM object to apply editor to -*/ -phpbb.applyCodeEditor = function(textarea) { - // list of allowed start and end bbcode code tags, in lower case - var startTags = ['[code]', '[code='], - startTagsEnd = ']', - endTags = ['[/code]']; - - if (!textarea || typeof textarea.selectionStart !== 'number') { - return; - } - - if ($(textarea).data('code-editor') === true) { - return; - } - - function inTag() { - return phpbb.inBBCodeTag(textarea, startTags, endTags); - } - - /** - * Get line of text before cursor - * - * @param {boolean} stripCodeStart If true, only part of line - * after [code] tag will be returned. - * - * @returns {string} Line of text - */ - function getLastLine(stripCodeStart) { - var start = textarea.selectionStart, - value = textarea.value, - index = value.lastIndexOf('\n', start - 1); - - value = value.substring(index + 1, start); - - if (stripCodeStart) { - for (var i = 0; i < startTags.length; i++) { - index = value.lastIndexOf(startTags[i]); - if (index >= 0) { - var tagLength = startTags[i].length; - - value = value.substring(index + tagLength); - if (startTags[i].lastIndexOf(startTagsEnd) !== tagLength) { - index = value.indexOf(startTagsEnd); - - if (index >= 0) { - value = value.substr(index + 1); - } - } - } - } - } - - return value; - } - - /** - * Append text at cursor position - * - * @param {string} text Text to append - */ - function appendText(text) { - var start = textarea.selectionStart, - end = textarea.selectionEnd, - value = textarea.value; - - textarea.value = value.substr(0, start) + text + value.substr(end); - textarea.selectionStart = textarea.selectionEnd = start + text.length; - } - - $(textarea).data('code-editor', true).on('keydown', function(event) { - var key = event.keyCode || event.which; - - // intercept tabs - if (key === keymap.TAB && - !event.ctrlKey && - !event.shiftKey && - !event.altKey && - !event.metaKey) { - if (inTag()) { - appendText('\t'); - event.preventDefault(); - return; - } - } - - // intercept new line characters - if (key === keymap.ENTER) { - if (inTag()) { - var lastLine = getLastLine(true), - code = '' + /^\s*/g.exec(lastLine); - - if (code.length > 0) { - appendText('\n' + code); - event.preventDefault(); - } - } - } - }); -}; - -/** - * Show drag and drop animation when textarea is present - * - * This function will enable the drag and drop animation for a specified - * textarea. - * - * @param {HTMLElement} textarea Textarea DOM object to apply editor to - */ -phpbb.showDragNDrop = function(textarea) { - if (!textarea) { - return; - } - - $('body').on('dragenter dragover', function () { - $(textarea).addClass('drag-n-drop'); - }).on('dragleave dragout dragend drop', function() { - $(textarea).removeClass('drag-n-drop'); - }); - $(textarea).on('dragenter dragover', function () { - $(textarea).addClass('drag-n-drop-highlight'); - }).on('dragleave dragout dragend drop', function() { - $(textarea).removeClass('drag-n-drop-highlight'); - }); -}; - -/** -* List of classes that toggle dropdown menu, -* list of classes that contain visible dropdown menu -* -* Add your own classes to strings with comma (probably you -* will never need to do that) -*/ -phpbb.dropdownHandles = '.dropdown-container.dropdown-visible .dropdown-toggle'; -phpbb.dropdownVisibleContainers = '.dropdown-container.dropdown-visible'; - -/** -* Dropdown toggle event handler -* This handler is used by phpBB.registerDropdown() and other functions -*/ -phpbb.toggleDropdown = function() { - var $this = $(this), - options = $this.data('dropdown-options'), - parent = options.parent, - visible = parent.hasClass('dropdown-visible'), - direction; - - if (!visible) { - // Hide other dropdown menus - $(phpbb.dropdownHandles).each(phpbb.toggleDropdown); - - // Figure out direction of dropdown - direction = options.direction; - var verticalDirection = options.verticalDirection, - offset = $this.offset(); - - if (direction === 'auto') { - if (($(window).width() - $this.outerWidth(true)) / 2 > offset.left) { - direction = 'right'; - } else { - direction = 'left'; - } - } - parent.toggleClass(options.leftClass, direction === 'left') - .toggleClass(options.rightClass, direction === 'right'); - - if (verticalDirection === 'auto') { - var height = $(window).height(), - top = offset.top - $(window).scrollTop(); - - verticalDirection = (top < height * 0.7) ? 'down' : 'up'; - } - parent.toggleClass(options.upClass, verticalDirection === 'up') - .toggleClass(options.downClass, verticalDirection === 'down'); - } - - options.dropdown.toggle(); - parent.toggleClass(options.visibleClass, !visible) - .toggleClass('dropdown-visible', !visible); - - // Check dimensions when showing dropdown - // !visible because variable shows state of dropdown before it was toggled - if (!visible) { - var windowWidth = $(window).width(); - - options.dropdown.find('.dropdown-contents').each(function() { - var $this = $(this); - - $this.css({ - marginLeft: 0, - left: 0, - marginRight: 0, - maxWidth: (windowWidth - 4) + 'px' - }); - - var offset = $this.offset().left, - width = $this.outerWidth(true); - - if (offset < 2) { - $this.css('left', (2 - offset) + 'px'); - } else if ((offset + width + 2) > windowWidth) { - $this.css('margin-left', (windowWidth - offset - width - 2) + 'px'); - } - - // Check whether the vertical scrollbar is present. - $this.toggleClass('dropdown-nonscroll', this.scrollHeight === $this.innerHeight()); - - }); - var freeSpace = parent.offset().left - 4; - - if (direction === 'left') { - options.dropdown.css('margin-left', '-' + freeSpace + 'px'); - - // Try to position the notification dropdown correctly in RTL-responsive mode - if (options.dropdown.hasClass('dropdown-extended')) { - var contentWidth, - fullFreeSpace = freeSpace + parent.outerWidth(); - - options.dropdown.find('.dropdown-contents').each(function() { - contentWidth = parseInt($(this).outerWidth(), 10); - $(this).css({ marginLeft: 0, left: 0 }); - }); - - var maxOffset = Math.min(contentWidth, fullFreeSpace) + 'px'; - options.dropdown.css({ - width: maxOffset, - marginLeft: -maxOffset - }); - } - } else { - options.dropdown.css('margin-right', '-' + (windowWidth + freeSpace) + 'px'); - } - } - - // Prevent event propagation - if (arguments.length > 0) { - try { - var e = arguments[0]; - e.preventDefault(); - e.stopPropagation(); - } catch (error) { } - } - return false; -}; - -/** -* Toggle dropdown submenu -*/ -phpbb.toggleSubmenu = function(e) { - $(this).siblings('.dropdown-submenu').toggle(); - e.preventDefault(); -}; - -/** -* Register dropdown menu -* Shows/hides dropdown, decides which side to open to -* -* @param {jQuery} toggle Link that toggles dropdown. -* @param {jQuery} dropdown Dropdown menu. -* @param {Object} options List of options. Optional. -*/ -phpbb.registerDropdown = function(toggle, dropdown, options) { - var ops = { - parent: toggle.parent(), // Parent item to add classes to - direction: 'auto', // Direction of dropdown menu. Possible values: auto, left, right - verticalDirection: 'auto', // Vertical direction. Possible values: auto, up, down - visibleClass: 'visible', // Class to add to parent item when dropdown is visible - leftClass: 'dropdown-left', // Class to add to parent item when dropdown opens to left side - rightClass: 'dropdown-right', // Class to add to parent item when dropdown opens to right side - upClass: 'dropdown-up', // Class to add to parent item when dropdown opens above menu item - downClass: 'dropdown-down' // Class to add to parent item when dropdown opens below menu item - }; - if (options) { - ops = $.extend(ops, options); - } - ops.dropdown = dropdown; - - ops.parent.addClass('dropdown-container'); - toggle.addClass('dropdown-toggle'); - - toggle.data('dropdown-options', ops); - - toggle.click(phpbb.toggleDropdown); - $('.dropdown-toggle-submenu', ops.parent).click(phpbb.toggleSubmenu); -}; - -/** -* Get the HTML for a color palette table. -* -* @param {string} dir Palette direction - either v or h -* @param {int} width Palette cell width. -* @param {int} height Palette cell height. -*/ -phpbb.colorPalette = function(dir, width, height) { - var r, g, b, - numberList = new Array(6), - color = '', - html = ''; - - numberList[0] = '00'; - numberList[1] = '40'; - numberList[2] = '80'; - numberList[3] = 'BF'; - numberList[4] = 'FF'; - - var tableClass = (dir === 'h') ? 'horizontal-palette' : 'vertical-palette'; - html += ''; - - for (r = 0; r < 5; r++) { - if (dir === 'h') { - html += ''; - } - - for (g = 0; g < 5; g++) { - if (dir === 'v') { - html += ''; - } - - for (b = 0; b < 5; b++) { - color = '' + numberList[r] + numberList[g] + numberList[b]; - html += ''; - } - - if (dir === 'v') { - html += ''; - } - } - - if (dir === 'h') { - html += ''; - } - } - html += '
'; - html += '
'; - return html; -}; - -/** -* Register a color palette. -* -* @param {jQuery} el jQuery object for the palette container. -*/ -phpbb.registerPalette = function(el) { - var orientation = el.attr('data-orientation'), - height = el.attr('data-height'), - width = el.attr('data-width'), - target = el.attr('data-target'), - bbcode = el.attr('data-bbcode'); - - // Insert the palette HTML into the container. - el.html(phpbb.colorPalette(orientation, width, height)); - - // Add toggle control. - $('#color_palette_toggle').click(function(e) { - el.toggle(); - e.preventDefault(); - }); - - // Attach event handler when a palette cell is clicked. - $(el).on('click', 'a', function(e) { - var color = $(this).attr('data-color'); - - if (bbcode) { - bbfontstyle('[color=#' + color + ']', '[/color]'); - } else { - $(target).val(color); - } - e.preventDefault(); - }); -}; - -/** -* Set display of page element -* -* @param {string} id The ID of the element to change -* @param {int} action Set to 0 if element display should be toggled, -1 for -* hiding the element, and 1 for showing it. -* @param {string} type Display type that should be used, e.g. inline, block or -* other CSS "display" types -*/ -phpbb.toggleDisplay = function(id, action, type) { - if (!type) { - type = 'block'; - } - - var $element = $('#' + id); - - var display = $element.css('display'); - if (!action) { - action = (display === '' || display === type) ? -1 : 1; - } - $element.css('display', ((action === 1) ? type : 'none')); -}; - -/** -* Toggle additional settings based on the selected -* option of select element. -* -* @param {jQuery} el jQuery select element object. -*/ -phpbb.toggleSelectSettings = function(el) { - el.children().each(function() { - var $this = $(this), - $setting = $($this.data('toggle-setting')); - $setting.toggle($this.is(':selected')); - - // Disable any input elements that are not visible right now - if ($this.is(':selected')) { - $($this.data('toggle-setting') + ' input').prop('disabled', false); - } else { - $($this.data('toggle-setting') + ' input').prop('disabled', true); - } - }); -}; - -/** -* Get function from name. -* Based on http://stackoverflow.com/a/359910 -* -* @param {string} functionName Function to get. -* @returns function -*/ -phpbb.getFunctionByName = function (functionName) { - var namespaces = functionName.split('.'), - func = namespaces.pop(), - context = window; - - for (var i = 0; i < namespaces.length; i++) { - context = context[namespaces[i]]; - } - return context[func]; -}; - -/** -* Register page dropdowns. -*/ -phpbb.registerPageDropdowns = function() { - var $body = $('body'); - - $body.find('.dropdown-container').each(function() { - var $this = $(this), - $trigger = $this.find('.dropdown-trigger:first'), - $contents = $this.find('.dropdown'), - options = { - direction: 'auto', - verticalDirection: 'auto' - }, - data; - - if (!$trigger.length) { - data = $this.attr('data-dropdown-trigger'); - $trigger = data ? $this.children(data) : $this.children('a:first'); - } - - if (!$contents.length) { - data = $this.attr('data-dropdown-contents'); - $contents = data ? $this.children(data) : $this.children('div:first'); - } - - if (!$trigger.length || !$contents.length) { - return; - } - - if ($this.hasClass('dropdown-up')) { - options.verticalDirection = 'up'; - } - if ($this.hasClass('dropdown-down')) { - options.verticalDirection = 'down'; - } - if ($this.hasClass('dropdown-left')) { - options.direction = 'left'; - } - if ($this.hasClass('dropdown-right')) { - options.direction = 'right'; - } - - phpbb.registerDropdown($trigger, $contents, options); - }); - - // Hide active dropdowns when click event happens outside - $body.click(function(e) { - var $parents = $(e.target).parents(); - if (!$parents.is(phpbb.dropdownVisibleContainers)) { - $(phpbb.dropdownHandles).each(phpbb.toggleDropdown); - } - }); -}; - -/** - * Handle avatars to be lazy loaded. - */ -phpbb.lazyLoadAvatars = function loadAvatars() { - $('.avatar[data-src]').each(function () { - var $avatar = $(this); - - $avatar - .attr('src', $avatar.data('src')) - .removeAttr('data-src'); - }); -}; - -$(window).on('load', phpbb.lazyLoadAvatars); - -/** -* Apply code editor to all textarea elements with data-bbcode attribute -*/ -$(function() { - $('textarea[data-bbcode]').each(function() { - phpbb.applyCodeEditor(this); - }); - - phpbb.registerPageDropdowns(); - - $('[data-orientation]').each(function() { - phpbb.registerPalette($(this)); - }); - - // Update browser history URL to point to specific post in viewtopic.php - // when using view=unread#unread link. - phpbb.history.replaceUrl($('#unread[data-url]').data('url')); - - // Hide settings that are not selected via select element. - $('select[data-togglable-settings]').each(function() { - var $this = $(this); - - $this.change(function() { - phpbb.toggleSelectSettings($this); - }); - phpbb.toggleSelectSettings($this); - }); -}); - -})(jQuery); // Avoid conflicts with other libraries diff --git a/install/update/old/assets/javascript/editor.js b/install/update/old/assets/javascript/editor.js deleted file mode 100644 index 23244f5..0000000 --- a/install/update/old/assets/javascript/editor.js +++ /dev/null @@ -1,425 +0,0 @@ -/** -* bbCode control by subBlue design [ www.subBlue.com ] -* Includes unixsafe colour palette selector by SHS` -*/ - -// Startup variables -var imageTag = false; -var theSelection = false; -var bbcodeEnabled = true; - -// Check for Browser & Platform for PC & IE specific bits -// More details from: http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html -var clientPC = navigator.userAgent.toLowerCase(); // Get client info -var clientVer = parseInt(navigator.appVersion, 10); // Get browser version - -var is_ie = ((clientPC.indexOf('msie') !== -1) && (clientPC.indexOf('opera') === -1)); -var is_win = ((clientPC.indexOf('win') !== -1) || (clientPC.indexOf('16bit') !== -1)); -var baseHeight; - -/** -* 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; - - if (document.forms[form_name]) { - doc = document; - } else { - doc = opener.document; - } - - var textarea = doc.forms[form_name].elements[text_name]; - - if (is_ie && typeof(baseHeight) !== 'number') { - textarea.focus(); - baseHeight = doc.selection.createRange().duplicate().boundingHeight; - - if (!document.forms[form_name]) { - document.body.focus(); - } - } -} - -/** -* bbstyle -*/ -function bbstyle(bbnumber) { - if (bbnumber !== -1) { - bbfontstyle(bbtags[bbnumber], bbtags[bbnumber+1]); - } else { - insert_text('[*]'); - document.forms[form_name].elements[text_name].focus(); - } -} - -/** -* Apply bbcodes -*/ -function bbfontstyle(bbopen, bbclose) { - theSelection = false; - - var textarea = document.forms[form_name].elements[text_name]; - - textarea.focus(); - - if ((clientVer >= 4) && is_ie && is_win) { - // Get text selection - theSelection = document.selection.createRange().text; - - if (theSelection) { - // Add tags around selection - document.selection.createRange().text = bbopen + theSelection + bbclose; - textarea.focus(); - theSelection = ''; - return; - } - } else if (textarea.selectionEnd && (textarea.selectionEnd - textarea.selectionStart > 0)) { - mozWrap(textarea, bbopen, bbclose); - textarea.focus(); - theSelection = ''; - return; - } - - //The new position for the cursor after adding the bbcode - var caret_pos = getCaretPosition(textarea).start; - var new_pos = caret_pos + bbopen.length; - - // Open tag - insert_text(bbopen + bbclose); - - // Center the cursor when we don't have a selection - // Gecko and proper browsers - if (!isNaN(textarea.selectionStart)) { - textarea.selectionStart = new_pos; - textarea.selectionEnd = new_pos; - } - // IE - else if (document.selection) { - var range = textarea.createTextRange(); - range.move("character", new_pos); - range.select(); - storeCaret(textarea); - } - - textarea.focus(); -} - -/** -* Insert text at position -*/ -function insert_text(text, spaces, popup) { - var textarea; - - if (!popup) { - textarea = document.forms[form_name].elements[text_name]; - } else { - textarea = opener.document.forms[form_name].elements[text_name]; - } - - if (spaces) { - text = ' ' + text + ' '; - } - - // Since IE9, IE also has textarea.selectionStart, but it still needs to be treated the old way. - // Therefore we simply add a !is_ie here until IE fixes the text-selection completely. - if (!isNaN(textarea.selectionStart) && !is_ie) { - var sel_start = textarea.selectionStart; - var sel_end = textarea.selectionEnd; - - mozWrap(textarea, text, ''); - textarea.selectionStart = sel_start + text.length; - textarea.selectionEnd = sel_end + text.length; - } else if (textarea.createTextRange && textarea.caretPos) { - if (baseHeight !== textarea.caretPos.boundingHeight) { - textarea.focus(); - storeCaret(textarea); - } - - var caret_pos = textarea.caretPos; - caret_pos.text = caret_pos.text.charAt(caret_pos.text.length - 1) === ' ' ? caret_pos.text + text + ' ' : caret_pos.text + text; - } else { - textarea.value = textarea.value + text; - } - - if (!popup) { - textarea.focus(); - } -} - -/** -* Add inline attachment at position -*/ -function attachInline(index, filename) { - insert_text('[attachment=' + index + ']' + filename + '[/attachment]'); - document.forms[form_name].elements[text_name].focus(); -} - -/** -* Add quote text to message -*/ -function addquote(post_id, username, l_wrote, attributes) { - var message_name = 'message_' + post_id; - var theSelection = ''; - var divarea = false; - var i; - - if (l_wrote === undefined) { - // Backwards compatibility - l_wrote = 'wrote'; - } - if (typeof attributes !== 'object') { - attributes = {}; - } - - if (document.all) { - divarea = document.all[message_name]; - } else { - divarea = document.getElementById(message_name); - } - - // Get text selection - not only the post content :( - // IE9 must use the document.selection method but has the *.getSelection so we just force no IE - if (window.getSelection && !is_ie && !window.opera) { - theSelection = window.getSelection().toString(); - } else if (document.getSelection && !is_ie) { - theSelection = document.getSelection(); - } else if (document.selection) { - theSelection = document.selection.createRange().text; - } - - if (theSelection === '' || typeof theSelection === 'undefined' || theSelection === null) { - if (divarea.innerHTML) { - theSelection = divarea.innerHTML.replace(/
/ig, '\n'); - theSelection = theSelection.replace(//ig, '\n'); - theSelection = theSelection.replace(/<\;/ig, '<'); - theSelection = theSelection.replace(/>\;/ig, '>'); - theSelection = theSelection.replace(/&\;/ig, '&'); - theSelection = theSelection.replace(/ \;/ig, ' '); - } else if (document.all) { - theSelection = divarea.innerText; - } else if (divarea.textContent) { - theSelection = divarea.textContent; - } else if (divarea.firstChild.nodeValue) { - theSelection = divarea.firstChild.nodeValue; - } - } - - if (theSelection) { - if (bbcodeEnabled) { - attributes.author = username; - insert_text(generateQuote(theSelection, attributes)); - } else { - insert_text(username + ' ' + l_wrote + ':' + '\n'); - var lines = split_lines(theSelection); - for (i = 0; i < lines.length; i++) { - insert_text('> ' + lines[i] + '\n'); - } - } - } -} - -/** -* 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) { - var lines = text.split('\n'); - var splitLines = new Array(); - var j = 0; - var i; - - for(i = 0; i < lines.length; i++) { - if (lines[i].length <= 80) { - splitLines[j] = lines[i]; - j++; - } else { - var line = lines[i]; - var splitAt; - do { - splitAt = line.indexOf(' ', 80); - - if (splitAt === -1) { - splitLines[j] = line; - j++; - } else { - splitLines[j] = line.substring(0, splitAt); - line = line.substring(splitAt); - j++; - } - } - while(splitAt !== -1); - } - } - return splitLines; -} - -/** -* From http://www.massless.org/mozedit/ -*/ -function mozWrap(txtarea, open, close) { - var selLength = (typeof(txtarea.textLength) === 'undefined') ? txtarea.value.length : txtarea.textLength; - var selStart = txtarea.selectionStart; - var selEnd = txtarea.selectionEnd; - var scrollTop = txtarea.scrollTop; - - var s1 = (txtarea.value).substring(0,selStart); - var s2 = (txtarea.value).substring(selStart, selEnd); - var s3 = (txtarea.value).substring(selEnd, selLength); - - txtarea.value = s1 + open + s2 + close + s3; - txtarea.selectionStart = selStart + open.length; - txtarea.selectionEnd = selEnd + open.length; - txtarea.focus(); - txtarea.scrollTop = scrollTop; - - return; -} - -/** -* Insert at Caret position. Code from -* http://www.faqts.com/knowledge_base/view.phtml/aid/1052/fid/130 -*/ -function storeCaret(textEl) { - if (textEl.createTextRange && document.selection) { - textEl.caretPos = document.selection.createRange().duplicate(); - } -} - -/** -* Caret Position object -*/ -function caretPosition() { - var start = null; - var end = null; -} - -/** -* Get the caret position in an textarea -*/ -function getCaretPosition(txtarea) { - var caretPos = new caretPosition(); - - // simple Gecko/Opera way - if (txtarea.selectionStart || txtarea.selectionStart === 0) { - caretPos.start = txtarea.selectionStart; - caretPos.end = txtarea.selectionEnd; - } - // dirty and slow IE way - else if (document.selection) { - // get current selection - var range = document.selection.createRange(); - - // a new selection of the whole textarea - var range_all = document.body.createTextRange(); - range_all.moveToElementText(txtarea); - - // calculate selection start point by moving beginning of range_all to beginning of range - var sel_start; - for (sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start++) { - range_all.moveStart('character', 1); - } - - txtarea.sel_start = sel_start; - - // we ignore the end value for IE, this is already dirty enough and we don't need it - caretPos.start = txtarea.sel_start; - caretPos.end = txtarea.sel_start; - } - - return caretPos; -} - -/** -* Allow to use tab character when typing code -* Keep indentation of last line of code when typing code -*/ -(function($) { - $(document).ready(function() { - var doc, textarea; - - // find textarea, make sure browser supports necessary functions - if (document.forms[form_name]) { - doc = document; - } else { - doc = opener.document; - } - - if (!doc.forms[form_name]) { - return; - } - - textarea = doc.forms[form_name].elements[text_name]; - - phpbb.applyCodeEditor(textarea); - if ($('#attach-panel').length) { - phpbb.showDragNDrop(textarea); - } - - $('textarea').on('keydown', function (e) { - if (e.which === 13 && (e.metaKey || e.ctrlKey)) { - $(this).closest('form').find(':submit').click(); - } - }); - }); -})(jQuery); - diff --git a/install/update/old/assets/javascript/plupload.js b/install/update/old/assets/javascript/plupload.js deleted file mode 100644 index 495d756..0000000 --- a/install/update/old/assets/javascript/plupload.js +++ /dev/null @@ -1,657 +0,0 @@ -/* global phpbb, plupload, attachInline */ - -plupload.addI18n(phpbb.plupload.i18n); -phpbb.plupload.ids = []; - -(function($) { // Avoid conflicts with other libraries - -'use strict'; - -/** - * Set up the uploader. - */ -phpbb.plupload.initialize = function() { - // Initialize the Plupload uploader. - phpbb.plupload.uploader.init(); - - // Set attachment data. - phpbb.plupload.setData(phpbb.plupload.data); - phpbb.plupload.updateMultipartParams(phpbb.plupload.getSerializedData()); - - // 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; - - // Hide the basic upload panel and remove the attach row template. - $('#attach-row-tpl, #attach-panel-basic').remove(); - // Show multi-file upload options. - $('#attach-panel-multi').show(); - }); - - phpbb.plupload.uploader.bind('PostInit', function() { - // Point out the drag-and-drop zone if it's supported. - if (phpbb.plupload.uploader.features.dragdrop) { - $('#drag-n-drop-message').show(); - } - - // Ensure "Add files" button position is correctly calculated. - if ($('#attach-panel-multi').is(':visible')) { - phpbb.plupload.uploader.refresh(); - } - $('[data-subpanel="attach-panel"]').one('click', function() { - phpbb.plupload.uploader.refresh(); - }); - }); -}; - -/** - * Unsets all elements in the object uploader.settings.multipart_params whose keys - * begin with 'attachment_data[' - */ -phpbb.plupload.clearParams = function() { - var obj = phpbb.plupload.uploader.settings.multipart_params; - for (var key in obj) { - if (!obj.hasOwnProperty(key) || key.indexOf('attachment_data[') !== 0) { - continue; - } - - delete phpbb.plupload.uploader.settings.multipart_params[key]; - } -}; - -/** - * Update uploader.settings.multipart_params object with new data. - * - * @param {object} obj - */ -phpbb.plupload.updateMultipartParams = function(obj) { - var settings = phpbb.plupload.uploader.settings; - settings.multipart_params = $.extend(settings.multipart_params, obj); -}; - -/** - * Convert the array of attachment objects into an object that PHP would expect as POST data. - * - * @returns {object} An object in the form 'attachment_data[i][key]': value as - * expected by the server - */ -phpbb.plupload.getSerializedData = function() { - var obj = {}; - for (var i = 0; i < phpbb.plupload.data.length; i++) { - var datum = phpbb.plupload.data[i]; - for (var key in datum) { - if (!datum.hasOwnProperty(key)) { - continue; - } - - obj['attachment_data[' + i + '][' + key + ']'] = datum[key]; - } - } - return obj; -}; - -/** - * Get the index from the phpbb.plupload.data array where the given - * attachment id appears. - * - * @param {int} attachId The attachment id of the file. - * @returns {bool|int} Index of the file if exists, otherwise false. - */ -phpbb.plupload.getIndex = function(attachId) { - var index = $.inArray(Number(attachId), phpbb.plupload.ids); - return (index !== -1) ? index : false; -}; - -/** - * Set the data in phpbb.plupload.data and phpbb.plupload.ids arrays. - * - * @param {Array} data Array containing the new data to use. In the form of - * array(index => object(property: value). Requires attach_id to be one of the object properties. - */ -phpbb.plupload.setData = function(data) { - // Make sure that the array keys are reset. - phpbb.plupload.ids = phpbb.plupload.data = []; - phpbb.plupload.data = data; - - for (var i = 0; i < data.length; i++) { - phpbb.plupload.ids.push(Number(data[i].attach_id)); - } -}; - -/** - * Update the attachment data in the HTML and the phpbb & phpbb.plupload objects. - * - * @param {Array} data Array containing the new data to use. - * @param {string} action The action that required the update. Used to update the inline attachment bbcodes. - * @param {int} index The index from phpbb.plupload_ids that was affected by the action. - * @param {Array} downloadUrl Optional array of download urls to update. - */ -phpbb.plupload.update = function(data, action, index, downloadUrl) { - - phpbb.plupload.updateBbcode(action, index); - phpbb.plupload.setData(data); - phpbb.plupload.updateRows(downloadUrl); - phpbb.plupload.clearParams(); - phpbb.plupload.updateMultipartParams(phpbb.plupload.getSerializedData()); -}; - -/** - * Update the relevant elements and hidden data for all attachments. - * - * @param {Array} downloadUrl Optional array of download urls to update. - */ -phpbb.plupload.updateRows = function(downloadUrl) { - for (var i = 0; i < phpbb.plupload.ids.length; i++) { - phpbb.plupload.updateRow(i, downloadUrl); - } -}; - -/** - * Insert a row for a new attachment. This expects an HTML snippet in the HTML - * using the id "attach-row-tpl" to be present. This snippet is cloned and the - * data for the file inserted into it. The row is then appended or prepended to - * #file-list based on the attach_order setting. - * - * @param {object} file Plupload file object for the new attachment. - */ -phpbb.plupload.insertRow = function(file) { - var row = $(phpbb.plupload.rowTpl); - - row.attr('id', file.id); - row.find('.file-name').html(plupload.xmlEncode(file.name)); - row.find('.file-size').html(plupload.formatSize(file.size)); - - if (phpbb.plupload.order === 'desc') { - $('#file-list').prepend(row); - } else { - $('#file-list').append(row); - } -}; - -/** - * Update the relevant elements and hidden data for an attachment. - * - * @param {int} index The index from phpbb.plupload.ids of the attachment to edit. - * @param {Array} downloadUrl Optional array of download urls to update. - */ -phpbb.plupload.updateRow = function(index, downloadUrl) { - var attach = phpbb.plupload.data[index], - row = $('[data-attach-id="' + attach.attach_id + '"]'); - - // Add the link to the file - if (typeof downloadUrl !== 'undefined' && typeof downloadUrl[index] !== 'undefined') { - var url = downloadUrl[index].replace('&', '&'), - link = $(''); - - link.attr('href', url).html(attach.real_filename); - row.find('.file-name').html(link); - } - - row.find('textarea').attr('name', 'comment_list[' + index + ']'); - phpbb.plupload.updateHiddenData(row, attach, index); -}; - -/** - * Update hidden input data for an attachment. - * - * @param {object} row jQuery object for the attachment row. - * @param {object} attach Attachment data object from phpbb.plupload.data - * @param {int} index Attachment index from phpbb.plupload.ids - */ -phpbb.plupload.updateHiddenData = function(row, attach, index) { - row.find('input[type="hidden"]').remove(); - - for (var key in attach) { - if (!attach.hasOwnProperty(key)) { - return; - } - - var input = $('') - .attr('type', 'hidden') - .attr('name', 'attachment_data[' + index + '][' + key + ']') - .attr('value', attach[key]); - $(row).append(input); - } -}; - -/** - * Deleting a file removes it from the queue and fires an AJAX event to the - * server to tell it to remove the temporary attachment. The server - * responds with the updated attachment data list so that any future - * uploads can maintain state with the server - * - * @param {object} row jQuery object for the attachment row. - * @param {int} attachId Attachment id of the file to be removed. - */ -phpbb.plupload.deleteFile = function(row, attachId) { - // If there's no attach id, then the file hasn't been uploaded. Simply delete the row. - if (typeof attachId === 'undefined') { - var file = phpbb.plupload.uploader.getFile(row.attr('id')); - phpbb.plupload.uploader.removeFile(file); - - row.slideUp(100, function() { - row.remove(); - phpbb.plupload.hideEmptyList(); - }); - } - - var index = phpbb.plupload.getIndex(attachId); - row.find('.file-status').toggleClass('file-uploaded file-working'); - - if (index === false) { - return; - } - var fields = {}; - fields['delete_file[' + index + ']'] = 1; - - var always = function() { - row.find('.file-status').removeClass('file-working'); - }; - - var done = function(response) { - if (typeof response !== 'object') { - return; - } - - // trigger_error() was called which likely means a permission error was encountered. - if (typeof response.title !== 'undefined') { - phpbb.plupload.uploader.trigger('Error', { message: response.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(); - - if (row.attr('id')) { - var file = phpbb.plupload.uploader.getFile(row.attr('id')); - phpbb.plupload.uploader.removeFile(file); - } - row.slideUp(100, function() { - row.remove(); - // Hide the file list if it's empty now. - phpbb.plupload.hideEmptyList(); - }); - phpbb.plupload.uploader.trigger('FilesRemoved'); - }; - - $.ajax(phpbb.plupload.config.url, { - type: 'POST', - data: $.extend(fields, phpbb.plupload.getSerializedData()), - headers: phpbb.plupload.config.headers - }) - .always(always) - .done(done); -}; - -/** - * Check the attachment list and hide its container if it's empty. - */ -phpbb.plupload.hideEmptyList = function() { - if (!$('#file-list').children().length) { - $('#file-list-container').slideUp(100); - } -}; - -/** - * Update the indices used in inline attachment bbcodes. This ensures that the - * bbcodes correspond to the correct file after a file is added or removed. - * This should be called before the phpbb.plupload,data and phpbb.plupload.ids - * arrays are updated, otherwise it will not work correctly. - * - * @param {string} action The action that occurred -- either "addition" or "removal" - * @param {int} index The index of the attachment from phpbb.plupload.ids that was affected. - */ -phpbb.plupload.updateBbcode = function(action, index) { - var textarea = $('#message', phpbb.plupload.form), - text = textarea.val(), - removal = (action === 'removal'); - - // Return if the bbcode isn't used at all. - if (text.indexOf('[attachment=') === -1) { - return; - } - - function runUpdate(i) { - var regex = new RegExp('\\[attachment=' + i + '\\](.*?)\\[\\/attachment\\]', 'g'); - text = text.replace(regex, function updateBbcode(_, fileName) { - // Remove the bbcode if the file was removed. - if (removal && index === i) { - return ''; - } - var newIndex = i + ((removal) ? -1 : 1); - return '[attachment=' + newIndex + ']' + fileName + '[/attachment]'; - }); - } - - // Loop forwards when removing and backwards when adding ensures we don't - // corrupt the bbcode index. - var i; - if (removal) { - for (i = index; i < phpbb.plupload.ids.length; i++) { - runUpdate(i); - } - } else { - for (i = phpbb.plupload.ids.length - 1; i >= index; i--) { - runUpdate(i); - } - } - - textarea.val(text); -}; - -/** - * Get Plupload file objects based on their upload status. - * - * @param {int} status Plupload status - plupload.DONE, plupload.FAILED, - * plupload.QUEUED, plupload.STARTED, plupload.STOPPED - * - * @returns {Array} The Plupload file objects matching the status. - */ -phpbb.plupload.getFilesByStatus = function(status) { - var files = []; - - $.each(phpbb.plupload.uploader.files, function(i, file) { - if (file.status === status) { - files.push(file); - } - }); - return files; -}; - -/** - * Check whether the user has reached the maximun number of files that he's allowed - * to upload. If so, disables the uploader and marks the queued files as failed. Otherwise - * makes sure that the uploader is enabled. - * - * @returns {bool} True if the limit has been reached. False if otherwise. - */ -phpbb.plupload.handleMaxFilesReached = function() { - // If there is no limit, the user is an admin or moderator. - if (!phpbb.plupload.maxFiles) { - return false; - } - - if (phpbb.plupload.maxFiles <= phpbb.plupload.ids.length) { - // Fail the rest of the queue. - phpbb.plupload.markQueuedFailed(phpbb.plupload.lang.TOO_MANY_ATTACHMENTS); - // Disable the uploader. - phpbb.plupload.disableUploader(); - phpbb.plupload.uploader.trigger('Error', { message: phpbb.plupload.lang.TOO_MANY_ATTACHMENTS }); - - return true; - } else if (phpbb.plupload.maxFiles > phpbb.plupload.ids.length) { - // Enable the uploader if the user is under the limit - phpbb.plupload.enableUploader(); - } - return false; -}; - -/** - * Disable the uploader - */ -phpbb.plupload.disableUploader = function() { - $('#add_files').addClass('disabled'); - phpbb.plupload.uploader.disableBrowse(); -}; - -/** - * Enable the uploader - */ -phpbb.plupload.enableUploader = function() { - $('#add_files').removeClass('disabled'); - phpbb.plupload.uploader.disableBrowse(false); -}; - -/** - * Mark all queued files as failed. - * - * @param {string} error Error message to present to the user. - */ -phpbb.plupload.markQueuedFailed = function(error) { - var files = phpbb.plupload.getFilesByStatus(plupload.QUEUED); - - $.each(files, function(i, file) { - $('#' + file.id).find('.file-progress').hide(); - phpbb.plupload.fileError(file, error); - }); -}; - -/** - * Marks a file as failed and sets the error message for it. - * - * @param {object} file Plupload file object that failed. - * @param {string} error Error message to present to the user. - */ -phpbb.plupload.fileError = function(file, error) { - file.status = plupload.FAILED; - file.error = error; - $('#' + file.id).find('.file-status') - .addClass('file-error') - .attr({ - 'data-error-title': phpbb.plupload.lang.ERROR, - 'data-error-message': error - }); -}; - - -/** - * Set up the Plupload object and get some basic data. - */ -phpbb.plupload.uploader = new plupload.Uploader(phpbb.plupload.config); -phpbb.plupload.initialize(); - -var $fileList = $('#file-list'); - -/** - * Insert inline attachment bbcode. - */ -$fileList.on('click', '.file-inline-bbcode', function(e) { - var attachId = $(this).parents('.attach-row').attr('data-attach-id'), - index = phpbb.plupload.getIndex(attachId); - - attachInline(index, phpbb.plupload.data[index].real_filename); - e.preventDefault(); -}); - -/** - * Delete a file. - */ -$fileList.on('click', '.file-delete', function(e) { - var row = $(this).parents('.attach-row'), - attachId = row.attr('data-attach-id'); - - phpbb.plupload.deleteFile(row, attachId); - e.preventDefault(); -}); - -/** - * Display the error message for a particular file when the error icon is clicked. - */ -$fileList.on('click', '.file-error', function(e) { - phpbb.alert($(this).attr('data-error-title'), $(this).attr('data-error-message')); - e.preventDefault(); -}); - -/** - * Fires when an error occurs. - */ -phpbb.plupload.uploader.bind('Error', function(up, error) { - error.file.name = plupload.xmlEncode(error.file.name); - - // The error message that Plupload provides for these is vague, so we'll be more specific. - if (error.code === plupload.FILE_EXTENSION_ERROR) { - error.message = plupload.translate('Invalid file extension:') + ' ' + error.file.name; - } else if (error.code === plupload.FILE_SIZE_ERROR) { - error.message = plupload.translate('File too large:') + ' ' + error.file.name; - } - phpbb.alert(phpbb.plupload.lang.ERROR, error.message); -}); - -/** - * Fires before a given file is about to be uploaded. This allows us to - * send the real filename along with the chunk. This is necessary because - * for some reason the filename is set to 'blob' whenever a file is chunked - * - * @param {object} up The plupload.Uploader object - * @param {object} file The plupload.File object that is about to be uploaded - */ -phpbb.plupload.uploader.bind('BeforeUpload', function(up, file) { - if (phpbb.plupload.handleMaxFilesReached()) { - return; - } - - phpbb.plupload.updateMultipartParams({ real_filename: file.name }); -}); - -/** - * Fired when a single chunk of any given file is uploaded. This parses the - * response from the server and checks for an error. If an error occurs it - * is reported to the user and the upload of this particular file is halted - * - * @param {object} up The plupload.Uploader object - * @param {object} file The plupload.File object whose chunk has just - * been uploaded - * @param {object} response The response object from the server - */ -phpbb.plupload.uploader.bind('ChunkUploaded', function(up, file, response) { - if (response.chunk >= response.chunks - 1) { - return; - } - - var json = {}; - try { - json = $.parseJSON(response.response); - } catch (e) { - file.status = plupload.FAILED; - up.trigger('FileUploaded', file, { - response: JSON.stringify({ - error: { - message: 'Error parsing server response.' - } - }) - }); - } - - // If trigger_error() was called, then a permission error likely occurred. - if (typeof json.title !== 'undefined') { - json.error = { message: json.message }; - } - - if (json.error) { - file.status = plupload.FAILED; - up.trigger('FileUploaded', file, { - response: JSON.stringify({ - error: { - message: json.error.message - } - }) - }); - } -}); - -/** - * Fires when files are added to the queue. - */ -phpbb.plupload.uploader.bind('FilesAdded', function(up, files) { - // Prevent unnecessary requests to the server if the user already uploaded - // the maximum number of files allowed. - if (phpbb.plupload.handleMaxFilesReached()) { - return; - } - - // Switch the active tab if the style supports it - if (typeof activateSubPanel === 'function') { - activateSubPanel('attach-panel'); // jshint ignore: line - } - - // Show the file list if there aren't any files currently. - var $fileListContainer = $('#file-list-container'); - if (!$fileListContainer.is(':visible')) { - $fileListContainer.show(100); - } - - $.each(files, function(i, file) { - phpbb.plupload.insertRow(file); - }); - - up.bind('UploadProgress', function(up, file) { - $('.file-progress-bar', '#' + file.id).css('width', file.percent + '%'); - $('#file-total-progress-bar').css('width', up.total.percent + '%'); - }); - - // Do not allow more files to be added to the running queue. - phpbb.plupload.disableUploader(); - - // Start uploading the files once the user has selected them. - up.start(); -}); - - -/** - * Fires when an entire file has been uploaded. It checks for errors - * returned by the server otherwise parses the list of attachment data and - * appends it to the next file upload so that the server can maintain state - * with regards to the attachments in a given post - * - * @param {object} up The plupload.Uploader object - * @param {object} file The plupload.File object that has just been - * uploaded - * @param {string} response The response string from the server - */ -phpbb.plupload.uploader.bind('FileUploaded', function(up, file, response) { - var json = {}, - row = $('#' + file.id), - error; - - // Hide the progress indicator. - row.find('.file-progress').hide(); - - try { - json = JSON.parse(response.response); - } catch (e) { - error = 'Error parsing server response.'; - } - - // If trigger_error() was called, then a permission error likely occurred. - if (typeof json.title !== 'undefined') { - error = json.message; - up.trigger('Error', { message: error }); - - // The rest of the queue will fail. - phpbb.plupload.markQueuedFailed(error); - } else if (json.error) { - error = json.error.message; - } - - if (typeof error !== 'undefined') { - phpbb.plupload.fileError(file, error); - } else if (file.status === plupload.DONE) { - file.attachment_data = json.data[0]; - - row.attr('data-attach-id', file.attachment_data.attach_id); - row.find('.file-inline-bbcode').show(); - row.find('.file-status').addClass('file-uploaded'); - phpbb.plupload.update(json.data, 'addition', 0, [json.download_url]); - } -}); - -/** - * Fires when the entire queue of files have been uploaded. - */ -phpbb.plupload.uploader.bind('UploadComplete', function() { - // Hide the progress bar - setTimeout(function() { - $('#file-total-progress-bar').fadeOut(500, function() { - $(this).css('width', 0).show(); - }); - }, 2000); - - // Re-enable the uploader - phpbb.plupload.enableUploader(); -}); - -})(jQuery); // Avoid conflicts with other libraries diff --git a/install/update/old/common.php b/install/update/old/common.php deleted file mode 100644 index 172503f..0000000 --- a/install/update/old/common.php +++ /dev/null @@ -1,164 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* Minimum Requirement: PHP 5.4.0 -*/ - -if (!defined('IN_PHPBB')) -{ - exit; -} - -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_ENVIRONMENT')) -{ - @define('PHPBB_ENVIRONMENT', 'production'); -} - -if (!defined('PHPBB_INSTALLED')) -{ - // Redirect the user to the installer - require($phpbb_root_path . 'includes/functions.' . $phpEx); - - // We have to generate a full HTTP/1.1 header here since we can't guarantee to have any of the information - // available as used by the redirect function - $server_name = (!empty($_SERVER['HTTP_HOST'])) ? strtolower($_SERVER['HTTP_HOST']) : ((!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME')); - $server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT'); - $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 1 : 0; - - if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') - { - $secure = 1; - $server_port = 443; - } - - $script_name = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : getenv('PHP_SELF'); - if (!$script_name) - { - $script_name = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : getenv('REQUEST_URI'); - } - - // $phpbb_root_path accounts for redirects from e.g. /adm - $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\filesystem(); - $script_path = $phpbb_filesystem->clean_path($script_path); - - $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; - header('Location: ' . $url); - exit; -} - -// 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); -include($phpbb_root_path . 'includes/functions_compatibility.' . $phpEx); - -require($phpbb_root_path . 'includes/constants.' . $phpEx); -require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - -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(); - -// Set up 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) -{ - @include($phpbb_root_path . 'includes/hooks/' . $hook . '.' . $phpEx); -} - -/** -* Main event which is triggered on every page -* -* You can use this event to load function files and initiate objects -* -* NOTE: At this point the global session ($user) and permissions ($auth) -* do NOT exist yet. If you need to use the user object -* (f.e. to include language files) or need to check permissions, -* please use the core.user_setup event instead! -* -* @event core.common -* @since 3.1.0-a1 -*/ -$phpbb_dispatcher->dispatch('core.common'); diff --git a/install/update/old/composer.json b/install/update/old/composer.json deleted file mode 100644 index d192fd5..0000000 --- a/install/update/old/composer.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "phpbb/phpbb", - "description": "phpBB Forum Software application", - "type": "project", - "keywords": ["phpbb", "forum"], - "homepage": "https://www.phpbb.com", - "license": "GPL-2.0-only", - "authors": [ - { - "name": "phpBB Limited", - "email": "operations@phpbb.com", - "homepage": "https://www.phpbb.com/go/authors" - } - ], - "support": { - "issues": "https://tracker.phpbb.com", - "forum": "https://www.phpbb.com/community/", - "wiki": "https://wiki.phpbb.com", - "irc": "irc://irc.freenode.org/phpbb" - }, - "scripts": { - "post-update-cmd": "echo 'You MUST manually modify the clean-vendor-dir target in build/build.xml when adding or upgrading dependencies.'" - }, - "replace": { - "phpbb/phpbb-core": "self.version" - }, - "require": { - "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": "^1.4", - "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": "~2.0", - "facebook/webdriver": "~1.1", - "laravel/homestead": "~2.2", - "phing/phing": "2.4.*", - "phpunit/dbunit": "1.3.*", - "phpunit/phpunit": "^4.1", - "sami/sami": "1.*", - "squizlabs/php_codesniffer": "2.*", - "symfony/browser-kit": "^2.8", - "symfony/css-selector": "^2.8", - "symfony/dom-crawler": "^2.8" - }, - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev" - } - }, - "config": { - "platform": { - "php": "5.4.7" - } - } -} diff --git a/install/update/old/composer.lock b/install/update/old/composer.lock deleted file mode 100644 index 2c338bf..0000000 --- a/install/update/old/composer.lock +++ /dev/null @@ -1,3644 +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#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "6daa2f5f7a161377dee1835bd4d5b463", - "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.3", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "93bbdb30d59be6cd9839495306c65f2907370eb9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/93bbdb30d59be6cd9839495306c65f2907370eb9", - "reference": "93bbdb30d59be6cd9839495306c65f2907370eb9", - "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": "2018-07-31T13:33:10+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.8.11", - "source": { - "type": "git", - "url": "https://github.com/Lusitanian/PHPoAuthLib.git", - "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/fc11a53db4b66da555a6a11fce294f574a8374f9", - "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "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." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.1-dev" - } - }, - "autoload": { - "psr-0": { - "OAuth": "src", - "OAuth\\Unit": "tests" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "David Desberg", - "email": "david@daviddesberg.com" - }, - { - "name": "Elliot Chance", - "email": "elliotchance@gmail.com" - }, - { - "name": "Pieter Hordijk", - "email": "info@pieterhordijk.com" - } - ], - "description": "PHP 5.3+ oAuth 1/2 Library", - "keywords": [ - "Authentication", - "authorization", - "oauth", - "security" - ], - "time": "2016-07-12T22:15:00+00:00" - }, - { - "name": "marc1706/fast-image-size", - "version": "v1.1.4", - "source": { - "type": "git", - "url": "https://github.com/marc1706/fast-image-size.git", - "reference": "c4ded0223a4e49ae45a2183a69f6afac5baf7250" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/marc1706/fast-image-size/zipball/c4ded0223a4e49ae45a2183a69f6afac5baf7250", - "reference": "c4ded0223a4e49ae45a2183a69f6afac5baf7250", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "type": "library", - "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": "2017-10-23T18:52:01+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": "v1.4.3", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "9b3899e3c3ddde89016f576edb8c489708ad64cd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/9b3899e3c3ddde89016f576edb8c489708ad64cd", - "reference": "9b3899e3c3ddde89016f576edb8c489708ad64cd", - "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", - "pseudorandom", - "random" - ], - "time": "2017-03-13T16:22:52+00:00" - }, - { - "name": "patchwork/utf8", - "version": "v1.3.1", - "source": { - "type": "git", - "url": "https://github.com/tchwork/utf8.git", - "reference": "30ec6451aec7d2536f0af8fe535f70c764f2c47a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tchwork/utf8/zipball/30ec6451aec7d2536f0af8fe535f70c764f2c47a", - "reference": "30ec6451aec7d2536f0af8fe535f70c764f2c47a", - "shasum": "" - }, - "require": { - "lib-pcre": ">=7.3", - "php": ">=5.3.0" - }, - "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": "2016-05-18T13:57:10+00:00" - }, - { - "name": "psr/log", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2018-11-20T15:27:04+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.2", - "source": { - "type": "git", - "url": "https://github.com/s9e/TextFormatter.git", - "reference": "dc7efff70b67b9cee00881ad3bef0a1da076b31e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/s9e/TextFormatter/zipball/dc7efff70b67b9cee00881ad3bef0a1da076b31e", - "reference": "dc7efff70b67b9cee00881ad3bef0a1da076b31e", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-filter": "*", - "lib-pcre": ">=7.2", - "php": ">=5.4.7" - }, - "require-dev": { - "matthiasmullie/minify": "*", - "php-coveralls/php-coveralls": "*", - "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-03-27T14:19:41+00:00" - }, - { - "name": "symfony/config", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "7dd5f5040dc04c118d057fb5886563963eb70011" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/7dd5f5040dc04c118d057fb5886563963eb70011", - "reference": "7dd5f5040dc04c118d057fb5886563963eb70011", - "shasum": "" - }, - "require": { - "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.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "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 Config Component", - "homepage": "https://symfony.com", - "time": "2018-11-26T09:38:12+00:00" - }, - { - "name": "symfony/console", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12", - "reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/debug": "^2.7.2|~3.0.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1|~3.0.0", - "symfony/process": "~2.1|~3.0.0" - }, - "suggest": { - "psr/log-implementation": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "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 Console Component", - "homepage": "https://symfony.com", - "time": "2018-11-20T15:55:20+00:00" - }, - { - "name": "symfony/debug", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "74251c8d50dd3be7c4ce0c7b862497cdc641a5d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/74251c8d50dd3be7c4ce0c7b862497cdc641a5d0", - "reference": "74251c8d50dd3be7c4ce0c7b862497cdc641a5d0", - "shasum": "" - }, - "require": { - "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/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.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "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 Debug Component", - "homepage": "https://symfony.com", - "time": "2018-11-11T11:18:13+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "a2f40df187f0053bc361bcea3b27ff2b85744d9f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a2f40df187f0053bc361bcea3b27ff2b85744d9f", - "reference": "a2f40df187f0053bc361bcea3b27ff2b85744d9f", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "conflict": { - "symfony/expression-language": "<2.6" - }, - "require-dev": { - "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.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "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 DependencyInjection Component", - "homepage": "https://symfony.com", - "time": "2018-11-11T11:18:13+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0", - "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "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": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "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 EventDispatcher Component", - "homepage": "https://symfony.com", - "time": "2018-11-21T14:20:20+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "7ae46872dad09dffb7fe1e93a0937097339d0080" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7ae46872dad09dffb7fe1e93a0937097339d0080", - "reference": "7ae46872dad09dffb7fe1e93a0937097339d0080", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "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 Filesystem Component", - "homepage": "https://symfony.com", - "time": "2018-11-11T11:18:13+00:00" - }, - { - "name": "symfony/finder", - "version": "v2.8.49", - "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.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "d0ab719bedc9fc6748a95b2dcb04137292a27b92" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0ab719bedc9fc6748a95b2dcb04137292a27b92", - "reference": "d0ab719bedc9fc6748a95b2dcb04137292a27b92", - "shasum": "" - }, - "require": { - "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.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "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 HttpFoundation Component", - "homepage": "https://symfony.com", - "time": "2018-11-25T11:27:05+00:00" - }, - { - "name": "symfony/http-kernel", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "3df0207d4c973eb9c91b38a608aef4654dc256fa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/3df0207d4c973eb9c91b38a608aef4654dc256fa", - "reference": "3df0207d4c973eb9c91b38a608aef4654dc256fa", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "psr/log": "~1.0", - "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" - }, - "conflict": { - "symfony/config": "<2.7", - "twig/twig": "<1.34|<2.4,>=2" - }, - "require-dev": { - "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": "", - "symfony/class-loader": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" - }, - "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 HttpKernel Component", - "homepage": "https://symfony.com", - "time": "2018-12-06T14:45:07+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.11.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "82ebae02209c21113908c229e9883c419720738a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", - "reference": "82ebae02209c21113908c229e9883c419720738a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, - { - "name": "Gert de Pagter", - "email": "backendtea@gmail.com" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "time": "2019-02-06T07:57:58+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.11.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "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 for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2019-02-06T07:57:58+00:00" - }, - { - "name": "symfony/polyfill-php54", - "version": "v1.11.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php54.git", - "reference": "2964b17ddc32dba7bcba009d5501c84d3fba1452" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/2964b17ddc32dba7bcba009d5501c84d3fba1452", - "reference": "2964b17ddc32dba7bcba009d5501c84d3fba1452", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-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-02-06T07:57:58+00:00" - }, - { - "name": "symfony/polyfill-php55", - "version": "v1.11.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php55.git", - "reference": "96fa25cef405ea452919559a0025d5dc16e30e4c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/96fa25cef405ea452919559a0025d5dc16e30e4c", - "reference": "96fa25cef405ea452919559a0025d5dc16e30e4c", - "shasum": "" - }, - "require": { - "ircmaxell/password-compat": "~1.0", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-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-02-06T07:57:58+00:00" - }, - { - "name": "symfony/proxy-manager-bridge", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/proxy-manager-bridge.git", - "reference": "9c5f8d58e9c8017affdbeaec86c89d558aee4ec8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/9c5f8d58e9c8017affdbeaec86c89d558aee4ec8", - "reference": "9c5f8d58e9c8017affdbeaec86c89d558aee4ec8", - "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": "2018-11-11T11:18:13+00:00" - }, - { - "name": "symfony/routing", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "8b0df6869d1997baafff6a1541826eac5a03d067" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/8b0df6869d1997baafff6a1541826eac5a03d067", - "reference": "8b0df6869d1997baafff6a1541826eac5a03d067", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "conflict": { - "symfony/config": "<2.7" - }, - "require-dev": { - "doctrine/annotations": "~1.0", - "psr/log": "~1.0", - "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/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.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Routing\\": "" - }, - "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 Routing Component", - "homepage": "https://symfony.com", - "keywords": [ - "router", - "routing", - "uri", - "url" - ], - "time": "2018-11-20T15:55:20+00:00" - }, - { - "name": "symfony/twig-bridge", - "version": "v2.8.49", - "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.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "02c1859112aa779d9ab394ae4f3381911d84052b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/02c1859112aa779d9ab394ae4f3381911d84052b", - "reference": "02c1859112aa779d9ab394ae4f3381911d84052b", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "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 Yaml Component", - "homepage": "https://symfony.com", - "time": "2018-11-11T11:18:13+00:00" - }, - { - "name": "twig/twig", - "version": "v1.39.1", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "23e7b6f0cfa1d7ba3de69f30d8e05cf957412fec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/23e7b6f0cfa1d7ba3de69f30d8e05cf957412fec", - "reference": "23e7b6f0cfa1d7ba3de69f30d8e05cf957412fec", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "symfony/polyfill-ctype": "^1.8" - }, - "require-dev": { - "psr/container": "^1.0", - "symfony/debug": "^2.7", - "symfony/phpunit-bridge": "^3.4.19|^4.1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.39-dev" - } - }, - "autoload": { - "psr-0": { - "Twig_": "lib/" - }, - "psr-4": { - "Twig\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - }, - { - "name": "Twig Team", - "homepage": "https://twig.symfony.com/contributors", - "role": "Contributors" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], - "time": "2019-04-16T17:12:57+00:00" - }, - { - "name": "zendframework/zend-code", - "version": "2.5.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-code.git", - "reference": "5d998f261ec2a55171c71da57a11622745680153" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-code/zipball/5d998f261ec2a55171c71da57a11622745680153", - "reference": "5d998f261ec2a55171c71da57a11622745680153", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-eventmanager": "~2.5" - }, - "require-dev": { - "doctrine/common": ">=2.1", - "fabpot/php-cs-fixer": "1.7.*", - "phpunit/phpunit": "~4.0", - "zendframework/zend-stdlib": "~2.5", - "zendframework/zend-version": "~2.5" - }, - "suggest": { - "doctrine/common": "Doctrine\\Common >=2.1 for annotation features", - "zendframework/zend-stdlib": "Zend\\Stdlib component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev", - "dev-develop": "2.6-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Code\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides facilities to generate arbitrary code using an object oriented interface", - "homepage": "https://github.com/zendframework/zend-code", - "keywords": [ - "code", - "zf2" - ], - "time": "2015-06-03T15:31:59+00:00" - }, - { - "name": "zendframework/zend-eventmanager", - "version": "2.5.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-eventmanager.git", - "reference": "d94a16039144936f107f906896349900fd634443" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/d94a16039144936f107f906896349900fd634443", - "reference": "d94a16039144936f107f906896349900fd634443", - "shasum": "" - }, - "require": { - "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": "2.5-dev", - "dev-develop": "2.6-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\EventManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zend-eventmanager", - "keywords": [ - "eventmanager", - "zf2" - ], - "time": "2015-06-03T15:32:01+00:00" - }, - { - "name": "zendframework/zend-stdlib", - "version": "2.5.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-stdlib.git", - "reference": "cc8e90a60dd5d44b9730b77d07b97550091da1ae" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/cc8e90a60dd5d44b9730b77d07b97550091da1ae", - "reference": "cc8e90a60dd5d44b9730b77d07b97550091da1ae", - "shasum": "" - }, - "require": { - "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": { - "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": "2.5-dev", - "dev-develop": "2.6-dev" - } - }, - "autoload": { - "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/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2015-06-14T21:17:01+00:00" - }, - { - "name": "fabpot/goutte", - "version": "v2.0.4", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/Goutte.git", - "reference": "0ad3ee6dc2d0aaa832a80041a1e09bf394e99802" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/0ad3ee6dc2d0aaa832a80041a1e09bf394e99802", - "reference": "0ad3ee6dc2d0aaa832a80041a1e09bf394e99802", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": ">=4,<6", - "php": ">=5.4.0", - "symfony/browser-kit": "~2.1", - "symfony/css-selector": "~2.1", - "symfony/dom-crawler": "~2.1" - }, - "type": "application", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-4": { - "Goutte\\": "Goutte" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "A simple PHP Web Scraper", - "homepage": "https://github.com/FriendsOfPHP/Goutte", - "keywords": [ - "scraper" - ], - "time": "2015-05-05T21:14:57+00:00" - }, - { - "name": "facebook/webdriver", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/facebook/php-webdriver.git", - "reference": "b7186fb1bcfda956d237f59face250d06ef47253" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/b7186fb1bcfda956d237f59face250d06ef47253", - "reference": "b7186fb1bcfda956d237f59face250d06ef47253", - "shasum": "" - }, - "require": { - "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": { - "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-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-4": { - "Laravel\\Homestead\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "description": "A virtual machine for web artisans.", - "time": "2016-09-17T04:42:33+00:00" - }, - { - "name": "michelf/php-markdown", - "version": "1.8.0", - "source": { - "type": "git", - "url": "https://github.com/michelf/php-markdown.git", - "reference": "01ab082b355bf188d907b9929cd99b2923053495" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/michelf/php-markdown/zipball/01ab082b355bf188d907b9929cd99b2923053495", - "reference": "01ab082b355bf188d907b9929cd99b2923053495", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Michelf\\": "Michelf/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Michel Fortin", - "email": "michel.fortin@michelf.ca", - "homepage": "https://michelf.ca/", - "role": "Developer" - }, - { - "name": "John Gruber", - "homepage": "https://daringfireball.net/" - } - ], - "description": "PHP Markdown", - "homepage": "https://michelf.ca/projects/php-markdown/", - "keywords": [ - "markdown" - ], - "time": "2018-01-15T00:49:33+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v0.9.5", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ef70767475434bdb3615b43c327e2cae17ef12eb", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.9-dev" - } - }, - "autoload": { - "psr-0": { - "PHPParser": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "time": "2014-07-23T18:24:17+00:00" - }, - { - "name": "phing/phing", - "version": "2.4.14", - "source": { - "type": "git", - "url": "https://github.com/phingofficial/phing.git", - "reference": "41075d93ca254f1c90c79ec7ce81be2b2629e138" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phingofficial/phing/zipball/41075d93ca254f1c90c79ec7ce81be2b2629e138", - "reference": "41075d93ca254f1c90c79ec7ce81be2b2629e138", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "bin": [ - "bin/phing" - ], - "type": "library", - "autoload": { - "classmap": [ - "classes/phing/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "classes" - ], - "license": [ - "LGPL3" - ], - "authors": [ - { - "name": "Michiel Rook", - "email": "mrook@php.net" - }, - { - "name": "Phing Community", - "homepage": "http://www.phing.info/trac/wiki/Development/Contributors" - } - ], - "description": "PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.", - "homepage": "http://www.phing.info/", - "keywords": [ - "build", - "task", - "tool" - ], - "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.8.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^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.8.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "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": "2018-08-05T17:53:17+00:00" - }, - { - "name": "phpunit/dbunit", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/dbunit.git", - "reference": "1507040c2541bdffd7fbd71fc792cecdea6a7c61" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/1507040c2541bdffd7fbd71fc792cecdea6a7c61", - "reference": "1507040c2541bdffd7fbd71fc792cecdea6a7c61", - "shasum": "" - }, - "require": { - "ext-pdo": "*", - "ext-simplexml": "*", - "php": ">=5.3.3", - "phpunit/phpunit": "~3.7|~4.0", - "symfony/yaml": "~2.1" - }, - "bin": [ - "composer/bin/dbunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "", - "../../symfony/yaml/" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "DbUnit port for PHP/PHPUnit to support database interaction testing.", - "homepage": "https://github.com/sebastianbergmann/dbunit/", - "keywords": [ - "database", - "testing", - "xunit" - ], - "abandoned": true, - "time": "2015-03-29T14:23:04+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "2.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2015-10-06T15:47:00+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" - }, - "dist": { - "type": "zip", - "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": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2017-11-27T13:52:08+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.9", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "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": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2017-02-26T11:10:40+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.4.12", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", - "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2017-12-04T08:55:13+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "4.8.36", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", - "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "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.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.1|~3.0" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.8.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2017-06-21T08:07:12+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" - }, - "dist": { - "type": "zip", - "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", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "abandoned": true, - "time": "2015-10-02T06:51:40+00:00" - }, - { - "name": "pimple/pimple", - "version": "v1.0.2", - "source": { - "type": "git", - "url": "https://github.com/silexphp/Pimple.git", - "reference": "ae11e57e8c2bb414b2ff93396dbbfc0eb92feb94" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/silexphp/Pimple/zipball/ae11e57e8c2bb414b2ff93396dbbfc0eb92feb94", - "reference": "ae11e57e8c2bb414b2ff93396dbbfc0eb92feb94", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "Pimple": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", - "homepage": "http://pimple.sensiolabs.org", - "keywords": [ - "container", - "dependency injection" - ], - "time": "2013-03-08T08:21:40+00:00" - }, - { - "name": "sami/sami", - "version": "v1.4.1", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/Sami.git", - "reference": "160018bfefffa730dc35a2c606691a45acbf41a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/Sami/zipball/160018bfefffa730dc35a2c606691a45acbf41a1", - "reference": "160018bfefffa730dc35a2c606691a45acbf41a1", - "shasum": "" - }, - "require": { - "michelf/php-markdown": "~1.3", - "nikic/php-parser": "0.9.*", - "php": ">=5.3.0", - "pimple/pimple": "1.0.*", - "symfony/console": "~2.1", - "symfony/filesystem": "~2.1", - "symfony/finder": "~2.1", - "symfony/process": "~2.1", - "symfony/yaml": "~2.1", - "twig/twig": "1.*" - }, - "bin": [ - "sami.php" - ], - "type": "application", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "psr-0": { - "Sami": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Sami, an API documentation generator", - "homepage": "http://sami.sensiolabs.org", - "keywords": [ - "phpdoc" - ], - "abandoned": true, - "time": "2015-06-05T03:36:34+00:00" - }, - { - "name": "sebastian/comparator", - "version": "1.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2017-01-29T09:50:25+00:00" - }, - { - "name": "sebastian/diff", - "version": "1.4.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2017-05-22T07:24:03+00:00" - }, - { - "name": "sebastian/environment", - "version": "1.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2016-08-18T05:49:44+00:00" - }, - { - "name": "sebastian/exporter", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "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", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", - "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-10-03T07:41:43+00:00" - }, - { - "name": "sebastian/version", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21T13:59:46+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "2.9.2", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "2acf168de78487db620ab4bc524135a13cfe6745" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745", - "reference": "2acf168de78487db620ab4bc524135a13cfe6745", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "bin": [ - "scripts/phpcs", - "scripts/phpcbf" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "classmap": [ - "CodeSniffer.php", - "CodeSniffer/CLI.php", - "CodeSniffer/Exception.php", - "CodeSniffer/File.php", - "CodeSniffer/Fixer.php", - "CodeSniffer/Report.php", - "CodeSniffer/Reporting.php", - "CodeSniffer/Sniff.php", - "CodeSniffer/Tokens.php", - "CodeSniffer/Reports/", - "CodeSniffer/Tokenizers/", - "CodeSniffer/DocGenerators/", - "CodeSniffer/Standards/AbstractPatternSniff.php", - "CodeSniffer/Standards/AbstractScopeSniff.php", - "CodeSniffer/Standards/AbstractVariableSniff.php", - "CodeSniffer/Standards/IncorrectPatternException.php", - "CodeSniffer/Standards/Generic/Sniffs/", - "CodeSniffer/Standards/MySource/Sniffs/", - "CodeSniffer/Standards/PEAR/Sniffs/", - "CodeSniffer/Standards/PSR1/Sniffs/", - "CodeSniffer/Standards/PSR2/Sniffs/", - "CodeSniffer/Standards/Squiz/Sniffs/", - "CodeSniffer/Standards/Zend/Sniffs/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", - "keywords": [ - "phpcs", - "standards" - ], - "time": "2018-11-07T22:31:41+00:00" - }, - { - "name": "symfony/browser-kit", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/browser-kit.git", - "reference": "b507697225f32a76a9d333d0766fb46353e9d00d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/b507697225f32a76a9d333d0766fb46353e9d00d", - "reference": "b507697225f32a76a9d333d0766fb46353e9d00d", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/dom-crawler": "~2.1|~3.0.0" - }, - "require-dev": { - "symfony/css-selector": "^2.0.5|~3.0.0", - "symfony/process": "~2.3.34|^2.7.6|~3.0.0" - }, - "suggest": { - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\BrowserKit\\": "" - }, - "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 BrowserKit Component", - "homepage": "https://symfony.com", - "time": "2018-11-26T06:55:10+00:00" - }, - { - "name": "symfony/css-selector", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "7b1692e418d7ccac24c373528453bc90e42797de" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/7b1692e418d7ccac24c373528453bc90e42797de", - "reference": "7b1692e418d7ccac24c373528453bc90e42797de", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony CssSelector Component", - "homepage": "https://symfony.com", - "time": "2018-11-11T11:18:13+00:00" - }, - { - "name": "symfony/dom-crawler", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "2cdc7d3909eea6f982a6298d2e9ab7db01b6403c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2cdc7d3909eea6f982a6298d2e9ab7db01b6403c", - "reference": "2cdc7d3909eea6f982a6298d2e9ab7db01b6403c", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "symfony/css-selector": "~2.8|~3.0.0" - }, - "suggest": { - "symfony/css-selector": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "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 DomCrawler Component", - "homepage": "https://symfony.com", - "time": "2018-11-24T22:30:19+00:00" - }, - { - "name": "symfony/process", - "version": "v2.8.49", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "c3591a09c78639822b0b290d44edb69bf9f05dc8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c3591a09c78639822b0b290d44edb69bf9f05dc8", - "reference": "c3591a09c78639822b0b290d44edb69bf9f05dc8", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "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 Process Component", - "homepage": "https://symfony.com", - "time": "2018-11-11T11:18:13+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.4" - }, - "platform-dev": [], - "platform-overrides": { - "php": "5.4.7" - } -} diff --git a/install/update/old/config/default/container/parameters.yml b/install/update/old/config/default/container/parameters.yml deleted file mode 100644 index 8ecc142..0000000 --- a/install/update/old/config/default/container/parameters.yml +++ /dev/null @@ -1,20 +0,0 @@ -parameters: - # Disable the usage of the super globals (_GET, _POST, _SERVER...) - core.disable_super_globals: true - - # Datetime class to use - datetime.class: \phpbb\datetime - - # Mimetype guesser priorities - mimetype.guesser.priority.lowest: -2 - mimetype.guesser.priority.low: -1 - mimetype.guesser.priority.default: 0 - mimetype.guesser.priority.high: 1 - mimetype.guesser.priority.highest: 2 - - # List of default password driver types - passwords.algorithms: - - passwords.driver.bcrypt_2y - - passwords.driver.bcrypt - - passwords.driver.salted_md5 - - passwords.driver.phpass diff --git a/install/update/old/config/default/container/services.yml b/install/update/old/config/default/container/services.yml deleted file mode 100644 index 9bb1d67..0000000 --- a/install/update/old/config/default/container/services.yml +++ /dev/null @@ -1,169 +0,0 @@ -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: - - '@language' - - 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/install/update/old/config/default/container/services_auth.yml b/install/update/old/config/default/container/services_auth.yml deleted file mode 100644 index ed8dc90..0000000 --- a/install/update/old/config/default/container/services_auth.yml +++ /dev/null @@ -1,110 +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_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/install/update/old/config/default/container/services_console.yml b/install/update/old/config/default/container/services_console.yml deleted file mode 100644 index 05e467f..0000000 --- a/install/update/old/config/default/container/services_console.yml +++ /dev/null @@ -1,295 +0,0 @@ -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/install/update/old/config/default/container/services_cron.yml b/install/update/old/config/default/container/services_cron.yml deleted file mode 100644 index d7f6388..0000000 --- a/install/update/old/config/default/container/services_cron.yml +++ /dev/null @@ -1,235 +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' - - '%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/install/update/old/config/default/container/services_password.yml b/install/update/old/config/default/container/services_password.yml deleted file mode 100644 index d5f5fe2..0000000 --- a/install/update/old/config/default/container/services_password.yml +++ /dev/null @@ -1,136 +0,0 @@ -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/install/update/old/config/default/container/services_routing.yml b/install/update/old/config/default/container/services_routing.yml deleted file mode 100644 index 3048145..0000000 --- a/install/update/old/config/default/container/services_routing.yml +++ /dev/null @@ -1,79 +0,0 @@ -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/install/update/old/config/default/container/services_text_formatter.yml b/install/update/old/config/default/container/services_text_formatter.yml deleted file mode 100644 index 07087cd..0000000 --- a/install/update/old/config/default/container/services_text_formatter.yml +++ /dev/null @@ -1,79 +0,0 @@ -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/install/update/old/config/default/container/services_twig.yml b/install/update/old/config/default/container/services_twig.yml deleted file mode 100644 index a9b5b6d..0000000 --- a/install/update/old/config/default/container/services_twig.yml +++ /dev/null @@ -1,68 +0,0 @@ -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/install/update/old/config/default/routing/routing.yml b/install/update/old/config/default/routing/routing.yml deleted file mode 100644 index f381f02..0000000 --- a/install/update/old/config/default/routing/routing.yml +++ /dev/null @@ -1,24 +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. -# - -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/install/update/old/cron.php b/install/update/old/cron.php deleted file mode 100644 index 2f51994..0000000 --- a/install/update/old/cron.php +++ /dev/null @@ -1,84 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -*/ -define('IN_PHPBB', true); -define('IN_CRON', true); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -include($phpbb_root_path . 'common.' . $phpEx); - -// Do not update users last page entry -$user->session_begin(false); -$auth->acl($user->data); - -function output_image() -{ - // Output transparent gif - header('Cache-Control: no-cache'); - header('Content-type: image/gif'); - header('Content-length: 43'); - - echo base64_decode('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='); - - // Flush here to prevent browser from showing the page as loading while - // running cron. - flush(); -} - -// Thanks to various fatal errors and lack of try/finally, it is quite easy to leave -// the cron lock locked, especially when working on cron-related code. -// -// Attempt to alleviate the problem by doing setup outside of the lock as much as possible. - -$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); - if ($task) - { - /** - * This event enables you to catch the task before it runs - * - * @event core.cron_run_before - * @var \phpbb\cron\task\wrapper task Current Cron task - * @since 3.1.8-RC1 - */ - $vars = array( - 'task', - ); - extract($phpbb_dispatcher->trigger_event('core.cron_run_before', compact($vars))); - - if ($task->is_parametrized()) - { - $task->parse_parameters($request); - } - if ($task->is_ready()) - { - $task->run(); - } - } - $cron_lock->release(); -} - -garbage_collection(); diff --git a/install/update/old/download/file.php b/install/update/old/download/file.php deleted file mode 100644 index 9ee489c..0000000 --- a/install/update/old/download/file.php +++ /dev/null @@ -1,326 +0,0 @@ - -* @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); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); - -// Thank you sun. -if (isset($_SERVER['CONTENT_TYPE'])) -{ - if ($_SERVER['CONTENT_TYPE'] === 'application/x-java-archive') - { - exit; - } -} -else if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'Java') !== false) -{ - exit; -} - -if (isset($_GET['avatar'])) -{ - 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_ENVIRONMENT')) - { - @define('PHPBB_ENVIRONMENT', 'production'); - } - - if (!defined('PHPBB_INSTALLED') || empty($dbms) || empty($acm_type)) - { - exit; - } - - require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/functions.' . $phpEx); - require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx); - require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - - // Setup class loader first - $phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/", $phpEx); - $phpbb_class_loader_ext->register(); - - // Set up 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); - - /* @var $config \phpbb\config\config */ - $config = $phpbb_container->get('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->variable('avatar', ''); - $avatar_group = false; - $exit = false; - - if (isset($filename[0]) && $filename[0] === 'g') - { - $avatar_group = true; - $filename = substr($filename, 1); - } - - // '==' is not a bug - . as the first char is as bad as no dot at all - if (strpos($filename, '.') == false) - { - send_status_line(403, 'Forbidden'); - $exit = true; - } - - if (!$exit) - { - $ext = substr(strrchr($filename, '.'), 1); - $stamp = (int) substr(stristr($filename, '_'), 1); - $filename = (int) $filename; - $exit = set_modified_headers($stamp, $browser); - } - if (!$exit && !in_array($ext, array('png', 'gif', 'jpg', 'jpeg'))) - { - // no way such an avatar could exist. They are not following the rules, stop the show. - send_status_line(403, 'Forbidden'); - $exit = true; - } - - - if (!$exit) - { - if (!$filename) - { - // no way such an avatar could exist. They are not following the rules, stop the show. - send_status_line(403, 'Forbidden'); - } - else - { - send_avatar_to_browser(($avatar_group ? 'g' : '') . $filename . '.' . $ext, $browser); - } - } - file_gc(); -} - -// implicit else: we are not in avatar mode -include($phpbb_root_path . 'common.' . $phpEx); -require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx); - -$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'); - trigger_error('ATTACHMENT_FUNCTIONALITY_DISABLED'); -} - -if (!$attach_id) -{ - send_status_line(404, 'Not Found'); - trigger_error('NO_ATTACHMENT_SELECTED'); -} - -$sql = 'SELECT attach_id, post_msg_id, topic_id, in_message, poster_id, is_orphan, physical_filename, real_filename, extension, mimetype, filesize, filetime - FROM ' . ATTACHMENTS_TABLE . " - WHERE attach_id = $attach_id"; -$result = $db->sql_query($sql); -$attachment = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -if (!$attachment) -{ - send_status_line(404, 'Not Found'); - trigger_error('ERROR_NO_ATTACHMENT'); -} -else if (!download_allowed()) -{ - send_status_line(403, 'Forbidden'); - trigger_error($user->lang['LINKAGE_FORBIDDEN']); -} -else -{ - $attachment['physical_filename'] = utf8_basename($attachment['physical_filename']); - - if (!$attachment['in_message'] && !$config['allow_attachments'] || $attachment['in_message'] && !$config['allow_pm_attach']) - { - send_status_line(404, 'Not Found'); - trigger_error('ATTACHMENT_FUNCTIONALITY_DISABLED'); - } - - if ($attachment['is_orphan']) - { - // We allow admins having attachment permissions to see orphan attachments... - $own_attachment = ($auth->acl_get('a_attach') || $attachment['poster_id'] == $user->data['user_id']) ? true : false; - - if (!$own_attachment || ($attachment['in_message'] && !$auth->acl_get('u_pm_download')) || (!$attachment['in_message'] && !$auth->acl_get('u_download'))) - { - send_status_line(404, 'Not Found'); - trigger_error('ERROR_NO_ATTACHMENT'); - } - - // Obtain all extensions... - $extensions = $cache->obtain_attach_extensions(true); - } - else - { - if (!$attachment['in_message']) - { - phpbb_download_handle_forum_auth($db, $auth, $attachment['topic_id']); - - $sql = 'SELECT forum_id, post_visibility - FROM ' . POSTS_TABLE . ' - WHERE post_id = ' . (int) $attachment['post_msg_id']; - $result = $db->sql_query($sql); - $post_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - 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'); - trigger_error('ERROR_NO_ATTACHMENT'); - } - } - else - { - // Attachment is in a private message. - $post_row = array('forum_id' => false); - phpbb_download_handle_pm_auth($db, $auth, $user->data['user_id'], $attachment['post_msg_id']); - } - - $extensions = array(); - if (!extension_allowed($post_row['forum_id'], $attachment['extension'], $extensions)) - { - send_status_line(403, 'Forbidden'); - trigger_error(sprintf($user->lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachment['extension'])); - } - } - - $download_mode = (int) $extensions[$attachment['extension']]['download_mode']; - $display_cat = $extensions[$attachment['extension']]['display_cat']; - - if (($display_cat == ATTACHMENT_CATEGORY_IMAGE || $display_cat == ATTACHMENT_CATEGORY_THUMB) && !$user->optionget('viewimg')) - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - - if ($display_cat == ATTACHMENT_CATEGORY_FLASH && !$user->optionget('viewflash')) - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - - /** - * Event to modify data before sending file to browser - * - * @event core.download_file_send_to_browser_before - * @var int attach_id The attachment ID - * @var array attachment Array with attachment data - * @var int display_cat Attachment category - * @var int download_mode File extension specific download mode - * @var array extensions Array with file extensions data - * @var string mode Download mode - * @var bool thumbnail Flag indicating if the file is a thumbnail - * @since 3.1.6-RC1 - * @changed 3.1.7-RC1 Fixing wrong name of a variable (replacing "extension" by "extensions") - */ - $vars = array( - 'attach_id', - 'attachment', - 'display_cat', - 'download_mode', - 'extensions', - 'mode', - 'thumbnail', - ); - extract($phpbb_dispatcher->trigger_event('core.download_file_send_to_browser_before', compact($vars))); - - if ($thumbnail) - { - $attachment['physical_filename'] = 'thumb_' . $attachment['physical_filename']; - } - else if ($display_cat == ATTACHMENT_CATEGORY_NONE && !$attachment['is_orphan'] && !phpbb_http_byte_range($attachment['filesize'])) - { - // Update download count - phpbb_increment_downloads($db, $attachment['attach_id']); - } - - if ($display_cat == ATTACHMENT_CATEGORY_IMAGE && $mode === 'view' && (strpos($attachment['mimetype'], 'image') === 0) && (strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7)) - { - wrap_img_in_html(append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'id=' . $attachment['attach_id']), $attachment['real_filename']); - file_gc(); - } - else - { - // Determine the 'presenting'-method - if ($download_mode == PHYSICAL_LINK) - { - // This presenting method should no longer be used - if (!@is_dir($phpbb_root_path . $config['upload_path'])) - { - send_status_line(500, 'Internal Server Error'); - trigger_error($user->lang['PHYSICAL_DOWNLOAD_NOT_POSSIBLE']); - } - - redirect($phpbb_root_path . $config['upload_path'] . '/' . $attachment['physical_filename']); - file_gc(); - } - else - { - send_file_to_browser($attachment, $config['upload_path'], $display_cat); - file_gc(); - } - } -} diff --git a/install/update/old/ext/phpbb/viglink/acp/viglink_helper.php b/install/update/old/ext/phpbb/viglink/acp/viglink_helper.php deleted file mode 100644 index 86568de..0000000 --- a/install/update/old/ext/phpbb/viglink/acp/viglink_helper.php +++ /dev/null @@ -1,146 +0,0 @@ - - * @license GNU General Public License, version 2 (GPL-2.0) - * - */ - -namespace phpbb\viglink\acp; - -/** - * Class to handle allowing or disallowing VigLink services - */ -class viglink_helper -{ - /** @var \phpbb\cache\driver\driver_interface $cache */ - protected $cache; - - /** @var \phpbb\config\config $config */ - protected $config; - - /** @var \phpbb\file_downloader $file_downloader */ - protected $file_downloader; - - /** @var \phpbb\language\language $language */ - protected $language; - - /** @var \phpbb\log\log $log */ - protected $log; - - /** @var \phpbb\user $user */ - protected $user; - - /** @var bool Use SSL or not */ - protected $use_ssl = false; - - /** - * Constructor - * - * @param \phpbb\cache\driver\driver_interface $cache - * @param \phpbb\config\config $config - * @param \phpbb\file_downloader $file_downloader - * @param \phpbb\language\language $language - * @param \phpbb\log\log $log - * @param \phpbb\user $user - */ - public function __construct(\phpbb\cache\driver\driver_interface $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader, \phpbb\language\language $language, \phpbb\log\log $log, \phpbb\user $user) - { - $this->cache = $cache; - $this->config = $config; - $this->file_downloader = $file_downloader; - $this->language = $language; - $this->log = $log; - $this->user = $user; - } - - /** - * Obtains the latest VigLink services information from phpBB - * - * @param bool $force_update Ignores cached data. Defaults to false. - * @param bool $force_cache Force the use of the cache. Override $force_update. - * - * @throws \RuntimeException - * - * @return void - */ - public function set_viglink_services($force_update = false, $force_cache = false) - { - $cache_key = '_versioncheck_viglink_' . $this->use_ssl; - - $info = $this->cache->get($cache_key); - - if ($info === false && $force_cache) - { - throw new \RuntimeException($this->language->lang('VERSIONCHECK_FAIL')); - } - else if ($info === false || $force_update) - { - try - { - $info = $this->file_downloader->get('www.phpbb.com', '/viglink', 'enabled', 443); - } - 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->language, 'lang'), $prepare_parameters)); - } - - if ($info === '0') - { - $this->set_viglink_configs(array( - 'allow_viglink_phpbb' => false, - )); - } - else - { - $info = '1'; - $this->set_viglink_configs(array( - 'allow_viglink_phpbb' => true, - )); - } - - $this->cache->put($cache_key, $info, 86400); // 24 hours - } - } - - /** - * Sets VigLink service configs as determined by phpBB - * - * @param array $data Array of VigLink file data. - * - * @return void - */ - protected function set_viglink_configs($data) - { - $viglink_configs = array( - 'allow_viglink_phpbb', - 'phpbb_viglink_api_key', - ); - - foreach ($viglink_configs as $cfg_name) - { - if (array_key_exists($cfg_name, $data) && ($data[$cfg_name] != $this->config[$cfg_name] || !isset($this->config[$cfg_name]))) - { - $this->config->set($cfg_name, $data[$cfg_name]); - } - } - - $this->config->set('viglink_last_gc', time(), false); - } - - /** - * Log a VigLink error message to the error log - * - * @param string $message The error message - */ - public function log_viglink_error($message) - { - $user_id = empty($this->user->data) ? ANONYMOUS : $this->user->data['user_id']; - $user_ip = empty($this->user->ip) ? '' : $this->user->ip; - - $this->log->add('critical', $user_id, $user_ip, 'LOG_VIGLINK_CHECK_FAIL', false, array($message)); - } -} diff --git a/install/update/old/ext/phpbb/viglink/composer.json b/install/update/old/ext/phpbb/viglink/composer.json deleted file mode 100644 index 30312e3..0000000 --- a/install/update/old/ext/phpbb/viglink/composer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "phpbb/viglink", - "type": "phpbb-extension", - "description": "The VigLink extension for phpBB makes it possible to earn revenue, without any change to the user experience, when users post and follow links to commercial sites.", - "homepage": "https://www.phpbb.com", - "version": "1.0.4", - "keywords": ["phpbb", "extension", "viglink"], - "license": "GPL-2.0-only", - "authors": [ - { - "name": "phpBB Limited", - "email": "operations@phpbb.com", - "homepage": "https://www.phpbb.com/go/authors" - } - ], - "require": { - "php": ">=5.4", - "phpbb/phpbb": ">=3.2.0-b1", - "composer/installers": "~1.0" - }, - "extra": { - "display-name": "VigLink", - "soft-require": { - "phpbb/phpbb": ">=3.2.0-b1,<3.3" - } - } -} diff --git a/install/update/old/ext/phpbb/viglink/composer.lock b/install/update/old/ext/phpbb/viglink/composer.lock deleted file mode 100644 index f03a73d..0000000 --- a/install/update/old/ext/phpbb/viglink/composer.lock +++ /dev/null @@ -1,115 +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": "155838fcd9206482cc645c3de6a7e8db", - "content-hash": "610135270d537f2e8580b747c6b57ce9", - "packages": [ - { - "name": "composer/installers", - "version": "v1.0.20", - "source": { - "type": "git", - "url": "https://github.com/composer/installers.git", - "reference": "1bff8aa77a18f3616f468ed8000cf86a5725bac3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/1bff8aa77a18f3616f468ed8000cf86a5725bac3", - "reference": "1bff8aa77a18f3616f468ed8000cf86a5725bac3", - "shasum": "" - }, - "replace": { - "roundcube/plugin-installer": "*", - "shama/baton": "*" - }, - "require-dev": { - "composer/composer": "1.0.*@dev", - "phpunit/phpunit": "4.1.*" - }, - "type": "composer-installer", - "extra": { - "class": "Composer\\Installers\\Installer", - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "Composer\\Installers\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kyle Robinson Young", - "email": "kyle@dontkry.com", - "homepage": "https://github.com/shama" - } - ], - "description": "A multi-framework Composer library installer", - "homepage": "http://composer.github.com/installers/", - "keywords": [ - "Craft", - "Dolibarr", - "Hurad", - "MODX Evo", - "OXID", - "SMF", - "Thelia", - "WolfCMS", - "agl", - "annotatecms", - "bitrix", - "cakephp", - "chef", - "codeigniter", - "concrete5", - "croogo", - "dokuwiki", - "drupal", - "elgg", - "fuelphp", - "grav", - "installer", - "joomla", - "kohana", - "laravel", - "lithium", - "magento", - "mako", - "mediawiki", - "modulework", - "moodle", - "phpbb", - "piwik", - "ppi", - "puppet", - "roundcube", - "shopware", - "silverstripe", - "symfony", - "typo3", - "wordpress", - "zend", - "zikula" - ], - "time": "2015-01-11 03:51:11" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.3.3" - }, - "platform-dev": [] -} diff --git a/install/update/old/ext/phpbb/viglink/styles/all/theme/viglink.css b/install/update/old/ext/phpbb/viglink/styles/all/theme/viglink.css deleted file mode 100644 index c507a54..0000000 --- a/install/update/old/ext/phpbb/viglink/styles/all/theme/viglink.css +++ /dev/null @@ -1,18 +0,0 @@ -/* phpBB VigLink Extension Style Sheet - ------------------------------------------------------------------------ - Copyright (c) phpBB Limited - - For full copyright and license information, please see - the docs/CREDITS.txt file. - ------------------------------------------------------------------------ -*/ - -.viglink-header { - background: url('images/VigLink_logo.png') no-repeat 0 0; - padding-bottom: 18px; - padding-left: 142px; -} - -.send-stats-tile > .viglink-header-h2 { - margin-bottom: 10px; -} diff --git a/install/update/old/feed.php b/install/update/old/feed.php deleted file mode 100644 index 1480867..0000000 --- a/install/update/old/feed.php +++ /dev/null @@ -1,58 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -* Idea and original RSS Feed 2.0 MOD (Version 1.0.8/9) by leviatan21 -* Original MOD: http://www.phpbb.com/community/viewtopic.php?f=69&t=1214645 -* MOD Author Profile: http://www.phpbb.com/community/memberlist.php?mode=viewprofile&u=345763 -* MOD Author Homepage: http://www.mssti.com/phpbb3/ -* -**/ - -use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\Routing\Exception\InvalidParameterException; - -/** -* @ignore -**/ -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); - -/** @var \phpbb\controller\helper $controller_helper */ -$controller_helper = $phpbb_container->get('controller.helper'); - -$forum_id = $request->variable('f', 0); -$topic_id = $request->variable('t', 0); -$mode = $request->variable('mode', ''); - -if ($forum_id !== 0) -{ - $url = $controller_helper->route('phpbb_feed_forum', array('forum_id' => $forum_id)); -} -else if ($topic_id !== 0) -{ - $url = $controller_helper->route('phpbb_feed_topic', array('topic_id' => $topic_id)); -} -else -{ - try - { - $url = $controller_helper->route('phpbb_feed_overall', array('mode' => $mode)); - } - catch (InvalidParameterException $e) - { - $url = $controller_helper->route('phpbb_feed_index'); - } -} - -$response = new RedirectResponse($url, 301); -$response->send(); diff --git a/install/update/old/includes/acp/acp_attachments.php b/install/update/old/includes/acp/acp_attachments.php deleted file mode 100644 index 5b1db5c..0000000 --- a/install/update/old/includes/acp/acp_attachments.php +++ /dev/null @@ -1,1732 +0,0 @@ - -* @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_attachments -{ - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\config\config */ - protected $config; - - /** @var ContainerBuilder */ - protected $phpbb_container; - - /** @var \phpbb\template\template */ - protected $template; - - /** @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_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->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->variable('action', ''); - - $form_key = 'acp_attach'; - 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); - } - - switch ($mode) - { - case 'attach': - $l_title = 'ACP_ATTACHMENT_SETTINGS'; - break; - - case 'extensions': - $l_title = 'ACP_MANAGE_EXTENSIONS'; - break; - - case 'ext_groups': - $l_title = 'ACP_EXTENSION_GROUPS'; - break; - - case 'orphan': - $l_title = 'ACP_ORPHAN_ATTACHMENTS'; - break; - - case 'manage': - $l_title = 'ACP_MANAGE_ATTACHMENTS'; - break; - - default: - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - - $this->tpl_name = 'acp_attachments'; - $this->page_title = $l_title; - - $template->assign_vars(array( - 'L_TITLE' => $user->lang[$l_title], - 'L_TITLE_EXPLAIN' => $user->lang[$l_title . '_EXPLAIN'], - 'U_ACTION' => $this->u_action) - ); - - switch ($mode) - { - case 'attach': - - if (!function_exists('get_supported_image_types')) - { - include($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - } - - $sql = 'SELECT group_name, cat_id - FROM ' . EXTENSION_GROUPS_TABLE . ' - WHERE cat_id > 0 - ORDER BY cat_id'; - $result = $db->sql_query($sql); - - $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']; - $s_assigned_groups[$row['cat_id']][] = $row['group_name']; - } - $db->sql_freeresult($result); - - $l_legend_cat_images = $user->lang['SETTINGS_CAT_IMAGES'] . ' [' . $user->lang['ASSIGNED_GROUP'] . ': ' . ((!empty($s_assigned_groups[ATTACHMENT_CATEGORY_IMAGE])) ? implode($user->lang['COMMA_SEPARATOR'], $s_assigned_groups[ATTACHMENT_CATEGORY_IMAGE]) : $user->lang['NO_EXT_GROUP']) . ']'; - - $display_vars = array( - 'title' => 'ACP_ATTACHMENT_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_ATTACHMENT_SETTINGS', - - 'img_max_width' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'img_max_height' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'img_link_width' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'img_link_height' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - - 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'upload_path' => array('lang' => 'UPLOAD_DIR', 'validate' => 'wpath', 'type' => 'text:25:100', 'explain' => true), - 'display_order' => array('lang' => 'DISPLAY_ORDER', 'validate' => 'bool', 'type' => 'custom', 'method' => 'display_order', 'explain' => true), - 'attachment_quota' => array('lang' => 'ATTACH_QUOTA', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_filesize' => array('lang' => 'ATTACH_MAX_FILESIZE', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_filesize_pm' => array('lang' => 'ATTACH_MAX_PM_FILESIZE','validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false), - 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false), - 'secure_downloads' => array('lang' => 'SECURE_DOWNLOADS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'secure_allow_deny' => array('lang' => 'SECURE_ALLOW_DENY', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_allow_deny', 'explain' => true), - 'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'check_attachment_content' => array('lang' => 'CHECK_CONTENT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend2' => $l_legend_cat_images, - 'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int: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_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']), - ) - ); - - /** - * Event to add and/or modify acp_attachement configurations - * - * @event core.acp_attachments_config_edit_add - * @var array display_vars Array of config values to display and process - * @var string mode Mode of the config page we are displaying - * @var boolean submit Do we display the form or process the submission - * @since 3.1.11-RC1 - */ - $vars = array('display_vars', 'mode', 'submit'); - extract($phpbb_dispatcher->trigger_event('core.acp_attachments_config_edit_add', compact($vars))); - - $this->new_config = $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 (count($error)) - { - $submit = false; - } - - // We go through the display_vars to make sure no one is trying to set variables he/she is not allowed to... - foreach ($display_vars['vars'] as $config_name => $null) - { - if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false) - { - continue; - } - - $this->new_config[$config_name] = $config_value = $cfg_array[$config_name]; - - if (in_array($config_name, array('attachment_quota', 'max_filesize', 'max_filesize_pm'))) - { - $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) - { - $config->set($config_name, $config_value); - } - } - - $this->perform_site_list(); - - if ($submit) - { - $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 (!count($error)) - { - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - } - - $template->assign_var('S_ATTACHMENT_SETTINGS', true); - - // Secure Download Options - Same procedure as with banning - $allow_deny = ($this->new_config['secure_allow_deny']) ? 'ALLOWED' : 'DISALLOWED'; - - $sql = 'SELECT * - FROM ' . SITELIST_TABLE; - $result = $db->sql_query($sql); - - $defined_ips = ''; - $ips = array(); - - while ($row = $db->sql_fetchrow($result)) - { - $value = ($row['site_ip']) ? $row['site_ip'] : $row['site_hostname']; - if ($value) - { - $defined_ips .= '' . $value . ''; - $ips[$row['site_id']] = $value; - } - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_SECURE_DOWNLOADS' => $this->new_config['secure_downloads'], - 'S_DEFINED_IPS' => ($defined_ips != '') ? true : false, - 'S_WARNING' => (count($error)) ? true : false, - - 'WARNING_MSG' => implode('
', $error), - 'DEFINED_IPS' => $defined_ips, - - 'L_SECURE_TITLE' => $user->lang['DEFINE_' . $allow_deny . '_IPS'], - 'L_IP_EXCLUDE' => $user->lang['EXCLUDE_FROM_' . $allow_deny . '_IP'], - 'L_REMOVE_IPS' => $user->lang['REMOVE_' . $allow_deny . '_IPS']) - ); - - // Output relevant options - foreach ($display_vars['vars'] 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' => (isset($user->lang[$vars])) ? $user->lang[$vars] : $vars) - ); - - continue; - } - - $type = explode(':', $vars['type']); - - $l_explain = ''; - if ($vars['explain'] && isset($vars['lang_explain'])) - { - $l_explain = (isset($user->lang[$vars['lang_explain']])) ? $user->lang[$vars['lang_explain']] : $vars['lang_explain']; - } - else if ($vars['explain']) - { - $l_explain = (isset($user->lang[$vars['lang'] . '_EXPLAIN'])) ? $user->lang[$vars['lang'] . '_EXPLAIN'] : ''; - } - - $content = build_cfg_template($type, $config_key, $this->new_config, $config_key, $vars); - if (empty($content)) - { - continue; - } - - $template->assign_block_vars('options', array( - 'KEY' => $config_key, - 'TITLE' => $user->lang[$vars['lang']], - 'S_EXPLAIN' => $vars['explain'], - 'TITLE_EXPLAIN' => $l_explain, - 'CONTENT' => $content, - ) - ); - - unset($display_vars['vars'][$config_key]); - } - - break; - - case 'extensions': - - if ($submit || isset($_POST['add_extension_check'])) - { - if ($submit) - { - // Change Extensions ? - $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 = count($extension_change_list); $i < $size; $i++) - { - $extensions[$extension_change_list[$i]]['group_id'] = $group_select_list[$i]; - } - - $sql = 'SELECT * - FROM ' . EXTENSIONS_TABLE . ' - ORDER BY extension_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['group_id'] != $extensions[$row['extension_id']]['group_id']) - { - $sql = 'UPDATE ' . EXTENSIONS_TABLE . ' - SET group_id = ' . (int) $extensions[$row['extension_id']]['group_id'] . ' - WHERE extension_id = ' . $row['extension_id']; - $db->sql_query($sql); - - $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->variable('extension_id_list', array(0)); - - if (count($extension_id_list)) - { - $sql = 'SELECT extension - FROM ' . EXTENSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('extension_id', $extension_id_list); - $result = $db->sql_query($sql); - - $extension_list = ''; - while ($row = $db->sql_fetchrow($result)) - { - $extension_list .= ($extension_list == '') ? $row['extension'] : ', ' . $row['extension']; - } - $db->sql_freeresult($result); - - $sql = 'DELETE - FROM ' . EXTENSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('extension_id', $extension_id_list); - $db->sql_query($sql); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXT_DEL', false, array($extension_list)); - } - } - - // Add Extension? - $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 (!count($error)) - { - $sql = 'SELECT extension_id - FROM ' . EXTENSIONS_TABLE . " - WHERE extension = '" . $db->sql_escape($add_extension) . "'"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $error[] = sprintf($user->lang['EXTENSION_EXIST'], $add_extension); - } - $db->sql_freeresult($result); - - if (!count($error)) - { - $sql_ary = array( - 'group_id' => $add_extension_group, - 'extension' => $add_extension - ); - - $db->sql_query('INSERT INTO ' . EXTENSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXT_ADD', false, array($add_extension)); - } - } - } - - if (!count($error)) - { - $notify[] = $user->lang['EXTENSIONS_UPDATED']; - } - - $cache->destroy('_extensions'); - } - - $template->assign_vars(array( - 'S_EXTENSIONS' => true, - 'ADD_EXTENSION' => (isset($add_extension)) ? $add_extension : '', - 'GROUP_SELECT_OPTIONS' => (isset($_POST['add_extension_check'])) ? $this->group_select('add_group_select', $add_extension_group, 'extension_group') : $this->group_select('add_group_select', false, 'extension_group')) - ); - - $sql = 'SELECT * - FROM ' . EXTENSIONS_TABLE . ' - ORDER BY group_id, extension'; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $old_group_id = $row['group_id']; - do - { - $s_spacer = false; - - $current_group_id = $row['group_id']; - if ($old_group_id != $current_group_id) - { - $s_spacer = true; - $old_group_id = $current_group_id; - } - - $template->assign_block_vars('extensions', array( - 'S_SPACER' => $s_spacer, - 'EXTENSION_ID' => $row['extension_id'], - 'EXTENSION' => $row['extension'], - 'GROUP_OPTIONS' => $this->group_select('group_select[]', $row['group_id'])) - ); - } - while ($row = $db->sql_fetchrow($result)); - } - $db->sql_freeresult($result); - - break; - - case 'ext_groups': - - $template->assign_var('S_EXTENSION_GROUPS', true); - - if ($submit) - { - $action = $request->variable('action', ''); - $group_id = $request->variable('g', 0); - - if ($action != 'add' && $action != 'edit') - { - trigger_error('NO_MODE', E_USER_ERROR); - } - - if (!$group_id && $action == 'edit') - { - trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if ($group_id) - { - $sql = 'SELECT * - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $result = $db->sql_query($sql); - $ext_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$ext_row) - { - trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - else - { - $ext_row = array(); - } - - $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) - { - $error[] = $user->lang['NO_EXT_GROUP_NAME']; - } - - // Check New Group Name - if ($new_group_name) - { - $sql = 'SELECT group_id - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($new_group_name)) . "'"; - if ($group_id) - { - $sql .= ' AND group_id <> ' . $group_id; - } - $result = $db->sql_query($sql); - - if ($db->sql_fetchrow($result)) - { - $error[] = sprintf($user->lang['EXTENSION_GROUP_EXIST'], $new_group_name); - } - $db->sql_freeresult($result); - } - - if (!count($error)) - { - // Ok, build the update/insert array - $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->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; - - if ($max_filesize == $config['max_filesize']) - { - $max_filesize = 0; - } - - if (!count($allowed_forums)) - { - $forum_select = false; - } - - $group_ary = array( - 'group_name' => $group_name, - '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, - 'allowed_forums'=> ($forum_select) ? serialize($allowed_forums) : '', - 'allow_in_pm' => ($allow_in_pm) ? 1 : 0, - ); - - if ($action == 'add') - { - $group_ary['download_mode'] = INLINE_LINK; - } - - $sql = ($action == 'add') ? 'INSERT INTO ' . EXTENSION_GROUPS_TABLE . ' ' : 'UPDATE ' . EXTENSION_GROUPS_TABLE . ' SET '; - $sql .= $db->sql_build_array((($action == 'add') ? 'INSERT' : 'UPDATE'), $group_ary); - $sql .= ($action == 'edit') ? " WHERE group_id = $group_id" : ''; - - $db->sql_query($sql); - - if ($action == 'add') - { - $group_id = $db->sql_nextid(); - } - - $group_name = (isset($user->lang['EXT_GROUP_' . $group_name])) ? $user->lang['EXT_GROUP_' . $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->variable('extensions', array(0)); - - if ($action == 'edit' && count($extension_list)) - { - $sql = 'UPDATE ' . EXTENSIONS_TABLE . " - SET group_id = 0 - WHERE group_id = $group_id"; - $db->sql_query($sql); - } - - if (count($extension_list)) - { - $sql = 'UPDATE ' . EXTENSIONS_TABLE . " - SET group_id = $group_id - WHERE " . $db->sql_in_set('extension_id', $extension_list); - $db->sql_query($sql); - } - - $cache->destroy('_extensions'); - - if (!count($error)) - { - $notify[] = $user->lang['SUCCESS_EXTENSION_GROUP_' . strtoupper($action)]; - } - } - - $cat_lang = array( - ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'], - ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'], - ATTACHMENT_CATEGORY_FLASH => $user->lang['CAT_FLASH_FILES'], - ); - - $group_id = $request->variable('g', 0); - $action = (isset($_POST['add'])) ? 'add' : $action; - - switch ($action) - { - case 'delete': - - if (confirm_box(true)) - { - $sql = 'SELECT group_name - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $result = $db->sql_query($sql); - $group_name = (string) $db->sql_fetchfield('group_name'); - $db->sql_freeresult($result); - - $sql = 'DELETE - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $db->sql_query($sql); - - // Set corresponding Extensions to a pending Group - $sql = 'UPDATE ' . EXTENSIONS_TABLE . " - SET group_id = 0 - WHERE group_id = $group_id"; - $db->sql_query($sql); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXTGROUP_DEL', false, array($group_name)); - - $cache->destroy('_extensions'); - - trigger_error($user->lang['EXTENSION_GROUP_DELETED'] . adm_back_link($this->u_action)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'group_id' => $group_id, - 'action' => 'delete', - ))); - } - - break; - - case 'edit': - - if (!$group_id) - { - trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql = 'SELECT * - FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $result = $db->sql_query($sql); - $ext_group_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $forum_ids = (!$ext_group_row['allowed_forums']) ? array() : unserialize(trim($ext_group_row['allowed_forums'])); - - // no break; - - case 'add': - - if ($action == 'add') - { - $ext_group_row = array( - 'group_name' => $request->variable('group_name', '', true), - 'cat_id' => 0, - 'allow_group' => 1, - 'allow_in_pm' => 1, - 'upload_icon' => '', - 'max_filesize' => 0, - ); - - $forum_ids = array(); - } - - $sql = 'SELECT * - FROM ' . EXTENSIONS_TABLE . " - WHERE group_id = $group_id - OR group_id = 0 - ORDER BY extension"; - $result = $db->sql_query($sql); - $extensions = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - if ($ext_group_row['max_filesize'] == 0) - { - $ext_group_row['max_filesize'] = (int) $config['max_filesize']; - } - - $max_filesize = get_formatted_filesize($ext_group_row['max_filesize'], false, array('mb', 'kb', 'b')); - $size_format = $max_filesize['si_identifier']; - $ext_group_row['max_filesize'] = $max_filesize['value']; - - $img_path = $config['upload_icons_path']; - - $filename_list = ''; - $no_image_select = false; - - $imglist = filelist($phpbb_root_path . $img_path); - - if (!empty($imglist[''])) - { - $imglist = array_values($imglist); - $imglist = $imglist[0]; - - foreach ($imglist as $key => $img) - { - if (!$ext_group_row['upload_icon']) - { - $no_image_select = true; - $selected = ''; - } - else - { - $selected = ($ext_group_row['upload_icon'] == $img) ? ' selected="selected"' : ''; - } - - if (strlen($img) > 255) - { - continue; - } - - $filename_list .= ''; - } - } - - $i = 0; - $assigned_extensions = ''; - foreach ($extensions as $num => $row) - { - if ($row['group_id'] == $group_id && $group_id) - { - $assigned_extensions .= ($i) ? ', ' . $row['extension'] : $row['extension']; - $i++; - } - } - - $s_extension_options = ''; - foreach ($extensions as $row) - { - $s_extension_options .= '' . $row['extension'] . ''; - } - - $template->assign_vars(array( - 'IMG_PATH' => $img_path, - 'ACTION' => $action, - 'GROUP_ID' => $group_id, - 'GROUP_NAME' => $ext_group_row['group_name'], - 'ALLOW_GROUP' => $ext_group_row['allow_group'], - 'ALLOW_IN_PM' => $ext_group_row['allow_in_pm'], - 'UPLOAD_ICON_SRC' => $phpbb_root_path . $img_path . '/' . $ext_group_row['upload_icon'], - 'EXTGROUP_FILESIZE' => $ext_group_row['max_filesize'], - 'ASSIGNED_EXTENSIONS' => $assigned_extensions, - - 'S_CATEGORY_SELECT' => $this->category_select('special_category', $group_id, 'category'), - 'S_EXT_GROUP_SIZE_OPTIONS' => size_select_options($size_format), - 'S_EXTENSION_OPTIONS' => $s_extension_options, - 'S_FILENAME_LIST' => $filename_list, - 'S_EDIT_GROUP' => true, - 'S_NO_IMAGE' => $no_image_select, - 'S_FORUM_IDS' => (count($forum_ids)) ? true : false, - - 'U_EXTENSIONS' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&mode=extensions"), - 'U_BACK' => $this->u_action, - - 'L_LEGEND' => $user->lang[strtoupper($action) . '_EXTENSION_GROUP']) - ); - - $s_forum_id_options = ''; - - /** @todo use in-built function **/ - - $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql, 600); - - $right = $cat_right = $padding_inc = 0; - $padding = $forum_list = $holding = ''; - $padding_store = array('0' => ''); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) - { - // Non-postable forum with no subforums, don't display - continue; - } - - if (!$auth->acl_get('f_list', $row['forum_id'])) - { - // if the user does not have permissions to list this forum skip - continue; - } - - if ($row['left_id'] < $right) - { - $padding .= '   '; - $padding_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - $padding = empty($padding_store[$row['parent_id']]) ? '' : $padding_store[$row['parent_id']]; - } - - $right = $row['right_id']; - - $selected = (in_array($row['forum_id'], $forum_ids)) ? ' selected="selected"' : ''; - - if ($row['left_id'] > $cat_right) - { - // make sure we don't forget anything - $s_forum_id_options .= $holding; - $holding = ''; - } - - if ($row['right_id'] - $row['left_id'] > 1) - { - $cat_right = max($cat_right, $row['right_id']); - - $holding .= ''; - } - else - { - $s_forum_id_options .= $holding . ''; - $holding = ''; - } - } - - if ($holding) - { - $s_forum_id_options .= $holding; - } - - $db->sql_freeresult($result); - unset($padding_store); - - $template->assign_vars(array( - 'S_FORUM_ID_OPTIONS' => $s_forum_id_options) - ); - - break; - } - - $sql = 'SELECT * - FROM ' . EXTENSION_GROUPS_TABLE . ' - ORDER BY allow_group DESC, allow_in_pm DESC, group_name'; - $result = $db->sql_query($sql); - - $old_allow_group = $old_allow_pm = 1; - while ($row = $db->sql_fetchrow($result)) - { - $s_add_spacer = ($old_allow_group != $row['allow_group'] || $old_allow_pm != $row['allow_in_pm']) ? true : false; - - $template->assign_block_vars('groups', array( - 'S_ADD_SPACER' => $s_add_spacer, - 'S_ALLOWED_IN_PM' => ($row['allow_in_pm']) ? true : false, - 'S_GROUP_ALLOWED' => ($row['allow_group']) ? true : false, - - 'U_EDIT' => $this->u_action . "&action=edit&g={$row['group_id']}", - 'U_DELETE' => $this->u_action . "&action=delete&g={$row['group_id']}", - - 'GROUP_NAME' => (isset($user->lang['EXT_GROUP_' . $row['group_name']])) ? $user->lang['EXT_GROUP_' . $row['group_name']] : $row['group_name'], - 'CATEGORY' => $cat_lang[$row['cat_id']], - ) - ); - - $old_allow_group = $row['allow_group']; - $old_allow_pm = $row['allow_in_pm']; - } - $db->sql_freeresult($result); - - break; - - case 'orphan': - - /* @var $pagination \phpbb\pagination */ - $pagination = $this->phpbb_container->get('pagination'); - - if ($submit) - { - $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 (count($delete_files)) - { - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', $delete_files) . ' - AND is_orphan = 1'; - $result = $db->sql_query($sql); - - $delete_files = array(); - while ($row = $db->sql_fetchrow($result)) - { - $this->attachment_manager->unlink($row['physical_filename'], 'file'); - - if ($row['thumbnail']) - { - $this->attachment_manager->unlink($row['physical_filename'], 'thumbnail'); - } - - $delete_files[$row['attach_id']] = $row['real_filename']; - } - $db->sql_freeresult($result); - } - - if (count($delete_files)) - { - $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($delete_files)); - $db->sql_query($sql); - - $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)); - } - - $upload_list = array(); - foreach ($add_files as $attach_id) - { - if (!isset($delete_files[$attach_id]) && !empty($post_ids[$attach_id])) - { - $upload_list[$attach_id] = $post_ids[$attach_id]; - } - } - unset($add_files); - - if (count($upload_list)) - { - $template->assign_var('S_UPLOADING_FILES', true); - - $sql = 'SELECT forum_id, forum_name - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - - $forum_names = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_names[$row['forum_id']] = $row['forum_name']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT forum_id, topic_id, post_id, poster_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $upload_list); - $result = $db->sql_query($sql); - - $post_info = array(); - while ($row = $db->sql_fetchrow($result)) - { - $post_info[$row['post_id']] = $row; - } - $db->sql_freeresult($result); - - // Select those attachments we want to change... - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($upload_list)) . ' - AND is_orphan = 1'; - $result = $db->sql_query($sql); - - $files_added = $space_taken = 0; - while ($row = $db->sql_fetchrow($result)) - { - $post_row = $post_info[$upload_list[$row['attach_id']]]; - - $template->assign_block_vars('upload', array( - 'FILE_INFO' => sprintf($user->lang['UPLOADING_FILE_TO'], $row['real_filename'], $post_row['post_id']), - 'S_DENIED' => (!$auth->acl_get('f_attach', $post_row['forum_id'])) ? true : false, - 'L_DENIED' => (!$auth->acl_get('f_attach', $post_row['forum_id'])) ? sprintf($user->lang['UPLOAD_DENIED_FORUM'], $forum_names[$row['forum_id']]) : '') - ); - - if (!$auth->acl_get('f_attach', $post_row['forum_id'])) - { - continue; - } - - // Adjust attachment entry - $sql_ary = array( - 'in_message' => 0, - 'is_orphan' => 0, - 'poster_id' => $post_row['poster_id'], - 'post_msg_id' => $post_row['post_id'], - 'topic_id' => $post_row['topic_id'], - ); - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE attach_id = ' . $row['attach_id']; - $db->sql_query($sql); - - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_attachment = 1 - WHERE post_id = ' . $post_row['post_id']; - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_attachment = 1 - WHERE topic_id = ' . $post_row['topic_id']; - $db->sql_query($sql); - - $space_taken += $row['filesize']; - $files_added++; - - $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) - { - $config->increment('upload_dir_size', $space_taken, false); - $config->increment('num_files', $files_added, false); - } - } - } - - $template->assign_vars(array( - '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_limit($sql, $attachments_per_page, $start); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('orphan', array( - 'FILESIZE' => get_formatted_filesize($row['filesize']), - 'FILETIME' => $user->format_date($row['filetime']), - 'REAL_FILENAME' => utf8_basename($row['real_filename']), - 'PHYSICAL_FILENAME' => utf8_basename($row['physical_filename']), - 'ATTACH_ID' => $row['attach_id'], - 'POST_IDS' => (!empty($post_ids[$row['attach_id']])) ? $post_ids[$row['attach_id']] : '', - 'U_FILE' => append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'mode=view&id=' . $row['attach_id'])) - ); - } - $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->variable('delete', array('' => 0))) : array(); - - if (count($delete_files)) - { - // Select those attachments we want to delete... - $sql = 'SELECT real_filename - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', $delete_files) . ' - AND is_orphan = 0'; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $deleted_filenames[] = $row['real_filename']; - } - $db->sql_freeresult($result); - - if ($num_deleted = $this->attachment_manager->delete('attach', $delete_files)) - { - if (count($delete_files) != $num_deleted) - { - $error[] = $user->lang['FILES_GONE']; - } - - $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 - { - $error[] = $user->lang['NO_FILES_TO_DELETE']; - } - } - } - - if ($action == 'stats') - { - $this->handle_stats_resync(); - } - - $stats_error = $this->check_stats_accuracy(); - - if ($stats_error) - { - $error[] = $stats_error; - } - - $template->assign_vars(array( - 'S_MANAGE' => true, - )); - - $start = $request->variable('start', 0); - - // Sort keys - $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']); - $sort_by_text = array('f' => $user->lang['FILENAME'], 't' => $user->lang['FILEDATE'], 's' => $user->lang['FILESIZE'], 'x' => $user->lang['EXTENSION'], 'd' => $user->lang['DOWNLOADS'],'p' => $user->lang['ATTACH_POST_TYPE'], 'u' => $user->lang['AUTHOR']); - $sort_by_sql = array('f' => 'a.real_filename', 't' => 'a.filetime', 's' => 'a.filesize', 'x' => 'a.extension', 'd' => 'a.download_count', 'p' => 'a.in_message', 'u' => 'u.username'); - - $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); - - $min_filetime = ($sort_days) ? (time() - ($sort_days * 86400)) : ''; - $limit_filetime = ($min_filetime) ? " AND a.filetime >= $min_filetime " : ''; - $start = ($sort_days && isset($_POST['sort'])) ? 0 : $start; - - $attachments_per_page = (int) $config['topics_per_page']; - - $stats = $this->get_attachment_stats($limit_filetime); - $num_files = $stats['num_files']; - $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); - - // If the user is trying to reach the second half of the attachments list, fetch it starting from the end - $store_reverse = false; - $sql_limit = $attachments_per_page; - - if ($start > $num_files / 2) - { - $store_reverse = true; - - // Select the sort order. Add time sort anchor for non-time sorting cases - $sql_sort_anchor = ($sort_key != 't') ? ', a.filetime ' . (($sort_dir == 'd') ? 'ASC' : 'DESC') : ''; - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'ASC' : 'DESC') . $sql_sort_anchor; - $sql_limit = $pagination->reverse_limit($start, $sql_limit, $num_files); - $sql_start = $pagination->reverse_start($start, $sql_limit, $num_files); - } - else - { - // Select the sort order. Add time sort anchor for non-time sorting cases - $sql_sort_anchor = ($sort_key != 't') ? ', a.filetime ' . (($sort_dir == 'd') ? 'DESC' : 'ASC') : ''; - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC') . $sql_sort_anchor; - $sql_start = $start; - } - - $attachments_list = array(); - - // Just get the files - $sql = 'SELECT a.*, u.username, u.user_colour, t.topic_title - FROM ' . ATTACHMENTS_TABLE . ' a - LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = a.poster_id) - LEFT JOIN ' . TOPICS_TABLE . " t ON (a.topic_id = t.topic_id) - WHERE a.is_orphan = 0 - $limit_filetime - ORDER BY $sql_sort_order"; - $result = $db->sql_query_limit($sql, $sql_limit, $sql_start); - - $i = ($store_reverse) ? $sql_limit - 1 : 0; - - // Store increment value in a variable to save some conditional calls - $i_increment = ($store_reverse) ? -1 : 1; - while ($attachment_row = $db->sql_fetchrow($result)) - { - $attachments_list[$i] = $attachment_row; - $i = $i + $i_increment; - } - $db->sql_freeresult($result); - - $base_url = $this->u_action . "&$u_sort_param"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_files, $attachments_per_page, $start); - - $template->assign_vars(array( - 'TOTAL_FILES' => $num_files, - 'TOTAL_SIZE' => get_formatted_filesize($total_size), - - 'S_LIMIT_DAYS' => $s_limit_days, - 'S_SORT_KEY' => $s_sort_key, - 'S_SORT_DIR' => $s_sort_dir) - ); - - // Grab extensions - $extensions = $cache->obtain_attach_extensions(true); - - 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('
', "\n"), $row['attach_comment']) : ''; - $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']] : '', - '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']), - - 'S_IN_MESSAGE' => (bool) $row['in_message'], - - 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}") . "#p{$row['post_msg_id']}", - 'U_FILE' => append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'mode=view&id=' . $row['attach_id'])) - ); - } - - break; - } - - if (count($error)) - { - $template->assign_vars(array( - 'S_WARNING' => true, - 'WARNING_MSG' => implode('
', $error)) - ); - } - - if (count($notify)) - { - $template->assign_vars(array( - 'S_NOTIFY' => true, - 'NOTIFY_MSG' => implode('
', $notify)) - ); - } - } - - /** - * Get attachment file count and size of upload directory - * - * @param $limit string Additional limit for WHERE clause to filter stats by. - * @return array Returns array with stats: num_files and upload_dir_size - */ - public function get_attachment_stats($limit = '') - { - $sql = 'SELECT COUNT(a.attach_id) AS num_files, SUM(a.filesize) AS upload_dir_size - FROM ' . ATTACHMENTS_TABLE . " a - WHERE a.is_orphan = 0 - $limit"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - return array( - 'num_files' => (int) $row['num_files'], - 'upload_dir_size' => (float) $row['upload_dir_size'], - ); - } - - /** - * Set config attachment stat values - * - * @param $stats array Array of config key => value pairs to set. - * @return null - */ - public function set_attachment_stats($stats) - { - foreach ($stats as $key => $value) - { - $this->config->set($key, $value, true); - } - } - - /** - * Check accuracy of attachment statistics. - * - * @return bool|string Returns false if stats are correct or error message - * otherwise. - */ - public function check_stats_accuracy() - { - // Get fresh stats. - $stats = $this->get_attachment_stats(); - - // Get current files stats - $num_files = (int) $this->config['num_files']; - $total_size = (float) $this->config['upload_dir_size']; - - if (($num_files != $stats['num_files']) || ($total_size != $stats['upload_dir_size'])) - { - $u_resync = $this->u_action . '&action=stats'; - - return $this->user->lang( - 'FILES_STATS_WRONG', - (int) $stats['num_files'], - get_formatted_filesize($stats['upload_dir_size']), - '', - '' - ); - } - return false; - } - - /** - * Handle stats resync. - * - * @return null - */ - public function handle_stats_resync() - { - if (!confirm_box(true)) - { - confirm_box(false, $this->user->lang['RESYNC_FILES_STATS_CONFIRM'], build_hidden_fields(array( - 'i' => $this->id, - 'mode' => 'manage', - 'action' => 'stats', - ))); - } - 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'); - } - - } - - /** - * Build Select for category items - */ - function category_select($select_name, $group_id = false, $key = '') - { - global $db, $user; - - $types = array( - ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'], - ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'], - ATTACHMENT_CATEGORY_FLASH => $user->lang['CAT_FLASH_FILES'], - ); - - if ($group_id) - { - $sql = 'SELECT cat_id - FROM ' . EXTENSION_GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - - $cat_type = (!($row = $db->sql_fetchrow($result))) ? ATTACHMENT_CATEGORY_NONE : $row['cat_id']; - - $db->sql_freeresult($result); - } - else - { - $cat_type = ATTACHMENT_CATEGORY_NONE; - } - - $group_select = ''; - - return $group_select; - } - - /** - * Extension group select - */ - function group_select($select_name, $default_group = false, $key = '') - { - global $db, $user; - - $group_select = ''; - - return $group_select; - } - - /** - * Test Settings - */ - function test_upload(&$error, $upload_dir, $create_directory = false) - { - global $user, $phpbb_root_path; - - // Does the target directory exist, is it a directory and writable. - if ($create_directory) - { - if (!file_exists($phpbb_root_path . $upload_dir)) - { - @mkdir($phpbb_root_path . $upload_dir, 0777); - - try - { - $this->filesystem->phpbb_chmod($phpbb_root_path . $upload_dir, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - - if (!file_exists($phpbb_root_path . $upload_dir)) - { - $error[] = sprintf($user->lang['NO_UPLOAD_DIR'], $upload_dir); - return; - } - - if (!is_dir($phpbb_root_path . $upload_dir)) - { - $error[] = sprintf($user->lang['UPLOAD_NOT_DIR'], $upload_dir); - return; - } - - if (!$this->filesystem->is_writable($phpbb_root_path . $upload_dir)) - { - $error[] = sprintf($user->lang['NO_WRITE_UPLOAD'], $upload_dir); - return; - } - } - - /** - * Perform operations on sites for external linking - */ - function perform_site_list() - { - global $db, $user, $request, $phpbb_log; - - if (isset($_REQUEST['securesubmit'])) - { - // Grab the list of entries - $ips = $request->variable('ips', ''); - $ip_list = array_unique(explode("\n", $ips)); - $ip_list_log = implode(', ', $ip_list); - - $ip_exclude = (int) $request->variable('ipexclude', false, false, \phpbb\request\request_interface::POST); - - $iplist = array(); - $hostlist = array(); - - foreach ($ip_list as $item) - { - if (preg_match('#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})[ ]*\-[ ]*([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#', trim($item), $ip_range_explode)) - { - // Don't ask about all this, just don't ask ... ! - $ip_1_counter = $ip_range_explode[1]; - $ip_1_end = $ip_range_explode[5]; - - while ($ip_1_counter <= $ip_1_end) - { - $ip_2_counter = ($ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[2] : 0; - $ip_2_end = ($ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[6]; - - if ($ip_2_counter == 0 && $ip_2_end == 254) - { - $ip_2_counter = 256; - - $iplist[] = "'$ip_1_counter.*'"; - } - - while ($ip_2_counter <= $ip_2_end) - { - $ip_3_counter = ($ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[3] : 0; - $ip_3_end = ($ip_2_counter < $ip_2_end || $ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[7]; - - if ($ip_3_counter == 0 && $ip_3_end == 254) - { - $ip_3_counter = 256; - - $iplist[] = "'$ip_1_counter.$ip_2_counter.*'"; - } - - while ($ip_3_counter <= $ip_3_end) - { - $ip_4_counter = ($ip_3_counter == $ip_range_explode[3] && $ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[4] : 0; - $ip_4_end = ($ip_3_counter < $ip_3_end || $ip_2_counter < $ip_2_end) ? 254 : $ip_range_explode[8]; - - if ($ip_4_counter == 0 && $ip_4_end == 254) - { - $ip_4_counter = 256; - - $iplist[] = "'$ip_1_counter.$ip_2_counter.$ip_3_counter.*'"; - } - - while ($ip_4_counter <= $ip_4_end) - { - $iplist[] = "'$ip_1_counter.$ip_2_counter.$ip_3_counter.$ip_4_counter'"; - $ip_4_counter++; - } - $ip_3_counter++; - } - $ip_2_counter++; - } - $ip_1_counter++; - } - } - else if (preg_match('#^([0-9]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})$#', trim($item)) || preg_match('#^[a-f0-9:]+\*?$#i', trim($item))) - { - $iplist[] = "'" . trim($item) . "'"; - } - else if (preg_match('#^([\w\-_]\.?){2,}$#is', trim($item))) - { - $hostlist[] = "'" . trim($item) . "'"; - } - else if (preg_match("#^([a-z0-9\-\*\._/]+?)$#is", trim($item))) - { - $hostlist[] = "'" . trim($item) . "'"; - } - } - - $sql = 'SELECT site_ip, site_hostname - FROM ' . SITELIST_TABLE . " - WHERE ip_exclude = $ip_exclude"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $iplist_tmp = array(); - $hostlist_tmp = array(); - do - { - if ($row['site_ip']) - { - if (strlen($row['site_ip']) > 40) - { - continue; - } - - $iplist_tmp[] = "'" . $row['site_ip'] . "'"; - } - else if ($row['site_hostname']) - { - if (strlen($row['site_hostname']) > 255) - { - continue; - } - - $hostlist_tmp[] = "'" . $row['site_hostname'] . "'"; - } - // break; - } - while ($row = $db->sql_fetchrow($result)); - - $iplist = array_unique(array_diff($iplist, $iplist_tmp)); - $hostlist = array_unique(array_diff($hostlist, $hostlist_tmp)); - unset($iplist_tmp); - unset($hostlist_tmp); - } - $db->sql_freeresult($result); - - if (count($iplist)) - { - foreach ($iplist as $ip_entry) - { - $sql = 'INSERT INTO ' . SITELIST_TABLE . " (site_ip, ip_exclude) - VALUES ($ip_entry, $ip_exclude)"; - $db->sql_query($sql); - } - } - - if (count($hostlist)) - { - foreach ($hostlist as $host_entry) - { - $sql = 'INSERT INTO ' . SITELIST_TABLE . " (site_hostname, ip_exclude) - VALUES ($host_entry, $ip_exclude)"; - $db->sql_query($sql); - } - } - - if (!empty($ip_list_log)) - { - // Update log - $log_entry = ($ip_exclude) ? 'LOG_DOWNLOAD_EXCLUDE_IP' : 'LOG_DOWNLOAD_IP'; - $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->variable('unip', array(0)); - - if (count($unip_sql)) - { - $l_unip_list = ''; - - // Grab details of ips for logging information later - $sql = 'SELECT site_ip, site_hostname - FROM ' . SITELIST_TABLE . ' - WHERE ' . $db->sql_in_set('site_id', $unip_sql); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $l_unip_list .= (($l_unip_list != '') ? ', ' : '') . (($row['site_ip']) ? $row['site_ip'] : $row['site_hostname']); - } - $db->sql_freeresult($result); - - $sql = 'DELETE FROM ' . SITELIST_TABLE . ' - WHERE ' . $db->sql_in_set('site_id', $unip_sql); - $db->sql_query($sql); - - $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)); - } - } - - /** - * Write display_order config field - */ - function display_order($value, $key = '') - { - $radio_ary = array(0 => 'DESCENDING', 1 => 'ASCENDING'); - - return h_radio('config[display_order]', $radio_ary, $value, $key); - } - - /** - * Adjust all three max_filesize config vars for display - */ - function max_filesize($value, $key = '') - { - // Determine size var and adjust the value accordingly - $filesize = get_formatted_filesize($value, false, array('mb', 'kb', 'b')); - $size_var = $filesize['si_identifier']; - $value = $filesize['value']; - - // size and maxlength must not be specified for input of type number - return ' '; - } - - /** - * Write secure_allow_deny config field - */ - function select_allow_deny($value, $key = '') - { - $radio_ary = array(1 => 'ORDER_ALLOW_DENY', 0 => 'ORDER_DENY_ALLOW'); - - return h_radio('config[' . $key . ']', $radio_ary, $value, $key); - } - -} diff --git a/install/update/old/includes/acp/acp_bbcodes.php b/install/update/old/includes/acp/acp_bbcodes.php deleted file mode 100644 index 1f7374a..0000000 --- a/install/update/old/includes/acp/acp_bbcodes.php +++ /dev/null @@ -1,620 +0,0 @@ - -* @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_bbcodes -{ - var $u_action; - - function main($id, $mode) - { - global $db, $user, $template, $cache, $request, $phpbb_dispatcher, $phpbb_container; - global $phpbb_log; - - $user->add_lang('acp/posting'); - - // Set up general vars - $action = $request->variable('action', ''); - $bbcode_id = $request->variable('bbcode', 0); - $submit = $request->is_set_post('submit'); - - $this->tpl_name = 'acp_bbcodes'; - $this->page_title = 'ACP_BBCODES'; - $form_key = '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) - { - case 'add': - $bbcode_match = $bbcode_tpl = $bbcode_helpline = ''; - $display_on_posting = 0; - break; - - case 'edit': - $sql = 'SELECT bbcode_match, bbcode_tpl, display_on_posting, bbcode_helpline - FROM ' . BBCODES_TABLE . ' - WHERE bbcode_id = ' . $bbcode_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['BBCODE_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $bbcode_match = $row['bbcode_match']; - $bbcode_tpl = htmlspecialchars($row['bbcode_tpl']); - $display_on_posting = $row['display_on_posting']; - $bbcode_helpline = $row['bbcode_helpline']; - break; - - case 'modify': - $sql = 'SELECT bbcode_id, bbcode_tag - FROM ' . BBCODES_TABLE . ' - WHERE bbcode_id = ' . $bbcode_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['BBCODE_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // No break here - - case 'create': - $display_on_posting = $request->variable('display_on_posting', 0); - - $bbcode_match = $request->variable('bbcode_match', ''); - $bbcode_tpl = htmlspecialchars_decode($request->variable('bbcode_tpl', '', true)); - $bbcode_helpline = $request->variable('bbcode_helpline', '', true); - break; - } - - // Do major work - switch ($action) - { - case 'edit': - case 'add': - - $tpl_ary = array( - 'S_EDIT_BBCODE' => true, - 'U_BACK' => $this->u_action, - 'U_ACTION' => $this->u_action . '&action=' . (($action == 'add') ? 'create' : 'modify') . (($bbcode_id) ? "&bbcode=$bbcode_id" : ''), - - 'L_BBCODE_USAGE_EXPLAIN'=> sprintf($user->lang['BBCODE_USAGE_EXPLAIN'], '', ''), - 'BBCODE_MATCH' => $bbcode_match, - 'BBCODE_TPL' => $bbcode_tpl, - 'BBCODE_HELPLINE' => $bbcode_helpline, - 'DISPLAY_ON_POSTING' => $display_on_posting, - ); - - $bbcode_tokens = array('TEXT', 'SIMPLETEXT', 'INTTEXT', 'IDENTIFIER', 'NUMBER', 'EMAIL', 'URL', 'LOCAL_URL', 'RELATIVE_URL', 'COLOR'); - - /** - * Modify custom bbcode template data before we display the add/edit form - * - * @event core.acp_bbcodes_edit_add - * @var string action Type of the action: add|edit - * @var array tpl_ary Array with custom bbcode add/edit data - * @var int bbcode_id When editing: the bbcode id, - * when creating: 0 - * @var array bbcode_tokens Array of bbcode tokens - * @since 3.1.0-a3 - */ - $vars = array('action', 'tpl_ary', 'bbcode_id', 'bbcode_tokens'); - extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_edit_add', compact($vars))); - - $template->assign_vars($tpl_ary); - - foreach ($bbcode_tokens as $token) - { - $template->assign_block_vars('token', array( - 'TOKEN' => '{' . $token . '}', - 'EXPLAIN' => ($token === 'LOCAL_URL') ? $user->lang(array('tokens', $token), generate_board_url() . '/') : $user->lang(array('tokens', $token)), - )); - } - - return; - - break; - - case 'modify': - case 'create': - - $sql_ary = $hidden_fields = array(); - - /** - * Modify custom bbcode data before the modify/create action - * - * @event core.acp_bbcodes_modify_create - * @var string action Type of the action: modify|create - * @var array sql_ary Array with new bbcode data - * @var int bbcode_id When editing: the bbcode id, - * when creating: 0 - * @var bool display_on_posting Display bbcode on posting form - * @var string bbcode_match The bbcode usage string to match - * @var string bbcode_tpl The bbcode HTML replacement string - * @var string bbcode_helpline The bbcode help line string - * @var array hidden_fields Array of hidden fields for use when - * submitting form when $warn_text is true - * @since 3.1.0-a3 - */ - $vars = array( - 'action', - 'sql_ary', - 'bbcode_id', - 'display_on_posting', - 'bbcode_match', - 'bbcode_tpl', - 'bbcode_helpline', - 'hidden_fields', - ); - extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_modify_create', compact($vars))); - - $warn_text = preg_match('%<[^>]*\{text[\d]*\}[^>]*>%i', $bbcode_tpl); - if (!$warn_text || confirm_box(true)) - { - $data = $this->build_regexp($bbcode_match, $bbcode_tpl); - - // Make sure the user didn't pick a "bad" name for the BBCode tag. - $hard_coded = array('code', 'quote', 'quote=', 'attachment', 'attachment=', 'b', 'i', 'url', 'url=', 'img', 'size', 'size=', 'color', 'color=', 'u', 'list', 'list=', 'email', 'email=', 'flash', 'flash='); - - if (($action == 'modify' && strtolower($data['bbcode_tag']) !== strtolower($row['bbcode_tag'])) || ($action == 'create')) - { - $sql = 'SELECT 1 as test - FROM ' . BBCODES_TABLE . " - WHERE LOWER(bbcode_tag) = '" . $db->sql_escape(strtolower($data['bbcode_tag'])) . "'"; - $result = $db->sql_query($sql); - $info = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Grab the end, interrogate the last closing tag - if ($info['test'] === '1' || in_array(strtolower($data['bbcode_tag']), $hard_coded) || (preg_match('#\[/([^[]*)]$#', $bbcode_match, $regs) && in_array(strtolower($regs[1]), $hard_coded))) - { - trigger_error($user->lang['BBCODE_INVALID_TAG_NAME'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - if (substr($data['bbcode_tag'], -1) === '=') - { - $test = substr($data['bbcode_tag'], 0, -1); - } - else - { - $test = $data['bbcode_tag']; - } - - if (!preg_match('%\\[' . $test . '[^]]*].*?\\[/' . $test . ']%s', $bbcode_match)) - { - trigger_error($user->lang['BBCODE_OPEN_ENDED_TAG'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (strlen($data['bbcode_tag']) > 16) - { - trigger_error($user->lang['BBCODE_TAG_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (strlen($bbcode_match) > 4000) - { - trigger_error($user->lang['BBCODE_TAG_DEF_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (strlen($bbcode_helpline) > 255) - { - trigger_error($user->lang['BBCODE_HELPLINE_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql_ary = array_merge($sql_ary, array( - 'bbcode_tag' => $data['bbcode_tag'], - 'bbcode_match' => $bbcode_match, - 'bbcode_tpl' => $bbcode_tpl, - 'display_on_posting' => $display_on_posting, - 'bbcode_helpline' => $bbcode_helpline, - 'first_pass_match' => $data['first_pass_match'], - 'first_pass_replace' => $data['first_pass_replace'], - 'second_pass_match' => $data['second_pass_match'], - 'second_pass_replace' => $data['second_pass_replace'] - )); - - if ($action == 'create') - { - $sql = 'SELECT MAX(bbcode_id) as max_bbcode_id - FROM ' . BBCODES_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $bbcode_id = (int) $row['max_bbcode_id'] + 1; - - // Make sure it is greater than the core bbcode ids... - if ($bbcode_id <= NUM_CORE_BBCODES) - { - $bbcode_id = NUM_CORE_BBCODES + 1; - } - } - else - { - $bbcode_id = NUM_CORE_BBCODES + 1; - } - - if ($bbcode_id > BBCODE_LIMIT) - { - trigger_error($user->lang['TOO_MANY_BBCODES'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql_ary['bbcode_id'] = (int) $bbcode_id; - - $db->sql_query('INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary)); - $cache->destroy('sql', BBCODES_TABLE); - $phpbb_container->get('text_formatter.cache')->invalidate(); - - $lang = 'BBCODE_ADDED'; - $log_action = 'LOG_BBCODE_ADD'; - } - else - { - $sql = 'UPDATE ' . BBCODES_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE bbcode_id = ' . $bbcode_id; - $db->sql_query($sql); - $cache->destroy('sql', BBCODES_TABLE); - $phpbb_container->get('text_formatter.cache')->invalidate(); - - $lang = 'BBCODE_EDITED'; - $log_action = 'LOG_BBCODE_EDIT'; - } - - $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)); - } - else - { - confirm_box(false, $user->lang['BBCODE_DANGER'], build_hidden_fields(array_merge($hidden_fields, array( - 'action' => $action, - 'bbcode' => $bbcode_id, - 'bbcode_match' => $bbcode_match, - 'bbcode_tpl' => htmlspecialchars($bbcode_tpl), - 'bbcode_helpline' => $bbcode_helpline, - 'display_on_posting' => $display_on_posting, - ))) - , 'confirm_bbcode.html'); - } - - break; - - case 'delete': - - $sql = 'SELECT bbcode_tag - FROM ' . BBCODES_TABLE . " - WHERE bbcode_id = $bbcode_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - 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); - $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()) - { - $json_response = new \phpbb\json_response; - $json_response->send(array( - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $user->lang['BBCODE_DELETED'], - 'REFRESH_DATA' => array( - 'time' => 3 - ) - )); - } - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'bbcode' => $bbcode_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action)) - ); - } - } - - break; - } - - $u_action = $this->u_action; - - $template_data = array( - 'U_ACTION' => $this->u_action . '&action=add', - ); - - $sql_ary = array( - 'SELECT' => 'b.*', - 'FROM' => array(BBCODES_TABLE => 'b'), - 'ORDER_BY' => 'b.bbcode_tag', - ); - - /** - * Modify custom bbcode template data before we display the form - * - * @event core.acp_bbcodes_display_form - * @var string action Type of the action: modify|create - * @var array sql_ary The SQL array to get custom bbcode data - * @var array template_data Array with form template data - * @var string u_action The u_action link - * @since 3.1.0-a3 - */ - $vars = array('action', 'sql_ary', 'template_data', 'u_action'); - extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_display_form', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - - $template->assign_vars($template_data); - - while ($row = $db->sql_fetchrow($result)) - { - $bbcodes_array = array( - 'BBCODE_TAG' => $row['bbcode_tag'], - 'U_EDIT' => $u_action . '&action=edit&bbcode=' . $row['bbcode_id'], - 'U_DELETE' => $u_action . '&action=delete&bbcode=' . $row['bbcode_id'], - ); - - /** - * Modify display of custom bbcodes in the form - * - * @event core.acp_bbcodes_display_bbcodes - * @var array row Array with current bbcode data - * @var array bbcodes_array Array of bbcodes template data - * @var string u_action The u_action link - * @since 3.1.0-a3 - */ - $vars = array('bbcodes_array', 'row', 'u_action'); - extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_display_bbcodes', compact($vars))); - - $template->assign_block_vars('bbcodes', $bbcodes_array); - - } - $db->sql_freeresult($result); - } - - /* - * Build regular expression for custom bbcode - */ - function build_regexp(&$bbcode_match, &$bbcode_tpl) - { - $bbcode_match = trim($bbcode_match); - $bbcode_tpl = trim($bbcode_tpl); - - // Allow unicode characters for URL|LOCAL_URL|RELATIVE_URL|INTTEXT tokens - $utf8 = preg_match('/(URL|LOCAL_URL|RELATIVE_URL|INTTEXT)/', $bbcode_match); - - $fp_match = preg_quote($bbcode_match, '!'); - $fp_replace = preg_replace('#^\[(.*?)\]#', '[$1:$uid]', $bbcode_match); - $fp_replace = preg_replace('#\[/(.*?)\]$#', '[/$1:$uid]', $fp_replace); - - $sp_match = preg_quote($bbcode_match, '!'); - $sp_match = preg_replace('#^\\\\\[(.*?)\\\\\]#', '\[$1:$uid\]', $sp_match); - $sp_match = preg_replace('#\\\\\[/(.*?)\\\\\]$#', '\[/$1:$uid\]', $sp_match); - $sp_replace = $bbcode_tpl; - - // @todo Make sure to change this too if something changed in message parsing - $tokens = array( - 'URL' => array( - '!(?:(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('url')) . ')|(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('www_url')) . '))!ie' => "\$this->bbcode_specialchars(('\$1') ? '\$1' : 'http://\$2')" - ), - 'LOCAL_URL' => array( - '!(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')!e' => "\$this->bbcode_specialchars('$1')" - ), - 'RELATIVE_URL' => array( - '!(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')!e' => "\$this->bbcode_specialchars('$1')" - ), - 'EMAIL' => array( - '!(' . get_preg_expression('email') . ')!ie' => "\$this->bbcode_specialchars('$1')" - ), - 'TEXT' => array( - '!(.*?)!es' => "str_replace(array(\"\\r\\n\", '\\\"', '\\'', '(', ')'), array(\"\\n\", '\"', ''', '(', ')'), trim('\$1'))" - ), - 'SIMPLETEXT' => array( - '!([a-zA-Z0-9-+.,_ ]+)!' => "$1" - ), - 'INTTEXT' => array( - '!([\p{L}\p{N}\-+,_. ]+)!u' => "$1" - ), - 'IDENTIFIER' => array( - '!([a-zA-Z0-9-_]+)!' => "$1" - ), - 'COLOR' => array( - '!([a-z]+|#[0-9abcdef]+)!i' => '$1' - ), - 'NUMBER' => array( - '!([0-9]+)!' => '$1' - ) - ); - - $sp_tokens = array( - 'URL' => '(?i)((?:' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('url')) . ')|(?:' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('www_url')) . '))(?-i)', - 'LOCAL_URL' => '(?i)(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')(?-i)', - 'RELATIVE_URL' => '(?i)(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')(?-i)', - 'EMAIL' => '(' . get_preg_expression('email') . ')', - 'TEXT' => '(.*?)', - 'SIMPLETEXT' => '([a-zA-Z0-9-+.,_ ]+)', - 'INTTEXT' => '([\p{L}\p{N}\-+,_. ]+)', - 'IDENTIFIER' => '([a-zA-Z0-9-_]+)', - 'COLOR' => '([a-zA-Z]+|#[0-9abcdefABCDEF]+)', - 'NUMBER' => '([0-9]+)', - ); - - $pad = 0; - $modifiers = 'i'; - $modifiers .= ($utf8) ? 'u' : ''; - - if (preg_match_all('/\{(' . implode('|', array_keys($tokens)) . ')[0-9]*\}/i', $bbcode_match, $m)) - { - foreach ($m[0] as $n => $token) - { - $token_type = $m[1][$n]; - - reset($tokens[strtoupper($token_type)]); - list($match, $replace) = each($tokens[strtoupper($token_type)]); - - // Pad backreference numbers from tokens - if (preg_match_all('/(?lang['BBCODE_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $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, - 'first_pass_match' => $fp_match, - 'first_pass_replace' => $fp_replace, - 'second_pass_match' => $sp_match, - 'second_pass_replace' => $sp_replace - ); - } -} diff --git a/install/update/old/includes/acp/acp_board.php b/install/update/old/includes/acp/acp_board.php deleted file mode 100644 index e348c76..0000000 --- a/install/update/old/includes/acp/acp_board.php +++ /dev/null @@ -1,1178 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @todo add cron intervals to server settings? (database_gc, queue_interval, session_gc, search_gc, cache_gc, warnings_gc) -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -class acp_board -{ - var $u_action; - var $new_config; - - function main($id, $mode) - { - 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'); - - $submit = (isset($_POST['submit']) || isset($_POST['allow_quick_reply_enable'])) ? true : false; - - $form_key = 'acp_board'; - add_form_key($form_key); - - /** - * Validation types are: - * string, int, bool, - * script_path (absolute path in url - beginning with / and no trailing slash), - * rpath (relative), rwpath (realtive, writable), path (relative path, but able to escape the root), wpath (writable) - */ - switch ($mode) - { - case 'settings': - $display_vars = array( - 'title' => 'ACP_BOARD_SETTINGS', - 'vars' => array( - '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' => '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), - 'board_disable_msg' => false, - 'default_lang' => array('lang' => 'DEFAULT_LANGUAGE', 'validate' => 'lang', 'type' => 'select', 'function' => 'language_select', 'params' => array('{CONFIG_VALUE}'), 'explain' => false), - 'default_dateformat' => array('lang' => 'DEFAULT_DATE_FORMAT', 'validate' => 'string', 'type' => 'custom', 'method' => 'dateformat_select', 'explain' => true), - 'board_timezone' => array('lang' => 'SYSTEM_TIMEZONE', 'validate' => 'timezone', 'type' => 'custom', 'method' => 'timezone_select', 'explain' => true), - - 'legend2' => 'BOARD_STYLE', - 'default_style' => array('lang' => 'DEFAULT_STYLE', 'validate' => 'int', 'type' => 'select', 'function' => 'style_select', 'params' => array('{CONFIG_VALUE}', false), 'explain' => true), - 'guest_style' => array('lang' => 'GUEST_STYLE', 'validate' => 'int', 'type' => 'select', 'function' => 'style_select', 'params' => array($this->guest_style_get(), false), 'explain' => true), - 'override_user_style' => array('lang' => 'OVERRIDE_STYLE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend3' => 'WARNINGS', - 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - - 'legend4' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'features': - $display_vars = array( - 'title' => 'ACP_BOARD_FEATURES', - 'vars' => array( - 'legend1' => 'ACP_BOARD_FEATURES', - 'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_topic_notify' => array('lang' => 'ALLOW_TOPIC_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_forum_notify' => array('lang' => 'ALLOW_FORUM_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_report' => array('lang' => 'ALLOW_PM_REPORT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig' => array('lang' => 'ALLOW_SIG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_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), - 'display_last_subject' => array('lang' => 'DISPLAY_LAST_SUBJECT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'custom', 'method' => 'quick_reply', 'explain' => true), - - 'legend2' => 'ACP_LOAD_SETTINGS', - 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - '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_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - 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); - - /* - * First grab the settings for enabling/disabling the avatar - * driver and afterwards grab additional settings the driver - * might have. - */ - $avatar_vars += $phpbb_avatar_manager->get_avatar_settings($driver); - $avatar_vars += $driver->prepare_form_acp($user); - } - - $display_vars = array( - 'title' => 'ACP_AVATAR_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_AVATAR_SETTINGS', - - 'avatar_min_width' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), - 'avatar_min_height' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), - 'avatar_max_width' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), - 'avatar_max_height' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), - - 'allow_avatar' => array('lang' => 'ALLOW_AVATARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - ) - ); - - if (!empty($avatar_vars)) - { - $display_vars['vars'] += $avatar_vars; - } - break; - - case 'message': - $display_vars = array( - 'title' => 'ACP_MESSAGE_SETTINGS', - 'lang' => 'ucp', - 'vars' => array( - 'legend1' => 'GENERAL_SETTINGS', - 'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'full_folder_action' => array('lang' => 'FULL_FOLDER_ACTION', 'validate' => 'int', 'type' => 'select', 'method' => 'full_folder_select', 'explain' => true), - 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'pm_max_recipients' => array('lang' => 'PM_MAX_RECIPIENTS', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), - - 'legend2' => 'GENERAL_OPTIONS', - 'allow_mass_pm' => array('lang' => 'ALLOW_MASS_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_bbcode_pm' => array('lang' => 'ALLOW_BBCODE_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_smilies_pm' => array('lang' => 'ALLOW_SMILIES_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_pm' => array('lang' => 'ALLOW_SIG_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'print_pm' => array('lang' => 'ALLOW_PRINT_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'forward_pm' => array('lang' => 'ALLOW_FORWARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_img_pm' => array('lang' => 'ALLOW_IMG_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_flash_pm' => array('lang' => 'ALLOW_FLASH_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'enable_pm_icons' => array('lang' => 'ENABLE_PM_ICONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'post': - $display_vars = array( - 'title' => 'ACP_POST_SETTINGS', - 'vars' => array( - 'legend1' => 'GENERAL_OPTIONS', - 'allow_topic_notify' => array('lang' => 'ALLOW_TOPIC_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_forum_notify' => array('lang' => 'ALLOW_FORUM_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - '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), - 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'custom', 'method' => 'quick_reply', 'explain' => true), - - 'legend2' => 'POSTING', - 'bump_type' => false, - 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'delete_time' => array('lang' => 'DELETE_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'display_last_edited' => array('lang' => 'DISPLAY_LAST_EDITED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int:0:9999999999', 'type' => 'number:0:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'bump_interval' => array('lang' => 'BUMP_INTERVAL', 'validate' => 'int:0', 'type' => 'custom', 'method' => 'bump_interval', 'explain' => true), - 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), - 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), - 'smilies_per_page' => array('lang' => 'SMILIES_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), - 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int:2:127', 'type' => 'number:2:127', 'explain' => false), - 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int:0:999999', 'type' => 'number:0:999999', 'explain' => true), - 'min_post_chars' => array('lang' => 'MIN_CHAR_LIMIT', 'validate' => 'int:1:999999', 'type' => 'number:1:999999', 'explain' => true), - 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'), - 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'signature': - $display_vars = array( - 'title' => 'ACP_SIGNATURE_SETTINGS', - 'vars' => array( - 'legend1' => 'GENERAL_OPTIONS', - 'allow_sig' => array('lang' => 'ALLOW_SIG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_bbcode' => array('lang' => 'ALLOW_SIG_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_img' => array('lang' => 'ALLOW_SIG_IMG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_flash' => array('lang' => 'ALLOW_SIG_FLASH', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_smilies' => array('lang' => 'ALLOW_SIG_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_links' => array('lang' => 'ALLOW_SIG_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend2' => 'GENERAL_SETTINGS', - 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'), - 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'registration': - $display_vars = array( - 'title' => 'ACP_REGISTER_SETTINGS', - 'vars' => array( - 'legend1' => 'GENERAL_SETTINGS', - 'max_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int:8:180', 'type' => false, 'method' => false, 'explain' => false,), - 'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,), - - 'require_activation' => array('lang' => 'ACC_ACTIVATION', 'validate' => 'int', 'type' => 'select', 'method' => 'select_acc_activation', 'explain' => true), - 'new_member_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'number:0:255', 'explain' => true, 'append' => ' ' . $user->lang['POSTS']), - 'new_member_group_default'=> array('lang' => 'NEW_MEMBER_GROUP_DEFAULT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'min_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int:1', 'type' => 'custom:5:180', 'method' => 'username_length', 'explain' => true), - 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), - 'allow_name_chars' => array('lang' => 'USERNAME_CHARS', 'validate' => 'string', 'type' => 'select', 'method' => 'select_username_chars', 'explain' => true), - 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), - 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - - 'legend2' => 'GENERAL_OPTIONS', - 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_emailreuse' => array('lang' => 'ALLOW_EMAIL_REUSE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'enable_confirm' => array('lang' => 'VISUAL_CONFIRM_REG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), - 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - - 'legend3' => 'COPPA', - 'coppa_enable' => array('lang' => 'ENABLE_COPPA', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'coppa_mail' => array('lang' => 'COPPA_MAIL', 'validate' => 'string', 'type' => 'textarea:5:40', 'explain' => true), - 'coppa_fax' => array('lang' => 'COPPA_FAX', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => false), - - 'legend4' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'feed': - $display_vars = array( - 'title' => 'ACP_FEED_MANAGEMENT', - 'vars' => array( - 'legend1' => 'ACP_FEED_GENERAL', - 'feed_enable' => array('lang' => 'ACP_FEED_ENABLE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_item_statistics' => array('lang' => 'ACP_FEED_ITEM_STATISTICS', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), - 'feed_http_auth' => array('lang' => 'ACP_FEED_HTTP_AUTH', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), - - 'legend2' => 'ACP_FEED_POST_BASED', - 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true), - 'feed_overall' => array('lang' => 'ACP_FEED_OVERALL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_forum' => array('lang' => 'ACP_FEED_FORUM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_topic' => array('lang' => 'ACP_FEED_TOPIC', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - - 'legend3' => 'ACP_FEED_TOPIC_BASED', - 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true), - 'feed_topics_new' => array('lang' => 'ACP_FEED_TOPICS_NEW', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_topics_active' => array('lang' => 'ACP_FEED_TOPICS_ACTIVE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_news_id' => array('lang' => 'ACP_FEED_NEWS', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_news_forums', 'explain' => true), - - 'legend4' => 'ACP_FEED_SETTINGS_OTHER', - 'feed_overall_forums' => array('lang' => 'ACP_FEED_OVERALL_FORUMS', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_exclude_id' => array('lang' => 'ACP_FEED_EXCLUDE_ID', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_exclude_forums', 'explain' => true), - ) - ); - break; - - case 'cookie': - $display_vars = array( - 'title' => 'ACP_COOKIE_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_COOKIE_SETTINGS', - '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:enabled_disabled', 'explain' => true), - 'cookie_notice' => array('lang' => 'COOKIE_NOTICE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), - ) - ); - break; - - case 'load': - $display_vars = array( - 'title' => 'ACP_LOAD_SETTINGS', - 'vars' => array( - 'legend1' => 'GENERAL_SETTINGS', - 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int:60:9999999999', 'type' => 'number:60:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), - 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'read_notification_expire_days' => array('lang' => 'READ_NOTIFICATION_EXPIRE_DAYS', 'validate' => 'int:0', 'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - - 'legend2' => 'GENERAL_OPTIONS', - 'load_notifications' => array('lang' => 'LOAD_NOTIFICATIONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_db_track' => array('lang' => 'YES_POST_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_db_lastread' => array('lang' => 'YES_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_anon_lastread' => array('lang' => 'YES_ANON_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_online' => array('lang' => 'YES_ONLINE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_online_guests' => array('lang' => 'YES_ONLINE_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_onlinetrack' => array('lang' => 'YES_ONLINE_TRACK', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_unreads_search' => array('lang' => 'YES_UNREAD_SEARCH', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - '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', - 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - - 'legend4' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'auth': - $display_vars = array( - 'title' => 'ACP_AUTH_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_AUTH_SETTINGS', - 'auth_method' => array('lang' => 'AUTH_METHOD', 'validate' => 'string', 'type' => 'select:1:toggable', 'method' => 'select_auth_method', 'explain' => false), - ) - ); - break; - - case 'server': - $display_vars = array( - 'title' => 'ACP_SERVER_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_SERVER_SETTINGS', - 'gzip_compress' => array('lang' => 'ENABLE_GZIP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'use_system_cron' => array('lang' => 'USE_SYSTEM_CRON', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend2' => 'PATH_SETTINGS', - 'enable_mod_rewrite' => array('lang' => 'MOD_REWRITE_ENABLE', 'validate' => 'bool', 'type' => 'custom', 'method' => 'enable_mod_rewrite', 'explain' => true), - 'smilies_path' => array('lang' => 'SMILIES_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - 'icons_path' => array('lang' => 'ICONS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - 'upload_icons_path' => array('lang' => 'UPLOAD_ICONS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - 'ranks_path' => array('lang' => 'RANKS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - - 'legend3' => 'SERVER_URL_SETTINGS', - 'force_server_vars' => array('lang' => 'FORCE_SERVER_VARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'server_protocol' => array('lang' => 'SERVER_PROTOCOL', 'validate' => 'string', 'type' => 'text:10:10', 'explain' => true), - 'server_name' => array('lang' => 'SERVER_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), - 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), - 'script_path' => array('lang' => 'SCRIPT_PATH', 'validate' => 'script_path', 'type' => 'text::255', 'explain' => true), - - 'legend4' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - case 'security': - $display_vars = array( - 'title' => 'ACP_SECURITY_SETTINGS', - 'vars' => array( - 'legend1' => 'ACP_SECURITY_SETTINGS', - 'allow_autologin' => array('lang' => 'ALLOW_AUTOLOGIN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_password_reset' => array('lang' => 'ALLOW_PASSWORD_RESET', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - 'ip_check' => array('lang' => 'IP_VALID', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true), - 'browser_check' => array('lang' => 'BROWSER_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'forwarded_for_check' => array('lang' => 'FORWARDED_FOR_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - '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,), - 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), - 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), - 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), - 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), - 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'ip_login_limit_use_forwarded' => array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1:99999', 'type' => 'number:-1:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'form_token_sid_guests' => array('lang' => 'FORM_SID_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - ) - ); - break; - - case 'email': - $display_vars = array( - 'title' => 'ACP_EMAIL_SETTINGS', - 'vars' => array( - '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_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'number:0:99999', 'explain' => true), - 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true), - 'board_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), - 'smtp_host' => array('lang' => 'SMTP_SERVER', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => true), - 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), - 'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true), - 'smtp_username' => array('lang' => 'SMTP_USERNAME', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true), - 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true), - 'smtp_verify_peer' => array('lang' => 'SMTP_VERIFY_PEER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'smtp_verify_peer_name' => array('lang' => 'SMTP_VERIFY_PEER_NAME', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'smtp_allow_self_signed'=> array('lang' => 'SMTP_ALLOW_SELF_SIGNED','validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - - 'legend3' => 'ACP_SUBMIT_CHANGES', - ) - ); - break; - - default: - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - - /** - * Event to add and/or modify acp_board configurations - * - * @event core.acp_board_config_edit_add - * @var array display_vars Array of config values to display and process - * @var string mode Mode of the config page we are displaying - * @var boolean submit Do we display the form or process the submission - * @since 3.1.0-a4 - */ - $vars = array('display_vars', 'mode', 'submit'); - extract($phpbb_dispatcher->trigger_event('core.acp_board_config_edit_add', compact($vars))); - - if (isset($display_vars['lang'])) - { - $user->add_lang($display_vars['lang']); - } - - $this->new_config = clone $config; - $cfg_array = (isset($_REQUEST['config'])) ? $request->variable('config', array('' => ''), true) : $this->new_config; - $error = array(); - - // We validate the complete config if wished - validate_config_vars($display_vars['vars'], $cfg_array, $error); - - 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; - } - - // We go through the display_vars to make sure no one is trying to set variables he/she is not allowed to... - foreach ($display_vars['vars'] as $config_name => $data) - { - if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false) - { - continue; - } - - if ($config_name == 'auth_method' || $config_name == 'feed_news_id' || $config_name == 'feed_exclude_id') - { - continue; - } - - if ($config_name == 'guest_style') - { - if (isset($cfg_array[$config_name])) - { - $this->guest_style_set($cfg_array[$config_name]); - } - continue; - } - - $this->new_config[$config_name] = $config_value = $cfg_array[$config_name]; - - if ($submit) - { - if (strpos($data['type'], 'password') === 0 && $config_value === '********') - { - // Do not update password fields if the content is ********, - // because that is the password replacement we use to not - // send the password to the output - continue; - } - $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', 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) - { - $cache->destroy('_feed_news_forum_ids'); - $cache->destroy('_feed_excluded_forum_ids'); - - $this->store_feed_forums(FORUM_OPTION_FEED_NEWS, 'feed_news_id'); - $this->store_feed_forums(FORUM_OPTION_FEED_EXCLUDE, 'feed_exclude_id'); - } - - 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; - $old_auth_config = array(); - foreach ($auth_providers as $provider) - { - /** @var \phpbb\auth\provider\provider_interface $provider */ - if ($fields = $provider->acp()) - { - // Check if we need to create config fields for this plugin and save config when submit was pressed - foreach ($fields as $field) - { - if (!isset($config[$field])) - { - $config->set($field, ''); - } - - if (!isset($cfg_array[$field]) || strpos($field, 'legend') !== false) - { - continue; - } - - if (substr($field, -9) === '_password' && $cfg_array[$field] === '********') - { - // Do not update password fields if the content is ********, - // because that is the password replacement we use to not - // send the password to the output - continue; - } - - $old_auth_config[$field] = $this->new_config[$field]; - $config_value = $cfg_array[$field]; - $this->new_config[$field] = $config_value; - - if ($submit) - { - $updated_auth_settings = true; - $config->set($field, $config_value); - } - } - } - unset($fields); - } - - if ($submit && (($cfg_array['auth_method'] != $this->new_config['auth_method']) || $updated_auth_settings)) - { - $method = basename($cfg_array['auth_method']); - if (array_key_exists('auth.provider.' . $method, $auth_providers)) - { - $provider = $auth_providers['auth.provider.' . $method]; - if ($error = $provider->init()) - { - foreach ($old_auth_config as $config_name => $config_value) - { - $config->set($config_name, $config_value); - } - trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); - } - $config->set('auth_method', basename($cfg_array['auth_method'])); - } - else - { - trigger_error('NO_AUTH_PLUGIN', E_USER_ERROR); - } - } - } - - 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) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_' . strtoupper($mode)); - - $message = $user->lang('CONFIG_UPDATED'); - $message_type = E_USER_NOTICE; - if (!$config['email_enable'] && in_array($mode, array('email', 'registration')) && - in_array($config['require_activation'], array(USER_ACTIVATION_SELF, USER_ACTIVATION_ADMIN))) - { - $message .= '

' . $user->lang('ACC_ACTIVATION_WARNING'); - $message_type = E_USER_WARNING; - } - trigger_error($message . adm_back_link($this->u_action), $message_type); - } - - $this->tpl_name = 'acp_board'; - $this->page_title = $display_vars['title']; - - $template->assign_vars(array( - 'L_TITLE' => $user->lang[$display_vars['title']], - 'L_TITLE_EXPLAIN' => $user->lang[$display_vars['title'] . '_EXPLAIN'], - - 'S_ERROR' => (count($error)) ? true : false, - 'ERROR_MSG' => implode('
', $error), - - 'U_ACTION' => $this->u_action) - ); - - // Output relevant page - foreach ($display_vars['vars'] 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' => (isset($user->lang[$vars])) ? $user->lang[$vars] : $vars) - ); - - continue; - } - - $type = explode(':', $vars['type']); - - $l_explain = ''; - if ($vars['explain'] && isset($vars['lang_explain'])) - { - $l_explain = (isset($user->lang[$vars['lang_explain']])) ? $user->lang[$vars['lang_explain']] : $vars['lang_explain']; - } - else if ($vars['explain']) - { - $l_explain = (isset($user->lang[$vars['lang'] . '_EXPLAIN'])) ? $user->lang[$vars['lang'] . '_EXPLAIN'] : ''; - } - - $content = build_cfg_template($type, $config_key, $this->new_config, $config_key, $vars); - - if (empty($content)) - { - continue; - } - - $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'] && !empty($l_explain), - 'TITLE_EXPLAIN' => $l_explain, - 'CONTENT' => $content, - ) - ); - - unset($display_vars['vars'][$config_key]); - } - - if ($mode == 'auth') - { - $template->assign_var('S_AUTH', true); - - foreach ($auth_providers as $provider) - { - $auth_tpl = $provider->get_acp_template($this->new_config); - if ($auth_tpl) - { - if (array_key_exists('BLOCK_VAR_NAME', $auth_tpl)) - { - foreach ($auth_tpl['BLOCK_VARS'] as $block_vars) - { - $template->assign_block_vars($auth_tpl['BLOCK_VAR_NAME'], $block_vars); - } - } - $template->assign_vars($auth_tpl['TEMPLATE_VARS']); - $template->assign_block_vars('auth_tpl', array( - 'TEMPLATE_FILE' => $auth_tpl['TEMPLATE_FILE'], - )); - } - } - } - } - - /** - * Select auth method - */ - function select_auth_method($selected_method, $key = '') - { - global $phpbb_container; - - /* @var $auth_providers \phpbb\auth\provider_collection */ - $auth_providers = $phpbb_container->get('auth.provider_collection'); - $auth_plugins = array(); - - foreach ($auth_providers as $key => $value) - { - if (!($value instanceof \phpbb\auth\provider\provider_interface)) - { - continue; - } - $auth_plugins[] = str_replace('auth.provider.', '', $key); - } - - sort($auth_plugins); - - $auth_select = ''; - foreach ($auth_plugins as $method) - { - $selected = ($selected_method == $method) ? ' selected="selected"' : ''; - $auth_select .= "'; - } - - return $auth_select; - } - - /** - * Select mail authentication method - */ - function mail_auth_select($selected_method, $key = '') - { - global $user; - - $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 .= ''; - } - - return $s_smtp_auth_options; - } - - /** - * Select full folder action - */ - function full_folder_select($value, $key = '') - { - global $user; - - return ''; - } - - /** - * Select ip validation - */ - function select_ip_check($value, $key = '') - { - $radio_ary = array(4 => 'ALL', 3 => 'CLASS_C', 2 => 'CLASS_B', 0 => 'NO_IP_VALIDATION'); - - return h_radio('config[ip_check]', $radio_ary, $value, $key); - } - - /** - * Select referer validation - */ - function select_ref_check($value, $key = '') - { - $radio_ary = array(REFERER_VALIDATE_PATH => 'REF_PATH', REFERER_VALIDATE_HOST => 'REF_HOST', REFERER_VALIDATE_NONE => 'NO_REF_VALIDATION'); - - return h_radio('config[referer_validation]', $radio_ary, $value, $key); - } - - /** - * Select account activation method - */ - function select_acc_activation($selected_value, $value) - { - global $user, $config; - - $act_ary = array( - 'ACC_DISABLE' => array(true, USER_ACTIVATION_DISABLE), - 'ACC_NONE' => array(true, USER_ACTIVATION_NONE), - 'ACC_USER' => array($config['email_enable'], USER_ACTIVATION_SELF), - 'ACC_ADMIN' => array($config['email_enable'], USER_ACTIVATION_ADMIN), - ); - - $act_options = ''; - foreach ($act_ary as $key => $data) - { - list($available, $value) = $data; - $selected = ($selected_value == $value) ? ' selected="selected"' : ''; - $class = (!$available) ? ' class="disabled-option"' : ''; - $act_options .= ''; - } - - return $act_options; - } - - /** - * Maximum/Minimum username length - */ - function username_length($value, $key = '') - { - global $user; - - return ' ' . $user->lang['MIN_CHARS'] . '   ' . $user->lang['MAX_CHARS']; - } - - /** - * Allowed chars in usernames - */ - function select_username_chars($selected_value, $key) - { - global $user; - - $user_char_ary = array('USERNAME_CHARS_ANY', 'USERNAME_ALPHA_ONLY', 'USERNAME_ALPHA_SPACERS', 'USERNAME_LETTER_NUM', 'USERNAME_LETTER_NUM_SPACERS', 'USERNAME_ASCII'); - $user_char_options = ''; - foreach ($user_char_ary as $user_type) - { - $selected = ($selected_value == $user_type) ? ' selected="selected"' : ''; - $user_char_options .= ''; - } - - return $user_char_options; - } - - /** - * Maximum/Minimum password length - */ - function password_length($value, $key) - { - global $user; - - return ' ' . $user->lang['MIN_CHARS'] . '   ' . $user->lang['MAX_CHARS']; - } - - /** - * Required chars in passwords - */ - function select_password_chars($selected_value, $key) - { - global $user; - - $pass_type_ary = array('PASS_TYPE_ANY', 'PASS_TYPE_CASE', 'PASS_TYPE_ALPHA', 'PASS_TYPE_SYMBOL'); - $pass_char_options = ''; - foreach ($pass_type_ary as $pass_type) - { - $selected = ($selected_value == $pass_type) ? ' selected="selected"' : ''; - $pass_char_options .= ''; - } - - return $pass_char_options; - } - - /** - * Select bump interval - */ - function bump_interval($value, $key) - { - global $user; - - $s_bump_type = ''; - $types = array('m' => 'MINUTES', 'h' => 'HOURS', 'd' => 'DAYS'); - foreach ($types as $type => $lang) - { - $selected = ($this->new_config['bump_type'] == $type) ? ' selected="selected"' : ''; - $s_bump_type .= ''; - } - - return ' '; - } - - /** - * Board disable option and message - */ - function board_disable($value, $key) - { - $radio_ary = array(1 => 'YES', 0 => 'NO'); - - return h_radio('config[board_disable]', $radio_ary, $value) . '
'; - } - - /** - * Global quick reply enable/disable setting and button to enable in all forums - */ - function quick_reply($value, $key) - { - global $user; - - $radio_ary = array(1 => 'YES', 0 => 'NO'); - - return h_radio('config[allow_quick_reply]', $radio_ary, $value) . - '

'; - } - - /** - * Select guest timezone - */ - function timezone_select($value, $key) - { - global $template, $user; - - $timezone_select = phpbb_timezone_select($template, $user, $value, true); - - return ''; - } - - /** - * Get guest style - */ - public function guest_style_get() - { - global $db; - - $sql = 'SELECT user_style - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . ANONYMOUS; - $result = $db->sql_query($sql); - - $style = (int) $db->sql_fetchfield('user_style'); - $db->sql_freeresult($result); - - return $style; - } - - /** - * Set guest style - * - * @param int $style_id The style ID - */ - public function guest_style_set($style_id) - { - global $db; - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_style = ' . (int) $style_id . ' - WHERE user_id = ' . ANONYMOUS; - $db->sql_query($sql); - } - - /** - * Select default dateformat - */ - function dateformat_select($value, $key) - { - global $user, $config; - - // Let the format_date function operate with the acp values - $old_tz = $user->timezone; - try - { - $user->timezone = new DateTimeZone($config['board_timezone']); - } - catch (\Exception $e) - { - // If the board timezone is invalid, we just use the users timezone. - } - - $dateformat_options = ''; - - foreach ($user->lang['dateformats'] as $format => $null) - { - $dateformat_options .= ''; - } - - $dateformat_options .= ''; - - // Reset users date options - $user->timezone = $old_tz; - - return " - "; - } - - /** - * Select multiple forums - */ - function select_news_forums($value, $key) - { - $forum_list = make_forum_select(false, false, true, true, true, false, true); - - // Build forum options - $s_forum_options = ''; - - return $s_forum_options; - } - - function select_exclude_forums($value, $key) - { - $forum_list = make_forum_select(false, false, true, true, true, false, true); - - // Build forum options - $s_forum_options = ''; - - return $s_forum_options; - } - - function store_feed_forums($option, $key) - { - global $db, $cache, $request; - - // Get key - $values = $request->variable($key, array(0 => 0)); - - // Empty option bit for all forums - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_options = forum_options - ' . (1 << $option) . ' - WHERE ' . $db->sql_bit_and('forum_options', $option, '<> 0'); - $db->sql_query($sql); - - // Already emptied for all... - if (count($values)) - { - // Set for selected forums - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_options = forum_options + ' . (1 << $option) . ' - WHERE ' . $db->sql_in_set('forum_id', $values); - $db->sql_query($sql); - } - - // Empty sql cache for forums table because options changed - $cache->destroy('sql', FORUMS_TABLE); - } - - /** - * Option to enable/disable removal of 'app.php' from URLs - * - * Note that if mod_rewrite is on, URLs without app.php will still work, - * but any paths generated by the controller helper url() method will not - * contain app.php. - * - * @param int $value The current config value - * @param string $key The config key - * @return string The HTML for the form field - */ - function enable_mod_rewrite($value, $key) - { - global $user; - - // Determine whether mod_rewrite is enabled on the server - // NOTE: This only works on Apache servers on which PHP is NOT - // installed as CGI. In that case, there is no way for PHP to - // determine whether or not the Apache module is enabled. - // - // To be clear on the value of $mod_rewite: - // null = Cannot determine whether or not the server has mod_rewrite - // enabled - // false = Can determine that the server does NOT have mod_rewrite - // enabled - // true = Can determine that the server DOES have mod_rewrite_enabled - $mod_rewrite = null; - if (function_exists('apache_get_modules')) - { - $mod_rewrite = (bool) in_array('mod_rewrite', apache_get_modules()); - } - - // If $message is false, mod_rewrite is enabled. - // Otherwise, it is not and we need to: - // 1) disable the form field - // 2) make sure the config value is set to 0 - // 3) append the message to the return - $value = ($mod_rewrite === false) ? 0 : $value; - $message = $mod_rewrite === null ? 'MOD_REWRITE_INFORMATION_UNAVAILABLE' : ($mod_rewrite === false ? 'MOD_REWRITE_DISABLED' : false); - - // Let's do some friendly HTML injection if we want to disable the - // form field because h_radio() has no pretty way of doing so - $field_name = 'config[enable_mod_rewrite]' . ($message === 'MOD_REWRITE_DISABLED' ? '" disabled="disabled' : ''); - - return h_radio($field_name, array(1 => 'YES', 0 => 'NO'), $value) . - ($message !== false ? '
' . $user->lang($message) . '' : ''); - } - - function send_test_email($value, $key) - { - global $user; - - return ''; - } -} diff --git a/install/update/old/includes/acp/acp_database.php b/install/update/old/includes/acp/acp_database.php deleted file mode 100644 index 05f2b98..0000000 --- a/install/update/old/includes/acp/acp_database.php +++ /dev/null @@ -1,622 +0,0 @@ - -* @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_database -{ - var $db_tools; - var $u_action; - public $page_title; - - function main($id, $mode) - { - global $cache, $db, $user, $template, $table_prefix, $request; - global $phpbb_root_path, $phpbb_container, $phpbb_log; - - $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->variable('action', ''); - - $form_key = 'acp_database'; - add_form_key($form_key); - - $template->assign_vars(array( - 'MODE' => $mode - )); - - switch ($mode) - { - case 'backup': - - $this->page_title = 'ACP_BACKUP'; - - switch ($action) - { - case 'download': - $type = $request->variable('type', ''); - $table = array_intersect($this->db_tools->sql_list_tables(), $request->variable('table', array(''))); - $format = $request->variable('method', ''); - $where = $request->variable('where', ''); - - if (!count($table)) - { - trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (!check_form_key($form_key)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $store = $structure = $schema_data = false; - - if ($where == 'store') - { - $store = true; - } - - if ($type == 'full' || $type == 'structure') - { - $structure = true; - } - - if ($type == 'full' || $type == 'data') - { - $schema_data = true; - } - - @set_time_limit(1200); - @set_time_limit(0); - - $time = time(); - - $filename = 'backup_' . $time . '_' . unique_id(); - - /** @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); - - foreach ($table as $table_name) - { - // Get the table structure - if ($structure) - { - $extractor->write_table($table_name); - } - else - { - // We might wanna empty out all that junk :D - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $extractor->flush('DELETE FROM ' . $table_name . ";\n"); - break; - - case 'mssql_odbc': - case 'mssqlnative': - $extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n"); - break; - - case 'oracle': - $extractor->flush('TRUNCATE TABLE ' . $table_name . "/\n"); - break; - - default: - $extractor->flush('TRUNCATE TABLE ' . $table_name . ";\n"); - break; - } - } - - // Data - if ($schema_data) - { - $extractor->write_data($table_name); - } - } - - $extractor->write_end(); - - $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; - - default: - $tables = $this->db_tools->sql_list_tables(); - asort($tables); - foreach ($tables as $table_name) - { - if (strlen($table_prefix) === 0 || stripos($table_name, $table_prefix) === 0) - { - $template->assign_block_vars('tables', array( - 'TABLE' => $table_name - )); - } - } - unset($tables); - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action . '&action=download' - )); - - $available_methods = array('gzip' => 'zlib', 'bzip2' => 'bz2'); - - foreach ($available_methods as $type => $module) - { - if (!@extension_loaded($module)) - { - continue; - } - - $template->assign_block_vars('methods', array( - 'TYPE' => $type - )); - } - - $template->assign_block_vars('methods', array( - 'TYPE' => 'text' - )); - break; - } - break; - - case 'restore': - - $this->page_title = 'ACP_RESTORE'; - - switch ($action) - { - case 'submit': - $delete = $request->variable('delete', ''); - $file = $request->variable('file', ''); - - $backup_info = $this->get_backup_file($phpbb_root_path . 'store/', $file); - - 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); - } - - if ($delete) - { - if (confirm_box(true)) - { - 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 - { - confirm_box(false, $user->lang['DELETE_SELECTED_BACKUP'], build_hidden_fields(array('delete' => $delete, 'file' => $file))); - } - } - else if (confirm_box(true)) - { - switch ($backup_info['extensions']) - { - case 'sql': - $fp = fopen($backup_info['file_name'], 'rb'); - $read = 'fread'; - $seek = 'fseek'; - $eof = 'feof'; - $close = 'fclose'; - $fgetd = 'fgetd'; - break; - - case 'sql.bz2': - $fp = bzopen($backup_info['file_name'], 'r'); - $read = 'bzread'; - $seek = ''; - $eof = 'feof'; - $close = 'bzclose'; - $fgetd = 'fgetd_seekless'; - break; - - case 'sql.gz': - $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()) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - case 'sqlite3': - while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false) - { - $db->sql_query($sql); - } - break; - - case 'postgres': - $delim = ";\n"; - while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false) - { - $query = trim($sql); - - if (substr($query, 0, 13) == 'CREATE DOMAIN') - { - list(, , $domain) = explode(' ', $query); - $sql = "SELECT domain_name - FROM information_schema.domains - WHERE domain_name = '$domain';"; - $result = $db->sql_query($sql); - if (!$db->sql_fetchrow($result)) - { - $db->sql_query($query); - } - $db->sql_freeresult($result); - } - else - { - $db->sql_query($query); - } - - if (substr($query, 0, 4) == 'COPY') - { - while (($sub = $fgetd($fp, "\n", $read, $seek, $eof)) !== '\.') - { - if ($sub === false) - { - trigger_error($user->lang['RESTORE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - pg_put_line($db->get_db_connect_id(), $sub . "\n"); - } - pg_put_line($db->get_db_connect_id(), "\\.\n"); - pg_end_copy($db->get_db_connect_id()); - } - } - break; - - case 'oracle': - while (($sql = $fgetd($fp, "/\n", $read, $seek, $eof)) !== false) - { - $db->sql_query($sql); - } - break; - - case 'mssql_odbc': - case 'mssqlnative': - while (($sql = $fgetd($fp, "GO\n", $read, $seek, $eof)) !== false) - { - $db->sql_query($sql); - } - break; - } - - $close($fp); - - // Purge the cache due to updated data - $cache->purge(); - - $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 - { - confirm_box(false, $user->lang['RESTORE_SELECTED_BACKUP'], build_hidden_fields(array('file' => $file))); - } - - default: - $backup_files = $this->get_file_list($phpbb_root_path . 'store/'); - - if (!empty($backup_files)) - { - krsort($backup_files); - - foreach ($backup_files as $name => $file) - { - $template->assign_block_vars('files', array( - 'FILE' => sha1($file), - 'NAME' => $user->format_date($name, 'd-m-Y H:i', true), - 'SUPPORTED' => true, - )); - } - } - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action . '&action=submit' - )); - break; - } - break; - } - } - - /** - * 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) - { - $backup_data = []; - - $file_list = $this->get_file_list($directory); - $supported_extensions = $this->get_supported_extensions(); - - foreach ($file_list as $file) - { - 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)) - { - $backup_data = [ - 'file_name' => $directory . $file, - 'extension' => $matches[2], - ]; - break; - } - } - - return $backup_data; - } - - /** - * 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) - { - $supported_extensions = $this->get_supported_extensions(); - - $dh = @opendir($directory); - - $backup_files = []; - - if ($dh) - { - while (($file = readdir($dh)) !== false) - { - if (preg_match('#^backup_(\d{10,})_(?:[a-z\d]{16}|[a-z\d]{32})\.(sql(?:\.(?:gz|bz2))?)$#i', $file, $matches)) - { - if (in_array($matches[2], $supported_extensions)) - { - $backup_files[(int) $matches[1]] = $file; - } - } - } - closedir($dh); - } - - return $backup_files; - } - - /** - * Get supported extensions for backup - * - * @return array List of supported extensions - */ - protected function get_supported_extensions() - { - $extensions = ['sql']; - $available_methods = ['sql.gz' => 'zlib', 'sql.bz2' => 'bz2']; - - foreach ($available_methods as $type => $module) - { - if (!@extension_loaded($module)) - { - continue; - } - $extensions[] = $type; - } - - return $extensions; - } -} - -// get how much space we allow for a chunk of data, very similar to phpMyAdmin's way of doing things ;-) (hey, we only do this for MySQL anyway :P) -function get_usable_memory() -{ - $val = trim(@ini_get('memory_limit')); - - if (preg_match('/(\\d+)([mkg]?)/i', $val, $regs)) - { - $memory_limit = (int) $regs[1]; - switch ($regs[2]) - { - - case 'k': - case 'K': - $memory_limit *= 1024; - break; - - case 'm': - case 'M': - $memory_limit *= 1048576; - break; - - case 'g': - case 'G': - $memory_limit *= 1073741824; - break; - } - - // how much memory PHP requires at the start of export (it is really a little less) - if ($memory_limit > 6100000) - { - $memory_limit -= 6100000; - } - - // allow us to consume half of the total memory available - $memory_limit /= 2; - } - else - { - // set the buffer to 1M if we have no clue how much memory PHP will give us :P - $memory_limit = 1048576; - } - - return $memory_limit; -} - -function sanitize_data_mssql($text) -{ - $data = preg_split('/[\n\t\r\b\f]/', $text); - preg_match_all('/[\n\t\r\b\f]/', $text, $matches); - - $val = array(); - - foreach ($data as $value) - { - if (strlen($value)) - { - $val[] = "'" . $value . "'"; - } - if (count($matches[0])) - { - $val[] = 'char(' . ord(array_shift($matches[0])) . ')'; - } - } - - return implode('+', $val); -} - -function sanitize_data_oracle($text) -{ -// $data = preg_split('/[\0\n\t\r\b\f\'"\/\\\]/', $text); -// preg_match_all('/[\0\n\t\r\b\f\'"\/\\\]/', $text, $matches); - $data = preg_split('/[\0\b\f\'\/]/', $text); - preg_match_all('/[\0\r\b\f\'\/]/', $text, $matches); - - $val = array(); - - foreach ($data as $value) - { - if (strlen($value)) - { - $val[] = "'" . $value . "'"; - } - if (count($matches[0])) - { - $val[] = 'chr(' . ord(array_shift($matches[0])) . ')'; - } - } - - return implode('||', $val); -} - -function sanitize_data_generic($text) -{ - $data = preg_split('/[\n\t\r\b\f]/', $text); - preg_match_all('/[\n\t\r\b\f]/', $text, $matches); - - $val = array(); - - foreach ($data as $value) - { - if (strlen($value)) - { - $val[] = "'" . $value . "'"; - } - if (count($matches[0])) - { - $val[] = "'" . array_shift($matches[0]) . "'"; - } - } - - return implode('||', $val); -} - -// modified from PHP.net -function fgetd(&$fp, $delim, $read, $seek, $eof, $buffer = 8192) -{ - $record = ''; - $delim_len = strlen($delim); - - while (!$eof($fp)) - { - $pos = strpos($record, $delim); - if ($pos === false) - { - $record .= $read($fp, $buffer); - if ($eof($fp) && ($pos = strpos($record, $delim)) !== false) - { - $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR); - return substr($record, 0, $pos); - } - } - else - { - $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR); - return substr($record, 0, $pos); - } - } - - return false; -} - -function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192) -{ - static $array = array(); - static $record = ''; - - if (!count($array)) - { - while (!$eof($fp)) - { - if (strpos($record, $delim) !== false) - { - $array = explode($delim, $record); - $record = array_pop($array); - break; - } - else - { - $record .= $read($fp, $buffer); - } - } - if ($eof($fp) && strpos($record, $delim) !== false) - { - $array = explode($delim, $record); - $record = array_pop($array); - } - } - - if (count($array)) - { - return array_shift($array); - } - - return false; -} diff --git a/install/update/old/includes/acp/acp_extensions.php b/install/update/old/includes/acp/acp_extensions.php deleted file mode 100644 index a1cb210..0000000 --- a/install/update/old/includes/acp/acp_extensions.php +++ /dev/null @@ -1,665 +0,0 @@ - -* @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\exception\exception_interface; -use phpbb\exception\version_check_exception; - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -class acp_extensions -{ - var $u_action; - var $tpl_name; - var $page_title; - - private $config; - private $template; - private $user; - 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, $phpbb_log, $phpbb_dispatcher, $phpbb_container; - - $this->config = $config; - $this->template = $template; - $this->user = $user; - $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')); - - $this->page_title = 'ACP_EXTENSIONS'; - - $action = $this->request->variable('action', 'list'); - $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 = ($this->php_ini->getNumeric('max_execution_time') / 2); - $start_time = time(); - - // Cancel action - if ($this->request->is_set_post('cancel')) - { - $action = 'list'; - $ext_name = ''; - } - - if (in_array($action, array('enable', 'disable', 'delete_data')) && !check_link_hash($this->request->variable('hash', ''), $action . '.' . $ext_name)) - { - trigger_error('FORM_INVALID', E_USER_WARNING); - } - - /** - * Event to run a specific action on extension - * - * @event core.acp_extensions_run_action_before - * @var string action Action to run; if the event completes execution of the action, should be set to 'none' - * @var string u_action Url we are at - * @var string ext_name Extension name from request - * @var int safe_time_limit Safe limit of execution time - * @var int start_time Start time - * @var string tpl_name Template file to load - * @since 3.1.11-RC1 - * @changed 3.2.1-RC1 Renamed to core.acp_extensions_run_action_before, added tpl_name, added action 'none' - */ - $u_action = $this->u_action; - $tpl_name = ''; - $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name'); - extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_before', compact($vars))); - - // In case they have been updated by the event - $this->u_action = $u_action; - $this->tpl_name = $tpl_name; - - // 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); - - try - { - $md_manager->get_metadata('all'); - } - catch (exception_interface $e) - { - $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); - } - } - - // What are we doing? - switch ($action) - { - case 'none': - // Intentionally empty, used by extensions that execute additional actions in the prior event - break; - - case 'set_config_version_check_force_unstable': - $force_unstable = $this->request->variable('force_unstable', false); - - if ($force_unstable) - { - $s_hidden_fields = build_hidden_fields(array( - 'force_unstable' => $force_unstable, - )); - - confirm_box(false, $this->user->lang('EXTENSION_FORCE_UNSTABLE_CONFIRM'), $s_hidden_fields); - } - else - { - $this->config->set('extension_force_unstable', false); - trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - break; - - case 'list': - default: - if (confirm_box(true)) - { - $this->config->set('extension_force_unstable', true); - trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - - $this->list_enabled_exts(); - $this->list_disabled_exts(); - $this->list_available_exts(); - - $this->template->assign_vars(array( - 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=list&versioncheck_force=1', - 'FORCE_UNSTABLE' => $this->config['extension_force_unstable'], - 'U_ACTION' => $this->u_action, - )); - - $this->tpl_name = 'acp_ext_list'; - break; - - case 'enable_pre': - try - { - $md_manager->validate_enable(); - } - catch (exception_interface $e) - { - $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); - if (!$extension->is_enableable()) - { - trigger_error($this->user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if ($this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - $this->tpl_name = 'acp_ext_enable'; - - $this->template->assign_vars(array( - 'PRE' => true, - 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_ENABLE_CONFIRM', $md_manager->get_metadata('display-name')), - 'U_ENABLE' => $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name), - )); - break; - - case 'enable': - try - { - $md_manager->validate_enable(); - } - catch (exception_interface $e) - { - $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); - if (!$extension->is_enableable()) - { - trigger_error($this->user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - try - { - while ($this->ext_manager->enable_step($ext_name)) - { - // Are we approaching the time limit? If so we want to pause the update and continue after refreshing - if ((time() - $start_time) >= $safe_time_limit) - { - $this->template->assign_var('S_NEXT_STEP', true); - - meta_refresh(0, $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name)); - } - } - - // Update custom style for admin area - $this->template->set_custom_style(array( - array( - 'name' => 'adm', - 'ext_path' => 'adm/style/', - ), - ), array($phpbb_root_path . 'adm/style')); - - $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name)); - } - catch (\phpbb\db\migration\exception $e) - { - $this->template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($this->user)); - } - - $this->tpl_name = 'acp_ext_enable'; - - $this->template->assign_vars(array( - 'U_RETURN' => $this->u_action . '&action=list', - )); - break; - - case 'disable_pre': - if (!$this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - $this->tpl_name = 'acp_ext_disable'; - - $this->template->assign_vars(array( - 'PRE' => true, - 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DISABLE_CONFIRM', $md_manager->get_metadata('display-name')), - 'U_DISABLE' => $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name), - )); - break; - - case 'disable': - if (!$this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - while ($this->ext_manager->disable_step($ext_name)) - { - // Are we approaching the time limit? If so we want to pause the update and continue after refreshing - if ((time() - $start_time) >= $safe_time_limit) - { - $this->template->assign_var('S_NEXT_STEP', true); - - meta_refresh(0, $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name)); - } - } - $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_DISABLE', time(), array($ext_name)); - - $this->tpl_name = 'acp_ext_disable'; - - $this->template->assign_vars(array( - 'U_RETURN' => $this->u_action . '&action=list', - )); - break; - - case 'delete_data_pre': - if ($this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - $this->tpl_name = 'acp_ext_delete_data'; - - $this->template->assign_vars(array( - 'PRE' => true, - 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DELETE_DATA_CONFIRM', $md_manager->get_metadata('display-name')), - 'U_PURGE' => $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name), - )); - break; - - case 'delete_data': - if ($this->ext_manager->is_enabled($ext_name)) - { - redirect($this->u_action); - } - - try - { - while ($this->ext_manager->purge_step($ext_name)) - { - // Are we approaching the time limit? If so we want to pause the update and continue after refreshing - if ((time() - $start_time) >= $safe_time_limit) - { - $this->template->assign_var('S_NEXT_STEP', true); - - meta_refresh(0, $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name)); - } - } - $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_PURGE', time(), array($ext_name)); - } - catch (\phpbb\db\migration\exception $e) - { - $this->template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($this->user)); - } - - $this->tpl_name = 'acp_ext_delete_data'; - - $this->template->assign_vars(array( - 'U_RETURN' => $this->u_action . '&action=list', - )); - break; - - case 'details': - // Output it to the template - $meta = $md_manager->get_metadata('all'); - $this->output_metadata_to_template($meta); - - if (isset($meta['extra']['version-check'])) - { - 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), - '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_vars(array( - 'S_VERSIONCHECK_FAIL' => true, - 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== 'VERSIONCHECK_FAIL') ? $message : '', - )); - } - $this->template->assign_var('S_VERSIONCHECK', true); - } - else - { - $this->template->assign_var('S_VERSIONCHECK', false); - } - - $this->template->assign_vars(array( - 'U_BACK' => $this->u_action . '&action=list', - 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')), - )); - - $this->tpl_name = 'acp_ext_details'; - break; - } - - /** - * Event to run after a specific action on extension has completed - * - * @event core.acp_extensions_run_action_after - * @var string action Action that has run - * @var string u_action Url we are at - * @var string ext_name Extension name from request - * @var int safe_time_limit Safe limit of execution time - * @var int start_time Start time - * @var string tpl_name Template file to load - * @since 3.1.11-RC1 - */ - $u_action = $this->u_action; - $tpl_name = $this->tpl_name; - $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name'); - extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_after', compact($vars))); - - // In case they have been updated by the event - $this->u_action = $u_action; - $this->tpl_name = $tpl_name; - } - - /** - * Lists all the enabled extensions and dumps to the template - * - * @return null - */ - public function list_enabled_exts() - { - $enabled_extension_meta_data = array(); - - foreach ($this->ext_manager->all_enabled() as $name => $location) - { - $md_manager = $this->ext_manager->create_extension_metadata_manager($name); - - try - { - $meta = $md_manager->get_metadata('all'); - $enabled_extension_meta_data[$name] = array( - 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), - 'META_VERSION' => $meta['version'], - ); - - 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 . '&action=details&versioncheck_force=1&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 (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, $message), - 'S_VERSIONCHECK' => false, - )); - } - catch (\RuntimeException $e) - { - $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; - } - } - - uasort($enabled_extension_meta_data, array($this, 'sort_extension_meta_data_table')); - - foreach ($enabled_extension_meta_data as $name => $block_vars) - { - $block_vars['NAME'] = $name; - $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); - - $this->template->assign_block_vars('enabled', $block_vars); - - $this->output_actions('enabled', array( - 'DISABLE' => $this->u_action . '&action=disable_pre&ext_name=' . urlencode($name), - )); - } - } - - /** - * Lists all the disabled extensions and dumps to the template - * - * @return null - */ - public function list_disabled_exts() - { - $disabled_extension_meta_data = array(); - - foreach ($this->ext_manager->all_disabled() as $name => $location) - { - $md_manager = $this->ext_manager->create_extension_metadata_manager($name); - - try - { - $meta = $md_manager->get_metadata('all'); - $disabled_extension_meta_data[$name] = array( - 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), - 'META_VERSION' => $meta['version'], - ); - - 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 . '&action=details&versioncheck_force=1&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 (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, $message), - 'S_VERSIONCHECK' => false, - )); - } - catch (\RuntimeException $e) - { - $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; - } - } - - uasort($disabled_extension_meta_data, array($this, 'sort_extension_meta_data_table')); - - foreach ($disabled_extension_meta_data as $name => $block_vars) - { - $block_vars['NAME'] = $name; - $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); - - $this->template->assign_block_vars('disabled', $block_vars); - - $this->output_actions('disabled', array( - 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), - 'DELETE_DATA' => $this->u_action . '&action=delete_data_pre&ext_name=' . urlencode($name), - )); - } - } - - /** - * Lists all the available extensions and dumps to the template - * - * @return null - */ - public function list_available_exts() - { - $uninstalled = array_diff_key($this->ext_manager->all_available(), $this->ext_manager->all_configured()); - - $available_extension_meta_data = array(); - - foreach ($uninstalled as $name => $location) - { - $md_manager = $this->ext_manager->create_extension_metadata_manager($name); - - try - { - $meta = $md_manager->get_metadata('all'); - $available_extension_meta_data[$name] = array( - 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), - 'META_VERSION' => $meta['version'], - ); - - 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 . '&action=details&versioncheck_force=1&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 (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, $message), - 'S_VERSIONCHECK' => false, - )); - } - } - - uasort($available_extension_meta_data, array($this, 'sort_extension_meta_data_table')); - - foreach ($available_extension_meta_data as $name => $block_vars) - { - $block_vars['NAME'] = $name; - $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); - - $this->template->assign_block_vars('disabled', $block_vars); - - $this->output_actions('disabled', array( - 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), - )); - } - } - - /** - * Output actions to a block - * - * @param string $block - * @param array $actions - */ - private function output_actions($block, $actions) - { - foreach ($actions as $lang => $url) - { - $this->template->assign_block_vars($block . '.actions', array( - 'L_ACTION' => $this->user->lang('EXTENSION_' . $lang), - 'L_ACTION_EXPLAIN' => (isset($this->user->lang['EXTENSION_' . $lang . '_EXPLAIN'])) ? $this->user->lang('EXTENSION_' . $lang . '_EXPLAIN') : '', - 'U_ACTION' => $url, - )); - } - } - - /** - * Sort helper for the table containing the metadata about the extensions. - */ - protected function sort_extension_meta_data_table($val1, $val2) - { - return strnatcasecmp($val1['META_DISPLAY_NAME'], $val2['META_DISPLAY_NAME']); - } - - /** - * Outputs extension metadata into the template - * - * @param array $metadata Array with all metadata for the extension - * @return null - */ - public function output_metadata_to_template($metadata) - { - $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/install/update/old/includes/acp/acp_forums.php b/install/update/old/includes/acp/acp_forums.php deleted file mode 100644 index be5a7a2..0000000 --- a/install/update/old/includes/acp/acp_forums.php +++ /dev/null @@ -1,2179 +0,0 @@ - -* @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_forums -{ - var $u_action; - var $parent_id = 0; - - function main($id, $mode) - { - global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher; - global $phpbb_admin_path, $phpbb_root_path, $phpEx, $phpbb_log; - - $user->add_lang('acp/forums'); - $this->tpl_name = 'acp_forums'; - $this->page_title = 'ACP_MANAGE_FORUMS'; - - $form_key = 'acp_forums'; - add_form_key($form_key); - - $action = $request->variable('action', ''); - $update = (isset($_POST['update'])) ? true : false; - $forum_id = $request->variable('f', 0); - - $this->parent_id = $request->variable('parent_id', 0); - $forum_data = $errors = array(); - if ($update && !check_form_key($form_key)) - { - $update = false; - $errors[] = $user->lang['FORM_INVALID']; - } - - // Check additional permissions - switch ($action) - { - case 'progress_bar': - $start = $request->variable('start', 0); - $total = $request->variable('total', 0); - - $this->display_progress_bar($start, $total); - break; - - case 'delete': - - if (!$auth->acl_get('a_forumdel')) - { - trigger_error($user->lang['NO_PERMISSION_FORUM_DELETE'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - break; - - case 'add': - - if (!$auth->acl_get('a_forumadd')) - { - trigger_error($user->lang['NO_PERMISSION_FORUM_ADD'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - break; - } - - // Major routines - if ($update) - { - switch ($action) - { - case 'delete': - $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 (count($errors)) - { - break; - } - - $auth->acl_clear_prefetch(); - $cache->destroy('sql', FORUMS_TABLE); - - trigger_error($user->lang['FORUM_DELETED'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); - - break; - - case 'edit': - $forum_data = array( - 'forum_id' => $forum_id - ); - - // No break here - - case 'add': - - $forum_data += array( - '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' => $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' => $request->variable('forum_rules', '', true), - 'forum_rules_uid' => '', - 'forum_rules_options' => 7, - 'forum_rules_bitfield' => '', - '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), - ); - - /** - * Request forum data and operate on it (parse texts, etc.) - * - * @event core.acp_manage_forums_request_data - * @var string action Type of the action: add|edit - * @var array forum_data Array with new forum data - * @since 3.1.0-a1 - */ - $vars = array('action', 'forum_data'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_request_data', compact($vars))); - - // On add, add empty forum_options... else do not consider it (not updating it) - if ($action == 'add') - { - $forum_data['forum_options'] = 0; - } - - // Use link_display_on_index setting if forum type is link - if ($forum_data['forum_type'] == FORUM_LINK) - { - $forum_data['display_on_index'] = $request->variable('link_display_on_index', false); - } - - // Linked forums and categories are not able to be locked... - if ($forum_data['forum_type'] == FORUM_LINK || $forum_data['forum_type'] == FORUM_CAT) - { - $forum_data['forum_status'] = ITEM_UNLOCKED; - } - - $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->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->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 (!count($errors)) - { - $forum_perm_from = $request->variable('forum_perm_from', 0); - $cache->destroy('sql', FORUMS_TABLE); - - $copied_permissions = false; - // Copy permissions? - if ($forum_perm_from && $forum_perm_from != $forum_data['forum_id'] && - ($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')))) - { - copy_forum_permissions($forum_perm_from, $forum_data['forum_id'], ($action == 'edit') ? true : false); - phpbb_cache_moderators($db, $cache, $auth); - $copied_permissions = true; - } -/* Commented out because of questionable UI workflow - re-visit for 3.0.7 - else if (!$this->parent_id && $action != 'edit' && $auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')) - { - $this->copy_permission_page($forum_data); - return; - } -*/ - $auth->acl_clear_prefetch(); - - $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_data['forum_id']; - - $message = ($action == 'add') ? $user->lang['FORUM_CREATED'] : $user->lang['FORUM_UPDATED']; - - // redirect directly to permission settings screen if authed - if ($action == 'add' && !$copied_permissions && $auth->acl_get('a_fauth')) - { - $message .= '

' . sprintf($user->lang['REDIRECT_ACL'], '', ''); - - meta_refresh(4, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url)); - } - - trigger_error($message . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); - } - - break; - } - } - - switch ($action) - { - case 'move_up': - case 'move_down': - - if (!$forum_id) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - $sql = 'SELECT * - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - $move_forum_name = $this->move_forum_by($row, $action, 1); - - if ($move_forum_name !== false) - { - $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); - } - - if ($request->is_ajax()) - { - $json_response = new \phpbb\json_response; - $json_response->send(array('success' => ($move_forum_name !== false))); - } - - break; - - case 'sync': - if (!$forum_id) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - @set_time_limit(0); - - $sql = 'SELECT forum_name, (forum_topics_approved + forum_topics_unapproved + forum_topics_softdeleted) AS total_topics - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - if ($row['total_topics']) - { - $sql = 'SELECT MIN(topic_id) as min_topic_id, MAX(topic_id) as max_topic_id - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = ' . $forum_id; - $result = $db->sql_query($sql); - $row2 = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Typecast to int if there is no data available - $row2['min_topic_id'] = (int) $row2['min_topic_id']; - $row2['max_topic_id'] = (int) $row2['max_topic_id']; - - $start = $request->variable('start', $row2['min_topic_id']); - - $batch_size = 2000; - $end = $start + $batch_size; - - // Sync all topics in batch mode... - sync('topic', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, true); - - if ($end < $row2['max_topic_id']) - { - // We really need to find a way of showing statistics... no progress here - $sql = 'SELECT COUNT(topic_id) as num_topics - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = ' . $forum_id . ' - AND topic_id BETWEEN ' . $start . ' AND ' . $end; - $result = $db->sql_query($sql); - $topics_done = $request->variable('topics_done', 0) + (int) $db->sql_fetchfield('num_topics'); - $db->sql_freeresult($result); - - $start += $batch_size; - - $url = $this->u_action . "&parent_id={$this->parent_id}&f=$forum_id&action=sync&start=$start&topics_done=$topics_done&total={$row['total_topics']}"; - - meta_refresh(0, $url); - - $template->assign_vars(array( - 'U_PROGRESS_BAR' => $this->u_action . "&action=progress_bar&start=$topics_done&total={$row['total_topics']}", - 'UA_PROGRESS_BAR' => addslashes($this->u_action . "&action=progress_bar&start=$topics_done&total={$row['total_topics']}"), - 'S_CONTINUE_SYNC' => true, - 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $topics_done, $row['total_topics'])) - ); - - return; - } - } - - $url = $this->u_action . "&parent_id={$this->parent_id}&f=$forum_id&action=sync_forum"; - meta_refresh(0, $url); - - $template->assign_vars(array( - 'U_PROGRESS_BAR' => $this->u_action . '&action=progress_bar', - 'UA_PROGRESS_BAR' => addslashes($this->u_action . '&action=progress_bar'), - 'S_CONTINUE_SYNC' => true, - 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], 0, $row['total_topics'])) - ); - - return; - - break; - - case 'sync_forum': - - $sql = 'SELECT forum_name, forum_type - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - sync('forum', 'forum_id', $forum_id, false, true); - - $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'])); - - break; - - case 'add': - case 'edit': - - if ($update) - { - $forum_data['forum_flags'] = 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->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 - $row = array(); - - // Show form to create/modify a forum - if ($action == 'edit') - { - $this->page_title = 'EDIT_FORUM'; - $row = $this->get_forum_info($forum_id); - $old_forum_type = $row['forum_type']; - - if (!$update) - { - $forum_data = $row; - } - else - { - $forum_data['left_id'] = $row['left_id']; - $forum_data['right_id'] = $row['right_id']; - } - - // Make sure no direct child forums are able to be selected as parents. - $exclude_forums = array(); - foreach (get_forum_branch($forum_id, 'children') as $row) - { - $exclude_forums[] = $row['forum_id']; - } - - $parents_list = make_forum_select($forum_data['parent_id'], $exclude_forums, false, false, false); - - $forum_data['forum_password_confirm'] = $forum_data['forum_password']; - } - else - { - $this->page_title = 'CREATE_FORUM'; - - $forum_id = $this->parent_id; - $parents_list = make_forum_select($this->parent_id, false, false, false, false); - - // Fill forum data with default values - if (!$update) - { - $forum_data = array( - 'parent_id' => $this->parent_id, - 'forum_type' => FORUM_POST, - 'forum_status' => ITEM_UNLOCKED, - 'forum_name' => $request->variable('forum_name', '', true), - 'forum_link' => '', - 'forum_link_track' => false, - 'forum_desc' => '', - 'forum_rules' => '', - 'forum_rules_link' => '', - 'forum_image' => '', - 'forum_style' => 0, - 'display_subforum_list' => true, - 'display_on_index' => false, - 'forum_topics_per_page' => 0, - 'enable_indexing' => true, - 'enable_icons' => false, - 'enable_prune' => false, - 'prune_days' => 7, - 'prune_viewed' => 7, - 'prune_freq' => 1, - 'enable_shadow_prune' => false, - 'prune_shadow_days' => 7, - 'prune_shadow_freq' => 1, - 'forum_flags' => FORUM_FLAG_POST_REVIEW + FORUM_FLAG_ACTIVE_TOPICS, - 'forum_options' => 0, - 'forum_password' => '', - 'forum_password_confirm'=> '', - ); - } - } - - /** - * Initialise data before we display the add/edit form - * - * @event core.acp_manage_forums_initialise_data - * @var string action Type of the action: add|edit - * @var bool update Do we display the form only - * or did the user press submit - * @var int forum_id When editing: the forum id, - * when creating: the parent forum id - * @var array row Array with current forum data - * empty when creating new forum - * @var array forum_data Array with new forum data - * @var string parents_list List of parent options - * @since 3.1.0-a1 - */ - $vars = array('action', 'update', 'forum_id', 'row', 'forum_data', 'parents_list'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_initialise_data', compact($vars))); - - $forum_rules_data = array( - 'text' => $forum_data['forum_rules'], - 'allow_bbcode' => true, - 'allow_smilies' => true, - 'allow_urls' => true - ); - - $forum_desc_data = array( - 'text' => $forum_data['forum_desc'], - 'allow_bbcode' => true, - 'allow_smilies' => true, - 'allow_urls' => true - ); - - $forum_rules_preview = ''; - - // Parse rules if specified - if ($forum_data['forum_rules']) - { - if (!isset($forum_data['forum_rules_uid'])) - { - // 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->variable('rules_allow_bbcode', false), $request->variable('rules_allow_urls', false), $request->variable('rules_allow_smilies', false)); - } - - // Generate preview content - $forum_rules_preview = generate_text_for_display($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options']); - - // decode... - $forum_rules_data = generate_text_for_edit($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_options']); - } - - // Parse desciption if specified - if ($forum_data['forum_desc']) - { - if (!isset($forum_data['forum_desc_uid'])) - { - // 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->variable('desc_allow_bbcode', false), $request->variable('desc_allow_urls', false), $request->variable('desc_allow_smilies', false)); - } - - // decode... - $forum_desc_data = generate_text_for_edit($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_options']); - } - - $forum_type_options = ''; - $forum_type_ary = array(FORUM_CAT => 'CAT', FORUM_POST => 'FORUM', FORUM_LINK => 'LINK'); - - foreach ($forum_type_ary as $value => $lang) - { - $forum_type_options .= ''; - } - - $styles_list = style_select($forum_data['forum_style'], true); - - $statuslist = ''; - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type = ' . FORUM_POST . " - AND forum_id <> $forum_id"; - $result = $db->sql_query_limit($sql, 1); - - $postable_forum_exists = false; - if ($db->sql_fetchrow($result)) - { - $postable_forum_exists = true; - } - $db->sql_freeresult($result); - - // Subforum move options - if ($action == 'edit' && $forum_data['forum_type'] == FORUM_CAT) - { - $subforums_id = array(); - $subforums = get_forum_branch($forum_id, 'children'); - - foreach ($subforums as $row) - { - $subforums_id[] = $row['forum_id']; - } - - $forums_list = make_forum_select($forum_data['parent_id'], $subforums_id); - - if ($postable_forum_exists) - { - $template->assign_vars(array( - 'S_MOVE_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $subforums_id)) // , false, true, false??? - ); - } - - $template->assign_vars(array( - 'S_HAS_SUBFORUMS' => ($forum_data['right_id'] - $forum_data['left_id'] > 1) ? true : false, - 'S_FORUMS_LIST' => $forums_list) - ); - } - else if ($postable_forum_exists) - { - $template->assign_vars(array( - 'S_MOVE_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $forum_id, false, true, false)) - ); - } - - $s_show_display_on_index = false; - - if ($forum_data['parent_id'] > 0) - { - // if this forum is a subforum put the "display on index" checkbox - if ($parent_info = $this->get_forum_info($forum_data['parent_id'])) - { - if ($parent_info['parent_id'] > 0 || $parent_info['forum_type'] == FORUM_CAT) - { - $s_show_display_on_index = true; - } - } - } - - if (strlen($forum_data['forum_password']) == 32) - { - $errors[] = $user->lang['FORUM_PASSWORD_OLD']; - } - - $template_data = array( - 'S_EDIT_FORUM' => true, - '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, - - 'U_BACK' => $this->u_action . '&parent_id=' . $this->parent_id, - 'U_EDIT_ACTION' => $this->u_action . "&parent_id={$this->parent_id}&action=$action&f=$forum_id", - - 'L_COPY_PERMISSIONS_EXPLAIN' => $user->lang['COPY_PERMISSIONS_' . strtoupper($action) . '_EXPLAIN'], - 'L_TITLE' => $user->lang[$this->page_title], - 'ERROR_MSG' => (count($errors)) ? implode('
', $errors) : '', - - 'FORUM_NAME' => $forum_data['forum_name'], - 'FORUM_DATA_LINK' => $forum_data['forum_link'], - 'FORUM_IMAGE' => $forum_data['forum_image'], - 'FORUM_IMAGE_SRC' => ($forum_data['forum_image']) ? $phpbb_root_path . $forum_data['forum_image'] : '', - 'FORUM_POST' => FORUM_POST, - 'FORUM_LINK' => FORUM_LINK, - 'FORUM_CAT' => FORUM_CAT, - 'PRUNE_FREQ' => $forum_data['prune_freq'], - 'PRUNE_DAYS' => $forum_data['prune_days'], - 'PRUNE_VIEWED' => $forum_data['prune_viewed'], - 'PRUNE_SHADOW_FREQ' => $forum_data['prune_shadow_freq'], - 'PRUNE_SHADOW_DAYS' => $forum_data['prune_shadow_days'], - 'TOPICS_PER_PAGE' => $forum_data['forum_topics_per_page'], - 'FORUM_RULES_LINK' => $forum_data['forum_rules_link'], - 'FORUM_RULES' => $forum_data['forum_rules'], - 'FORUM_RULES_PREVIEW' => $forum_rules_preview, - 'FORUM_RULES_PLAIN' => $forum_rules_data['text'], - 'S_BBCODE_CHECKED' => ($forum_rules_data['allow_bbcode']) ? true : false, - 'S_SMILIES_CHECKED' => ($forum_rules_data['allow_smilies']) ? true : false, - 'S_URLS_CHECKED' => ($forum_rules_data['allow_urls']) ? true : false, - 'S_FORUM_PASSWORD_SET' => (empty($forum_data['forum_password'])) ? false : true, - - 'FORUM_DESC' => $forum_desc_data['text'], - 'S_DESC_BBCODE_CHECKED' => ($forum_desc_data['allow_bbcode']) ? true : false, - 'S_DESC_SMILIES_CHECKED' => ($forum_desc_data['allow_smilies']) ? true : false, - 'S_DESC_URLS_CHECKED' => ($forum_desc_data['allow_urls']) ? true : false, - - 'S_FORUM_TYPE_OPTIONS' => $forum_type_options, - 'S_STATUS_OPTIONS' => $statuslist, - 'S_PARENT_OPTIONS' => $parents_list, - 'S_STYLES_OPTIONS' => $styles_list, - 'S_FORUM_OPTIONS' => make_forum_select(($action == 'add') ? $forum_data['parent_id'] : false, ($action == 'edit') ? $forum_data['forum_id'] : false, false, false, false), - 'S_SHOW_DISPLAY_ON_INDEX' => $s_show_display_on_index, - 'S_FORUM_POST' => ($forum_data['forum_type'] == FORUM_POST) ? true : false, - 'S_FORUM_ORIG_POST' => (isset($old_forum_type) && $old_forum_type == FORUM_POST) ? true : false, - 'S_FORUM_ORIG_CAT' => (isset($old_forum_type) && $old_forum_type == FORUM_CAT) ? true : false, - 'S_FORUM_ORIG_LINK' => (isset($old_forum_type) && $old_forum_type == FORUM_LINK) ? true : false, - 'S_FORUM_LINK' => ($forum_data['forum_type'] == FORUM_LINK) ? true : false, - 'S_FORUM_CAT' => ($forum_data['forum_type'] == FORUM_CAT) ? true : false, - 'S_ENABLE_INDEXING' => ($forum_data['enable_indexing']) ? true : false, - 'S_TOPIC_ICONS' => ($forum_data['enable_icons']) ? true : false, - 'S_DISPLAY_SUBFORUM_LIST' => ($forum_data['display_subforum_list']) ? true : false, - 'S_DISPLAY_ON_INDEX' => ($forum_data['display_on_index']) ? true : false, - 'S_PRUNE_ENABLE' => ($forum_data['enable_prune']) ? true : false, - 'S_PRUNE_SHADOW_ENABLE' => ($forum_data['enable_shadow_prune']) ? true : false, - 'S_FORUM_LINK_TRACK' => ($forum_data['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? true : false, - 'S_PRUNE_OLD_POLLS' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_POLL) ? true : false, - 'S_PRUNE_ANNOUNCE' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_ANNOUNCE) ? true : false, - 'S_PRUNE_STICKY' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_STICKY) ? true : false, - 'S_DISPLAY_ACTIVE_TOPICS' => ($forum_data['forum_type'] == FORUM_POST) ? ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) : true, - 'S_ENABLE_ACTIVE_TOPICS' => ($forum_data['forum_type'] == FORUM_CAT) ? ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) : false, - 'S_ENABLE_POST_REVIEW' => ($forum_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) ? true : false, - 'S_ENABLE_QUICK_REPLY' => ($forum_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) ? true : false, - 'S_CAN_COPY_PERMISSIONS' => ($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth'))) ? true : false, - ); - - /** - * Modify forum template data before we display the form - * - * @event core.acp_manage_forums_display_form - * @var string action Type of the action: add|edit - * @var bool update Do we display the form only - * or did the user press submit - * @var int forum_id When editing: the forum id, - * when creating: the parent forum id - * @var array row Array with current forum data - * empty when creating new forum - * @var array forum_data Array with new forum data - * @var string parents_list List of parent options - * @var array errors Array of errors, if you add errors - * ensure to update the template variables - * S_ERROR and ERROR_MSG to display it - * @var array template_data Array with new forum data - * @since 3.1.0-a1 - */ - $vars = array( - 'action', - 'update', - 'forum_id', - 'row', - 'forum_data', - 'parents_list', - 'errors', - 'template_data', - ); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_display_form', compact($vars))); - - $template->assign_vars($template_data); - - return; - - break; - - case 'delete': - - if (!$forum_id) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - $forum_data = $this->get_forum_info($forum_id); - - $subforums_id = array(); - $subforums = get_forum_branch($forum_id, 'children'); - - foreach ($subforums as $row) - { - $subforums_id[] = $row['forum_id']; - } - - $forums_list = make_forum_select($forum_data['parent_id'], $subforums_id); - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type = ' . FORUM_POST . " - AND forum_id <> $forum_id"; - $result = $db->sql_query_limit($sql, 1); - - if ($db->sql_fetchrow($result)) - { - $template->assign_vars(array( - 'S_MOVE_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $subforums_id, false, true)) // , false, true, false??? - ); - } - $db->sql_freeresult($result); - - $parent_id = ($this->parent_id == $forum_id) ? 0 : $this->parent_id; - - $template->assign_vars(array( - 'S_DELETE_FORUM' => true, - 'U_ACTION' => $this->u_action . "&parent_id={$parent_id}&action=delete&f=$forum_id", - 'U_BACK' => $this->u_action . '&parent_id=' . $this->parent_id, - - 'FORUM_NAME' => $forum_data['forum_name'], - 'S_FORUM_POST' => ($forum_data['forum_type'] == FORUM_POST) ? true : false, - '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' => (count($errors)) ? true : false, - 'ERROR_MSG' => (count($errors)) ? implode('
', $errors) : '') - ); - - return; - break; - - case 'copy_perm': - $forum_perm_from = $request->variable('forum_perm_from', 0); - - // Copy permissions? - if (!empty($forum_perm_from) && $forum_perm_from != $forum_id) - { - copy_forum_permissions($forum_perm_from, $forum_id, true); - phpbb_cache_moderators($db, $cache, $auth); - $auth->acl_clear_prefetch(); - $cache->destroy('sql', FORUMS_TABLE); - - $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_id; - - $message = $user->lang['FORUM_UPDATED']; - - // Redirect to permissions - if ($auth->acl_get('a_fauth')) - { - $message .= '

' . sprintf($user->lang['REDIRECT_ACL'], '', ''); - } - - trigger_error($message . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); - } - - break; - } - - // Default management page - if (!$this->parent_id) - { - $navigation = $user->lang['FORUM_INDEX']; - } - else - { - $navigation = '' . $user->lang['FORUM_INDEX'] . ''; - - $forums_nav = get_forum_branch($this->parent_id, 'parents', 'descending'); - foreach ($forums_nav as $row) - { - if ($row['forum_id'] == $this->parent_id) - { - $navigation .= ' -> ' . $row['forum_name']; - } - else - { - $navigation .= ' -> ' . $row['forum_name'] . ''; - } - } - } - - // Jumpbox - $forum_box = make_forum_select($this->parent_id, false, false, false, false); //make_forum_select($this->parent_id); - - if ($action == 'sync' || $action == 'sync_forum') - { - $template->assign_var('S_RESYNCED', true); - } - - $sql = 'SELECT * - FROM ' . FORUMS_TABLE . " - WHERE parent_id = $this->parent_id - ORDER BY left_id"; - $result = $db->sql_query($sql); - - $rowset = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[(int) $row['forum_id']] = $row; - } - $db->sql_freeresult($result); - - /** - * Modify the forum list data - * - * @event core.acp_manage_forums_modify_forum_list - * @var array rowset Array with the forums list data - * @since 3.1.10-RC1 - */ - $vars = array('rowset'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_modify_forum_list', compact($vars))); - - if (!empty($rowset)) - { - foreach ($rowset as $row) - { - $forum_type = $row['forum_type']; - - if ($row['forum_status'] == ITEM_LOCKED) - { - $folder_image = '' . $user->lang['LOCKED'] . ''; - } - else - { - switch ($forum_type) - { - case FORUM_LINK: - $folder_image = '' . $user->lang['LINK'] . ''; - break; - - default: - $folder_image = ($row['left_id'] + 1 != $row['right_id']) ? '' . $user->lang['SUBFORUM'] . '' : '' . $user->lang['FOLDER'] . ''; - break; - } - } - - $url = $this->u_action . "&parent_id=$this->parent_id&f={$row['forum_id']}"; - - $template->assign_block_vars('forums', array( - 'FOLDER_IMAGE' => $folder_image, - 'FORUM_IMAGE' => ($row['forum_image']) ? '' : '', - 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', - 'FORUM_NAME' => $row['forum_name'], - 'FORUM_DESCRIPTION' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), - 'FORUM_TOPICS' => $row['forum_topics_approved'], - 'FORUM_POSTS' => $row['forum_posts_approved'], - - 'S_FORUM_LINK' => ($forum_type == FORUM_LINK) ? true : false, - 'S_FORUM_POST' => ($forum_type == FORUM_POST) ? true : false, - - 'U_FORUM' => $this->u_action . '&parent_id=' . $row['forum_id'], - 'U_MOVE_UP' => $url . '&action=move_up', - 'U_MOVE_DOWN' => $url . '&action=move_down', - 'U_EDIT' => $url . '&action=edit', - 'U_DELETE' => $url . '&action=delete', - 'U_SYNC' => $url . '&action=sync') - ); - } - } - else if ($this->parent_id) - { - $row = $this->get_forum_info($this->parent_id); - - $url = $this->u_action . '&parent_id=' . $this->parent_id . '&f=' . $row['forum_id']; - - $template->assign_vars(array( - 'S_NO_FORUMS' => true, - - 'U_EDIT' => $url . '&action=edit', - 'U_DELETE' => $url . '&action=delete', - 'U_SYNC' => $url . '&action=sync') - ); - } - unset($rowset); - - $template->assign_vars(array( - 'ERROR_MSG' => (count($errors)) ? implode('
', $errors) : '', - 'NAVIGATION' => $navigation, - 'FORUM_BOX' => $forum_box, - 'U_SEL_ACTION' => $this->u_action, - 'U_ACTION' => $this->u_action . '&parent_id=' . $this->parent_id, - - 'U_PROGRESS_BAR' => $this->u_action . '&action=progress_bar', - 'UA_PROGRESS_BAR' => addslashes($this->u_action . '&action=progress_bar'), - )); - } - - /** - * Get forum details - */ - function get_forum_info($forum_id) - { - global $db; - - $sql = 'SELECT * - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error("Forum #$forum_id does not exist", E_USER_ERROR); - } - - return $row; - } - - /** - * Update forum data - */ - function update_forum_data(&$forum_data_ary) - { - 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 - * - * @event core.acp_manage_forums_validate_data - * @var array forum_data Array with new forum data - * @var array errors Array of errors, should be strings and not - * language key. - * @since 3.1.0-a1 - */ - $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_ary['forum_name'] == '') - { - $errors[] = $user->lang['FORUM_NAME_EMPTY']; - } - - if (utf8_strlen($forum_data_ary['forum_desc']) > 4000) - { - $errors[] = $user->lang['FORUM_DESC_TOO_LONG']; - } - - if (utf8_strlen($forum_data_ary['forum_rules']) > 4000) - { - $errors[] = $user->lang['FORUM_RULES_TOO_LONG']; - } - - if ($forum_data_ary['forum_password'] || $forum_data_ary['forum_password_confirm']) - { - if ($forum_data_ary['forum_password'] != $forum_data_ary['forum_password_confirm']) - { - $forum_data_ary['forum_password'] = $forum_data_ary['forum_password_confirm'] = ''; - $errors[] = $user->lang['FORUM_PASSWORD_MISMATCH']; - } - } - - if ($forum_data_ary['prune_days'] < 0 || $forum_data_ary['prune_viewed'] < 0 || $forum_data_ary['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_ary['forum_topics_per_page'], 'column_type' => 'USINT:0'), - ); - - if (!empty($forum_data_ary['forum_image']) && !file_exists($phpbb_root_path . $forum_data_ary['forum_image'])) - { - $errors[] = $user->lang['FORUM_IMAGE_NO_EXIST']; - } - - validate_range($range_test_ary, $errors); - - // Set forum flags - // 1 = link tracking - // 2 = prune old polls - // 4 = prune announcements - // 8 = prune stickies - // 16 = show active topics - // 32 = enable post review - $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_ary; - - unset($forum_data_sql['forum_link_track']); - unset($forum_data_sql['prune_old_polls']); - unset($forum_data_sql['prune_announce']); - unset($forum_data_sql['prune_sticky']); - unset($forum_data_sql['show_active']); - unset($forum_data_sql['enable_post_review']); - unset($forum_data_sql['enable_quick_reply']); - unset($forum_data_sql['forum_password_confirm']); - - // What are we going to do tonight Brain? The same thing we do everynight, - // 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 (count($errors)) - { - return $errors; - } - - // As we don't know the old password, it's kinda tricky to detect changes - if ($forum_data_sql['forum_password_unset']) - { - $forum_data_sql['forum_password'] = ''; - } - else if (empty($forum_data_sql['forum_password'])) - { - unset($forum_data_sql['forum_password']); - } - 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 - * - * @event core.acp_manage_forums_update_data_before - * @var array forum_data Array with forum data - * @var array forum_data_sql Array with data we are going to update - * If forum_data_sql[forum_id] is set, we update - * that forum, otherwise a new one is created. - * @since 3.1.0-a1 - */ - $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']); - - if ($is_new_forum) - { - // no forum_id means we're creating a new forum - unset($forum_data_sql['type_action']); - - if ($forum_data_sql['parent_id']) - { - $sql = 'SELECT left_id, right_id, forum_type - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $forum_data_sql['parent_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['PARENT_NOT_EXIST'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); - } - - if ($row['forum_type'] == FORUM_LINK) - { - $errors[] = $user->lang['PARENT_IS_LINK_FORUM']; - return $errors; - } - - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET left_id = left_id + 2, right_id = right_id + 2 - WHERE left_id > ' . $row['right_id']; - $db->sql_query($sql); - - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET right_id = right_id + 2 - WHERE ' . $row['left_id'] . ' BETWEEN left_id AND right_id'; - $db->sql_query($sql); - - $forum_data_sql['left_id'] = $row['right_id']; - $forum_data_sql['right_id'] = $row['right_id'] + 1; - } - else - { - $sql = 'SELECT MAX(right_id) AS right_id - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $forum_data_sql['left_id'] = $row['right_id'] + 1; - $forum_data_sql['right_id'] = $row['right_id'] + 2; - } - - $sql = 'INSERT INTO ' . FORUMS_TABLE . ' ' . $db->sql_build_array('INSERT', $forum_data_sql); - $db->sql_query($sql); - - $forum_data_ary['forum_id'] = $db->sql_nextid(); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_ADD', false, array($forum_data_ary['forum_name'])); - } - else - { - $row = $this->get_forum_info($forum_data_sql['forum_id']); - - if ($row['forum_type'] == FORUM_POST && $row['forum_type'] != $forum_data_sql['forum_type']) - { - // Has subforums and want to change into a link? - if ($row['right_id'] - $row['left_id'] > 1 && $forum_data_sql['forum_type'] == FORUM_LINK) - { - $errors[] = $user->lang['FORUM_WITH_SUBFORUMS_NOT_TO_LINK']; - return $errors; - } - - // we're turning a postable forum into a non-postable forum - if ($forum_data_sql['type_action'] == 'move') - { - $to_forum_id = $request->variable('to_forum_id', 0); - - if ($to_forum_id) - { - $errors = $this->move_forum_content($forum_data_sql['forum_id'], $to_forum_id); - } - else - { - return array($user->lang['NO_DESTINATION_FORUM']); - } - } - else if ($forum_data_sql['type_action'] == 'delete') - { - $errors = $this->delete_forum_content($forum_data_sql['forum_id']); - } - else - { - return array($user->lang['NO_FORUM_ACTION']); - } - - $forum_data_sql['forum_posts_approved'] = $forum_data_sql['forum_posts_unapproved'] = $forum_data_sql['forum_posts_softdeleted'] = $forum_data_sql['forum_topics_approved'] = $forum_data_sql['forum_topics_unapproved'] = $forum_data_sql['forum_topics_softdeleted'] = 0; - $forum_data_sql['forum_last_post_id'] = $forum_data_sql['forum_last_poster_id'] = $forum_data_sql['forum_last_post_time'] = 0; - $forum_data_sql['forum_last_poster_name'] = $forum_data_sql['forum_last_poster_colour'] = ''; - } - else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_LINK) - { - // Has subforums? - 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->variable('action_subforums', ''); - $subforums_to_id = $request->variable('subforums_to_id', 0); - - if ($action_subforums == 'delete') - { - $rows = get_forum_branch($row['forum_id'], 'children', 'descending', false); - - foreach ($rows as $_row) - { - // Do not remove the forum id we are about to change. ;) - if ($_row['forum_id'] == $row['forum_id']) - { - continue; - } - - $forum_ids[] = $_row['forum_id']; - $errors = array_merge($errors, $this->delete_forum_content($_row['forum_id'])); - } - - if (count($errors)) - { - return $errors; - } - - if (count($forum_ids)) - { - $sql = 'DELETE FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - // Delete forum ids from extension groups table - $sql = 'SELECT group_id, allowed_forums - FROM ' . EXTENSION_GROUPS_TABLE; - $result = $db->sql_query($sql); - - while ($_row = $db->sql_fetchrow($result)) - { - if (!$_row['allowed_forums']) - { - continue; - } - - $allowed_forums = unserialize(trim($_row['allowed_forums'])); - $allowed_forums = array_diff($allowed_forums, $forum_ids); - - $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . " - SET allowed_forums = '" . ((count($allowed_forums)) ? serialize($allowed_forums) : '') . "' - WHERE group_id = {$_row['group_id']}"; - $db->sql_query($sql); - } - $db->sql_freeresult($result); - - $cache->destroy('_extensions'); - } - } - else if ($action_subforums == 'move') - { - if (!$subforums_to_id) - { - return array($user->lang['NO_DESTINATION_FORUM']); - } - - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $subforums_to_id; - $result = $db->sql_query($sql); - $_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$_row) - { - return array($user->lang['NO_FORUM']); - } - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . " - WHERE parent_id = {$row['forum_id']}"; - $result = $db->sql_query($sql); - - while ($_row = $db->sql_fetchrow($result)) - { - $this->move_forum($_row['forum_id'], $subforums_to_id); - } - $db->sql_freeresult($result); - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET parent_id = $subforums_to_id - WHERE parent_id = {$row['forum_id']}"; - $db->sql_query($sql); - } - - // Adjust the left/right id - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET right_id = left_id + 1 - WHERE forum_id = ' . $row['forum_id']; - $db->sql_query($sql); - } - } - else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_POST) - { - // Changing a category to a forum? Reset the data (you can't post directly in a cat, you must use a forum) - $forum_data_sql['forum_posts_approved'] = 0; - $forum_data_sql['forum_posts_unapproved'] = 0; - $forum_data_sql['forum_posts_softdeleted'] = 0; - $forum_data_sql['forum_topics_approved'] = 0; - $forum_data_sql['forum_topics_unapproved'] = 0; - $forum_data_sql['forum_topics_softdeleted'] = 0; - $forum_data_sql['forum_last_post_id'] = 0; - $forum_data_sql['forum_last_post_subject'] = ''; - $forum_data_sql['forum_last_post_time'] = 0; - $forum_data_sql['forum_last_poster_id'] = 0; - $forum_data_sql['forum_last_poster_name'] = ''; - $forum_data_sql['forum_last_poster_colour'] = ''; - } - - if (count($errors)) - { - return $errors; - } - - if ($row['parent_id'] != $forum_data_sql['parent_id']) - { - if ($row['forum_id'] != $forum_data_sql['parent_id']) - { - $errors = $this->move_forum($forum_data_sql['forum_id'], $forum_data_sql['parent_id']); - } - else - { - $forum_data_sql['parent_id'] = $row['parent_id']; - } - } - - if (count($errors)) - { - return $errors; - } - - unset($forum_data_sql['type_action']); - - if ($row['forum_name'] != $forum_data_sql['forum_name']) - { - // the forum name has changed, clear the parents list of all forums (for safety) - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_parents = ''"; - $db->sql_query($sql); - } - - // Setting the forum id to the forum id is not really received well by some dbs. ;) - $forum_id = $forum_data_sql['forum_id']; - unset($forum_data_sql['forum_id']); - - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $forum_data_sql) . ' - WHERE forum_id = ' . $forum_id; - $db->sql_query($sql); - - // Add it back - $forum_data_ary['forum_id'] = $forum_id; - - $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 - * - * @event core.acp_manage_forums_update_data_after - * @var array forum_data Array with forum data - * @var array forum_data_sql Array with data we updated - * @var bool is_new_forum Did we create a forum or update one - * If you want to overwrite this value, - * ensure to set forum_data_sql[forum_id] - * @var array errors Array of errors, should be strings and not - * language key. - * @since 3.1.0-a1 - */ - $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; - } - - /** - * Move forum - */ - function move_forum($from_id, $to_id) - { - global $db, $user, $phpbb_dispatcher; - - $errors = array(); - - // Check if we want to move to a parent with link type - if ($to_id > 0) - { - $to_data = $this->get_forum_info($to_id); - - if ($to_data['forum_type'] == FORUM_LINK) - { - $errors[] = $user->lang['PARENT_IS_LINK_FORUM']; - } - } - - /** - * Event when we move all children of one forum to another - * - * 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 array errors Array of errors, should be strings and not - * language key. - * @since 3.1.0-a1 - */ - $vars = array('from_id', 'to_id', 'errors'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_children', compact($vars))); - - // Return if there were errors - if (!empty($errors)) - { - return $errors; - } - - $db->sql_transaction('begin'); - - $moved_forums = get_forum_branch($from_id, 'children', 'descending'); - $from_data = $moved_forums[0]; - $diff = count($moved_forums) * 2; - - $moved_ids = array(); - for ($i = 0, $size = count($moved_forums); $i < $size; ++$i) - { - $moved_ids[] = $moved_forums[$i]['forum_id']; - } - - // Resync parents - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET right_id = right_id - $diff, forum_parents = '' - WHERE left_id < " . $from_data['right_id'] . " - AND right_id > " . $from_data['right_id']; - $db->sql_query($sql); - - // Resync righthand side of tree - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET left_id = left_id - $diff, right_id = right_id - $diff, forum_parents = '' - WHERE left_id > " . $from_data['right_id']; - $db->sql_query($sql); - - if ($to_id > 0) - { - // Retrieve $to_data again, it may have been changed... - $to_data = $this->get_forum_info($to_id); - - // Resync new parents - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET right_id = right_id + $diff, forum_parents = '' - WHERE " . $to_data['right_id'] . ' BETWEEN left_id AND right_id - AND ' . $db->sql_in_set('forum_id', $moved_ids, true); - $db->sql_query($sql); - - // Resync the righthand side of the tree - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET left_id = left_id + $diff, right_id = right_id + $diff, forum_parents = '' - WHERE left_id > " . $to_data['right_id'] . ' - AND ' . $db->sql_in_set('forum_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 ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $moved_ids, true); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $diff = '+ ' . ($row['right_id'] - $from_data['left_id'] + 1); - } - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET left_id = left_id $diff, right_id = right_id $diff, forum_parents = '' - WHERE " . $db->sql_in_set('forum_id', $moved_ids); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - return $errors; - } - - /** - * Move forum content from one to another forum - */ - function move_forum_content($from_id, $to_id, $sync = true) - { - global $db, $phpbb_dispatcher; - - $errors = array(); - - /** - * 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 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, - * The content will not be moved. - * @since 3.1.0-a1 - */ - $vars = array('from_id', 'to_id', 'sync', 'errors'); - extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_content', compact($vars))); - - // Return if there were errors - if (!empty($errors)) - { - return $errors; - } - - $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 - SET forum_id = $to_id - WHERE forum_id = $from_id"; - $db->sql_query($sql); - } - unset($table_ary); - - $table_ary = array(FORUMS_ACCESS_TABLE, FORUMS_TRACK_TABLE, FORUMS_WATCH_TABLE, MODERATOR_CACHE_TABLE); - - foreach ($table_ary as $table) - { - $sql = "DELETE FROM $table - WHERE forum_id = $from_id"; - $db->sql_query($sql); - } - - if ($sync) - { - // Delete ghost topics that link back to the same forum then resync counters - sync('topic_moved'); - sync('forum', 'forum_id', $to_id, false, true); - } - - return array(); - } - - /** - * Remove complete forum - */ - function delete_forum($forum_id, $action_posts = 'delete', $action_subforums = 'delete', $posts_to_id = 0, $subforums_to_id = 0) - { - global $db, $user, $cache, $phpbb_log; - - $forum_data = $this->get_forum_info($forum_id); - - $errors = array(); - $log_action_posts = $log_action_forums = $posts_to_name = $subforums_to_name = ''; - $forum_ids = array($forum_id); - - if ($action_posts == 'delete') - { - $log_action_posts = 'POSTS'; - $errors = array_merge($errors, $this->delete_forum_content($forum_id)); - } - else if ($action_posts == 'move') - { - if (!$posts_to_id) - { - $errors[] = $user->lang['NO_DESTINATION_FORUM']; - } - else - { - $log_action_posts = 'MOVE_POSTS'; - - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $posts_to_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $errors[] = $user->lang['NO_FORUM']; - } - else - { - $posts_to_name = $row['forum_name']; - $errors = array_merge($errors, $this->move_forum_content($forum_id, $posts_to_id)); - } - } - } - - if (count($errors)) - { - return $errors; - } - - if ($action_subforums == 'delete') - { - $log_action_forums = 'FORUMS'; - $rows = get_forum_branch($forum_id, 'children', 'descending', false); - - foreach ($rows as $row) - { - $forum_ids[] = $row['forum_id']; - $errors = array_merge($errors, $this->delete_forum_content($row['forum_id'])); - } - - if (count($errors)) - { - return $errors; - } - - $diff = count($forum_ids) * 2; - - $sql = 'DELETE FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids); - $db->sql_query($sql); - } - else if ($action_subforums == 'move') - { - if (!$subforums_to_id) - { - $errors[] = $user->lang['NO_DESTINATION_FORUM']; - } - else - { - $log_action_forums = 'MOVE_FORUMS'; - - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $subforums_to_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $errors[] = $user->lang['NO_FORUM']; - } - else - { - $subforums_to_name = $row['forum_name']; - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . " - WHERE parent_id = $forum_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $this->move_forum($row['forum_id'], $subforums_to_id); - } - $db->sql_freeresult($result); - - // Grab new forum data for correct tree updating later - $forum_data = $this->get_forum_info($forum_id); - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET parent_id = $subforums_to_id - WHERE parent_id = $forum_id"; - $db->sql_query($sql); - - $diff = 2; - $sql = 'DELETE FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - } - } - - if (count($errors)) - { - return $errors; - } - } - else - { - $diff = 2; - $sql = 'DELETE FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . " - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - } - - // Resync tree - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET right_id = right_id - $diff - WHERE left_id < {$forum_data['right_id']} AND right_id > {$forum_data['right_id']}"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET left_id = left_id - $diff, right_id = right_id - $diff - WHERE left_id > {$forum_data['right_id']}"; - $db->sql_query($sql); - - // Delete forum ids from extension groups table - $sql = 'SELECT group_id, allowed_forums - FROM ' . EXTENSION_GROUPS_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$row['allowed_forums']) - { - continue; - } - - $allowed_forums = unserialize(trim($row['allowed_forums'])); - $allowed_forums = array_diff($allowed_forums, $forum_ids); - - $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . " - SET allowed_forums = '" . ((count($allowed_forums)) ? serialize($allowed_forums) : '') . "' - WHERE group_id = {$row['group_id']}"; - $db->sql_query($sql); - } - $db->sql_freeresult($result); - - $cache->destroy('_extensions'); - - $log_action = implode('_', array($log_action_posts, $log_action_forums)); - - switch ($log_action) - { - case 'MOVE_POSTS_MOVE_FORUMS': - $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': - $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': - $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': - $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_': - $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': - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS_FORUMS', false, array($forum_data['forum_name'])); - break; - - case '_FORUMS': - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_FORUMS', false, array($forum_data['forum_name'])); - break; - - case 'POSTS_': - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS', false, array($forum_data['forum_name'])); - break; - - default: - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_FORUM', false, array($forum_data['forum_name'])); - break; - } - - return $errors; - } - - /** - * Delete forum content - */ - function delete_forum_content($forum_id) - { - global $db, $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher; - - include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - - $db->sql_transaction('begin'); - - // Select then delete all attachments - $sql = 'SELECT a.topic_id - FROM ' . POSTS_TABLE . ' p, ' . ATTACHMENTS_TABLE . " a - WHERE p.forum_id = $forum_id - AND a.in_message = 0 - AND a.topic_id = p.topic_id"; - $result = $db->sql_query($sql); - - $topic_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - /** @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); - - // Before we remove anything we make sure we are able to adjust the post counts later. ;) - $sql = 'SELECT poster_id - FROM ' . POSTS_TABLE . ' - WHERE forum_id = ' . $forum_id . ' - AND post_postcount = 1 - AND post_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - - $post_counts = array(); - while ($row = $db->sql_fetchrow($result)) - { - $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1; - } - $db->sql_freeresult($result); - - switch ($db->get_sql_layer()) - { - case 'mysql4': - case 'mysqli': - - // Delete everything else and thank MySQL for offering multi-table deletion - $tables_ary = array( - SEARCH_WORDMATCH_TABLE => 'post_id', - REPORTS_TABLE => 'post_id', - WARNINGS_TABLE => 'post_id', - BOOKMARKS_TABLE => 'topic_id', - TOPICS_WATCH_TABLE => 'topic_id', - TOPICS_POSTED_TABLE => 'topic_id', - POLL_OPTIONS_TABLE => 'topic_id', - POLL_VOTES_TABLE => 'topic_id', - ); - - $sql = 'DELETE ' . POSTS_TABLE; - $sql_using = "\nFROM " . POSTS_TABLE; - $sql_where = "\nWHERE " . POSTS_TABLE . ".forum_id = $forum_id\n"; - - foreach ($tables_ary as $table => $field) - { - $sql .= ", $table "; - $sql_using .= ", $table "; - $sql_where .= "\nAND $table.$field = " . POSTS_TABLE . ".$field"; - } - - $db->sql_query($sql . $sql_using . $sql_where); - - break; - - default: - - // Delete everything else and curse your DB for not offering multi-table deletion - $tables_ary = array( - 'post_id' => array( - SEARCH_WORDMATCH_TABLE, - REPORTS_TABLE, - WARNINGS_TABLE, - ), - - 'topic_id' => array( - BOOKMARKS_TABLE, - TOPICS_WATCH_TABLE, - TOPICS_POSTED_TABLE, - POLL_OPTIONS_TABLE, - POLL_VOTES_TABLE, - ) - ); - - // Amount of rows we select and delete in one iteration. - $batch_size = 500; - - foreach ($tables_ary as $field => $tables) - { - $start = 0; - - do - { - $sql = "SELECT $field - FROM " . POSTS_TABLE . ' - WHERE forum_id = ' . $forum_id; - $result = $db->sql_query_limit($sql, $batch_size, $start); - - $ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $ids[] = $row[$field]; - } - $db->sql_freeresult($result); - - if (count($ids)) - { - $start += count($ids); - - foreach ($tables as $table) - { - $db->sql_query("DELETE FROM $table WHERE " . $db->sql_in_set($field, $ids)); - } - } - } - while (count($ids) == $batch_size); - } - unset($ids); - - break; - } - - $table_ary = array(FORUMS_ACCESS_TABLE, FORUMS_TRACK_TABLE, FORUMS_WATCH_TABLE, LOG_TABLE, MODERATOR_CACHE_TABLE, POSTS_TABLE, TOPICS_TABLE, TOPICS_TRACK_TABLE); - - /** - * Perform additional actions before forum content deletion - * - * @event core.delete_forum_content_before_query - * @var array table_ary Array of tables from which all rows will be deleted that hold the forum_id - * @var int forum_id the forum id - * @var array topic_ids Array of the topic ids from the forum to be deleted - * @var array post_counts Array of counts of posts in the forum, by poster_id - * @since 3.1.6-RC1 - */ - $vars = array( - 'table_ary', - 'forum_id', - 'topic_ids', - 'post_counts', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_forum_content_before_query', compact($vars))); - - foreach ($table_ary as $table) - { - $db->sql_query("DELETE FROM $table WHERE forum_id = $forum_id"); - } - - // Set forum ids to 0 - $table_ary = array(DRAFTS_TABLE); - - foreach ($table_ary as $table) - { - $db->sql_query("UPDATE $table SET forum_id = 0 WHERE forum_id = $forum_id"); - } - - // Adjust users post counts - if (count($post_counts)) - { - foreach ($post_counts as $poster_id => $substract) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = 0 - WHERE user_id = ' . $poster_id . ' - AND user_posts < ' . $substract; - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts - ' . $substract . ' - WHERE user_id = ' . $poster_id . ' - AND user_posts >= ' . $substract; - $db->sql_query($sql); - } - } - - $db->sql_transaction('commit'); - - // Make sure the overall post/topic count is correct... - $sql = 'SELECT COUNT(post_id) AS stat - FROM ' . POSTS_TABLE . ' - WHERE post_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_posts', (int) $row['stat'], false); - - $sql = 'SELECT COUNT(topic_id) AS stat - FROM ' . TOPICS_TABLE . ' - WHERE topic_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_topics', (int) $row['stat'], false); - - $sql = 'SELECT COUNT(attach_id) as stat - FROM ' . ATTACHMENTS_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_files', (int) $row['stat'], false); - - $sql = 'SELECT SUM(filesize) as stat - FROM ' . ATTACHMENTS_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('upload_dir_size', (float) $row['stat'], false); - - return array(); - } - - /** - * Move forum position by $steps up/down - */ - function move_forum_by($forum_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 forum_id, forum_name, left_id, right_id - FROM ' . FORUMS_TABLE . " - WHERE parent_id = {$forum_row['parent_id']} - AND " . (($action == 'move_up') ? "right_id < {$forum_row['right_id']} ORDER BY right_id DESC" : "left_id > {$forum_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 (!count($target)) - { - // The forum 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 = $target['left_id']; - $right_id = $forum_row['right_id']; - - $diff_up = $forum_row['left_id'] - $target['left_id']; - $diff_down = $forum_row['right_id'] + 1 - $forum_row['left_id']; - - $move_up_left = $forum_row['left_id']; - $move_up_right = $forum_row['right_id']; - } - else - { - $left_id = $forum_row['left_id']; - $right_id = $target['right_id']; - - $diff_up = $forum_row['right_id'] + 1 - $forum_row['left_id']; - $diff_down = $target['right_id'] - $forum_row['right_id']; - - $move_up_left = $forum_row['right_id'] + 1; - $move_up_right = $target['right_id']; - } - - // Now do the dirty job - $sql = 'UPDATE ' . FORUMS_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, - forum_parents = '' - WHERE - left_id BETWEEN {$left_id} AND {$right_id} - AND right_id BETWEEN {$left_id} AND {$right_id}"; - $db->sql_query($sql); - - return $target['forum_name']; - } - - /** - * Display progress bar for syncinc forums - */ - function display_progress_bar($start, $total) - { - global $template, $user; - - adm_page_header($user->lang['SYNC_IN_PROGRESS']); - - $template->set_filenames(array( - 'body' => 'progress_bar.html') - ); - - $template->assign_vars(array( - 'L_PROGRESS' => $user->lang['SYNC_IN_PROGRESS'], - 'L_PROGRESS_EXPLAIN' => ($start && $total) ? sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $start, $total) : $user->lang['SYNC_IN_PROGRESS']) - ); - - adm_page_footer(); - } - - /** - * Display copy permission page - * Not used at the moment - we will have a look at it for 3.0.7 - */ - function copy_permission_page($forum_data) - { - global $phpEx, $phpbb_admin_path, $template, $user; - - $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_data['forum_id']; - $action = append_sid($this->u_action . "&parent_id={$this->parent_id}&f={$forum_data['forum_id']}&action=copy_perm"); - - $l_acl = sprintf($user->lang['COPY_TO_ACL'], '', ''); - - $this->tpl_name = 'acp_forums_copy_perm'; - - $template->assign_vars(array( - 'U_ACL' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url), - 'L_ACL_LINK' => $l_acl, - 'L_BACK_LINK' => adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), - 'S_COPY_ACTION' => $action, - 'S_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $forum_data['forum_id'], false, false, false), - )); - } - -} diff --git a/install/update/old/includes/acp/acp_help_phpbb.php b/install/update/old/includes/acp/acp_help_phpbb.php deleted file mode 100644 index a36b36e..0000000 --- a/install/update/old/includes/acp/acp_help_phpbb.php +++ /dev/null @@ -1,143 +0,0 @@ - -* @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/install/update/old/includes/acp/acp_main.php b/install/update/old/includes/acp/acp_main.php deleted file mode 100644 index 8f169d1..0000000 --- a/install/update/old/includes/acp/acp_main.php +++ /dev/null @@ -1,707 +0,0 @@ - -* @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_main -{ - var $u_action; - - function main($id, $mode) - { - 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')) - { - $this->tpl_name = 'acp_main'; - $this->page_title = 'ACP_MAIN'; - - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user->data['user_perm_from']; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $perm_from = get_username_string('full', $user_row['user_id'], $user_row['username'], $user_row['user_colour']); - - $template->assign_vars(array( - 'S_RESTORE_PERMISSIONS' => true, - 'U_RESTORE_PERMISSIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm'), - 'PERM_FROM' => $perm_from, - 'L_PERMISSIONS_TRANSFERRED_EXPLAIN' => sprintf($user->lang['PERMISSIONS_TRANSFERRED_EXPLAIN'], $perm_from, append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm')), - )); - - return; - } - - $action = $request->variable('action', ''); - - if ($action) - { - if ($action === 'admlogout') - { - $user->unset_admin(); - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - if (!confirm_box(true)) - { - switch ($action) - { - case 'online': - $confirm = true; - $confirm_lang = 'RESET_ONLINE_CONFIRM'; - break; - case 'stats': - $confirm = true; - $confirm_lang = 'RESYNC_STATS_CONFIRM'; - break; - case 'user': - $confirm = true; - $confirm_lang = 'RESYNC_POSTCOUNTS_CONFIRM'; - break; - case 'date': - $confirm = true; - $confirm_lang = 'RESET_DATE_CONFIRM'; - break; - case 'db_track': - $confirm = true; - $confirm_lang = 'RESYNC_POST_MARKING_CONFIRM'; - break; - case 'purge_cache': - $confirm = true; - $confirm_lang = 'PURGE_CACHE_CONFIRM'; - break; - case 'purge_sessions': - $confirm = true; - $confirm_lang = 'PURGE_SESSIONS_CONFIRM'; - break; - - default: - $confirm = true; - $confirm_lang = 'CONFIRM_OPERATION'; - } - - if ($confirm) - { - confirm_box(false, $user->lang[$confirm_lang], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - ))); - } - } - else - { - switch ($action) - { - - 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); - } - - $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()) - { - trigger_error('RESET_ONLINE_SUCCESS'); - } - break; - - 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); - } - - $sql = 'SELECT COUNT(post_id) AS stat - FROM ' . POSTS_TABLE . ' - WHERE post_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $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); - $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); - $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); - $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); - $config->set('upload_dir_size', (float) $db->sql_fetchfield('stat'), false); - $db->sql_freeresult($result); - - if (!function_exists('update_last_username')) - { - include($phpbb_root_path . "includes/functions_user.$phpEx"); - } - update_last_username(); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_STATS'); - - if ($request->is_ajax()) - { - trigger_error('RESYNC_STATS_SUCCESS'); - } - break; - - 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); - } - - // Resync post counts - $start = $max_post_id = 0; - - // Find the maximum post ID, we can only stop the cycle when we've reached it - $sql = 'SELECT MAX(forum_last_post_id) as max_post_id - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - $max_post_id = (int) $db->sql_fetchfield('max_post_id'); - $db->sql_freeresult($result); - - // No maximum post id? :o - if (!$max_post_id) - { - $sql = 'SELECT MAX(post_id) as max_post_id - FROM ' . POSTS_TABLE; - $result = $db->sql_query($sql); - $max_post_id = (int) $db->sql_fetchfield('max_post_id'); - $db->sql_freeresult($result); - } - - // Still no maximum post id? Then we are finished - if (!$max_post_id) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POSTCOUNTS'); - break; - } - - $step = ($config['num_posts']) ? (max((int) ($config['num_posts'] / 5), 20000)) : 20000; - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_posts = 0'); - - while ($start < $max_post_id) - { - $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id - FROM ' . POSTS_TABLE . ' - WHERE post_id BETWEEN ' . ($start + 1) . ' AND ' . ($start + $step) . ' - AND post_postcount = 1 AND post_visibility = ' . ITEM_APPROVED . ' - GROUP BY poster_id'; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - do - { - $sql = 'UPDATE ' . USERS_TABLE . " SET user_posts = user_posts + {$row['num_posts']} WHERE user_id = {$row['poster_id']}"; - $db->sql_query($sql); - } - while ($row = $db->sql_fetchrow($result)); - } - $db->sql_freeresult($result); - - $start += $step; - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POSTCOUNTS'); - - if ($request->is_ajax()) - { - trigger_error('RESYNC_POSTCOUNTS_SUCCESS'); - } - break; - - 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); - } - - $config->set('board_startdate', time() - 1); - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESET_DATE'); - - if ($request->is_ajax()) - { - trigger_error('RESET_DATE_SUCCESS'); - } - break; - - case 'db_track': - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); - break; - - default: - $db->sql_query('TRUNCATE TABLE ' . TOPICS_POSTED_TABLE); - break; - } - - // This can get really nasty... therefore we only do the last six months - $get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60); - - // Select forum ids, do not include categories - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type <> ' . FORUM_CAT; - $result = $db->sql_query($sql); - - $forum_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $db->sql_freeresult($result); - - // Any global announcements? ;) - $forum_ids[] = 0; - - // Now go through the forums and get us some topics... - foreach ($forum_ids as $forum_id) - { - $sql = 'SELECT p.poster_id, p.topic_id - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t - WHERE t.forum_id = ' . $forum_id . ' - AND t.topic_moved_id = 0 - AND t.topic_last_post_time > ' . $get_from_time . ' - AND t.topic_id = p.topic_id - AND p.poster_id <> ' . ANONYMOUS . ' - GROUP BY p.poster_id, p.topic_id'; - $result = $db->sql_query($sql); - - $posted = array(); - while ($row = $db->sql_fetchrow($result)) - { - $posted[$row['poster_id']][] = $row['topic_id']; - } - $db->sql_freeresult($result); - - $sql_ary = array(); - foreach ($posted as $user_id => $topic_row) - { - foreach ($topic_row as $topic_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user_id, - 'topic_id' => (int) $topic_id, - 'topic_posted' => 1, - ); - } - } - unset($posted); - - if (count($sql_ary)) - { - $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); - } - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POST_MARKING'); - - if ($request->is_ajax()) - { - trigger_error('RESYNC_POST_MARKING_SUCCESS'); - } - break; - - case 'purge_cache': - $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); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PURGE_CACHE'); - - if ($request->is_ajax()) - { - trigger_error('PURGE_CACHE_SUCCESS'); - } - break; - - 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); - } - - $tables = array(CONFIRM_TABLE, SESSIONS_TABLE); - - foreach ($tables as $table) - { - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $db->sql_query("DELETE FROM $table"); - break; - - default: - $db->sql_query("TRUNCATE TABLE $table"); - break; - } - } - - // let's restore the admin session - $reinsert_ary = array( - 'session_id' => (string) $user->session_id, - 'session_page' => (string) substr($user->page['page'], 0, 199), - 'session_forum_id' => $user->page['forum'], - 'session_user_id' => (int) $user->data['user_id'], - 'session_start' => (int) $user->data['session_start'], - 'session_last_visit' => (int) $user->data['session_last_visit'], - 'session_time' => (int) $user->time_now, - 'session_browser' => (string) trim(substr($user->browser, 0, 149)), - 'session_forwarded_for' => (string) $user->forwarded_for, - 'session_ip' => (string) $user->ip, - 'session_autologin' => (int) $user->data['session_autologin'], - 'session_admin' => 1, - 'session_viewonline' => (int) $user->data['session_viewonline'], - ); - - $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $reinsert_ary); - $db->sql_query($sql); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PURGE_SESSIONS'); - - if ($request->is_ajax()) - { - trigger_error('PURGE_SESSIONS_SUCCESS'); - } - break; - } - } - } - - // Version check - $user->add_lang('install'); - - if ($auth->acl_get('a_server') && version_compare(PHP_VERSION, '5.4.0', '<')) - { - $template->assign_vars(array( - 'S_PHP_VERSION_OLD' => true, - 'L_PHP_VERSION_OLD' => sprintf($user->lang['PHP_VERSION_OLD'], PHP_VERSION, '5.4.0', '', ''), - )); - } - - if ($auth->acl_get('a_board')) - { - $version_helper = $phpbb_container->get('version_helper'); - try - { - $recheck = $request->variable('versioncheck_force', false); - $updates_available = $version_helper->get_update_on_branch($recheck); - $upgrades_available = $version_helper->get_suggested_updates(); - if (!empty($upgrades_available)) - { - $upgrades_available = array_pop($upgrades_available); - } - - $template->assign_vars(array( - 'S_VERSION_UP_TO_DATE' => empty($updates_available), - 'S_VERSION_UPGRADEABLE' => !empty($upgrades_available), - 'UPGRADE_INSTRUCTIONS' => !empty($upgrades_available) ? $user->lang('UPGRADE_INSTRUCTIONS', $upgrades_available['current'], $upgrades_available['announcement']) : false, - )); - } - 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() !== 'VERSIONCHECK_FAIL') ? $message : '', - )); - } - } - else - { - // We set this template var to true, to not display an outdated version notice. - $template->assign_var('S_VERSION_UP_TO_DATE', true); - } - - // Incomplete update? - if (phpbb_version_compare($config['version'], PHPBB_VERSION, '<')) - { - $template->assign_var('S_UPDATE_INCOMPLETE', true); - } - - /** - * Notice admin - * - * @event core.acp_main_notice - * @since 3.1.0-RC3 - */ - $phpbb_dispatcher->dispatch('core.acp_main_notice'); - - // Get forum statistics - $total_posts = $config['num_posts']; - $total_topics = $config['num_topics']; - $total_users = $config['num_users']; - $total_files = $config['num_files']; - - $start_date = $user->format_date($config['board_startdate']); - - $boarddays = (time() - $config['board_startdate']) / 86400; - - $posts_per_day = sprintf('%.2f', $total_posts / $boarddays); - $topics_per_day = sprintf('%.2f', $total_topics / $boarddays); - $users_per_day = sprintf('%.2f', $total_users / $boarddays); - $files_per_day = sprintf('%.2f', $total_files / $boarddays); - - $upload_dir_size = get_formatted_filesize($config['upload_dir_size']); - - $avatar_dir_size = 0; - - if ($avatar_dir = @opendir($phpbb_root_path . $config['avatar_path'])) - { - while (($file = readdir($avatar_dir)) !== false) - { - if ($file[0] != '.' && $file != 'CVS' && strpos($file, 'index.') === false) - { - $avatar_dir_size += filesize($phpbb_root_path . $config['avatar_path'] . '/' . $file); - } - } - closedir($avatar_dir); - - $avatar_dir_size = get_formatted_filesize($avatar_dir_size); - } - else - { - // Couldn't open Avatar dir. - $avatar_dir_size = $user->lang['NOT_AVAILABLE']; - } - - if ($posts_per_day > $total_posts) - { - $posts_per_day = $total_posts; - } - - if ($topics_per_day > $total_topics) - { - $topics_per_day = $total_topics; - } - - if ($users_per_day > $total_users) - { - $users_per_day = $total_users; - } - - if ($files_per_day > $total_files) - { - $files_per_day = $total_files; - } - - if ($config['allow_attachments'] || $config['allow_pm_attach']) - { - $sql = 'SELECT COUNT(attach_id) AS total_orphan - FROM ' . ATTACHMENTS_TABLE . ' - WHERE is_orphan = 1 - AND filetime < ' . (time() - 3*60*60); - $result = $db->sql_query($sql); - $total_orphan = (int) $db->sql_fetchfield('total_orphan'); - $db->sql_freeresult($result); - } - else - { - $total_orphan = false; - } - - $dbsize = get_database_size(); - - $template->assign_vars(array( - 'TOTAL_POSTS' => $total_posts, - 'POSTS_PER_DAY' => $posts_per_day, - 'TOTAL_TOPICS' => $total_topics, - 'TOPICS_PER_DAY' => $topics_per_day, - 'TOTAL_USERS' => $total_users, - 'USERS_PER_DAY' => $users_per_day, - 'TOTAL_FILES' => $total_files, - 'FILES_PER_DAY' => $files_per_day, - 'START_DATE' => $start_date, - 'AVATAR_DIR_SIZE' => $avatar_dir_size, - 'DBSIZE' => $dbsize, - 'UPLOAD_DIR_SIZE' => $upload_dir_size, - 'TOTAL_ORPHAN' => $total_orphan, - '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, - 'U_ADMIN_LOG' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=logs&mode=admin'), - 'U_INACTIVE_USERS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=inactive&mode=list'), - 'U_VERSIONCHECK' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=update&mode=version_check'), - 'U_VERSIONCHECK_FORCE' => append_sid("{$phpbb_admin_path}index.$phpEx", '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, - 'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, - ) - ); - - $log_data = array(); - $log_count = false; - - if ($auth->acl_get('a_viewlogs')) - { - view_log('admin', $log_data, $log_count, 5); - - foreach ($log_data as $row) - { - $template->assign_block_vars('log', array( - 'USERNAME' => $row['username_full'], - 'IP' => $row['ip'], - 'DATE' => $user->format_date($row['time']), - 'ACTION' => $row['action']) - ); - } - } - - if ($auth->acl_get('a_user')) - { - $user->add_lang('memberlist'); - - $inactive = array(); - $inactive_count = 0; - - view_inactive_users($inactive, $inactive_count, 10); - - foreach ($inactive as $row) - { - $template->assign_block_vars('inactive', array( - 'INACTIVE_DATE' => $user->format_date($row['user_inactive_time']), - 'REMINDED_DATE' => $user->format_date($row['user_reminded_time']), - 'JOINED' => $user->format_date($row['user_regdate']), - 'LAST_VISIT' => (!$row['user_lastvisit']) ? ' - ' : $user->format_date($row['user_lastvisit']), - - 'REASON' => $row['inactive_reason'], - 'USER_ID' => $row['user_id'], - 'POSTS' => ($row['user_posts']) ? $row['user_posts'] : 0, - 'REMINDED' => $row['user_reminded'], - - 'REMINDED_EXPLAIN' => $user->lang('USER_LAST_REMINDED', (int) $row['user_reminded'], $user->format_date($row['user_reminded_time'])), - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview')), - 'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), - 'USER_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), - - 'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&mode=overview&u={$row['user_id']}"), - 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id={$row['user_id']}&sr=posts") : '', - )); - } - - $option_ary = array('activate' => 'ACTIVATE', 'delete' => 'DELETE'); - if ($config['email_enable']) - { - $option_ary += array('remind' => 'REMIND'); - } - - $template->assign_vars(array( - 'S_INACTIVE_USERS' => true, - 'S_INACTIVE_OPTIONS' => build_select($option_ary)) - ); - } - - // Warn if install is still present - if (file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) - { - $template->assign_var('S_REMOVE_INSTALL', true); - } - - // Warn if no search index is created - if ($config['num_posts'] && class_exists($config['search_type'])) - { - $error = false; - $search_type = $config['search_type']; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if (!$search->index_created()) - { - $template->assign_vars(array( - 'S_SEARCH_INDEX_MISSING' => true, - 'L_NO_SEARCH_INDEX' => $user->lang('NO_SEARCH_INDEX', $search->get_name(), '', ''), - )); - } - } - - 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)); - } - - if (extension_loaded('mbstring')) - { - $template->assign_vars(array( - 'S_MBSTRING_LOADED' => true, - 'S_MBSTRING_FUNC_OVERLOAD_FAIL' => (intval(@ini_get('mbstring.func_overload')) & (MB_OVERLOAD_MAIL | MB_OVERLOAD_STRING)), - 'S_MBSTRING_ENCODING_TRANSLATION_FAIL' => (@ini_get('mbstring.encoding_translation') != 0), - 'S_MBSTRING_HTTP_INPUT_FAIL' => !in_array(@ini_get('mbstring.http_input'), array('pass', '')), - 'S_MBSTRING_HTTP_OUTPUT_FAIL' => !in_array(@ini_get('mbstring.http_output'), array('pass', '')), - )); - } - - // Fill dbms version if not yet filled - if (empty($config['dbms_version'])) - { - $config->set('dbms_version', $db->sql_server_info(true)); - } - - $this->tpl_name = 'acp_main'; - $this->page_title = 'ACP_MAIN'; - } -} diff --git a/install/update/old/includes/acp/acp_permissions.php b/install/update/old/includes/acp/acp_permissions.php deleted file mode 100644 index e683b19..0000000 --- a/install/update/old/includes/acp/acp_permissions.php +++ /dev/null @@ -1,1346 +0,0 @@ - -* @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_permissions -{ - var $u_action; - var $permission_dropdown; - - /** - * @var $phpbb_permissions \phpbb\permissions - */ - protected $permissions; - - function main($id, $mode) - { - global $db, $user, $auth, $template, $phpbb_container, $request; - global $config, $phpbb_root_path, $phpEx; - - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - if (!class_exists('auth_admin')) - { - include($phpbb_root_path . 'includes/acp/auth.' . $phpEx); - } - - $this->permissions = $phpbb_container->get('acl.permissions'); - - $auth_admin = new auth_admin(); - - $user->add_lang('acp/permissions'); - add_permission_language(); - - $this->tpl_name = 'acp_permissions'; - - // Trace has other vars - if ($mode == 'trace') - { - $user_id = $request->variable('u', 0); - $forum_id = $request->variable('f', 0); - $permission = $request->variable('auth', ''); - - $this->tpl_name = 'permission_trace'; - - if ($user_id && isset($auth_admin->acl_options['id'][$permission]) && $auth->acl_get('a_viewauth')) - { - $this->page_title = sprintf($user->lang['TRACE_PERMISSION'], $this->permissions->get_permission_lang($permission)); - $this->permission_trace($user_id, $forum_id, $permission); - return; - } - trigger_error('NO_MODE', E_USER_ERROR); - } - - // Copy forum permissions - if ($mode == 'setting_forum_copy') - { - $this->tpl_name = 'permission_forum_copy'; - - if ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')) - { - $this->page_title = 'ACP_FORUM_PERMISSIONS_COPY'; - $this->copy_forum_permissions(); - return; - } - - trigger_error('NO_MODE', E_USER_ERROR); - } - - // Set some vars - $action = $request->variable('action', array('' => 0)); - $action = key($action); - $action = (isset($_POST['psubmit'])) ? 'apply_permissions' : $action; - - $all_forums = $request->variable('all_forums', 0); - $subforum_id = $request->variable('subforum_id', 0); - $forum_id = $request->variable('forum_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->variable('group_id', array(0)); - $select_all_groups = $request->variable('select_all_groups', 0); - - $form_name = 'acp_permissions'; - add_form_key($form_name); - - // If select all groups is set, we pre-build the group id array (this option is used for other screens to link to the permission settings screen) - if ($select_all_groups) - { - // Add default groups to selection - $sql_and = (!$config['coppa_enable']) ? " AND group_name <> 'REGISTERED_COPPA'" : ''; - - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . ' - WHERE group_type = ' . GROUP_SPECIAL . " - $sql_and"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $group_id[] = $row['group_id']; - } - $db->sql_freeresult($result); - } - - // Map usernames to ids and vice versa - if ($usernames) - { - $username = explode("\n", $usernames); - } - unset($usernames); - - if (count($username) && !count($user_id)) - { - user_get_id_name($user_id, $username); - - if (!count($user_id)) - { - trigger_error($user->lang['SELECTED_USER_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - unset($username); - - // Build forum ids (of all forums are checked or subforum listing used) - if ($all_forums) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id'; - $result = $db->sql_query($sql); - - $forum_id = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_id[] = (int) $row['forum_id']; - } - $db->sql_freeresult($result); - } - else if ($subforum_id) - { - $forum_id = array(); - foreach (get_forum_branch($subforum_id, 'children') as $row) - { - $forum_id[] = (int) $row['forum_id']; - } - } - - // Define some common variables for every mode - $permission_scope = (strpos($mode, '_global') !== false) ? 'global' : 'local'; - - // Showing introductionary page? - if ($mode == 'intro') - { - $this->page_title = 'ACP_PERMISSIONS'; - - $template->assign_vars(array( - 'S_INTRO' => true) - ); - - return; - } - - switch ($mode) - { - case 'setting_user_global': - case 'setting_group_global': - $this->permission_dropdown = array('u_', 'm_', 'a_'); - $permission_victim = ($mode == 'setting_user_global') ? array('user') : array('group'); - $this->page_title = ($mode == 'setting_user_global') ? 'ACP_USERS_PERMISSIONS' : 'ACP_GROUPS_PERMISSIONS'; - break; - - case 'setting_user_local': - case 'setting_group_local': - $this->permission_dropdown = array('f_', 'm_'); - $permission_victim = ($mode == 'setting_user_local') ? array('user', 'forums') : array('group', 'forums'); - $this->page_title = ($mode == 'setting_user_local') ? 'ACP_USERS_FORUM_PERMISSIONS' : 'ACP_GROUPS_FORUM_PERMISSIONS'; - break; - - case 'setting_admin_global': - case 'setting_mod_global': - $this->permission_dropdown = (strpos($mode, '_admin_') !== false) ? array('a_') : array('m_'); - $permission_victim = array('usergroup'); - $this->page_title = ($mode == 'setting_admin_global') ? 'ACP_ADMINISTRATORS' : 'ACP_GLOBAL_MODERATORS'; - break; - - case 'setting_mod_local': - case 'setting_forum_local': - $this->permission_dropdown = ($mode == 'setting_mod_local') ? array('m_') : array('f_'); - $permission_victim = array('forums', 'usergroup'); - $this->page_title = ($mode == 'setting_mod_local') ? 'ACP_FORUM_MODERATORS' : 'ACP_FORUM_PERMISSIONS'; - break; - - case 'view_admin_global': - case 'view_user_global': - case 'view_mod_global': - $this->permission_dropdown = ($mode == 'view_admin_global') ? array('a_') : (($mode == 'view_user_global') ? array('u_') : array('m_')); - $permission_victim = array('usergroup_view'); - $this->page_title = ($mode == 'view_admin_global') ? 'ACP_VIEW_ADMIN_PERMISSIONS' : (($mode == 'view_user_global') ? 'ACP_VIEW_USER_PERMISSIONS' : 'ACP_VIEW_GLOBAL_MOD_PERMISSIONS'); - break; - - case 'view_mod_local': - case 'view_forum_local': - $this->permission_dropdown = ($mode == 'view_mod_local') ? array('m_') : array('f_'); - $permission_victim = array('forums', 'usergroup_view'); - $this->page_title = ($mode == 'view_mod_local') ? 'ACP_VIEW_FORUM_MOD_PERMISSIONS' : 'ACP_VIEW_FORUM_PERMISSIONS'; - break; - - default: - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - - $template->assign_vars(array( - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN']) - ); - - // Get permission type - $permission_type = $request->variable('type', $this->permission_dropdown[0]); - - if (!in_array($permission_type, $this->permission_dropdown)) - { - trigger_error($user->lang['WRONG_PERMISSION_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Handle actions - if (strpos($mode, 'setting_') === 0 && $action) - { - switch ($action) - { - case 'delete': - if (confirm_box(true)) - { - // All users/groups selected? - $all_users = (isset($_POST['all_users'])) ? true : false; - $all_groups = (isset($_POST['all_groups'])) ? true : false; - - if ($all_users || $all_groups) - { - $items = $this->retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type); - - if ($all_users && count($items['user_ids'])) - { - $user_id = $items['user_ids']; - } - else if ($all_groups && count($items['group_ids'])) - { - $group_id = $items['group_ids']; - } - } - - if (count($user_id) || count($group_id)) - { - $this->remove_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id, $forum_id); - } - else - { - trigger_error($user->lang['NO_USER_GROUP_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - else - { - if (isset($_POST['cancel'])) - { - $u_redirect = $this->u_action . '&type=' . $permission_type; - foreach ($forum_id as $fid) - { - $u_redirect .= '&forum_id[]=' . $fid; - } - redirect($u_redirect); - } - - $s_hidden_fields = array( - 'i' => $id, - 'mode' => $mode, - 'action' => array($action => 1), - 'user_id' => $user_id, - 'group_id' => $group_id, - 'forum_id' => $forum_id, - 'type' => $permission_type, - ); - if (isset($_POST['all_users'])) - { - $s_hidden_fields['all_users'] = 1; - } - if (isset($_POST['all_groups'])) - { - $s_hidden_fields['all_groups'] = 1; - } - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); - } - break; - - 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)) - { - trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING); - } - - $this->set_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id); - break; - - 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)) - { - trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING); - } - - $this->set_all_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id); - break; - } - } - - // Go through the screens/options needed and present them in correct order - foreach ($permission_victim as $victim) - { - switch ($victim) - { - case 'forum_dropdown': - - if (count($forum_id)) - { - $this->check_existence('forum', $forum_id); - continue 2; - } - - $template->assign_vars(array( - 'S_SELECT_FORUM' => true, - 'S_FORUM_OPTIONS' => make_forum_select(false, false, true, false, false)) - ); - - break; - - case 'forums': - - if (count($forum_id)) - { - $this->check_existence('forum', $forum_id); - continue 2; - } - - $forum_list = make_forum_select(false, false, true, false, false, false, true); - - // Build forum options - $s_forum_options = ''; - foreach ($forum_list as $f_id => $f_row) - { - $s_forum_options .= ''; - } - - // Build subforum options - $s_subforum_options = $this->build_subforum_options($forum_list); - - $template->assign_vars(array( - 'S_SELECT_FORUM' => true, - 'S_FORUM_OPTIONS' => $s_forum_options, - 'S_SUBFORUM_OPTIONS' => $s_subforum_options, - 'S_FORUM_ALL' => true, - 'S_FORUM_MULTIPLE' => true) - ); - - break; - - case 'user': - - if (count($user_id)) - { - $this->check_existence('user', $user_id); - continue 2; - } - - $template->assign_vars(array( - 'S_SELECT_USER' => true, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_victim&field=username&select_single=true'), - )); - - break; - - case 'group': - - if (count($group_id)) - { - $this->check_existence('group', $group_id); - continue 2; - } - - $template->assign_vars(array( - 'S_SELECT_GROUP' => true, - 'S_GROUP_OPTIONS' => group_select_options(false, false, false), // Show all groups - )); - - break; - - case 'usergroup': - case 'usergroup_view': - - $all_users = (isset($_POST['all_users'])) ? true : false; - $all_groups = (isset($_POST['all_groups'])) ? true : false; - - if ((count($user_id) && !$all_users) || (count($group_id) && !$all_groups)) - { - if (count($user_id)) - { - $this->check_existence('user', $user_id); - } - - if (count($group_id)) - { - $this->check_existence('group', $group_id); - } - - continue 2; - } - - // 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 && count($items['user_ids'])) - { - $user_id = $items['user_ids']; - continue 2; - } - - if ($all_groups && count($items['group_ids'])) - { - $group_id = $items['group_ids']; - continue 2; - } - - $template->assign_vars(array( - 'S_SELECT_USERGROUP' => ($victim == 'usergroup') ? true : false, - 'S_SELECT_USERGROUP_VIEW' => ($victim == 'usergroup_view') ? true : false, - 'S_DEFINED_USER_OPTIONS' => $items['user_ids_options'], - 'S_DEFINED_GROUP_OPTIONS' => $items['group_ids_options'], - 'S_ADD_GROUP_OPTIONS' => group_select_options(false, $items['group_ids'], false), // Show all groups - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=add_user&field=username&select_single=true'), - )); - - break; - } - - // The S_ALLOW_SELECT parameter below is a measure to lower memory usage. - // If there are more than 5 forums selected the admin is not able to select all users/groups too. - // We need to see if the number of forums can be increased or need to be decreased. - - // Setting permissions screen - $s_hidden_fields = build_hidden_fields(array( - 'user_id' => $user_id, - 'group_id' => $group_id, - 'forum_id' => $forum_id, - 'type' => $permission_type, - )); - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - 'ANONYMOUS_USER_ID' => ANONYMOUS, - - 'S_SELECT_VICTIM' => 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 (count($forum_id)) - { - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id) . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql); - - $forum_names = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_names[] = $row['forum_name']; - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_FORUM_NAMES' => (count($forum_names)) ? true : false, - 'FORUM_NAMES' => implode($user->lang['COMMA_SEPARATOR'], $forum_names)) - ); - } - - return; - } - - // Setting permissions screen - $s_hidden_fields = build_hidden_fields(array( - 'user_id' => $user_id, - 'group_id' => $group_id, - 'forum_id' => $forum_id, - 'type' => $permission_type, - )); - - // Do not allow forum_ids being set and no other setting defined (will bog down the server too much) - 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' => (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, - 'S_HIDDEN_FIELDS' => $s_hidden_fields) - ); - - if (strpos($mode, 'setting_') === 0) - { - $template->assign_vars(array( - 'S_SETTING_PERMISSIONS' => true) - ); - - $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 - { - $template->assign_vars(array( - 'S_VIEWING_PERMISSIONS' => true) - ); - - $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)); - } - } - - /** - * Build +subforum options - */ - function build_subforum_options($forum_list) - { - global $user; - - $s_options = ''; - - $forum_list = array_merge($forum_list); - - foreach ($forum_list as $key => $row) - { - if ($row['disabled']) - { - continue; - } - - $s_options .= ''; - } - - return $s_options; - } - - /** - * Build dropdown field for changing permission types - */ - function build_permission_dropdown($options, $default_option, $permission_scope) - { - global $auth; - - $s_dropdown_options = ''; - foreach ($options as $setting) - { - if (!$auth->acl_get('a_' . str_replace('_', '', $setting) . 'auth')) - { - continue; - } - - $selected = ($setting == $default_option) ? ' selected="selected"' : ''; - $l_setting = $this->permissions->get_type_lang($setting, $permission_scope); - $s_dropdown_options .= ''; - } - - return $s_dropdown_options; - } - - /** - * Check if selected items exist. Remove not found ids and if empty return error. - */ - function check_existence($mode, &$ids) - { - global $db, $user; - - switch ($mode) - { - case 'user': - $table = USERS_TABLE; - $sql_id = 'user_id'; - break; - - case 'group': - $table = GROUPS_TABLE; - $sql_id = 'group_id'; - break; - - case 'forum': - $table = FORUMS_TABLE; - $sql_id = 'forum_id'; - break; - } - - if (count($ids)) - { - $sql = "SELECT $sql_id - FROM $table - WHERE " . $db->sql_in_set($sql_id, $ids); - $result = $db->sql_query($sql); - - $ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $ids[] = (int) $row[$sql_id]; - } - $db->sql_freeresult($result); - } - - if (!count($ids)) - { - trigger_error($user->lang['SELECTED_' . strtoupper($mode) . '_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - /** - * Apply permissions - */ - function set_permissions($mode, $permission_type, $auth_admin, &$user_id, &$group_id) - { - global $db, $cache, $user, $auth; - global $request; - - $psubmit = $request->variable('psubmit', array(0 => array(0 => 0))); - - // User or group to be set? - $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); - } - - // We loop through the auth settings defined in our submit - list($ug_id, ) = each($psubmit); - list($forum_id, ) = each($psubmit[$ug_id]); - - $settings = $request->variable('setting', array(0 => array(0 => array('' => 0))), false, \phpbb\request\request_interface::POST); - if (empty($settings) || empty($settings[$ug_id]) || empty($settings[$ug_id][$forum_id])) - { - trigger_error('WRONG_PERMISSION_SETTING_FORMAT', E_USER_WARNING); - } - - $auth_settings = $settings[$ug_id][$forum_id]; - - // Do we have a role we want to set? - $roles = $request->variable('role', array(0 => array(0 => 0)), false, \phpbb\request\request_interface::POST); - $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->variable('inherit', array(0 => array(0))); - - $ug_id = array($ug_id); - $forum_id = array($forum_id); - - if (count($inherit)) - { - foreach ($inherit as $_ug_id => $forum_id_ary) - { - // Inherit users/groups? - if (!in_array($_ug_id, $ug_id)) - { - $ug_id[] = $_ug_id; - } - - // Inherit forums? - $forum_id = array_merge($forum_id, array_keys($forum_id_ary)); - } - } - - $forum_id = array_unique($forum_id); - - // If the auth settings differ from the assigned role, then do not set a role... - if ($assigned_role) - { - if (!$this->check_assigned_role($assigned_role, $auth_settings)) - { - $assigned_role = 0; - } - } - - // Update the permission set... - $auth_admin->acl_set($ug_type, $forum_id, $ug_id, $auth_settings, $assigned_role); - - // Do we need to recache the moderator lists? - if ($permission_type == 'm_') - { - phpbb_cache_moderators($db, $cache, $auth); - } - - // Remove users who are now moderators or admins from everyones foes list - if ($permission_type == 'm_' || $permission_type == 'a_') - { - phpbb_update_foes($db, $auth, $group_id, $user_id); - } - - $this->log_action($mode, 'add', $permission_type, $ug_type, $ug_id, $forum_id); - - meta_refresh(5, $this->u_action); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); - } - - /** - * Apply all permissions - */ - 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 = (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_settings = $request->variable('setting', array(0 => array(0 => array('' => 0))), false, \phpbb\request\request_interface::POST); - $auth_roles = $request->variable('role', array(0 => array(0 => 0)), false, \phpbb\request\request_interface::POST); - $ug_ids = $forum_ids = array(); - - // We need to go through the auth settings - foreach ($auth_settings as $ug_id => $forum_auth_row) - { - $ug_id = (int) $ug_id; - $ug_ids[] = $ug_id; - - foreach ($forum_auth_row as $forum_id => $auth_options) - { - $forum_id = (int) $forum_id; - $forum_ids[] = $forum_id; - - // Check role... - $assigned_role = (isset($auth_roles[$ug_id][$forum_id])) ? (int) $auth_roles[$ug_id][$forum_id] : 0; - - // If the auth settings differ from the assigned role, then do not set a role... - if ($assigned_role) - { - if (!$this->check_assigned_role($assigned_role, $auth_options)) - { - $assigned_role = 0; - } - } - - // Update the permission set... - $auth_admin->acl_set($ug_type, $forum_id, $ug_id, $auth_options, $assigned_role, false); - } - } - - $auth_admin->acl_clear_prefetch(); - - // Do we need to recache the moderator lists? - if ($permission_type == 'm_') - { - phpbb_cache_moderators($db, $cache, $auth); - } - - // Remove users who are now moderators or admins from everyones foes list - if ($permission_type == 'm_' || $permission_type == 'a_') - { - phpbb_update_foes($db, $auth, $group_id, $user_id); - } - - $this->log_action($mode, 'add', $permission_type, $ug_type, $ug_ids, $forum_ids); - - if ($mode == 'setting_forum_local' || $mode == 'setting_mod_local') - { - meta_refresh(5, $this->u_action . '&forum_id[]=' . implode('&forum_id[]=', $forum_ids)); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action . '&forum_id[]=' . implode('&forum_id[]=', $forum_ids))); - } - else - { - meta_refresh(5, $this->u_action); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); - } - } - - /** - * Compare auth settings with auth settings from role - * returns false if they differ, true if they are equal - */ - function check_assigned_role($role_id, &$auth_settings) - { - global $db; - - $sql = 'SELECT o.auth_option, r.auth_setting - FROM ' . ACL_OPTIONS_TABLE . ' o, ' . ACL_ROLES_DATA_TABLE . ' r - WHERE o.auth_option_id = r.auth_option_id - AND r.role_id = ' . $role_id; - $result = $db->sql_query($sql); - - $test_auth_settings = array(); - while ($row = $db->sql_fetchrow($result)) - { - $test_auth_settings[$row['auth_option']] = $row['auth_setting']; - } - $db->sql_freeresult($result); - - // We need to add any ACL_NO setting from auth_settings to compare correctly - foreach ($auth_settings as $option => $setting) - { - if ($setting == ACL_NO) - { - $test_auth_settings[$option] = $setting; - } - } - - if (count(array_diff_assoc($auth_settings, $test_auth_settings))) - { - return false; - } - - return true; - } - - /** - * Remove permissions - */ - 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 = (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), (count($forum_id) ? $forum_id : false), $permission_type); - - // Do we need to recache the moderator lists? - if ($permission_type == 'm_') - { - phpbb_cache_moderators($db, $cache, $auth); - } - - $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') - { - meta_refresh(5, $this->u_action . '&forum_id[]=' . implode('&forum_id[]=', $forum_id)); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action . '&forum_id[]=' . implode('&forum_id[]=', $forum_id))); - } - else - { - meta_refresh(5, $this->u_action); - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); - } - } - - /** - * Log permission changes - */ - function log_action($mode, $action, $permission_type, $ug_type, $ug_id, $forum_id) - { - global $db, $user, $phpbb_log, $phpbb_container; - - if (!is_array($ug_id)) - { - $ug_id = array($ug_id); - } - - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - // Logging ... first grab user or groupnames ... - $sql = ($ug_type == 'group') ? 'SELECT group_name as name, group_type FROM ' . GROUPS_TABLE . ' WHERE ' : 'SELECT username as name FROM ' . USERS_TABLE . ' WHERE '; - $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)) - { - $group_name = $group_helper->get_name($row['name']); - $l_ug_list .= (($l_ug_list != '') ? ', ' : '') . ((isset($row['group_type']) && $row['group_type'] == GROUP_SPECIAL) ? '' . $group_name . '' : $group_name); - } - $db->sql_freeresult($result); - - $mode = str_replace('setting_', '', $mode); - - if ($forum_id[0] == 0) - { - $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 - { - // Grab the forum details if non-zero forum_id - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id); - $result = $db->sql_query($sql); - - $l_forum_list = ''; - while ($row = $db->sql_fetchrow($result)) - { - $l_forum_list .= (($l_forum_list != '') ? ', ' : '') . $row['forum_name']; - } - $db->sql_freeresult($result); - - $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)); - } - } - - /** - * Display a complete trace tree for the selected permission to determine where settings are set/unset - */ - function permission_trace($user_id, $forum_id, $permission) - { - global $db, $template, $user, $auth, $request, $phpbb_container; - - if ($user_id != $user->data['user_id']) - { - $userdata = $auth->obtain_user_data($user_id); - } - else - { - $userdata = $user->data; - } - - if (!$userdata) - { - 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) - { - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql, 3600); - $forum_name = $db->sql_fetchfield('forum_name'); - $db->sql_freeresult($result); - } - - $back = $request->variable('back', 0); - - $template->assign_vars(array( - 'PERMISSION' => $this->permissions->get_permission_lang($permission), - 'PERMISSION_USERNAME' => $userdata['username'], - 'FORUM_NAME' => $forum_name, - - 'S_GLOBAL_TRACE' => ($forum_id) ? false : true, - - 'U_BACK' => ($back) ? build_url(array('f', 'back')) . "&f=$back" : '') - ); - - $template->assign_block_vars('trace', array( - 'WHO' => $user->lang['DEFAULT'], - 'INFORMATION' => $user->lang['TRACE_DEFAULT'], - - 'S_SETTING_NO' => true, - 'S_TOTAL_NO' => true) - ); - - $sql = 'SELECT DISTINCT g.group_name, g.group_id, g.group_type - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug ON (ug.group_id = g.group_id) - WHERE ug.user_id = ' . $user_id . ' - AND ug.user_pending = 0 - AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) - ORDER BY g.group_type DESC, g.group_id DESC'; - $result = $db->sql_query($sql); - - $groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $groups[$row['group_id']] = array( - 'auth_setting' => ACL_NO, - 'group_name' => $group_helper->get_name($row['group_name']), - ); - } - $db->sql_freeresult($result); - - $total = ACL_NO; - $add_key = (($forum_id) ? '_LOCAL' : ''); - - if (count($groups)) - { - // Get group auth settings - $hold_ary = $auth->acl_group_raw_data(array_keys($groups), $permission, $forum_id); - - foreach ($hold_ary as $group_id => $forum_ary) - { - $groups[$group_id]['auth_setting'] = $hold_ary[$group_id][$forum_id][$permission]; - } - unset($hold_ary); - - foreach ($groups as $id => $row) - { - switch ($row['auth_setting']) - { - case ACL_NO: - $information = $user->lang['TRACE_GROUP_NO' . $add_key]; - break; - - case ACL_YES: - $information = ($total == ACL_YES) ? $user->lang['TRACE_GROUP_YES_TOTAL_YES' . $add_key] : (($total == ACL_NEVER) ? $user->lang['TRACE_GROUP_YES_TOTAL_NEVER' . $add_key] : $user->lang['TRACE_GROUP_YES_TOTAL_NO' . $add_key]); - $total = ($total == ACL_NO) ? ACL_YES : $total; - break; - - case ACL_NEVER: - $information = ($total == ACL_YES) ? $user->lang['TRACE_GROUP_NEVER_TOTAL_YES' . $add_key] : (($total == ACL_NEVER) ? $user->lang['TRACE_GROUP_NEVER_TOTAL_NEVER' . $add_key] : $user->lang['TRACE_GROUP_NEVER_TOTAL_NO' . $add_key]); - $total = ACL_NEVER; - break; - } - - $template->assign_block_vars('trace', array( - 'WHO' => $row['group_name'], - 'INFORMATION' => $information, - - 'S_SETTING_NO' => ($row['auth_setting'] == ACL_NO) ? true : false, - 'S_SETTING_YES' => ($row['auth_setting'] == ACL_YES) ? true : false, - 'S_SETTING_NEVER' => ($row['auth_setting'] == ACL_NEVER) ? true : false, - 'S_TOTAL_NO' => ($total == ACL_NO) ? true : false, - 'S_TOTAL_YES' => ($total == ACL_YES) ? true : false, - 'S_TOTAL_NEVER' => ($total == ACL_NEVER) ? true : false) - ); - } - } - - // Get user specific permission... globally or for this forum - $hold_ary = $auth->acl_user_raw_data($user_id, $permission, $forum_id); - $auth_setting = (!count($hold_ary)) ? ACL_NO : $hold_ary[$user_id][$forum_id][$permission]; - - switch ($auth_setting) - { - case ACL_NO: - $information = ($total == ACL_NO) ? $user->lang['TRACE_USER_NO_TOTAL_NO' . $add_key] : $user->lang['TRACE_USER_KEPT' . $add_key]; - $total = ($total == ACL_NO) ? ACL_NEVER : $total; - break; - - case ACL_YES: - $information = ($total == ACL_YES) ? $user->lang['TRACE_USER_YES_TOTAL_YES' . $add_key] : (($total == ACL_NEVER) ? $user->lang['TRACE_USER_YES_TOTAL_NEVER' . $add_key] : $user->lang['TRACE_USER_YES_TOTAL_NO' . $add_key]); - $total = ($total == ACL_NO) ? ACL_YES : $total; - break; - - case ACL_NEVER: - $information = ($total == ACL_YES) ? $user->lang['TRACE_USER_NEVER_TOTAL_YES' . $add_key] : (($total == ACL_NEVER) ? $user->lang['TRACE_USER_NEVER_TOTAL_NEVER' . $add_key] : $user->lang['TRACE_USER_NEVER_TOTAL_NO' . $add_key]); - $total = ACL_NEVER; - break; - } - - $template->assign_block_vars('trace', array( - 'WHO' => $userdata['username'], - 'INFORMATION' => $information, - - 'S_SETTING_NO' => ($auth_setting == ACL_NO) ? true : false, - 'S_SETTING_YES' => ($auth_setting == ACL_YES) ? true : false, - 'S_SETTING_NEVER' => ($auth_setting == ACL_NEVER) ? true : false, - 'S_TOTAL_NO' => false, - 'S_TOTAL_YES' => ($total == ACL_YES) ? true : false, - 'S_TOTAL_NEVER' => ($total == ACL_NEVER) ? true : false) - ); - - if ($forum_id != 0 && isset($auth->acl_options['global'][$permission])) - { - if ($user_id != $user->data['user_id']) - { - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($userdata); - $auth_setting = $auth2->acl_get($permission); - } - else - { - $auth_setting = $auth->acl_get($permission); - } - - if ($auth_setting) - { - $information = ($total == ACL_YES) ? $user->lang['TRACE_USER_GLOBAL_YES_TOTAL_YES'] : $user->lang['TRACE_USER_GLOBAL_YES_TOTAL_NEVER']; - $total = ACL_YES; - } - else - { - $information = $user->lang['TRACE_USER_GLOBAL_NEVER_TOTAL_KEPT']; - } - - // If there is no auth information we do not need to worry the user by showing non-relevant data. - if ($auth_setting) - { - $template->assign_block_vars('trace', array( - 'WHO' => sprintf($user->lang['TRACE_GLOBAL_SETTING'], $userdata['username']), - 'INFORMATION' => sprintf($information, '", ''), - - 'S_SETTING_NO' => false, - 'S_SETTING_YES' => $auth_setting, - 'S_SETTING_NEVER' => !$auth_setting, - 'S_TOTAL_NO' => false, - 'S_TOTAL_YES' => ($total == ACL_YES) ? true : false, - 'S_TOTAL_NEVER' => ($total == ACL_NEVER) ? true : false) - ); - } - } - - // Take founder status into account, overwriting the default values - if ($userdata['user_type'] == USER_FOUNDER && strpos($permission, 'a_') === 0) - { - $template->assign_block_vars('trace', array( - 'WHO' => $userdata['username'], - 'INFORMATION' => $user->lang['TRACE_USER_FOUNDER'], - - 'S_SETTING_NO' => ($auth_setting == ACL_NO) ? true : false, - 'S_SETTING_YES' => ($auth_setting == ACL_YES) ? true : false, - 'S_SETTING_NEVER' => ($auth_setting == ACL_NEVER) ? true : false, - 'S_TOTAL_NO' => false, - 'S_TOTAL_YES' => true, - 'S_TOTAL_NEVER' => false) - ); - - $total = ACL_YES; - } - - // Total value... - $template->assign_vars(array( - 'S_RESULT_NO' => ($total == ACL_NO) ? true : false, - 'S_RESULT_YES' => ($total == ACL_YES) ? true : false, - 'S_RESULT_NEVER' => ($total == ACL_NEVER) ? true : false, - )); - } - - /** - * Handles copying permissions from one forum to others - */ - function copy_forum_permissions() - { - global $db, $auth, $cache, $template, $user, $request; - - $user->add_lang('acp/forums'); - - $submit = isset($_POST['submit']) ? true : false; - - if ($submit) - { - $src = $request->variable('src_forum_id', 0); - $dest = $request->variable('dest_forum_ids', array(0)); - - if (confirm_box(true)) - { - if (copy_forum_permissions($src, $dest)) - { - phpbb_cache_moderators($db, $cache, $auth); - - $auth->acl_clear_prefetch(); - $cache->destroy('sql', FORUMS_TABLE); - - trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); - } - else - { - trigger_error($user->lang['SELECTED_FORUM_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - else - { - $s_hidden_fields = array( - 'submit' => $submit, - 'src_forum_id' => $src, - 'dest_forum_ids' => $dest, - ); - - $s_hidden_fields = build_hidden_fields($s_hidden_fields); - - confirm_box(false, $user->lang['COPY_PERMISSIONS_CONFIRM'], $s_hidden_fields); - } - } - - $template->assign_vars(array( - 'S_FORUM_OPTIONS' => make_forum_select(false, false, false, false, false), - )); - } - - /** - * Get already assigned users/groups - */ - function retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type) - { - 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' : ((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(); - - $sql = 'SELECT auth_option_id - FROM ' . ACL_OPTIONS_TABLE . ' - WHERE auth_option ' . $db->sql_like_expression($permission_type . $db->get_any_char()); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $option_ids[] = (int) $row['auth_option_id']; - } - $db->sql_freeresult($result); - - if (count($option_ids)) - { - $sql = 'SELECT DISTINCT role_id - FROM ' . ACL_ROLES_DATA_TABLE . ' - WHERE ' . $db->sql_in_set('auth_option_id', $option_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $role_ids[] = (int) $row['role_id']; - } - $db->sql_freeresult($result); - } - - 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 (count($role_ids)) - { - $sql_where = 'AND ' . $db->sql_in_set('a.auth_role_id', $role_ids); - } - else if (count($option_ids)) - { - $sql_where = 'AND ' . $db->sql_in_set('a.auth_option_id', $option_ids); - } - - // Not ideal, due to the filesort, non-use of indexes, etc. - $sql = 'SELECT DISTINCT u.user_id, u.username, u.username_clean, u.user_regdate - FROM ' . USERS_TABLE . ' u, ' . ACL_USERS_TABLE . " a - WHERE u.user_id = a.user_id - $sql_forum_id - $sql_where - ORDER BY u.username_clean, u.user_regdate ASC"; - $result = $db->sql_query($sql); - - $s_defined_user_options = ''; - $defined_user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $s_defined_user_options .= ''; - $defined_user_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT DISTINCT g.group_type, g.group_name, g.group_id - FROM ' . GROUPS_TABLE . ' g, ' . ACL_GROUPS_TABLE . " a - WHERE g.group_id = a.group_id - $sql_forum_id - $sql_where - ORDER BY g.group_type DESC, g.group_name ASC"; - $result = $db->sql_query($sql); - - $s_defined_group_options = ''; - $defined_group_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $s_defined_group_options .= '' . $group_helper->get_name($row['group_name']) . ''; - $defined_group_ids[] = $row['group_id']; - } - $db->sql_freeresult($result); - - return array( - 'group_ids' => $defined_group_ids, - 'group_ids_options' => $s_defined_group_options, - 'user_ids' => $defined_user_ids, - 'user_ids_options' => $s_defined_user_options - ); - } -} diff --git a/install/update/old/includes/acp/acp_prune.php b/install/update/old/includes/acp/acp_prune.php deleted file mode 100644 index 3eee4f7..0000000 --- a/install/update/old/includes/acp/acp_prune.php +++ /dev/null @@ -1,587 +0,0 @@ - -* @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_prune -{ - var $u_action; - - function main($id, $mode) - { - global $user, $phpEx, $phpbb_root_path; - - $user->add_lang('acp/prune'); - - if (!function_exists('user_active_flip')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - switch ($mode) - { - case 'forums': - $this->tpl_name = 'acp_prune_forums'; - $this->page_title = 'ACP_PRUNE_FORUMS'; - $this->prune_forums($id, $mode); - break; - - case 'users': - $this->tpl_name = 'acp_prune_users'; - $this->page_title = 'ACP_PRUNE_USERS'; - $this->prune_users($id, $mode); - break; - } - } - - /** - * Prune forums - */ - function prune_forums($id, $mode) - { - global $db, $user, $auth, $template, $phpbb_log, $request, $phpbb_dispatcher; - - $all_forums = $request->variable('all_forums', 0); - $forum_id = $request->variable('f', array(0)); - $submit = (isset($_POST['submit'])) ? true : false; - - if ($all_forums) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id'; - $result = $db->sql_query($sql); - - $forum_id = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_id[] = $row['forum_id']; - } - $db->sql_freeresult($result); - } - - if ($submit) - { - if (confirm_box(true)) - { - $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->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); - $prunedate_viewed = time() - ($prune_viewed * 86400); - - $template->assign_vars(array( - 'S_PRUNED' => true) - ); - - $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 - FROM ' . FORUMS_TABLE . ' - WHERE forum_type = ' . FORUM_POST . " - $sql_forum - ORDER BY left_id ASC"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $prune_ids = array(); - $p_result['topics'] = 0; - $p_result['posts'] = 0; - $log_data = ''; - - do - { - if (!$auth->acl_get('f_list', $row['forum_id'])) - { - continue; - } - - if ($prune_all) - { - $p_result = prune($row['forum_id'], 'posted', time(), $prune_flags, false); - } - else - { - if ($prune_posted) - { - $return = prune($row['forum_id'], 'posted', $prunedate_posted, $prune_flags, false); - $p_result['topics'] += $return['topics']; - $p_result['posts'] += $return['posts']; - } - - if ($prune_viewed) - { - $return = prune($row['forum_id'], 'viewed', $prunedate_viewed, $prune_flags, false); - $p_result['topics'] += $return['topics']; - $p_result['posts'] += $return['posts']; - } - } - - $prune_ids[] = $row['forum_id']; - - $template->assign_block_vars('pruned', array( - 'FORUM_NAME' => $row['forum_name'], - 'NUM_TOPICS' => $p_result['topics'], - 'NUM_POSTS' => $p_result['posts']) - ); - - $log_data .= (($log_data != '') ? ', ' : '') . $row['forum_name']; - } - while ($row = $db->sql_fetchrow($result)); - - // Sync all pruned forums at once - sync('forum', 'forum_id', $prune_ids, true, true); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PRUNE', false, array($log_data)); - } - $db->sql_freeresult($result); - - return; - } - else - { - $hidden_fields = array( - 'i' => $id, - 'mode' => $mode, - 'submit' => 1, - 'all_forums' => $all_forums, - 'f' => $forum_id, - - '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 (!count($forum_id)) - { - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - 'S_SELECT_FORUM' => true, - 'S_FORUM_OPTIONS' => make_forum_select(false, false, false)) - ); - } - else - { - $sql = 'SELECT forum_id, forum_name - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - - if (!$row) - { - $db->sql_freeresult($result); - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $forum_list = $s_hidden_fields = ''; - do - { - $forum_list .= (($forum_list != '') ? ', ' : '') . '' . $row['forum_name'] . ''; - $s_hidden_fields .= ''; - } - while ($row = $db->sql_fetchrow($result)); - - $db->sql_freeresult($result); - - $l_selected_forums = (count($forum_id) == 1) ? 'SELECTED_FORUM' : 'SELECTED_FORUMS'; - - $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, - ); - - /** - * 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); - } - } - - /** - * Prune users - */ - function prune_users($id, $mode) - { - 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'); - - $prune = (isset($_POST['prune'])) ? true : false; - - if ($prune) - { - $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 (count($user_ids)) - { - if ($action == 'deactivate') - { - user_active_flip('deactivate', $user_ids); - $l_log = 'LOG_PRUNE_USER_DEAC'; - } - else if ($action == 'delete') - { - if ($deleteposts) - { - user_delete('remove', $user_ids); - - $l_log = 'LOG_PRUNE_USER_DEL_DEL'; - } - else - { - user_delete('retain', $user_ids, true); - - $l_log = 'LOG_PRUNE_USER_DEL_ANON'; - } - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $l_log, false, array(implode(', ', $usernames))); - $msg = $user->lang['USER_' . strtoupper($action) . '_SUCCESS']; - } - else - { - $msg = $user->lang['USER_PRUNE_FAILURE']; - } - - trigger_error($msg . adm_back_link($this->u_action)); - } - else - { - // We list the users which will be pruned... - $user_ids = $usernames = array(); - $this->get_prune_users($user_ids, $usernames); - - if (!count($user_ids)) - { - trigger_error($user->lang['USER_PRUNE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Assign to template - foreach ($user_ids as $user_id) - { - $template->assign_block_vars('users', array( - 'USERNAME' => $usernames[$user_id], - 'USER_ID' => $user_id, - 'U_PROFILE' => get_username_string('profile', $user_id, $usernames[$user_id]), - 'U_USER_ADMIN' => ($auth->acl_get('a_user')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview&u=' . $user_id, true, $user->session_id) : '', - )); - } - - $template->assign_vars(array( - 'S_DEACTIVATE' => ($action == 'deactivate') ? true : false, - 'S_DELETE' => ($action == 'delete') ? true : false, - )); - - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'prune' => 1, - - 'deleteposts' => $request->variable('deleteposts', 0), - 'action' => $request->variable('action', ''), - )), 'confirm_body_prune.html'); - } - } - - $find_count = array('lt' => $user->lang['LESS_THAN'], 'eq' => $user->lang['EQUAL_TO'], 'gt' => $user->lang['MORE_THAN']); - $s_find_count = ''; - - foreach ($find_count as $key => $value) - { - $selected = ($key == 'eq') ? ' selected="selected"' : ''; - $s_find_count .= ''; - } - - $find_time = array('lt' => $user->lang['BEFORE'], 'gt' => $user->lang['AFTER']); - $s_find_active_time = ''; - foreach ($find_time as $key => $value) - { - $s_find_active_time .= ''; - } - - $sql = 'SELECT group_id, group_name - FROM ' . GROUPS_TABLE . ' - WHERE group_type <> ' . GROUP_SPECIAL . ' - ORDER BY group_name ASC'; - $result = $db->sql_query($sql); - - $s_group_list = ''; - while ($row = $db->sql_fetchrow($result)) - { - $s_group_list .= ''; - } - $db->sql_freeresult($result); - - if ($s_group_list) - { - // Only prepend the "All groups" option if there are groups, - // otherwise we don't want to display this option at all. - $s_group_list = '' . $s_group_list; - } - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - 'S_ACTIVE_OPTIONS' => $s_find_active_time, - 'S_GROUP_LIST' => $s_group_list, - 'S_COUNT_OPTIONS' => $s_find_count, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=acp_prune&field=users'), - )); - } - - /** - * Get user_ids/usernames from those being pruned - */ - function get_prune_users(&$user_ids, &$usernames) - { - global $user, $db, $request; - - $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) - { - $users = explode("\n", $users_by_name); - $where_sql = ' AND ' . $db->sql_in_set('username_clean', array_map('utf8_clean_string', $users)); - } - else if (!empty($users_by_id)) - { - $user_ids = $users_by_id; - user_get_id_name($user_ids, $usernames); - - $where_sql = ' AND ' . $db->sql_in_set('user_id', $user_ids); - } - else - { - $username = $request->variable('username', '', true); - $email = $request->variable('email', ''); - - $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); - - $active = ($active) ? explode('-', $active) : array(); - $joined_before = ($joined_before) ? explode('-', $joined_before) : array(); - $joined_after = ($joined_after) ? explode('-', $joined_after) : array(); - - // calculate the conditions required by the join time criteria - $joined_sql = ''; - if (!empty($joined_before) && !empty($joined_after)) - { - // if the two entered dates are equal, we need to adjust - // so that our time range is a full day instead of 1 second - if ($joined_after == $joined_before) - { - $joined_after[2] += 1; - } - - $joined_sql = ' AND user_regdate BETWEEN ' . gmmktime(0, 0, 0, (int) $joined_after[1], (int) $joined_after[2], (int) $joined_after[0]) . - ' AND ' . gmmktime(0, 0, 0, (int) $joined_before[1], (int) $joined_before[2], (int) $joined_before[0]); - } - else if (empty($joined_before) && !empty($joined_after)) - { - $joined_sql = ' AND user_regdate > ' . gmmktime(0, 0, 0, (int) $joined_after[1], (int) $joined_after[2], (int) $joined_after[0]); - } - else if (empty($joined_after) && !empty($joined_before)) - { - $joined_sql = ' AND user_regdate < ' . gmmktime(0, 0, 0, (int) $joined_before[1], (int) $joined_before[2], (int) $joined_before[0]); - } - // implicit else when both arrays are empty do nothing - - 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' => '='); - - $where_sql = ''; - $where_sql .= ($username) ? ' AND username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($username))) : ''; - $where_sql .= ($email) ? ' AND user_email ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $email)) . ' ' : ''; - $where_sql .= $joined_sql; - $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 (count($active) && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0) - { - $where_sql .= ' AND user_lastvisit = 0'; - } - 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 (count($active)) - { - $where_sql .= ' AND (user_lastvisit > 0 AND user_lastvisit < ' . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]) . ')'; - } - } - - // If no search criteria were provided, go no further. - if (!$where_sql && !$group_id && $posts_on_queue === false) - { - return; - } - - // Get bot ids - $sql = 'SELECT user_id - FROM ' . BOTS_TABLE; - $result = $db->sql_query($sql); - - $bot_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $bot_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - // Protect the admin, do not prune if no options are given... - if ($where_sql) - { - // Do not prune founder members - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE user_id <> ' . ANONYMOUS . ' - AND user_type <> ' . USER_FOUNDER . " - $where_sql"; - $result = $db->sql_query($sql); - - $user_ids = $usernames = array(); - - while ($row = $db->sql_fetchrow($result)) - { - // Do not prune bots and the user currently pruning. - if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) - { - $user_ids[] = $row['user_id']; - $usernames[$row['user_id']] = $row['username']; - } - } - $db->sql_freeresult($result); - } - - if ($group_id) - { - $sql = 'SELECT u.user_id, u.username - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u - WHERE ug.group_id = ' . (int) $group_id . ' - AND ug.user_id <> ' . ANONYMOUS . ' - AND u.user_type <> ' . USER_FOUNDER . ' - AND ug.user_pending = 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); - - // we're performing an intersection operation, so all the relevant users - // come from this most recent query (which was limited to the results of the - // previous query) - $user_ids = $usernames = array(); - while ($row = $db->sql_fetchrow($result)) - { - // Do not prune bots and the user currently pruning. - if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) - { - $user_ids[] = $row['user_id']; - $usernames[$row['user_id']] = $row['username']; - } - } - $db->sql_freeresult($result); - } - - if ($posts_on_queue !== false) - { - $sql = 'SELECT u.user_id, u.username, COUNT(p.post_id) AS queue_posts - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE u.user_id <> ' . ANONYMOUS . ' - AND u.user_type <> ' . USER_FOUNDER . ' - AND ' . $db->sql_in_set('p.post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)) . ' - AND u.user_id = p.poster_id - ' . (!empty($user_ids) ? ' AND ' . $db->sql_in_set('p.poster_id', $user_ids) : '') . ' - GROUP BY p.poster_id - HAVING queue_posts ' . $key_match[$queue_select] . ' ' . $posts_on_queue; - $result = $db->sql_query($sql); - - // same intersection logic as the above group ID portion - $user_ids = $usernames = array(); - while ($row = $db->sql_fetchrow($result)) - { - // Do not prune bots and the user currently pruning. - if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) - { - $user_ids[] = $row['user_id']; - $usernames[$row['user_id']] = $row['username']; - } - } - $db->sql_freeresult($result); - } - } -} diff --git a/install/update/old/includes/acp/acp_reasons.php b/install/update/old/includes/acp/acp_reasons.php deleted file mode 100644 index dfb2ccb..0000000 --- a/install/update/old/includes/acp/acp_reasons.php +++ /dev/null @@ -1,394 +0,0 @@ - -* @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_reasons -{ - var $u_action; - - function main($id, $mode) - { - global $db, $user, $template; - global $request, $phpbb_log; - - $user->add_lang(array('mcp', 'acp/posting')); - - // Set up general vars - $action = $request->variable('action', ''); - $submit = (isset($_POST['submit'])) ? true : false; - $reason_id = $request->variable('id', 0); - - $this->tpl_name = 'acp_reasons'; - $this->page_title = 'ACP_REASONS'; - - $form_name = 'acp_reason'; - add_form_key('acp_reason'); - - $error = array(); - - switch ($action) - { - case 'add': - case 'edit': - - $reason_row = array( - 'reason_title' => $request->variable('reason_title', '', true), - 'reason_description' => $request->variable('reason_description', '', true), - ); - - if ($submit) - { - if (!check_form_key($form_name)) - { - $error[] = $user->lang['FORM_INVALID']; - } - // Reason specified? - if (!$reason_row['reason_title'] || !$reason_row['reason_description']) - { - $error[] = $user->lang['NO_REASON_INFO']; - } - - $check_double = ($action == 'add') ? true : false; - - if ($action == 'edit') - { - $sql = 'SELECT reason_title - FROM ' . REPORTS_REASONS_TABLE . " - WHERE reason_id = $reason_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (strtolower($row['reason_title']) == 'other' || strtolower($reason_row['reason_title']) == 'other') - { - $reason_row['reason_title'] = 'other'; - } - - if ($row['reason_title'] != $reason_row['reason_title']) - { - $check_double = true; - } - } - - // Check for same reason if adding it... - if ($check_double) - { - $sql = 'SELECT reason_id - FROM ' . REPORTS_REASONS_TABLE . " - WHERE reason_title = '" . $db->sql_escape($reason_row['reason_title']) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row || ($action == 'add' && strtolower($reason_row['reason_title']) == 'other')) - { - $error[] = $user->lang['REASON_ALREADY_EXIST']; - } - } - - if (!count($error)) - { - // New reason? - if ($action == 'add') - { - // Get new order... - $sql = 'SELECT MAX(reason_order) as max_reason_order - FROM ' . REPORTS_REASONS_TABLE; - $result = $db->sql_query($sql); - $max_order = (int) $db->sql_fetchfield('max_reason_order'); - $db->sql_freeresult($result); - - $sql_ary = array( - 'reason_title' => (string) $reason_row['reason_title'], - 'reason_description' => (string) $reason_row['reason_description'], - 'reason_order' => $max_order + 1 - ); - - $db->sql_query('INSERT INTO ' . REPORTS_REASONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $log = 'ADDED'; - } - else if ($reason_id) - { - $sql_ary = array( - 'reason_title' => (string) $reason_row['reason_title'], - 'reason_description' => (string) $reason_row['reason_description'], - ); - - $db->sql_query('UPDATE ' . REPORTS_REASONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE reason_id = ' . $reason_id); - - $log = 'UPDATED'; - } - - $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)); - } - } - else if ($reason_id) - { - $sql = 'SELECT * - FROM ' . REPORTS_REASONS_TABLE . ' - WHERE reason_id = ' . $reason_id; - $result = $db->sql_query($sql); - $reason_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$reason_row) - { - trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - $l_title = ($action == 'edit') ? 'EDIT' : 'ADD'; - - $translated = false; - - // 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($reason_row['reason_title'])]) && isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason_row['reason_title'])])) - { - $translated = true; - } - - $template->assign_vars(array( - 'L_TITLE' => $user->lang['REASON_' . $l_title], - 'U_ACTION' => $this->u_action . "&id=$reason_id&action=$action", - 'U_BACK' => $this->u_action, - 'ERROR_MSG' => (count($error)) ? implode('
', $error) : '', - - 'REASON_TITLE' => $reason_row['reason_title'], - 'REASON_DESCRIPTION' => $reason_row['reason_description'], - - 'TRANSLATED_TITLE' => ($translated) ? $user->lang['report_reasons']['TITLE'][strtoupper($reason_row['reason_title'])] : '', - 'TRANSLATED_DESCRIPTION'=> ($translated) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason_row['reason_title'])] : '', - - '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' => (count($error)) ? true : false, - ) - ); - - return; - break; - - case 'delete': - - $sql = 'SELECT * - FROM ' . REPORTS_REASONS_TABLE . ' - WHERE reason_id = ' . $reason_id; - $result = $db->sql_query($sql); - $reason_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$reason_row) - { - trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (strtolower($reason_row['reason_title']) == 'other') - { - trigger_error($user->lang['NO_REMOVE_DEFAULT_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Let the deletion be confirmed... - if (confirm_box(true)) - { - $sql = 'SELECT reason_id - FROM ' . REPORTS_REASONS_TABLE . " - WHERE LOWER(reason_title) = 'other'"; - $result = $db->sql_query($sql); - $other_reason_id = (int) $db->sql_fetchfield('reason_id'); - $db->sql_freeresult($result); - - switch ($db->get_sql_layer()) - { - // The ugly one! - case 'mysqli': - case 'mysql4': - case 'mysql': - // Change the reports using this reason to 'other' - $sql = 'UPDATE ' . REPORTS_TABLE . ' - SET reason_id = ' . $other_reason_id . ", report_text = CONCAT('" . $db->sql_escape($reason_row['reason_description']) . "\n\n', report_text) - WHERE reason_id = $reason_id"; - break; - - // Standard? What's that? - case 'mssql_odbc': - case 'mssqlnative': - // Change the reports using this reason to 'other' - $sql = "DECLARE @ptrval binary(16) - - SELECT @ptrval = TEXTPTR(report_text) - FROM " . REPORTS_TABLE . " - WHERE reason_id = " . $reason_id . " - - UPDATETEXT " . REPORTS_TABLE . ".report_text @ptrval 0 0 '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' - - UPDATE " . REPORTS_TABLE . ' - SET reason_id = ' . $other_reason_id . " - WHERE reason_id = $reason_id"; - break; - - // Teh standard - case 'postgres': - case 'oracle': - case 'sqlite3': - // Change the reports using this reason to 'other' - $sql = 'UPDATE ' . REPORTS_TABLE . ' - SET reason_id = ' . $other_reason_id . ", report_text = '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' || report_text - WHERE reason_id = $reason_id"; - break; - } - $db->sql_query($sql); - - $db->sql_query('DELETE FROM ' . REPORTS_REASONS_TABLE . ' WHERE reason_id = ' . $reason_id); - - $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 - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'id' => $reason_id)) - ); - } - - break; - - case 'move_up': - case 'move_down': - - if (!check_link_hash($request->variable('hash', ''), 'acp_reasons')) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql = 'SELECT reason_order - FROM ' . REPORTS_REASONS_TABLE . " - WHERE reason_id = $reason_id"; - $result = $db->sql_query($sql); - $order = $db->sql_fetchfield('reason_order'); - $db->sql_freeresult($result); - - if ($order === false || ($order == 0 && $action == 'move_up')) - { - break; - } - $order = (int) $order; - $order_total = $order * 2 + (($action == 'move_up') ? -1 : 1); - - $sql = 'UPDATE ' . REPORTS_REASONS_TABLE . ' - SET reason_order = ' . $order_total . ' - reason_order - WHERE reason_order IN (' . $order . ', ' . (($action == 'move_up') ? $order - 1 : $order + 1) . ')'; - $db->sql_query($sql); - - if ($request->is_ajax()) - { - $json_response = new \phpbb\json_response; - $json_response->send(array( - 'success' => (bool) $db->sql_affectedrows(), - )); - } - break; - } - - // By default, check that order is valid and fix it if necessary - $sql = 'SELECT reason_id, reason_order - FROM ' . REPORTS_REASONS_TABLE . ' - ORDER BY reason_order'; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $order = 0; - do - { - ++$order; - - if ($row['reason_order'] != $order) - { - $sql = 'UPDATE ' . REPORTS_REASONS_TABLE . " - SET reason_order = $order - WHERE reason_id = {$row['reason_id']}"; - $db->sql_query($sql); - } - } - while ($row = $db->sql_fetchrow($result)); - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - ) - ); - - // Reason count - $sql = 'SELECT reason_id, COUNT(reason_id) AS reason_count - FROM ' . REPORTS_TABLE . ' - GROUP BY reason_id'; - $result = $db->sql_query($sql); - - $reason_count = array(); - while ($row = $db->sql_fetchrow($result)) - { - $reason_count[$row['reason_id']] = $row['reason_count']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT * - FROM ' . REPORTS_REASONS_TABLE . ' - ORDER BY reason_order ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $translated = false; - $other_reason = ($row['reason_title'] == 'other') ? true : false; - - // 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'])]; - - $translated = true; - } - - $template->assign_block_vars('reasons', array( - 'REASON_TITLE' => $row['reason_title'], - 'REASON_DESCRIPTION' => $row['reason_description'], - 'REASON_COUNT' => (isset($reason_count[$row['reason_id']])) ? $reason_count[$row['reason_id']] : 0, - - 'S_TRANSLATED' => $translated, - 'S_OTHER_REASON' => $other_reason, - - 'U_EDIT' => $this->u_action . '&action=edit&id=' . $row['reason_id'], - 'U_DELETE' => (!$other_reason) ? $this->u_action . '&action=delete&id=' . $row['reason_id'] : '', - 'U_MOVE_UP' => $this->u_action . '&action=move_up&id=' . $row['reason_id'] . '&hash=' . generate_link_hash('acp_reasons'), - 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&id=' . $row['reason_id'] . '&hash=' . generate_link_hash('acp_reasons')) - ); - } - $db->sql_freeresult($result); - } -} diff --git a/install/update/old/includes/acp/acp_styles.php b/install/update/old/includes/acp/acp_styles.php deleted file mode 100644 index 1bf5a3c..0000000 --- a/install/update/old/includes/acp/acp_styles.php +++ /dev/null @@ -1,1373 +0,0 @@ - -* @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_styles -{ - public $u_action; - - protected $u_base_action; - protected $s_hidden_fields; - protected $mode; - protected $styles_path; - protected $styles_path_absolute = 'styles'; - protected $default_style = 0; - 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; - - /** @var \phpbb\user */ - protected $user; - - /** @var \phpbb\template\template */ - protected $template; - - /** @var \phpbb\request\request_interface */ - protected $request; - - /** @var \phpbb\cache\driver\driver_interface */ - protected $cache; - - /** @var \phpbb\auth\auth */ - protected $auth; - - /** @var \phpbb\textformatter\cache_interface */ - protected $text_formatter_cache; - - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - - /** @var \phpbb\event\dispatcher_interface */ - protected $dispatcher; - - public function main($id, $mode) - { - 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; - $this->template = $template; - $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; - $this->dispatcher = $phpbb_dispatcher; - - $this->default_style = $config['default_style']; - $this->styles_path = $this->phpbb_root_path . $this->styles_path_absolute . '/'; - - $this->u_base_action = append_sid("{$phpbb_admin_path}index.{$this->php_ext}", "i={$id}"); - $this->s_hidden_fields = array( - 'mode' => $mode, - ); - - $this->user->add_lang('acp/styles'); - - $this->tpl_name = 'acp_styles'; - $this->page_title = 'ACP_CAT_STYLES'; - $this->mode = $mode; - - $action = $this->request->variable('action', ''); - $post_actions = array('install', 'activate', 'deactivate', 'uninstall'); - - foreach ($post_actions as $key) - { - if ($this->request->is_set_post($key)) - { - $action = $key; - } - } - - // The uninstall action uses confirm_box() to verify the validity of the request, - // so there is no need to check for a valid token here. - if (in_array($action, $post_actions) && $action != 'uninstall') - { - $is_valid_request = check_link_hash($request->variable('hash', ''), $action) || check_form_key('styles_management'); - - if (!$is_valid_request) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - if ($action != '') - { - $this->s_hidden_fields['action'] = $action; - } - - $this->template->assign_vars(array( - 'U_ACTION' => $this->u_base_action, - 'S_HIDDEN_FIELDS' => build_hidden_fields($this->s_hidden_fields) - ) - ); - - /** - * Run code before ACP styles action execution - * - * @event core.acp_styles_action_before - * @var int id Module ID - * @var string mode Active module - * @var string action Module that should be run - * @since 3.1.7-RC1 - */ - $vars = array('id', 'mode', 'action'); - extract($this->dispatcher->trigger_event('core.acp_styles_action_before', compact($vars))); - - // Execute actions - switch ($action) - { - case 'install': - $this->action_install(); - return; - case 'uninstall': - $this->action_uninstall(); - return; - case 'activate': - $this->action_activate(); - return; - case 'deactivate': - $this->action_deactivate(); - return; - case 'details': - $this->action_details(); - return; - default: - $this->frontend(); - } - } - - /** - * Main page - */ - protected function frontend() - { - add_form_key('styles_management'); - - // Check mode - switch ($this->mode) - { - case 'style': - $this->welcome_message('ACP_STYLES', 'ACP_STYLES_EXPLAIN'); - $this->show_installed(); - return; - case 'install': - $this->welcome_message('INSTALL_STYLES', 'INSTALL_STYLES_EXPLAIN'); - $this->show_available(); - return; - } - trigger_error($this->user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - /** - * Install style(s) - */ - protected function action_install() - { - // Get list of styles to install - $dirs = $this->request_vars('dir', '', true); - - // Get list of styles that can be installed - $styles = $this->find_available(false); - - // Install each style - $messages = array(); - $installed_names = array(); - $installed_dirs = array(); - foreach ($dirs as $dir) - { - if (in_array($dir, $this->reserved_style_names)) - { - $messages[] = $this->user->lang('STYLE_NAME_RESERVED', htmlspecialchars($dir)); - continue; - } - - $found = false; - foreach ($styles as &$style) - { - // Check if: - // 1. Directory matches directory we are looking for - // 2. Style is not installed yet - // 3. Style with same name or directory hasn't been installed already within this function - if ($style['style_path'] == $dir && empty($style['_installed']) && !in_array($style['style_path'], $installed_dirs) && !in_array($style['style_name'], $installed_names)) - { - // Install style - $style['style_active'] = 1; - $style['style_id'] = $this->install_style($style); - $style['_installed'] = true; - $found = true; - $installed_names[] = $style['style_name']; - $installed_dirs[] = $style['style_path']; - $messages[] = sprintf($this->user->lang['STYLE_INSTALLED'], htmlspecialchars($style['style_name'])); - } - } - if (!$found) - { - $messages[] = sprintf($this->user->lang['STYLE_NOT_INSTALLED'], htmlspecialchars($dir)); - } - } - - // 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)) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - $message = implode('
', $messages); - $message .= '

« ' . $this->user->lang('STYLE_INSTALLED_RETURN_INSTALLED_STYLES') . ''; - $message .= '

» ' . $this->user->lang('STYLE_INSTALLED_RETURN_UNINSTALLED_STYLES') . ''; - trigger_error($message, E_USER_NOTICE); - } - - /** - * Confirm styles removal - */ - protected function action_uninstall() - { - // Get list of styles to uninstall - $ids = $this->request_vars('id', 0, true); - - // Check if confirmation box was submitted - if (confirm_box(true)) - { - // Uninstall - $this->action_uninstall_confirmed($ids, $this->request->variable('confirm_delete_files', false)); - return; - } - - // Confirm box - $s_hidden = build_hidden_fields(array( - 'action' => 'uninstall', - 'ids' => $ids - )); - $this->template->assign_var('S_CONFIRM_DELETE', true); - confirm_box(false, $this->user->lang['CONFIRM_UNINSTALL_STYLES'], $s_hidden, 'acp_styles.html'); - - // Canceled - show styles list - $this->frontend(); - } - - /** - * Uninstall styles(s) - * - * @param array $ids List of style IDs - * @param bool $delete_files If true, script will attempt to remove files for selected styles - */ - protected function action_uninstall_confirmed($ids, $delete_files) - { - global $user, $phpbb_log; - - $default = $this->default_style; - $uninstalled = array(); - $messages = array(); - - // Check styles list - foreach ($ids as $id) - { - if (!$id) - { - trigger_error($this->user->lang['INVALID_STYLE_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - if ($id == $default) - { - trigger_error($this->user->lang['UNINSTALL_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); - } - $uninstalled[$id] = false; - } - - // Order by reversed style_id, so parent styles would be removed after child styles - // This way parent and child styles can be removed in same function call - $sql = 'SELECT * - FROM ' . STYLES_TABLE . ' - WHERE style_id IN (' . implode(', ', $ids) . ') - ORDER BY style_id DESC'; - $result = $this->db->sql_query($sql); - - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - // Uinstall each style - $uninstalled = array(); - foreach ($rows as $style) - { - $result = $this->uninstall_style($style, $delete_files); - - if (is_string($result)) - { - $messages[] = $result; - continue; - } - $messages[] = sprintf($this->user->lang['STYLE_UNINSTALLED'], $style['style_name']); - $uninstalled[] = $style['style_name']; - - // Attempt to delete files - if ($delete_files) - { - $messages[] = sprintf($this->user->lang[$this->delete_style_files($style['style_path']) ? 'DELETE_STYLE_FILES_SUCCESS' : 'DELETE_STYLE_FILES_FAILED'], $style['style_name']); - } - } - - if (empty($messages)) - { - // Nothing to uninstall? - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Log action - if (count($uninstalled)) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_DELETE', false, array(implode(', ', $uninstalled))); - } - - // Clear cache - $this->cache->purge(); - - // Show message - trigger_error(implode('
', $messages) . adm_back_link($this->u_action), E_USER_NOTICE); - } - - /** - * Activate styles - */ - protected function action_activate() - { - // Get list of styles to activate - $ids = $this->request_vars('id', 0, true); - - // Activate styles - $sql = 'UPDATE ' . STYLES_TABLE . ' - SET style_active = 1 - WHERE style_id IN (' . implode(', ', $ids) . ')'; - $this->db->sql_query($sql); - - // Purge cache - $this->cache->destroy('sql', STYLES_TABLE); - - // Show styles list - $this->frontend(); - } - - /** - * Deactivate styles - */ - protected function action_deactivate() - { - // Get list of styles to deactivate - $ids = $this->request_vars('id', 0, true); - - // Check for default style - foreach ($ids as $id) - { - if ($id == $this->default_style) - { - trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - // Reset default style for users who use selected styles - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_style = ' . (int) $this->default_style . ' - WHERE user_style IN (' . implode(', ', $ids) . ')'; - $this->db->sql_query($sql); - - // Deactivate styles - $sql = 'UPDATE ' . STYLES_TABLE . ' - SET style_active = 0 - WHERE style_id IN (' . implode(', ', $ids) . ')'; - $this->db->sql_query($sql); - - // Purge cache - $this->cache->destroy('sql', STYLES_TABLE); - - // Show styles list - $this->frontend(); - } - - /** - * Show style details - */ - protected function action_details() - { - global $user, $phpbb_log; - - $id = $this->request->variable('id', 0); - if (!$id) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Get all styles - $styles = $this->get_styles(); - usort($styles, array($this, 'sort_styles')); - - // Find current style - $style = false; - foreach ($styles as $row) - { - if ($row['style_id'] == $id) - { - $style = $row; - break; - } - } - - if ($style === false) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Read style configuration file - $style_cfg = $this->read_style_cfg($style['style_path']); - - // Find all available parent styles - $list = $this->find_possible_parents($styles, $id); - - // Add form key - $form_key = 'acp_styles'; - add_form_key($form_key); - - // Change data - if ($this->request->variable('update', false)) - { - if (!check_form_key($form_key)) - { - trigger_error($this->user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $update = array( - 'style_name' => trim($this->request->variable('style_name', $style['style_name'])), - 'style_parent_id' => $this->request->variable('style_parent', (int) $style['style_parent_id']), - 'style_active' => $this->request->variable('style_active', (int) $style['style_active']), - ); - $update_action = $this->u_action . '&action=details&id=' . $id; - - // Check style name - if ($update['style_name'] != $style['style_name']) - { - if (!strlen($update['style_name'])) - { - trigger_error($this->user->lang['STYLE_ERR_STYLE_NAME'] . adm_back_link($update_action), E_USER_WARNING); - } - foreach ($styles as $row) - { - if ($row['style_name'] == $update['style_name']) - { - trigger_error($this->user->lang['STYLE_ERR_NAME_EXIST'] . adm_back_link($update_action), E_USER_WARNING); - } - } - } - else - { - unset($update['style_name']); - } - - // Check parent style id - if ($update['style_parent_id'] != $style['style_parent_id']) - { - if ($update['style_parent_id'] != 0) - { - $found = false; - foreach ($list as $row) - { - if ($row['style_id'] == $update['style_parent_id']) - { - $found = true; - $update['style_parent_tree'] = ($row['style_parent_tree'] != '' ? $row['style_parent_tree'] . '/' : '') . $row['style_path']; - break; - } - } - if (!$found) - { - trigger_error($this->user->lang['STYLE_ERR_INVALID_PARENT'] . adm_back_link($update_action), E_USER_WARNING); - } - } - else - { - $update['style_parent_tree'] = ''; - } - } - else - { - unset($update['style_parent_id']); - } - - // Check style_active - if ($update['style_active'] != $style['style_active']) - { - if (!$update['style_active'] && $this->default_style == $style['style_id']) - { - trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($update_action), E_USER_WARNING); - } - } - else - { - unset($update['style_active']); - } - - // Update data - if (count($update)) - { - $sql = 'UPDATE ' . STYLES_TABLE . ' - SET ' . $this->db->sql_build_array('UPDATE', $update) . " - WHERE style_id = $id"; - $this->db->sql_query($sql); - - $style = array_merge($style, $update); - - if (isset($update['style_parent_id'])) - { - // Update styles tree - $styles = $this->get_styles(); - if ($this->update_styles_tree($styles, $style)) - { - // Something was changed in styles tree, purge all cache - $this->cache->purge(); - } - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_EDIT_DETAILS', false, array($style['style_name'])); - } - - // Update default style - $default = $this->request->variable('style_default', 0); - if ($default) - { - if (!$style['style_active']) - { - trigger_error($this->user->lang['STYLE_DEFAULT_CHANGE_INACTIVE'] . adm_back_link($update_action), E_USER_WARNING); - } - $this->config->set('default_style', $id); - $this->cache->purge(); - } - - // Show styles list - $this->frontend(); - return; - } - - // Show page title - $this->welcome_message('ACP_STYLES', null); - - // Show parent styles - foreach ($list as $row) - { - $this->template->assign_block_vars('parent_styles', array( - 'STYLE_ID' => $row['style_id'], - 'STYLE_NAME' => htmlspecialchars($row['style_name']), - 'LEVEL' => $row['level'], - 'SPACER' => str_repeat('  ', $row['level']), - ) - ); - } - - // Show style details - $this->template->assign_vars(array( - 'S_STYLE_DETAILS' => true, - 'STYLE_ID' => $style['style_id'], - 'STYLE_NAME' => htmlspecialchars($style['style_name']), - 'STYLE_PATH' => htmlspecialchars($style['style_path']), - 'STYLE_VERSION' => htmlspecialchars($style_cfg['style_version']), - 'STYLE_COPYRIGHT' => strip_tags($style['style_copyright']), - 'STYLE_PARENT' => $style['style_parent_id'], - 'S_STYLE_ACTIVE' => $style['style_active'], - 'S_STYLE_DEFAULT' => ($style['style_id'] == $this->default_style) - ) - ); - } - - /** - * List installed styles - */ - protected function show_installed() - { - // Get all installed styles - $styles = $this->get_styles(); - - if (!count($styles)) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - usort($styles, array($this, 'sort_styles')); - - // Get users - $users = $this->get_users(); - - // Add users counter to rows - foreach ($styles as &$style) - { - $style['_users'] = isset($users[$style['style_id']]) ? $users[$style['style_id']] : 0; - } - - // Set up styles list variables - // Addons should increase this number and update template variable - $this->styles_list_cols = 4; - $this->template->assign_var('STYLES_LIST_COLS', $this->styles_list_cols); - - // Show styles list - $this->show_styles_list($styles, 0, 0); - - // Show styles with invalid inherits_id - foreach ($styles as $style) - { - if (empty($style['_shown'])) - { - $style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($style['style_parent_tree'])); - $this->list_style($style, 0); - } - } - - // Add buttons - $this->template->assign_block_vars('extra_actions', array( - 'ACTION_NAME' => 'activate', - 'L_ACTION' => $this->user->lang['STYLE_ACTIVATE'], - ) - ); - - $this->template->assign_block_vars('extra_actions', array( - 'ACTION_NAME' => 'deactivate', - 'L_ACTION' => $this->user->lang['STYLE_DEACTIVATE'], - ) - ); - - if (isset($this->style_counters) && $this->style_counters['total'] > 1) - { - $this->template->assign_block_vars('extra_actions', array( - 'ACTION_NAME' => 'uninstall', - 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'], - ) - ); - } - } - - /** - * Show list of styles that can be installed - */ - protected function show_available() - { - // Get list of styles - $styles = $this->find_available(true); - - // Show styles - if (empty($styles)) - { - trigger_error($this->user->lang['NO_UNINSTALLED_STYLE'] . adm_back_link($this->u_base_action), E_USER_NOTICE); - } - - usort($styles, array($this, 'sort_styles')); - - $this->styles_list_cols = 3; - $this->template->assign_vars(array( - 'STYLES_LIST_COLS' => $this->styles_list_cols, - 'STYLES_LIST_HIDE_COUNT' => true - ) - ); - - // Show styles - foreach ($styles as &$style) - { - // Check if style has a parent style in styles list - $has_parent = false; - if ($style['_inherit_name'] != '') - { - foreach ($styles as $parent_style) - { - if ($parent_style['style_name'] == $style['_inherit_name'] && empty($parent_style['_shown'])) - { - // Show parent style first - $has_parent = true; - } - } - } - if (!$has_parent) - { - $this->list_style($style, 0); - $this->show_available_child_styles($styles, $style['style_name'], 1); - } - } - - // Show styles that do not have parent style in styles list - foreach ($styles as $style) - { - if (empty($style['_shown'])) - { - $this->list_style($style, 0); - } - } - - // Add button - if (isset($this->style_counters) && $this->style_counters['caninstall'] > 0) - { - $this->template->assign_block_vars('extra_actions', array( - 'ACTION_NAME' => 'install', - 'L_ACTION' => $this->user->lang['INSTALL_STYLES'], - ) - ); - } - } - - /** - * Find styles available for installation - * - * @param bool $all if true, function will return all installable styles. if false, function will return only styles that can be installed - * @return array List of styles - */ - protected function find_available($all) - { - // Get list of installed styles - $installed = $this->get_styles(); - - $installed_dirs = array(); - $installed_names = array(); - foreach ($installed as $style) - { - $installed_dirs[] = $style['style_path']; - $installed_names[$style['style_name']] = array( - 'path' => $style['style_path'], - 'id' => $style['style_id'], - 'parent' => $style['style_parent_id'], - 'tree' => (strlen($style['style_parent_tree']) ? $style['style_parent_tree'] . '/' : '') . $style['style_path'], - ); - } - - // Get list of directories - $dirs = $this->find_style_dirs(); - - // Find styles that can be installed - $styles = array(); - foreach ($dirs as $dir) - { - if (in_array($dir, $installed_dirs)) - { - // Style is already installed - continue; - } - $cfg = $this->read_style_cfg($dir); - if ($cfg === false) - { - // Invalid style.cfg - continue; - } - - // Style should be available for installation - $parent = $cfg['parent']; - $style = array( - 'style_id' => 0, - 'style_name' => $cfg['name'], - 'style_copyright' => $cfg['copyright'], - 'style_active' => 0, - 'style_path' => $dir, - 'bbcode_bitfield' => $cfg['template_bitfield'], - 'style_parent_id' => 0, - 'style_parent_tree' => '', - // Extra values for styles list - // All extra variable start with _ so they won't be confused with data that can be added to styles table - '_inherit_name' => $parent, - '_available' => true, - '_note' => '', - ); - - // Check style inheritance - if ($parent != '') - { - if (isset($installed_names[$parent])) - { - // Parent style is installed - $row = $installed_names[$parent]; - $style['style_parent_id'] = $row['id']; - $style['style_parent_tree'] = $row['tree']; - } - else - { - // Parent style is not installed yet - $style['_available'] = false; - $style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($parent)); - } - } - - if ($all || $style['_available']) - { - $styles[] = $style; - } - } - - return $styles; - } - - /** - * Show styles list - * - * @param array $styles styles list - * @param int $parent parent style id - * @param int $level style inheritance level - */ - protected function show_styles_list(&$styles, $parent, $level) - { - foreach ($styles as &$style) - { - if (empty($style['_shown']) && $style['style_parent_id'] == $parent) - { - $this->list_style($style, $level); - $this->show_styles_list($styles, $style['style_id'], $level + 1); - } - } - } - - /** - * Show available styles tree - * - * @param array $styles Styles list, passed as reference - * @param string $name Name of parent style - * @param int $level Styles tree level - */ - protected function show_available_child_styles(&$styles, $name, $level) - { - foreach ($styles as &$style) - { - if (empty($style['_shown']) && $style['_inherit_name'] == $name) - { - $this->list_style($style, $level); - $this->show_available_child_styles($styles, $style['style_name'], $level + 1); - } - } - } - - /** - * Update styles tree - * - * @param array $styles Styles list, passed as reference - * @param array|false $style Current style, false if root - * @return bool True if something was updated, false if not - */ - protected function update_styles_tree(&$styles, $style = false) - { - $parent_id = ($style === false) ? 0 : $style['style_id']; - $parent_tree = ($style === false) ? '' : ($style['style_parent_tree'] == '' ? '' : $style['style_parent_tree']) . $style['style_path']; - $update = false; - $updated = false; - foreach ($styles as &$row) - { - if ($row['style_parent_id'] == $parent_id) - { - if ($row['style_parent_tree'] != $parent_tree) - { - $row['style_parent_tree'] = $parent_tree; - $update = true; - } - $updated |= $this->update_styles_tree($styles, $row); - } - } - if ($update) - { - $sql = 'UPDATE ' . STYLES_TABLE . " - SET style_parent_tree = '" . $this->db->sql_escape($parent_tree) . "' - WHERE style_parent_id = {$parent_id}"; - $this->db->sql_query($sql); - $updated = true; - } - return $updated; - } - - /** - * Find all possible parent styles for style - * - * @param array $styles list of styles - * @param int $id id of style - * @param int $parent current parent style id - * @param int $level current tree level - * @return array Style ids, names and levels - */ - protected function find_possible_parents($styles, $id = -1, $parent = 0, $level = 0) - { - $results = array(); - foreach ($styles as $style) - { - if ($style['style_id'] != $id && $style['style_parent_id'] == $parent) - { - $results[] = array( - 'style_id' => $style['style_id'], - 'style_name' => $style['style_name'], - 'style_path' => $style['style_path'], - 'style_parent_id' => $style['style_parent_id'], - 'style_parent_tree' => $style['style_parent_tree'], - 'level' => $level - ); - $results = array_merge($results, $this->find_possible_parents($styles, $id, $style['style_id'], $level + 1)); - } - } - return $results; - } - - /** - * Show item in styles list - * - * @param array $style style row - * @param int $level style inheritance level - */ - protected function list_style(&$style, $level) - { - // Mark row as shown - if (!empty($style['_shown'])) - { - return; - } - - $style['_shown'] = true; - - // Generate template variables - $actions = array(); - $row = array( - // 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'], - - // Additional data - 'DEFAULT' => ($style['style_id'] && $style['style_id'] == $this->default_style), - 'USERS' => (isset($style['_users'])) ? $style['_users'] : '', - 'LEVEL' => $level, - 'PADDING' => (4 + 16 * $level), - 'SHOW_COPYRIGHT' => ($style['style_id']) ? false : true, - 'STYLE_PATH_FULL' => htmlspecialchars($this->styles_path_absolute . '/' . $style['style_path']) . '/', - - // Comment to show below style - 'COMMENT' => (isset($style['_note'])) ? $style['_note'] : '', - - // The following variables should be used by hooks to add custom HTML code - 'EXTRA' => '', - 'EXTRA_OPTIONS' => '' - ); - - // Status specific data - if ($style['style_id']) - { - // Style is installed - - // Details - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=details&id=' . $style['style_id'], - 'L_ACTION' => $this->user->lang['DETAILS'] - ); - - // Activate/Deactive - $action_name = ($style['style_active'] ? 'de' : '') . 'activate'; - - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=' . $action_name . '&hash=' . generate_link_hash($action_name) . '&id=' . $style['style_id'], - 'L_ACTION' => $this->user->lang['STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE'] - ); - -/* // Export - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=export&hash=' . generate_link_hash('export') . '&id=' . $style['style_id'], - 'L_ACTION' => $this->user->lang['EXPORT'] - ); */ - - // Uninstall - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=uninstall&hash=' . generate_link_hash('uninstall') . '&id=' . $style['style_id'], - 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'] - ); - - // Preview - $actions[] = array( - 'U_ACTION' => append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'style=' . $style['style_id']), - 'L_ACTION' => $this->user->lang['PREVIEW'] - ); - } - else - { - // Style is not installed - if (empty($style['_available'])) - { - $actions[] = array( - 'HTML' => $this->user->lang['CANNOT_BE_INSTALLED'] - ); - } - else - { - $actions[] = array( - 'U_ACTION' => $this->u_action . '&action=install&hash=' . generate_link_hash('install') . '&dir=' . urlencode($style['style_path']), - 'L_ACTION' => $this->user->lang['INSTALL_STYLE'] - ); - } - } - - // todo: add hook - - // Assign template variables - $this->template->assign_block_vars('styles_list', $row); - foreach ($actions as $action) - { - $this->template->assign_block_vars('styles_list.actions', $action); - } - - // Increase counters - $counter = ($style['style_id']) ? ($style['style_active'] ? 'active' : 'inactive') : (empty($style['_available']) ? 'cannotinstall' : 'caninstall'); - if (!isset($this->style_counters)) - { - $this->style_counters = array( - 'total' => 0, - 'active' => 0, - 'inactive' => 0, - 'caninstall' => 0, - 'cannotinstall' => 0 - ); - } - $this->style_counters[$counter]++; - $this->style_counters['total']++; - } - - /** - * Show welcome message - * - * @param string $title main title - * @param string $description page description - */ - protected function welcome_message($title, $description) - { - $this->template->assign_vars(array( - 'L_TITLE' => $this->user->lang[$title], - 'L_EXPLAIN' => (isset($this->user->lang[$description])) ? $this->user->lang[$description] : '' - ) - ); - } - - /** - * Find all directories that have styles - * - * @return array Directory names - */ - protected function find_style_dirs() - { - $styles = array(); - - $dp = @opendir($this->styles_path); - if ($dp) - { - while (($file = readdir($dp)) !== false) - { - $dir = $this->styles_path . $file; - if ($file[0] == '.' || !is_dir($dir)) - { - continue; - } - - if (file_exists("{$dir}/style.cfg")) - { - $styles[] = $file; - } - } - closedir($dp); - } - - return $styles; - } - - /** - * Sort styles - */ - public function sort_styles($style1, $style2) - { - if ($style1['style_active'] != $style2['style_active']) - { - return ($style1['style_active']) ? -1 : 1; - } - if (isset($style1['_available']) && $style1['_available'] != $style2['_available']) - { - return ($style1['_available']) ? -1 : 1; - } - return strcasecmp(isset($style1['style_name']) ? $style1['style_name'] : $style1['name'], isset($style2['style_name']) ? $style2['style_name'] : $style2['name']); - } - - /** - * Read style configuration file - * - * @param string $dir style directory - * @return array|bool Style data, false on error - */ - protected function read_style_cfg($dir) - { - static $required = array('name', 'phpbb_version', 'copyright'); - $cfg = parse_cfg_file($this->styles_path . $dir . '/style.cfg'); - - // Check if it is a valid file - foreach ($required as $key) - { - if (!isset($cfg[$key])) - { - return false; - } - } - - // Check data - if (!isset($cfg['parent']) || !is_string($cfg['parent']) || $cfg['parent'] == $cfg['name']) - { - $cfg['parent'] = ''; - } - if (!isset($cfg['template_bitfield'])) - { - $cfg['template_bitfield'] = $this->default_bitfield(); - } - - return $cfg; - } - - /** - * Install style - * - * @param array $style style data - * @return int Style id - */ - protected function install_style($style) - { - global $user, $phpbb_log; - - // Generate row - $sql_ary = array(); - foreach ($style as $key => $value) - { - if ($key != 'style_id' && substr($key, 0, 1) != '_') - { - $sql_ary[$key] = $value; - } - } - - // Add to database - $this->db->sql_transaction('begin'); - - $sql = 'INSERT INTO ' . STYLES_TABLE . ' - ' . $this->db->sql_build_array('INSERT', $sql_ary); - $this->db->sql_query($sql); - - $id = $this->db->sql_nextid(); - - $this->db->sql_transaction('commit'); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_ADD', false, array($sql_ary['style_name'])); - - return $id; - } - - /** - * Lists all styles - * - * @return array Rows with styles data - */ - protected function get_styles() - { - $sql = 'SELECT * - FROM ' . STYLES_TABLE; - $result = $this->db->sql_query($sql); - - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - return $rows; - } - - /** - * Count users for each style - * - * @return array Styles in following format: [style_id] = number of users - */ - protected function get_users() - { - $sql = 'SELECT user_style, COUNT(user_style) AS style_count - FROM ' . USERS_TABLE . ' - GROUP BY user_style'; - $result = $this->db->sql_query($sql); - - $style_count = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $style_count[$row['user_style']] = $row['style_count']; - } - $this->db->sql_freeresult($result); - - return $style_count; - } - - /** - * Uninstall style - * - * @param array $style Style data - * @return bool|string True on success, error message on error - */ - protected function uninstall_style($style) - { - $id = $style['style_id']; - $path = $style['style_path']; - - // Check if style has child styles - $sql = 'SELECT style_id - FROM ' . STYLES_TABLE . ' - WHERE style_parent_id = ' . (int) $id . " OR style_parent_tree = '" . $this->db->sql_escape($path) . "'"; - $result = $this->db->sql_query($sql); - - $conflict = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($conflict !== false) - { - return sprintf($this->user->lang['STYLE_UNINSTALL_DEPENDENT'], $style['style_name']); - } - - // Change default style for users - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_style = ' . (int) $this->default_style . ' - WHERE user_style = ' . $id; - $this->db->sql_query($sql); - - // Uninstall style - $sql = 'DELETE FROM ' . STYLES_TABLE . ' - WHERE style_id = ' . $id; - $this->db->sql_query($sql); - return true; - } - - /** - * Delete all files in style directory - * - * @param string $path Style directory - * @param string $dir Directory to remove inside style's directory - * @return bool True on success, false on error - */ - protected function delete_style_files($path, $dir = '') - { - $dirname = $this->styles_path . $path . $dir; - $result = true; - - $dp = @opendir($dirname); - - if ($dp) - { - while (($file = readdir($dp)) !== false) - { - if ($file == '.' || $file == '..') - { - continue; - } - $filename = $dirname . '/' . $file; - if (is_dir($filename)) - { - if (!$this->delete_style_files($path, $dir . '/' . $file)) - { - $result = false; - } - } - else - { - if (!@unlink($filename)) - { - $result = false; - } - } - } - closedir($dp); - } - if (!@rmdir($dirname)) - { - return false; - } - - return $result; - } - - /** - * Get list of items from posted data - * - * @param string $name Variable name - * @param string|int $default Default value for array - * @param bool $error If true, error will be triggered if list is empty - * @return array Items - */ - protected function request_vars($name, $default, $error = false) - { - $item = $this->request->variable($name, $default); - $items = $this->request->variable($name . 's', array($default)); - - if (count($items) == 1 && $items[0] == $default) - { - $items = array(); - } - - if ($item != $default && !count($items)) - { - $items[] = $item; - } - - if ($error && !count($items)) - { - trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - return $items; - } - - /** - * Generates default bitfield - * - * This bitfield decides which bbcodes are defined in a template. - * - * @return string Bitfield - */ - protected function default_bitfield() - { - static $value; - if (isset($value)) - { - return $value; - } - - // Hardcoded template bitfield to add for new templates - $default_bitfield = '1111111111111'; - - $bitfield = new bitfield(); - for ($i = 0; $i < strlen($default_bitfield); $i++) - { - if ($default_bitfield[$i] == '1') - { - $bitfield->set($i); - } - } - - return $bitfield->get_base64(); - } - -} diff --git a/install/update/old/includes/acp/acp_update.php b/install/update/old/includes/acp/acp_update.php deleted file mode 100644 index 9124a59..0000000 --- a/install/update/old/includes/acp/acp_update.php +++ /dev/null @@ -1,86 +0,0 @@ - -* @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_update -{ - var $u_action; - - function main($id, $mode) - { - global $config, $user, $template, $request; - global $phpbb_root_path, $phpEx, $phpbb_container; - - $user->add_lang('install'); - - $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 - { - $recheck = $request->variable('versioncheck_force', false); - $updates_available = $version_helper->get_update_on_branch($recheck); - $upgrades_available = $version_helper->get_suggested_updates(); - if (!empty($upgrades_available)) - { - $upgrades_available = array_pop($upgrades_available); - } - } - catch (\RuntimeException $e) - { - $template->assign_var('S_VERSIONCHECK_FAIL', true); - - $updates_available = array(); - } - - if (!empty($updates_available)) - { - $template->assign_block_vars('updates_available', $updates_available); - } - - $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 . '&versioncheck_force=1'), - - 'CURRENT_VERSION' => $config['version'], - - 'UPDATE_INSTRUCTIONS' => sprintf($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, - )); - - // Incomplete update? - if (phpbb_version_compare($config['version'], PHPBB_VERSION, '<')) - { - $database_update_link = $phpbb_root_path . 'install/app.php/update'; - - $template->assign_vars(array( - 'S_UPDATE_INCOMPLETE' => true, - 'FILES_VERSION' => PHPBB_VERSION, - 'INCOMPLETE_INSTRUCTIONS' => $user->lang('UPDATE_INCOMPLETE_EXPLAIN', $database_update_link), - )); - } - } -} diff --git a/install/update/old/includes/acp/acp_users.php b/install/update/old/includes/acp/acp_users.php deleted file mode 100644 index 2d1eaad..0000000 --- a/install/update/old/includes/acp/acp_users.php +++ /dev/null @@ -1,2692 +0,0 @@ - -* @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_users -{ - var $u_action; - var $p_master; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $config, $db, $user, $auth, $template; - global $phpbb_root_path, $phpbb_admin_path, $phpEx; - global $phpbb_dispatcher, $request; - global $phpbb_container, $phpbb_log; - - $user->add_lang(array('posting', 'ucp', 'acp/users')); - $this->tpl_name = 'acp_users'; - - $error = array(); - $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->variable('redirect', ''); - $redirect_tag = "redirect=$redirect"; - $redirect_url = append_sid("{$phpbb_admin_path}index.$phpEx", "i=$redirect"); - - $submit = (isset($_POST['update']) && !isset($_POST['cancel'])) ? true : false; - - $form_name = 'acp_users'; - add_form_key($form_name); - - // Whois (special case) - if ($action == 'whois') - { - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $this->page_title = 'WHOIS'; - $this->tpl_name = 'simple_body'; - - $user_ip = phpbb_ip_normalise($request->variable('user_ip', '')); - $domain = gethostbyaddr($user_ip); - $ipwhois = user_ipwhois($user_ip); - - $template->assign_vars(array( - 'MESSAGE_TITLE' => sprintf($user->lang['IP_WHOIS_FOR'], $domain), - 'MESSAGE_TEXT' => nl2br($ipwhois)) - ); - - return; - } - - // Show user selection mask - if (!$username && !$user_id) - { - $this->page_title = 'SELECT_USER'; - - $template->assign_vars(array( - 'U_ACTION' => $this->u_action, - 'ANONYMOUS_USER_ID' => ANONYMOUS, - - 'S_SELECT_USER' => true, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_user&field=username&select_single=true'), - )); - - return; - } - - if (!$user_id) - { - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $db->sql_query($sql); - $user_id = (int) $db->sql_fetchfield('user_id'); - $db->sql_freeresult($result); - - if (!$user_id) - { - trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - - // Generate content for all modes - $sql = 'SELECT u.*, s.* - FROM ' . USERS_TABLE . ' u - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) - WHERE u.user_id = ' . $user_id . ' - ORDER BY s.session_time DESC'; - $result = $db->sql_query_limit($sql, 1); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Generate overall "header" for user admin - $s_form_options = ''; - - // Build modes dropdown list - $sql = 'SELECT module_mode, module_auth - FROM ' . MODULES_TABLE . " - WHERE module_basename = 'acp_users' - AND module_enabled = 1 - AND module_class = 'acp' - ORDER BY left_id, module_mode"; - $result = $db->sql_query($sql); - - $dropdown_modes = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (!$this->p_master->module_auth_self($row['module_auth'])) - { - continue; - } - - $dropdown_modes[$row['module_mode']] = true; - } - $db->sql_freeresult($result); - - foreach ($dropdown_modes as $module_mode => $null) - { - $selected = ($mode == $module_mode) ? ' selected="selected"' : ''; - $s_form_options .= ''; - } - - $template->assign_vars(array( - 'U_BACK' => (empty($redirect)) ? $this->u_action : $redirect_url, - 'U_MODE_SELECT' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&u=$user_id"), - 'U_ACTION' => $this->u_action . '&u=' . $user_id . ((empty($redirect)) ? '' : '&' . $redirect_tag), - 'S_FORM_OPTIONS' => $s_form_options, - 'MANAGED_USERNAME' => $user_row['username']) - ); - - // Prevent normal users/admins change/view founders if they are not a founder by themselves - if ($user->data['user_type'] != USER_FOUNDER && $user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['NOT_MANAGE_FOUNDER'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $this->page_title = $user_row['username'] . ' :: ' . $user->lang('ACP_USER_' . strtoupper($mode)); - - switch ($mode) - { - case 'overview': - - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $user->add_lang('acp/ban'); - - $delete = $request->variable('delete', 0); - $delete_type = $request->variable('delete_type', ''); - $ip = $request->variable('ip', 'ip'); - - /** - * Run code at beginning of ACP users overview - * - * @event core.acp_users_overview_before - * @var array user_row Current user data - * @var string mode Active module - * @var string action Module that should be run - * @var bool submit Do we display the form only - * or did the user press submit - * @var array error Array holding error messages - * @since 3.1.3-RC1 - */ - $vars = array('user_row', 'mode', 'action', 'submit', 'error'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_overview_before', compact($vars))); - - if ($submit) - { - if ($delete) - { - if (!$auth->acl_get('a_userdel')) - { - send_status_line(403, 'Forbidden'); - trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // Check if the user wants to remove himself or the guest user account - if ($user_id == ANONYMOUS) - { - trigger_error($user->lang['CANNOT_REMOVE_ANONYMOUS'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // Founders can not be deleted. - if ($user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['CANNOT_REMOVE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_id == $user->data['user_id']) - { - trigger_error($user->lang['CANNOT_REMOVE_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($delete_type) - { - if (confirm_box(true)) - { - user_delete($delete_type, $user_id, $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 - ) - ); - } - else - { - $delete_confirm_hidden_fields = array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true, - 'delete' => 1, - 'delete_type' => $delete_type, - ); - - // Checks if the redirection page is specified - if (!empty($redirect)) - { - $delete_confirm_hidden_fields['redirect'] = $redirect; - } - - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($delete_confirm_hidden_fields)); - } - } - else - { - trigger_error($user->lang['NO_MODE'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - } - - // Handle quicktool actions - switch ($action) - { - case 'banuser': - case 'banemail': - case 'banip': - - if ($user_id == $user->data['user_id']) - { - trigger_error($user->lang['CANNOT_BAN_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_id == ANONYMOUS) - { - trigger_error($user->lang['CANNOT_BAN_ANONYMOUS'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['CANNOT_BAN_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $ban = array(); - - switch ($action) - { - case 'banuser': - $ban[] = $user_row['username']; - $reason = 'USER_ADMIN_BAN_NAME_REASON'; - break; - - case 'banemail': - $ban[] = $user_row['user_email']; - $reason = 'USER_ADMIN_BAN_EMAIL_REASON'; - break; - - case 'banip': - $ban[] = $user_row['user_ip']; - - $sql = 'SELECT DISTINCT poster_ip - FROM ' . POSTS_TABLE . " - WHERE poster_id = $user_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $ban[] = $row['poster_ip']; - } - $db->sql_freeresult($result); - - $reason = 'USER_ADMIN_BAN_IP_REASON'; - break; - } - - $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); - - trigger_error((($result === false) ? $user->lang['BAN_ALREADY_ENTERED'] : $user->lang['BAN_SUCCESSFUL']) . adm_back_link($this->u_action . '&u=' . $user_id)); - - break; - - case 'reactivate': - - if ($user_id == $user->data['user_id']) - { - trigger_error($user->lang['CANNOT_FORCE_REACT_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['CANNOT_FORCE_REACT_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error($user->lang['CANNOT_FORCE_REACT_BOT'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($config['email_enable']) - { - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $server_url = generate_board_url(); - - $user_actkey = gen_rand_string(mt_rand(6, 10)); - $email_template = ($user_row['user_type'] == USER_NORMAL) ? 'user_reactivate_account' : 'user_resend_inactive'; - - if ($user_row['user_type'] == USER_NORMAL) - { - user_active_flip('deactivate', $user_id, INACTIVE_REMIND); - } - else - { - // Grabbing the last confirm key - we only send a reminder - $sql = 'SELECT user_actkey - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - $user_activation_key = (string) $db->sql_fetchfield('user_actkey'); - $db->sql_freeresult($result); - - $user_actkey = empty($user_activation_key) ? $user_actkey : $user_activation_key; - } - - if ($user_row['user_type'] == USER_NORMAL || empty($user_activation_key)) - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_actkey = '" . $db->sql_escape($user_actkey) . "' - WHERE user_id = $user_id"; - $db->sql_query($sql); - } - - $messenger = new messenger(false); - - $messenger->template($email_template, $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey") - ); - - $messenger->send(NOTIFY_EMAIL); - - $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 . '&u=' . $user_id)); - } - - break; - - case 'active': - - if ($user_id == $user->data['user_id']) - { - // It is only deactivation since the user is already activated (else he would not have reached this page) - trigger_error($user->lang['CANNOT_DEACTIVATE_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_FOUNDER) - { - trigger_error($user->lang['CANNOT_DEACTIVATE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error($user->lang['CANNOT_DEACTIVATE_BOT'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - user_active_flip('flip', $user_id); - - if ($user_row['user_type'] == USER_INACTIVE) - { - 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']); - - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $messenger = new messenger(false); - - $messenger->template('admin_welcome_activated', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($user_row['username'])) - ); - - $messenger->send(NOTIFY_EMAIL); - } - } - - $message = ($user_row['user_type'] == USER_INACTIVE) ? 'USER_ADMIN_ACTIVATED' : 'USER_ADMIN_DEACTIVED'; - $log = ($user_row['user_type'] == USER_INACTIVE) ? 'LOG_USER_ACTIVE' : 'LOG_USER_INACTIVE'; - - $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 . '&u=' . $user_id)); - - break; - - case 'delsig': - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $sql_ary = array( - 'user_sig' => '', - 'user_sig_bbcode_uid' => '', - 'user_sig_bbcode_bitfield' => '' - ); - - $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - $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 . '&u=' . $user_id)); - - break; - - case 'delavatar': - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // 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_'); - - $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 . '&u=' . $user_id)); - break; - - case 'delposts': - - if (confirm_box(true)) - { - // Delete posts, attachments, etc. - delete_posts('poster_id', $user_id); - - $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 . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true)) - ); - } - - break; - - case 'delattach': - - if (confirm_box(true)) - { - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $attachment_manager->delete('user', $user_id); - unset($attachment_manager); - - $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 . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true)) - ); - } - - break; - - case 'deloutbox': - - if (confirm_box(true)) - { - $msg_ids = array(); - $lang = 'EMPTY'; - - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE author_id = $user_id - AND folder_id = " . PRIVMSGS_OUTBOX; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - if (!function_exists('delete_pm')) - { - include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - } - - do - { - $msg_ids[] = (int) $row['msg_id']; - } - while ($row = $db->sql_fetchrow($result)); - - $db->sql_freeresult($result); - - delete_pm($user_id, $msg_ids, PRIVMSGS_OUTBOX); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_OUTBOX', false, array($user_row['username'])); - - $lang = 'EMPTIED'; - } - $db->sql_freeresult($result); - - trigger_error($user->lang['USER_OUTBOX_' . $lang] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true)) - ); - } - break; - - case 'moveposts': - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $user->add_lang('acp/forums'); - - $new_forum_id = $request->variable('new_f', 0); - - if (!$new_forum_id) - { - $this->page_title = 'USER_ADMIN_MOVE_POSTS'; - - $template->assign_vars(array( - 'S_SELECT_FORUM' => true, - 'U_ACTION' => $this->u_action . "&action=$action&u=$user_id", - 'U_BACK' => $this->u_action . "&u=$user_id", - 'S_FORUM_OPTIONS' => make_forum_select(false, false, false, true)) - ); - - return; - } - - // Is the new forum postable to? - $sql = 'SELECT forum_name, forum_type - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $new_forum_id"; - $result = $db->sql_query($sql); - $forum_info = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$forum_info) - { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($forum_info['forum_type'] != FORUM_POST) - { - trigger_error($user->lang['MOVE_POSTS_NO_POSTABLE_FORUM'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // Two stage? - // Move topics comprising only posts from this user - $topic_id_ary = $move_topic_ary = $move_post_ary = $new_topic_id_ary = array(); - $forum_id_ary = array($new_forum_id); - - $sql = 'SELECT topic_id, post_visibility, COUNT(post_id) AS total_posts - FROM ' . POSTS_TABLE . " - WHERE poster_id = $user_id - AND forum_id <> $new_forum_id - GROUP BY topic_id, post_visibility"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id_ary[$row['topic_id']][$row['post_visibility']] = $row['total_posts']; - } - $db->sql_freeresult($result); - - 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 . ' - WHERE ' . $db->sql_in_set('topic_id', array_keys($topic_id_ary)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($topic_id_ary[$row['topic_id']][ITEM_APPROVED] == $row['topic_posts_approved'] - && $topic_id_ary[$row['topic_id']][ITEM_UNAPPROVED] == $row['topic_posts_unapproved'] - && $topic_id_ary[$row['topic_id']][ITEM_REAPPROVE] == $row['topic_posts_unapproved'] - && $topic_id_ary[$row['topic_id']][ITEM_DELETED] == $row['topic_posts_softdeleted']) - { - $move_topic_ary[] = $row['topic_id']; - } - else - { - $move_post_ary[$row['topic_id']]['title'] = $row['topic_title']; - $move_post_ary[$row['topic_id']]['attach'] = ($row['topic_attachment']) ? 1 : 0; - } - - $forum_id_ary[] = $row['forum_id']; - } - $db->sql_freeresult($result); - } - - // Entire topic comprises posts by this user, move these topics - if (count($move_topic_ary)) - { - move_topics($move_topic_ary, $new_forum_id, false); - } - - if (count($move_post_ary)) - { - // Create new topic - // Update post_ids, report_ids, attachment_ids - foreach ($move_post_ary as $topic_id => $post_ary) - { - // Create new topic - $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'topic_poster' => $user_id, - 'topic_time' => time(), - 'forum_id' => $new_forum_id, - 'icon_id' => 0, - 'topic_visibility' => ITEM_APPROVED, - 'topic_title' => $post_ary['title'], - 'topic_first_poster_name' => $user_row['username'], - 'topic_type' => POST_NORMAL, - 'topic_time_limit' => 0, - 'topic_attachment' => $post_ary['attach']) - ); - $db->sql_query($sql); - - $new_topic_id = $db->sql_nextid(); - - // Move posts - $sql = 'UPDATE ' . POSTS_TABLE . " - SET forum_id = $new_forum_id, topic_id = $new_topic_id - WHERE topic_id = $topic_id - AND poster_id = $user_id"; - $db->sql_query($sql); - - if ($post_ary['attach']) - { - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET topic_id = $new_topic_id - WHERE topic_id = $topic_id - AND poster_id = $user_id"; - $db->sql_query($sql); - } - - $new_topic_id_ary[] = $new_topic_id; - } - } - - $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 (count($topic_id_ary)) - { - sync('topic_reported', 'topic_id', $topic_id_ary); - sync('topic', 'topic_id', $topic_id_ary); - } - - if (count($forum_id_ary)) - { - sync('forum', 'forum_id', $forum_id_ary, false, true); - } - - $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 . '&u=' . $user_id)); - - break; - - case 'leave_nr': - - if (confirm_box(true)) - { - remove_newly_registered($user_id, $user_row); - - $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 . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'update' => true)) - ); - } - - break; - - default: - $u_action = $this->u_action; - - /** - * Run custom quicktool code - * - * @event core.acp_users_overview_run_quicktool - * @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', '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' => $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), - ); - - // Validation data - we do not check the password complexity setting here - $check_ary = array( - 'new_password' => array( - array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), - array('password')), - 'password_confirm' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), - ); - - // Check username if altered - if ($data['username'] != $user_row['username']) - { - $check_ary += array( - 'username' => array( - array('string', false, $config['min_name_chars'], $config['max_name_chars']), - array('username', $user_row['username']) - ), - ); - } - - // Check email if altered - if ($data['email'] != $user_row['user_email']) - { - $check_ary += array( - 'email' => array( - array('string', false, 6, 60), - array('user_email', $user_row['user_email']), - ), - ); - } - - $error = validate_data($data, $check_ary); - - if ($data['new_password'] && $data['password_confirm'] != $data['new_password']) - { - $error[] = 'NEW_PASSWORD_ERROR'; - } - - if (!check_form_key($form_name)) - { - $error[] = 'FORM_INVALID'; - } - - // Instantiate passwords manager - /* @var $passwords_manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('passwords.manager'); - - // Which updates do we need to do? - $update_username = ($user_row['username'] != $data['username']) ? $data['username'] : false; - $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 (!count($error)) - { - $sql_ary = array(); - - if ($user_row['user_type'] != USER_FOUNDER || $user->data['user_type'] == USER_FOUNDER) - { - // Only allow founders updating the founder status... - if ($user->data['user_type'] == USER_FOUNDER) - { - // Setting a normal member to be a founder - if ($data['user_founder'] && $user_row['user_type'] != USER_FOUNDER) - { - // Make sure the user is not setting an Inactive or ignored user to be a founder - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error($user->lang['CANNOT_SET_FOUNDER_IGNORED'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($user_row['user_type'] == USER_INACTIVE) - { - trigger_error($user->lang['CANNOT_SET_FOUNDER_INACTIVE'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $sql_ary['user_type'] = USER_FOUNDER; - } - else if (!$data['user_founder'] && $user_row['user_type'] == USER_FOUNDER) - { - // Check if at least one founder is present - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_FOUNDER . ' - AND user_id <> ' . $user_id; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $sql_ary['user_type'] = USER_NORMAL; - } - else - { - trigger_error($user->lang['AT_LEAST_ONE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - } - } - } - - /** - * Modify user data before we update it - * - * @event core.acp_users_overview_modify_data - * @var array user_row Current user data - * @var array data Submitted user data - * @var array sql_ary User data we udpate - * @since 3.1.0-a1 - */ - $vars = array('user_row', 'data', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_overview_modify_data', compact($vars))); - - if ($update_username !== false) - { - $sql_ary['username'] = $update_username; - $sql_ary['username_clean'] = utf8_clean_string($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) - { - $sql_ary += array( - 'user_email' => $update_email, - 'user_email_hash' => phpbb_email_hash($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) - { - $sql_ary += array( - 'user_password' => $passwords_manager->hash($data['new_password']), - 'user_passchg' => time(), - ); - - $user->reset_login_keys($user_id); - - $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_NEW_PASSWORD', false, array( - 'reportee_id' => $user_id, - $user_row['username'] - )); - } - - if (count($sql_ary)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - } - - if ($update_username) - { - user_update_name($user_row['username'], $update_username); - } - - // Let the users permissions being updated - $auth->acl_clear_prefetch($user_id); - - $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 . '&u=' . $user_id)); - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - if ($user_id == $user->data['user_id']) - { - $quick_tool_ary = array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH', 'deloutbox' => 'DEL_OUTBOX'); - if ($user_row['user_new']) - { - $quick_tool_ary['leave_nr'] = 'LEAVE_NR'; - } - } - else - { - $quick_tool_ary = array(); - - if ($user_row['user_type'] != USER_FOUNDER) - { - $quick_tool_ary += array('banuser' => 'BAN_USER', 'banemail' => 'BAN_EMAIL', 'banip' => 'BAN_IP'); - } - - if ($user_row['user_type'] != USER_FOUNDER && $user_row['user_type'] != USER_IGNORE) - { - $quick_tool_ary += array('active' => (($user_row['user_type'] == USER_INACTIVE) ? 'ACTIVATE' : 'DEACTIVATE')); - } - - $quick_tool_ary += array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH', 'deloutbox' => 'DEL_OUTBOX'); - - if ($config['email_enable'] && ($user_row['user_type'] == USER_NORMAL || $user_row['user_type'] == USER_INACTIVE)) - { - $quick_tool_ary['reactivate'] = 'FORCE'; - } - - if ($user_row['user_new']) - { - $quick_tool_ary['leave_nr'] = 'LEAVE_NR'; - } - } - - if ($config['load_onlinetrack']) - { - $sql = 'SELECT MAX(session_time) AS session_time, MIN(session_viewonline) AS session_viewonline - FROM ' . SESSIONS_TABLE . " - WHERE session_user_id = $user_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $user_row['session_time'] = (isset($row['session_time'])) ? $row['session_time'] : 0; - $user_row['session_viewonline'] = (isset($row['session_viewonline'])) ? $row['session_viewonline'] : 0; - unset($row); - } - - /** - * Add additional quick tool options and overwrite user data - * - * @event core.acp_users_display_overview - * @var array user_row Array with user data - * @var array quick_tool_ary Ouick tool options - * @since 3.1.0-a1 - */ - $vars = array('user_row', 'quick_tool_ary'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_display_overview', compact($vars))); - - $s_action_options = ''; - foreach ($quick_tool_ary as $value => $lang) - { - $s_action_options .= ''; - } - - $last_active = (!empty($user_row['session_time'])) ? $user_row['session_time'] : $user_row['user_lastvisit']; - - $inactive_reason = ''; - if ($user_row['user_type'] == USER_INACTIVE) - { - $inactive_reason = $user->lang['INACTIVE_REASON_UNKNOWN']; - - switch ($user_row['user_inactive_reason']) - { - case INACTIVE_REGISTER: - $inactive_reason = $user->lang['INACTIVE_REASON_REGISTER']; - break; - - case INACTIVE_PROFILE: - $inactive_reason = $user->lang['INACTIVE_REASON_PROFILE']; - break; - - case INACTIVE_MANUAL: - $inactive_reason = $user->lang['INACTIVE_REASON_MANUAL']; - break; - - case INACTIVE_REMIND: - $inactive_reason = $user->lang['INACTIVE_REASON_REMIND']; - break; - } - } - - // Posts in Queue - $sql = 'SELECT COUNT(post_id) as posts_in_queue - FROM ' . POSTS_TABLE . ' - WHERE poster_id = ' . $user_id . ' - AND ' . $db->sql_in_set('post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)); - $result = $db->sql_query($sql); - $user_row['posts_in_queue'] = (int) $db->sql_fetchfield('posts_in_queue'); - $db->sql_freeresult($result); - - $sql = 'SELECT post_id - FROM ' . POSTS_TABLE . ' - WHERE poster_id = '. $user_id; - $result = $db->sql_query_limit($sql, 1); - $user_row['user_has_posts'] = (bool) $db->sql_fetchfield('post_id'); - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'L_NAME_CHARS_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), - 'L_POSTS_IN_QUEUE' => $user->lang('NUM_POSTS_IN_QUEUE', $user_row['posts_in_queue']), - 'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, - - 'S_OVERVIEW' => true, - 'S_USER_IP' => ($user_row['user_ip']) ? true : false, - 'S_USER_FOUNDER' => ($user_row['user_type'] == USER_FOUNDER) ? true : false, - 'S_ACTION_OPTIONS' => $s_action_options, - 'S_OWN_ACCOUNT' => ($user_id == $user->data['user_id']) ? true : false, - 'S_USER_INACTIVE' => ($user_row['user_type'] == USER_INACTIVE) ? true : false, - - 'U_SHOW_IP' => $this->u_action . "&u=$user_id&ip=" . (($ip == 'ip') ? 'hostname' : 'ip'), - 'U_WHOIS' => $this->u_action . "&action=whois&user_ip={$user_row['user_ip']}", - 'U_MCP_QUEUE' => ($auth->acl_getf_global('m_approve')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue', true, $user->session_id) : '', - 'U_SEARCH_USER' => ($config['load_search'] && $auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id={$user_row['user_id']}&sr=posts") : '', - - 'U_SWITCH_PERMISSIONS' => ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_row['user_id']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&u={$user_row['user_id']}&hash=" . generate_link_hash('switchperm')) : '', - - 'POSTS_IN_QUEUE' => $user_row['posts_in_queue'], - 'USER' => $user_row['username'], - 'USER_REGISTERED' => $user->format_date($user_row['user_regdate']), - 'REGISTERED_IP' => ($ip == 'hostname') ? gethostbyaddr($user_row['user_ip']) : $user_row['user_ip'], - 'USER_LASTACTIVE' => ($last_active) ? $user->format_date($last_active) : ' - ', - 'USER_EMAIL' => $user_row['user_email'], - 'USER_WARNINGS' => $user_row['user_warnings'], - 'USER_POSTS' => $user_row['user_posts'], - 'USER_HAS_POSTS' => $user_row['user_has_posts'], - 'USER_INACTIVE_REASON' => $inactive_reason, - )); - - break; - - case 'feedback': - - $user->add_lang('mcp'); - - // Set up general vars - $start = $request->variable('start', 0); - $deletemark = (isset($_POST['delmarked'])) ? true : false; - $deleteall = (isset($_POST['delall'])) ? true : false; - $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->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')) - { - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $where_sql = ''; - if ($deletemark && $marked) - { - $sql_in = array(); - foreach ($marked as $mark) - { - $sql_in[] = $mark; - } - $where_sql = ' AND ' . $db->sql_in_set('log_id', $sql_in); - unset($sql_in); - } - - if ($where_sql || $deleteall) - { - $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE log_type = ' . LOG_USERS . " - AND reportee_id = $user_id - $where_sql"; - $db->sql_query($sql); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CLEAR_USER', false, array($user_row['username'])); - } - } - - if ($submit && $message) - { - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $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 . '&u=' . $user_id)); - } - - // Sorting - $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_text = array('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'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - - // Define where and sort sql for use in displaying logs - $sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0; - $sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); - - // Grab log data - $log_data = array(); - $log_count = 0; - $start = view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort); - - $base_url = $this->u_action . "&u=$user_id&$u_sort_param"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'S_FEEDBACK' => true, - - 'S_LIMIT_DAYS' => $s_limit_days, - 'S_SORT_KEY' => $s_sort_key, - 'S_SORT_DIR' => $s_sort_dir, - 'S_CLEARLOGS' => $auth->acl_get('a_clearlogs')) - ); - - foreach ($log_data as $row) - { - $template->assign_block_vars('log', array( - 'USERNAME' => $row['username_full'], - 'IP' => $row['ip'], - 'DATE' => $user->format_date($row['time']), - 'ACTION' => nl2br($row['action']), - 'ID' => $row['id']) - ); - } - - break; - - case 'warnings': - $user->add_lang('mcp'); - - // Set up general vars - $deletemark = (isset($_POST['delmarked'])) ? true : false; - $deleteall = (isset($_POST['delall'])) ? true : false; - $confirm = (isset($_POST['confirm'])) ? true : false; - $marked = $request->variable('mark', array(0)); - - // Delete entries if requested and able - if ($deletemark || $deleteall || $confirm) - { - if (confirm_box(true)) - { - $where_sql = ''; - $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)); - } - - if ($where_sql || $deleteall) - { - $sql = 'DELETE FROM ' . WARNINGS_TABLE . " - WHERE user_id = $user_id - $where_sql"; - $db->sql_query($sql); - - if ($deleteall) - { - $log_warnings = $deleted_warnings = 0; - } - else - { - $num_warnings = (int) $db->sql_affectedrows(); - $deleted_warnings = ' user_warnings - ' . $num_warnings; - $log_warnings = ($num_warnings > 2) ? 2 : $num_warnings; - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_warnings = $deleted_warnings - WHERE user_id = $user_id"; - $db->sql_query($sql); - - if ($log_warnings) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_WARNINGS_DELETED', false, array($user_row['username'], $num_warnings)); - } - else - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_WARNINGS_DELETED_ALL', false, array($user_row['username'])); - } - } - } - else - { - $s_hidden_fields = array( - 'i' => $id, - 'mode' => $mode, - 'u' => $user_id, - 'mark' => $marked, - ); - if (isset($_POST['delmarked'])) - { - $s_hidden_fields['delmarked'] = 1; - } - if (isset($_POST['delall'])) - { - $s_hidden_fields['delall'] = 1; - } - if (isset($_POST['delall']) || (isset($_POST['delmarked']) && count($marked))) - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); - } - } - } - - $sql = 'SELECT w.warning_id, w.warning_time, w.post_id, l.log_operation, l.log_data, l.user_id AS mod_user_id, m.username AS mod_username, m.user_colour AS mod_user_colour - FROM ' . WARNINGS_TABLE . ' w - LEFT JOIN ' . LOG_TABLE . ' l - ON (w.log_id = l.log_id) - LEFT JOIN ' . USERS_TABLE . ' m - ON (l.user_id = m.user_id) - WHERE w.user_id = ' . $user_id . ' - ORDER BY w.warning_time DESC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$row['log_operation']) - { - // We do not have a log-entry anymore, so there is no data available - $row['action'] = $user->lang['USER_WARNING_LOG_DELETED']; - } - else - { - $row['action'] = (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}'; - if (!empty($row['log_data'])) - { - $log_data_ary = @unserialize($row['log_data']); - $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary; - - if (isset($user->lang[$row['log_operation']])) - { - // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array - // It doesn't matter if we add more arguments than placeholders - if ((substr_count($row['action'], '%') - count($log_data_ary)) > 0) - { - $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'])); - } - else if (!empty($log_data_ary)) - { - $row['action'] .= '
' . implode('', $log_data_ary); - } - } - } - - $template->assign_block_vars('warn', array( - 'ID' => $row['warning_id'], - 'USERNAME' => ($row['log_operation']) ? get_username_string('full', $row['mod_user_id'], $row['mod_username'], $row['mod_user_colour']) : '-', - 'ACTION' => make_clickable($row['action']), - 'DATE' => $user->format_date($row['warning_time']), - )); - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_WARNINGS' => true, - )); - - break; - - case 'profile': - - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - /* @var $cp \phpbb\profilefields\manager */ - $cp = $phpbb_container->get('profilefields.manager'); - - $cp_data = $cp_error = array(); - - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($user->data['user_lang']) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $user_row['iso_lang_id'] = $row['lang_id']; - - $data = array( - 'jabber' => $request->variable('jabber', $user_row['user_jabber'], true), - 'bday_day' => 0, - 'bday_month' => 0, - 'bday_year' => 0, - ); - - if ($user_row['user_birthday']) - { - list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user_row['user_birthday']); - } - - $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']); - - /** - * Modify user data on editing profile in ACP - * - * @event core.acp_users_modify_profile - * @var array data Array with user profile data - * @var bool submit Flag indicating if submit button has been pressed - * @var int user_id The user id - * @var array user_row Array with the full user data - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit', 'user_id', 'user_row'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_modify_profile', compact($vars))); - - if ($submit) - { - $error = validate_data($data, array( - 'jabber' => array( - array('string', true, 5, 255), - array('jabber')), - 'bday_day' => array('num', true, 1, 31), - 'bday_month' => array('num', true, 1, 12), - 'bday_year' => array('num', true, 1901, gmdate('Y', time())), - 'user_birthday' => array('date', true), - )); - - // validate custom profile fields - $cp->submit_cp_field('profile', $user_row['iso_lang_id'], $cp_data, $cp_error); - - if (count($cp_error)) - { - $error = array_merge($error, $cp_error); - } - if (!check_form_key($form_name)) - { - $error[] = 'FORM_INVALID'; - } - - /** - * Validate profile data in ACP before submitting to the database - * - * @event core.acp_users_profile_validate - * @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('data', 'user_id', 'user_row', 'error'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_validate', compact($vars))); - - if (!count($error)) - { - $sql_ary = array( - 'user_jabber' => $data['jabber'], - 'user_birthday' => $data['user_birthday'], - ); - - /** - * Modify profile data in ACP before submitting to the database - * - * @event core.acp_users_profile_modify_sql_ary - * @var array cp_data Array with the user custom profile fields data - * @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 sql_ary Array with sql data - * @since 3.1.4-RC1 - */ - $vars = array('cp_data', 'data', 'user_id', 'user_row', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_modify_sql_ary', compact($vars))); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - // Update Custom Fields - $cp->update_profile_field_data($user_id, $cp_data); - - trigger_error($user->lang['USER_PROFILE_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - $s_birthday_day_options = ''; - for ($i = 1; $i < 32; $i++) - { - $selected = ($i == $data['bday_day']) ? ' selected="selected"' : ''; - $s_birthday_day_options .= ""; - } - - $s_birthday_month_options = ''; - for ($i = 1; $i < 13; $i++) - { - $selected = ($i == $data['bday_month']) ? ' selected="selected"' : ''; - $s_birthday_month_options .= ""; - } - - $now = getdate(); - $s_birthday_year_options = ''; - for ($i = $now['year'] - 100; $i <= $now['year']; $i++) - { - $selected = ($i == $data['bday_year']) ? ' selected="selected"' : ''; - $s_birthday_year_options .= ""; - } - unset($now); - - $template->assign_vars(array( - 'JABBER' => $data['jabber'], - 'S_BIRTHDAY_DAY_OPTIONS' => $s_birthday_day_options, - 'S_BIRTHDAY_MONTH_OPTIONS' => $s_birthday_month_options, - 'S_BIRTHDAY_YEAR_OPTIONS' => $s_birthday_year_options, - - 'S_PROFILE' => true) - ); - - // Get additional profile fields and assign them to the template block var 'profile_fields' - $user->get_profile_fields($user_id); - - $cp->generate_profile_fields('profile', $user_row['iso_lang_id']); - - break; - - case 'prefs': - - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $data = array( - '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']), - ); - - /** - * Modify users preferences data - * - * @event core.acp_users_prefs_modify_data - * @var array data Array with users preferences data - * @var array user_row Array with user data - * @since 3.1.0-b3 - */ - $vars = array('data', 'user_row'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_data', compact($vars))); - - if ($submit) - { - $error = validate_data($data, array( - 'dateformat' => array('string', false, 1, 64), - 'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'), - 'tz' => array('timezone'), - - 'topic_sk' => array('string', false, 1, 1), - 'topic_sd' => array('string', false, 1, 1), - 'post_sk' => array('string', false, 1, 1), - 'post_sd' => array('string', false, 1, 1), - )); - - if (!check_form_key($form_name)) - { - $error[] = 'FORM_INVALID'; - } - - if (!count($error)) - { - $this->optionset($user_row, 'viewimg', $data['view_images']); - $this->optionset($user_row, 'viewflash', $data['view_flash']); - $this->optionset($user_row, 'viewsmilies', $data['view_smilies']); - $this->optionset($user_row, 'viewsigs', $data['view_sigs']); - $this->optionset($user_row, 'viewavatars', $data['view_avatars']); - $this->optionset($user_row, 'viewcensors', $data['view_wordcensor']); - $this->optionset($user_row, 'bbcode', $data['bbcode']); - $this->optionset($user_row, 'smilies', $data['smilies']); - $this->optionset($user_row, 'attachsig', $data['sig']); - - $sql_ary = array( - 'user_options' => $user_row['user_options'], - - 'user_allow_pm' => $data['allowpm'], - 'user_allow_viewemail' => $data['viewemail'], - 'user_allow_massemail' => $data['massemail'], - 'user_allow_viewonline' => !$data['hideonline'], - 'user_notify_type' => $data['notifymethod'], - 'user_notify_pm' => $data['notifypm'], - - 'user_dateformat' => $data['dateformat'], - 'user_lang' => $data['lang'], - 'user_timezone' => $data['tz'], - 'user_style' => $data['style'], - - 'user_topic_sortby_type' => $data['topic_sk'], - 'user_post_sortby_type' => $data['post_sk'], - 'user_topic_sortby_dir' => $data['topic_sd'], - 'user_post_sortby_dir' => $data['post_sd'], - - 'user_topic_show_days' => $data['topic_st'], - 'user_post_show_days' => $data['post_st'], - - 'user_notify' => $data['notify'], - ); - - /** - * Modify SQL query before users preferences are updated - * - * @event core.acp_users_prefs_modify_sql - * @var array data Array with users preferences data - * @var array user_row Array with user data - * @var array sql_ary SQL array with users preferences data to update - * @var array error Array with errors data - * @since 3.1.0-b3 - */ - $vars = array('data', 'user_row', 'sql_ary', 'error'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_sql', compact($vars))); - - if (!count($error)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - // Check if user has an active session - if ($user_row['session_id']) - { - // We'll update the session if user_allow_viewonline has changed and the user is a bot - // Or if it's a regular user and the admin set it to hide the session - if ($user_row['user_allow_viewonline'] != $sql_ary['user_allow_viewonline'] && $user_row['user_type'] == USER_IGNORE - || $user_row['user_allow_viewonline'] && !$sql_ary['user_allow_viewonline']) - { - // We also need to check if the user has the permission to cloak. - $user_auth = new \phpbb\auth\auth(); - $user_auth->acl($user_row); - - $session_sql_ary = array( - 'session_viewonline' => ($user_auth->acl_get('u_hideonline')) ? $sql_ary['user_allow_viewonline'] : true, - ); - - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $session_sql_ary) . " - WHERE session_user_id = $user_id"; - $db->sql_query($sql); - - unset($user_auth); - } - } - - trigger_error($user->lang['USER_PREFS_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - $dateformat_options = ''; - foreach ($user->lang['dateformats'] as $format => $null) - { - $dateformat_options .= ''; - } - - $s_custom = false; - - $dateformat_options .= ''; - - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - // Topic ordering options - $limit_topic_days = array(0 => $user->lang['ALL_TOPICS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_topic_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 'r' => $user->lang['REPLIES'], 's' => $user->lang['SUBJECT'], 'v' => $user->lang['VIEWS']); - - // Post ordering options - $limit_post_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_post_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); - - $_options = array('topic', 'post'); - foreach ($_options as $sort_option) - { - ${'s_limit_' . $sort_option . '_days'} = ''; - - ${'s_sort_' . $sort_option . '_key'} = ''; - - ${'s_sort_' . $sort_option . '_dir'} = ''; - } - - phpbb_timezone_select($template, $user, $data['tz'], true); - $user_prefs_data = array( - 'S_PREFS' => true, - 'S_JABBER_DISABLED' => ($config['jab_enable'] && $user_row['user_jabber'] && @extension_loaded('xml')) ? false : true, - - 'VIEW_EMAIL' => $data['viewemail'], - 'MASS_EMAIL' => $data['massemail'], - 'ALLOW_PM' => $data['allowpm'], - 'HIDE_ONLINE' => $data['hideonline'], - 'NOTIFY_EMAIL' => ($data['notifymethod'] == NOTIFY_EMAIL) ? true : false, - 'NOTIFY_IM' => ($data['notifymethod'] == NOTIFY_IM) ? true : false, - 'NOTIFY_BOTH' => ($data['notifymethod'] == NOTIFY_BOTH) ? true : false, - 'NOTIFY_PM' => $data['notifypm'], - 'BBCODE' => $data['bbcode'], - 'SMILIES' => $data['smilies'], - 'ATTACH_SIG' => $data['sig'], - 'NOTIFY' => $data['notify'], - 'VIEW_IMAGES' => $data['view_images'], - 'VIEW_FLASH' => $data['view_flash'], - 'VIEW_SMILIES' => $data['view_smilies'], - 'VIEW_SIGS' => $data['view_sigs'], - 'VIEW_AVATARS' => $data['view_avatars'], - 'VIEW_WORDCENSOR' => $data['view_wordcensor'], - - 'S_TOPIC_SORT_DAYS' => $s_limit_topic_days, - 'S_TOPIC_SORT_KEY' => $s_sort_topic_key, - 'S_TOPIC_SORT_DIR' => $s_sort_topic_dir, - 'S_POST_SORT_DAYS' => $s_limit_post_days, - 'S_POST_SORT_KEY' => $s_sort_post_key, - 'S_POST_SORT_DIR' => $s_sort_post_dir, - - 'DATE_FORMAT' => $data['dateformat'], - 'S_DATEFORMAT_OPTIONS' => $dateformat_options, - 'S_CUSTOM_DATEFORMAT' => $s_custom, - 'DEFAULT_DATEFORMAT' => $config['default_dateformat'], - 'A_DEFAULT_DATEFORMAT' => addslashes($config['default_dateformat']), - - 'S_LANG_OPTIONS' => language_select($data['lang']), - 'S_STYLE_OPTIONS' => style_select($data['style']), - ); - - /** - * Modify users preferences data before assigning it to the template - * - * @event core.acp_users_prefs_modify_template_data - * @var array data Array with users preferences data - * @var array user_row Array with user data - * @var array user_prefs_data Array with users preferences data to be assigned to the template - * @since 3.1.0-b3 - */ - $vars = array('data', 'user_row', 'user_prefs_data'); - extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_template_data', compact($vars))); - - $template->assign_vars($user_prefs_data); - - break; - - case 'avatar': - - $avatars_enabled = false; - /** @var \phpbb\avatar\manager $phpbb_avatar_manager */ - $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); - - if ($config['allow_avatar']) - { - $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers(); - - // This is normalised data, without the user_ prefix - $avatar_data = \phpbb\avatar\manager::clean_row($user_row, 'user'); - - if ($submit) - { - if (check_form_key($form_name)) - { - $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); - - if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) - { - $driver = $phpbb_avatar_manager->get_driver($driver_name); - $result = $driver->process_form($request, $template, $user, $avatar_data, $error); - - if ($result && empty($error)) - { - // Success! Lets save the result in the database - $result = array( - 'user_avatar_type' => $driver_name, - 'user_avatar' => $result['avatar'], - 'user_avatar_width' => $result['avatar_width'], - 'user_avatar_height' => $result['avatar_height'], - ); - - /** - * 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; - - $db->sql_query($sql); - trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - } - } - else - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - } - - // Handle deletion of avatars - if ($request->is_set_post('avatar_delete')) - { - if (!confirm_box(true)) - { - confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( - 'avatar_delete' => true)) - ); - } - else - { - $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, USERS_TABLE, 'user_'); - - trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - } - - $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user_row['user_avatar_type'])); - - // Assign min and max values before generating avatar driver html - $template->assign_vars(array( - 'AVATAR_MIN_WIDTH' => $config['avatar_min_width'], - 'AVATAR_MAX_WIDTH' => $config['avatar_max_width'], - 'AVATAR_MIN_HEIGHT' => $config['avatar_min_height'], - 'AVATAR_MAX_HEIGHT' => $config['avatar_max_height'], - )); - - foreach ($avatar_drivers as $current_driver) - { - $driver = $phpbb_avatar_manager->get_driver($current_driver); - - $avatars_enabled = true; - $template->set_filenames(array( - 'avatar' => $driver->get_acp_template_name(), - )); - - if ($driver->prepare_form($request, $template, $user, $avatar_data, $error)) - { - $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); - $driver_upper = strtoupper($driver_name); - - $template->assign_block_vars('avatar_drivers', array( - 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), - 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), - - 'DRIVER' => $driver_name, - 'SELECTED' => $current_driver == $selected_driver, - 'OUTPUT' => $template->assign_display('avatar'), - )); - } - } - } - - // Avatar manager is not initialized if avatars are disabled - if (isset($phpbb_avatar_manager)) - { - // Replace "error" strings with their real, localised form - $error = $phpbb_avatar_manager->localize_errors($user, $error); - } - - $avatar = phpbb_get_user_avatar($user_row, 'USER_AVATAR', true); - - $template->assign_vars(array( - 'S_AVATAR' => true, - 'ERROR' => (!empty($error)) ? implode('
', $error) : '', - 'AVATAR' => (empty($avatar) ? '' : $avatar), - - 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', - - 'L_AVATAR_EXPLAIN' => $user->lang(($config['avatar_filesize'] == 0) ? 'AVATAR_EXPLAIN_NO_FILESIZE' : 'AVATAR_EXPLAIN', $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024), - - 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled), - )); - - break; - - case 'rank': - - if ($submit) - { - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $rank_id = $request->variable('user_rank', 0); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_rank = $rank_id - WHERE user_id = $user_id"; - $db->sql_query($sql); - - trigger_error($user->lang['USER_RANK_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - - $sql = 'SELECT * - FROM ' . RANKS_TABLE . ' - WHERE rank_special = 1 - ORDER BY rank_title'; - $result = $db->sql_query($sql); - - $s_rank_options = ''; - - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($user_row['user_rank'] && $row['rank_id'] == $user_row['user_rank']) ? ' selected="selected"' : ''; - $s_rank_options .= ''; - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_RANK' => true, - 'S_RANK_OPTIONS' => $s_rank_options) - ); - - break; - - case 'sig': - - if (!function_exists('display_custom_bbcodes')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $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; - - $bbcode_flags = ($enable_bbcode ? OPTION_FLAG_BBCODE : 0) + ($enable_smilies ? OPTION_FLAG_SMILIES : 0) + ($enable_urls ? OPTION_FLAG_LINKS : 0); - - $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 = ''; - - 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'; - } - } - - $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 (!$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' => $signature, - 'user_options' => $user_row['user_options'], - '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; - $db->sql_query($sql); - - trigger_error($user->lang['USER_SIG_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); - } - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - - if ($request->is_set_post('preview')) - { - $decoded_message = generate_text_for_edit($signature, $bbcode_uid, $bbcode_flags); - } - - /** @var \phpbb\controller\helper $controller_helper */ - $controller_helper = $phpbb_container->get('controller.helper'); - - $template->assign_vars(array( - 'S_SIGNATURE' => true, - - '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' => $user->lang(($config['allow_sig_bbcode'] ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '', ''), - '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'], - 'URL_STATUS' => ($config['allow_sig_links']) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], - - 'L_SIGNATURE_EXPLAIN' => $user->lang('SIGNATURE_EXPLAIN', (int) $config['max_sig_chars']), - - 'S_BBCODE_ALLOWED' => $config['allow_sig_bbcode'], - 'S_SMILIES_ALLOWED' => $config['allow_sig_smilies'], - 'S_BBCODE_IMG' => ($config['allow_sig_img']) ? true : false, - 'S_BBCODE_FLASH' => ($config['allow_sig_flash']) ? true : false, - 'S_LINKS_ALLOWED' => ($config['allow_sig_links']) ? true : false) - ); - - // Assigning custom bbcodes - display_custom_bbcodes(); - - break; - - case 'attach': - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - - $start = $request->variable('start', 0); - $deletemark = (isset($_POST['delmarked'])) ? true : false; - $marked = $request->variable('mark', array(0)); - - // Sort keys - $sort_key = $request->variable('sk', 'a'); - $sort_dir = $request->variable('sd', 'd'); - - if ($deletemark && count($marked)) - { - $sql = 'SELECT attach_id - FROM ' . ATTACHMENTS_TABLE . ' - WHERE poster_id = ' . $user_id . ' - AND is_orphan = 0 - AND ' . $db->sql_in_set('attach_id', $marked); - $result = $db->sql_query($sql); - - $marked = array(); - while ($row = $db->sql_fetchrow($result)) - { - $marked[] = $row['attach_id']; - } - $db->sql_freeresult($result); - } - - if ($deletemark && count($marked)) - { - if (confirm_box(true)) - { - $sql = 'SELECT real_filename - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', $marked); - $result = $db->sql_query($sql); - - $log_attachments = array(); - while ($row = $db->sql_fetchrow($result)) - { - $log_attachments[] = $row['real_filename']; - } - $db->sql_freeresult($result); - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $attachment_manager->delete('attach', $marked); - unset($attachment_manager); - - $message = (count($log_attachments) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED']; - - $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 . '&u=' . $user_id)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'delmarked' => true, - 'mark' => $marked)) - ); - } - } - - $sk_text = array('a' => $user->lang['SORT_FILENAME'], 'c' => $user->lang['SORT_EXTENSION'], 'd' => $user->lang['SORT_SIZE'], 'e' => $user->lang['SORT_DOWNLOADS'], 'f' => $user->lang['SORT_POST_TIME'], 'g' => $user->lang['SORT_TOPIC_TITLE']); - $sk_sql = array('a' => 'a.real_filename', 'c' => 'a.extension', 'd' => 'a.filesize', 'e' => 'a.download_count', 'f' => 'a.filetime', 'g' => 't.topic_title'); - - $sd_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - $s_sort_key = ''; - foreach ($sk_text as $key => $value) - { - $selected = ($sort_key == $key) ? ' selected="selected"' : ''; - $s_sort_key .= ''; - } - - $s_sort_dir = ''; - foreach ($sd_text as $key => $value) - { - $selected = ($sort_dir == $key) ? ' selected="selected"' : ''; - $s_sort_dir .= ''; - } - - if (!isset($sk_sql[$sort_key])) - { - $sort_key = 'a'; - } - - $order_by = $sk_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); - - $sql = 'SELECT COUNT(attach_id) as num_attachments - FROM ' . ATTACHMENTS_TABLE . " - WHERE poster_id = $user_id - AND is_orphan = 0"; - $result = $db->sql_query_limit($sql, 1); - $num_attachments = (int) $db->sql_fetchfield('num_attachments'); - $db->sql_freeresult($result); - - $sql = 'SELECT a.*, t.topic_title, p.message_subject as message_title - FROM ' . ATTACHMENTS_TABLE . ' a - 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) - WHERE a.poster_id = ' . $user_id . " - AND a.is_orphan = 0 - ORDER BY $order_by"; - $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['in_message']) - { - $view_topic = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&p={$row['post_msg_id']}"); - } - else - { - $view_topic = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}") . '#p' . $row['post_msg_id']; - } - - $template->assign_block_vars('attach', array( - 'REAL_FILENAME' => $row['real_filename'], - 'COMMENT' => nl2br($row['attach_comment']), - 'EXTENSION' => $row['extension'], - 'SIZE' => get_formatted_filesize($row['filesize']), - 'DOWNLOAD_COUNT' => $row['download_count'], - 'POST_TIME' => $user->format_date($row['filetime']), - 'TOPIC_TITLE' => ($row['in_message']) ? $row['message_title'] : $row['topic_title'], - - 'ATTACH_ID' => $row['attach_id'], - 'POST_ID' => $row['post_msg_id'], - 'TOPIC_ID' => $row['topic_id'], - - 'S_IN_MESSAGE' => $row['in_message'], - - 'U_DOWNLOAD' => append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&id=' . $row['attach_id']), - 'U_VIEW_TOPIC' => $view_topic) - ); - } - $db->sql_freeresult($result); - - $base_url = $this->u_action . "&u=$user_id&sk=$sort_key&sd=$sort_dir"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_attachments, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'S_ATTACHMENTS' => true, - 'S_SORT_KEY' => $s_sort_key, - 'S_SORT_DIR' => $s_sort_dir, - )); - - break; - - case 'groups': - - if (!function_exists('group_user_attributes')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $user->add_lang(array('groups', 'acp/groups')); - $group_id = $request->variable('g', 0); - - if ($group_id) - { - // Check the founder only entry for this group to make sure everything is well - $sql = 'SELECT group_founder_manage - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . $group_id; - $result = $db->sql_query($sql); - $founder_manage = (int) $db->sql_fetchfield('group_founder_manage'); - $db->sql_freeresult($result); - - if ($user->data['user_type'] != USER_FOUNDER && $founder_manage) - { - trigger_error($user->lang['NOT_ALLOWED_MANAGE_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - } - - switch ($action) - { - case 'demote': - case 'promote': - case 'default': - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!check_link_hash($request->variable('hash', ''), 'acp_users')) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - group_user_attributes($action, $group_id, $user_id); - - if ($action == 'default') - { - $user_row['group_id'] = $group_id; - } - break; - - case 'delete': - - if (confirm_box(true)) - { - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if ($error = group_user_del($group_id, $user_id)) - { - trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $error = array(); - - // The delete action was successful - therefore update the user row... - $sql = 'SELECT u.*, s.* - FROM ' . USERS_TABLE . ' u - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) - WHERE u.user_id = ' . $user_id . ' - ORDER BY s.session_time DESC'; - $result = $db->sql_query_limit($sql, 1); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'g' => $group_id)) - ); - } - - break; - - case 'approve': - - if (confirm_box(true)) - { - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - group_user_attributes($action, $group_id, $user_id); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'u' => $user_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'g' => $group_id)) - ); - } - - break; - } - - // Add user to group? - if ($submit) - { - - if (!check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - // Add user/s to group - if ($error = group_user_add($group_id, $user_id)) - { - trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); - } - - $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 - AND g.group_id = ug.group_id - ORDER BY g.group_type DESC, ug.user_pending ASC, g.group_name"; - $result = $db->sql_query($sql); - - $i = 0; - $group_data = $id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $type = ($row['group_type'] == GROUP_SPECIAL) ? 'special' : (($row['user_pending']) ? 'pending' : 'normal'); - - $group_data[$type][$i]['group_id'] = $row['group_id']; - $group_data[$type][$i]['group_name'] = $row['group_name']; - $group_data[$type][$i]['group_leader'] = ($row['group_leader']) ? 1 : 0; - - $id_ary[] = $row['group_id']; - - $i++; - } - $db->sql_freeresult($result); - - // Select box for other groups - $sql = 'SELECT group_id, group_name, group_type, group_founder_manage - FROM ' . GROUPS_TABLE . ' - ' . ((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); - - $s_group_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - if (!$config['coppa_enable'] && $row['group_name'] == 'REGISTERED_COPPA') - { - continue; - } - - // Do not display those groups not allowed to be managed - if ($user->data['user_type'] != USER_FOUNDER && $row['group_founder_manage']) - { - continue; - } - - $s_group_options .= '' . $group_helper->get_name($row['group_name']) . ''; - } - $db->sql_freeresult($result); - - $current_type = ''; - foreach ($group_data as $group_type => $data_ary) - { - if ($current_type != $group_type) - { - $template->assign_block_vars('group', array( - 'S_NEW_GROUP_TYPE' => true, - 'GROUP_TYPE' => $user->lang['USER_GROUP_' . strtoupper($group_type)]) - ); - } - - foreach ($data_ary as $data) - { - $template->assign_block_vars('group', array( - 'U_EDIT_GROUP' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=groups&mode=manage&action=edit&u=$user_id&g={$data['group_id']}&back_link=acp_users_groups"), - 'U_DEFAULT' => $this->u_action . "&action=default&u=$user_id&g=" . $data['group_id'] . '&hash=' . generate_link_hash('acp_users'), - 'U_DEMOTE_PROMOTE' => $this->u_action . '&action=' . (($data['group_leader']) ? 'demote' : 'promote') . "&u=$user_id&g=" . $data['group_id'] . '&hash=' . generate_link_hash('acp_users'), - 'U_DELETE' => $this->u_action . "&action=delete&u=$user_id&g=" . $data['group_id'], - 'U_APPROVE' => ($group_type == 'pending') ? $this->u_action . "&action=approve&u=$user_id&g=" . $data['group_id'] : '', - - 'GROUP_NAME' => $group_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, - 'S_NO_DEFAULT' => ($user_row['group_id'] != $data['group_id']) ? true : false, - 'S_SPECIAL_GROUP' => ($group_type == 'special') ? true : false, - ) - ); - } - } - - $template->assign_vars(array( - 'S_GROUPS' => true, - 'S_GROUP_OPTIONS' => $s_group_options) - ); - - break; - - case 'perm': - - if (!class_exists('auth_admin')) - { - include($phpbb_root_path . 'includes/acp/auth.' . $phpEx); - } - - $auth_admin = new auth_admin(); - - $user->add_lang('acp/permissions'); - add_permission_language(); - - $forum_id = $request->variable('f', 0); - - // Global Permissions - if (!$forum_id) - { - // Select auth options - $sql = 'SELECT auth_option, is_local, is_global - FROM ' . ACL_OPTIONS_TABLE . ' - WHERE auth_option ' . $db->sql_like_expression($db->get_any_char() . '_') . ' - AND is_global = 1 - ORDER BY auth_option'; - $result = $db->sql_query($sql); - - $hold_ary = array(); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary = $auth_admin->get_mask('view', $user_id, false, false, $row['auth_option'], 'global', ACL_NEVER); - $auth_admin->display_mask('view', $row['auth_option'], $hold_ary, 'user', false, false); - } - $db->sql_freeresult($result); - - unset($hold_ary); - } - else - { - $sql = 'SELECT auth_option, is_local, is_global - FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($db->get_any_char() . '_') . " - AND is_local = 1 - ORDER BY is_global DESC, auth_option"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary = $auth_admin->get_mask('view', $user_id, false, $forum_id, $row['auth_option'], 'local', ACL_NEVER); - $auth_admin->display_mask('view', $row['auth_option'], $hold_ary, 'user', true, false); - } - $db->sql_freeresult($result); - } - - $s_forum_options = ''; - $s_forum_options .= make_forum_select($forum_id, false, true, false, false, false); - - $template->assign_vars(array( - 'S_PERMISSIONS' => true, - - 'S_GLOBAL' => (!$forum_id) ? true : false, - 'S_FORUM_OPTIONS' => $s_forum_options, - - 'U_ACTION' => $this->u_action . '&u=' . $user_id, - 'U_USER_PERMISSIONS' => append_sid("{$phpbb_admin_path}index.$phpEx" ,'i=permissions&mode=setting_user_global&user_id[]=' . $user_id), - 'U_USER_FORUM_PERMISSIONS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions&mode=setting_user_local&user_id[]=' . $user_id)) - ); - - 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' => (count($error)) ? true : false, - 'ERROR_MSG' => (count($error)) ? implode('
', $error) : '') - ); - } - - /** - * Set option bit field for user options in a user row array. - * - * Optionset replacement for this module based on $user->optionset. - * - * @param array $user_row Row from the users table. - * @param int $key Option key, as defined in $user->keyoptions property. - * @param bool $value True to set the option, false to clear the option. - * @param int $data Current bit field value, or false to use $user_row['user_options'] - * @return int|bool If $data is false, the bit field is modified and - * written back to $user_row['user_options'], and - * return value is true if the bit field changed and - * false otherwise. If $data is not false, the new - * bitfield value is returned. - */ - function optionset(&$user_row, $key, $value, $data = false) - { - global $user; - - $var = ($data !== false) ? $data : $user_row['user_options']; - - $new_var = phpbb_optionset($user->keyoptions[$key], $value, $var); - - if ($data === false) - { - if ($new_var != $var) - { - $user_row['user_options'] = $new_var; - return true; - } - else - { - return false; - } - } - else - { - return $new_var; - } - } - - /** - * Get option bit field from user options in a user row array. - * - * Optionget replacement for this module based on $user->optionget. - * - * @param array $user_row Row from the users table. - * @param int $key option key, as defined in $user->keyoptions property. - * @param int $data bit field value to use, or false to use $user_row['user_options'] - * @return bool true if the option is set in the bit field, false otherwise - */ - function optionget(&$user_row, $key, $data = false) - { - global $user; - - $var = ($data !== false) ? $data : $user_row['user_options']; - return phpbb_optionget($user->keyoptions[$key], $var); - } -} diff --git a/install/update/old/includes/acp/auth.php b/install/update/old/includes/acp/auth.php deleted file mode 100644 index b414a31..0000000 --- a/install/update/old/includes/acp/auth.php +++ /dev/null @@ -1,1323 +0,0 @@ - -* @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; -} - -/** -* ACP Permission/Auth class -*/ -class auth_admin extends \phpbb\auth\auth -{ - /** - * Init auth settings - */ - function __construct() - { - global $db, $cache; - - if (($this->acl_options = $cache->get('_acl_options')) === false) - { - $sql = 'SELECT auth_option_id, auth_option, is_global, is_local - FROM ' . ACL_OPTIONS_TABLE . ' - ORDER BY auth_option_id'; - $result = $db->sql_query($sql); - - $global = $local = 0; - $this->acl_options = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['is_global']) - { - $this->acl_options['global'][$row['auth_option']] = $global++; - } - - if ($row['is_local']) - { - $this->acl_options['local'][$row['auth_option']] = $local++; - } - - $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id']; - $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option']; - } - $db->sql_freeresult($result); - - $cache->put('_acl_options', $this->acl_options); - } - } - - /** - * Get permission mask - * This function only supports getting permissions of one type (for example a_) - * - * @param set|view $mode defines the permissions we get, view gets effective permissions (checking user AND group permissions), set only gets the user or group permission set alone - * @param mixed $user_id user ids to search for (a user_id or a group_id has to be specified at least) - * @param mixed $group_id group ids to search for, return group related settings (a user_id or a group_id has to be specified at least) - * @param mixed $forum_id forum_ids to search for. Defining a forum id also means getting local settings - * @param string $auth_option the auth_option defines the permission setting to look for (a_ for example) - * @param local|global $scope the scope defines the permission scope. If local, a forum_id is additionally required - * @param ACL_NEVER|ACL_NO|ACL_YES $acl_fill defines the mode those permissions not set are getting filled with - */ - function get_mask($mode, $user_id = false, $group_id = false, $forum_id = false, $auth_option = false, $scope = false, $acl_fill = ACL_NEVER) - { - global $db, $user; - - $hold_ary = array(); - $view_user_mask = ($mode == 'view' && $group_id === false) ? true : false; - - if ($auth_option === false || $scope === false) - { - return array(); - } - - $acl_user_function = ($mode == 'set') ? 'acl_user_raw_data' : 'acl_raw_data'; - - if (!$view_user_mask) - { - if ($forum_id !== false) - { - $hold_ary = ($group_id !== false) ? $this->acl_group_raw_data($group_id, $auth_option . '%', $forum_id) : $this->$acl_user_function($user_id, $auth_option . '%', $forum_id); - } - else - { - $hold_ary = ($group_id !== false) ? $this->acl_group_raw_data($group_id, $auth_option . '%', ($scope == 'global') ? 0 : false) : $this->$acl_user_function($user_id, $auth_option . '%', ($scope == 'global') ? 0 : false); - } - } - - // Make sure hold_ary is filled with every setting (prevents missing forums/users/groups) - $ug_id = ($group_id !== false) ? ((!is_array($group_id)) ? array($group_id) : $group_id) : ((!is_array($user_id)) ? array($user_id) : $user_id); - $forum_ids = ($forum_id !== false) ? ((!is_array($forum_id)) ? array($forum_id) : $forum_id) : (($scope == 'global') ? array(0) : array()); - - // Only those options we need - $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' && !count($forum_ids)) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql, 120); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = (int) $row['forum_id']; - } - $db->sql_freeresult($result); - } - - if ($view_user_mask) - { - $auth2 = null; - - $sql = 'SELECT user_id, user_permissions, user_type - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $ug_id); - $result = $db->sql_query($sql); - - while ($userdata = $db->sql_fetchrow($result)) - { - if ($user->data['user_id'] != $userdata['user_id']) - { - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($userdata); - } - else - { - global $auth; - $auth2 = &$auth; - } - - $hold_ary[$userdata['user_id']] = array(); - foreach ($forum_ids as $f_id) - { - $hold_ary[$userdata['user_id']][$f_id] = array(); - foreach ($compare_options as $option) - { - $hold_ary[$userdata['user_id']][$f_id][$option] = $auth2->acl_get($option, $f_id); - } - } - } - $db->sql_freeresult($result); - - unset($userdata); - unset($auth2); - } - - foreach ($ug_id as $_id) - { - if (!isset($hold_ary[$_id])) - { - $hold_ary[$_id] = array(); - } - - foreach ($forum_ids as $f_id) - { - if (!isset($hold_ary[$_id][$f_id])) - { - $hold_ary[$_id][$f_id] = array(); - } - } - } - - // Now, we need to fill the gaps with $acl_fill. ;) - - // Now switch back to keys - if (count($compare_options)) - { - $compare_options = array_combine($compare_options, array_fill(1, count($compare_options), $acl_fill)); - } - - // Defining the user-function here to save some memory - $return_acl_fill = function () use ($acl_fill) - { - return $acl_fill; - }; - - // Actually fill the gaps - if (count($hold_ary)) - { - foreach ($hold_ary as $ug_id => $row) - { - foreach ($row as $id => $options) - { - // Do not include the global auth_option - unset($options[$auth_option]); - - // Not a "fine" solution, but at all it's a 1-dimensional - // array_diff_key function filling the resulting array values with zeros - // The differences get merged into $hold_ary (all permissions having $acl_fill set) - $hold_ary[$ug_id][$id] = array_merge($options, - - array_map($return_acl_fill, - array_flip( - array_diff( - array_keys($compare_options), array_keys($options) - ) - ) - ) - ); - } - } - } - else - { - $hold_ary[($group_id !== false) ? $group_id : $user_id][(int) $forum_id] = $compare_options; - } - - return $hold_ary; - } - - /** - * Get permission mask for roles - * This function only supports getting masks for one role - */ - function get_role_mask($role_id) - { - global $db; - - $hold_ary = array(); - - // Get users having this role set... - $sql = 'SELECT user_id, forum_id - FROM ' . ACL_USERS_TABLE . ' - WHERE auth_role_id = ' . $role_id . ' - ORDER BY forum_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary[$row['forum_id']]['users'][] = $row['user_id']; - } - $db->sql_freeresult($result); - - // Now grab groups... - $sql = 'SELECT group_id, forum_id - FROM ' . ACL_GROUPS_TABLE . ' - WHERE auth_role_id = ' . $role_id . ' - ORDER BY forum_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary[$row['forum_id']]['groups'][] = $row['group_id']; - } - $db->sql_freeresult($result); - - return $hold_ary; - } - - /** - * Display permission mask (assign to template) - */ - function display_mask($mode, $permission_type, &$hold_ary, $user_mode = 'user', $local = false, $group_display = true) - { - 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'; - $tpl_category = 'category'; - $tpl_mask = 'mask'; - - $l_acl_type = $phpbb_permissions->get_type_lang($permission_type, (($local) ? 'local' : 'global')); - - // Allow trace for viewing permissions and in user mode - $show_trace = ($mode == 'view' && $user_mode == 'user') ? true : false; - - // Get names - if ($user_mode == 'user') - { - $sql = 'SELECT user_id as ug_id, username as ug_name - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary)) . ' - ORDER BY username_clean ASC'; - } - else - { - $sql = 'SELECT group_id as ug_id, group_name as ug_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', array_keys($hold_ary)) . ' - ORDER BY group_type DESC, group_name ASC'; - } - $result = $db->sql_query($sql); - - $ug_names_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $ug_names_ary[$row['ug_id']] = ($user_mode == 'user') ? $row['ug_name'] : $group_helper->get_name($row['ug_name']); - } - $db->sql_freeresult($result); - - // Get used forums - $forum_ids = array(); - foreach ($hold_ary as $ug_id => $row) - { - $forum_ids = array_merge($forum_ids, array_keys($row)); - } - $forum_ids = array_unique($forum_ids); - - $forum_names_ary = array(); - if ($local) - { - $forum_names_ary = make_forum_select(false, false, true, false, false, false, true); - - // Remove the disabled ones, since we do not create an option field here... - foreach ($forum_names_ary as $key => $value) - { - if (!$value['disabled']) - { - continue; - } - unset($forum_names_ary[$key]); - } - } - else - { - $forum_names_ary[0] = $l_acl_type; - } - - // Get available roles - $sql = 'SELECT * - FROM ' . ACL_ROLES_TABLE . " - WHERE role_type = '" . $db->sql_escape($permission_type) . "' - ORDER BY role_order ASC"; - $result = $db->sql_query($sql); - - $roles = array(); - while ($row = $db->sql_fetchrow($result)) - { - $roles[$row['role_id']] = $row; - } - $db->sql_freeresult($result); - - $cur_roles = $this->acl_role_data($user_mode, $permission_type, array_keys($hold_ary)); - - // Build js roles array (role data assignments) - $s_role_js_array = ''; - - if (count($roles)) - { - $s_role_js_array = array(); - - // Make sure every role (even if empty) has its array defined - foreach ($roles as $_role_id => $null) - { - $s_role_js_array[$_role_id] = "\n" . 'role_options[' . $_role_id . '] = new Array();' . "\n"; - } - - $sql = 'SELECT r.role_id, o.auth_option, r.auth_setting - FROM ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' o - WHERE o.auth_option_id = r.auth_option_id - AND ' . $db->sql_in_set('r.role_id', array_keys($roles)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $flag = substr($row['auth_option'], 0, strpos($row['auth_option'], '_') + 1); - if ($flag == $row['auth_option']) - { - continue; - } - - $s_role_js_array[$row['role_id']] .= 'role_options[' . $row['role_id'] . '][\'' . addslashes($row['auth_option']) . '\'] = ' . $row['auth_setting'] . '; '; - } - $db->sql_freeresult($result); - - $s_role_js_array = implode('', $s_role_js_array); - } - - $template->assign_var('S_ROLE_JS_ARRAY', $s_role_js_array); - unset($s_role_js_array); - - // Now obtain memberships - $user_groups_default = $user_groups_custom = array(); - if ($user_mode == 'user' && $group_display) - { - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE . ' - ORDER BY group_type DESC, group_name ASC'; - $result = $db->sql_query($sql); - - $groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $groups[$row['group_id']] = $row; - } - $db->sql_freeresult($result); - - $memberships = group_memberships(false, array_keys($hold_ary), false); - - // User is not a member of any group? Bad admin, bad bad admin... - if ($memberships) - { - foreach ($memberships as $row) - { - $user_groups_default[$row['user_id']][] = $group_helper->get_name($groups[$row['group_id']]['group_name']); - } - } - unset($memberships, $groups); - } - - // 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 (count($forum_ids) == 1 || ($local && count($ug_names_ary) > 1)) - { - $hold_ary_temp = $hold_ary; - $hold_ary = array(); - foreach ($hold_ary_temp as $ug_id => $row) - { - foreach ($forum_names_ary as $forum_id => $forum_row) - { - if (isset($row[$forum_id])) - { - $hold_ary[$forum_id][$ug_id] = $row[$forum_id]; - } - } - } - unset($hold_ary_temp); - - foreach ($hold_ary as $forum_id => $forum_array) - { - $content_array = $categories = array(); - $this->build_permission_array($hold_ary[$forum_id], $content_array, $categories, array_keys($ug_names_ary)); - - $template->assign_block_vars($tpl_pmask, 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'], - - 'CATEGORIES' => implode('', $categories), - - 'L_ACL_TYPE' => $l_acl_type, - - 'S_LOCAL' => ($local) ? true : false, - 'S_GLOBAL' => (!$local) ? true : false, - 'S_NUM_CATS' => count($categories), - 'S_VIEW' => ($mode == 'view') ? true : false, - 'S_NUM_OBJECTS' => count($content_array), - 'S_USER_MODE' => ($user_mode == 'user') ? true : false, - 'S_GROUP_MODE' => ($user_mode == 'group') ? true : false) - ); - - @reset($content_array); - while (list($ug_id, $ug_array) = each($content_array)) - { - // 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)) - { - $role_description = (!empty($user->lang[$role_row['role_description']])) ? $user->lang[$role_row['role_description']] : nl2br($role_row['role_description']); - $role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name']; - - $title = ($role_description) ? ' title="' . $role_description . '"' : ''; - $s_role_options .= ''; - - $role_options[] = array( - 'ID' => $role_id, - 'ROLE_NAME' => $role_name, - 'TITLE' => $role_description, - 'SELECTED' => $role_id == $current_role_id, - ); - } - - if ($s_role_options) - { - $s_role_options = '' . $s_role_options; - } - - if (!$current_role_id && $mode != 'view') - { - $s_custom_permissions = false; - - foreach ($ug_array as $key => $value) - { - if ($value['S_NEVER'] || $value['S_YES']) - { - $s_custom_permissions = true; - break; - } - } - } - else - { - $s_custom_permissions = false; - } - - $template->assign_block_vars($tpl_pmask . '.' . $tpl_fmask, array( - 'NAME' => $ug_names_ary[$ug_id], - 'UG_ID' => $ug_id, - 'S_ROLE_OPTIONS' => $s_role_options, - 'S_CUSTOM' => $s_custom_permissions, - '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); - - unset($content_array[$ug_id]); - } - - unset($hold_ary[$forum_id]); - } - } - else - { - foreach ($ug_names_ary as $ug_id => $ug_name) - { - if (!isset($hold_ary[$ug_id])) - { - continue; - } - - $content_array = $categories = array(); - $this->build_permission_array($hold_ary[$ug_id], $content_array, $categories, array_keys($forum_names_ary)); - - $template->assign_block_vars($tpl_pmask, array( - 'NAME' => $ug_name, - 'CATEGORIES' => implode('', $categories), - - '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' => count($categories), - 'S_VIEW' => ($mode == 'view') ? true : false, - 'S_NUM_OBJECTS' => count($content_array), - 'S_USER_MODE' => ($user_mode == 'user') ? true : false, - 'S_GROUP_MODE' => ($user_mode == 'group') ? true : false) - ); - - @reset($content_array); - while (list($forum_id, $forum_array) = each($content_array)) - { - // 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); - while (list($role_id, $role_row) = each($roles)) - { - $role_description = (!empty($user->lang[$role_row['role_description']])) ? $user->lang[$role_row['role_description']] : nl2br($role_row['role_description']); - $role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name']; - - $title = ($role_description) ? ' title="' . $role_description . '"' : ''; - $s_role_options .= ''; - - $role_options[] = array( - 'ID' => $role_id, - 'ROLE_NAME' => $role_name, - 'TITLE' => $role_description, - 'SELECTED' => $role_id == $current_role_id, - ); - } - - if ($s_role_options) - { - $s_role_options = '' . $s_role_options; - } - - if (!$current_role_id && $mode != 'view') - { - $s_custom_permissions = false; - - foreach ($forum_array as $key => $value) - { - if ($value['S_NEVER'] || $value['S_YES']) - { - $s_custom_permissions = true; - break; - } - } - } - else - { - $s_custom_permissions = false; - } - - $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_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); - } - - unset($hold_ary[$ug_id], $ug_names_ary[$ug_id]); - } - } - } - - /** - * Display permission mask for roles - */ - function display_role_mask(&$hold_ary) - { - global $db, $template, $user, $phpbb_root_path, $phpEx; - global $phpbb_container; - - 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 . ' - WHERE ' . $db->sql_in_set('forum_id', array_keys($hold_ary)) . ' - ORDER BY left_id'; - $result = $db->sql_query($sql); - - // If the role is used globally, then reflect that - $forum_names = (isset($hold_ary[0])) ? array(0 => '') : array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_names[$row['forum_id']] = $row['forum_name']; - } - $db->sql_freeresult($result); - - foreach ($forum_names as $forum_id => $forum_name) - { - $auth_ary = $hold_ary[$forum_id]; - - $template->assign_block_vars('role_mask', array( - 'NAME' => ($forum_id == 0) ? $user->lang['GLOBAL_MASK'] : $forum_name, - 'FORUM_ID' => $forum_id) - ); - - if (isset($auth_ary['users']) && count($auth_ary['users'])) - { - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $auth_ary['users']) . ' - ORDER BY username_clean ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('role_mask.users', array( - 'USER_ID' => $row['user_id'], - 'USERNAME' => get_username_string('username', $row['user_id'], $row['username']), - 'U_PROFILE' => get_username_string('profile', $row['user_id'], $row['username']), - )); - } - $db->sql_freeresult($result); - } - - if (isset($auth_ary['groups']) && count($auth_ary['groups'])) - { - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', $auth_ary['groups']) . ' - ORDER BY group_type ASC, group_name'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('role_mask.groups', array( - 'GROUP_ID' => $row['group_id'], - 'GROUP_NAME' => $group_helper->get_name($row['group_name']), - 'U_PROFILE' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=group&g={$row['group_id']}")) - ); - } - $db->sql_freeresult($result); - } - } - } - - /** - * NOTE: this function is not in use atm - * Add a new option to the list ... $options is a hash of form -> - * $options = array( - * 'local' => array('option1', 'option2', ...), - * 'global' => array('optionA', 'optionB', ...) - * ); - */ - function acl_add_option($options) - { - global $db, $cache; - - if (!is_array($options)) - { - return false; - } - - $cur_options = array(); - - // Determine current options - $sql = 'SELECT auth_option, is_global, is_local - FROM ' . ACL_OPTIONS_TABLE . ' - ORDER BY auth_option_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $cur_options[$row['auth_option']] = ($row['is_global'] && $row['is_local']) ? 'both' : (($row['is_global']) ? 'global' : 'local'); - } - $db->sql_freeresult($result); - - // Here we need to insert new options ... this requires discovering whether - // an options is global, local or both and whether we need to add an permission - // set flag (x_) - $new_options = array('local' => array(), 'global' => array()); - - foreach ($options as $type => $option_ary) - { - $option_ary = array_unique($option_ary); - - foreach ($option_ary as $option_value) - { - $new_options[$type][] = $option_value; - - $flag = substr($option_value, 0, strpos($option_value, '_') + 1); - - if (!in_array($flag, $new_options[$type])) - { - $new_options[$type][] = $flag; - } - } - } - unset($options); - - $options = array(); - $options['local'] = array_diff($new_options['local'], $new_options['global']); - $options['global'] = array_diff($new_options['global'], $new_options['local']); - $options['both'] = array_intersect($new_options['local'], $new_options['global']); - - // Now check which options to add/update - $add_options = $update_options = array(); - - // First local ones... - foreach ($options as $type => $option_ary) - { - foreach ($option_ary as $option) - { - if (!isset($cur_options[$option])) - { - $add_options[] = array( - 'auth_option' => (string) $option, - 'is_global' => ($type == 'global' || $type == 'both') ? 1 : 0, - 'is_local' => ($type == 'local' || $type == 'both') ? 1 : 0 - ); - - continue; - } - - // Else, update existing entry if it is changed... - if ($type === $cur_options[$option]) - { - continue; - } - - // New type is always both: - // If is now both, we set both. - // If it was global the new one is local and we need to set it to both - // If it was local the new one is global and we need to set it to both - $update_options[] = $option; - } - } - - if (!empty($add_options)) - { - $db->sql_multi_insert(ACL_OPTIONS_TABLE, $add_options); - } - - if (!empty($update_options)) - { - $sql = 'UPDATE ' . ACL_OPTIONS_TABLE . ' - SET is_global = 1, is_local = 1 - WHERE ' . $db->sql_in_set('auth_option', $update_options); - $db->sql_query($sql); - } - - $cache->destroy('_acl_options'); - $this->acl_clear_prefetch(); - - // 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->__construct(); - - return true; - } - - /** - * Set a user or group ACL record - */ - function acl_set($ug_type, $forum_id, $ug_id, $auth, $role_id = 0, $clear_prefetch = true) - { - global $db; - - // One or more forums - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - // One or more users - if (!is_array($ug_id)) - { - $ug_id = array($ug_id); - } - - $ug_id_sql = $db->sql_in_set($ug_type . '_id', array_map('intval', $ug_id)); - $forum_sql = $db->sql_in_set('forum_id', array_map('intval', $forum_id)); - - // Instead of updating, inserting, removing we just remove all current settings and re-set everything... - $table = ($ug_type == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE; - $id_field = $ug_type . '_id'; - - // Get any flags as required - reset($auth); - $flag = key($auth); - $flag = substr($flag, 0, strpos($flag, '_') + 1); - - // This ID (the any-flag) is set if one or more permissions are true... - $any_option_id = (int) $this->acl_options['id'][$flag]; - - // Remove any-flag from auth ary - if (isset($auth[$flag])) - { - unset($auth[$flag]); - } - - // Remove current auth options... - $auth_option_ids = array((int) $any_option_id); - foreach ($auth as $auth_option => $auth_setting) - { - $auth_option_ids[] = (int) $this->acl_options['id'][$auth_option]; - } - - $sql = "DELETE FROM $table - WHERE $forum_sql - AND $ug_id_sql - AND " . $db->sql_in_set('auth_option_id', $auth_option_ids); - $db->sql_query($sql); - - // Remove those having a role assigned... the correct type of course... - $sql = 'SELECT role_id - FROM ' . ACL_ROLES_TABLE . " - WHERE role_type = '" . $db->sql_escape($flag) . "'"; - $result = $db->sql_query($sql); - - $role_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $role_ids[] = $row['role_id']; - } - $db->sql_freeresult($result); - - if (count($role_ids)) - { - $sql = "DELETE FROM $table - WHERE $forum_sql - AND $ug_id_sql - AND auth_option_id = 0 - AND " . $db->sql_in_set('auth_role_id', $role_ids); - $db->sql_query($sql); - } - - // Ok, include the any-flag if one or more auth options are set to yes... - foreach ($auth as $auth_option => $setting) - { - if ($setting == ACL_YES && (!isset($auth[$flag]) || $auth[$flag] == ACL_NEVER)) - { - $auth[$flag] = ACL_YES; - } - } - - $sql_ary = array(); - foreach ($forum_id as $forum) - { - $forum = (int) $forum; - - if ($role_id) - { - foreach ($ug_id as $id) - { - $sql_ary[] = array( - $id_field => (int) $id, - 'forum_id' => (int) $forum, - 'auth_option_id' => 0, - 'auth_setting' => 0, - 'auth_role_id' => (int) $role_id, - ); - } - } - else - { - foreach ($auth as $auth_option => $setting) - { - $auth_option_id = (int) $this->acl_options['id'][$auth_option]; - - if ($setting != ACL_NO) - { - foreach ($ug_id as $id) - { - $sql_ary[] = array( - $id_field => (int) $id, - 'forum_id' => (int) $forum, - 'auth_option_id' => (int) $auth_option_id, - 'auth_setting' => (int) $setting - ); - } - } - } - } - } - - $db->sql_multi_insert($table, $sql_ary); - - if ($clear_prefetch) - { - $this->acl_clear_prefetch(); - } - } - - /** - * Set a role-specific ACL record - */ - function acl_set_role($role_id, $auth) - { - global $db; - - // Get any-flag as required - reset($auth); - $flag = key($auth); - $flag = substr($flag, 0, strpos($flag, '_') + 1); - - // Remove any-flag from auth ary - if (isset($auth[$flag])) - { - unset($auth[$flag]); - } - - // Re-set any flag... - foreach ($auth as $auth_option => $setting) - { - if ($setting == ACL_YES && (!isset($auth[$flag]) || $auth[$flag] == ACL_NEVER)) - { - $auth[$flag] = ACL_YES; - } - } - - $sql_ary = array(); - foreach ($auth as $auth_option => $setting) - { - $auth_option_id = (int) $this->acl_options['id'][$auth_option]; - - if ($setting != ACL_NO) - { - $sql_ary[] = array( - 'role_id' => (int) $role_id, - 'auth_option_id' => (int) $auth_option_id, - 'auth_setting' => (int) $setting - ); - } - } - - // If no data is there, we set the any-flag to ACL_NEVER... - if (!count($sql_ary)) - { - $sql_ary[] = array( - 'role_id' => (int) $role_id, - 'auth_option_id' => (int) $this->acl_options['id'][$flag], - 'auth_setting' => ACL_NEVER - ); - } - - // Remove current auth options... - $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . ' - WHERE role_id = ' . $role_id; - $db->sql_query($sql); - - // Now insert the new values - $db->sql_multi_insert(ACL_ROLES_DATA_TABLE, $sql_ary); - - $this->acl_clear_prefetch(); - } - - /** - * Remove local permission - */ - function acl_delete($mode, $ug_id = false, $forum_id = false, $permission_type = false) - { - global $db; - - if ($ug_id === false && $forum_id === false) - { - return; - } - - $option_id_ary = array(); - $table = ($mode == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE; - $id_field = $mode . '_id'; - - $where_sql = array(); - - if ($forum_id !== false) - { - $where_sql[] = (!is_array($forum_id)) ? 'forum_id = ' . (int) $forum_id : $db->sql_in_set('forum_id', array_map('intval', $forum_id)); - } - - if ($ug_id !== false) - { - $where_sql[] = (!is_array($ug_id)) ? $id_field . ' = ' . (int) $ug_id : $db->sql_in_set($id_field, array_map('intval', $ug_id)); - } - - // There seem to be auth options involved, therefore we need to go through the list and make sure we capture roles correctly - if ($permission_type !== false) - { - // Get permission type - $sql = 'SELECT auth_option, auth_option_id - FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char()); - $result = $db->sql_query($sql); - - $auth_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $option_id_ary[] = $row['auth_option_id']; - $auth_id_ary[$row['auth_option']] = ACL_NO; - } - $db->sql_freeresult($result); - - // First of all, lets grab the items having roles with the specified auth options assigned - $sql = "SELECT auth_role_id, $id_field, forum_id - FROM $table, " . ACL_ROLES_TABLE . " r - WHERE auth_role_id <> 0 - AND auth_role_id = r.role_id - AND r.role_type = '{$permission_type}' - AND " . implode(' AND ', $where_sql) . ' - ORDER BY auth_role_id'; - $result = $db->sql_query($sql); - - $cur_role_auth = array(); - while ($row = $db->sql_fetchrow($result)) - { - $cur_role_auth[$row['auth_role_id']][$row['forum_id']][] = $row[$id_field]; - } - $db->sql_freeresult($result); - - // Get role data for resetting data - 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 - WHERE ao.auth_option_id = rd.auth_option_id - AND ' . $db->sql_in_set('rd.role_id', array_keys($cur_role_auth)); - $result = $db->sql_query($sql); - - $auth_settings = array(); - while ($row = $db->sql_fetchrow($result)) - { - // We need to fill all auth_options, else setting it will fail... - if (!isset($auth_settings[$row['role_id']])) - { - $auth_settings[$row['role_id']] = $auth_id_ary; - } - $auth_settings[$row['role_id']][$row['auth_option']] = $row['auth_setting']; - } - $db->sql_freeresult($result); - - // Set the options - foreach ($cur_role_auth as $role_id => $auth_row) - { - foreach ($auth_row as $f_id => $ug_row) - { - $this->acl_set($mode, $f_id, $ug_row, $auth_settings[$role_id], 0, false); - } - } - } - } - - // Now, normally remove permissions... - if ($permission_type !== false) - { - $where_sql[] = $db->sql_in_set('auth_option_id', array_map('intval', $option_id_ary)); - } - - $sql = "DELETE FROM $table - WHERE " . implode(' AND ', $where_sql); - $db->sql_query($sql); - - $this->acl_clear_prefetch(); - } - - /** - * Assign category to template - * used by display_mask() - */ - function assign_cat_array(&$category_array, $tpl_cat, $tpl_mask, $ug_id, $forum_id, $s_view, $show_trace = false) - { - global $template, $phpbb_admin_path, $phpEx, $phpbb_container; - - /* @var $phpbb_permissions \phpbb\permissions */ - $phpbb_permissions = $phpbb_container->get('acl.permissions'); - - @reset($category_array); - while (list($cat, $cat_array) = each($category_array)) - { - if (!$phpbb_permissions->category_defined($cat)) - { - continue; - } - - $template->assign_block_vars($tpl_cat, array( - 'S_YES' => ($cat_array['S_YES'] && !$cat_array['S_NEVER'] && !$cat_array['S_NO']) ? true : false, - 'S_NEVER' => ($cat_array['S_NEVER'] && !$cat_array['S_YES'] && !$cat_array['S_NO']) ? true : false, - 'S_NO' => ($cat_array['S_NO'] && !$cat_array['S_NEVER'] && !$cat_array['S_YES']) ? true : false, - - 'CAT_NAME' => $phpbb_permissions->get_category_lang($cat), - )); - - /* Sort permissions by name (more naturaly and user friendly than sorting by a primary key) - * Commented out due to it's memory consumption and time needed - * - $key_array = array_intersect(array_keys($user->lang), array_map(create_function('$a', 'return "acl_" . $a;'), array_keys($cat_array['permissions']))); - $values_array = $cat_array['permissions']; - - $cat_array['permissions'] = array(); - - foreach ($key_array as $key) - { - $key = str_replace('acl_', '', $key); - $cat_array['permissions'][$key] = $values_array[$key]; - } - unset($key_array, $values_array); -*/ - @reset($cat_array['permissions']); - while (list($permission, $allowed) = each($cat_array['permissions'])) - { - if (!$phpbb_permissions->permission_defined($permission)) - { - continue; - } - - if ($s_view) - { - $template->assign_block_vars($tpl_cat . '.' . $tpl_mask, array( - 'S_YES' => ($allowed == ACL_YES) ? true : false, - 'S_NEVER' => ($allowed == ACL_NEVER) ? true : false, - - 'UG_ID' => $ug_id, - 'FORUM_ID' => $forum_id, - 'FIELD_NAME' => $permission, - 'S_FIELD_NAME' => 'setting[' . $ug_id . '][' . $forum_id . '][' . $permission . ']', - - 'U_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission") : '', - 'UA_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '', - - 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission), - )); - } - else - { - $template->assign_block_vars($tpl_cat . '.' . $tpl_mask, array( - 'S_YES' => ($allowed == ACL_YES) ? true : false, - 'S_NEVER' => ($allowed == ACL_NEVER) ? true : false, - 'S_NO' => ($allowed == ACL_NO) ? true : false, - - 'UG_ID' => $ug_id, - 'FORUM_ID' => $forum_id, - 'FIELD_NAME' => $permission, - 'S_FIELD_NAME' => 'setting[' . $ug_id . '][' . $forum_id . '][' . $permission . ']', - - 'U_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission") : '', - 'UA_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '', - - 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission), - )); - } - } - } - } - - /** - * Building content array from permission rows with explicit key ordering - * used by display_mask() - */ - function build_permission_array(&$permission_row, &$content_array, &$categories, $key_sort_array) - { - global $phpbb_container; - - /* @var $phpbb_permissions \phpbb\permissions */ - $phpbb_permissions = $phpbb_container->get('acl.permissions'); - - foreach ($key_sort_array as $forum_id) - { - if (!isset($permission_row[$forum_id])) - { - continue; - } - - $permissions = $permission_row[$forum_id]; - ksort($permissions); - - @reset($permissions); - while (list($permission, $auth_setting) = each($permissions)) - { - $cat = $phpbb_permissions->get_permission_category($permission); - - // Build our categories array - if (!isset($categories[$cat])) - { - $categories[$cat] = $phpbb_permissions->get_category_lang($cat); - } - - // Build our content array - if (!isset($content_array[$forum_id])) - { - $content_array[$forum_id] = array(); - } - - if (!isset($content_array[$forum_id][$cat])) - { - $content_array[$forum_id][$cat] = array( - 'S_YES' => false, - 'S_NEVER' => false, - 'S_NO' => false, - 'permissions' => array(), - ); - } - - $content_array[$forum_id][$cat]['S_YES'] |= ($auth_setting == ACL_YES) ? true : false; - $content_array[$forum_id][$cat]['S_NEVER'] |= ($auth_setting == ACL_NEVER) ? true : false; - $content_array[$forum_id][$cat]['S_NO'] |= ($auth_setting == ACL_NO) ? true : false; - - $content_array[$forum_id][$cat]['permissions'][$permission] = $auth_setting; - } - } - } - - /** - * Use permissions from another user. This transferes a permission set from one user to another. - * The other user is always able to revert back to his permission set. - * This function does not check for lower/higher permissions, it is possible for the user to gain - * "more" permissions by this. - * Admin permissions will not be copied. - */ - function ghost_permissions($from_user_id, $to_user_id) - { - global $db; - - if ($to_user_id == ANONYMOUS) - { - return false; - } - - $hold_ary = $this->acl_raw_data_single_user($from_user_id); - - // Key 0 in $hold_ary are global options, all others are forum_ids - - // We disallow copying admin permissions - foreach ($this->acl_options['global'] as $opt => $id) - { - if (strpos($opt, 'a_') === 0) - { - $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_NEVER; - } - } - - // Force a_switchperm to be allowed - $hold_ary[0][$this->acl_options['id']['a_switchperm']] = ACL_YES; - - $user_permissions = $this->build_bitstring($hold_ary); - - if (!$user_permissions) - { - return false; - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_permissions = '" . $db->sql_escape($user_permissions) . "', - user_perm_from = $from_user_id - WHERE user_id = " . $to_user_id; - $db->sql_query($sql); - - return true; - } -} diff --git a/install/update/old/includes/bbcode.php b/install/update/old/includes/bbcode.php deleted file mode 100644 index c31b63a..0000000 --- a/install/update/old/includes/bbcode.php +++ /dev/null @@ -1,707 +0,0 @@ - -* @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; -} - -/** -* BBCode class -*/ -class bbcode -{ - var $bbcode_uid = ''; - var $bbcode_bitfield = ''; - var $bbcode_cache = array(); - var $bbcode_template = array(); - - var $bbcodes = array(); - - var $template_bitfield; - - /** - * 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_set_bitfield($bitfield = '') - { - if ($bitfield) - { - $this->bbcode_bitfield = $bitfield; - $this->bbcode_cache_init(); - } - } - - /** - * Second pass bbcodes - */ - function bbcode_second_pass(&$message, $bbcode_uid = '', $bbcode_bitfield = false) - { - if ($bbcode_uid) - { - $this->bbcode_uid = $bbcode_uid; - } - - if ($bbcode_bitfield !== false) - { - $this->bbcode_bitfield = $bbcode_bitfield; - - // Init those added with a new bbcode_bitfield (already stored codes will not get parsed again) - $this->bbcode_cache_init(); - } - - if (!$this->bbcode_bitfield) - { - // Remove the uid from tags that have not been transformed into HTML - if ($this->bbcode_uid) - { - $message = str_replace(':' . $this->bbcode_uid, '', $message); - } - - return; - } - - $str = array('search' => array(), 'replace' => array()); - $preg = array('search' => array(), 'replace' => array()); - - $bitfield = new bitfield($this->bbcode_bitfield); - $bbcodes_set = $bitfield->get_all_set(); - - $undid_bbcode_specialchars = false; - foreach ($bbcodes_set as $bbcode_id) - { - if (!empty($this->bbcode_cache[$bbcode_id])) - { - foreach ($this->bbcode_cache[$bbcode_id] as $type => $array) - { - foreach ($array as $search => $replace) - { - ${$type}['search'][] = str_replace('$uid', $this->bbcode_uid, $search); - ${$type}['replace'][] = $replace; - } - - if (count($str['search'])) - { - $message = str_replace($str['search'], $str['replace'], $message); - $str = array('search' => array(), 'replace' => array()); - } - - if (count($preg['search'])) - { - // we need to turn the entities back into their original form to allow the - // search patterns to work properly - if (!$undid_bbcode_specialchars) - { - $message = str_replace(array(':', '.'), array(':', '.'), $message); - $undid_bbcode_specialchars = true; - } - - 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()); - } - } - } - } - - // Remove the uid from tags that have not been transformed into HTML - $message = str_replace(':' . $this->bbcode_uid, '', $message); - } - - /** - * Init bbcode cache - * - * requires: $this->bbcode_bitfield - * sets: $this->bbcode_cache with bbcode templates needed for bbcode_bitfield - */ - function bbcode_cache_init() - { - 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_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'); - } - - $bbcode_ids = $rowset = $sql = array(); - - $bitfield = new bitfield($this->bbcode_bitfield); - $bbcodes_set = $bitfield->get_all_set(); - - foreach ($bbcodes_set as $bbcode_id) - { - if (isset($this->bbcode_cache[$bbcode_id])) - { - // do not try to re-cache it if it's already in - continue; - } - $bbcode_ids[] = $bbcode_id; - - if ($bbcode_id > NUM_CORE_BBCODES) - { - $sql[] = $bbcode_id; - } - } - - if (count($sql)) - { - global $db; - - $sql = 'SELECT * - FROM ' . BBCODES_TABLE . ' - WHERE ' . $db->sql_in_set('bbcode_id', $sql); - $result = $db->sql_query($sql, 3600); - - while ($row = $db->sql_fetchrow($result)) - { - // To circumvent replacing newlines with
for the generated html, - // we use carriage returns here. They are later changed back to newlines - $row['bbcode_tpl'] = str_replace("\n", "\r", $row['bbcode_tpl']); - $row['second_pass_replace'] = str_replace("\n", "\r", $row['second_pass_replace']); - - $rowset[$row['bbcode_id']] = $row; - } - $db->sql_freeresult($result); - } - - // To perform custom second pass in extension, use $this->bbcode_second_pass_by_extension() - // method which accepts variable number of parameters - foreach ($bbcode_ids as $bbcode_id) - { - switch ($bbcode_id) - { - case BBCODE_ID_QUOTE: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[/quote:$uid]' => $this->bbcode_tpl('quote_close', $bbcode_id) - ), - 'preg' => array( - '#\[quote(?:="(.*?)")?:$uid\]((?!\[quote(?:=".*?")?:$uid\]).)?#is' => function ($match) { - if (!isset($match[2])) - { - $match[2] = ''; - } - - return $this->bbcode_second_pass_quote($match[1], $match[2]); - }, - ) - ); - break; - - case BBCODE_ID_B: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[b:$uid]' => $this->bbcode_tpl('b_open', $bbcode_id), - '[/b:$uid]' => $this->bbcode_tpl('b_close', $bbcode_id), - ) - ); - break; - - case BBCODE_ID_I: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[i:$uid]' => $this->bbcode_tpl('i_open', $bbcode_id), - '[/i:$uid]' => $this->bbcode_tpl('i_close', $bbcode_id), - ) - ); - break; - - case BBCODE_ID_URL: - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[url:$uid\]((.*?))\[/url:$uid\]#s' => $this->bbcode_tpl('url', $bbcode_id), - '#\[url=([^\[]+?):$uid\](.*?)\[/url:$uid\]#s' => $this->bbcode_tpl('url', $bbcode_id), - ) - ); - break; - - case BBCODE_ID_IMG: - if ($user->optionget('viewimg')) - { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[img:$uid\](.*?)\[/img:$uid\]#s' => $this->bbcode_tpl('img', $bbcode_id), - ) - ); - } - else - { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[img:$uid\](.*?)\[/img:$uid\]#s' => str_replace('$2', '[ img ]', $this->bbcode_tpl('url', $bbcode_id, true)), - ) - ); - } - break; - - case BBCODE_ID_SIZE: - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[size=([\-\+]?\d+):$uid\](.*?)\[/size:$uid\]#s' => $this->bbcode_tpl('size', $bbcode_id), - ) - ); - break; - - 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), - ) - ); - break; - - case BBCODE_ID_U: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[u:$uid]' => $this->bbcode_tpl('u_open', $bbcode_id), - '[/u:$uid]' => $this->bbcode_tpl('u_close', $bbcode_id), - ) - ); - break; - - case BBCODE_ID_CODE: - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[code(?:=([a-z]+))?:$uid\](.*?)\[/code:$uid\]#is' => function ($match) { - return $this->bbcode_second_pass_code($match[1], $match[2]); - }, - ) - ); - break; - - 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\]#' => function ($match) { - return $this->bbcode_list($match[1]); - }, - ), - 'str' => array( - '[list:$uid]' => $this->bbcode_tpl('ulist_open_default', $bbcode_id), - '[/list:u:$uid]' => $this->bbcode_tpl('ulist_close', $bbcode_id), - '[/list:o:$uid]' => $this->bbcode_tpl('olist_close', $bbcode_id), - '[*:$uid]' => $this->bbcode_tpl('listitem', $bbcode_id), - '[/*:$uid]' => $this->bbcode_tpl('listitem_close', $bbcode_id), - '[/*:m:$uid]' => $this->bbcode_tpl('listitem_close', $bbcode_id) - ), - ); - break; - - case BBCODE_ID_EMAIL: - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[email:$uid\]((.*?))\[/email:$uid\]#is' => $this->bbcode_tpl('email', $bbcode_id), - '#\[email=([^\[]+):$uid\](.*?)\[/email:$uid\]#is' => $this->bbcode_tpl('email', $bbcode_id) - ) - ); - break; - - case BBCODE_ID_FLASH: - if ($user->optionget('viewflash')) - { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#' => $this->bbcode_tpl('flash', $bbcode_id), - ) - ); - } - else - { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array( - '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#' => str_replace('$1', '$3', str_replace('$2', '[ flash ]', $this->bbcode_tpl('url', $bbcode_id, true))) - ) - ); - } - break; - - case BBCODE_ID_ATTACH: - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array( - '[/attachment:$uid]' => $this->bbcode_tpl('inline_attachment_close', $bbcode_id) - ), - 'preg' => array( - '#\[attachment=([0-9]+):$uid\]#' => $this->bbcode_tpl('inline_attachment_open', $bbcode_id) - ) - ); - break; - - default: - if (isset($rowset[$bbcode_id])) - { - if ($this->template_bitfield->get($bbcode_id)) - { - // The bbcode requires a custom template to be loaded - if (!$bbcode_tpl = $this->bbcode_tpl($rowset[$bbcode_id]['bbcode_tag'], $bbcode_id)) - { - // For some reason, the required template seems not to be available, use the default template - $bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl']; - } - else - { - // In order to use templates with custom bbcodes we need - // to replace all {VARS} to corresponding backreferences - // Note that backreferences are numbered from bbcode_match - if (preg_match_all('/\{(URL|LOCAL_URL|EMAIL|TEXT|SIMPLETEXT|INTTEXT|IDENTIFIER|COLOR|NUMBER)[0-9]*\}/', $rowset[$bbcode_id]['bbcode_match'], $m)) - { - foreach ($m[0] as $i => $tok) - { - $bbcode_tpl = str_replace($tok, '$' . ($i + 1), $bbcode_tpl); - } - } - } - } - else - { - // Default template - $bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl']; - } - - // Replace {L_*} lang strings - $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'])) - { - // The custom BBCode requires second-pass pattern replacements - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl) - ); - } - else - { - $this->bbcode_cache[$bbcode_id] = array( - 'str' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl) - ); - } - } - else - { - $this->bbcode_cache[$bbcode_id] = false; - } - break; - } - } - - $bbcode_cache = $this->bbcode_cache; - $bbcode_bitfield = $this->bbcode_bitfield; - $bbcode_uid = $this->bbcode_uid; - - /** - * Use this event to modify the bbcode_cache - * - * @event core.bbcode_cache_init_end - * @var array bbcode_cache The array of cached search and replace patterns of bbcodes - * @var string bbcode_bitfield The bbcode bitfield - * @var string bbcode_uid The bbcode uid - * @since 3.1.3-RC1 - */ - $vars = array('bbcode_cache', 'bbcode_bitfield', 'bbcode_uid'); - extract($phpbb_dispatcher->trigger_event('core.bbcode_cache_init_end', compact($vars))); - - $this->bbcode_cache = $bbcode_cache; - $this->bbcode_bitfield = $bbcode_bitfield; - $this->bbcode_uid = $bbcode_uid; - } - - /** - * Return bbcode template - */ - function bbcode_tpl($tpl_name, $bbcode_id = -1, $skip_bitfield_check = false) - { - static $bbcode_hardtpl = array(); - if (empty($bbcode_hardtpl)) - { - global $user; - - $bbcode_hardtpl = array( - 'b_open' => '', - 'b_close' => '', - 'i_open' => '', - 'i_close' => '', - 'u_open' => '', - 'u_close' => '', - 'img' => '' . $user->lang['IMAGE'] . '', - 'size' => '$2', - 'color' => '$2', - 'email' => '$2' - ); - } - - if ($bbcode_id != -1 && !$skip_bitfield_check && !$this->template_bitfield->get($bbcode_id)) - { - return (isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false; - } - - if (empty($this->bbcode_template)) - { - if (($tpl = file_get_contents($this->template_filename)) === false) - { - trigger_error('Could not load bbcode template', E_USER_ERROR); - } - - // replace \ with \\ and then ' with \'. - $tpl = str_replace('\\', '\\\\', $tpl); - $tpl = str_replace("'", "\'", $tpl); - - // strip newlines and indent - $tpl = preg_replace("/\n[\n\r\s\t]*/", '', $tpl); - - // Turn template blocks into PHP assignment statements for the values of $bbcode_tpl.. - $this->bbcode_template = array(); - - // Capture the BBCode template matches - // Allow phpBB template or the Twig syntax - $matches = (preg_match_all('#(.*?)#', $tpl, $match)) ?: - preg_match_all('#{% for (.*?) in .*? %}(.*?){% endfor %}#s', $tpl, $match); - - for ($i = 0; $i < $matches; $i++) - { - if (empty($match[1][$i])) - { - continue; - } - - $this->bbcode_template[$match[1][$i]] = $this->bbcode_tpl_replace($match[1][$i], $match[2][$i]); - } - } - - return (isset($this->bbcode_template[$tpl_name])) ? $this->bbcode_template[$tpl_name] : ((isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false); - } - - /** - * Return bbcode template replacement - */ - function bbcode_tpl_replace($tpl_name, $tpl) - { - global $user; - - static $replacements = array( - 'quote_username_open' => array('{USERNAME}' => '$1'), - 'color' => array('{COLOR}' => '$1', '{TEXT}' => '$2'), - 'size' => array('{SIZE}' => '$1', '{TEXT}' => '$2'), - 'img' => array('{URL}' => '$1'), - 'flash' => array('{WIDTH}' => '$1', '{HEIGHT}' => '$2', '{URL}' => '$3'), - 'url' => array('{URL}' => '$1', '{DESCRIPTION}' => '$2'), - 'email' => array('{EMAIL}' => '$1', '{DESCRIPTION}' => '$2') - ); - - $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])) - { - $tpl = strtr($tpl, $replacements[$tpl_name]); - } - - return trim($tpl); - } - - /** - * Second parse list bbcode - */ - function bbcode_list($type) - { - if ($type == '') - { - $tpl = 'ulist_open_default'; - $type = 'default'; - } - else if ($type == 'i') - { - $tpl = 'olist_open'; - $type = 'lower-roman'; - } - else if ($type == 'I') - { - $tpl = 'olist_open'; - $type = 'upper-roman'; - } - else if (preg_match('#^(disc|circle|square)$#i', $type)) - { - $tpl = 'ulist_open'; - $type = strtolower($type); - } - else if (preg_match('#^[a-z]$#', $type)) - { - $tpl = 'olist_open'; - $type = 'lower-alpha'; - } - else if (preg_match('#[A-Z]#', $type)) - { - $tpl = 'olist_open'; - $type = 'upper-alpha'; - } - else if (is_numeric($type)) - { - $tpl = 'olist_open'; - $type = 'decimal'; - } - else - { - $tpl = 'olist_open'; - $type = 'decimal'; - } - - return str_replace('{LIST_TYPE}', $type, $this->bbcode_tpl($tpl)); - } - - /** - * Second parse quote tag - */ - function bbcode_second_pass_quote($username, $quote) - { - // when using the /e modifier, preg_replace slashes double-quotes but does not - // seem to slash anything else - $quote = str_replace('\"', '"', $quote); - $username = str_replace('\"', '"', $username); - - // remove newline at the beginning - if ($quote == "\n") - { - $quote = ''; - } - - $quote = (($username) ? str_replace('$1', $username, $this->bbcode_tpl('quote_username_open')) : $this->bbcode_tpl('quote_open')) . $quote; - - return $quote; - } - - /** - * Second parse code tag - */ - function bbcode_second_pass_code($type, $code) - { - // when using the /e modifier, preg_replace slashes double-quotes but does not - // seem to slash anything else - $code = str_replace('\"', '"', $code); - - switch ($type) - { - case 'php': - // Not the english way, but valid because of hardcoded syntax highlighting - if (strpos($code, '
') === 0) - { - $code = substr($code, 41); - } - - // no break; - - default: - $code = str_replace("\t", '   ', $code); - $code = str_replace(' ', '  ', $code); - $code = str_replace(' ', '  ', $code); - $code = str_replace("\n ", "\n ", $code); - - // keep space at the beginning - if (!empty($code) && $code[0] == ' ') - { - $code = ' ' . substr($code, 1); - } - - // remove newline at the beginning - if (!empty($code) && $code[0] == "\n") - { - $code = substr($code, 1); - } - break; - } - - $code = $this->bbcode_tpl('code_open') . $code . $this->bbcode_tpl('code_close'); - - return $code; - } - - /** - * Function to perform custom bbcode second pass by extensions - * can be used to assign bbcode pattern replacement - * Example: '#\[list=([^\[]+):$uid\]#e' => "\$this->bbcode_second_pass_by_extension('\$1')" - * - * Accepts variable number of parameters - * - * @return mixed Second pass result - */ - function bbcode_second_pass_by_extension() - { - global $phpbb_dispatcher; - - $return = false; - $params_array = func_get_args(); - - /** - * Event to perform bbcode second pass with - * the custom validating methods provided by extensions - * - * @event core.bbcode_second_pass_by_extension - * @var array params_array Array with the function parameters - * @var mixed return Second pass result to return - * - * @since 3.1.5-RC1 - */ - $vars = array('params_array', 'return'); - extract($phpbb_dispatcher->trigger_event('core.bbcode_second_pass_by_extension', compact($vars))); - - return $return; - } -} diff --git a/install/update/old/includes/compatibility_globals.php b/install/update/old/includes/compatibility_globals.php deleted file mode 100644 index ad394e3..0000000 --- a/install/update/old/includes/compatibility_globals.php +++ /dev/null @@ -1,84 +0,0 @@ - -* @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; -} - -/** - * 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); - - /* @var $user \phpbb\user */ - $user = $phpbb_container->get('user'); - - /* @var \phpbb\language\language $language */ - $language = $phpbb_container->get('language'); - - /* @var $auth \phpbb\auth\auth */ - $auth = $phpbb_container->get('auth'); - - /* @var $db \phpbb\db\driver\driver_interface */ - $db = $phpbb_container->get('dbal.conn'); - - // 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); - - /* @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/install/update/old/includes/constants.php b/install/update/old/includes/constants.php deleted file mode 100644 index 3effe6c..0000000 --- a/install/update/old/includes/constants.php +++ /dev/null @@ -1,316 +0,0 @@ - -* @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; -} - -/** -* valid external constants: -* PHPBB_MSG_HANDLER -* PHPBB_DB_NEW_LINK -* PHPBB_ROOT_PATH -* PHPBB_ADMIN_PATH -*/ - -// phpBB Version -@define('PHPBB_VERSION', '3.2.7'); - -// QA-related -// define('PHPBB_QA', 1); - -// User related -define('ANONYMOUS', 1); - -define('USER_ACTIVATION_NONE', 0); -define('USER_ACTIVATION_SELF', 1); -define('USER_ACTIVATION_ADMIN', 2); -define('USER_ACTIVATION_DISABLE', 3); - -define('AVATAR_UPLOAD', 1); -define('AVATAR_REMOTE', 2); -define('AVATAR_GALLERY', 3); - -define('USER_NORMAL', 0); -define('USER_INACTIVE', 1); -define('USER_IGNORE', 2); -define('USER_FOUNDER', 3); - -define('INACTIVE_REGISTER', 1); // Newly registered account -define('INACTIVE_PROFILE', 2); // Profile details changed -define('INACTIVE_MANUAL', 3); // Account deactivated by administrator -define('INACTIVE_REMIND', 4); // Forced user account reactivation - -// ACL -define('ACL_NEVER', 0); -define('ACL_YES', 1); -define('ACL_NO', -1); - -// Login error codes -define('LOGIN_CONTINUE', 1); -define('LOGIN_BREAK', 2); -define('LOGIN_SUCCESS', 3); -define('LOGIN_SUCCESS_CREATE_PROFILE', 20); -define('LOGIN_SUCCESS_LINK_PROFILE', 21); -define('LOGIN_ERROR_USERNAME', 10); -define('LOGIN_ERROR_PASSWORD', 11); -define('LOGIN_ERROR_ACTIVE', 12); -define('LOGIN_ERROR_ATTEMPTS', 13); -define('LOGIN_ERROR_EXTERNAL_AUTH', 14); -define('LOGIN_ERROR_PASSWORD_CONVERT', 15); - -// Maximum login attempts -// The value is arbitrary, but it has to fit into the user_login_attempts field. -define('LOGIN_ATTEMPTS_MAX', 100); - -// Group settings -define('GROUP_OPEN', 0); -define('GROUP_CLOSED', 1); -define('GROUP_HIDDEN', 2); -define('GROUP_SPECIAL', 3); -define('GROUP_FREE', 4); - -// Forum/Topic states -define('FORUM_CAT', 0); -define('FORUM_POST', 1); -define('FORUM_LINK', 2); -define('ITEM_UNLOCKED', 0); -define('ITEM_LOCKED', 1); -define('ITEM_MOVED', 2); - -define('ITEM_UNAPPROVED', 0); // => has not yet been approved -define('ITEM_APPROVED', 1); // => has been approved, and has not been soft deleted -define('ITEM_DELETED', 2); // => has been soft deleted -define('ITEM_REAPPROVE', 3); // => has been edited and needs to be re-approved - -// Forum Flags -define('FORUM_FLAG_LINK_TRACK', 1); -define('FORUM_FLAG_PRUNE_POLL', 2); -define('FORUM_FLAG_PRUNE_ANNOUNCE', 4); -define('FORUM_FLAG_PRUNE_STICKY', 8); -define('FORUM_FLAG_ACTIVE_TOPICS', 16); -define('FORUM_FLAG_POST_REVIEW', 32); -define('FORUM_FLAG_QUICK_REPLY', 64); - -// Forum Options... sequential order. Modifications should begin at number 10 (number 29 is maximum) -define('FORUM_OPTION_FEED_NEWS', 1); -define('FORUM_OPTION_FEED_EXCLUDE', 2); - -// Optional text flags -define('OPTION_FLAG_BBCODE', 1); -define('OPTION_FLAG_SMILIES', 2); -define('OPTION_FLAG_LINKS', 4); - -// Topic types -define('POST_NORMAL', 0); -define('POST_STICKY', 1); -define('POST_ANNOUNCE', 2); -define('POST_GLOBAL', 3); - -// Lastread types -define('TRACK_NORMAL', 0); -define('TRACK_POSTED', 1); - -// Notify methods -define('NOTIFY_EMAIL', 0); -define('NOTIFY_IM', 1); -define('NOTIFY_BOTH', 2); - -// Notify status -define('NOTIFY_YES', 0); -define('NOTIFY_NO', 1); - -// Email Priority Settings -define('MAIL_LOW_PRIORITY', 4); -define('MAIL_NORMAL_PRIORITY', 3); -define('MAIL_HIGH_PRIORITY', 2); - -// Log types -define('LOG_ADMIN', 0); -define('LOG_MOD', 1); -define('LOG_CRITICAL', 2); -define('LOG_USERS', 3); - -// Private messaging - Do NOT change these values -define('PRIVMSGS_HOLD_BOX', -4); -define('PRIVMSGS_NO_BOX', -3); -define('PRIVMSGS_OUTBOX', -2); -define('PRIVMSGS_SENTBOX', -1); -define('PRIVMSGS_INBOX', 0); - -// Full Folder Actions -define('FULL_FOLDER_NONE', -3); -define('FULL_FOLDER_DELETE', -2); -define('FULL_FOLDER_HOLD', -1); - -// Download Modes - Attachments -define('INLINE_LINK', 1); -// This mode is only used internally to allow modders extending the attachment functionality -define('PHYSICAL_LINK', 2); - -// Confirm types -define('CONFIRM_REG', 1); -define('CONFIRM_LOGIN', 2); -define('CONFIRM_POST', 3); -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 - @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 - @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); - -// Smiley hard limit -define('SMILEY_LIMIT', 1000); - -// Magic url types -define('MAGIC_URL_EMAIL', 1); -define('MAGIC_URL_FULL', 2); -define('MAGIC_URL_LOCAL', 3); -define('MAGIC_URL_WWW', 4); - -// Profile Field Types -define('FIELD_INT', 1); -define('FIELD_STRING', 2); -define('FIELD_TEXT', 3); -define('FIELD_BOOL', 4); -define('FIELD_DROPDOWN', 5); -define('FIELD_DATE', 6); - -// referer validation -define('REFERER_VALIDATE_NONE', 0); -define('REFERER_VALIDATE_HOST', 1); -define('REFERER_VALIDATE_PATH', 2); - -// phpbb_chmod() permissions -@define('CHMOD_ALL', 7); -@define('CHMOD_READ', 4); -@define('CHMOD_WRITE', 2); -@define('CHMOD_EXECUTE', 1); - -// Captcha code length -define('CAPTCHA_MIN_CHARS', 4); -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'); -define('ACL_ROLES_DATA_TABLE', $table_prefix . 'acl_roles_data'); -define('ACL_ROLES_TABLE', $table_prefix . 'acl_roles'); -define('ACL_USERS_TABLE', $table_prefix . 'acl_users'); -define('ATTACHMENTS_TABLE', $table_prefix . 'attachments'); -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_TEXT_TABLE', $table_prefix . 'config_text'); -define('CONFIRM_TABLE', $table_prefix . 'confirm'); -define('DISALLOW_TABLE', $table_prefix . 'disallow'); -define('DRAFTS_TABLE', $table_prefix . 'drafts'); -define('EXT_TABLE', $table_prefix . 'ext'); -define('EXTENSIONS_TABLE', $table_prefix . 'extensions'); -define('EXTENSION_GROUPS_TABLE', $table_prefix . 'extension_groups'); -define('FORUMS_TABLE', $table_prefix . 'forums'); -define('FORUMS_ACCESS_TABLE', $table_prefix . 'forums_access'); -define('FORUMS_TRACK_TABLE', $table_prefix . 'forums_track'); -define('FORUMS_WATCH_TABLE', $table_prefix . 'forums_watch'); -define('GROUPS_TABLE', $table_prefix . 'groups'); -define('ICONS_TABLE', $table_prefix . 'icons'); -define('LANG_TABLE', $table_prefix . 'lang'); -define('LOG_TABLE', $table_prefix . 'log'); -define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts'); -define('MIGRATIONS_TABLE', $table_prefix . 'migrations'); -define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache'); -define('MODULES_TABLE', $table_prefix . 'modules'); -define('NOTIFICATION_TYPES_TABLE', $table_prefix . 'notification_types'); -define('NOTIFICATIONS_TABLE', $table_prefix . 'notifications'); -define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options'); -define('POLL_VOTES_TABLE', $table_prefix . 'poll_votes'); -define('POSTS_TABLE', $table_prefix . 'posts'); -define('PRIVMSGS_TABLE', $table_prefix . 'privmsgs'); -define('PRIVMSGS_FOLDER_TABLE', $table_prefix . 'privmsgs_folder'); -define('PRIVMSGS_RULES_TABLE', $table_prefix . 'privmsgs_rules'); -define('PRIVMSGS_TO_TABLE', $table_prefix . 'privmsgs_to'); -define('PROFILE_FIELDS_TABLE', $table_prefix . 'profile_fields'); -define('PROFILE_FIELDS_DATA_TABLE', $table_prefix . 'profile_fields_data'); -define('PROFILE_FIELDS_LANG_TABLE', $table_prefix . 'profile_fields_lang'); -define('PROFILE_LANG_TABLE', $table_prefix . 'profile_lang'); -define('RANKS_TABLE', $table_prefix . 'ranks'); -define('REPORTS_TABLE', $table_prefix . 'reports'); -define('REPORTS_REASONS_TABLE', $table_prefix . 'reports_reasons'); -define('SEARCH_RESULTS_TABLE', $table_prefix . 'search_results'); -define('SEARCH_WORDLIST_TABLE', $table_prefix . 'search_wordlist'); -define('SEARCH_WORDMATCH_TABLE', $table_prefix . 'search_wordmatch'); -define('SESSIONS_TABLE', $table_prefix . 'sessions'); -define('SESSIONS_KEYS_TABLE', $table_prefix . 'sessions_keys'); -define('SITELIST_TABLE', $table_prefix . 'sitelist'); -define('SMILIES_TABLE', $table_prefix . 'smilies'); -define('SPHINX_TABLE', $table_prefix . 'sphinx'); -define('STYLES_TABLE', $table_prefix . 'styles'); -define('STYLES_TEMPLATE_TABLE', $table_prefix . 'styles_template'); -define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data'); -define('STYLES_THEME_TABLE', $table_prefix . 'styles_theme'); -define('STYLES_IMAGESET_TABLE', $table_prefix . 'styles_imageset'); -define('STYLES_IMAGESET_DATA_TABLE',$table_prefix . 'styles_imageset_data'); -define('TEAMPAGE_TABLE', $table_prefix . 'teampage'); -define('TOPICS_TABLE', $table_prefix . 'topics'); -define('TOPICS_POSTED_TABLE', $table_prefix . 'topics_posted'); -define('TOPICS_TRACK_TABLE', $table_prefix . 'topics_track'); -define('TOPICS_WATCH_TABLE', $table_prefix . 'topics_watch'); -define('USER_GROUP_TABLE', $table_prefix . 'user_group'); -define('USER_NOTIFICATIONS_TABLE', $table_prefix . 'user_notifications'); -define('USERS_TABLE', $table_prefix . 'users'); -define('WARNINGS_TABLE', $table_prefix . 'warnings'); -define('WORDS_TABLE', $table_prefix . 'words'); -define('ZEBRA_TABLE', $table_prefix . 'zebra'); - -// Additional tables diff --git a/install/update/old/includes/diff/engine.php b/install/update/old/includes/diff/engine.php deleted file mode 100644 index 757fdad..0000000 --- a/install/update/old/includes/diff/engine.php +++ /dev/null @@ -1,555 +0,0 @@ - -* @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; -} - -/** -* Code from pear.php.net, Text_Diff-1.1.0 package -* http://pear.php.net/package/Text_Diff/ (native engine) -* -* Modified by phpBB Limited to meet our coding standards -* and being able to integrate into phpBB -* -* Class used internally by Text_Diff to actually compute the diffs. This -* class is implemented using native PHP code. -* -* The algorithm used here is mostly lifted from the perl module -* Algorithm::Diff (version 1.06) by Ned Konz, which is available at: -* http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip -* -* More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html -* -* Some ideas (and a bit of code) are taken from analyze.c, of GNU -* diffutils-2.7, which can be found at: -* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz -* -* Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from -* Geoffrey T. Dairiki . The original PHP version of this -* code was written by him, and is used/adapted with his permission. -* -* Copyright 2004-2008 The Horde Project (http://www.horde.org/) -* -* @author Geoffrey T. Dairiki -* @package diff -* -* @access private -*/ -class diff_engine -{ - /** - * If set to true we trim all lines before we compare them. This ensures that sole space/tab changes do not trigger diffs. - */ - var $skip_whitespace_changes = true; - - function diff(&$from_lines, &$to_lines, $preserve_cr = true) - { - // Remove empty lines... - // If preserve_cr is true, we basically only change \r\n and bare \r to \n to get the same carriage returns for both files - // If it is false, we try to only use \n once per line and ommit all empty lines to be able to get a proper data diff - - if (is_array($from_lines)) - { - $from_lines = implode("\n", $from_lines); - } - - if (is_array($to_lines)) - { - $to_lines = implode("\n", $to_lines); - } - - if ($preserve_cr) - { - $from_lines = explode("\n", str_replace("\r", "\n", str_replace("\r\n", "\n", $from_lines))); - $to_lines = explode("\n", str_replace("\r", "\n", str_replace("\r\n", "\n", $to_lines))); - } - else - { - $from_lines = explode("\n", preg_replace('#[\n\r]+#', "\n", $from_lines)); - $to_lines = explode("\n", preg_replace('#[\n\r]+#', "\n", $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); - - // Skip leading common lines. - for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) - { - if (trim($from_lines[$skip]) !== trim($to_lines[$skip])) - { - break; - } - $this->xchanged[$skip] = $this->ychanged[$skip] = false; - } - - // Skip trailing common lines. - $xi = $n_from; - $yi = $n_to; - - for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) - { - if (trim($from_lines[$xi]) !== trim($to_lines[$yi])) - { - break; - } - $this->xchanged[$xi] = $this->ychanged[$yi] = false; - } - - // Ignore lines which do not exist in both files. - for ($xi = $skip; $xi < $n_from - $endskip; $xi++) - { - if ($this->skip_whitespace_changes) $xhash[trim($from_lines[$xi])] = 1; else $xhash[$from_lines[$xi]] = 1; - } - - for ($yi = $skip; $yi < $n_to - $endskip; $yi++) - { - $line = ($this->skip_whitespace_changes) ? trim($to_lines[$yi]) : $to_lines[$yi]; - - if (($this->ychanged[$yi] = empty($xhash[$line]))) - { - continue; - } - $yhash[$line] = 1; - $this->yv[] = $line; - $this->yind[] = $yi; - } - - for ($xi = $skip; $xi < $n_from - $endskip; $xi++) - { - $line = ($this->skip_whitespace_changes) ? trim($from_lines[$xi]) : $from_lines[$xi]; - - if (($this->xchanged[$xi] = empty($yhash[$line]))) - { - continue; - } - $this->xv[] = $line; - $this->xind[] = $xi; - } - - // Find the LCS. - $this->_compareseq(0, count($this->xv), 0, count($this->yv)); - - // Merge edits when possible. - if ($this->skip_whitespace_changes) - { - $from_lines_clean = array_map('trim', $from_lines); - $to_lines_clean = array_map('trim', $to_lines); - - $this->_shift_boundaries($from_lines_clean, $this->xchanged, $this->ychanged); - $this->_shift_boundaries($to_lines_clean, $this->ychanged, $this->xchanged); - - unset($from_lines_clean, $to_lines_clean); - } - else - { - $this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged); - $this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged); - } - - // Compute the edit operations. - $edits = array(); - $xi = $yi = 0; - - while ($xi < $n_from || $yi < $n_to) - { - // Skip matching "snake". - $copy = array(); - - while ($xi < $n_from && $yi < $n_to && !$this->xchanged[$xi] && !$this->ychanged[$yi]) - { - $copy[] = $from_lines[$xi++]; - $yi++; - } - - if ($copy) - { - $edits[] = new diff_op_copy($copy); - } - - // Find deletes & adds. - $delete = array(); - while ($xi < $n_from && $this->xchanged[$xi]) - { - $delete[] = $from_lines[$xi++]; - } - - $add = array(); - while ($yi < $n_to && $this->ychanged[$yi]) - { - $add[] = $to_lines[$yi++]; - } - - if ($delete && $add) - { - $edits[] = new diff_op_change($delete, $add); - } - else if ($delete) - { - $edits[] = new diff_op_delete($delete); - } - else if ($add) - { - $edits[] = new diff_op_add($add); - } - } - - return $edits; - } - - /** - * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF, - * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized segments. - * - * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of - * NCHUNKS+1 (X, Y) indexes giving the diving points between sub - * sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1), - * the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) == - * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM). - * - * This function assumes that the first lines of the specified portions of - * the two files do not match, and likewise that the last lines do not - * match. The caller must trim matching lines from the beginning and end - * of the portions it is going to specify. - */ - function _diag($xoff, $xlim, $yoff, $ylim, $nchunks) - { - $flip = false; - - if ($xlim - $xoff > $ylim - $yoff) - { - // Things seems faster (I'm not sure I understand why) when the shortest sequence is in X. - $flip = true; - list($xoff, $xlim, $yoff, $ylim) = array($yoff, $ylim, $xoff, $xlim); - } - - if ($flip) - { - for ($i = $ylim - 1; $i >= $yoff; $i--) - { - $ymatches[$this->xv[$i]][] = $i; - } - } - else - { - for ($i = $ylim - 1; $i >= $yoff; $i--) - { - $ymatches[$this->yv[$i]][] = $i; - } - } - - $this->lcs = 0; - $this->seq[0]= $yoff - 1; - $this->in_seq = array(); - $ymids[0] = array(); - - $numer = $xlim - $xoff + $nchunks - 1; - $x = $xoff; - - for ($chunk = 0; $chunk < $nchunks; $chunk++) - { - if ($chunk > 0) - { - for ($i = 0; $i <= $this->lcs; $i++) - { - $ymids[$i][$chunk - 1] = $this->seq[$i]; - } - } - - $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks); - - for (; $x < $x1; $x++) - { - $line = $flip ? $this->yv[$x] : $this->xv[$x]; - if (empty($ymatches[$line])) - { - continue; - } - $matches = $ymatches[$line]; - - reset($matches); - while (list(, $y) = each($matches)) - { - if (empty($this->in_seq[$y])) - { - $k = $this->_lcs_pos($y); - $ymids[$k] = $ymids[$k - 1]; - break; - } - } - - // no reset() here - while (list(, $y) = each($matches)) - { - if ($y > $this->seq[$k - 1]) - { - // Optimization: this is a common case: next match is just replacing previous match. - $this->in_seq[$this->seq[$k]] = false; - $this->seq[$k] = $y; - $this->in_seq[$y] = 1; - } - else if (empty($this->in_seq[$y])) - { - $k = $this->_lcs_pos($y); - $ymids[$k] = $ymids[$k - 1]; - } - } - } - } - - $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff); - $ymid = $ymids[$this->lcs]; - - for ($n = 0; $n < $nchunks - 1; $n++) - { - $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks); - $y1 = $ymid[$n] + 1; - $seps[] = $flip ? array($y1, $x1) : array($x1, $y1); - } - $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim); - - return array($this->lcs, $seps); - } - - function _lcs_pos($ypos) - { - $end = $this->lcs; - - if ($end == 0 || $ypos > $this->seq[$end]) - { - $this->seq[++$this->lcs] = $ypos; - $this->in_seq[$ypos] = 1; - return $this->lcs; - } - - $beg = 1; - while ($beg < $end) - { - $mid = (int)(($beg + $end) / 2); - if ($ypos > $this->seq[$mid]) - { - $beg = $mid + 1; - } - else - { - $end = $mid; - } - } - - $this->in_seq[$this->seq[$end]] = false; - $this->seq[$end] = $ypos; - $this->in_seq[$ypos] = 1; - - return $end; - } - - /** - * Finds LCS of two sequences. - * - * The results are recorded in the vectors $this->{x,y}changed[], by - * storing a 1 in the element for each line that is an insertion or - * deletion (ie. is not in the LCS). - * - * The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1. - * - * Note that XLIM, YLIM are exclusive bounds. All line numbers are - * origin-0 and discarded lines are not counted. - */ - function _compareseq($xoff, $xlim, $yoff, $ylim) - { - // Slide down the bottom initial diagonal. - while ($xoff < $xlim && $yoff < $ylim && $this->xv[$xoff] == $this->yv[$yoff]) - { - ++$xoff; - ++$yoff; - } - - // Slide up the top initial diagonal. - while ($xlim > $xoff && $ylim > $yoff && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) - { - --$xlim; - --$ylim; - } - - if ($xoff == $xlim || $yoff == $ylim) - { - $lcs = 0; - } - else - { - // This is ad hoc but seems to work well. - // $nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); - // $nchunks = max(2,min(8,(int)$nchunks)); - $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1; - list($lcs, $seps) = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks); - } - - if ($lcs == 0) - { - // X and Y sequences have no common subsequence: mark all changed. - while ($yoff < $ylim) - { - $this->ychanged[$this->yind[$yoff++]] = 1; - } - - while ($xoff < $xlim) - { - $this->xchanged[$this->xind[$xoff++]] = 1; - } - } - else - { - // Use the partitions to split this problem into subproblems. - reset($seps); - $pt1 = $seps[0]; - - while ($pt2 = next($seps)) - { - $this->_compareseq($pt1[0], $pt2[0], $pt1[1], $pt2[1]); - $pt1 = $pt2; - } - } - } - - /** - * Adjusts inserts/deletes of identical lines to join changes as much as possible. - * - * We do something when a run of changed lines include a line at one end - * and has an excluded, identical line at the other. We are free to - * choose which identical line is included. 'compareseq' usually chooses - * the one at the beginning, but usually it is cleaner to consider the - * following identical line to be the "change". - * - * This is extracted verbatim from analyze.c (GNU diffutils-2.7). - */ - function _shift_boundaries($lines, &$changed, $other_changed) - { - $i = 0; - $j = 0; - - $len = count($lines); - $other_len = count($other_changed); - - while (1) - { - // Scan forward to find the beginning of another run of - // changes. Also keep track of the corresponding point in the other file. - // - // Throughout this code, $i and $j are adjusted together so that - // the first $i elements of $changed and the first $j elements of - // $other_changed both contain the same number of zeros (unchanged lines). - // - // Furthermore, $j is always kept so that $j == $other_len or $other_changed[$j] == false. - while ($j < $other_len && $other_changed[$j]) - { - $j++; - } - - while ($i < $len && ! $changed[$i]) - { - $i++; - $j++; - - while ($j < $other_len && $other_changed[$j]) - { - $j++; - } - } - - if ($i == $len) - { - break; - } - - $start = $i; - - // Find the end of this run of changes. - while (++$i < $len && $changed[$i]) - { - continue; - } - - do - { - // Record the length of this run of changes, so that we can later determine whether the run has grown. - $runlength = $i - $start; - - // Move the changed region back, so long as the previous unchanged line matches the last changed one. - // This merges with previous changed regions. - while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) - { - $changed[--$start] = 1; - $changed[--$i] = false; - - while ($start > 0 && $changed[$start - 1]) - { - $start--; - } - - while ($other_changed[--$j]) - { - continue; - } - } - - // Set CORRESPONDING to the end of the changed run, at the last point where it corresponds to a changed run in the - // other file. CORRESPONDING == LEN means no such point has been found. - $corresponding = $j < $other_len ? $i : $len; - - // Move the changed region forward, so long as the first changed line matches the following unchanged one. - // This merges with following changed regions. - // Do this second, so that if there are no merges, the changed region is moved forward as far as possible. - while ($i < $len && $lines[$start] == $lines[$i]) - { - $changed[$start++] = false; - $changed[$i++] = 1; - - while ($i < $len && $changed[$i]) - { - $i++; - } - - $j++; - if ($j < $other_len && $other_changed[$j]) - { - $corresponding = $i; - while ($j < $other_len && $other_changed[$j]) - { - $j++; - } - } - } - } - while ($runlength != $i - $start); - - // If possible, move the fully-merged run of changes back to a corresponding run in the other file. - while ($corresponding < $i) - { - $changed[--$start] = 1; - $changed[--$i] = 0; - - while ($other_changed[--$j]) - { - continue; - } - } - } - } -} diff --git a/install/update/old/includes/functions.php b/install/update/old/includes/functions.php deleted file mode 100644 index 5234c34..0000000 --- a/install/update/old/includes/functions.php +++ /dev/null @@ -1,4945 +0,0 @@ - -* @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; -} - -// Common global functions -/** -* Load the autoloaders added by the extensions. -* -* @param string $phpbb_root_path Path to the phpbb root directory. -*/ -function phpbb_load_extensions_autoloaders($phpbb_root_path) -{ - $iterator = new \RecursiveIteratorIterator( - new \phpbb\recursive_dot_prefix_filter_iterator( - new \RecursiveDirectoryIterator( - $phpbb_root_path . 'ext/', - \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS - ) - ), - \RecursiveIteratorIterator::SELF_FIRST - ); - $iterator->setMaxDepth(2); - - foreach ($iterator as $file_info) - { - if ($file_info->getFilename() === 'vendor' && $iterator->getDepth() === 2) - { - $filename = $file_info->getRealPath() . '/autoload.php'; - if (file_exists($filename)) - { - require $filename; - } - } - } -} - -/** -* Casts a variable to the given type. -* -* @deprecated -*/ -function set_var(&$result, $var, $type, $multibyte = false) -{ - // no need for dependency injection here, if you have the object, call the method yourself! - $type_cast_helper = new \phpbb\request\type_cast_helper(); - $type_cast_helper->set_var($result, $var, $type, $multibyte); -} - -/** -* Generates an alphanumeric random string of given length -* -* @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($num_chars = 8) -{ - $range = array_merge(range('A', 'Z'), range(0, 9)); - $size = count($range); - - $output = ''; - for ($i = 0; $i < $num_chars; $i++) - { - $rand = random_int(0, $size-1); - $output .= $range[$rand]; - } - - 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) -{ - $range = array_merge(range('A', 'N'), range('P', 'Z'), range(1, 9)); - $size = count($range); - - $output = ''; - for ($i = 0; $i < $num_chars; $i++) - { - $rand = random_int(0, $size-1); - $output .= $range[$rand]; - } - - return $output; -} - -/** -* Return unique id -*/ -function unique_id() -{ - return strtolower(gen_rand_string(16)); -} - -/** -* Wrapper for mt_rand() which allows swapping $min and $max parameters. -* -* PHP does not allow us to swap the order of the arguments for mt_rand() anymore. -* (since PHP 5.3.4, see http://bugs.php.net/46587) -* -* @param int $min Lowest value to be returned -* @param int $max Highest value to be returned -* -* @return int Random integer between $min and $max (or $max and $min) -*/ -function phpbb_mt_rand($min, $max) -{ - return ($min > $max) ? mt_rand($max, $min) : mt_rand($min, $max); -} - -/** -* Wrapper for getdate() which returns the equivalent array for UTC timestamps. -* -* @param int $time Unix timestamp (optional) -* -* @return array Returns an associative array of information related to the timestamp. -* See http://www.php.net/manual/en/function.getdate.php -*/ -function phpbb_gmgetdate($time = false) -{ - if ($time === false) - { - $time = time(); - } - - // getdate() interprets timestamps in local time. - // What follows uses the fact that getdate() and - // date('Z') balance each other out. - return getdate($time - date('Z')); -} - -/** -* Return formatted string for filesizes -* -* @param mixed $value filesize in bytes -* (non-negative number; int, float or string) -* @param bool $string_only true if language string should be returned -* @param array $allowed_units only allow these units (data array indexes) -* -* @return mixed data array if $string_only is false -*/ -function get_formatted_filesize($value, $string_only = true, $allowed_units = false) -{ - global $user; - - $available_units = array( - 'tb' => array( - 'min' => 1099511627776, // pow(2, 40) - 'index' => 4, - 'si_unit' => 'TB', - 'iec_unit' => 'TIB', - ), - 'gb' => array( - 'min' => 1073741824, // pow(2, 30) - 'index' => 3, - 'si_unit' => 'GB', - 'iec_unit' => 'GIB', - ), - 'mb' => array( - 'min' => 1048576, // pow(2, 20) - 'index' => 2, - 'si_unit' => 'MB', - 'iec_unit' => 'MIB', - ), - 'kb' => array( - 'min' => 1024, // pow(2, 10) - 'index' => 1, - 'si_unit' => 'KB', - 'iec_unit' => 'KIB', - ), - 'b' => array( - 'min' => 0, - 'index' => 0, - 'si_unit' => 'BYTES', // Language index - 'iec_unit' => 'BYTES', // Language index - ), - ); - - foreach ($available_units as $si_identifier => $unit_info) - { - if (!empty($allowed_units) && $si_identifier != 'b' && !in_array($si_identifier, $allowed_units)) - { - continue; - } - - if ($value >= $unit_info['min']) - { - $unit_info['si_identifier'] = $si_identifier; - - break; - } - } - unset($available_units); - - for ($i = 0; $i < $unit_info['index']; $i++) - { - $value /= 1024; - } - $value = round($value, 2); - - // Lookup units in language dictionary - $unit_info['si_unit'] = (isset($user->lang[$unit_info['si_unit']])) ? $user->lang[$unit_info['si_unit']] : $unit_info['si_unit']; - $unit_info['iec_unit'] = (isset($user->lang[$unit_info['iec_unit']])) ? $user->lang[$unit_info['iec_unit']] : $unit_info['iec_unit']; - - // Default to IEC - $unit_info['unit'] = $unit_info['iec_unit']; - - if (!$string_only) - { - $unit_info['value'] = $value; - - return $unit_info; - } - - return $value . ' ' . $unit_info['unit']; -} - -/** -* Determine whether we are approaching the maximum execution time. Should be called once -* at the beginning of the script in which it's used. -* @return bool Either true if the maximum execution time is nearly reached, or false -* if some time is still left. -*/ -function still_on_time($extra_time = 15) -{ - static $max_execution_time, $start_time; - - $current_time = microtime(true); - - if (empty($max_execution_time)) - { - $max_execution_time = (function_exists('ini_get')) ? (int) @ini_get('max_execution_time') : (int) @get_cfg_var('max_execution_time'); - - // If zero, then set to something higher to not let the user catch the ten seconds barrier. - if ($max_execution_time === 0) - { - $max_execution_time = 50 + $extra_time; - } - - $max_execution_time = min(max(10, ($max_execution_time - $extra_time)), 50); - - // For debugging purposes - // $max_execution_time = 10; - - global $starttime; - $start_time = (empty($starttime)) ? $current_time : $starttime; - } - - return (ceil($current_time - $start_time) < $max_execution_time) ? true : false; -} - -/** -* Hashes an email address to a big integer -* -* @param string $email Email address -* -* @return string Unsigned Big Integer -*/ -function phpbb_email_hash($email) -{ - return sprintf('%u', crc32(strtolower($email))) . strlen($email); -} - -/** -* Wrapper for version_compare() that allows using uppercase A and B -* for alpha and beta releases. -* -* See http://www.php.net/manual/en/function.version-compare.php -* -* @param string $version1 First version number -* @param string $version2 Second version number -* @param string $operator Comparison operator (optional) -* -* @return mixed Boolean (true, false) if comparison operator is specified. -* Integer (-1, 0, 1) otherwise. -*/ -function phpbb_version_compare($version1, $version2, $operator = null) -{ - $version1 = strtolower($version1); - $version2 = strtolower($version2); - - if (is_null($operator)) - { - return version_compare($version1, $version2); - } - else - { - return version_compare($version1, $version2, $operator); - } -} - -// functions used for building option fields - -/** -* Pick a language, any language ... -*/ -function language_select($default = '') -{ - global $db; - - $sql = 'SELECT lang_iso, lang_local_name - FROM ' . LANG_TABLE . ' - ORDER BY lang_english_name'; - $result = $db->sql_query($sql); - - $lang_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($row['lang_iso'] == $default) ? ' selected="selected"' : ''; - $lang_options .= ''; - } - $db->sql_freeresult($result); - - return $lang_options; -} - -/** -* Pick a template/theme combo, -*/ -function style_select($default = '', $all = false) -{ - global $db; - - $sql_where = (!$all) ? 'WHERE style_active = 1 ' : ''; - $sql = 'SELECT style_id, style_name - FROM ' . STYLES_TABLE . " - $sql_where - ORDER BY style_name"; - $result = $db->sql_query($sql); - - $style_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($row['style_id'] == $default) ? ' selected="selected"' : ''; - $style_options .= ''; - } - $db->sql_freeresult($result); - - return $style_options; -} - -/** -* Format the timezone offset with hours and minutes -* -* @param int $tz_offset Timezone offset in seconds -* @param bool $show_null Whether null offsets should be shown -* @return string Normalized offset string: -7200 => -02:00 -* 16200 => +04:30 -*/ -function phpbb_format_timezone_offset($tz_offset, $show_null = false) -{ - $sign = ($tz_offset < 0) ? '-' : '+'; - $time_offset = abs($tz_offset); - - if ($time_offset == 0 && $show_null == false) - { - return ''; - } - - $offset_seconds = $time_offset % 3600; - $offset_minutes = $offset_seconds / 60; - $offset_hours = ($time_offset - $offset_seconds) / 3600; - - $offset_string = sprintf("%s%02d:%02d", $sign, $offset_hours, $offset_minutes); - return $offset_string; -} - -/** -* Compares two time zone labels. -* Arranges them in increasing order by timezone offset. -* Places UTC before other timezones in the same offset. -*/ -function phpbb_tz_select_compare($a, $b) -{ - $a_sign = $a[3]; - $b_sign = $b[3]; - if ($a_sign != $b_sign) - { - return $a_sign == '-' ? -1 : 1; - } - - $a_offset = substr($a, 4, 5); - $b_offset = substr($b, 4, 5); - if ($a_offset == $b_offset) - { - $a_name = substr($a, 12); - $b_name = substr($b, 12); - if ($a_name == $b_name) - { - return 0; - } - else if ($a_name == 'UTC') - { - return -1; - } - else if ($b_name == 'UTC') - { - return 1; - } - else - { - return $a_name < $b_name ? -1 : 1; - } - } - else - { - if ($a_sign == '-') - { - return $a_offset > $b_offset ? -1 : 1; - } - else - { - return $a_offset < $b_offset ? -1 : 1; - } - } -} - -/** -* Return list of timezone identifiers -* We also add the selected timezone if we can create an object with it. -* DateTimeZone::listIdentifiers seems to not add all identifiers to the list, -* because some are only kept for backward compatible reasons. If the user has -* a deprecated value, we add it here, so it can still be kept. Once the user -* changed his value, there is no way back to deprecated values. -* -* @param string $selected_timezone Additional timezone that shall -* be added to the list of identiers -* @return array DateTimeZone::listIdentifiers and additional -* selected_timezone if it is a valid timezone. -*/ -function phpbb_get_timezone_identifiers($selected_timezone) -{ - $timezones = DateTimeZone::listIdentifiers(); - - if (!in_array($selected_timezone, $timezones)) - { - try - { - // Add valid timezones that are currently selected but not returned - // by DateTimeZone::listIdentifiers - $validate_timezone = new DateTimeZone($selected_timezone); - $timezones[] = $selected_timezone; - } - catch (\Exception $e) - { - } - } - - return $timezones; -} - -/** -* Options to pick a timezone and date/time -* -* @param \phpbb\template\template $template phpBB template object -* @param \phpbb\user $user Object of the current user -* @param string $default A timezone to select -* @param boolean $truncate Shall we truncate the options text -* -* @return array Returns an array containing the options for the time selector. -*/ -function phpbb_timezone_select($template, $user, $default = '', $truncate = false) -{ - static $timezones; - - $default_offset = ''; - if (!isset($timezones)) - { - $unsorted_timezones = phpbb_get_timezone_identifiers($default); - - $timezones = array(); - foreach ($unsorted_timezones as $timezone) - { - $tz = new DateTimeZone($timezone); - $dt = $user->create_datetime('now', $tz); - $offset = $dt->getOffset(); - $current_time = $dt->format($user->lang['DATETIME_FORMAT'], true); - $offset_string = phpbb_format_timezone_offset($offset, true); - $timezones['UTC' . $offset_string . ' - ' . $timezone] = array( - 'tz' => $timezone, - 'offset' => $offset_string, - 'current' => $current_time, - ); - if ($timezone === $default) - { - $default_offset = 'UTC' . $offset_string; - } - } - unset($unsorted_timezones); - - uksort($timezones, 'phpbb_tz_select_compare'); - } - - $tz_select = $opt_group = ''; - - foreach ($timezones as $key => $timezone) - { - if ($opt_group != $timezone['offset']) - { - // Generate tz_select for backwards compatibility - $tz_select .= ($opt_group) ? '' : ''; - $tz_select .= ''; - $opt_group = $timezone['offset']; - $template->assign_block_vars('timezone_select', array( - 'LABEL' => $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $timezone['current']), - 'VALUE' => $key . ' - ' . $timezone['current'], - )); - - $selected = (!empty($default_offset) && strpos($key, $default_offset) !== false) ? ' selected="selected"' : ''; - $template->assign_block_vars('timezone_date', array( - 'VALUE' => $key . ' - ' . $timezone['current'], - 'SELECTED' => !empty($selected), - 'TITLE' => $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $timezone['current']), - )); - } - - $label = $timezone['tz']; - if (isset($user->lang['timezones'][$label])) - { - $label = $user->lang['timezones'][$label]; - } - $title = $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $label); - - if ($truncate) - { - $label = truncate_string($label, 50, 255, false, '...'); - } - - // Also generate timezone_select for backwards compatibility - $selected = ($timezone['tz'] === $default) ? ' selected="selected"' : ''; - $tz_select .= ''; - $template->assign_block_vars('timezone_select.timezone_options', array( - 'TITLE' => $title, - 'VALUE' => $timezone['tz'], - 'SELECTED' => !empty($selected), - 'LABEL' => $label, - )); - } - $tz_select .= ''; - - return $tz_select; -} - -// Functions handling topic/post tracking/marking - -/** -* Marks a topic/forum as read -* Marks a topic as posted to -* -* @param string $mode (all, topics, topic, post) -* @param int|bool $forum_id Used in all, topics, and topic mode -* @param int|bool $topic_id Used in topic and post mode -* @param int $post_time 0 means current time(), otherwise to set a specific mark time -* @param int $user_id can only be used with $mode == 'post' -*/ -function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0) -{ - global $db, $user, $config; - global $request, $phpbb_container, $phpbb_dispatcher; - - $post_time = ($post_time === 0 || $post_time > time()) ? time() : (int) $post_time; - - $should_markread = true; - - /** - * This event is used for performing actions directly before marking forums, - * topics or posts as read. - * - * It is also possible to prevent the marking. For that, the $should_markread parameter - * should be set to FALSE. - * - * @event core.markread_before - * @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 - * @var bool should_markread Flag indicating if the markread should be done or not. - * @since 3.1.4-RC1 - */ - $vars = array( - 'mode', - 'forum_id', - 'topic_id', - 'post_time', - 'user_id', - 'should_markread', - ); - extract($phpbb_dispatcher->trigger_event('core.markread_before', compact($vars))); - - if (!$should_markread) - { - return; - } - - if ($mode == 'all') - { - 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(array( - 'notification.type.topic', - 'notification.type.quote', - 'notification.type.bookmark', - 'notification.type.post', - 'notification.type.approve_topic', - 'notification.type.approve_post', - ), false, $user->data['user_id'], $post_time); - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - // Mark all forums read (index page) - $tables = array(TOPICS_TRACK_TABLE, FORUMS_TRACK_TABLE); - foreach ($tables as $table) - { - $sql = 'DELETE FROM ' . $table . " - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time"; - $db->sql_query($sql); - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastmark = $post_time - WHERE user_id = {$user->data['user_id']} - AND user_lastmark < $post_time"; - $db->sql_query($sql); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - - unset($tracking_topics['tf']); - unset($tracking_topics['t']); - unset($tracking_topics['f']); - $tracking_topics['l'] = base_convert($post_time - $config['board_startdate'], 10, 36); - - $user->set_cookie('track', tracking_serialize($tracking_topics), $post_time + 31536000); - $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking_topics), \phpbb\request\request_interface::COOKIE); - - unset($tracking_topics); - - if ($user->data['is_registered']) - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastmark = $post_time - WHERE user_id = {$user->data['user_id']} - AND user_lastmark < $post_time"; - $db->sql_query($sql); - } - } - } - } - else if ($mode == 'topics') - { - // Mark all topics in forums read - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - else - { - $forum_id = array_unique($forum_id); - } - - /* @var $phpbb_notifications \phpbb\notification\manager */ - $phpbb_notifications = $phpbb_container->get('notification_manager'); - - $phpbb_notifications->mark_notifications_by_parent(array( - 'notification.type.topic', - 'notification.type.approve_topic', - ), $forum_id, $user->data['user_id'], $post_time); - - // Mark all post/quote notifications read for this user in this forum - $topic_ids = array(); - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id); - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - $phpbb_notifications->mark_notifications_by_parent(array( - 'notification.type.quote', - 'notification.type.bookmark', - 'notification.type.post', - 'notification.type.approve_post', - ), $topic_ids, $user->data['user_id'], $post_time); - - // Add 0 to forums array to mark global announcements correctly - // $forum_id[] = 0; - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql = 'DELETE FROM ' . TOPICS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time - AND " . $db->sql_in_set('forum_id', $forum_id); - $db->sql_query($sql); - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND " . $db->sql_in_set('forum_id', $forum_id); - $result = $db->sql_query($sql); - - $sql_update = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_update[] = (int) $row['forum_id']; - } - $db->sql_freeresult($result); - - if (count($sql_update)) - { - $sql = 'UPDATE ' . FORUMS_TRACK_TABLE . " - SET mark_time = $post_time - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time - AND " . $db->sql_in_set('forum_id', $sql_update); - $db->sql_query($sql); - } - - if ($sql_insert = array_diff($forum_id, $sql_update)) - { - $sql_ary = array(); - foreach ($sql_insert as $f_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user->data['user_id'], - 'forum_id' => (int) $f_id, - 'mark_time' => $post_time, - ); - } - - $db->sql_multi_insert(FORUMS_TRACK_TABLE, $sql_ary); - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking = ($tracking) ? tracking_unserialize($tracking) : array(); - - foreach ($forum_id as $f_id) - { - $topic_ids36 = (isset($tracking['tf'][$f_id])) ? $tracking['tf'][$f_id] : array(); - - if (isset($tracking['tf'][$f_id])) - { - unset($tracking['tf'][$f_id]); - } - - foreach ($topic_ids36 as $topic_id36) - { - unset($tracking['t'][$topic_id36]); - } - - if (isset($tracking['f'][$f_id])) - { - unset($tracking['f'][$f_id]); - } - - $tracking['f'][$f_id] = base_convert($post_time - $config['board_startdate'], 10, 36); - } - - if (isset($tracking['tf']) && empty($tracking['tf'])) - { - unset($tracking['tf']); - } - - $user->set_cookie('track', tracking_serialize($tracking), $post_time + 31536000); - $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking), \phpbb\request\request_interface::COOKIE); - - unset($tracking); - } - } - else if ($mode == 'topic') - { - if ($topic_id === false || $forum_id === false) - { - 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(array( - 'notification.type.topic', - 'notification.type.approve_topic', - ), $topic_id, $user->data['user_id'], $post_time); - - $phpbb_notifications->mark_notifications_by_parent(array( - 'notification.type.quote', - 'notification.type.bookmark', - 'notification.type.post', - 'notification.type.approve_post', - ), $topic_id, $user->data['user_id'], $post_time); - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql = 'UPDATE ' . TOPICS_TRACK_TABLE . " - SET mark_time = $post_time - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time - AND topic_id = $topic_id"; - $db->sql_query($sql); - - // insert row - if (!$db->sql_affectedrows()) - { - $db->sql_return_on_error(true); - - $sql_ary = array( - 'user_id' => (int) $user->data['user_id'], - 'topic_id' => (int) $topic_id, - 'forum_id' => (int) $forum_id, - 'mark_time' => $post_time, - ); - - $db->sql_query('INSERT INTO ' . TOPICS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $db->sql_return_on_error(false); - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking = ($tracking) ? tracking_unserialize($tracking) : array(); - - $topic_id36 = base_convert($topic_id, 10, 36); - - if (!isset($tracking['t'][$topic_id36])) - { - $tracking['tf'][$forum_id][$topic_id36] = true; - } - - $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... - if (strlen($request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE)) > 10000) - { - //echo 'Cookie grown too large' . print_r($tracking, true); - - // We get the ten most minimum stored time offsets and its associated topic ids - $time_keys = array(); - for ($i = 0; $i < 10 && count($tracking['t']); $i++) - { - $min_value = min($tracking['t']); - $m_tkey = array_search($min_value, $tracking['t']); - unset($tracking['t'][$m_tkey]); - - $time_keys[$m_tkey] = $min_value; - } - - // Now remove the topic ids from the array... - foreach ($tracking['tf'] as $f_id => $topic_id_ary) - { - foreach ($time_keys as $m_tkey => $min_value) - { - if (isset($topic_id_ary[$m_tkey])) - { - $tracking['f'][$f_id] = $min_value; - unset($tracking['tf'][$f_id][$m_tkey]); - } - } - } - - if ($user->data['is_registered']) - { - $user->data['user_lastmark'] = intval(base_convert(max($time_keys) + $config['board_startdate'], 36, 10)); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastmark = $post_time - WHERE user_id = {$user->data['user_id']} - AND mark_time < $post_time"; - $db->sql_query($sql); - } - else - { - $tracking['l'] = max($time_keys); - } - } - - $user->set_cookie('track', tracking_serialize($tracking), $post_time + 31536000); - $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking), \phpbb\request\request_interface::COOKIE); - } - } - else if ($mode == 'post') - { - if ($topic_id === false) - { - return; - } - - $use_user_id = (!$user_id) ? $user->data['user_id'] : $user_id; - - if ($config['load_db_track'] && $use_user_id != ANONYMOUS) - { - $db->sql_return_on_error(true); - - $sql_ary = array( - 'user_id' => (int) $use_user_id, - 'topic_id' => (int) $topic_id, - 'topic_posted' => 1, - ); - - $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $db->sql_return_on_error(false); - } - } - - /** - * 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))); -} - -/** -* Get topic tracking info by using already fetched info -*/ -function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $global_announce_list = false) -{ - global $user; - - $last_read = array(); - - if (!is_array($topic_ids)) - { - $topic_ids = array($topic_ids); - } - - foreach ($topic_ids as $topic_id) - { - if (!empty($rowset[$topic_id]['mark_time'])) - { - $last_read[$topic_id] = $rowset[$topic_id]['mark_time']; - } - } - - $topic_ids = array_diff($topic_ids, array_keys($last_read)); - - if (count($topic_ids)) - { - $mark_time = array(); - - if (!empty($forum_mark_time[$forum_id]) && $forum_mark_time[$forum_id] !== false) - { - $mark_time[$forum_id] = $forum_mark_time[$forum_id]; - } - - $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user->data['user_lastmark']; - - foreach ($topic_ids as $topic_id) - { - $last_read[$topic_id] = $user_lastmark; - } - } - - return $last_read; -} - -/** -* Get topic tracking info from db (for cookie based tracking only this function is used) -*/ -function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_list = false) -{ - global $config, $user, $request; - - $last_read = array(); - - if (!is_array($topic_ids)) - { - $topic_ids = array($topic_ids); - } - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - global $db; - - $sql = 'SELECT topic_id, mark_time - FROM ' . TOPICS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND " . $db->sql_in_set('topic_id', $topic_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $last_read[$row['topic_id']] = $row['mark_time']; - } - $db->sql_freeresult($result); - - $topic_ids = array_diff($topic_ids, array_keys($last_read)); - - if (count($topic_ids)) - { - $sql = 'SELECT forum_id, mark_time - FROM ' . FORUMS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND forum_id = $forum_id"; - $result = $db->sql_query($sql); - - $mark_time = array(); - while ($row = $db->sql_fetchrow($result)) - { - $mark_time[$row['forum_id']] = $row['mark_time']; - } - $db->sql_freeresult($result); - - $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user->data['user_lastmark']; - - foreach ($topic_ids as $topic_id) - { - $last_read[$topic_id] = $user_lastmark; - } - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - global $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(); - } - - if (!$user->data['is_registered']) - { - $user_lastmark = (isset($tracking_topics['l'])) ? base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate'] : 0; - } - else - { - $user_lastmark = $user->data['user_lastmark']; - } - - foreach ($topic_ids as $topic_id) - { - $topic_id36 = base_convert($topic_id, 10, 36); - - if (isset($tracking_topics['t'][$topic_id36])) - { - $last_read[$topic_id] = base_convert($tracking_topics['t'][$topic_id36], 36, 10) + $config['board_startdate']; - } - } - - $topic_ids = array_diff($topic_ids, array_keys($last_read)); - - if (count($topic_ids)) - { - $mark_time = array(); - - if (isset($tracking_topics['f'][$forum_id])) - { - $mark_time[$forum_id] = base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']; - } - - $user_lastmark = (isset($mark_time[$forum_id])) ? $mark_time[$forum_id] : $user_lastmark; - - foreach ($topic_ids as $topic_id) - { - $last_read[$topic_id] = $user_lastmark; - } - } - } - - return $last_read; -} - -/** -* Get list of unread topics -* -* @param int $user_id User ID (or false for current user) -* @param string $sql_extra Extra WHERE SQL statement -* @param string $sql_sort ORDER BY SQL sorting statement -* @param string $sql_limit Limits the size of unread topics list, 0 for unlimited query -* @param string $sql_limit_offset Sets the offset of the first row to search, 0 to search from the start -* -* @return array[int][int] Topic ids as keys, mark_time of topic as value -*/ -function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $sql_limit = 1001, $sql_limit_offset = 0) -{ - global $config, $db, $user, $request; - global $phpbb_dispatcher; - - $user_id = ($user_id === false) ? (int) $user->data['user_id'] : (int) $user_id; - - // Data array we're going to return - $unread_topics = array(); - - if (empty($sql_sort)) - { - $sql_sort = 'ORDER BY t.topic_last_post_time DESC, t.topic_last_post_id DESC'; - } - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - // Get list of the unread topics - $last_mark = (int) $user->data['user_lastmark']; - - $sql_array = array( - 'SELECT' => 't.topic_id, t.topic_last_post_time, tt.mark_time as topic_mark_time, ft.mark_time as forum_mark_time', - - 'FROM' => array(TOPICS_TABLE => 't'), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(TOPICS_TRACK_TABLE => 'tt'), - 'ON' => "tt.user_id = $user_id AND t.topic_id = tt.topic_id", - ), - array( - 'FROM' => array(FORUMS_TRACK_TABLE => 'ft'), - 'ON' => "ft.user_id = $user_id AND t.forum_id = ft.forum_id", - ), - ), - - 'WHERE' => " - t.topic_last_post_time > $last_mark AND - ( - (tt.mark_time IS NOT NULL AND t.topic_last_post_time > tt.mark_time) OR - (tt.mark_time IS NULL AND ft.mark_time IS NOT NULL AND t.topic_last_post_time > ft.mark_time) OR - (tt.mark_time IS NULL AND ft.mark_time IS NULL) - ) - $sql_extra - $sql_sort", - ); - - /** - * Change SQL query for fetching unread topics data - * - * @event core.get_unread_topics_modify_sql - * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, LEFT_JOIN, WHERE - * @var int last_mark User's last_mark time - * @var string sql_extra Extra WHERE SQL statement - * @var string sql_sort ORDER BY SQL sorting statement - * @since 3.1.4-RC1 - */ - $vars = array( - 'sql_array', - 'last_mark', - 'sql_extra', - 'sql_sort', - ); - extract($phpbb_dispatcher->trigger_event('core.get_unread_topics_modify_sql', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query_limit($sql, $sql_limit, $sql_limit_offset); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id = (int) $row['topic_id']; - $unread_topics[$topic_id] = ($row['topic_mark_time']) ? (int) $row['topic_mark_time'] : (($row['forum_mark_time']) ? (int) $row['forum_mark_time'] : $last_mark); - } - $db->sql_freeresult($result); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - global $tracking_topics; - - if (empty($tracking_topics)) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', false, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - } - - if (!$user->data['is_registered']) - { - $user_lastmark = (isset($tracking_topics['l'])) ? base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate'] : 0; - } - else - { - $user_lastmark = (int) $user->data['user_lastmark']; - } - - $sql = 'SELECT t.topic_id, t.forum_id, t.topic_last_post_time - FROM ' . TOPICS_TABLE . ' t - WHERE t.topic_last_post_time > ' . $user_lastmark . " - $sql_extra - $sql_sort"; - $result = $db->sql_query_limit($sql, $sql_limit, $sql_limit_offset); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_id = (int) $row['forum_id']; - $topic_id = (int) $row['topic_id']; - $topic_id36 = base_convert($topic_id, 10, 36); - - if (isset($tracking_topics['t'][$topic_id36])) - { - $last_read = base_convert($tracking_topics['t'][$topic_id36], 36, 10) + $config['board_startdate']; - - if ($row['topic_last_post_time'] > $last_read) - { - $unread_topics[$topic_id] = $last_read; - } - } - else if (isset($tracking_topics['f'][$forum_id])) - { - $mark_time = base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']; - - if ($row['topic_last_post_time'] > $mark_time) - { - $unread_topics[$topic_id] = $mark_time; - } - } - else - { - $unread_topics[$topic_id] = $user_lastmark; - } - } - $db->sql_freeresult($result); - } - - return $unread_topics; -} - -/** -* Check for read forums and update topic tracking info accordingly -* -* @param int $forum_id the forum id to check -* @param int $forum_last_post_time the forums last post time -* @param int $f_mark_time the forums last mark time if user is registered and load_db_lastread enabled -* @param int $mark_time_forum false if the mark time needs to be obtained, else the last users forum mark time -* -* @return true if complete forum got marked read, else false. -*/ -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, $request, $phpbb_container; - - // Determine the users last forum mark time if not given. - if ($mark_time_forum === false) - { - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $mark_time_forum = (!empty($f_mark_time)) ? $f_mark_time : $user->data['user_lastmark']; - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - - $mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark']; - } - } - - // 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. - // If there are none, we mark the forum as read. - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - if ($mark_time_forum >= $forum_last_post_time) - { - // We do not need to mark read, this happened before. Therefore setting this to true - $row = true; - } - else - { - $sql = 'SELECT t.forum_id - FROM ' . TOPICS_TABLE . ' t - LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt - ON (tt.topic_id = t.topic_id - AND tt.user_id = ' . $user->data['user_id'] . ') - WHERE t.forum_id = ' . $forum_id . ' - AND t.topic_last_post_time > ' . $mark_time_forum . ' - AND t.topic_moved_id = 0 - AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.') . ' - AND (tt.topic_id IS NULL - OR tt.mark_time < t.topic_last_post_time)'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - // Get information from cookie - if (!isset($tracking_topics['tf'][$forum_id])) - { - // We do not need to mark read, this happened before. Therefore setting this to true - $row = true; - } - else - { - $sql = 'SELECT t.topic_id - FROM ' . TOPICS_TABLE . ' t - WHERE t.forum_id = ' . $forum_id . ' - AND t.topic_last_post_time > ' . $mark_time_forum . ' - AND t.topic_moved_id = 0 - AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'); - $result = $db->sql_query($sql); - - $check_forum = $tracking_topics['tf'][$forum_id]; - $unread = false; - - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($check_forum[base_convert($row['topic_id'], 10, 36)])) - { - $unread = true; - break; - } - } - $db->sql_freeresult($result); - - $row = $unread; - } - } - else - { - $row = true; - } - - if (!$row) - { - markread('topics', $forum_id); - return true; - } - - return false; -} - -/** -* Transform an array into a serialized format -*/ -function tracking_serialize($input) -{ - $out = ''; - foreach ($input as $key => $value) - { - if (is_array($value)) - { - $out .= $key . ':(' . tracking_serialize($value) . ');'; - } - else - { - $out .= $key . ':' . $value . ';'; - } - } - return $out; -} - -/** -* Transform a serialized array into an actual array -*/ -function tracking_unserialize($string, $max_depth = 3) -{ - $n = strlen($string); - if ($n > 10010) - { - die('Invalid data supplied'); - } - $data = $stack = array(); - $key = ''; - $mode = 0; - $level = &$data; - for ($i = 0; $i < $n; ++$i) - { - switch ($mode) - { - case 0: - switch ($string[$i]) - { - case ':': - $level[$key] = 0; - $mode = 1; - break; - case ')': - unset($level); - $level = array_pop($stack); - $mode = 3; - break; - default: - $key .= $string[$i]; - } - break; - - case 1: - switch ($string[$i]) - { - case '(': - if (count($stack) >= $max_depth) - { - die('Invalid data supplied'); - } - $stack[] = &$level; - $level[$key] = array(); - $level = &$level[$key]; - $key = ''; - $mode = 0; - break; - default: - $level[$key] = $string[$i]; - $mode = 2; - break; - } - break; - - case 2: - switch ($string[$i]) - { - case ')': - unset($level); - $level = array_pop($stack); - $mode = 3; - break; - case ';': - $key = ''; - $mode = 0; - break; - default: - $level[$key] .= $string[$i]; - break; - } - break; - - case 3: - switch ($string[$i]) - { - case ')': - unset($level); - $level = array_pop($stack); - break; - case ';': - $key = ''; - $mode = 0; - break; - default: - die('Invalid data supplied'); - break; - } - break; - } - } - - if (count($stack) != 0 || ($mode != 0 && $mode != 3)) - { - die('Invalid data supplied'); - } - - return $level; -} - -// Server functions (building urls, redirecting...) - -/** -* Append session id to url. -* This function supports hooks. -* -* @param string $url The url the session id needs to be appended to (can have params) -* @param mixed $params String or array of additional url parameters -* @param bool $is_amp Is url using & (true) or & (false) -* @param string $session_id Possibility to use a custom session id instead of the global one -* @param bool $is_route Is url generated by a route. -* -* @return string The corrected url. -* -* Examples: -* -* append_sid("{$phpbb_root_path}viewtopic.$phpEx?t=1&f=2"); -* append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2'); -* append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=1&f=2', false); -* append_sid("{$phpbb_root_path}viewtopic.$phpEx", array('t' => 1, 'f' => 2)); -* -* -*/ -function append_sid($url, $params = false, $is_amp = true, $session_id = false, $is_route = false) -{ - global $_SID, $_EXTRA_URL, $phpbb_hook, $phpbb_path_helper; - global $phpbb_dispatcher; - - if ($params === '' || (is_array($params) && empty($params))) - { - // Do not append the ? if the param-list is empty anyway. - $params = false; - } - - // Update the root path with the correct relative web path - if (!$is_route && $phpbb_path_helper instanceof \phpbb\path_helper) - { - $url = $phpbb_path_helper->update_web_root_path($url); - } - - $append_sid_overwrite = false; - - /** - * This event can either supplement or override the append_sid() function - * - * To override this function, the event must set $append_sid_overwrite to - * the new URL value, which will be returned following the event - * - * @event core.append_sid - * @var string url The url the session id needs - * to be appended to (can have - * params) - * @var mixed params String or array of additional - * url parameters - * @var bool is_amp Is url using & (true) or - * & (false) - * @var bool|string session_id Possibility to use a custom - * session id (string) instead of - * the global one (false) - * @var bool|string append_sid_overwrite Overwrite function (string - * URL) or not (false) - * @var bool is_route Is url generated by a route. - * @since 3.1.0-a1 - */ - $vars = array('url', 'params', 'is_amp', 'session_id', 'append_sid_overwrite', 'is_route'); - extract($phpbb_dispatcher->trigger_event('core.append_sid', compact($vars))); - - if ($append_sid_overwrite) - { - return $append_sid_overwrite; - } - - // The following hook remains for backwards compatibility, though use of - // the event above is preferred. - // Developers using the hook function need to globalise the $_SID and $_EXTRA_URL on their own and also handle it appropriately. - // They could mimic most of what is within this function - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id)) - { - if ($phpbb_hook->hook_return(__FUNCTION__)) - { - return $phpbb_hook->hook_return_result(__FUNCTION__); - } - } - - $params_is_array = is_array($params); - - // Get anchor - $anchor = ''; - if (strpos($url, '#') !== false) - { - list($url, $anchor) = explode('#', $url, 2); - $anchor = '#' . $anchor; - } - else if (!$params_is_array && strpos($params, '#') !== false) - { - list($params, $anchor) = explode('#', $params, 2); - $anchor = '#' . $anchor; - } - - // Handle really simple cases quickly - if ($_SID == '' && $session_id === false && empty($_EXTRA_URL) && !$params_is_array && !$anchor) - { - if ($params === false) - { - return $url; - } - - $url_delim = (strpos($url, '?') === false) ? '?' : (($is_amp) ? '&' : '&'); - return $url . ($params !== false ? $url_delim. $params : ''); - } - - // Assign sid if session id is not specified - if ($session_id === false) - { - $session_id = $_SID; - } - - $amp_delim = ($is_amp) ? '&' : '&'; - $url_delim = (strpos($url, '?') === false) ? '?' : $amp_delim; - - // Appending custom url parameter? - $append_url = (!empty($_EXTRA_URL)) ? implode($amp_delim, $_EXTRA_URL) : ''; - - // Use the short variant if possible ;) - if ($params === false) - { - // Append session id - if (!$session_id) - { - return $url . (($append_url) ? $url_delim . $append_url : '') . $anchor; - } - else - { - return $url . (($append_url) ? $url_delim . $append_url . $amp_delim : $url_delim) . 'sid=' . $session_id . $anchor; - } - } - - // Build string if parameters are specified as array - if (is_array($params)) - { - $output = array(); - - foreach ($params as $key => $item) - { - if ($item === NULL) - { - continue; - } - - if ($key == '#') - { - $anchor = '#' . $item; - continue; - } - - $output[] = $key . '=' . $item; - } - - $params = implode($amp_delim, $output); - } - - // Append session id and parameters (even if they are empty) - // If parameters are empty, the developer can still append his/her parameters without caring about the delimiter - return $url . (($append_url) ? $url_delim . $append_url . $amp_delim : $url_delim) . $params . ((!$session_id) ? '' : $amp_delim . 'sid=' . $session_id) . $anchor; -} - -/** -* Generate board url (example: http://www.example.com/phpBB) -* -* @param bool $without_script_path if set to true the script path gets not appended (example: http://www.example.com) -* -* @return string the generated board url -*/ -function generate_board_url($without_script_path = false) -{ - global $config, $user, $request, $symfony_request; - - $server_name = $user->host; - - // Forcing server vars is the only way to specify/override the protocol - if ($config['force_server_vars'] || !$server_name) - { - $server_protocol = ($config['server_protocol']) ? $config['server_protocol'] : (($config['cookie_secure']) ? 'https://' : 'http://'); - $server_name = $config['server_name']; - $server_port = (int) $config['server_port']; - $script_path = $config['script_path']; - - $url = $server_protocol . $server_name; - $cookie_secure = $config['cookie_secure']; - } - else - { - $server_port = (int) $symfony_request->getPort(); - - $forwarded_proto = $request->server('HTTP_X_FORWARDED_PROTO'); - - if (!empty($forwarded_proto) && $forwarded_proto === 'https') - { - $server_port = 443; - } - // Do not rely on cookie_secure, users seem to think that it means a secured cookie instead of an encrypted connection - $cookie_secure = $request->is_secure() ? 1 : 0; - $url = (($cookie_secure) ? 'https://' : 'http://') . $server_name; - - $script_path = $user->page['root_script_path']; - } - - if ($server_port && (($cookie_secure && $server_port <> 443) || (!$cookie_secure && $server_port <> 80))) - { - // HTTP HOST can carry a port number (we fetch $user->host, but for old versions this may be true) - if (strpos($server_name, ':') === false) - { - $url .= ':' . $server_port; - } - } - - if (!$without_script_path) - { - $url .= $script_path; - } - - // Strip / from the end - if (substr($url, -1, 1) == '/') - { - $url = substr($url, 0, -1); - } - - return $url; -} - -/** -* Redirects the user to another page then exits the script nicely -* This function is intended for urls within the board. It's not meant to redirect to cross-domains. -* -* @param string $url The url to redirect to -* @param bool $return If true, do not redirect but return the sanitized URL. Default is no return. -* @param bool $disable_cd_check If true, redirect() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. Default is false. -*/ -function redirect($url, $return = false, $disable_cd_check = false) -{ - global $user, $phpbb_path_helper, $phpbb_dispatcher; - - if (!$user->is_setup()) - { - $user->add_lang('common'); - } - - // Make sure no &'s are in, this will break the redirect - $url = str_replace('&', '&', $url); - - // Determine which type of redirect we need to handle... - $url_parts = @parse_url($url); - - if ($url_parts === false) - { - // 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_WARNING); - } - } - else if ($url[0] == '/') - { - // Absolute uri, prepend direct url... - $url = generate_board_url(true) . $url; - } - else - { - // Relative uri - $pathinfo = pathinfo($url); - - // Is the uri pointing to the current directory? - if ($pathinfo['dirname'] == '.') - { - $url = str_replace('./', '', $url); - - // Strip / from the beginning - if ($url && substr($url, 0, 1) == '/') - { - $url = substr($url, 1); - } - } - - $url = $phpbb_path_helper->remove_web_root_path($url); - - if ($user->page['page_dir']) - { - $url = $user->page['page_dir'] . '/' . $url; - } - - $url = generate_board_url() . '/' . $url; - } - - // Clean URL and check if we go outside the forum directory - $url = $phpbb_path_helper->clean_url($url); - - if (!$disable_cd_check && strpos($url, generate_board_url(true) . '/') !== 0) - { - 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_WARNING); - } - - // Now, also check the protocol and for a valid url the last time... - $allowed_protocols = array('http', 'https', 'ftp', 'ftps'); - $url_parts = parse_url($url); - - if ($url_parts === false || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], $allowed_protocols)) - { - trigger_error('INSECURE_REDIRECT', E_USER_WARNING); - } - - /** - * Execute code and/or overwrite redirect() - * - * @event core.functions.redirect - * @var string url The url - * @var bool return If true, do not redirect but return the sanitized URL. - * @var bool disable_cd_check If true, redirect() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. - * @since 3.1.0-RC3 - */ - $vars = array('url', 'return', 'disable_cd_check'); - extract($phpbb_dispatcher->trigger_event('core.functions.redirect', compact($vars))); - - if ($return) - { - return $url; - } - else - { - garbage_collection(); - } - - // Redirect via an HTML form for PITA webservers - if (@preg_match('#WebSTAR|Xitami#', getenv('SERVER_SOFTWARE'))) - { - header('Refresh: 0; URL=' . $url); - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '' . $user->lang['REDIRECT'] . ''; - echo ''; - echo ''; - echo '
' . sprintf($user->lang['URL_REDIRECT'], '', '') . '
'; - echo ''; - echo ''; - - exit; - } - - // Behave as per HTTP/1.1 spec for others - header('Location: ' . $url); - exit; -} - -/** -* Re-Apply session id after page reloads -*/ -function reapply_sid($url, $is_route = false) -{ - global $phpEx, $phpbb_root_path; - - if ($url === "index.$phpEx") - { - return append_sid("index.$phpEx"); - } - else if ($url === "{$phpbb_root_path}index.$phpEx") - { - return append_sid("{$phpbb_root_path}index.$phpEx"); - } - - // Remove previously added sid - if (strpos($url, 'sid=') !== false) - { - // All kind of links - $url = preg_replace('/(\?)?(&|&)?sid=[a-z0-9]+/', '', $url); - // if the sid was the first param, make the old second as first ones - $url = preg_replace("/$phpEx(&|&)+?/", "$phpEx?", $url); - } - - return append_sid($url, false, true, false, $is_route); -} - -/** -* Returns url from the session/current page with an re-appended SID with optionally stripping vars from the url -*/ -function build_url($strip_vars = false) -{ - global $config, $user, $phpbb_path_helper; - - $page = $phpbb_path_helper->get_valid_page($user->page['page'], $config['enable_mod_rewrite']); - - // Append SID - $redirect = append_sid($page, false, false); - - if ($strip_vars !== false) - { - $redirect = $phpbb_path_helper->strip_url_params($redirect, $strip_vars, false); - } - else - { - $redirect = str_replace('&', '&', $redirect); - } - - return $redirect . ((strpos($redirect, '?') === false) ? '?' : ''); -} - -/** -* Meta refresh assignment -* Adds META template variable with meta http tag. -* -* @param int $time Time in seconds for meta refresh tag -* @param string $url URL to redirect to. The url will go through redirect() first before the template variable is assigned -* @param bool $disable_cd_check If true, meta_refresh() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. Default is false. -*/ -function meta_refresh($time, $url, $disable_cd_check = false) -{ - global $template, $refresh_data, $request; - - $url = redirect($url, true, $disable_cd_check); - if ($request->is_ajax()) - { - $refresh_data = array( - 'time' => $time, - 'url' => $url, - ); - } - else - { - // For XHTML compatibility we change back & to & - $url = str_replace('&', '&', $url); - - $template->assign_vars(array( - 'META' => '') - ); - } - - return $url; -} - -/** -* Outputs correct status line header. -* -* Depending on php sapi one of the two following forms is used: -* -* Status: 404 Not Found -* -* HTTP/1.x 404 Not Found -* -* HTTP version is taken from HTTP_VERSION environment variable, -* and defaults to 1.0. -* -* Sample usage: -* -* send_status_line(404, 'Not Found'); -* -* @param int $code HTTP status code -* @param string $message Message for the status code -* @return null -*/ -function send_status_line($code, $message) -{ - if (substr(strtolower(@php_sapi_name()), 0, 3) === 'cgi') - { - // in theory, we shouldn't need that due to php doing it. Reality offers a differing opinion, though - header("Status: $code $message", true, $code); - } - else - { - $version = phpbb_request_http_version(); - header("$version $code $message", true, $code); - } -} - -/** -* Returns the HTTP version used in the current request. -* -* Handles the case of being called before $request is present, -* in which case it falls back to the $_SERVER superglobal. -* -* @return string HTTP version -*/ -function phpbb_request_http_version() -{ - global $request; - - $version = ''; - if ($request && $request->server('SERVER_PROTOCOL')) - { - $version = $request->server('SERVER_PROTOCOL'); - } - else if (isset($_SERVER['SERVER_PROTOCOL'])) - { - $version = $_SERVER['SERVER_PROTOCOL']; - } - - if (!empty($version) && is_string($version) && preg_match('#^HTTP/[0-9]\.[0-9]$#', $version)) - { - return $version; - } - - return 'HTTP/1.0'; -} - -//Form validation - - -/** -* Add a secret hash for use in links/GET requests -* @param string $link_name The name of the link; has to match the name used in check_link_hash, otherwise no restrictions apply -* @return string the hash - -*/ -function generate_link_hash($link_name) -{ - global $user; - - if (!isset($user->data["hash_$link_name"])) - { - $user->data["hash_$link_name"] = substr(sha1($user->data['user_form_salt'] . $link_name), 0, 8); - } - - return $user->data["hash_$link_name"]; -} - - -/** -* checks a link hash - for GET requests -* @param string $token the submitted token -* @param string $link_name The name of the link -* @return boolean true if all is fine -*/ -function check_link_hash($token, $link_name) -{ - return $token === generate_link_hash($link_name); -} - -/** -* Add a secret token to the form (requires the S_FORM_TOKEN template variable) -* @param string $form_name The name of the form; has to match the name used in check_form_key, otherwise no restrictions apply -* @param string $template_variable_suffix A string that is appended to the name of the template variable to which the form elements are assigned -*/ -function add_form_key($form_name, $template_variable_suffix = '') -{ - global $config, $template, $user, $phpbb_dispatcher; - - $now = time(); - $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : ''; - $token = sha1($now . $user->data['user_form_salt'] . $form_name . $token_sid); - - $s_fields = build_hidden_fields(array( - 'creation_time' => $now, - 'form_token' => $token, - )); - - /** - * Perform additional actions on creation of the form token - * - * @event core.add_form_key - * @var string form_name The form name - * @var int now Current time timestamp - * @var string s_fields Generated hidden fields - * @var string token Form token - * @var string token_sid User session ID - * @var string template_variable_suffix The string that is appended to template variable name - * - * @since 3.1.0-RC3 - * @changed 3.1.11-RC1 Added template_variable_suffix - */ - $vars = array( - 'form_name', - 'now', - 's_fields', - 'token', - 'token_sid', - 'template_variable_suffix', - ); - extract($phpbb_dispatcher->trigger_event('core.add_form_key', compact($vars))); - - $template->assign_var('S_FORM_TOKEN' . $template_variable_suffix, $s_fields); -} - -/** - * Check the form key. Required for all altering actions not secured by confirm_box - * - * @param string $form_name The name of the form; has to match the name used - * in add_form_key, otherwise no restrictions apply - * @param int $timespan The maximum acceptable age for a submitted form - * in seconds. Defaults to the config setting. - * @return bool True, if the form key was valid, false otherwise - */ -function check_form_key($form_name, $timespan = false) -{ - global $config, $request, $user; - - if ($timespan === false) - { - // we enforce a minimum value of half a minute here. - $timespan = ($config['form_token_lifetime'] == -1) ? -1 : max(30, $config['form_token_lifetime']); - } - - if ($request->is_set_post('creation_time') && $request->is_set_post('form_token')) - { - $creation_time = abs($request->variable('creation_time', 0)); - $token = $request->variable('form_token', ''); - - $diff = time() - $creation_time; - - // If creation_time and the time() now is zero we can assume it was not a human doing this (the check for if ($diff)... - if (defined('DEBUG_TEST') || $diff && ($diff <= $timespan || $timespan === -1)) - { - $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : ''; - $key = sha1($creation_time . $user->data['user_form_salt'] . $form_name . $token_sid); - - if ($key === $token) - { - return true; - } - } - } - - return false; -} - -// Message/Login boxes - -/** -* Build Confirm box -* @param boolean $check True for checking if confirmed (without any additional parameters) and false for displaying the 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, $language, $phpbb_path_helper; - - if (isset($_POST['cancel'])) - { - return false; - } - - $confirm = ($language->lang('YES') === $request->variable('confirm', '', true, \phpbb\request\request_interface::POST)); - - if ($check && $confirm) - { - $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']) - { - return false; - } - - // Reset user_last_confirm_key - $sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '' - WHERE user_id = " . $user->data['user_id']; - $db->sql_query($sql); - - return true; - } - else if ($check) - { - return false; - } - - $s_hidden_fields = build_hidden_fields(array( - 'confirm_uid' => $user->data['user_id'], - 'sess' => $user->session_id, - 'sid' => $user->session_id, - )); - - // 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($confirm_title); - } - else - { - page_header($confirm_title); - } - - $template->set_filenames(array( - 'body' => $html_body) - ); - - // If activation key already exist, we better do not re-use the key (something very strange is going on...) - if ($request->variable('confirm_key', '')) - { - // This should not occur, therefore we cancel the operation to safe the user - return false; - } - - // re-add sid / transform & to & for user->page (user->page is always using &) - $use_page = ($u_action) ? $u_action : str_replace('&', '&', $user->page['page']); - $u_action = reapply_sid($phpbb_path_helper->get_valid_page($use_page, $config['enable_mod_rewrite'])); - $u_action .= ((strpos($u_action, '?') === false) ? '?' : '&') . 'confirm_key=' . $confirm_key; - - $template->assign_vars(array( - 'MESSAGE_TITLE' => $confirm_title, - 'MESSAGE_TEXT' => $confirm_text, - - 'YES_VALUE' => $language->lang('YES'), - 'S_CONFIRM_ACTION' => $u_action, - 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields, - 'S_AJAX_REQUEST' => $request->is_ajax(), - )); - - $sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "' - WHERE user_id = " . $user->data['user_id']; - $db->sql_query($sql); - - 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( - 'MESSAGE_BODY' => $template->assign_display('body'), - 'MESSAGE_TITLE' => $confirm_title, - 'MESSAGE_TEXT' => $confirm_text, - - 'YES_VALUE' => $language->lang('YES'), - 'S_CONFIRM_ACTION' => str_replace('&', '&', $u_action), //inefficient, rewrite whole function - 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields - )); - } - - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_footer(); - } - else - { - page_footer(); - } - - exit; // unreachable, page_footer() above will call exit() -} - -/** -* Generate login box or verify password -*/ -function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true) -{ - 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 (!$user->is_setup()) - { - $user->setup(); - } - - /** - * This event allows an extension to modify the login process - * - * @event core.login_box_before - * @var string redirect Redirect string - * @var string l_explain Explain language string - * @var string l_success Success language string - * @var bool admin Is admin? - * @var bool s_display Display full login form? - * @var string err Error string - * @since 3.1.9-RC1 - */ - $vars = array('redirect', 'l_explain', 'l_success', 'admin', 's_display', 'err'); - extract($phpbb_dispatcher->trigger_event('core.login_box_before', compact($vars))); - - // Print out error if user tries to authenticate as an administrator without having the privileges... - if ($admin && !$auth->acl_get('a_')) - { - // Not authd - // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions - if ($user->data['is_registered']) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL'); - } - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_ADMIN'); - } - - if (empty($err) && ($request->is_set_post('login') || ($request->is_set('login') && $request->variable('login', '') == 'external'))) - { - // Get credential - if ($admin) - { - $credential = $request->variable('credential', ''); - - if (strspn($credential, 'abcdef0123456789') !== strlen($credential) || strlen($credential) != 32) - { - if ($user->data['is_registered']) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL'); - } - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_ADMIN'); - } - - $password = $request->untrimmed_variable('password_' . $credential, '', true); - } - else - { - $password = $request->untrimmed_variable('password', '', true); - } - - $username = $request->variable('username', '', true); - $autologin = $request->is_set_post('autologin'); - $viewonline = (int) !$request->is_set_post('viewonline'); - $admin = ($admin) ? 1 : 0; - $viewonline = ($admin) ? $user->data['session_viewonline'] : $viewonline; - - // Check if the supplied username is equal to the one stored within the database if re-authenticating - if ($admin && utf8_clean_string($username) != utf8_clean_string($user->data['username'])) - { - // We log the attempt to use a different username... - $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'); - } - - // Check form key - if ($password && !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 - if ($admin) - { - if ($result['status'] == LOGIN_SUCCESS) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_SUCCESS'); - } - else - { - // Only log the failed attempt if a real user tried to. - // anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions - if ($user->data['is_registered']) - { - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL'); - } - } - } - - // The result parameter is always an array, holding the relevant information... - if ($result['status'] == LOGIN_SUCCESS) - { - $redirect = $request->variable('redirect', "{$phpbb_root_path}index.$phpEx"); - - /** - * This event allows an extension to modify the redirection when a user successfully logs in - * - * @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', 'result'); - extract($phpbb_dispatcher->trigger_event('core.login_box_redirect', compact($vars))); - - // append/replace SID (may change during the session for AOL users) - $redirect = reapply_sid($redirect); - - // Special case... the user is effectively banned, but we allow founders to login - if (defined('IN_CHECK_BAN') && $result['user_row']['user_type'] != USER_FOUNDER) - { - return; - } - - redirect($redirect); - } - - // Something failed, determine what... - if ($result['status'] == LOGIN_BREAK) - { - trigger_error($result['error_msg']); - } - - // Special cases... determine - switch ($result['status']) - { - case LOGIN_ERROR_PASSWORD_CONVERT: - $err = sprintf( - $user->lang[$result['error_msg']], - ($config['email_enable']) ? '' : '', - ($config['email_enable']) ? '' : '', - '', - '' - ); - break; - - case LOGIN_ERROR_ATTEMPTS: - - $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); - $captcha->init(CONFIRM_LOGIN); - // $captcha->reset(); - - $template->assign_vars(array( - 'CAPTCHA_TEMPLATE' => $captcha->get_template(), - )); - // no break; - - // Username, password, etc... - default: - $err = $user->lang[$result['error_msg']]; - - // Assign admin contact to some error messages - if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' || $result['error_msg'] == 'LOGIN_ERROR_PASSWORD') - { - $err = sprintf($user->lang[$result['error_msg']], '', ''); - } - - break; - } - - /** - * This event allows an extension to process when a user fails a login attempt - * - * @event core.login_box_failed - * @var array result Login result data - * @var string username User name used to login - * @var string password Password used to login - * @var string err Error message - * @since 3.1.3-RC1 - */ - $vars = array('result', 'username', 'password', 'err'); - extract($phpbb_dispatcher->trigger_event('core.login_box_failed', compact($vars))); - } - - // Assign credential for username/password pair - $credential = ($admin) ? md5(unique_id()) : false; - - $s_hidden_fields = array( - 'sid' => $user->session_id, - ); - - if ($redirect) - { - $s_hidden_fields['redirect'] = $redirect; - } - - if ($admin) - { - $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(); - - $auth_provider_data = $auth_provider->get_login_data(); - if ($auth_provider_data) - { - if (isset($auth_provider_data['VARS'])) - { - $template->assign_vars($auth_provider_data['VARS']); - } - - if (isset($auth_provider_data['BLOCK_VAR_NAME'])) - { - foreach ($auth_provider_data['BLOCK_VARS'] as $block_vars) - { - $template->assign_block_vars($auth_provider_data['BLOCK_VAR_NAME'], $block_vars); - } - } - - $template->assign_vars(array( - 'PROVIDER_TEMPLATE_FILE' => $auth_provider_data['TEMPLATE_FILE'], - )); - } - - // Add form token for login box - add_form_key($form_name, '_LOGIN'); - - $s_hidden_fields = build_hidden_fields($s_hidden_fields); - - $login_box_template_data = array( - 'LOGIN_ERROR' => $err, - 'LOGIN_EXPLAIN' => $l_explain, - - 'U_SEND_PASSWORD' => ($config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '', - 'U_RESEND_ACTIVATION' => ($config['require_activation'] == USER_ACTIVATION_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, - - 'S_ADMIN_AUTH' => $admin, - 'USERNAME' => ($admin) ? $user->data['username'] : '', - - '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']); - - $template->set_filenames(array( - 'body' => 'login_body.html') - ); - make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - - page_footer(); -} - -/** -* Generate forum login box -*/ -function login_forum_box($forum_data) -{ - global $db, $phpbb_container, $request, $template, $user, $phpbb_dispatcher, $phpbb_root_path, $phpEx; - - $password = $request->variable('password', '', true); - - $sql = 'SELECT forum_id - FROM ' . FORUMS_ACCESS_TABLE . ' - WHERE forum_id = ' . $forum_data['forum_id'] . ' - AND user_id = ' . $user->data['user_id'] . " - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return true; - } - - if ($password) - { - // Remove expired authorised sessions - $sql = 'SELECT f.session_id - FROM ' . FORUMS_ACCESS_TABLE . ' f - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (f.session_id = s.session_id) - WHERE s.session_id IS NULL'; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - do - { - $sql_in[] = (string) $row['session_id']; - } - while ($row = $db->sql_fetchrow($result)); - - // Remove expired sessions - $sql = 'DELETE FROM ' . FORUMS_ACCESS_TABLE . ' - WHERE ' . $db->sql_in_set('session_id', $sql_in); - $db->sql_query($sql); - } - $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'])) - { - $sql_ary = array( - 'forum_id' => (int) $forum_data['forum_id'], - 'user_id' => (int) $user->data['user_id'], - 'session_id' => (string) $user->session_id, - ); - - $db->sql_query('INSERT INTO ' . FORUMS_ACCESS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - return true; - } - - $template->assign_var('LOGIN_ERROR', $user->lang['WRONG_PASSWORD']); - } - - /** - * Performing additional actions, load additional data on forum login - * - * @event core.login_forum_box - * @var array forum_data Array with forum data - * @var string password Password entered - * @since 3.1.0-RC3 - */ - $vars = array('forum_data', 'password'); - extract($phpbb_dispatcher->trigger_event('core.login_forum_box', compact($vars))); - - page_header($user->lang['LOGIN']); - - // Add form token for login box - add_form_key('login', '_LOGIN'); - - $template->assign_vars(array( - 'FORUM_NAME' => isset($forum_data['forum_name']) ? $forum_data['forum_name'] : '', - 'S_LOGIN_ACTION' => build_url(array('f')), - 'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id']))) - ); - - $template->set_filenames(array( - 'body' => 'login_forum.html') - ); - - make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_data['forum_id']); - - page_footer(); -} - -// Little helpers - -/** -* Little helper for the build_hidden_fields function -*/ -function _build_hidden_fields($key, $value, $specialchar, $stripslashes) -{ - $hidden_fields = ''; - - if (!is_array($value)) - { - $value = ($stripslashes) ? stripslashes($value) : $value; - $value = ($specialchar) ? htmlspecialchars($value, ENT_COMPAT, 'UTF-8') : $value; - - $hidden_fields .= '' . "\n"; - } - else - { - foreach ($value as $_key => $_value) - { - $_key = ($stripslashes) ? stripslashes($_key) : $_key; - $_key = ($specialchar) ? htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') : $_key; - - $hidden_fields .= _build_hidden_fields($key . '[' . $_key . ']', $_value, $specialchar, $stripslashes); - } - } - - return $hidden_fields; -} - -/** -* Build simple hidden fields from array -* -* @param array $field_ary an array of values to build the hidden field from -* @param bool $specialchar if true, keys and values get specialchared -* @param bool $stripslashes if true, keys and values get stripslashed -* -* @return string the hidden fields -*/ -function build_hidden_fields($field_ary, $specialchar = false, $stripslashes = false) -{ - $s_hidden_fields = ''; - - foreach ($field_ary as $name => $vars) - { - $name = ($stripslashes) ? stripslashes($name) : $name; - $name = ($specialchar) ? htmlspecialchars($name, ENT_COMPAT, 'UTF-8') : $name; - - $s_hidden_fields .= _build_hidden_fields($name, $vars, $specialchar, $stripslashes); - } - - return $s_hidden_fields; -} - -/** -* Parse cfg file -*/ -function parse_cfg_file($filename, $lines = false) -{ - $parsed_items = array(); - - if ($lines === false) - { - $lines = file($filename); - } - - foreach ($lines as $line) - { - $line = trim($line); - - if (!$line || $line[0] == '#' || ($delim_pos = strpos($line, '=')) === false) - { - continue; - } - - // Determine first occurrence, since in values the equal sign is allowed - $key = htmlspecialchars(strtolower(trim(substr($line, 0, $delim_pos)))); - $value = trim(substr($line, $delim_pos + 1)); - - if (in_array($value, array('off', 'false', '0'))) - { - $value = false; - } - else if (in_array($value, array('on', 'true', '1'))) - { - $value = true; - } - else if (!trim($value)) - { - $value = ''; - } - else if (($value[0] == "'" && $value[strlen($value) - 1] == "'") || ($value[0] == '"' && $value[strlen($value) - 1] == '"')) - { - $value = htmlspecialchars(substr($value, 1, strlen($value)-2)); - } - else - { - $value = htmlspecialchars($value); - } - - $parsed_items[$key] = $value; - } - - if (isset($parsed_items['parent']) && isset($parsed_items['name']) && $parsed_items['parent'] == $parsed_items['name']) - { - unset($parsed_items['parent']); - } - - return $parsed_items; -} - -/** -* Return a nicely formatted backtrace. -* -* Turns the array returned by debug_backtrace() into HTML markup. -* Also filters out absolute paths to phpBB root. -* -* @return string HTML markup -*/ -function get_backtrace() -{ - $output = '
'; - $backtrace = debug_backtrace(); - - // We skip the first one, because it only shows this file/function - unset($backtrace[0]); - - foreach ($backtrace as $trace) - { - // Strip the current directory from path - $trace['file'] = (empty($trace['file'])) ? '(not given by php)' : htmlspecialchars(phpbb_filter_root_path($trace['file'])); - $trace['line'] = (empty($trace['line'])) ? '(not given by php)' : $trace['line']; - - // Only show function arguments for include etc. - // Other parameters may contain sensible information - $argument = ''; - if (!empty($trace['args'][0]) && in_array($trace['function'], array('include', 'require', 'include_once', 'require_once'))) - { - $argument = htmlspecialchars(phpbb_filter_root_path($trace['args'][0])); - } - - $trace['class'] = (!isset($trace['class'])) ? '' : $trace['class']; - $trace['type'] = (!isset($trace['type'])) ? '' : $trace['type']; - - $output .= '
'; - $output .= 'FILE: ' . $trace['file'] . '
'; - $output .= 'LINE: ' . ((!empty($trace['line'])) ? $trace['line'] : '') . '
'; - - $output .= 'CALL: ' . htmlspecialchars($trace['class'] . $trace['type'] . $trace['function']); - $output .= '(' . (($argument !== '') ? "'$argument'" : '') . ')
'; - } - $output .= '
'; - return $output; -} - -/** -* This function returns a regular expression pattern for commonly used expressions -* Use with / as delimiter for email mode and # for url modes -* mode can be: email|bbcode_htm|url|url_inline|www_url|www_url_inline|relative_url|relative_url_inline|ipv4|ipv6 -*/ -function get_preg_expression($mode) -{ - switch ($mode) - { - case 'email': - // Regex written by James Watts and Francisco Jose Martin Moreno - // http://fightingforalostcause.net/misc/2006/compare-email-regex.php - return '((?:[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+)@((((([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})?)'; - break; - - case 'bbcode_htm': - return array( - '#.*?#', - '#.*?#', - '#\2#', - '#.*?#', - '#(?:0|[1-9](?:(?:0|[1-9])+)*))[.](?(?:0|[1-9](?:(?:0|[1-9])+)*))[.](?(?:0|[1-9](?:(?:0|[1-9])+)*))(?:-(?(?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:0|[1-9](?:(?:0|[1-9])+)*))(?:[.](?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:0|[1-9](?:(?:0|[1-9])+)*)))*))?(?:[+](?(?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:(?:0|[1-9])+))(?:[.](?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:(?:0|[1-9])+)))*))?)$/'; - break; - } - - return ''; -} - -/** -* Generate regexp for naughty words censoring -* Depends on whether installed PHP version supports unicode properties -* -* @param string $word word template to be replaced -* -* @return string $preg_expr regex to use with word censor -*/ -function get_censor_preg_expression($word) -{ - // Unescape the asterisk to simplify further conversions - $word = str_replace('\*', '*', preg_quote($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 = '#(? strlen($longest_match)) - { - $longest_match = $match[0]; - $longest_match_offset = $match[1]; - } - } - - $ret = substr_replace($ret, '', $longest_match_offset, strlen($longest_match)); - - if ($longest_match_offset == strlen($ret)) - { - $ret .= ':'; - } - - if ($longest_match_offset == 0) - { - $ret = ':' . $ret; - } - - return $ret; - - default: - return false; - } -} - -/** -* Wrapper for inet_pton() -* -* Converts a human readable IP address to its packed in_addr representation -* inet_pton() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. -* -* @param string $address A human readable IPv4 or IPv6 address. -* -* @return mixed false if address is invalid, -* in_addr representation of the given address otherwise (string) -*/ -function phpbb_inet_pton($address) -{ - $ret = ''; - if (preg_match(get_preg_expression('ipv4'), $address)) - { - foreach (explode('.', $address) as $part) - { - $ret .= ($part <= 0xF ? '0' : '') . dechex($part); - } - - return pack('H*', $ret); - } - - if (preg_match(get_preg_expression('ipv6'), $address)) - { - $parts = explode(':', $address); - $missing_parts = 8 - count($parts) + 1; - - if (substr($address, 0, 2) === '::') - { - ++$missing_parts; - } - - if (substr($address, -2) === '::') - { - ++$missing_parts; - } - - $embedded_ipv4 = false; - $last_part = end($parts); - - if (preg_match(get_preg_expression('ipv4'), $last_part)) - { - $parts[count($parts) - 1] = ''; - $last_part = phpbb_inet_pton($last_part); - $embedded_ipv4 = true; - --$missing_parts; - } - - foreach ($parts as $i => $part) - { - if (strlen($part)) - { - $ret .= str_pad($part, 4, '0', STR_PAD_LEFT); - } - else if ($i && $i < count($parts) - 1) - { - $ret .= str_repeat('0000', $missing_parts); - } - } - - $ret = pack('H*', $ret); - - if ($embedded_ipv4) - { - $ret .= $last_part; - } - - return $ret; - } - - return false; -} - -/** -* Wrapper for php's checkdnsrr function. -* -* @param string $host Fully-Qualified Domain Name -* @param string $type Resource record type to lookup -* Supported types are: MX (default), A, AAAA, NS, TXT, CNAME -* Other types may work or may not work -* -* @return mixed true if entry found, -* false if entry not found, -* null if this function is not supported by this environment -* -* Since null can also be returned, you probably want to compare the result -* with === true or === false, -*/ -function phpbb_checkdnsrr($host, $type = 'MX') -{ - // The dot indicates to search the DNS root (helps those having DNS prefixes on the same domain) - if (substr($host, -1) == '.') - { - $host_fqdn = $host; - $host = substr($host, 0, -1); - } - else - { - $host_fqdn = $host . '.'; - } - // $host has format some.host.example.com - // $host_fqdn has format some.host.example.com. - - // If we're looking for an A record we can use gethostbyname() - if ($type == 'A' && function_exists('gethostbyname')) - { - return (@gethostbyname($host_fqdn) == $host_fqdn) ? false : true; - } - - if (function_exists('checkdnsrr')) - { - return checkdnsrr($host_fqdn, $type); - } - - 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. - $type_constant = 'DNS_' . $type; - $type_param = (defined($type_constant)) ? constant($type_constant) : DNS_ANY; - - // dns_get_record() might throw E_WARNING and return false for records that do not exist - $resultset = @dns_get_record($host_fqdn, $type_param); - - if (empty($resultset) || !is_array($resultset)) - { - return false; - } - else if ($type_param == DNS_ANY) - { - // $resultset is a non-empty array - return true; - } - - foreach ($resultset as $result) - { - if ( - isset($result['host']) && $result['host'] == $host && - isset($result['type']) && $result['type'] == $type - ) - { - return true; - } - } - - return false; - } - - // If we're on Windows we can still try to call nslookup via exec() as a last resort - if (DIRECTORY_SEPARATOR == '\\' && function_exists('exec')) - { - @exec('nslookup -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host_fqdn), $output); - - // If output is empty, the nslookup failed - if (empty($output)) - { - return NULL; - } - - foreach ($output as $line) - { - $line = trim($line); - - if (empty($line)) - { - continue; - } - - // Squash tabs and multiple whitespaces to a single whitespace. - $line = preg_replace('/\s+/', ' ', $line); - - switch ($type) - { - case 'MX': - if (stripos($line, "$host MX") === 0) - { - return true; - } - break; - - case 'NS': - if (stripos($line, "$host nameserver") === 0) - { - return true; - } - break; - - case 'TXT': - if (stripos($line, "$host text") === 0) - { - return true; - } - break; - - case 'CNAME': - if (stripos($line, "$host canonical name") === 0) - { - return true; - } - break; - - default: - case 'AAAA': - // AAAA records returned by nslookup on Windows XP/2003 have this format. - // Later Windows versions use the A record format below for AAAA records. - if (stripos($line, "$host AAAA IPv6 address") === 0) - { - return true; - } - // No break - - case 'A': - if (!empty($host_matches)) - { - // Second line - if (stripos($line, "Address: ") === 0) - { - return true; - } - else - { - $host_matches = false; - } - } - else if (stripos($line, "Name: $host") === 0) - { - // First line - $host_matches = true; - } - break; - } - } - - return false; - } - - return NULL; -} - -// Handler, header and footer - -/** -* Error and message handler, call with trigger_error if read -*/ -function msg_handler($errno, $msg_text, $errfile, $errline) -{ - global $cache, $db, $auth, $template, $config, $user, $request; - 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) - { - return; - } - - // Message handler is stripping text. In case we need it, we are possible to define long text... - if (isset($msg_long_text) && $msg_long_text && !$msg_text) - { - $msg_text = $msg_long_text; - } - - switch ($errno) - { - case E_NOTICE: - case E_WARNING: - - // Check the error reporting level and return if the error level does not match - // If DEBUG is defined the default level is E_ALL - if (($errno & ((defined('DEBUG')) ? E_ALL : error_reporting())) == 0) - { - return; - } - - if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false) - { - $errfile = phpbb_filter_root_path($errfile); - $msg_text = phpbb_filter_root_path($msg_text); - $error_name = ($errno === E_WARNING) ? 'PHP Warning' : 'PHP Notice'; - echo '[phpBB Debug] ' . $error_name . ': in file ' . $errfile . ' on line ' . $errline . ': ' . $msg_text . '
' . "\n"; - - // we are writing an image - the user won't see the debug, so let's place it in the log - if (defined('IMAGE_OUTPUT') || defined('IN_CRON')) - { - $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_IMAGE_GENERATION_ERROR', false, array($errfile, $errline, $msg_text)); - } - // echo '

BACKTRACE
' . get_backtrace() . '
' . "\n"; - } - - return; - - break; - - case E_USER_ERROR: - - 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); - - $l_return_index = sprintf($user->lang['RETURN_INDEX'], '', ''); - $l_notify = ''; - - if (!empty($config['board_contact'])) - { - $l_notify = '

' . sprintf($user->lang['NOTIFY_ADMIN_EMAIL'], $config['board_contact']) . '

'; - } - } - else - { - $msg_title = 'General Error'; - $l_return_index = 'Return to index page'; - $l_notify = ''; - - if (!empty($config['board_contact'])) - { - $l_notify = '

Please notify the board administrator or webmaster: ' . $config['board_contact'] . '

'; - } - } - - $log_text = $msg_text; - $backtrace = get_backtrace(); - if ($backtrace) - { - $log_text .= '

BACKTRACE
' . $backtrace; - } - - if (defined('IN_INSTALL') || defined('DEBUG') || isset($auth) && $auth->acl_get('a_')) - { - $msg_text = $log_text; - - // If this is defined there already was some output - // So let's not break it - if (defined('IN_DB_UPDATE')) - { - echo '
' . $msg_text . '
'; - - $db->sql_return_on_error(true); - phpbb_end_update($cache, $config); - } - } - - if ((defined('IN_CRON') || defined('IMAGE_OUTPUT')) && isset($db)) - { - // let's avoid loops - $db->sql_return_on_error(true); - $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); - } - - // Do not send 200 OK, but service unavailable on errors - send_status_line(503, 'Service Unavailable'); - - garbage_collection(); - - // Try to not call the adm page data... - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '' . $msg_title . ''; - echo ''; - echo ''; - echo ''; - echo '
'; - echo ' '; - echo '
'; - echo '
'; - echo '
'; - echo '

' . $msg_title . '

'; - - echo '
' . $msg_text . '
'; - - echo $l_notify; - - echo '
'; - echo '
'; - echo '
'; - echo ' '; - echo '
'; - echo ''; - echo ''; - - exit_handler(); - - // On a fatal error (and E_USER_ERROR *is* fatal) we never want other scripts to continue and force an exit here. - exit; - break; - - case E_USER_WARNING: - case E_USER_NOTICE: - - define('IN_ERROR_HANDLER', true); - - if (empty($user->data)) - { - $user->session_begin(); - } - - // We re-init the auth array to get correct results on login/logout - $auth->acl($user->data); - - if (!$user->is_setup()) - { - $user->setup(); - } - - if ($msg_text == 'ERROR_NO_ATTACHMENT' || $msg_text == 'NO_FORUM' || $msg_text == 'NO_TOPIC' || $msg_text == 'NO_USER') - { - send_status_line(404, 'Not Found'); - } - - $msg_text = (!empty($user->lang[$msg_text])) ? $user->lang[$msg_text] : $msg_text; - $msg_title = (!isset($msg_title)) ? $user->lang['INFORMATION'] : ((!empty($user->lang[$msg_title])) ? $user->lang[$msg_title] : $msg_title); - - if (!defined('HEADER_INC')) - { - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_header($msg_title); - } - else - { - page_header($msg_title); - } - } - - $template->set_filenames(array( - 'body' => 'message_body.html') - ); - - $template->assign_vars(array( - 'MESSAGE_TITLE' => $msg_title, - 'MESSAGE_TEXT' => $msg_text, - 'S_USER_WARNING' => ($errno == E_USER_WARNING) ? true : false, - 'S_USER_NOTICE' => ($errno == E_USER_NOTICE) ? true : false) - ); - - if ($request->is_ajax()) - { - global $refresh_data; - - $json_response = new \phpbb\json_response; - $json_response->send(array( - 'MESSAGE_TITLE' => $msg_title, - 'MESSAGE_TEXT' => $msg_text, - 'S_USER_WARNING' => ($errno == E_USER_WARNING) ? true : false, - 'S_USER_NOTICE' => ($errno == E_USER_NOTICE) ? true : false, - 'REFRESH_DATA' => (!empty($refresh_data)) ? $refresh_data : null - )); - } - - // We do not want the cron script to be called on error messages - define('IN_CRON', true); - - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_footer(); - } - else - { - page_footer(); - } - - exit_handler(); - break; - - // PHP4 compatibility - case E_DEPRECATED: - return true; - break; - } - - // If we notice an error not handled here we pass this back to PHP by returning false - // This may not work for all php versions - return false; -} - -/** -* Removes absolute path to phpBB root directory from error messages -* and converts backslashes to forward slashes. -* -* @param string $errfile Absolute file path -* (e.g. /var/www/phpbb3/phpBB/includes/functions.php) -* Please note that if $errfile is outside of the phpBB root, -* the root path will not be found and can not be filtered. -* @return string Relative file path -* (e.g. /includes/functions.php) -*/ -function phpbb_filter_root_path($errfile) -{ - global $phpbb_filesystem; - - static $root_path; - - if (empty($root_path)) - { - 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); -} - -/** -* Queries the session table to get information about online guests -* @param int $item_id Limits the search to the item with this id -* @param string $item The name of the item which is stored in the session table as session_{$item}_id -* @return int The number of active distinct guest sessions -*/ -function obtain_guest_count($item_id = 0, $item = 'forum') -{ - global $db, $config; - - if ($item_id) - { - $reading_sql = ' AND s.session_' . $item . '_id = ' . (int) $item_id; - } - else - { - $reading_sql = ''; - } - $time = (time() - (intval($config['load_online_time']) * 60)); - - // Get number of online guests - - if ($db->get_sql_layer() === 'sqlite3') - { - $sql = 'SELECT COUNT(session_ip) as num_guests - FROM ( - SELECT DISTINCT s.session_ip - FROM ' . SESSIONS_TABLE . ' s - WHERE s.session_user_id = ' . ANONYMOUS . ' - AND s.session_time >= ' . ($time - ((int) ($time % 60))) . - $reading_sql . - ')'; - } - else - { - $sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests - FROM ' . SESSIONS_TABLE . ' s - WHERE s.session_user_id = ' . ANONYMOUS . ' - AND s.session_time >= ' . ($time - ((int) ($time % 60))) . - $reading_sql; - } - $result = $db->sql_query($sql); - $guests_online = (int) $db->sql_fetchfield('num_guests'); - $db->sql_freeresult($result); - - return $guests_online; -} - -/** -* Queries the session table to get information about online users -* @param int $item_id Limits the search to the item with this id -* @param string $item The name of the item which is stored in the session table as session_{$item}_id -* @return array An array containing the ids of online, hidden and visible users, as well as statistical info -*/ -function obtain_users_online($item_id = 0, $item = 'forum') -{ - global $db, $config; - - $reading_sql = ''; - if ($item_id !== 0) - { - $reading_sql = ' AND s.session_' . $item . '_id = ' . (int) $item_id; - } - - $online_users = array( - 'online_users' => array(), - 'hidden_users' => array(), - 'total_online' => 0, - 'visible_online' => 0, - 'hidden_online' => 0, - 'guests_online' => 0, - ); - - if ($config['load_online_guests']) - { - $online_users['guests_online'] = obtain_guest_count($item_id, $item); - } - - // a little discrete magic to cache this for 30 seconds - $time = (time() - (intval($config['load_online_time']) * 60)); - - $sql = 'SELECT s.session_user_id, s.session_ip, s.session_viewonline - FROM ' . SESSIONS_TABLE . ' s - WHERE s.session_time >= ' . ($time - ((int) ($time % 30))) . - $reading_sql . - ' AND s.session_user_id <> ' . ANONYMOUS; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - // Skip multiple sessions for one user - if (!isset($online_users['online_users'][$row['session_user_id']])) - { - $online_users['online_users'][$row['session_user_id']] = (int) $row['session_user_id']; - if ($row['session_viewonline']) - { - $online_users['visible_online']++; - } - else - { - $online_users['hidden_users'][$row['session_user_id']] = (int) $row['session_user_id']; - $online_users['hidden_online']++; - } - } - } - $online_users['total_online'] = $online_users['guests_online'] + $online_users['visible_online'] + $online_users['hidden_online']; - $db->sql_freeresult($result); - - return $online_users; -} - -/** -* Uses the result of obtain_users_online to generate a localized, readable representation. -* @param mixed $online_users result of obtain_users_online - array with user_id lists for total, hidden and visible users, and statistics -* @param int $item_id Indicate that the data is limited to one item and not global -* @param string $item The name of the item which is stored in the session table as session_{$item}_id -* @return array An array containing the string for output to the template -*/ -function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum') -{ - global $config, $db, $user, $auth, $phpbb_dispatcher; - - $user_online_link = $rowset = array(); - // Need caps version of $item for language-strings - $item_caps = strtoupper($item); - - 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', - 'FROM' => array( - USERS_TABLE => 'u', - ), - 'WHERE' => $db->sql_in_set('u.user_id', $online_users['online_users']), - 'ORDER_BY' => 'u.username_clean ASC', - ); - - /** - * Modify SQL query to obtain online users data - * - * @event core.obtain_users_online_string_sql - * @var array online_users Array with online users data - * from obtain_users_online() - * @var int item_id Restrict online users to item id - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var array sql_ary SQL query array to obtain users online data - * @since 3.1.4-RC1 - * @changed 3.1.7-RC1 Change sql query into array and adjust var accordingly. Allows extension authors the ability to adjust the sql_ary. - */ - $vars = array('online_users', 'item_id', 'item', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_sql', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - $rowset = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - foreach ($rowset as $row) - { - // User is logged in and therefore not a guest - if ($row['user_id'] != ANONYMOUS) - { - if (isset($online_users['hidden_users'][$row['user_id']])) - { - $row['username'] = '' . $row['username'] . ''; - } - - if (!isset($online_users['hidden_users'][$row['user_id']]) || $auth->acl_get('u_viewonline') || $row['user_id'] === $user->data['user_id']) - { - $user_online_link[$row['user_id']] = get_username_string(($row['user_type'] <> USER_IGNORE) ? 'full' : 'no_profile', $row['user_id'], $row['username'], $row['user_colour']); - } - } - } - } - - /** - * Modify online userlist data - * - * @event core.obtain_users_online_string_before_modify - * @var array online_users Array with online users data - * from obtain_users_online() - * @var int item_id Restrict online users to item id - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var array rowset Array with online users data - * @var array user_online_link Array with online users items (usernames) - * @since 3.1.10-RC1 - */ - $vars = array( - 'online_users', - 'item_id', - 'item', - 'rowset', - 'user_online_link', - ); - extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_before_modify', compact($vars))); - - $online_userlist = implode(', ', $user_online_link); - - if (!$online_userlist) - { - $online_userlist = $user->lang['NO_ONLINE_USERS']; - } - - if ($item_id === 0) - { - $online_userlist = $user->lang['REGISTERED_USERS'] . ' ' . $online_userlist; - } - else if ($config['load_online_guests']) - { - $online_userlist = $user->lang('BROWSING_' . $item_caps . '_GUESTS', $online_users['guests_online'], $online_userlist); - } - else - { - $online_userlist = sprintf($user->lang['BROWSING_' . $item_caps], $online_userlist); - } - // Build online listing - $visible_online = $user->lang('REG_USERS_TOTAL', (int) $online_users['visible_online']); - $hidden_online = $user->lang('HIDDEN_USERS_TOTAL', (int) $online_users['hidden_online']); - - if ($config['load_online_guests']) - { - $guests_online = $user->lang('GUEST_USERS_TOTAL', (int) $online_users['guests_online']); - $l_online_users = $user->lang('ONLINE_USERS_TOTAL_GUESTS', (int) $online_users['total_online'], $visible_online, $hidden_online, $guests_online); - } - else - { - $l_online_users = $user->lang('ONLINE_USERS_TOTAL', (int) $online_users['total_online'], $visible_online, $hidden_online); - } - - /** - * Modify online userlist data - * - * @event core.obtain_users_online_string_modify - * @var array online_users Array with online users data - * from obtain_users_online() - * @var int item_id Restrict online users to item id - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var array rowset Array with online users data - * @var array user_online_link Array with online users items (usernames) - * @var string online_userlist String containing users online list - * @var string l_online_users String with total online users count info - * @since 3.1.4-RC1 - */ - $vars = array( - 'online_users', - 'item_id', - 'item', - 'rowset', - 'user_online_link', - 'online_userlist', - 'l_online_users', - ); - extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_modify', compact($vars))); - - return array( - 'online_userlist' => $online_userlist, - 'l_online_users' => $l_online_users, - ); -} - -/** -* Get option bitfield from custom data -* -* @param int $bit The bit/value to get -* @param int $data Current bitfield to check -* @return bool Returns true if value of constant is set in bitfield, else false -*/ -function phpbb_optionget($bit, $data) -{ - return ($data & 1 << (int) $bit) ? true : false; -} - -/** -* Set option bitfield -* -* @param int $bit The bit/value to set/unset -* @param bool $set True if option should be set, false if option should be unset. -* @param int $data Current bitfield to change -* -* @return int The new bitfield -*/ -function phpbb_optionset($bit, $set, $data) -{ - if ($set && !($data & 1 << $bit)) - { - $data += 1 << $bit; - } - else if (!$set && ($data & 1 << $bit)) - { - $data -= 1 << $bit; - } - - return $data; -} - -/** -* Login using http authenticate. -* -* @param array $param Parameter array, see $param_defaults array. -* -* @return null -*/ -function phpbb_http_login($param) -{ - global $auth, $user, $request; - global $config; - - $param_defaults = array( - 'auth_message' => '', - - 'autologin' => false, - 'viewonline' => true, - 'admin' => false, - ); - - // Overwrite default values with passed values - $param = array_merge($param_defaults, $param); - - // User is already logged in - // We will not overwrite his session - if (!empty($user->data['is_registered'])) - { - return; - } - - // $_SERVER keys to check - $username_keys = array( - 'PHP_AUTH_USER', - 'Authorization', - 'REMOTE_USER', 'REDIRECT_REMOTE_USER', - 'HTTP_AUTHORIZATION', 'REDIRECT_HTTP_AUTHORIZATION', - 'REMOTE_AUTHORIZATION', 'REDIRECT_REMOTE_AUTHORIZATION', - 'AUTH_USER', - ); - - $password_keys = array( - 'PHP_AUTH_PW', - 'REMOTE_PASSWORD', - 'AUTH_PASSWORD', - ); - - $username = null; - foreach ($username_keys as $k) - { - if ($request->is_set($k, \phpbb\request\request_interface::SERVER)) - { - $username = htmlspecialchars_decode($request->server($k)); - break; - } - } - - $password = null; - foreach ($password_keys as $k) - { - if ($request->is_set($k, \phpbb\request\request_interface::SERVER)) - { - $password = htmlspecialchars_decode($request->server($k)); - break; - } - } - - // Decode encoded information (IIS, CGI, FastCGI etc.) - if (!is_null($username) && is_null($password) && strpos($username, 'Basic ') === 0) - { - list($username, $password) = explode(':', base64_decode(substr($username, 6)), 2); - } - - if (!is_null($username) && !is_null($password)) - { - set_var($username, $username, 'string', true); - set_var($password, $password, 'string', true); - - $auth_result = $auth->login($username, $password, $param['autologin'], $param['viewonline'], $param['admin']); - - if ($auth_result['status'] == LOGIN_SUCCESS) - { - return; - } - else if ($auth_result['status'] == LOGIN_ERROR_ATTEMPTS) - { - send_status_line(401, 'Unauthorized'); - - trigger_error('NOT_AUTHORISED'); - } - } - - // Prepend sitename to auth_message - $param['auth_message'] = ($param['auth_message'] === '') ? $config['sitename'] : $config['sitename'] . ' - ' . $param['auth_message']; - - // We should probably filter out non-ASCII characters - RFC2616 - $param['auth_message'] = preg_replace('/[\x80-\xFF]/', '?', $param['auth_message']); - - header('WWW-Authenticate: Basic realm="' . $param['auth_message'] . '"'); - send_status_line(401, 'Unauthorized'); - - trigger_error('NOT_AUTHORISED'); -} - -/** -* Escapes and quotes a string for use as an HTML/XML attribute value. -* -* This is a port of Python xml.sax.saxutils quoteattr. -* -* The function will attempt to choose a quote character in such a way as to -* avoid escaping quotes in the string. If this is not possible the string will -* be wrapped in double quotes and double quotes will be escaped. -* -* @param string $data The string to be escaped -* @param array $entities Associative array of additional entities to be escaped -* @return string Escaped and quoted string -*/ -function phpbb_quoteattr($data, $entities = null) -{ - $data = str_replace('&', '&', $data); - $data = str_replace('>', '>', $data); - $data = str_replace('<', '<', $data); - - $data = str_replace("\n", ' ', $data); - $data = str_replace("\r", ' ', $data); - $data = str_replace("\t", ' ', $data); - - if (!empty($entities)) - { - $data = str_replace(array_keys($entities), array_values($entities), $data); - } - - if (strpos($data, '"') !== false) - { - if (strpos($data, "'") !== false) - { - $data = '"' . str_replace('"', '"', $data) . '"'; - } - else - { - $data = "'" . $data . "'"; - } - } - else - { - $data = '"' . $data . '"'; - } - - return $data; -} - -/** -* Converts query string (GET) parameters in request into hidden fields. -* -* Useful for forwarding GET parameters when submitting forms with GET method. -* -* It is possible to omit some of the GET parameters, which is useful if -* they are specified in the form being submitted. -* -* sid is always omitted. -* -* @param \phpbb\request\request $request Request object -* @param array $exclude A list of variable names that should not be forwarded -* @return string HTML with hidden fields -*/ -function phpbb_build_hidden_fields_for_query_params($request, $exclude = null) -{ - $names = $request->variable_names(\phpbb\request\request_interface::GET); - $hidden = ''; - foreach ($names as $name) - { - // Sessions are dealt with elsewhere, omit sid always - if ($name == 'sid') - { - continue; - } - - // Omit any additional parameters requested - if (!empty($exclude) && in_array($name, $exclude)) - { - continue; - } - - $escaped_name = phpbb_quoteattr($name); - - // Note: we might retrieve the variable from POST or cookies - // here. To avoid exposing cookies, skip variables that are - // overwritten somewhere other than GET entirely. - $value = $request->variable($name, '', true); - $get_value = $request->variable($name, '', true, \phpbb\request\request_interface::GET); - if ($value === $get_value) - { - $escaped_value = phpbb_quoteattr($value); - $hidden .= ""; - } - } - return $hidden; -} - -/** -* Get user avatar -* -* @param array $user_row Row from the users table -* @param string $alt Optional language string for alt tag within image, can be a language key or text -* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP -* @param bool $lazy If true, will be lazy loaded (requires JS) -* -* @return string Avatar html -*/ -function phpbb_get_user_avatar($user_row, $alt = 'USER_AVATAR', $ignore_config = false, $lazy = false) -{ - $row = \phpbb\avatar\manager::clean_row($user_row, 'user'); - return phpbb_get_avatar($row, $alt, $ignore_config, $lazy); -} - -/** -* 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 phpbb_get_group_avatar($user_row, $alt = 'GROUP_AVATAR', $ignore_config = false, $lazy = false) -{ - $row = \phpbb\avatar\manager::clean_row($user_row, 'group'); - return phpbb_get_avatar($row, $alt, $ignore_config, $lazy); -} - -/** -* Get avatar -* -* @param array $row Row cleaned by \phpbb\avatar\manager::clean_row -* @param string $alt Optional language string for alt tag within image, can be a language key or text -* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP -* @param bool $lazy If true, will be lazy loaded (requires JS) -* -* @return string Avatar html -*/ -function phpbb_get_avatar($row, $alt, $ignore_config = false, $lazy = false) -{ - global $user, $config; - global $phpbb_container, $phpbb_dispatcher; - - if (!$config['allow_avatar'] && !$ignore_config) - { - return ''; - } - - $avatar_data = array( - 'src' => $row['avatar'], - 'width' => $row['avatar_width'], - '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 = ''; - - if ($driver) - { - $html = $driver->get_custom_html($user, $row, $alt); - $avatar_data = $driver->get_data($row); - } - else - { - $avatar_data['src'] = ''; - } - - if (empty($html) && !empty($avatar_data['src'])) - { - if ($lazy) - { - // Determine board url - we may need it later - $board_url = generate_board_url() . '/'; - // 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. - $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; - - $theme = "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme'; - - $src = 'src="' . $theme . '/images/no_avatar.gif" data-src="' . $avatar_data['src'] . '"'; - } - else - { - $src = 'src="' . $avatar_data['src'] . '"'; - } - - $html = ''; - } - - /** - * Event to modify HTML tag of avatar - * - * @event core.get_avatar_after - * @var array row Row cleaned by \phpbb\avatar\manager::clean_row - * @var string alt Optional language string for alt tag within image, can be a language key or text - * @var bool ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP - * @var array avatar_data The HTML attributes for avatar tag - * @var string html The HTML tag of generated avatar - * @since 3.1.6-RC1 - */ - $vars = array('row', 'alt', 'ignore_config', 'avatar_data', 'html'); - extract($phpbb_dispatcher->trigger_event('core.get_avatar_after', compact($vars))); - - return $html; -} - -/** -* Generate page header -*/ -function page_header($page_title = '', $display_online_list = false, $item_id = 0, $item = 'forum', $send_headers = true) -{ - global $db, $config, $template, $SID, $_SID, $_EXTRA_URL, $user, $auth, $phpEx, $phpbb_root_path; - global $phpbb_dispatcher, $request, $phpbb_container, $phpbb_admin_path; - - if (defined('HEADER_INC')) - { - return; - } - - define('HEADER_INC', true); - - // A listener can set this variable to `true` when it overrides this function - $page_header_override = false; - - /** - * Execute code and/or overwrite page_header() - * - * @event core.page_header - * @var string page_title Page title - * @var bool display_online_list Do we display online users list - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var int item_id Restrict online users to item id - * @var bool page_header_override Shall we return instead of running - * the rest of page_header() - * @since 3.1.0-a1 - */ - $vars = array('page_title', 'display_online_list', 'item_id', 'item', 'page_header_override'); - extract($phpbb_dispatcher->trigger_event('core.page_header', compact($vars))); - - if ($page_header_override) - { - return; - } - - // gzip_compression - if ($config['gzip_compress']) - { - // to avoid partially compressed output resulting in blank pages in - // the browser or error messages, compression is disabled in a few cases: - // - // 1) if headers have already been sent, this indicates plaintext output - // has been started so further content must not be compressed - // 2) the length of the current output buffer is non-zero. This means - // there is already some uncompressed content in this output buffer - // so further output must not be compressed - // 3) if more than one level of output buffering is used because we - // cannot test all output buffer level content lengths. One level - // could be caused by php.ini output_buffering. Anything - // beyond that is manual, so the code wrapping phpBB in output buffering - // can easily compress the output itself. - // - if (@extension_loaded('zlib') && !headers_sent() && ob_get_level() <= 1 && ob_get_length() == 0) - { - ob_start('ob_gzhandler'); - } - } - - $user->update_session_infos(); - - // Generate logged in/logged out status - if ($user->data['user_id'] != ANONYMOUS) - { - $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout', true, $user->session_id); - $l_login_logout = $user->lang['LOGOUT']; - } - else - { - $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login'); - $l_login_logout = $user->lang['LOGIN']; - } - - // Last visit date/time - $s_last_visit = ($user->data['user_id'] != ANONYMOUS) ? $user->format_date($user->data['session_last_visit']) : ''; - - // Get users online list ... if required - $l_online_users = $online_userlist = $l_online_record = $l_online_time = ''; - - if ($config['load_online'] && $config['load_online_time'] && $display_online_list) - { - /** - * Load online data: - * For obtaining another session column use $item and $item_id in the function-parameter, whereby the column is session_{$item}_id. - */ - $item_id = max($item_id, 0); - - $online_users = obtain_users_online($item_id, $item); - $user_online_strings = obtain_users_online_string($online_users, $item_id, $item); - - $l_online_users = $user_online_strings['l_online_users']; - $online_userlist = $user_online_strings['online_userlist']; - $total_online_users = $online_users['total_online']; - - if ($total_online_users > $config['record_online_users']) - { - $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)); - - $l_online_time = $user->lang('VIEW_ONLINE_TIMES', (int) $config['load_online_time']); - } - - $s_privmsg_new = false; - - // Check for new private messages if user is logged in - if (!empty($user->data['is_registered'])) - { - if ($user->data['user_new_privmsg']) - { - if (!$user->data['user_last_privmsg'] || $user->data['user_last_privmsg'] > $user->data['session_last_visit']) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_last_privmsg = ' . $user->data['session_last_visit'] . ' - WHERE user_id = ' . $user->data['user_id']; - $db->sql_query($sql); - - $s_privmsg_new = true; - } - else - { - $s_privmsg_new = false; - } - } - else - { - $s_privmsg_new = false; - } - } - - $forum_id = $request->variable('f', 0); - $topic_id = $request->variable('t', 0); - - $s_feed_news = false; - - // Get option for news - if ($config['feed_enable']) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0'); - $result = $db->sql_query_limit($sql, 1, 0, 600); - $s_feed_news = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - } - - // Determine board url - we may need it later - $board_url = generate_board_url() . '/'; - // 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; - - // Send a proper content-language to the output - $user_lang = $user->lang['USER_LANG']; - if (strpos($user_lang, '-x-') !== false) - { - $user_lang = substr($user_lang, 0, strpos($user_lang, '-x-')); - } - - $s_search_hidden_fields = array(); - if ($_SID) - { - $s_search_hidden_fields['sid'] = $_SID; - } - - if (!empty($_EXTRA_URL)) - { - foreach ($_EXTRA_URL as $url_param) - { - $url_param = explode('=', $url_param, 2); - $s_search_hidden_fields[$url_param[0]] = $url_param[1]; - } - } - - $dt = $user->create_datetime(); - $timezone_offset = $user->lang(array('timezones', 'UTC_OFFSET'), phpbb_format_timezone_offset($dt->getOffset())); - $timezone_name = $user->timezone->getName(); - if (isset($user->lang['timezones'][$timezone_name])) - { - $timezone_name = $user->lang['timezones'][$timezone_name]; - } - - // Output the notifications - $notifications = false; - 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('notification.method.board', array( - 'all_unread' => true, - 'limit' => 5, - )); - - foreach ($notifications['notifications'] as $notification) - { - $template->assign_block_vars('notifications', $notification->prepare_for_display()); - } - } - - /** @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()))); - /** - * 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'], - 'SITE_DESCRIPTION' => $config['site_desc'], - 'PAGE_TITLE' => $page_title, - 'SCRIPT_NAME' => str_replace('.' . $phpEx, '', $user->page['page_name']), - 'LAST_VISIT_DATE' => sprintf($user->lang['YOU_LAST_VISIT'], $s_last_visit), - 'LAST_VISIT_YOU' => $s_last_visit, - 'CURRENT_TIME' => sprintf($user->lang['CURRENT_TIME'], $user->format_date(time(), false, true)), - 'TOTAL_USERS_ONLINE' => $l_online_users, - 'LOGGED_IN_USER_LIST' => $online_userlist, - 'RECORD_USERS' => $l_online_record, - - 'PRIVATE_MESSAGE_COUNT' => (!empty($user->data['user_unread_privmsg'])) ? $user->data['user_unread_privmsg'] : 0, - 'CURRENT_USER_AVATAR' => phpbb_get_user_avatar($user->data), - 'CURRENT_USERNAME_SIMPLE' => get_username_string('no_profile', $user->data['user_id'], $user->data['username'], $user->data['user_colour']), - 'CURRENT_USERNAME_FULL' => get_username_string('full', $user->data['user_id'], $user->data['username'], $user->data['user_colour']), - 'UNREAD_NOTIFICATIONS_COUNT' => ($notifications !== false) ? $notifications['unread_count'] : '', - 'NOTIFICATIONS_COUNT' => ($notifications !== false) ? $notifications['unread_count'] : '', - '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&mode=notification_list&mark=all&token=' . $notification_mark_hash), - 'U_NOTIFICATION_SETTINGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications&mode=notification_options'), - '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'], - 'S_USER_NEW' => $user->data['user_new'], - - 'SID' => $SID, - '_SID' => $_SID, - 'SESSION_ID' => $user->session_id, - 'ROOT_PATH' => $web_path, - 'BOARD_URL' => $board_url, - - 'L_LOGIN_LOGOUT' => $l_login_logout, - 'L_INDEX' => ($config['board_index_text'] !== '') ? $config['board_index_text'] : $user->lang['FORUM_INDEX'], - 'L_SITE_HOME' => ($config['site_home_text'] !== '') ? $config['site_home_text'] : $user->lang['HOME'], - 'L_ONLINE_EXPLAIN' => $l_online_time, - - 'U_PRIVATEMSGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'), - 'U_RETURN_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'), - 'U_MEMBERLIST' => append_sid("{$phpbb_root_path}memberlist.$phpEx"), - 'U_VIEWONLINE' => ($auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel')) ? append_sid("{$phpbb_root_path}viewonline.$phpEx") : '', - 'U_LOGIN_LOGOUT' => $u_login_logout, - 'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"), - 'U_SEARCH' => append_sid("{$phpbb_root_path}search.$phpEx"), - 'U_SITE_HOME' => $config['site_home_url'], - 'U_REGISTER' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), - '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' => $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'), - 'U_SEARCH_UNREAD' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unreadposts'), - 'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'), - 'U_DELETE_COOKIES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'), - 'U_CONTACT_US' => ($config['contact_admin_form_enable'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin') : '', - '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' => $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, - 'S_BOARD_DISABLED' => ($config['board_disable']) ? true : false, - 'S_REGISTERED_USER' => (!empty($user->data['is_registered'])) ? true : false, - 'S_IS_BOT' => (!empty($user->data['is_bot'])) ? true : false, - 'S_USER_LANG' => $user_lang, - 'S_USER_BROWSER' => (isset($user->data['session_browser'])) ? $user->data['session_browser'] : $user->lang['UNKNOWN_BROWSER'], - 'S_USERNAME' => $user->data['username'], - 'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'], - 'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right', - 'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left', - 'S_CONTENT_ENCODING' => 'UTF-8', - 'S_TIMEZONE' => sprintf($user->lang['ALL_TIMES'], $timezone_offset, $timezone_name), - 'S_DISPLAY_ONLINE_LIST' => ($l_online_time) ? 1 : 0, - 'S_DISPLAY_SEARCH' => (!$config['load_search']) ? 0 : (isset($auth) ? ($auth->acl_get('u_search') && $auth->acl_getf_global('f_search')) : 1), - 'S_DISPLAY_PM' => ($config['allow_privmsg'] && !empty($user->data['is_registered']) && ($auth->acl_get('u_readpm') || $auth->acl_get('u_sendpm'))) ? true : false, - 'S_DISPLAY_MEMBERLIST' => (isset($auth)) ? $auth->acl_get('u_viewprofile') : 0, - 'S_NEW_PM' => ($s_privmsg_new) ? 1 : 0, - 'S_REGISTER_ENABLED' => ($config['require_activation'] != USER_ACTIVATION_DISABLE) ? true : false, - 'S_FORUM_ID' => $forum_id, - 'S_TOPIC_ID' => $topic_id, - - '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' => $s_login_redirect, - - 'S_ENABLE_FEEDS' => ($config['feed_enable']) ? true : false, - 'S_ENABLE_FEEDS_OVERALL' => ($config['feed_overall']) ? true : false, - 'S_ENABLE_FEEDS_FORUMS' => ($config['feed_overall_forums']) ? true : false, - 'S_ENABLE_FEEDS_TOPICS' => ($config['feed_topics_new']) ? true : false, - 'S_ENABLE_FEEDS_TOPICS_ACTIVE' => ($config['feed_topics_active']) ? true : false, - 'S_ENABLE_FEEDS_NEWS' => ($s_feed_news) ? true : false, - - 'S_LOAD_UNREADS' => ($config['load_unreads_search'] && ($config['load_anon_lastread'] || $user->data['is_registered'])) ? true : false, - - 'S_SEARCH_HIDDEN_FIELDS' => build_hidden_fields($s_search_hidden_fields), - - 'T_ASSETS_VERSION' => $config['assets_version'], - 'T_ASSETS_PATH' => "{$web_path}assets", - 'T_THEME_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme', - 'T_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/template', - 'T_SUPER_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/template', - 'T_IMAGES_PATH' => "{$web_path}images/", - 'T_SMILIES_PATH' => "{$web_path}{$config['smilies_path']}/", - 'T_AVATAR_PATH' => "{$web_path}{$config['avatar_path']}/", - 'T_AVATAR_GALLERY_PATH' => "{$web_path}{$config['avatar_gallery_path']}/", - 'T_ICONS_PATH' => "{$web_path}{$config['icons_path']}/", - 'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/", - 'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/", - 'T_STYLESHEET_LINK' => "{$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_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->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', - 'T_SMILIES' => $config['smilies_path'], - 'T_AVATAR' => $config['avatar_path'], - 'T_AVATAR_GALLERY' => $config['avatar_gallery_path'], - 'T_ICONS' => $config['icons_path'], - 'T_RANKS' => $config['ranks_path'], - 'T_UPLOAD' => $config['upload_path'], - - 'SITE_LOGO_IMG' => $user->img('site_logo'), - )); - - $http_headers = array(); - - if ($send_headers) - { - // 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', - ); - if (!empty($user->data['is_bot'])) - { - // Let reverse proxies know we detected a bot. - $http_headers['X-PHPBB-IS-BOT'] = 'yes'; - } - } - - /** - * Execute code and/or overwrite _common_ template variables after they have been assigned. - * - * @event core.page_header_after - * @var string page_title Page title - * @var bool display_online_list Do we display online users list - * @var string item Restrict online users to a certain - * session item, e.g. forum for - * session_forum_id - * @var int item_id Restrict online users to item id - * @var array http_headers HTTP headers that should be set by phpbb - * - * @since 3.1.0-b3 - */ - $vars = array('page_title', 'display_online_list', 'item_id', 'item', 'http_headers'); - extract($phpbb_dispatcher->trigger_event('core.page_header_after', compact($vars))); - - foreach ($http_headers as $hname => $hval) - { - header((string) $hname . ': ' . (string) $hval); - } - - return; -} - -/** -* Check and display the SQL report if requested. -* -* @param \phpbb\request\request_interface $request Request object -* @param \phpbb\auth\auth $auth Auth object -* @param \phpbb\db\driver\driver_interface $db Database connection -*/ -function phpbb_check_and_display_sql_report(\phpbb\request\request_interface $request, \phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db) -{ - if ($request->variable('explain', false) && $auth->acl_get('a_') && defined('DEBUG')) - { - $db->sql_report('display'); - } -} - -/** -* Generate the debug output string -* -* @param \phpbb\db\driver\driver_interface $db Database connection -* @param \phpbb\config\config $config Config object -* @param \phpbb\auth\auth $auth Auth object -* @param \phpbb\user $user User object -* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher -* @return string -*/ -function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\auth\auth $auth, \phpbb\user $user, \phpbb\event\dispatcher_interface $phpbb_dispatcher) -{ - $debug_info = array(); - - // Output page creation time - if (defined('PHPBB_DISPLAY_LOAD_TIME')) - { - if (isset($GLOBALS['starttime'])) - { - $totaltime = microtime(true) - $GLOBALS['starttime']; - $debug_info[] = sprintf('Time: %.3fs', $db->get_sql_time(), ($totaltime - $db->get_sql_time()), $totaltime); - } - - $debug_info[] = sprintf('Queries: %d', $db->sql_num_queries(true), $db->sql_num_queries()); - - $memory_usage = memory_get_peak_usage(); - if ($memory_usage) - { - $memory_usage = get_formatted_filesize($memory_usage); - - $debug_info[] = 'Peak Memory Usage: ' . $memory_usage; - } - } - - if (defined('DEBUG')) - { - $debug_info[] = 'GZIP: ' . (($config['gzip_compress'] && @extension_loaded('zlib')) ? 'On' : 'Off'); - - if ($user->load) - { - $debug_info[] = 'Load: ' . $user->load; - } - - if ($auth->acl_get('a_')) - { - $debug_info[] = 'SQL Explain'; - } - } - - /** - * Modify debug output information - * - * @event core.phpbb_generate_debug_output - * @var array debug_info Array of strings with debug information - * - * @since 3.1.0-RC3 - */ - $vars = array('debug_info'); - extract($phpbb_dispatcher->trigger_event('core.phpbb_generate_debug_output', compact($vars))); - - return implode(' | ', $debug_info); -} - -/** -* Generate page footer -* -* @param bool $run_cron Whether or not to run the cron -* @param bool $display_template Whether or not to display the template -* @param bool $exit_handler Whether or not to run the exit_handler() -*/ -function page_footer($run_cron = true, $display_template = true, $exit_handler = true) -{ - 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 - $page_footer_override = false; - - /** - * Execute code and/or overwrite page_footer() - * - * @event core.page_footer - * @var bool run_cron Shall we run cron tasks - * @var bool page_footer_override Shall we return instead of running - * the rest of page_footer() - * @since 3.1.0-a1 - */ - $vars = array('run_cron', 'page_footer_override'); - extract($phpbb_dispatcher->trigger_event('core.page_footer', compact($vars))); - - if ($page_footer_override) - { - return; - } - - phpbb_check_and_display_sql_report($request, $auth, $db); - - $template->assign_vars(array( - 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher), - 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', - 'CREDIT_LINE' => $user->lang('POWERED_BY', 'phpBB® Forum Software © phpBB Limited'), - - 'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_admin_path}index.$phpEx", false, true, $user->session_id) : '') - ); - - // Call cron-type script - $call_cron = false; - if (!defined('IN_CRON') && !$config['use_system_cron'] && $run_cron && !$config['board_disable'] && !$user->data['is_bot'] && !$cache->get('_cron.lock_check')) - { - $call_cron = true; - $time_now = (!empty($user->time_now) && is_int($user->time_now)) ? $user->time_now : time(); - - // Any old lock present? - if (!empty($config['cron_lock'])) - { - $cron_time = explode(' ', $config['cron_lock']); - - // If 1 hour lock is present we do not call cron.php - if ($cron_time[0] + 3600 >= $time_now) - { - $call_cron = false; - } - } - } - - // Call cron job? - if ($call_cron) - { - global $phpbb_container; - - /* @var $cron \phpbb\cron\manager */ - $cron = $phpbb_container->get('cron.manager'); - $task = $cron->find_one_ready_task(); - - if ($task) - { - $url = $task->get_url(); - $template->assign_var('RUN_CRON_TASK', 'cron'); - } - else - { - $cache->put('_cron.lock_check', true, 60); - } - } - - /** - * Execute code and/or modify output before displaying the template. - * - * @event core.page_footer_after - * @var bool display_template Whether or not to display the template - * @var bool exit_handler Whether or not to run the exit_handler() - * - * @since 3.1.0-RC5 - */ - $vars = array('display_template', 'exit_handler'); - extract($phpbb_dispatcher->trigger_event('core.page_footer_after', compact($vars))); - - if ($display_template) - { - $template->display('body'); - } - - garbage_collection(); - - if ($exit_handler) - { - exit_handler(); - } -} - -/** -* Closing the cache object and the database -* Cool function name, eh? We might want to add operations to it later -*/ -function garbage_collection() -{ - global $cache, $db; - global $phpbb_dispatcher; - - if (!empty($phpbb_dispatcher)) - { - /** - * Unload some objects, to free some memory, before we finish our task - * - * @event core.garbage_collection - * @since 3.1.0-a1 - */ - $phpbb_dispatcher->dispatch('core.garbage_collection'); - } - - // Unload cache, must be done before the DB connection if closed - if (!empty($cache)) - { - $cache->unload(); - } - - // Close our DB connection. - if (!empty($db)) - { - $db->sql_close(); - } -} - -/** -* Handler for exit calls in phpBB. -* This function supports hooks. -* -* Note: This function is called after the template has been outputted. -*/ -function exit_handler() -{ - global $phpbb_hook; - - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__)) - { - if ($phpbb_hook->hook_return(__FUNCTION__)) - { - return $phpbb_hook->hook_return_result(__FUNCTION__); - } - } - - // As a pre-caution... some setups display a blank page if the flush() is not there. - (ob_get_level() > 0) ? @ob_flush() : @flush(); - - exit; -} - -/** -* Handler for init calls in phpBB. This function is called in \phpbb\user::setup(); -* This function supports hooks. -*/ -function phpbb_user_session_handler() -{ - global $phpbb_hook; - - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__)) - { - if ($phpbb_hook->hook_return(__FUNCTION__)) - { - return $phpbb_hook->hook_return_result(__FUNCTION__); - } - } - - return; -} - -/** -* Casts a numeric string $input to an appropriate numeric type (i.e. integer or float) -* -* @param string $input A numeric string. -* -* @return int|float Integer $input if $input fits integer, -* float $input otherwise. -*/ -function phpbb_to_numeric($input) -{ - return ($input > PHP_INT_MAX) ? (float) $input : (int) $input; -} - -/** -* Get the board contact details (e.g. for emails) -* -* @param \phpbb\config\config $config -* @param string $phpEx -* @return string -*/ -function phpbb_get_board_contact(\phpbb\config\config $config, $phpEx) -{ - if ($config['contact_admin_form_enable']) - { - return generate_board_url() . '/memberlist.' . $phpEx . '?mode=contactadmin'; - } - else - { - return $config['board_contact']; - } -} - -/** -* Get a clickable board contact details link -* -* @param \phpbb\config\config $config -* @param string $phpbb_root_path -* @param string $phpEx -* @return string -*/ -function phpbb_get_board_contact_link(\phpbb\config\config $config, $phpbb_root_path, $phpEx) -{ - if ($config['contact_admin_form_enable'] && $config['email_enable']) - { - return append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin'); - } - else - { - return 'mailto:' . htmlspecialchars($config['board_contact']); - } -} diff --git a/install/update/old/includes/functions_acp.php b/install/update/old/includes/functions_acp.php deleted file mode 100644 index dd326c3..0000000 --- a/install/update/old/includes/functions_acp.php +++ /dev/null @@ -1,726 +0,0 @@ - -* @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; -} - -/** -* Header for acp pages -*/ -function adm_page_header($page_title) -{ - global $config, $user, $template; - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $SID, $_SID; - global $phpbb_dispatcher, $phpbb_container; - - if (defined('HEADER_INC')) - { - return; - } - - define('HEADER_INC', true); - - // A listener can set this variable to `true` when it overrides this function - $adm_page_header_override = false; - - /** - * Execute code and/or overwrite adm_page_header() - * - * @event core.adm_page_header - * @var string page_title Page title - * @var bool adm_page_header_override Shall we return instead of - * running the rest of adm_page_header() - * @since 3.1.0-a1 - */ - $vars = array('page_title', 'adm_page_header_override'); - extract($phpbb_dispatcher->trigger_event('core.adm_page_header', compact($vars))); - - if ($adm_page_header_override) - { - return; - } - - $user->update_session_infos(); - - // gzip_compression - if ($config['gzip_compress']) - { - if (@extension_loaded('zlib') && !headers_sent()) - { - ob_start('ob_gzhandler'); - } - } - - $template->assign_vars(array( - 'PAGE_TITLE' => $page_title, - 'USERNAME' => $user->data['username'], - - 'SID' => $SID, - '_SID' => $_SID, - 'SESSION_ID' => $user->session_id, - 'ROOT_PATH' => $phpbb_root_path, - 'ADMIN_ROOT_PATH' => $phpbb_admin_path, - - 'U_LOGOUT' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout'), - 'U_ADM_LOGOUT' => append_sid("{$phpbb_admin_path}index.$phpEx", 'action=admlogout'), - 'U_ADM_INDEX' => append_sid("{$phpbb_admin_path}index.$phpEx"), - 'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"), - - 'T_IMAGES_PATH' => "{$phpbb_root_path}images/", - 'T_SMILIES_PATH' => "{$phpbb_root_path}{$config['smilies_path']}/", - 'T_AVATAR_PATH' => "{$phpbb_root_path}{$config['avatar_path']}/", - 'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/", - 'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/", - 'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/", - 'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/", - 'T_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'], - - 'ICON_MOVE_UP' => '' . $user->lang['MOVE_UP'] . '', - 'ICON_MOVE_UP_DISABLED' => '' . $user->lang['MOVE_UP'] . '', - 'ICON_MOVE_DOWN' => '' . $user->lang['MOVE_DOWN'] . '', - 'ICON_MOVE_DOWN_DISABLED' => '' . $user->lang['MOVE_DOWN'] . '', - 'ICON_EDIT' => '' . $user->lang['EDIT'] . '', - 'ICON_EDIT_DISABLED' => '' . $user->lang['EDIT'] . '', - 'ICON_DELETE' => '' . $user->lang['DELETE'] . '', - 'ICON_DELETE_DISABLED' => '' . $user->lang['DELETE'] . '', - 'ICON_SYNC' => '' . $user->lang['RESYNC'] . '', - 'ICON_SYNC_DISABLED' => '' . $user->lang['RESYNC'] . '', - - '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', - - '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. - $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', - ); - - /** - * Execute code and/or overwrite _common_ template variables after they have been assigned. - * - * @event core.adm_page_header_after - * @var string page_title Page title - * @var array http_headers HTTP headers that should be set by phpbb - * - * @since 3.1.0-RC3 - */ - $vars = array('page_title', 'http_headers'); - extract($phpbb_dispatcher->trigger_event('core.adm_page_header_after', compact($vars))); - - foreach ($http_headers as $hname => $hval) - { - header((string) $hname . ': ' . (string) $hval); - } - - return; -} - -/** -* Page footer for acp pages -*/ -function adm_page_footer($copyright_html = true) -{ - 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 - $adm_page_footer_override = false; - - /** - * Execute code and/or overwrite adm_page_footer() - * - * @event core.adm_page_footer - * @var bool copyright_html Shall we display the copyright? - * @var bool adm_page_footer_override Shall we return instead of - * running the rest of adm_page_footer() - * @since 3.1.0-a1 - */ - $vars = array('copyright_html', 'adm_page_footer_override'); - extract($phpbb_dispatcher->trigger_event('core.adm_page_footer', compact($vars))); - - if ($adm_page_footer_override) - { - return; - } - - phpbb_check_and_display_sql_report($request, $auth, $db); - - $template->assign_vars(array( - 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher), - 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', - 'S_COPYRIGHT_HTML' => $copyright_html, - 'CREDIT_LINE' => $user->lang('POWERED_BY', 'phpBB® Forum Software © phpBB Limited'), - 'T_JQUERY_LINK' => !empty($config['allow_cdn']) && !empty($config['load_jquery_url']) ? $config['load_jquery_url'] : "{$phpbb_root_path}assets/javascript/jquery.min.js", - 'S_ALLOW_CDN' => !empty($config['allow_cdn']), - 'VERSION' => $config['version']) - ); - - $template->display('body'); - - garbage_collection(); - exit_handler(); -} - -/** -* Generate back link for acp pages -*/ -function adm_back_link($u_action) -{ - global $user; - return '

« ' . $user->lang['BACK_TO_PREV'] . ''; -} - -/** -* Build select field options in acp pages -*/ -function build_select($option_ary, $option_default = false) -{ - global $user; - - $html = ''; - foreach ($option_ary as $value => $title) - { - $selected = ($option_default !== false && $value == $option_default) ? ' selected="selected"' : ''; - $html .= ''; - } - - return $html; -} - -/** -* Build radio fields in acp pages -*/ -function h_radio($name, $input_ary, $input_default = false, $id = false, $key = false, $separator = '') -{ - global $user; - - $html = ''; - $id_assigned = false; - foreach ($input_ary as $value => $title) - { - $selected = ($input_default !== false && $value == $input_default) ? ' checked="checked"' : ''; - $html .= '' . $separator; - $id_assigned = true; - } - - return $html; -} - -/** -* Build configuration template for acp configuration pages -*/ -function build_cfg_template($tpl_type, $key, &$new_ary, $config_key, $vars) -{ - global $user, $module, $phpbb_dispatcher; - - $tpl = ''; - $name = 'config[' . $config_key . ']'; - - // Make sure there is no notice printed out for non-existent config options (we simply set them) - if (!isset($new_ary[$config_key])) - { - $new_ary[$config_key] = ''; - } - - switch ($tpl_type[0]) - { - case 'password': - if ($new_ary[$config_key] !== '') - { - // replace passwords with asterixes - $new_ary[$config_key] = '********'; - } - case 'text': - case 'url': - case 'email': - case 'tel': - case 'search': - // maxlength and size are only valid for these types and will be - // ignored for other input types. - $size = (int) $tpl_type[1]; - $maxlength = (int) $tpl_type[2]; - - $tpl = ''; - break; - - case 'color': - case 'datetime': - case 'datetime-local': - case 'month': - case 'week': - $tpl = ''; - break; - - case 'date': - case 'time': - case 'number': - case 'range': - $max = ''; - $min = ( isset($tpl_type[1]) ) ? (int) $tpl_type[1] : false; - if ( isset($tpl_type[2]) ) - { - $max = (int) $tpl_type[2]; - } - - $tpl = ''; - break; - - case 'dimension': - $max = ''; - - $min = (int) $tpl_type[1]; - - if ( isset($tpl_type[2]) ) - { - $max = (int) $tpl_type[2]; - } - - $tpl = ' x '; - break; - - case 'textarea': - $rows = (int) $tpl_type[1]; - $cols = (int) $tpl_type[2]; - - $tpl = ''; - break; - - case 'radio': - $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; - - $tpl_no = ''; - $tpl_yes = ''; - - $tpl = ($tpl_type_cond[0] == 'yes' || $tpl_type_cond[0] == 'enabled') ? $tpl_yes . $tpl_no : $tpl_no . $tpl_yes; - break; - - case 'select': - case 'custom': - - if (isset($vars['method'])) - { - $call = array($module->module, $vars['method']); - } - else if (isset($vars['function'])) - { - $call = $vars['function']; - } - else - { - break; - } - - if (isset($vars['params'])) - { - $args = array(); - foreach ($vars['params'] as $value) - { - switch ($value) - { - case '{CONFIG_VALUE}': - $value = $new_ary[$config_key]; - break; - - case '{KEY}': - $value = $key; - break; - } - - $args[] = $value; - } - } - else - { - $args = array($new_ary[$config_key], $key); - } - - $return = call_user_func_array($call, $args); - - if ($tpl_type[0] == 'select') - { - $size = (isset($tpl_type[1])) ? (int) $tpl_type[1] : 1; - $data_toggle = (!empty($tpl_type[2])) ? ' data-togglable-settings="true"' : ''; - - $tpl = ''; - } - else - { - $tpl = $return; - } - - break; - - default: - break; - } - - if (isset($vars['append'])) - { - $tpl .= $vars['append']; - } - - $new = $new_ary; - /** - * Overwrite the html code we display for the config value - * - * @event core.build_config_template - * @var array tpl_type Config type array: - * 0 => data type - * 1 [optional] => string: size, int: minimum - * 2 [optional] => string: max. length, int: maximum - * @var string key Should be used for the id attribute in html - * @var array new Array with the config values we display - * @var string name Should be used for the name attribute - * @var array vars Array with the options for the config - * @var string tpl The resulting html code we display - * @since 3.1.0-a1 - */ - $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; -} - -/** -* Going through a config array and validate values, writing errors to $error. The validation method accepts parameters separated by ':' for string and int. -* The first parameter defines the type to be used, the second the lower bound and the third the upper bound. Only the type is required. -*/ -function validate_config_vars($config_vars, &$cfg_array, &$error) -{ - global $phpbb_root_path, $user, $phpbb_dispatcher, $phpbb_filesystem, $language; - - $type = 0; - $min = 1; - $max = 2; - - foreach ($config_vars as $config_name => $config_definition) - { - if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false) - { - continue; - } - - if (!isset($config_definition['validate'])) - { - continue; - } - - $validator = explode(':', $config_definition['validate']); - - // 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]); - - // the column is a VARCHAR - $validator[$max] = (isset($validator[$max])) ? min(255, $validator[$max]) : 255; - - if (isset($validator[$min]) && $length < $validator[$min]) - { - $error[] = sprintf($user->lang['SETTING_TOO_SHORT'], $user->lang[$config_definition['lang']], $validator[$min]); - } - else if (isset($validator[$max]) && $length > $validator[2]) - { - $error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$config_definition['lang']], $validator[$max]); - } - break; - - case 'bool': - $cfg_array[$config_name] = ($cfg_array[$config_name]) ? 1 : 0; - break; - - case 'int': - $cfg_array[$config_name] = (int) $cfg_array[$config_name]; - - if (isset($validator[$min]) && $cfg_array[$config_name] < $validator[$min]) - { - $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], $validator[$min]); - } - else if (isset($validator[$max]) && $cfg_array[$config_name] > $validator[$max]) - { - $error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$config_definition['lang']], $validator[$max]); - } - - if (strpos($config_name, '_max') !== false) - { - // Min/max pairs of settings should ensure that min <= max - // Replace _max with _min to find the name of the minimum - // corresponding configuration variable - $min_name = str_replace('_max', '_min', $config_name); - - if (isset($cfg_array[$min_name]) && is_numeric($cfg_array[$min_name]) && $cfg_array[$config_name] < $cfg_array[$min_name]) - { - // A minimum value exists and the maximum value is less than it - $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], (int) $cfg_array[$min_name]); - } - } - break; - - case 'email': - if (!preg_match('/^' . get_preg_expression('email') . '$/i', $cfg_array[$config_name])) - { - $error[] = $user->lang['EMAIL_INVALID_EMAIL']; - } - break; - - // Absolute path - case 'script_path': - if (!$cfg_array[$config_name]) - { - break; - } - - $destination = str_replace('\\', '/', $cfg_array[$config_name]); - - if ($destination !== '/') - { - // Adjust destination path (no trailing slash) - if (substr($destination, -1, 1) == '/') - { - $destination = substr($destination, 0, -1); - } - - $destination = str_replace(array('../', './'), '', $destination); - - if ($destination[0] != '/') - { - $destination = '/' . $destination; - } - } - - $cfg_array[$config_name] = trim($destination); - - break; - - // Absolute path - case 'lang': - if (!$cfg_array[$config_name]) - { - break; - } - - $cfg_array[$config_name] = basename($cfg_array[$config_name]); - - if (!file_exists($phpbb_root_path . 'language/' . $cfg_array[$config_name] . '/')) - { - $error[] = $user->lang['WRONG_DATA_LANG']; - } - break; - - // Relative path (appended $phpbb_root_path) - case 'rpath': - case 'rwpath': - if (!$cfg_array[$config_name]) - { - break; - } - - $destination = $cfg_array[$config_name]; - - // Adjust destination path (no trailing slash) - if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\') - { - $destination = substr($destination, 0, -1); - } - - $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination); - if ($destination && ($destination[0] == '/' || $destination[0] == "\\")) - { - $destination = ''; - } - - $cfg_array[$config_name] = trim($destination); - - // Path being relative (still prefixed by phpbb_root_path), but with the ability to escape the root dir... - case 'path': - case 'wpath': - - if (!$cfg_array[$config_name]) - { - break; - } - - $cfg_array[$config_name] = trim($cfg_array[$config_name]); - - // Make sure no NUL byte is present... - if (strpos($cfg_array[$config_name], "\0") !== false || strpos($cfg_array[$config_name], '%00') !== false) - { - $cfg_array[$config_name] = ''; - break; - } - - $path = $phpbb_root_path . $cfg_array[$config_name]; - - if (!file_exists($path)) - { - $error[] = sprintf($user->lang['DIRECTORY_DOES_NOT_EXIST'], $cfg_array[$config_name]); - } - - if (file_exists($path) && !is_dir($path)) - { - $error[] = sprintf($user->lang['DIRECTORY_NOT_DIR'], $cfg_array[$config_name]); - } - - // Check if the path is writable - if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath') - { - if (file_exists($path) && !$phpbb_filesystem->is_writable($path)) - { - $error[] = sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $cfg_array[$config_name]); - } - } - - break; - - default: - /** - * Validate a config value - * - * @event core.validate_config_variable - * @var array cfg_array Array with config values - * @var string config_name Name of the config we validate - * @var array config_definition Array with the options for - * this config - * @var array error Array of errors, the errors should - * be strings only, language keys are - * not replaced afterwards - * @since 3.1.0-a1 - */ - $vars = array('cfg_array', 'config_name', 'config_definition', 'error'); - extract($phpbb_dispatcher->trigger_event('core.validate_config_variable', compact($vars))); - break; - } - } - - return; -} - -/** -* Checks whatever or not a variable is OK for use in the Database -* param mixed $value_ary An array of the form array(array('lang' => ..., 'value' => ..., 'column_type' =>))' -* param mixed $error The error array -*/ -function validate_range($value_ary, &$error) -{ - global $user; - - $column_types = array( - 'BOOL' => array('php_type' => 'int', 'min' => 0, 'max' => 1), - 'USINT' => array('php_type' => 'int', 'min' => 0, 'max' => 65535), - 'UINT' => array('php_type' => 'int', 'min' => 0, 'max' => (int) 0x7fffffff), - // Do not use (int) 0x80000000 - it evaluates to different - // values on 32-bit and 64-bit systems. - // Apparently -2147483648 is a float on 32-bit systems, - // despite fitting in an int, thus explicit cast is needed. - 'INT' => array('php_type' => 'int', 'min' => (int) -2147483648, 'max' => (int) 0x7fffffff), - 'TINT' => array('php_type' => 'int', 'min' => -128, 'max' => 127), - - 'VCHAR' => array('php_type' => 'string', 'min' => 0, 'max' => 255), - ); - foreach ($value_ary as $value) - { - $column = explode(':', $value['column_type']); - if (!isset($column_types[$column[0]])) - { - continue; - } - else - { - $type = $column_types[$column[0]]; - } - - switch ($type['php_type']) - { - case 'string' : - $max = (isset($column[1])) ? min($column[1],$type['max']) : $type['max']; - if (utf8_strlen($value['value']) > $max) - { - $error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$value['lang']], $max); - } - break; - - case 'int': - $min = (isset($column[1])) ? max($column[1],$type['min']) : $type['min']; - $max = (isset($column[2])) ? min($column[2],$type['max']) : $type['max']; - if ($value['value'] < $min) - { - $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$value['lang']], $min); - } - else if ($value['value'] > $max) - { - $error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$value['lang']], $max); - } - break; - } - } -} - -/** -* Inserts new config display_vars into an exisiting display_vars array -* at the given position. -* -* @param array $display_vars An array of existing config display vars -* @param array $add_config_vars An array of new config display vars -* @param array $where Where to place the new config vars, -* before or after an exisiting config, as an array -* of the form: array('after' => 'config_name') or -* array('before' => 'config_name'). -* @return array The array of config display vars -*/ -function phpbb_insert_config_array($display_vars, $add_config_vars, $where) -{ - if (is_array($where) && array_key_exists(current($where), $display_vars)) - { - $position = array_search(current($where), array_keys($display_vars)) + ((key($where) == 'before') ? 0 : 1); - $display_vars = array_merge( - array_slice($display_vars, 0, $position), - $add_config_vars, - array_slice($display_vars, $position) - ); - } - - return $display_vars; -} diff --git a/install/update/old/includes/functions_admin.php b/install/update/old/includes/functions_admin.php deleted file mode 100644 index c19d48b..0000000 --- a/install/update/old/includes/functions_admin.php +++ /dev/null @@ -1,3109 +0,0 @@ - -* @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; -} - -/** -* Recalculate Nested Sets -* -* @param int $new_id first left_id (should start with 1) -* @param string $pkey primary key-column (containing the id for the parent_id of the children) -* @param string $table constant or fullname of the table -* @param int $parent_id parent_id of the current set (default = 0) -* @param array $where contains strings to compare closer on the where statement (additional) -*/ -function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = array()) -{ - global $db; - - $sql = 'SELECT * - FROM ' . $table . ' - WHERE parent_id = ' . (int) $parent_id . - ((!empty($where)) ? ' AND ' . implode(' AND ', $where) : '') . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - // First we update the left_id for this module - if ($row['left_id'] != $new_id) - { - $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('left_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}"); - } - $new_id++; - - // Then we go through any children and update their left/right id's - recalc_nested_sets($new_id, $pkey, $table, $row[$pkey], $where); - - // Then we come back and update the right_id for this module - if ($row['right_id'] != $new_id) - { - $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('right_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}"); - } - $new_id++; - } - $db->sql_freeresult($result); -} - -/** -* Simple version of jumpbox, just lists authed forums -*/ -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, $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 - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql, 600); - - $rowset = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[(int) $row['forum_id']] = $row; - } - $db->sql_freeresult($result); - - $right = 0; - $padding_store = array('0' => ''); - $padding = ''; - $forum_list = ($return_array) ? array() : ''; - - /** - * Modify the forum list data - * - * @event core.make_forum_select_modify_forum_list - * @var array rowset Array with the forums list data - * @since 3.1.10-RC1 - */ - $vars = array('rowset'); - extract($phpbb_dispatcher->trigger_event('core.make_forum_select_modify_forum_list', compact($vars))); - - // Sometimes it could happen that forums will be displayed here not be displayed within the index page - // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions. - // If this happens, the padding could be "broken" - - foreach ($rowset as $row) - { - if ($row['left_id'] < $right) - { - $padding .= '   '; - $padding_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : ''; - } - - $right = $row['right_id']; - $disabled = false; - - if (!$ignore_acl && $auth->acl_gets(array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'), $row['forum_id'])) - { - if ($only_acl_post && !$auth->acl_get('f_post', $row['forum_id']) || (!$auth->acl_get('m_approve', $row['forum_id']) && !$auth->acl_get('f_noapprove', $row['forum_id']))) - { - $disabled = true; - } - } - else if (!$ignore_acl) - { - continue; - } - - if ( - ((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id) - || - // Non-postable forum with no subforums, don't display - ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat) - || - ($row['forum_type'] != FORUM_POST && $ignore_nonpost) - ) - { - $disabled = true; - } - - if ($return_array) - { - // Include some more information... - $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? true : false) : (($row['forum_id'] == $select_id) ? true : false); - $forum_list[$row['forum_id']] = array_merge(array('padding' => $padding, 'selected' => ($selected && !$disabled), 'disabled' => $disabled), $row); - } - else - { - $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? ' selected="selected"' : '') : (($row['forum_id'] == $select_id) ? ' selected="selected"' : ''); - $forum_list .= ''; - } - } - unset($padding_store, $rowset); - - return $forum_list; -} - -/** -* Generate size select options -*/ -function size_select_options($size_compare) -{ - global $user; - - $size_types_text = array($user->lang['BYTES'], $user->lang['KIB'], $user->lang['MIB']); - $size_types = array('b', 'kb', 'mb'); - - $s_size_options = ''; - - for ($i = 0, $size = count($size_types_text); $i < $size; $i++) - { - $selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : ''; - $s_size_options .= ''; - } - - return $s_size_options; -} - -/** -* Generate list of groups (option fields without select) -* -* @param int $group_id The default group id to mark as selected -* @param array $exclude_ids The group ids to exclude from the list, false (default) if you whish to exclude no id -* @param int $manage_founder If set to false (default) all groups are returned, if 0 only those groups returned not being managed by founders only, if 1 only those groups returned managed by founders only. -* -* @return string The list of options. -*/ -function group_select_options($group_id, $exclude_ids = false, $manage_founder = false) -{ - global $db, $config, $phpbb_container; - - /** @var \phpbb\group\helper $group_helper */ - $group_helper = $phpbb_container->get('group_helper'); - - $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 : ''; - - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE . " - $exclude_sql - $sql_and - $sql_founder - ORDER BY group_type DESC, group_name ASC"; - $result = $db->sql_query($sql); - - $s_group_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : ''; - $s_group_options .= '' . $group_helper->get_name($row['group_name']) . ''; - } - $db->sql_freeresult($result); - - return $s_group_options; -} - -/** -* Obtain authed forums list -*/ -function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false) -{ - global $db, $auth, $phpbb_dispatcher; - static $forum_rows; - - if (!isset($forum_rows)) - { - // This query is identical to the jumpbox one - $expire_time = ($no_cache) ? 0 : 600; - - $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql, $expire_time); - - $forum_rows = array(); - - $right = $padding = 0; - $padding_store = array('0' => 0); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['left_id'] < $right) - { - $padding++; - $padding_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it. - // @todo digging deep to find out "how" this can happen. - $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding; - } - - $right = $row['right_id']; - $row['padding'] = $padding; - - $forum_rows[] = $row; - } - $db->sql_freeresult($result); - unset($padding_store); - } - - $rowset = array(); - foreach ($forum_rows as $row) - { - if ($postable_only && $row['forum_type'] != FORUM_POST) - { - continue; - } - - if ($acl_list == '' || ($acl_list != '' && $auth->acl_gets($acl_list, $row['forum_id']))) - { - $rowset[] = ($id_only) ? (int) $row['forum_id'] : $row; - } - } - - /** - * Modify the forum list data - * - * @event core.get_forum_list_modify_data - * @var array rowset Array with the forum list data - * @since 3.1.10-RC1 - */ - $vars = array('rowset'); - extract($phpbb_dispatcher->trigger_event('core.get_forum_list_modify_data', compact($vars))); - - return $rowset; -} - -/** -* Get forum branch -*/ -function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $include_forum = true) -{ - global $db; - - switch ($type) - { - case 'parents': - $condition = 'f1.left_id BETWEEN f2.left_id AND f2.right_id'; - break; - - case 'children': - $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id'; - break; - - default: - $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id OR f1.left_id BETWEEN f2.left_id AND f2.right_id'; - break; - } - - $rows = array(); - - $sql = 'SELECT f2.* - FROM ' . FORUMS_TABLE . ' f1 - LEFT JOIN ' . FORUMS_TABLE . " f2 ON ($condition) - WHERE f1.forum_id = $forum_id - ORDER BY f2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC'); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$include_forum && $row['forum_id'] == $forum_id) - { - continue; - } - - $rows[] = $row; - } - $db->sql_freeresult($result); - - return $rows; -} - -/** -* Copies permissions from one forum to others -* -* @param int $src_forum_id The source forum we want to copy permissions from -* @param array $dest_forum_ids The destination forum(s) we want to copy to -* @param bool $clear_dest_perms True if destination permissions should be deleted -* @param bool $add_log True if log entry should be added -* -* @return bool False on error -*/ -function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perms = true, $add_log = true) -{ - global $db, $user, $phpbb_log; - - // Only one forum id specified - if (!is_array($dest_forum_ids)) - { - $dest_forum_ids = array($dest_forum_ids); - } - - // Make sure forum ids are integers - $src_forum_id = (int) $src_forum_id; - $dest_forum_ids = array_map('intval', $dest_forum_ids); - - // No source forum or no destination forums specified - if (empty($src_forum_id) || empty($dest_forum_ids)) - { - return false; - } - - // Check if source forum exists - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $src_forum_id; - $result = $db->sql_query($sql); - $src_forum_name = $db->sql_fetchfield('forum_name'); - $db->sql_freeresult($result); - - // Source forum doesn't exist - if (empty($src_forum_name)) - { - return false; - } - - // Check if destination forums exists - $sql = 'SELECT forum_id, forum_name - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); - $result = $db->sql_query($sql); - - $dest_forum_ids = $dest_forum_names = array(); - while ($row = $db->sql_fetchrow($result)) - { - $dest_forum_ids[] = (int) $row['forum_id']; - $dest_forum_names[] = $row['forum_name']; - } - $db->sql_freeresult($result); - - // No destination forum exists - if (empty($dest_forum_ids)) - { - return false; - } - - // From the mysql documentation: - // Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear - // in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14. - // Due to this we stay on the safe side if we do the insertion "the manual way" - - // Rowsets we're going to insert - $users_sql_ary = $groups_sql_ary = array(); - - // Query acl users table for source forum data - $sql = 'SELECT user_id, auth_option_id, auth_role_id, auth_setting - FROM ' . ACL_USERS_TABLE . ' - WHERE forum_id = ' . $src_forum_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $row = array( - 'user_id' => (int) $row['user_id'], - 'auth_option_id' => (int) $row['auth_option_id'], - 'auth_role_id' => (int) $row['auth_role_id'], - 'auth_setting' => (int) $row['auth_setting'], - ); - - foreach ($dest_forum_ids as $dest_forum_id) - { - $users_sql_ary[] = $row + array('forum_id' => $dest_forum_id); - } - } - $db->sql_freeresult($result); - - // Query acl groups table for source forum data - $sql = 'SELECT group_id, auth_option_id, auth_role_id, auth_setting - FROM ' . ACL_GROUPS_TABLE . ' - WHERE forum_id = ' . $src_forum_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $row = array( - 'group_id' => (int) $row['group_id'], - 'auth_option_id' => (int) $row['auth_option_id'], - 'auth_role_id' => (int) $row['auth_role_id'], - 'auth_setting' => (int) $row['auth_setting'], - ); - - foreach ($dest_forum_ids as $dest_forum_id) - { - $groups_sql_ary[] = $row + array('forum_id' => $dest_forum_id); - } - } - $db->sql_freeresult($result); - - $db->sql_transaction('begin'); - - // Clear current permissions of destination forums - if ($clear_dest_perms) - { - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); - $db->sql_query($sql); - } - - $db->sql_multi_insert(ACL_USERS_TABLE, $users_sql_ary); - $db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary); - - if ($add_log) - { - $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'); - - return true; -} - -/** -* Get physical file listing -*/ -function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png') -{ - $matches = array($dir => array()); - - // Remove initial / if present - $rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir; - // Add closing / if not present - $rootdir = ($rootdir && substr($rootdir, -1) != '/') ? $rootdir . '/' : $rootdir; - - // Remove initial / if present - $dir = (substr($dir, 0, 1) == '/') ? substr($dir, 1) : $dir; - // Add closing / if not present - $dir = ($dir && substr($dir, -1) != '/') ? $dir . '/' : $dir; - - if (!is_dir($rootdir . $dir)) - { - return $matches; - } - - $dh = @opendir($rootdir . $dir); - - if (!$dh) - { - return $matches; - } - - while (($fname = readdir($dh)) !== false) - { - if (is_file("$rootdir$dir$fname")) - { - if (filesize("$rootdir$dir$fname") && preg_match('#\.' . $type . '$#i', $fname)) - { - $matches[$dir][] = $fname; - } - } - else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname")) - { - $matches += filelist($rootdir, "$dir$fname", $type); - } - } - closedir($dh); - - return $matches; -} - -/** -* Move topic(s) -*/ -function move_topics($topic_ids, $forum_id, $auto_sync = true) -{ - global $db, $phpbb_dispatcher; - - if (empty($topic_ids)) - { - return; - } - - $forum_ids = array($forum_id); - - if (!is_array($topic_ids)) - { - $topic_ids = array($topic_ids); - } - - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids) . ' - AND forum_id = ' . $forum_id; - $db->sql_query($sql); - - if ($auto_sync) - { - $sql = 'SELECT DISTINCT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $db->sql_freeresult($result); - } - - $table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE); - - /** - * Perform additional actions before topics move - * - * @event core.move_topics_before_query - * @var array table_ary Array of tables from which forum_id will be updated for all rows that hold the moved topics - * @var array topic_ids Array of the moved topic ids - * @var string forum_id The forum id from where the topics are moved - * @var array forum_ids Array of the forums where the topics are moving (includes also forum_id) - * @var bool auto_sync Whether or not to perform auto sync - * @since 3.1.5-RC1 - */ - $vars = array( - 'table_ary', - 'topic_ids', - 'forum_id', - 'forum_ids', - 'auto_sync', - ); - extract($phpbb_dispatcher->trigger_event('core.move_topics_before_query', compact($vars))); - - foreach ($table_ary as $table) - { - $sql = "UPDATE $table - SET forum_id = $forum_id - WHERE " . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - unset($table_ary); - - if ($auto_sync) - { - sync('forum', 'forum_id', $forum_ids, true, true); - unset($forum_ids); - } -} - -/** -* Move post(s) -*/ -function move_posts($post_ids, $topic_id, $auto_sync = true) -{ - global $db, $phpbb_dispatcher; - - if (!is_array($post_ids)) - { - $post_ids = array($post_ids); - } - - $forum_ids = array(); - $topic_ids = array($topic_id); - - $sql = 'SELECT DISTINCT topic_id, forum_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = (int) $row['forum_id']; - $topic_ids[] = (int) $row['topic_id']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $forum_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$forum_row) - { - trigger_error('NO_TOPIC'); - } - - /** - * Perform additional actions before moving posts - * - * @event core.move_posts_before - * @var array post_ids Array of post ids to move - * @var int topic_id The topic id the posts are moved to - * @var bool auto_sync Whether or not to perform auto sync - * @var array forum_ids Array of the forum ids the posts are moved from - * @var array topic_ids Array of the topic ids the posts are moved from - * @var array forum_row Array with the forum id of the topic the posts are moved to - * @since 3.1.7-RC1 - */ - $vars = array( - 'post_ids', - 'topic_id', - 'auto_sync', - 'forum_ids', - 'topic_ids', - 'forum_row', - ); - extract($phpbb_dispatcher->trigger_event('core.move_posts_before', compact($vars))); - - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET forum_id = ' . (int) $forum_row['forum_id'] . ", topic_id = $topic_id - WHERE " . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET topic_id = $topic_id, in_message = 0 - WHERE " . $db->sql_in_set('post_msg_id', $post_ids); - $db->sql_query($sql); - - /** - * Perform additional actions after moving posts - * - * @event core.move_posts_after - * @var array post_ids Array of the moved post ids - * @var int topic_id The topic id the posts are moved to - * @var bool auto_sync Whether or not to perform auto sync - * @var array forum_ids Array of the forum ids the posts are moved from - * @var array topic_ids Array of the topic ids the posts are moved from - * @var array forum_row Array with the forum id of the topic the posts are moved to - * @since 3.1.7-RC1 - */ - $vars = array( - 'post_ids', - 'topic_id', - 'auto_sync', - 'forum_ids', - 'topic_ids', - 'forum_row', - ); - extract($phpbb_dispatcher->trigger_event('core.move_posts_after', compact($vars))); - - if ($auto_sync) - { - $forum_ids[] = (int) $forum_row['forum_id']; - - sync('topic_reported', 'topic_id', $topic_ids); - sync('topic_attachment', 'topic_id', $topic_ids); - sync('topic', 'topic_id', $topic_ids, true); - sync('forum', 'forum_id', $forum_ids, true, true); - - /** - * Perform additional actions after move post sync - * - * @event core.move_posts_sync_after - * @var array post_ids Array of the moved post ids - * @var int topic_id The topic id the posts are moved to - * @var bool auto_sync Whether or not to perform auto sync - * @var array forum_ids Array of the forum ids the posts are moved from - * @var array topic_ids Array of the topic ids the posts are moved from - * @var array forum_row Array with the forum id of the topic the posts are moved to - * @since 3.1.11-RC1 - */ - $vars = array( - 'post_ids', - 'topic_id', - 'auto_sync', - 'forum_ids', - 'topic_ids', - 'forum_row', - ); - extract($phpbb_dispatcher->trigger_event('core.move_posts_sync_after', compact($vars))); - } - - // Update posted information - update_posted_info($topic_ids); -} - -/** -* Remove topic(s) -*/ -function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true) -{ - global $db, $config, $phpbb_container, $phpbb_dispatcher; - - $approved_topics = 0; - $forum_ids = $topic_ids = array(); - - if ($where_type === 'range') - { - $where_clause = $where_ids; - } - else - { - $where_ids = (is_array($where_ids)) ? array_unique($where_ids) : array($where_ids); - - if (!count($where_ids)) - { - return array('topics' => 0, 'posts' => 0); - } - - $where_clause = $db->sql_in_set($where_type, $where_ids); - } - - // Making sure that delete_posts does not call delete_topics again... - $return = array( - 'posts' => ($call_delete_posts) ? delete_posts($where_type, $where_ids, false, true, $post_count_sync, false) : 0, - ); - - $sql = 'SELECT topic_id, forum_id, topic_visibility, topic_moved_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $where_clause; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - $topic_ids[] = $row['topic_id']; - - if ($row['topic_visibility'] == ITEM_APPROVED && !$row['topic_moved_id']) - { - $approved_topics++; - } - } - $db->sql_freeresult($result); - - $return['topics'] = count($topic_ids); - - if (!count($topic_ids)) - { - return $return; - } - - $db->sql_transaction('begin'); - - $table_ary = array(BOOKMARKS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE); - - /** - * Perform additional actions before topic(s) deletion - * - * @event core.delete_topics_before_query - * @var array table_ary Array of tables from which all rows will be deleted that hold a topic_id occuring in topic_ids - * @var array topic_ids Array of topic ids to delete - * @since 3.1.4-RC1 - */ - $vars = array( - 'table_ary', - 'topic_ids', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_topics_before_query', compact($vars))); - - foreach ($table_ary as $table) - { - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - unset($table_ary); - - /** - * Perform additional actions after topic(s) deletion - * - * @event core.delete_topics_after_query - * @var array topic_ids Array of topic ids that were deleted - * @since 3.1.4-RC1 - */ - $vars = array( - 'topic_ids', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_topics_after_query', compact($vars))); - - $moved_topic_ids = array(); - - // update the other forums - $sql = 'SELECT topic_id, forum_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - $moved_topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (count($moved_topic_ids)) - { - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $moved_topic_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - if ($auto_sync) - { - sync('forum', 'forum_id', array_unique($forum_ids), true, true); - sync('topic_reported', $where_type, $where_ids); - } - - if ($approved_topics) - { - $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( - 'notification.type.topic', - 'notification.type.approve_topic', - 'notification.type.topic_in_queue', - ), $topic_ids); - - return $return; -} - -/** -* Remove post(s) -*/ -function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true) -{ - global $db, $config, $phpbb_root_path, $phpEx, $auth, $user, $phpbb_container, $phpbb_dispatcher; - - // Notifications types to delete - $delete_notifications_types = array( - 'notification.type.quote', - 'notification.type.approve_post', - 'notification.type.post_in_queue', - 'notification.type.report_post', - ); - - /** - * Perform additional actions before post(s) deletion - * - * @event core.delete_posts_before - * @var string where_type Variable containing posts deletion mode - * @var mixed where_ids Array or comma separated list of posts ids to delete - * @var bool auto_sync Flag indicating if topics/forums should be synchronized - * @var bool posted_sync Flag indicating if topics_posted table should be resynchronized - * @var bool post_count_sync Flag indicating if posts count should be resynchronized - * @var bool call_delete_topics Flag indicating if topics having no posts should be deleted - * @var array delete_notifications_types Array with notifications types to delete - * @since 3.1.0-a4 - */ - $vars = array( - 'where_type', - 'where_ids', - 'auto_sync', - 'posted_sync', - 'post_count_sync', - 'call_delete_topics', - 'delete_notifications_types', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_posts_before', compact($vars))); - - if ($where_type === 'range') - { - $where_clause = $where_ids; - } - else - { - if (is_array($where_ids)) - { - $where_ids = array_unique($where_ids); - } - else - { - $where_ids = array($where_ids); - } - - if (!count($where_ids)) - { - return false; - } - - $where_ids = array_map('intval', $where_ids); - -/* Possible code for splitting post deletion - if (count($where_ids) >= 1001) - { - // Split into chunks of 1000 - $chunks = array_chunk($where_ids, 1000); - - foreach ($chunks as $_where_ids) - { - delete_posts($where_type, $_where_ids, $auto_sync, $posted_sync, $post_count_sync, $call_delete_topics); - } - - return; - }*/ - - $where_clause = $db->sql_in_set($where_type, $where_ids); - } - - $approved_posts = 0; - $post_ids = $topic_ids = $forum_ids = $post_counts = $remove_topics = array(); - - $sql = 'SELECT post_id, poster_id, post_visibility, post_postcount, topic_id, forum_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $where_clause; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_ids[] = (int) $row['post_id']; - $poster_ids[] = (int) $row['poster_id']; - $topic_ids[] = (int) $row['topic_id']; - $forum_ids[] = (int) $row['forum_id']; - - if ($row['post_postcount'] && $post_count_sync && $row['post_visibility'] == ITEM_APPROVED) - { - $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1; - } - - if ($row['post_visibility'] == ITEM_APPROVED) - { - $approved_posts++; - } - } - $db->sql_freeresult($result); - - if (!count($post_ids)) - { - return false; - } - - $db->sql_transaction('begin'); - - $table_ary = array(POSTS_TABLE, REPORTS_TABLE); - - /** - * Perform additional actions during post(s) deletion before running the queries - * - * @event core.delete_posts_in_transaction_before - * @var array post_ids Array with deleted posts' ids - * @var array poster_ids Array with deleted posts' author ids - * @var array topic_ids Array with deleted posts' topic ids - * @var array forum_ids Array with deleted posts' forum ids - * @var string where_type Variable containing posts deletion mode - * @var mixed where_ids Array or comma separated list of post ids to delete - * @var array delete_notifications_types Array with notifications types to delete - * @var array table_ary Array with table names to delete data from - * @since 3.1.7-RC1 - */ - $vars = array( - 'post_ids', - 'poster_ids', - 'topic_ids', - 'forum_ids', - 'where_type', - 'where_ids', - 'delete_notifications_types', - 'table_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_posts_in_transaction_before', compact($vars))); - - foreach ($table_ary as $table) - { - $sql = "DELETE FROM $table - WHERE " . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - } - unset($table_ary); - - // Adjust users post counts - if (count($post_counts) && $post_count_sync) - { - foreach ($post_counts as $poster_id => $substract) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = 0 - WHERE user_id = ' . $poster_id . ' - AND user_posts < ' . $substract; - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts - ' . $substract . ' - WHERE user_id = ' . $poster_id . ' - AND user_posts >= ' . $substract; - $db->sql_query($sql); - } - } - - // Remove topics now having no posts? - if (count($topic_ids)) - { - $sql = 'SELECT topic_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - GROUP BY topic_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $remove_topics[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - // Actually, those not within remove_topics should be removed. ;) - $remove_topics = array_diff($topic_ids, $remove_topics); - } - - // Remove the message from the search index - $search_type = $config['search_type']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if ($error) - { - trigger_error($error); - } - - $search->index_remove($post_ids, $poster_ids, $forum_ids); - - /** @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 - * - * @event core.delete_posts_in_transaction - * @var array post_ids Array with deleted posts' ids - * @var array poster_ids Array with deleted posts' author ids - * @var array topic_ids Array with deleted posts' topic ids - * @var array forum_ids Array with deleted posts' forum ids - * @var string where_type Variable containing posts deletion mode - * @var mixed where_ids Array or comma separated list of posts ids to delete - * @var array delete_notifications_types Array with notifications types to delete - * @since 3.1.0-a4 - */ - $vars = array( - 'post_ids', - 'poster_ids', - 'topic_ids', - 'forum_ids', - 'where_type', - 'where_ids', - 'delete_notifications_types', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_posts_in_transaction', compact($vars))); - - $db->sql_transaction('commit'); - - /** - * Perform additional actions after post(s) deletion - * - * @event core.delete_posts_after - * @var array post_ids Array with deleted posts' ids - * @var array poster_ids Array with deleted posts' author ids - * @var array topic_ids Array with deleted posts' topic ids - * @var array forum_ids Array with deleted posts' forum ids - * @var string where_type Variable containing posts deletion mode - * @var mixed where_ids Array or comma separated list of posts ids to delete - * @var array delete_notifications_types Array with notifications types to delete - * @since 3.1.0-a4 - */ - $vars = array( - 'post_ids', - 'poster_ids', - 'topic_ids', - 'forum_ids', - 'where_type', - 'where_ids', - 'delete_notifications_types', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_posts_after', compact($vars))); - - // Resync topics_posted table - if ($posted_sync) - { - update_posted_info($topic_ids); - } - - if ($auto_sync) - { - sync('topic_reported', 'topic_id', $topic_ids); - sync('topic', 'topic_id', $topic_ids, true); - sync('forum', 'forum_id', $forum_ids, true, true); - } - - if ($approved_posts && $post_count_sync) - { - $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 (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 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 $phpbb_container; - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $num_deleted = $attachment_manager->delete($mode, $ids, $resync); - - unset($attachment_manager); - - return $num_deleted; -} - -/** -* Deletes shadow topics pointing to a specified forum. -* -* @param int $forum_id The forum id -* @param string $sql_more Additional WHERE statement, e.g. t.topic_time < (time() - 1234) -* @param bool $auto_sync Will call sync() if this is true -* -* @return array Array with affected forums -*/ -function delete_topic_shadows($forum_id, $sql_more = '', $auto_sync = true) -{ - global $db; - - if (!$forum_id) - { - // Nothing to do. - return; - } - - // Set of affected forums we have to resync - $sync_forum_ids = array(); - - // Amount of topics we select and delete at once. - $batch_size = 500; - - do - { - $sql = 'SELECT t2.forum_id, t2.topic_id - FROM ' . TOPICS_TABLE . ' t2, ' . TOPICS_TABLE . ' t - WHERE t2.topic_moved_id = t.topic_id - AND t.forum_id = ' . (int) $forum_id . ' - ' . (($sql_more) ? 'AND ' . $sql_more : ''); - $result = $db->sql_query_limit($sql, $batch_size); - - $topic_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = (int) $row['topic_id']; - - $sync_forum_ids[(int) $row['forum_id']] = (int) $row['forum_id']; - } - $db->sql_freeresult($result); - - if (!empty($topic_ids)) - { - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - } - while (count($topic_ids) == $batch_size); - - if ($auto_sync) - { - sync('forum', 'forum_id', $sync_forum_ids, true, true); - } - - return $sync_forum_ids; -} - -/** -* Update/Sync posted information for topics -*/ -function update_posted_info(&$topic_ids) -{ - global $db, $config; - - if (empty($topic_ids) || !$config['load_db_track']) - { - return; - } - - // First of all, let us remove any posted information for these topics - $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - - // Now, let us collect the user/topic combos for rebuilding the information - $sql = 'SELECT poster_id, topic_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - AND poster_id <> ' . ANONYMOUS . ' - GROUP BY poster_id, topic_id'; - $result = $db->sql_query($sql); - - $posted = array(); - while ($row = $db->sql_fetchrow($result)) - { - // Add as key to make them unique (grouping by) and circumvent empty keys on array_unique - $posted[$row['poster_id']][] = $row['topic_id']; - } - $db->sql_freeresult($result); - - // Now add the information... - $sql_ary = array(); - foreach ($posted as $user_id => $topic_row) - { - foreach ($topic_row as $topic_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user_id, - 'topic_id' => (int) $topic_id, - 'topic_posted' => 1, - ); - } - } - unset($posted); - - $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); -} - -/** -* Delete attached file -* -* @deprecated 3.2.0-a1 (To be removed: 3.4.0) -*/ -function phpbb_unlink($filename, $mode = 'file', $entry_removed = false) -{ - global $phpbb_container; - - /** @var \phpbb\attachment\manager $attachment_manager */ - $attachment_manager = $phpbb_container->get('attachment.manager'); - $unlink = $attachment_manager->unlink($filename, $mode, $entry_removed); - unset($attachment_manager); - - return $unlink; -} - -/** -* All-encompasing sync function -* -* Exaples: -* -* sync('topic', 'topic_id', 123); // resync topic #123 -* sync('topic', 'forum_id', array(2, 3)); // resync topics from forum #2 and #3 -* sync('topic'); // resync all topics -* sync('topic', 'range', 'topic_id BETWEEN 1 AND 60'); // resync a range of topics/forums (only available for 'topic' and 'forum' modes) -* -* -* Modes: -* - forum Resync complete forum -* - topic Resync topics -* - topic_moved Removes topic shadows that would be in the same forum as the topic they link to -* - topic_visibility Resyncs the topic_visibility flag according to the status of the first post -* - post_reported Resyncs the post_reported flag, relying on actual reports -* - topic_reported Resyncs the topic_reported flag, relying on post_reported flags -* - post_attachement Same as post_reported, but with attachment flags -* - topic_attachement Same as topic_reported, but with attachment flags -*/ -function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sync_extra = false) -{ - global $db; - - if (is_array($where_ids)) - { - $where_ids = array_unique($where_ids); - $where_ids = array_map('intval', $where_ids); - } - else if ($where_type != 'range') - { - $where_ids = ($where_ids) ? array((int) $where_ids) : array(); - } - - if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_visibility' || $mode == 'topic_reported' || $mode == 'post_reported') - { - if (!$where_type) - { - $where_sql = ''; - $where_sql_and = 'WHERE'; - } - else if ($where_type == 'range') - { - // Only check a range of topics/forums. For instance: 'topic_id BETWEEN 1 AND 60' - $where_sql = 'WHERE (' . $mode[0] . ".$where_ids)"; - $where_sql_and = $where_sql . "\n\tAND"; - } - else - { - // Do not sync the "global forum" - $where_ids = array_diff($where_ids, array(0)); - - if (!count($where_ids)) - { - // Empty array with IDs. This means that we don't have any work to do. Just return. - return; - } - - // Limit the topics/forums we are syncing, use specific topic/forum IDs. - // $where_type contains the field for the where clause (forum_id, topic_id) - $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids); - $where_sql_and = $where_sql . "\n\tAND"; - } - } - else - { - if (!count($where_ids)) - { - return; - } - - // $where_type contains the field for the where clause (forum_id, topic_id) - $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids); - $where_sql_and = $where_sql . "\n\tAND"; - } - - switch ($mode) - { - case 'topic_moved': - $db->sql_transaction('begin'); - switch ($db->get_sql_layer()) - { - case 'mysql4': - case 'mysqli': - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - USING ' . TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2 - WHERE t1.topic_moved_id = t2.topic_id - AND t1.forum_id = t2.forum_id"; - $db->sql_query($sql); - break; - - default: - $sql = 'SELECT t1.topic_id - FROM ' .TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2 - WHERE t1.topic_moved_id = t2.topic_id - AND t1.forum_id = t2.forum_id"; - $result = $db->sql_query($sql); - - $topic_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_id_ary[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (!count($topic_id_ary)) - { - return; - } - - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_id_ary); - $db->sql_query($sql); - - break; - } - - $db->sql_transaction('commit'); - break; - - case 'topic_visibility': - - $db->sql_transaction('begin'); - - $sql = 'SELECT t.topic_id, p.post_visibility - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and p.topic_id = t.topic_id - AND p.post_visibility = " . ITEM_APPROVED; - $result = $db->sql_query($sql); - - $topics_approved = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topics_approved[] = (int) $row['topic_id']; - } - $db->sql_freeresult($result); - - $sql = 'SELECT t.topic_id, p.post_visibility - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and " . $db->sql_in_set('t.topic_id', $topics_approved, true, true) . ' - AND p.topic_id = t.topic_id - AND p.post_visibility = ' . ITEM_DELETED; - $result = $db->sql_query($sql); - - $topics_softdeleted = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topics_softdeleted[] = (int) $row['topic_id']; - } - $db->sql_freeresult($result); - - $topics_softdeleted = array_diff($topics_softdeleted, $topics_approved); - $topics_not_unapproved = array_merge($topics_softdeleted, $topics_approved); - - $update_ary = array( - ITEM_UNAPPROVED => (!empty($topics_not_unapproved)) ? $where_sql_and . ' ' . $db->sql_in_set('topic_id', $topics_not_unapproved, true) : '', - ITEM_APPROVED => (!empty($topics_approved)) ? ' WHERE ' . $db->sql_in_set('topic_id', $topics_approved) : '', - ITEM_DELETED => (!empty($topics_softdeleted)) ? ' WHERE ' . $db->sql_in_set('topic_id', $topics_softdeleted) : '', - ); - - foreach ($update_ary as $visibility => $sql_where) - { - if ($sql_where) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_visibility = ' . $visibility . ' - ' . $sql_where; - $db->sql_query($sql); - } - } - - $db->sql_transaction('commit'); - break; - - case 'post_reported': - $post_ids = $post_reported = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT p.post_id, p.post_reported - FROM ' . POSTS_TABLE . " p - $where_sql - GROUP BY p.post_id, p.post_reported"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_ids[$row['post_id']] = $row['post_id']; - if ($row['post_reported']) - { - $post_reported[$row['post_id']] = 1; - } - } - $db->sql_freeresult($result); - - $sql = 'SELECT DISTINCT(post_id) - FROM ' . REPORTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids) . ' - AND report_closed = 0'; - $result = $db->sql_query($sql); - - $post_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($post_reported[$row['post_id']])) - { - $post_ids[] = $row['post_id']; - } - else - { - unset($post_reported[$row['post_id']]); - } - } - $db->sql_freeresult($result); - - // $post_reported should be empty by now, if it's not it contains - // posts that are falsely flagged as reported - foreach ($post_reported as $post_id => $void) - { - $post_ids[] = $post_id; - } - - if (count($post_ids)) - { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_reported = 1 - post_reported - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - break; - - case 'topic_reported': - if ($sync_extra) - { - sync('post_reported', $where_type, $where_ids); - } - - $topic_ids = $topic_reported = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT DISTINCT(t.topic_id) - FROM ' . POSTS_TABLE . " t - $where_sql_and t.post_reported = 1"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_reported[$row['topic_id']] = 1; - } - $db->sql_freeresult($result); - - $sql = 'SELECT t.topic_id, t.topic_reported - FROM ' . TOPICS_TABLE . " t - $where_sql"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_reported'] ^ isset($topic_reported[$row['topic_id']])) - { - $topic_ids[] = $row['topic_id']; - } - } - $db->sql_freeresult($result); - - if (count($topic_ids)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_reported = 1 - topic_reported - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - break; - - case 'post_attachment': - $post_ids = $post_attachment = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT p.post_id, p.post_attachment - FROM ' . POSTS_TABLE . " p - $where_sql - GROUP BY p.post_id, p.post_attachment"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_ids[$row['post_id']] = $row['post_id']; - if ($row['post_attachment']) - { - $post_attachment[$row['post_id']] = 1; - } - } - $db->sql_freeresult($result); - - $sql = 'SELECT DISTINCT(post_msg_id) - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . ' - AND in_message = 0'; - $result = $db->sql_query($sql); - - $post_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($post_attachment[$row['post_msg_id']])) - { - $post_ids[] = $row['post_msg_id']; - } - else - { - unset($post_attachment[$row['post_msg_id']]); - } - } - $db->sql_freeresult($result); - - // $post_attachment should be empty by now, if it's not it contains - // posts that are falsely flagged as having attachments - foreach ($post_attachment as $post_id => $void) - { - $post_ids[] = $post_id; - } - - if (count($post_ids)) - { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_attachment = 1 - post_attachment - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - break; - - case 'topic_attachment': - if ($sync_extra) - { - sync('post_attachment', $where_type, $where_ids); - } - - $topic_ids = $topic_attachment = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT DISTINCT(t.topic_id) - FROM ' . POSTS_TABLE . " t - $where_sql_and t.post_attachment = 1"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_attachment[$row['topic_id']] = 1; - } - $db->sql_freeresult($result); - - $sql = 'SELECT t.topic_id, t.topic_attachment - FROM ' . TOPICS_TABLE . " t - $where_sql"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_attachment'] ^ isset($topic_attachment[$row['topic_id']])) - { - $topic_ids[] = $row['topic_id']; - } - } - $db->sql_freeresult($result); - - if (count($topic_ids)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_attachment = 1 - topic_attachment - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - break; - - case 'forum': - - $db->sql_transaction('begin'); - - // 1: Get the list of all forums - $sql = 'SELECT f.* - FROM ' . FORUMS_TABLE . " f - $where_sql"; - $result = $db->sql_query($sql); - - $forum_data = $forum_ids = $post_ids = $last_post_id = $post_info = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['forum_type'] == FORUM_LINK) - { - continue; - } - - $forum_id = (int) $row['forum_id']; - $forum_ids[$forum_id] = $forum_id; - - $forum_data[$forum_id] = $row; - if ($sync_extra) - { - $forum_data[$forum_id]['posts_approved'] = 0; - $forum_data[$forum_id]['posts_unapproved'] = 0; - $forum_data[$forum_id]['posts_softdeleted'] = 0; - $forum_data[$forum_id]['topics_approved'] = 0; - $forum_data[$forum_id]['topics_unapproved'] = 0; - $forum_data[$forum_id]['topics_softdeleted'] = 0; - } - $forum_data[$forum_id]['last_post_id'] = 0; - $forum_data[$forum_id]['last_post_subject'] = ''; - $forum_data[$forum_id]['last_post_time'] = 0; - $forum_data[$forum_id]['last_poster_id'] = 0; - $forum_data[$forum_id]['last_poster_name'] = ''; - $forum_data[$forum_id]['last_poster_colour'] = ''; - } - $db->sql_freeresult($result); - - if (!count($forum_ids)) - { - break; - } - - $forum_ids = array_values($forum_ids); - - // 2: Get topic counts for each forum (optional) - if ($sync_extra) - { - $sql = 'SELECT forum_id, topic_visibility, COUNT(topic_id) AS total_topics - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . ' - GROUP BY forum_id, topic_visibility'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_id = (int) $row['forum_id']; - - if ($row['topic_visibility'] == ITEM_APPROVED) - { - $forum_data[$forum_id]['topics_approved'] = $row['total_topics']; - } - else if ($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) - { - $forum_data[$forum_id]['topics_unapproved'] = $row['total_topics']; - } - else if ($row['topic_visibility'] == ITEM_DELETED) - { - $forum_data[$forum_id]['topics_softdeleted'] = $row['total_topics']; - } - } - $db->sql_freeresult($result); - } - - // 3: Get post count for each forum (optional) - if ($sync_extra) - { - 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 - WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_status <> ' . ITEM_MOVED; - } - else - { - $sql = 'SELECT t.forum_id, SUM(t.topic_posts_approved) AS forum_posts_approved, SUM(t.topic_posts_unapproved) AS forum_posts_unapproved, SUM(t.topic_posts_softdeleted) AS forum_posts_softdeleted - FROM ' . TOPICS_TABLE . ' t - WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_status <> ' . ITEM_MOVED . ' - GROUP BY t.forum_id'; - } - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $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']; - $forum_data[$forum_id]['posts_softdeleted'] = (int) $row['forum_posts_softdeleted']; - } - $db->sql_freeresult($result); - } - - // 4: Get last_post_id for each forum - if (count($forum_ids) == 1) - { - $sql = 'SELECT MAX(t.topic_last_post_id) as last_post_id - FROM ' . TOPICS_TABLE . ' t - WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_visibility = ' . ITEM_APPROVED; - } - else - { - $sql = 'SELECT t.forum_id, MAX(t.topic_last_post_id) as last_post_id - FROM ' . TOPICS_TABLE . ' t - WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_visibility = ' . ITEM_APPROVED . ' - GROUP BY t.forum_id'; - } - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $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']; - - $post_ids[] = $row['last_post_id']; - } - $db->sql_freeresult($result); - - // 5: Retrieve last_post infos - 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 - WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' - AND p.poster_id = u.user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_info[$row['post_id']] = $row; - } - $db->sql_freeresult($result); - - foreach ($forum_data as $forum_id => $data) - { - if ($data['last_post_id']) - { - if (isset($post_info[$data['last_post_id']])) - { - $forum_data[$forum_id]['last_post_subject'] = $post_info[$data['last_post_id']]['post_subject']; - $forum_data[$forum_id]['last_post_time'] = $post_info[$data['last_post_id']]['post_time']; - $forum_data[$forum_id]['last_poster_id'] = $post_info[$data['last_post_id']]['poster_id']; - $forum_data[$forum_id]['last_poster_name'] = ($post_info[$data['last_post_id']]['poster_id'] != ANONYMOUS) ? $post_info[$data['last_post_id']]['username'] : $post_info[$data['last_post_id']]['post_username']; - $forum_data[$forum_id]['last_poster_colour'] = $post_info[$data['last_post_id']]['user_colour']; - } - else - { - // For some reason we did not find the post in the db - $forum_data[$forum_id]['last_post_id'] = 0; - $forum_data[$forum_id]['last_post_subject'] = ''; - $forum_data[$forum_id]['last_post_time'] = 0; - $forum_data[$forum_id]['last_poster_id'] = 0; - $forum_data[$forum_id]['last_poster_name'] = ''; - $forum_data[$forum_id]['last_poster_colour'] = ''; - } - } - } - unset($post_info); - } - - // 6: Now do that thing - $fieldnames = array('last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); - - if ($sync_extra) - { - array_push($fieldnames, 'posts_approved', 'posts_unapproved', 'posts_softdeleted', 'topics_approved', 'topics_unapproved', 'topics_softdeleted'); - } - - foreach ($forum_data as $forum_id => $row) - { - $sql_ary = array(); - - foreach ($fieldnames as $fieldname) - { - if ($row['forum_' . $fieldname] != $row[$fieldname]) - { - if (preg_match('#(name|colour|subject)$#', $fieldname)) - { - $sql_ary['forum_' . $fieldname] = (string) $row[$fieldname]; - } - else - { - $sql_ary['forum_' . $fieldname] = (int) $row[$fieldname]; - } - } - } - - if (count($sql_ary)) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE forum_id = ' . $forum_id; - $db->sql_query($sql); - } - } - - $db->sql_transaction('commit'); - break; - - case 'topic': - $topic_data = $post_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array(); - - $db->sql_transaction('begin'); - - $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_visibility, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_first_post_id, t.topic_first_poster_name, t.topic_first_poster_colour, t.topic_last_post_id, t.topic_last_post_subject, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_poster_colour, t.topic_last_post_time - FROM ' . TOPICS_TABLE . " t - $where_sql"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_moved_id']) - { - $moved_topics[] = $row['topic_id']; - continue; - } - - $topic_id = (int) $row['topic_id']; - $topic_data[$topic_id] = $row; - $topic_data[$topic_id]['visibility'] = ITEM_UNAPPROVED; - $topic_data[$topic_id]['posts_approved'] = 0; - $topic_data[$topic_id]['posts_unapproved'] = 0; - $topic_data[$topic_id]['posts_softdeleted'] = 0; - $topic_data[$topic_id]['first_post_id'] = 0; - $topic_data[$topic_id]['last_post_id'] = 0; - unset($topic_data[$topic_id]['topic_id']); - - // This array holds all topic_ids - $delete_topics[$topic_id] = ''; - - if ($sync_extra) - { - $topic_data[$topic_id]['reported'] = 0; - $topic_data[$topic_id]['attachment'] = 0; - } - } - $db->sql_freeresult($result); - - // Use "t" as table alias because of the $where_sql clause - // NOTE: 't.post_visibility' in the GROUP BY is causing a major slowdown. - $sql = 'SELECT t.topic_id, t.post_visibility, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id - FROM ' . POSTS_TABLE . " t - $where_sql - GROUP BY t.topic_id, t.post_visibility"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id = (int) $row['topic_id']; - - $row['first_post_id'] = (int) $row['first_post_id']; - $row['last_post_id'] = (int) $row['last_post_id']; - - if (!isset($topic_data[$topic_id])) - { - // Hey, these posts come from a topic that does not exist - $delete_posts[$topic_id] = ''; - } - else - { - // Unset the corresponding entry in $delete_topics - // When we'll be done, only topics with no posts will remain - unset($delete_topics[$topic_id]); - - if ($row['post_visibility'] == ITEM_APPROVED) - { - $topic_data[$topic_id]['posts_approved'] = $row['total_posts']; - } - else if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) - { - $topic_data[$topic_id]['posts_unapproved'] = $row['total_posts']; - } - else if ($row['post_visibility'] == ITEM_DELETED) - { - $topic_data[$topic_id]['posts_softdeleted'] = $row['total_posts']; - } - - if ($row['post_visibility'] == ITEM_APPROVED) - { - $topic_data[$topic_id]['visibility'] = ITEM_APPROVED; - $topic_data[$topic_id]['first_post_id'] = $row['first_post_id']; - $topic_data[$topic_id]['last_post_id'] = $row['last_post_id']; - } - else if ($topic_data[$topic_id]['visibility'] != ITEM_APPROVED) - { - // If there is no approved post, we take the min/max of the other visibilities - // for the last and first post info, because it is only visible to moderators anyway - $topic_data[$topic_id]['first_post_id'] = (!empty($topic_data[$topic_id]['first_post_id'])) ? min($topic_data[$topic_id]['first_post_id'], $row['first_post_id']) : $row['first_post_id']; - $topic_data[$topic_id]['last_post_id'] = max($topic_data[$topic_id]['last_post_id'], $row['last_post_id']); - - if ($topic_data[$topic_id]['visibility'] == ITEM_UNAPPROVED || $topic_data[$topic_id]['visibility'] == ITEM_REAPPROVE) - { - // Soft delete status is stronger than unapproved. - $topic_data[$topic_id]['visibility'] = $row['post_visibility']; - } - } - } - } - $db->sql_freeresult($result); - - foreach ($topic_data as $topic_id => $row) - { - $post_ids[] = $row['first_post_id']; - if ($row['first_post_id'] != $row['last_post_id']) - { - $post_ids[] = $row['last_post_id']; - } - } - - // Now we delete empty topics and orphan posts - if (count($delete_posts)) - { - delete_posts('topic_id', array_keys($delete_posts), false); - unset($delete_posts); - } - - 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 (count($delete_topics)) - { - $delete_topic_ids = array(); - foreach ($delete_topics as $topic_id => $void) - { - unset($topic_data[$topic_id]); - $delete_topic_ids[] = $topic_id; - } - - delete_topics('topic_id', $delete_topic_ids, false); - unset($delete_topics, $delete_topic_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 - WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' - AND u.user_id = p.poster_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id = intval($row['topic_id']); - - if ($row['post_id'] == $topic_data[$topic_id]['first_post_id']) - { - $topic_data[$topic_id]['time'] = $row['post_time']; - $topic_data[$topic_id]['poster'] = $row['poster_id']; - $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; - $topic_data[$topic_id]['first_poster_colour'] = $row['user_colour']; - } - - if ($row['post_id'] == $topic_data[$topic_id]['last_post_id']) - { - $topic_data[$topic_id]['last_poster_id'] = $row['poster_id']; - $topic_data[$topic_id]['last_post_subject'] = $row['post_subject']; - $topic_data[$topic_id]['last_post_time'] = $row['post_time']; - $topic_data[$topic_id]['last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; - $topic_data[$topic_id]['last_poster_colour'] = $row['user_colour']; - } - } - $db->sql_freeresult($result); - - // Make sure shadow topics do link to existing topics - if (count($moved_topics)) - { - $delete_topics = array(); - - $sql = 'SELECT t1.topic_id, t1.topic_moved_id - FROM ' . TOPICS_TABLE . ' t1 - LEFT JOIN ' . TOPICS_TABLE . ' t2 ON (t2.topic_id = t1.topic_moved_id) - WHERE ' . $db->sql_in_set('t1.topic_id', $moved_topics) . ' - AND t2.topic_id IS NULL'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $delete_topics[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (count($delete_topics)) - { - delete_topics('topic_id', $delete_topics, false); - } - unset($delete_topics); - - // Make sure shadow topics having no last post data being updated (this only rarely happens...) - $sql = 'SELECT topic_id, topic_moved_id, topic_last_post_id, topic_first_post_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $moved_topics) . ' - AND topic_last_post_time = 0'; - $result = $db->sql_query($sql); - - $shadow_topic_data = $post_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $shadow_topic_data[$row['topic_moved_id']] = $row; - $post_ids[] = $row['topic_last_post_id']; - $post_ids[] = $row['topic_first_post_id']; - } - $db->sql_freeresult($result); - - $sync_shadow_topics = array(); - 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 - WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' - AND u.user_id = p.poster_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_id = (int) $row['topic_id']; - - // Ok, there should be a shadow topic. If there isn't, then there's something wrong with the db. - // However, there's not much we can do about it. - if (!empty($shadow_topic_data[$topic_id])) - { - if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_first_post_id']) - { - $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id']; - - if (!isset($sync_shadow_topics[$orig_topic_id])) - { - $sync_shadow_topics[$orig_topic_id] = array(); - } - - $sync_shadow_topics[$orig_topic_id]['topic_time'] = $row['post_time']; - $sync_shadow_topics[$orig_topic_id]['topic_poster'] = $row['poster_id']; - $sync_shadow_topics[$orig_topic_id]['topic_first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; - $sync_shadow_topics[$orig_topic_id]['topic_first_poster_colour'] = $row['user_colour']; - } - - if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_last_post_id']) - { - $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id']; - - if (!isset($sync_shadow_topics[$orig_topic_id])) - { - $sync_shadow_topics[$orig_topic_id] = array(); - } - - $sync_shadow_topics[$orig_topic_id]['topic_last_poster_id'] = $row['poster_id']; - $sync_shadow_topics[$orig_topic_id]['topic_last_post_subject'] = $row['post_subject']; - $sync_shadow_topics[$orig_topic_id]['topic_last_post_time'] = $row['post_time']; - $sync_shadow_topics[$orig_topic_id]['topic_last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; - $sync_shadow_topics[$orig_topic_id]['topic_last_poster_colour'] = $row['user_colour']; - } - } - } - $db->sql_freeresult($result); - - $shadow_topic_data = array(); - - // Update the information we collected - if (count($sync_shadow_topics)) - { - foreach ($sync_shadow_topics as $sync_topic_id => $sql_ary) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE topic_id = ' . $sync_topic_id; - $db->sql_query($sql); - } - } - } - - unset($sync_shadow_topics, $shadow_topic_data); - } - - // These are fields that will be synchronised - $fieldnames = array('time', 'visibility', 'posts_approved', 'posts_unapproved', 'posts_softdeleted', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); - - if ($sync_extra) - { - // This routine assumes that post_reported values are correct - // if they are not, use sync('post_reported') first - $sql = 'SELECT t.topic_id, p.post_id - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and p.topic_id = t.topic_id - AND p.post_reported = 1 - GROUP BY t.topic_id, p.post_id"; - $result = $db->sql_query($sql); - - $fieldnames[] = 'reported'; - while ($row = $db->sql_fetchrow($result)) - { - $topic_data[intval($row['topic_id'])]['reported'] = 1; - } - $db->sql_freeresult($result); - - // This routine assumes that post_attachment values are correct - // if they are not, use sync('post_attachment') first - $sql = 'SELECT t.topic_id, p.post_id - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and p.topic_id = t.topic_id - AND p.post_attachment = 1 - GROUP BY t.topic_id, p.post_id"; - $result = $db->sql_query($sql); - - $fieldnames[] = 'attachment'; - while ($row = $db->sql_fetchrow($result)) - { - $topic_data[intval($row['topic_id'])]['attachment'] = 1; - } - $db->sql_freeresult($result); - } - - foreach ($topic_data as $topic_id => $row) - { - $sql_ary = array(); - - foreach ($fieldnames as $fieldname) - { - if (isset($row[$fieldname]) && isset($row['topic_' . $fieldname]) && $row['topic_' . $fieldname] != $row[$fieldname]) - { - $sql_ary['topic_' . $fieldname] = $row[$fieldname]; - } - } - - if (count($sql_ary)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE topic_id = ' . $topic_id; - $db->sql_query($sql); - - $resync_forums[$row['forum_id']] = $row['forum_id']; - } - } - unset($topic_data); - - $db->sql_transaction('commit'); - - // if some topics have been resync'ed then resync parent forums - // except when we're only syncing a range, we don't want to sync forums during - // batch processing. - if ($resync_parents && count($resync_forums) && $where_type != 'range') - { - sync('forum', 'forum_id', array_values($resync_forums), true, true); - } - break; - } - - return; -} - -/** -* Prune function -*/ -function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true, $prune_limit = 0) -{ - global $db, $phpbb_dispatcher; - - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - if (!count($forum_id)) - { - return; - } - - $sql_and = ''; - - if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE)) - { - $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE; - $sql_and .= ' AND topic_type <> ' . POST_GLOBAL; - } - - if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY)) - { - $sql_and .= ' AND topic_type <> ' . POST_STICKY; - } - - if ($prune_mode == 'posted') - { - $sql_and .= " AND topic_last_post_time < $prune_date"; - } - - if ($prune_mode == 'viewed') - { - $sql_and .= " AND topic_last_view_time < $prune_date"; - } - - if ($prune_mode == 'shadow') - { - $sql_and .= ' AND topic_status = ' . ITEM_MOVED . " AND topic_last_post_time < $prune_date"; - } - - /** - * Use this event to modify the SQL that selects topics to be pruned - * - * @event core.prune_sql - * @var string forum_id The forum id - * @var string prune_mode The prune mode - * @var string prune_date The prune date - * @var int prune_flags The prune flags - * @var bool auto_sync Whether or not to perform auto sync - * @var string sql_and SQL text appended to where clause - * @var int prune_limit The prune limit - * @since 3.1.3-RC1 - * @changed 3.1.10-RC1 Added prune_limit - */ - $vars = array( - 'forum_id', - 'prune_mode', - 'prune_date', - 'prune_flags', - 'auto_sync', - 'sql_and', - 'prune_limit', - ); - extract($phpbb_dispatcher->trigger_event('core.prune_sql', compact($vars))); - - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id) . " - AND poll_start = 0 - $sql_and"; - $result = $db->sql_query_limit($sql, $prune_limit); - - $topic_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_list[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if ($prune_flags & FORUM_FLAG_PRUNE_POLL) - { - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_id) . " - AND poll_start > 0 - AND poll_last_vote < $prune_date - $sql_and"; - $result = $db->sql_query_limit($sql, $prune_limit); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_list[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - $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); -} - -/** -* Function auto_prune(), this function now relies on passed vars -*/ -function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_freq) -{ - global $db, $user, $phpbb_log; - - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql, 3600); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $prune_date = time() - ($prune_days * 86400); - $next_prune = time() + ($prune_freq * 86400); - - $result = prune($forum_id, $prune_mode, $prune_date, $prune_flags, true, 300); - - if ($result['topics'] == 0 && $result['posts'] == 0) - { - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET prune_next = $next_prune - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_AUTO_PRUNE', false, array($row['forum_name'])); - } - - return; -} - -/** -* Cache moderators. Called whenever permissions are changed -* via admin_permissions. Changes of usernames and group names -* must be carried through for the moderators table. -* -* @param \phpbb\db\driver\driver_interface $db Database connection -* @param \phpbb\cache\driver\driver_interface Cache driver -* @param \phpbb\auth\auth $auth Authentication object -* @return null -*/ -function phpbb_cache_moderators($db, $cache, $auth) -{ - // Remove cached sql results - $cache->destroy('sql', MODERATOR_CACHE_TABLE); - - // Clear table - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE); - break; - - default: - $db->sql_query('TRUNCATE TABLE ' . MODERATOR_CACHE_TABLE); - break; - } - - // We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting - $sql_ary = array(); - - // Grab all users having moderative options... - $hold_ary = $auth->acl_user_raw_data(false, 'm_%', false); - - // Add users? - if (!empty($hold_ary)) - { - // At least one moderative option warrants a display - $ug_id_ary = array_keys($hold_ary); - - // Remove users who have group memberships with DENY moderator permissions - $sql_ary_deny = array( - 'SELECT' => 'a.forum_id, ug.user_id, g.group_id', - - 'FROM' => array( - ACL_OPTIONS_TABLE => 'o', - USER_GROUP_TABLE => 'ug', - GROUPS_TABLE => 'g', - ACL_GROUPS_TABLE => 'a', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id', - ), - ), - - 'WHERE' => '(o.auth_option_id = a.auth_option_id OR o.auth_option_id = r.auth_option_id) - AND ((a.auth_setting = ' . ACL_NEVER . ' AND r.auth_setting IS NULL) - OR r.auth_setting = ' . ACL_NEVER . ') - AND a.group_id = ug.group_id - AND g.group_id = ug.group_id - AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) - AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . " - AND ug.user_pending = 0 - AND o.auth_option " . $db->sql_like_expression('m_' . $db->get_any_char()), - ); - $sql = $db->sql_build_query('SELECT', $sql_ary_deny); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (isset($hold_ary[$row['user_id']][$row['forum_id']])) - { - unset($hold_ary[$row['user_id']][$row['forum_id']]); - } - } - $db->sql_freeresult($result); - - if (count($hold_ary)) - { - // Get usernames... - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary)); - $result = $db->sql_query($sql); - - $usernames_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $usernames_ary[$row['user_id']] = $row['username']; - } - $db->sql_freeresult($result); - - foreach ($hold_ary as $user_id => $forum_id_ary) - { - // Do not continue if user does not exist - if (!isset($usernames_ary[$user_id])) - { - continue; - } - - foreach ($forum_id_ary as $forum_id => $auth_ary) - { - $sql_ary[] = array( - 'forum_id' => (int) $forum_id, - 'user_id' => (int) $user_id, - 'username' => (string) $usernames_ary[$user_id], - 'group_id' => 0, - 'group_name' => '' - ); - } - } - } - } - - // Now to the groups... - $hold_ary = $auth->acl_group_raw_data(false, 'm_%', false); - - if (!empty($hold_ary)) - { - $ug_id_ary = array_keys($hold_ary); - - // Make sure not hidden or special groups are involved... - $sql = 'SELECT group_name, group_id, group_type - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', $ug_id_ary); - $result = $db->sql_query($sql); - - $groupnames_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['group_type'] == GROUP_HIDDEN || $row['group_type'] == GROUP_SPECIAL) - { - unset($hold_ary[$row['group_id']]); - } - - $groupnames_ary[$row['group_id']] = $row['group_name']; - } - $db->sql_freeresult($result); - - foreach ($hold_ary as $group_id => $forum_id_ary) - { - // If there is no group, we do not assign it... - if (!isset($groupnames_ary[$group_id])) - { - continue; - } - - foreach ($forum_id_ary as $forum_id => $auth_ary) - { - $flag = false; - foreach ($auth_ary as $auth_option => $setting) - { - // Make sure at least one ACL_YES option is set... - if ($setting == ACL_YES) - { - $flag = true; - break; - } - } - - if (!$flag) - { - continue; - } - - $sql_ary[] = array( - 'forum_id' => (int) $forum_id, - 'user_id' => 0, - 'username' => '', - 'group_id' => (int) $group_id, - 'group_name' => (string) $groupnames_ary[$group_id] - ); - } - } - } - - $db->sql_multi_insert(MODERATOR_CACHE_TABLE, $sql_ary); -} - -/** -* View log -* -* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved -* @param array &$log The result array with the logs -* @param mixed &$log_count If $log_count is set to false, we will skip counting all entries in the database. -* Otherwise an integer with the number of total matching entries is returned. -* @param int $limit Limit the number of entries that are returned -* @param int $offset Offset when fetching the log entries, f.e. when paginating -* @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids) -* @param int $topic_id Restrict the log entries to the given topic_id -* @param int $user_id Restrict the log entries to the given user_id -* @param int $log_time Only get log entries newer than the given timestamp -* @param string $sort_by SQL order option, e.g. 'l.log_time DESC' -* @param string $keywords Will only return log entries that have the keywords in log_operation or log_data -* -* @return int Returns the offset of the last valid page, if the specified offset was invalid (too high) -*/ -function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '') -{ - global $phpbb_log; - - $count_logs = ($log_count !== false); - - $log = $phpbb_log->get_logs($mode, $count_logs, $limit, $offset, $forum_id, $topic_id, $user_id, $limit_days, $sort_by, $keywords); - $log_count = $phpbb_log->get_log_count(); - - return $phpbb_log->get_valid_offset(); -} - -/** -* Removes moderators and administrators from foe lists. -* -* @param \phpbb\db\driver\driver_interface $db Database connection -* @param \phpbb\auth\auth $auth Authentication object -* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore -* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore -* @return null -*/ -function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false) -{ - // update foes for some user - if (is_array($user_id) && count($user_id)) - { - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $db->sql_in_set('zebra_id', $user_id) . ' - AND foe = 1'; - $db->sql_query($sql); - return; - } - - // update foes for some group - if (is_array($group_id) && count($group_id)) - { - // Grab group settings... - $sql_ary = array( - 'SELECT' => 'a.group_id', - - 'FROM' => array( - ACL_OPTIONS_TABLE => 'ao', - ACL_GROUPS_TABLE => 'a', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id', - ), - ), - - 'WHERE' => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id) - AND ' . $db->sql_in_set('a.group_id', $group_id) . " - AND ao.auth_option IN ('a_', 'm_')", - - 'GROUP_BY' => 'a.group_id', - ); - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - - $groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $groups[] = (int) $row['group_id']; - } - $db->sql_freeresult($result); - - if (!count($groups)) - { - return; - } - - switch ($db->get_sql_layer()) - { - case 'mysqli': - case 'mysql4': - $sql = 'DELETE ' . (($db->get_sql_layer() === 'mysqli' || version_compare($db->sql_server_info(true), '4.1', '>=')) ? 'z.*' : ZEBRA_TABLE) . ' - FROM ' . ZEBRA_TABLE . ' z, ' . USER_GROUP_TABLE . ' ug - WHERE z.zebra_id = ug.user_id - AND z.foe = 1 - AND ' . $db->sql_in_set('ug.group_id', $groups); - $db->sql_query($sql); - break; - - default: - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', $groups); - $result = $db->sql_query($sql); - - $users = array(); - while ($row = $db->sql_fetchrow($result)) - { - $users[] = (int) $row['user_id']; - } - $db->sql_freeresult($result); - - if (count($users)) - { - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $db->sql_in_set('zebra_id', $users) . ' - AND foe = 1'; - $db->sql_query($sql); - } - break; - } - - return; - } - - // update foes for everyone - $perms = array(); - foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary) - { - foreach ($forum_ary as $auth_option => $user_ary) - { - $perms = array_merge($perms, $user_ary); - } - } - - if (count($perms)) - { - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . ' - AND foe = 1'; - $db->sql_query($sql); - } - unset($perms); -} - -/** -* Lists inactive users -*/ -function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC') -{ - global $db, $user; - - $sql = 'SELECT COUNT(user_id) AS user_count - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_INACTIVE . - (($limit_days) ? " AND user_inactive_time >= $limit_days" : ''); - $result = $db->sql_query($sql); - $user_count = (int) $db->sql_fetchfield('user_count'); - $db->sql_freeresult($result); - - if ($user_count == 0) - { - // Save the queries, because there are no users to display - return 0; - } - - if ($offset >= $user_count) - { - $offset = ($offset - $limit < 0) ? 0 : $offset - $limit; - } - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_INACTIVE . - (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . " - ORDER BY $sort_by"; - $result = $db->sql_query_limit($sql, $limit, $offset); - - while ($row = $db->sql_fetchrow($result)) - { - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_UNKNOWN']; - switch ($row['user_inactive_reason']) - { - case INACTIVE_REGISTER: - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REGISTER']; - break; - - case INACTIVE_PROFILE: - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_PROFILE']; - break; - - case INACTIVE_MANUAL: - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_MANUAL']; - break; - - case INACTIVE_REMIND: - $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REMIND']; - break; - } - - $users[] = $row; - } - $db->sql_freeresult($result); - - return $offset; -} - -/** -* Lists warned users -*/ -function view_warned_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_warnings DESC') -{ - global $db; - - $sql = 'SELECT user_id, username, user_colour, user_warnings, user_last_warning - FROM ' . USERS_TABLE . ' - WHERE user_warnings > 0 - ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '') . " - ORDER BY $sort_by"; - $result = $db->sql_query_limit($sql, $limit, $offset); - $users = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - $sql = 'SELECT count(user_id) AS user_count - FROM ' . USERS_TABLE . ' - WHERE user_warnings > 0 - ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : ''); - $result = $db->sql_query($sql); - $user_count = (int) $db->sql_fetchfield('user_count'); - $db->sql_freeresult($result); - - return; -} - -/** -* Get database size -* Currently only mysql and mssql are supported -*/ -function get_database_size() -{ - global $db, $user, $table_prefix; - - $database_size = false; - - // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0 - switch ($db->get_sql_layer()) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $sql = 'SELECT VERSION() AS mysql_version'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $version = $row['mysql_version']; - - if (preg_match('#(3\.23|[45]\.|10\.[0-9]\.[0-9]{1,2}-+Maria)#', $version)) - { - $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.|10\.[0-9]\.[0-9]{1,2}-+Maria#', $version)) ? "`{$db->get_db_name()}`" : $db->get_db_name(); - - $sql = 'SHOW TABLE STATUS - FROM ' . $db_name; - $result = $db->sql_query($sql, 7200); - - $database_size = 0; - while ($row = $db->sql_fetchrow($result)) - { - if ((isset($row['Type']) && $row['Type'] != 'MRG_MyISAM') || (isset($row['Engine']) && ($row['Engine'] == 'MyISAM' || $row['Engine'] == 'InnoDB' || $row['Engine'] == 'Aria'))) - { - if ($table_prefix != '') - { - if (strpos($row['Name'], $table_prefix) !== false) - { - $database_size += $row['Data_length'] + $row['Index_length']; - } - } - else - { - $database_size += $row['Data_length'] + $row['Index_length']; - } - } - } - $db->sql_freeresult($result); - } - } - break; - - case 'sqlite3': - global $dbhost; - - if (file_exists($dbhost)) - { - $database_size = filesize($dbhost); - } - - break; - - case 'mssql_odbc': - case 'mssqlnative': - $sql = 'SELECT @@VERSION AS mssql_version'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize - FROM sysfiles'; - - if ($row) - { - // Azure stats are stored elsewhere - if (strpos($row['mssql_version'], 'SQL Azure') !== false) - { - $sql = 'SELECT ((SUM(reserved_page_count) * 8.0) * 1024.0) as dbsize - FROM sys.dm_db_partition_stats'; - } - } - - $result = $db->sql_query($sql, 7200); - $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false; - $db->sql_freeresult($result); - break; - - case 'postgres': - $sql = "SELECT proname - FROM pg_proc - WHERE proname = 'pg_database_size'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row['proname'] == 'pg_database_size') - { - $database = $db->get_db_name(); - if (strpos($database, '.') !== false) - { - list($database, ) = explode('.', $database); - } - - $sql = "SELECT oid - FROM pg_database - WHERE datname = '$database'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $oid = $row['oid']; - - $sql = 'SELECT pg_database_size(' . $oid . ') as size'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $database_size = $row['size']; - } - break; - - case 'oracle': - $sql = 'SELECT SUM(bytes) as dbsize - FROM user_segments'; - $result = $db->sql_query($sql, 7200); - $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false; - $db->sql_freeresult($result); - break; - } - - $database_size = ($database_size !== false) ? get_formatted_filesize($database_size) : $user->lang['NOT_AVAILABLE']; - - return $database_size; -} - -/* -* Tidy Warnings -* Remove all warnings which have now expired from the database -* The duration of a warning can be defined by the administrator -* This only removes the warning and reduces the associated count, -* it does not remove the user note recording the contents of the warning -*/ -function tidy_warnings() -{ - global $db, $config; - - $expire_date = time() - ($config['warnings_expire_days'] * 86400); - $warning_list = $user_list = array(); - - $sql = 'SELECT * FROM ' . WARNINGS_TABLE . " - WHERE warning_time < $expire_date"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $warning_list[] = $row['warning_id']; - $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? ++$user_list[$row['user_id']] : 1; - } - $db->sql_freeresult($result); - - if (count($warning_list)) - { - $db->sql_transaction('begin'); - - $sql = 'DELETE FROM ' . WARNINGS_TABLE . ' - WHERE ' . $db->sql_in_set('warning_id', $warning_list); - $db->sql_query($sql); - - foreach ($user_list as $user_id => $value) - { - $sql = 'UPDATE ' . USERS_TABLE . " SET user_warnings = user_warnings - $value - WHERE user_id = $user_id"; - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - } - - $config->set('warnings_last_gc', time(), false); -} - -/** -* Tidy database, doing some maintanance tasks -*/ -function tidy_database() -{ - global $config, $db; - - // Here we check permission consistency - - // Sometimes, it can happen permission tables having forums listed which do not exist - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - - $forum_ids = array(0); - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $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); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true); - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - $config->set('database_last_gc', time(), false); -} - -/** -* Add permission language - this will make sure custom files will be included -*/ -function add_permission_language() -{ - global $user, $phpEx, $phpbb_extension_manager; - - // add permission language files from extensions - $finder = $phpbb_extension_manager->get_finder(); - - $lang_files = $finder - ->prefix('permissions_') - ->suffix(".$phpEx") - ->core_path('language/') - ->extension_directory('/language') - ->find(); - - foreach ($lang_files as $lang_file => $ext_name) - { - if ($ext_name === '/') - { - $user->add_lang($lang_file); - } - else - { - $user->add_lang_ext($ext_name, $lang_file); - } - } -} - -/** - * Enables a particular flag in a bitfield column of a given table. - * - * @param string $table_name The table to update - * @param string $column_name The column containing a bitfield to update - * @param int $flag The binary flag which is OR-ed with the current column value - * @param string $sql_more This string is attached to the sql query generated to update the table. - * - * @return null - */ -function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '') -{ - global $db; - - $sql = 'UPDATE ' . $table_name . ' - SET ' . $column_name . ' = ' . $db->sql_bit_or($column_name, $flag) . ' - ' . $sql_more; - $db->sql_query($sql); -} diff --git a/install/update/old/includes/functions_compatibility.php b/install/update/old/includes/functions_compatibility.php deleted file mode 100644 index e95fa40..0000000 --- a/install/update/old/includes/functions_compatibility.php +++ /dev/null @@ -1,513 +0,0 @@ - -* @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; -} - -/** -* Get user avatar -* -* @deprecated 3.1.0-a1 (To be removed: 3.3.0) -* -* @param string $avatar Users assigned avatar name -* @param int $avatar_type Type of avatar -* @param string $avatar_width Width of users avatar -* @param string $avatar_height Height of users avatar -* @param string $alt Optional language string for alt tag within image, can be a language key or text -* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP -* @param bool $lazy If true, will be lazy loaded (requires JS) -* -* @return string Avatar image -*/ -function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false, $lazy = false) -{ - // map arguments to new function phpbb_get_avatar() - $row = array( - 'avatar' => $avatar, - 'avatar_type' => $avatar_type, - 'avatar_width' => $avatar_width, - 'avatar_height' => $avatar_height, - ); - - return phpbb_get_avatar($row, $alt, $ignore_config, $lazy); -} - -/** -* Hash the password -* -* @deprecated 3.1.0-a2 (To be removed: 3.3.0) -* -* @param string $password Password to be hashed -* -* @return string|bool Password hash or false if something went wrong during hashing -*/ -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); -} - -/** -* Check for correct password -* -* @deprecated 3.1.0-a2 (To be removed: 3.3.0) -* -* @param string $password The password in plain text -* @param string $hash The stored password hash -* -* @return bool Returns true if the password is correct, false if not. -*/ -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); -} - -/** -* Eliminates useless . and .. components from specified path. -* -* Deprecated, use filesystem class instead -* -* @param string $path Path to clean -* @return string Cleaned path -* -* @deprecated 3.1.0 (To be removed: 3.3.0) -*/ -function phpbb_clean_path($path) -{ - global $phpbb_path_helper, $phpbb_container; - - 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) - { - global $phpbb_root_path, $phpEx; - - // The container is not yet loaded, use a new instance - if (!class_exists('\phpbb\path_helper')) - { - require($phpbb_root_path . 'phpbb/path_helper.' . $phpEx); - } - - $request = new phpbb\request\request(); - $phpbb_path_helper = new phpbb\path_helper( - new phpbb\symfony_request( - $request - ), - new phpbb\filesystem\filesystem(), - $request, - $phpbb_root_path, - $phpEx - ); - } - - return $phpbb_path_helper->clean_path($path); -} - -/** -* Pick a timezone -* -* @param string $default A timezone to select -* @param boolean $truncate Shall we truncate the options text -* -* @return string Returns the options for timezone selector only -* -* @deprecated 3.1.0 (To be removed: 3.3.0) -*/ -function tz_select($default = '', $truncate = false) -{ - global $template, $user; - - return phpbb_timezone_select($template, $user, $default, $truncate); -} - -/** -* Cache moderators. Called whenever permissions are changed -* via admin_permissions. Changes of usernames and group names -* must be carried through for the moderators table. -* -* @deprecated 3.1.0 (To be removed: 3.3.0) -* @return null -*/ -function cache_moderators() -{ - global $db, $cache, $auth; - return phpbb_cache_moderators($db, $cache, $auth); -} - -/** -* Removes moderators and administrators from foe lists. -* -* @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 -*/ -function update_foes($group_id = false, $user_id = false) -{ - global $db, $auth; - return phpbb_update_foes($db, $auth, $group_id, $user_id); -} - -/** -* Get user rank title and image -* -* @param int $user_rank the current stored users rank id -* @param int $user_posts the users number of posts -* @param string &$rank_title the rank title will be stored here after execution -* @param string &$rank_img the rank image as full img tag is stored here after execution -* @param string &$rank_img_src the rank image source is stored here after execution -* -* @deprecated 3.1.0-RC5 (To be removed: 3.3.0) -* -* Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false -*/ -function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank_img_src) -{ - global $phpbb_root_path, $phpEx; - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $rank_data = phpbb_get_user_rank(array('user_rank' => $user_rank), $user_posts); - $rank_title = $rank_data['title']; - $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/install/update/old/includes/functions_compress.php b/install/update/old/includes/functions_compress.php deleted file mode 100644 index e86da77..0000000 --- a/install/update/old/includes/functions_compress.php +++ /dev/null @@ -1,830 +0,0 @@ - -* @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 for handling archives (compression/decompression) -*/ -class compress -{ - var $fp = 0; - - /** - * @var array - */ - protected $filelist = array(); - - /** - * Add file to archive - */ - function add_file($src, $src_rm_prefix = '', $src_add_prefix = '', $skip_files = '') - { - global $phpbb_root_path; - - $skip_files = explode(',', $skip_files); - - // Remove rm prefix from src path - $src_path = ($src_rm_prefix) ? preg_replace('#^(' . preg_quote($src_rm_prefix, '#') . ')#', '', $src) : $src; - // Add src prefix - $src_path = ($src_add_prefix) ? ($src_add_prefix . ((substr($src_add_prefix, -1) != '/') ? '/' : '') . $src_path) : $src_path; - // Remove initial "/" if present - $src_path = (substr($src_path, 0, 1) == '/') ? substr($src_path, 1) : $src_path; - - if (is_file($phpbb_root_path . $src)) - { - $this->data($src_path, file_get_contents("$phpbb_root_path$src"), stat("$phpbb_root_path$src"), false); - } - else if (is_dir($phpbb_root_path . $src)) - { - // Clean up path, add closing / if not present - $src_path = ($src_path && substr($src_path, -1) != '/') ? $src_path . '/' : $src_path; - - $filelist = filelist("$phpbb_root_path$src", '', '*'); - krsort($filelist); - - /** - * Commented out, as adding the folders produces corrupted archives - if ($src_path) - { - $this->data($src_path, '', true, stat("$phpbb_root_path$src")); - } - */ - - foreach ($filelist as $path => $file_ary) - { - /** - * Commented out, as adding the folders produces corrupted archives - if ($path) - { - // Same as for src_path - $path = (substr($path, 0, 1) == '/') ? substr($path, 1) : $path; - $path = ($path && substr($path, -1) != '/') ? $path . '/' : $path; - - $this->data("$src_path$path", '', true, stat("$phpbb_root_path$src$path")); - } - */ - - foreach ($file_ary as $file) - { - if (in_array($path . $file, $skip_files)) - { - continue; - } - - $this->data("$src_path$path$file", file_get_contents("$phpbb_root_path$src$path$file"), stat("$phpbb_root_path$src$path$file"), false); - } - } - } - else - { - // $src does not exist - return false; - } - - return true; - } - - /** - * Add custom file (the filepath will not be adjusted) - */ - function add_custom_file($src, $filename) - { - if (!file_exists($src)) - { - return false; - } - - $this->data($filename, file_get_contents($src), stat($src), false); - return true; - } - - /** - * Add file data - */ - function add_data($src, $name) - { - $stat = array(); - $stat[2] = 436; //384 - $stat[4] = $stat[5] = 0; - $stat[7] = strlen($src); - $stat[9] = time(); - $this->data($name, $src, $stat, false); - return true; - } - - /** - * Checks if a file by that name as already been added and, if it has, - * returns a new, unique name. - * - * @param string $name The filename - * @return string A unique filename - */ - protected function unique_filename($name) - { - if (isset($this->filelist[$name])) - { - $start = $name; - $ext = ''; - $this->filelist[$name]++; - - // Separate the extension off the end of the filename to preserve it - $pos = strrpos($name, '.'); - if ($pos !== false) - { - $start = substr($name, 0, $pos); - $ext = substr($name, $pos); - } - - return $start . '_' . $this->filelist[$name] . $ext; - } - - $this->filelist[$name] = 0; - return $name; - } - - /** - * Return available methods - * - * @return array Array of strings of available compression methods (.tar, .tar.gz, .zip, etc.) - */ - static public function methods() - { - $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; - } - - return $methods; - } -} - -/** -* 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 -* -* Modified extensively by psoTFX and DavidMJ, (c) phpBB Limited, 2003 -* -* Based on work by Eric Mueller and Denis125 -* Official ZIP file format: http://www.pkware.com/appnote.txt -*/ -class compress_zip extends compress -{ - var $datasec = array(); - var $ctrl_dir = array(); - var $eof_cdh = "\x50\x4b\x05\x06\x00\x00\x00\x00"; - - var $old_offset = 0; - var $datasec_len = 0; - - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * Constructor - */ - 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) - { - trigger_error('Unable to open file ' . $file . ' [' . $mode . 'b]'); - } - } - - /** - * Convert unix to dos time - */ - function unix_to_dos_time($time) - { - $timearray = (!$time) ? getdate() : getdate($time); - - if ($timearray['year'] < 1980) - { - $timearray['year'] = 1980; - $timearray['mon'] = $timearray['mday'] = 1; - $timearray['hours'] = $timearray['minutes'] = $timearray['seconds'] = 0; - } - - return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1); - } - - /** - * Extract archive - */ - function extract($dst) - { - // Loop the file, looking for files and folders - $dd_try = false; - rewind($this->fp); - - while (!feof($this->fp)) - { - // Check if the signature is valid... - $signature = fread($this->fp, 4); - - switch ($signature) - { - // 'Local File Header' - case "\x50\x4b\x03\x04": - // Lets get everything we need. - // We don't store the version needed to extract, the general purpose bit flag or the date and time fields - $data = unpack("@4/vc_method/@10/Vcrc/Vc_size/Vuc_size/vname_len/vextra_field", fread($this->fp, 26)); - $file_name = fread($this->fp, $data['name_len']); // filename - - if ($data['extra_field']) - { - fread($this->fp, $data['extra_field']); // extra field - } - - $target_filename = "$dst$file_name"; - - if (!$data['uc_size'] && !$data['crc'] && substr($file_name, -1, 1) == '/') - { - if (!is_dir($target_filename)) - { - $str = ''; - $folders = explode('/', $target_filename); - - // Create and folders and subfolders if they do not exist - foreach ($folders as $folder) - { - $folder = trim($folder); - if (!$folder) - { - continue; - } - - $str = (!empty($str)) ? $str . '/' . $folder : $folder; - if (!is_dir($str)) - { - if (!@mkdir($str, 0777)) - { - trigger_error("Could not create directory $folder"); - } - - try - { - $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - } - // This is a directory, we are not writting files - continue; - } - else - { - // Some archivers are punks, they don't include folders in their archives! - $str = ''; - $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME)); - - // Create and folders and subfolders if they do not exist - foreach ($folders as $folder) - { - $folder = trim($folder); - if (!$folder) - { - continue; - } - - $str = (!empty($str)) ? $str . '/' . $folder : $folder; - if (!is_dir($str)) - { - if (!@mkdir($str, 0777)) - { - trigger_error("Could not create directory $folder"); - } - - try - { - $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - } - - if (!$data['uc_size']) - { - $content = ''; - } - else - { - $content = fread($this->fp, $data['c_size']); - } - - $fp = fopen($target_filename, "w"); - - switch ($data['c_method']) - { - case 0: - // Not compressed - fwrite($fp, $content); - break; - - case 8: - // Deflate - fwrite($fp, gzinflate($content, $data['uc_size'])); - break; - - case 12: - // Bzip2 - fwrite($fp, bzdecompress($content)); - break; - } - - fclose($fp); - break; - - // We hit the 'Central Directory Header', we can stop because nothing else in here requires our attention - // or we hit the end of the central directory record, we can safely end the loop as we are totally finished with looking for files and folders - case "\x50\x4b\x01\x02": - // This case should simply never happen.. but it does exist.. - case "\x50\x4b\x05\x06": - break 2; - - // 'Packed to Removable Disk', ignore it and look for the next signature... - case 'PK00': - continue 2; - - // We have encountered a header that is weird. Lets look for better data... - default: - if (!$dd_try) - { - // Unexpected header. Trying to detect wrong placed 'Data Descriptor'; - $dd_try = true; - fseek($this->fp, 8, SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4) - continue 2; - } - trigger_error("Unexpected header, ending loop"); - break 2; - } - - $dd_try = false; - } - } - - /** - * Close archive - */ - function close() - { - // Write out central file directory and footer ... if it exists - if (count($this->ctrl_dir)) - { - fwrite($this->fp, $this->file()); - } - fclose($this->fp); - } - - /** - * Create the structures ... note we assume version made by is MSDOS - */ - function data($name, $data, $stat, $is_dir = false) - { - $name = str_replace('\\', '/', $name); - $name = $this->unique_filename($name); - - $hexdtime = pack('V', $this->unix_to_dos_time($stat[9])); - - if ($is_dir) - { - $unc_len = $c_len = $crc = 0; - $zdata = ''; - $var_ext = 10; - } - else - { - $unc_len = strlen($data); - $crc = crc32($data); - $zdata = gzdeflate($data); - $c_len = strlen($zdata); - $var_ext = 20; - - // Did we compress? No, then use data as is - if ($c_len >= $unc_len) - { - $zdata = $data; - $c_len = $unc_len; - $var_ext = 10; - } - } - unset($data); - - // If we didn't compress set method to store, else deflate - $c_method = ($c_len == $unc_len) ? "\x00\x00" : "\x08\x00"; - - // Are we a file or a directory? Set archive for file - $attrib = ($is_dir) ? 16 : 32; - - // File Record Header - $fr = "\x50\x4b\x03\x04"; // Local file header 4bytes - $fr .= pack('v', $var_ext); // ver needed to extract 2bytes - $fr .= "\x00\x00"; // gen purpose bit flag 2bytes - $fr .= $c_method; // compression method 2bytes - $fr .= $hexdtime; // last mod time and date 2+2bytes - $fr .= pack('V', $crc); // crc32 4bytes - $fr .= pack('V', $c_len); // compressed filesize 4bytes - $fr .= pack('V', $unc_len); // uncompressed filesize 4bytes - $fr .= pack('v', strlen($name));// length of filename 2bytes - - $fr .= pack('v', 0); // extra field length 2bytes - $fr .= $name; - $fr .= $zdata; - unset($zdata); - - $this->datasec_len += strlen($fr); - - // Add data to file ... by writing data out incrementally we save some memory - fwrite($this->fp, $fr); - unset($fr); - - // Central Directory Header - $cdrec = "\x50\x4b\x01\x02"; // header 4bytes - $cdrec .= "\x00\x00"; // version made by - $cdrec .= pack('v', $var_ext); // version needed to extract - $cdrec .= "\x00\x00"; // gen purpose bit flag - $cdrec .= $c_method; // compression method - $cdrec .= $hexdtime; // last mod time & date - $cdrec .= pack('V', $crc); // crc32 - $cdrec .= pack('V', $c_len); // compressed filesize - $cdrec .= pack('V', $unc_len); // uncompressed filesize - $cdrec .= pack('v', strlen($name)); // length of filename - $cdrec .= pack('v', 0); // extra field length - $cdrec .= pack('v', 0); // file comment length - $cdrec .= pack('v', 0); // disk number start - $cdrec .= pack('v', 0); // internal file attributes - $cdrec .= pack('V', $attrib); // external file attributes - $cdrec .= pack('V', $this->old_offset); // relative offset of local header - $cdrec .= $name; - - // Save to central directory - $this->ctrl_dir[] = $cdrec; - - $this->old_offset = $this->datasec_len; - } - - /** - * file - */ - function file() - { - $ctrldir = implode('', $this->ctrl_dir); - - return $ctrldir . $this->eof_cdh . - 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 - } - - /** - * Download archive - */ - function download($filename, $download_name = false) - { - global $phpbb_root_path; - - if ($download_name === false) - { - $download_name = $filename; - } - - $mimetype = 'application/zip'; - - header('Cache-Control: private, no-cache'); - header("Content-Type: $mimetype; name=\"$download_name.zip\""); - header("Content-disposition: attachment; filename=$download_name.zip"); - - $fp = @fopen("{$phpbb_root_path}store/$filename.zip", 'rb'); - if ($fp) - { - while ($buffer = fread($fp, 1024)) - { - echo $buffer; - } - fclose($fp); - } - } -} - -/** -* Tar/tar.gz compression routine -* Header/checksum creation derived from tarfile.pl, (c) Tom Horsley, 1994 -*/ -class compress_tar extends compress -{ - var $isgz = false; - var $isbz = false; - var $filename = ''; - var $mode = ''; - var $type = ''; - var $wrote = false; - - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * Constructor - */ - 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); - - $this->mode = &$mode; - $this->file = &$file; - $this->type = &$type; - $this->open(); - - $this->filesystem = ($phpbb_filesystem instanceof \phpbb\filesystem\filesystem_interface) ? $phpbb_filesystem : new \phpbb\filesystem\filesystem(); - } - - /** - * Extract archive - */ - function extract($dst) - { - $fzread = ($this->isbz && function_exists('bzread')) ? 'bzread' : (($this->isgz && @extension_loaded('zlib')) ? 'gzread' : 'fread'); - - // Run through the file and grab directory entries - while ($buffer = $fzread($this->fp, 512)) - { - $tmp = unpack('A6magic', substr($buffer, 257, 6)); - - if (trim($tmp['magic']) == 'ustar') - { - $tmp = unpack('A100name', $buffer); - $filename = trim($tmp['name']); - - $tmp = unpack('Atype', substr($buffer, 156, 1)); - $filetype = (int) trim($tmp['type']); - - $tmp = unpack('A12size', substr($buffer, 124, 12)); - $filesize = octdec((int) trim($tmp['size'])); - - $target_filename = "$dst$filename"; - - if ($filetype == 5) - { - if (!is_dir($target_filename)) - { - $str = ''; - $folders = explode('/', $target_filename); - - // Create and folders and subfolders if they do not exist - foreach ($folders as $folder) - { - $folder = trim($folder); - if (!$folder) - { - continue; - } - - $str = (!empty($str)) ? $str . '/' . $folder : $folder; - if (!is_dir($str)) - { - if (!@mkdir($str, 0777)) - { - trigger_error("Could not create directory $folder"); - } - - try - { - $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - } - } - else if ($filesize >= 0 && ($filetype == 0 || $filetype == "\0")) - { - // Some archivers are punks, they don't properly order the folders in their archives! - $str = ''; - $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME)); - - // Create and folders and subfolders if they do not exist - foreach ($folders as $folder) - { - $folder = trim($folder); - if (!$folder) - { - continue; - } - - $str = (!empty($str)) ? $str . '/' . $folder : $folder; - if (!is_dir($str)) - { - if (!@mkdir($str, 0777)) - { - trigger_error("Could not create directory $folder"); - } - - try - { - $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - - // Write out the files - if (!($fp = fopen($target_filename, 'wb'))) - { - trigger_error("Couldn't create file $filename"); - } - - 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); - fclose($fp); - } - } - } - } - - /** - * Close archive - */ - function close() - { - $fzclose = ($this->isbz && function_exists('bzclose')) ? 'bzclose' : (($this->isgz && @extension_loaded('zlib')) ? 'gzclose' : 'fclose'); - - if ($this->wrote) - { - $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite'); - - // The end of a tar archive ends in two records of all NULLs (1024 bytes of \0) - $fzwrite($this->fp, str_repeat("\0", 1024)); - } - - $fzclose($this->fp); - } - - /** - * Create the structures - */ - function data($name, $data, $stat, $is_dir = false) - { - $name = $this->unique_filename($name); - $this->wrote = true; - $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite'); - - $typeflag = ($is_dir) ? '5' : ''; - - // This is the header data, it contains all the info we know about the file or folder that we are about to archive - $header = ''; - $header .= pack('a100', $name); // file name - $header .= pack('a8', sprintf("%07o", $stat[2])); // file mode - $header .= pack('a8', sprintf("%07o", $stat[4])); // owner id - $header .= pack('a8', sprintf("%07o", $stat[5])); // group id - $header .= pack('a12', sprintf("%011o", $stat[7])); // file size - $header .= pack('a12', sprintf("%011o", $stat[9])); // last mod time - - // Checksum - $checksum = 0; - for ($i = 0; $i < 148; $i++) - { - $checksum += ord($header[$i]); - } - - // We precompute the rest of the hash, this saves us time in the loop and allows us to insert our hash without resorting to string functions - $checksum += 2415 + (($is_dir) ? 53 : 0); - - $header .= pack('a8', sprintf("%07o", $checksum)); // checksum - $header .= pack('a1', $typeflag); // link indicator - $header .= pack('a100', ''); // name of linked file - $header .= pack('a6', 'ustar'); // ustar indicator - $header .= pack('a2', '00'); // ustar version - $header .= pack('a32', 'Unknown'); // owner name - $header .= pack('a32', 'Unknown'); // group name - $header .= pack('a8', ''); // device major number - $header .= pack('a8', ''); // device minor number - $header .= pack('a155', ''); // filename prefix - $header .= pack('a12', ''); // end - - // This writes the entire file in one shot. Header, followed by data and then null padded to a multiple of 512 - $fzwrite($this->fp, $header . (($stat[7] !== 0 && !$is_dir) ? $data . str_repeat("\0", (($stat[7] + 511) &~ 511) - $stat[7]) : '')); - unset($data); - } - - /** - * Open archive - */ - function open() - { - $fzopen = ($this->isbz && function_exists('bzopen')) ? 'bzopen' : (($this->isgz && @extension_loaded('zlib')) ? 'gzopen' : 'fopen'); - $this->fp = @$fzopen($this->file, $this->mode . (($fzopen == 'bzopen') ? '' : 'b') . (($fzopen == 'gzopen') ? '9' : '')); - - if (!$this->fp) - { - trigger_error('Unable to open file ' . $this->file . ' [' . $fzopen . ' - ' . $this->mode . 'b]'); - } - } - - /** - * Download archive - */ - function download($filename, $download_name = false) - { - global $phpbb_root_path; - - if ($download_name === false) - { - $download_name = $filename; - } - - switch ($this->type) - { - case '.tar': - $mimetype = 'application/x-tar'; - break; - - case '.tar.gz': - $mimetype = 'application/x-gzip'; - break; - - case '.tar.bz2': - $mimetype = 'application/x-bzip2'; - break; - - default: - $mimetype = 'application/octet-stream'; - break; - } - - header('Cache-Control: private, no-cache'); - header("Content-Type: $mimetype; name=\"$download_name$this->type\""); - header("Content-disposition: attachment; filename=$download_name$this->type"); - - $fp = @fopen("{$phpbb_root_path}store/$filename$this->type", 'rb'); - if ($fp) - { - while ($buffer = fread($fp, 1024)) - { - echo $buffer; - } - fclose($fp); - } - } -} diff --git a/install/update/old/includes/functions_content.php b/install/update/old/includes/functions_content.php deleted file mode 100644 index a15a03f..0000000 --- a/install/update/old/includes/functions_content.php +++ /dev/null @@ -1,1805 +0,0 @@ - -* @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; -} - -/** -* gen_sort_selects() -* make_jumpbox() -* bump_topic_allowed() -* get_context() -* phpbb_clean_search_string() -* decode_message() -* strip_bbcode() -* generate_text_for_display() -* generate_text_for_storage() -* generate_text_for_edit() -* make_clickable_callback() -* make_clickable() -* censor_text() -* bbcode_nl2br() -* smiley_text() -* parse_attachments() -* extension_allowed() -* truncate_string() -* get_username_string() -* class bitfield -*/ - -/** -* Generate sort selection fields -*/ -function 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, $def_st = false, $def_sk = false, $def_sd = false) -{ - global $user, $phpbb_dispatcher; - - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - $sorts = array( - 'st' => array( - 'key' => 'sort_days', - 'default' => $def_st, - 'options' => $limit_days, - 'output' => &$s_limit_days, - ), - - 'sk' => array( - 'key' => 'sort_key', - 'default' => $def_sk, - 'options' => $sort_by_text, - 'output' => &$s_sort_key, - ), - - 'sd' => array( - 'key' => 'sort_dir', - 'default' => $def_sd, - 'options' => $sort_dir_text, - 'output' => &$s_sort_dir, - ), - ); - $u_sort_param = ''; - - foreach ($sorts as $name => $sort_ary) - { - $key = $sort_ary['key']; - $selected = ${$sort_ary['key']}; - - // Check if the key is selectable. If not, we reset to the default or first key found. - // This ensures the values are always valid. We also set $sort_dir/sort_key/etc. to the - // correct value, else the protection is void. ;) - if (!isset($sort_ary['options'][$selected])) - { - if ($sort_ary['default'] !== false) - { - $selected = ${$key} = $sort_ary['default']; - } - else - { - @reset($sort_ary['options']); - $selected = ${$key} = key($sort_ary['options']); - } - } - - $sort_ary['output'] = ''; - - $u_sort_param .= ($selected !== $sort_ary['default']) ? ((strlen($u_sort_param)) ? '&' : '') . "{$name}={$selected}" : ''; - } - - /** - * Run code before generated sort selects are returned - * - * @event core.gen_sort_selects_after - * @var int limit_days Days limit - * @var array sort_by_text Sort by text options - * @var int sort_days Sort by days flag - * @var string sort_key Sort key - * @var string sort_dir Sort dir - * @var string s_limit_days String of days limit - * @var string s_sort_key String of sort key - * @var string s_sort_dir String of sort dir - * @var string u_sort_param Sort URL params - * @var bool def_st Default sort days - * @var bool def_sk Default sort key - * @var bool def_sd Default sort dir - * @var array sorts Sorts - * @since 3.1.9-RC1 - */ - $vars = array( - 'limit_days', - 'sort_by_text', - 'sort_days', - 'sort_key', - 'sort_dir', - 's_limit_days', - 's_sort_key', - 's_sort_dir', - 'u_sort_param', - 'def_st', - 'def_sk', - 'def_sd', - 'sorts', - ); - extract($phpbb_dispatcher->trigger_event('core.gen_sort_selects_after', compact($vars))); - - return; -} - -/** -* Generate Jumpbox -*/ -function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list = false, $force_display = false) -{ - global $config, $auth, $template, $user, $db, $phpbb_path_helper, $phpbb_dispatcher; - - // We only return if the jumpbox is not forced to be displayed (in case it is needed for functionality) - if (!$config['load_jumpbox'] && $force_display === false) - { - return; - } - - $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id - FROM ' . FORUMS_TABLE . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql, 600); - - $rowset = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[(int) $row['forum_id']] = $row; - } - $db->sql_freeresult($result); - - $right = $padding = 0; - $padding_store = array('0' => 0); - $display_jumpbox = false; - $iteration = 0; - - /** - * Modify the jumpbox forum list data - * - * @event core.make_jumpbox_modify_forum_list - * @var array rowset Array with the forums list data - * @since 3.1.10-RC1 - */ - $vars = array('rowset'); - extract($phpbb_dispatcher->trigger_event('core.make_jumpbox_modify_forum_list', compact($vars))); - - // Sometimes it could happen that forums will be displayed here not be displayed within the index page - // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions. - // If this happens, the padding could be "broken" - - foreach ($rowset as $row) - { - if ($row['left_id'] < $right) - { - $padding++; - $padding_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it. - // @todo digging deep to find out "how" this can happen. - $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding; - } - - $right = $row['right_id']; - - if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) - { - // Non-postable forum with no subforums, don't display - continue; - } - - if (!$auth->acl_get('f_list', $row['forum_id'])) - { - // if the user does not have permissions to list this forum skip - continue; - } - - if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id'])) - { - continue; - } - - $tpl_ary = array(); - if (!$display_jumpbox) - { - $tpl_ary[] = array( - 'FORUM_ID' => ($select_all) ? 0 : -1, - 'FORUM_NAME' => ($select_all) ? $user->lang['ALL_FORUMS'] : $user->lang['SELECT_FORUM'], - 'S_FORUM_COUNT' => $iteration, - 'LINK' => $phpbb_path_helper->append_url_params($action, array('f' => $forum_id)), - ); - - $iteration++; - $display_jumpbox = true; - } - - $tpl_ary[] = array( - 'FORUM_ID' => $row['forum_id'], - 'FORUM_NAME' => $row['forum_name'], - 'SELECTED' => ($row['forum_id'] == $forum_id) ? ' selected="selected"' : '', - 'S_FORUM_COUNT' => $iteration, - 'S_IS_CAT' => ($row['forum_type'] == FORUM_CAT) ? true : false, - 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK) ? true : false, - 'S_IS_POST' => ($row['forum_type'] == FORUM_POST) ? true : false, - 'LINK' => $phpbb_path_helper->append_url_params($action, array('f' => $row['forum_id'])), - ); - - /** - * Modify the jumpbox before it is assigned to the template - * - * @event core.make_jumpbox_modify_tpl_ary - * @var array row The data of the forum - * @var array tpl_ary Template data of the forum - * @since 3.1.10-RC1 - */ - $vars = array( - 'row', - 'tpl_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.make_jumpbox_modify_tpl_ary', compact($vars))); - - $template->assign_block_vars_array('jumpbox_forums', $tpl_ary); - - unset($tpl_ary); - - for ($i = 0; $i < $padding; $i++) - { - $template->assign_block_vars('jumpbox_forums.level', array()); - } - $iteration++; - } - unset($padding_store, $rowset); - - $url_parts = $phpbb_path_helper->get_url_parts($action); - - $template->assign_vars(array( - 'S_DISPLAY_JUMPBOX' => $display_jumpbox, - 'S_JUMPBOX_ACTION' => $action, - 'HIDDEN_FIELDS_FOR_JUMPBOX' => build_hidden_fields($url_parts['params']), - )); - - return; -} - -/** -* Bump Topic Check - used by posting and viewtopic -*/ -function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_poster, $last_topic_poster) -{ - global $config, $auth, $user; - - // Check permission and make sure the last post was not already bumped - if (!$auth->acl_get('f_bump', $forum_id) || $topic_bumped) - { - return false; - } - - // Check bump time range, is the user really allowed to bump the topic at this time? - $bump_time = ($config['bump_type'] == 'm') ? $config['bump_interval'] * 60 : (($config['bump_type'] == 'h') ? $config['bump_interval'] * 3600 : $config['bump_interval'] * 86400); - - // Check bump time - if ($last_post_time + $bump_time > time()) - { - return false; - } - - // Check bumper, only topic poster and last poster are allowed to bump - if ($topic_poster != $user->data['user_id'] && $last_topic_poster != $user->data['user_id']) - { - return false; - } - - // A bump time of 0 will completely disable the bump feature... not intended but might be useful. - return $bump_time; -} - -/** -* Generates a text with approx. the specified length which contains the specified words and their context -* -* @param string $text The full text from which context shall be extracted -* @param string $words An array of words which should be contained in the result, has to be a valid part of a PCRE pattern (escape with preg_quote!) -* @param int $length The desired length of the resulting text, however the result might be shorter or longer than this value -* -* @return string Context of the specified words separated by "..." -*/ -function get_context($text, $words, $length = 400) -{ - // first replace all whitespaces with single spaces - $text = preg_replace('/ +/', ' ', strtr($text, "\t\n\r\x0C ", ' ')); - - // we need to turn the entities back into their original form, to not cut the message in between them - $entities = array('<', '>', '[', ']', '.', ':', ':'); - $characters = array('<', '>', '[', ']', '.', ':', ':'); - $text = str_replace($entities, $characters, $text); - - $word_indizes = array(); - if (count($words)) - { - $match = ''; - // find the starting indizes of all words - foreach ($words as $word) - { - if ($word) - { - if (preg_match('#(?:[^\w]|^)(' . $word . ')(?:[^\w]|$)#i', $text, $match)) - { - if (empty($match[1])) - { - continue; - } - - $pos = utf8_strpos($text, $match[1]); - if ($pos !== false) - { - $word_indizes[] = $pos; - } - } - } - } - unset($match); - - if (count($word_indizes)) - { - $word_indizes = array_unique($word_indizes); - sort($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 = ''; - $word = $j = 0; - $final_text_index = -1; - - // cycle through every character in the original text - for ($i = $word_indizes[$word], $n = utf8_strlen($text); $i < $n; $i++) - { - // if the current position is the start of one of the words then append $sequence_length characters to the final text - if (isset($word_indizes[$word]) && ($i == $word_indizes[$word])) - { - if ($final_text_index < $i - $sequence_length - 1) - { - $final_text .= '... ' . preg_replace('#^([^ ]*)#', '', utf8_substr($text, $i - $sequence_length, $sequence_length)); - } - else - { - // if the final text is already nearer to the current word than $sequence_length we only append the text - // from its current index on and distribute the unused length to all other sequenes - $sequence_length += (int) (($final_text_index - $i + $sequence_length + 1) / (2 * $wordnum)); - $final_text .= utf8_substr($text, $final_text_index + 1, $i - $final_text_index - 1); - } - $final_text_index = $i - 1; - - // add the following characters to the final text (see below) - $word++; - $j = 1; - } - - if ($j > 0) - { - // add the character to the final text and increment the sequence counter - $final_text .= utf8_substr($text, $i, 1); - $final_text_index++; - $j++; - - // if this is a whitespace then check whether we are done with this sequence - if (utf8_substr($text, $i, 1) == ' ') - { - // only check whether we have to exit the context generation completely if we haven't already reached the end anyway - if ($i + 4 < $n) - { - if (($j > $sequence_length && $word >= $wordnum) || utf8_strlen($final_text) > $length) - { - $final_text .= ' ...'; - break; - } - } - else - { - // make sure the text really reaches the end - $j -= 4; - } - - // stop context generation and wait for the next word - if ($j > $sequence_length) - { - $j = 0; - } - } - } - } - return str_replace($characters, $entities, $final_text); - } - } - - if (!count($words) || !count($word_indizes)) - { - return str_replace($characters, $entities, ((utf8_strlen($text) >= $length + 3) ? utf8_substr($text, 0, $length) . '...' : $text)); - } -} - -/** -* Cleans a search string by removing single wildcards from it and replacing multiple spaces with a single one. -* -* @param string $search_string The full search string which should be cleaned. -* -* @return string The cleaned search string without any wildcards and multiple spaces. -*/ -function phpbb_clean_search_string($search_string) -{ - // This regular expressions matches every single wildcard. - // That means one after a whitespace or the beginning of the string or one before a whitespace or the end of the string. - $search_string = preg_replace('#(?<=^|\s)\*+(?=\s|$)#', '', $search_string); - $search_string = trim($search_string); - $search_string = preg_replace(array('#\s+#u', '#\*+#u'), array(' ', '*'), $search_string); - return $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 $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 - */ - $message_text = $message; - $vars = array('message_text', 'bbcode_uid'); - extract($phpbb_dispatcher->trigger_event('core.decode_message_before', compact($vars))); - $message = $message_text; - - if (preg_match('#^<[rt][ >]#', $message)) - { - $message = htmlspecialchars($phpbb_container->get('text_formatter.utils')->unparse($message), ENT_COMPAT); - } - else - { - if ($bbcode_uid) - { - $match = array('
', "[/*:m:$bbcode_uid]", ":u:$bbcode_uid", ":o:$bbcode_uid", ":$bbcode_uid"); - $replace = array("\n", '', '', '', ''); - } - else - { - $match = array('
'); - $replace = array("\n"); - } - - $message = str_replace($match, $replace, $message); - - $match = get_preg_expression('bbcode_htm'); - $replace = array('\1', '\1', '\2', '\2', '\1', '', ''); - - $message = preg_replace($match, $replace, $message); - } - - /** - * Use this event to modify the message after it is decoded - * - * @event core.decode_message_after - * @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_after', compact($vars))); - $message = $message_text; -} - -/** -* Strips all bbcode from a text in place -*/ -function strip_bbcode(&$text, $uid = '') -{ - global $phpbb_container; - - if (preg_match('#^<[rt][ >]#', $text)) - { - $text = $phpbb_container->get('text_formatter.utils')->clean_formatting($text); - } - else - { - if (!$uid) - { - $uid = '[0-9a-z]{5,}'; - } - - $text = preg_replace("#\[\/?[a-z0-9\*\+\-]+(?:=(?:".*"|[^\]]*))?(?::[a-z])?(\:$uid)\]#", ' ', $text); - - $match = get_preg_expression('bbcode_htm'); - $replace = array('\1', '\1', '\2', '\1', '', ''); - - $text = preg_replace($match, $replace, $text); - } -} - -/** -* For display of custom parsed text on user-facing pages -* Expects $text to be the value directly from the database (stored value) -*/ -function generate_text_for_display($text, $uid, $bitfield, $flags, $censor_text = true) -{ - static $bbcode; - global $auth, $config, $user; - global $phpbb_dispatcher, $phpbb_container; - - if ($text === '') - { - return ''; - } - - /** - * Use this event to modify the text before it is parsed - * - * @event core.modify_text_for_display_before - * @var string text The text to parse - * @var string uid The BBCode UID - * @var string bitfield The BBCode Bitfield - * @var int flags The BBCode Flags - * @var bool censor_text Whether or not to apply word censors - * @since 3.1.0-a1 - */ - $vars = array('text', 'uid', 'bitfield', 'flags', 'censor_text'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_display_before', compact($vars))); - - if (preg_match('#^<[rt][ >]#', $text)) - { - $renderer = $phpbb_container->get('text_formatter.renderer'); - - // 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')) - { - $censor_text = false; - } - - if ($old_censor !== $censor_text) - { - $renderer->set_viewcensors($censor_text); - } - - $text = $renderer->render($text); - - // Restore the previous value - if ($old_censor !== $censor_text) - { - $renderer->set_viewcensors($old_censor); - } - } - 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); - } - - $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 - * - * @event core.modify_text_for_display_after - * @var string text The text to parse - * @var string uid The BBCode UID - * @var string bitfield The BBCode Bitfield - * @var int flags The BBCode Flags - * @since 3.1.0-a1 - */ - $vars = array('text', 'uid', 'bitfield', 'flags'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_display_after', compact($vars))); - - return $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->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 -* @param string $bitfield The BBCode bitfield for this parse -* @param int $flags The allow_bbcode, allow_urls and allow_smilies compiled into a single integer. -* @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, $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; - - /** - * Use this event to modify the text before it is prepared for storage - * - * @event core.modify_text_for_storage_before - * @var string text The text to parse - * @var string uid The BBCode UID - * @var string bitfield The BBCode Bitfield - * @var int flags The BBCode Flags - * @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', - 'uid', - 'bitfield', - 'flags', - '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 (!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, $allow_img_bbcode, $allow_flash_bbcode, $allow_quote_bbcode, $allow_url_bbcode, true, $mode); - - $text = $message_parser->message; - $uid = $message_parser->bbcode_uid; - - // If the bbcode_bitfield is empty, there is no need for the uid to be stored. - if (!$message_parser->bbcode_bitfield) - { - $uid = ''; - } - - $bitfield = $message_parser->bbcode_bitfield; - - /** - * Use this event to modify the text after it is prepared for storage - * - * @event core.modify_text_for_storage_after - * @var string text The text to parse - * @var string uid The BBCode UID - * @var string bitfield The BBCode Bitfield - * @var int flags The BBCode Flags - * @var string message_parser The message_parser object - * @since 3.1.0-a1 - * @changed 3.1.11-RC1 Added message_parser to vars - */ - $vars = array('text', 'uid', 'bitfield', 'flags', 'message_parser'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_storage_after', compact($vars))); - - return $message_parser->warn_msg; -} - -/** -* For decoding custom parsed text for edits as well as extracting the flags -* Expects $text to be the value directly from the database (pre-parsed content) -*/ -function generate_text_for_edit($text, $uid, $flags) -{ - global $phpbb_dispatcher; - - /** - * Use this event to modify the text before it is decoded for editing - * - * @event core.modify_text_for_edit_before - * @var string text The text to parse - * @var string uid The BBCode UID - * @var int flags The BBCode Flags - * @since 3.1.0-a1 - */ - $vars = array('text', 'uid', 'flags'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_edit_before', compact($vars))); - - decode_message($text, $uid); - - /** - * Use this event to modify the text after it is decoded for editing - * - * @event core.modify_text_for_edit_after - * @var string text The text to parse - * @var int flags The BBCode Flags - * @since 3.1.0-a1 - */ - $vars = array('text', 'flags'); - extract($phpbb_dispatcher->trigger_event('core.modify_text_for_edit_after', compact($vars))); - - return array( - 'allow_bbcode' => ($flags & OPTION_FLAG_BBCODE) ? 1 : 0, - 'allow_smilies' => ($flags & OPTION_FLAG_SMILIES) ? 1 : 0, - 'allow_urls' => ($flags & OPTION_FLAG_LINKS) ? 1 : 0, - 'text' => $text - ); -} - -/** -* A subroutine of make_clickable used with preg_replace -* It places correct HTML around an url, shortens the displayed text -* and makes sure no entities are inside URLs -*/ -function make_clickable_callback($type, $whitespace, $url, $relative_url, $class) -{ - $orig_url = $url; - $orig_relative = $relative_url; - $append = ''; - $url = htmlspecialchars_decode($url); - $relative_url = htmlspecialchars_decode($relative_url); - - // make sure no HTML entities were matched - $chars = array('<', '>', '"'); - $split = false; - - foreach ($chars as $char) - { - $next_split = strpos($url, $char); - if ($next_split !== false) - { - $split = ($split !== false) ? min($split, $next_split) : $next_split; - } - } - - if ($split !== false) - { - // an HTML entity was found, so the URL has to end before it - $append = substr($url, $split) . $relative_url; - $url = substr($url, 0, $split); - $relative_url = ''; - } - else if ($relative_url) - { - // same for $relative_url - $split = false; - foreach ($chars as $char) - { - $next_split = strpos($relative_url, $char); - if ($next_split !== false) - { - $split = ($split !== false) ? min($split, $next_split) : $next_split; - } - } - - if ($split !== false) - { - $append = substr($relative_url, $split); - $relative_url = substr($relative_url, 0, $split); - } - } - - // if the last character of the url is a punctuation mark, exclude it from the url - $last_char = ($relative_url) ? $relative_url[strlen($relative_url) - 1] : $url[strlen($url) - 1]; - - switch ($last_char) - { - case '.': - case '?': - case '!': - case ':': - case ',': - $append = $last_char; - if ($relative_url) - { - $relative_url = substr($relative_url, 0, -1); - } - else - { - $url = substr($url, 0, -1); - } - break; - - // set last_char to empty here, so the variable can be used later to - // check whether a character was removed - default: - $last_char = ''; - break; - } - - $short_url = (utf8_strlen($url) > 55) ? utf8_substr($url, 0, 39) . ' ... ' . utf8_substr($url, -10) : $url; - - switch ($type) - { - case MAGIC_URL_LOCAL: - $tag = 'l'; - $relative_url = preg_replace('/[&?]sid=[0-9a-f]{32}$/', '', preg_replace('/([&?])sid=[0-9a-f]{32}&/', '$1', $relative_url)); - $url = $url . '/' . $relative_url; - $text = $relative_url; - - // this url goes to http://domain.tld/path/to/board/ which - // would result in an empty link if treated as local so - // don't touch it and let MAGIC_URL_FULL take care of it. - if (!$relative_url) - { - return $whitespace . $orig_url . '/' . $orig_relative; // slash is taken away by relative url pattern - } - break; - - case MAGIC_URL_FULL: - $tag = 'm'; - $text = $short_url; - break; - - case MAGIC_URL_WWW: - $tag = 'w'; - $url = 'http://' . $url; - $text = $short_url; - break; - - case MAGIC_URL_EMAIL: - $tag = 'e'; - $text = $short_url; - $url = 'mailto:' . $url; - break; - } - - $url = htmlspecialchars($url); - $text = htmlspecialchars($text); - $append = htmlspecialchars($append); - - $html = "$whitespace$text$append"; - - return $html; -} - -/** -* make_clickable function -* -* Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx. -* Cuts down displayed size of link if over 50 chars, turns absolute links -* into relative versions when the server/script path matches the link -*/ -function make_clickable($text, $server_url = false, $class = 'postlink') -{ - if ($server_url === false) - { - $server_url = generate_board_url(); - } - - static $static_class; - static $magic_url_match_args; - - if (!isset($magic_url_match_args[$server_url]) || $static_class != $class) - { - $static_class = $class; - $class = ($static_class) ? ' class="' . $static_class . '"' : ''; - $local_class = ($static_class) ? ' class="' . $static_class . '-local"' : ''; - - if (!is_array($magic_url_match_args)) - { - $magic_url_match_args = array(); - } - - // relative urls for this board - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>.])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#iu', - MAGIC_URL_LOCAL, - $local_class, - ); - - // matches a xxxx://aaaaa.bbb.cccc. ... - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>.])(' . get_preg_expression('url_inline') . ')#iu', - MAGIC_URL_FULL, - $class, - ); - - // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>])(' . get_preg_expression('www_url_inline') . ')#iu', - MAGIC_URL_WWW, - $class, - ); - - // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode. - $magic_url_match_args[$server_url][] = array( - '/(^|[\n\t (>])(' . get_preg_expression('email') . ')/iu', - MAGIC_URL_EMAIL, - '', - ); - } - - foreach ($magic_url_match_args[$server_url] as $magic_args) - { - if (preg_match($magic_args[0], $text, $matches)) - { - $text = preg_replace_callback($magic_args[0], function($matches) use ($magic_args) - { - $relative_url = isset($matches[3]) ? $matches[3] : ''; - return make_clickable_callback($magic_args[1], $matches[1], $matches[2], $relative_url, $magic_args[2]); - }, $text); - } - } - - return $text; -} - -/** -* Censoring -*/ -function censor_text($text) -{ - static $censors; - - // Nothing to do? - if ($text === '') - { - return ''; - } - - // We moved the word censor checks in here because we call this function quite often - and then only need to do the check once - if (!isset($censors) || !is_array($censors)) - { - global $config, $user, $auth, $cache; - - // We 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')) - { - $censors = array(); - } - else - { - $censors = $cache->obtain_word_list(); - } - } - - if (count($censors)) - { - return preg_replace($censors['match'], $censors['replace'], $text); - } - - return $text; -} - -/** -* custom version of nl2br which takes custom BBCodes into account -*/ -function bbcode_nl2br($text) -{ - // custom BBCodes might contain carriage returns so they - // are not converted into
so now revert that - $text = str_replace(array("\n", "\r"), array('
', "\n"), $text); - return $text; -} - -/** -* Smiley processing -*/ -function smiley_text($text, $force_option = false) -{ - global $config, $user, $phpbb_path_helper, $phpbb_dispatcher; - - if ($force_option || !$config['allow_smilies'] || !$user->optionget('viewsmilies')) - { - return preg_replace('##', ''; - } - } - - $filesize = get_formatted_filesize($attachment['filesize'], false); - - $comment = bbcode_nl2br(censor_text($attachment['attach_comment'])); - - $block_array += array( - 'UPLOAD_ICON' => $upload_icon, - 'FILESIZE' => $filesize['value'], - 'SIZE_LANG' => $filesize['unit'], - 'DOWNLOAD_NAME' => utf8_basename($attachment['real_filename']), - 'COMMENT' => $comment, - ); - - $denied = false; - - if (!extension_allowed($forum_id, $attachment['extension'], $extensions)) - { - $denied = true; - - $block_array += array( - 'S_DENIED' => true, - 'DENIED_MESSAGE' => sprintf($user->lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachment['extension']) - ); - } - - if (!$denied) - { - $display_cat = $extensions[$attachment['extension']]['display_cat']; - - if ($display_cat == ATTACHMENT_CATEGORY_IMAGE) - { - if ($attachment['thumbnail']) - { - $display_cat = ATTACHMENT_CATEGORY_THUMB; - } - else - { - if ($config['img_display_inlined']) - { - if ($config['img_link_width'] || $config['img_link_height']) - { - $dimension = @getimagesize($filename); - - // If the dimensions could not be determined or the image being 0x0 we display it as a link for safety purposes - if ($dimension === false || empty($dimension[0]) || empty($dimension[1])) - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - else - { - $display_cat = ($dimension[0] <= $config['img_link_width'] && $dimension[1] <= $config['img_link_height']) ? ATTACHMENT_CATEGORY_IMAGE : ATTACHMENT_CATEGORY_NONE; - } - } - } - else - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - } - } - - // Make some descisions based on user options being set. - if (($display_cat == ATTACHMENT_CATEGORY_IMAGE || $display_cat == ATTACHMENT_CATEGORY_THUMB) && !$user->optionget('viewimg')) - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - - if ($display_cat == ATTACHMENT_CATEGORY_FLASH && !$user->optionget('viewflash')) - { - $display_cat = ATTACHMENT_CATEGORY_NONE; - } - - $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id']); - $l_downloaded_viewed = 'VIEWED_COUNTS'; - - switch ($display_cat) - { - // Images - case ATTACHMENT_CATEGORY_IMAGE: - $inline_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id']); - $download_link .= '&mode=view'; - - $block_array += array( - 'S_IMAGE' => true, - 'U_INLINE_LINK' => $inline_link, - ); - - $update_count_ary[] = $attachment['attach_id']; - break; - - // Images, but display Thumbnail - case ATTACHMENT_CATEGORY_THUMB: - $thumbnail_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id'] . '&t=1'); - $download_link .= '&mode=view'; - - $block_array += array( - 'S_THUMBNAIL' => true, - 'THUMB_IMAGE' => $thumbnail_link, - ); - - $update_count_ary[] = $attachment['attach_id']; - break; - - // Macromedia Flash Files - case ATTACHMENT_CATEGORY_FLASH: - list($width, $height) = @getimagesize($filename); - - $block_array += array( - 'S_FLASH_FILE' => true, - 'WIDTH' => $width, - 'HEIGHT' => $height, - 'U_VIEW_LINK' => $download_link . '&view=1', - ); - - // Viewed/Heared File ... update the download count - $update_count_ary[] = $attachment['attach_id']; - break; - - default: - $l_downloaded_viewed = 'DOWNLOAD_COUNTS'; - - $block_array += array( - 'S_FILE' => true, - ); - break; - } - - if (!isset($attachment['download_count'])) - { - $attachment['download_count'] = 0; - } - - $block_array += array( - 'U_DOWNLOAD_LINK' => $download_link, - 'L_DOWNLOAD_COUNT' => $user->lang($l_downloaded_viewed, (int) $attachment['download_count']), - ); - } - - $update_count = $update_count_ary; - /** - * Use this event to modify the attachment template data. - * - * This event is triggered once per attachment. - * - * @event core.parse_attachments_modify_template_data - * @var array attachment Array with attachment data - * @var array block_array Template data of the attachment - * @var int display_cat Attachment category data - * @var string download_link Attachment download link - * @var array extensions Array with attachment extensions data - * @var mixed forum_id The forum id the attachments are displayed in (false if in private message) - * @var bool preview Flag indicating if we are in post preview mode - * @var array update_count Array with attachment ids to update download count - * @since 3.1.0-RC5 - */ - $vars = array( - 'attachment', - 'block_array', - 'display_cat', - 'download_link', - 'extensions', - 'forum_id', - 'preview', - '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); - - $compiled_attachments[] = $template->assign_display('attachment_tpl'); - } - - $attachments = $compiled_attachments; - unset($compiled_attachments); - - $unset_tpl = array(); - - preg_match_all('#(.*?)#', $message, $matches, PREG_PATTERN_ORDER); - - $replace = array(); - foreach ($matches[0] as $num => $capture) - { - $index = $matches[1][$num]; - - $replace['from'][] = $matches[0][$num]; - $replace['to'][] = (isset($attachments[$index])) ? $attachments[$index] : sprintf($user->lang['MISSING_INLINE_ATTACHMENT'], $matches[2][array_search($index, $matches[1])]); - - $unset_tpl[] = $index; - } - - if (isset($replace['from'])) - { - $message = str_replace($replace['from'], $replace['to'], $message); - } - - $unset_tpl = array_unique($unset_tpl); - - // Sort correctly - if ($config['display_order']) - { - // Ascending sort - krsort($attachments); - } - else - { - // Descending sort - ksort($attachments); - } - - // Needed to let not display the inlined attachments at the end of the post again - foreach ($unset_tpl as $index) - { - unset($attachments[$index]); - } -} - -/** -* Check if extension is allowed to be posted. -* -* @param mixed $forum_id The forum id to check or false if private message -* @param string $extension The extension to check, for example zip. -* @param array &$extensions The extension array holding the information from the cache (will be obtained if empty) -* -* @return bool False if the extension is not allowed to be posted, else true. -*/ -function extension_allowed($forum_id, $extension, &$extensions) -{ - if (empty($extensions)) - { - global $cache; - $extensions = $cache->obtain_attach_extensions($forum_id); - } - - return (!isset($extensions['_allowed_'][$extension])) ? false : true; -} - -/** -* Truncates string while retaining special characters if going over the max length -* The default max length is 60 at the moment -* The maximum storage length is there to fit the string within the given length. The string may be further truncated due to html entities. -* For example: string given is 'a "quote"' (length: 9), would be a stored as 'a "quote"' (length: 19) -* -* @param string $string The text to truncate to the given length. String is specialchared. -* @param int $max_length Maximum length of string (multibyte character count as 1 char / Html entity count as 1 char) -* @param int $max_store_length Maximum character length of string (multibyte character count as 1 char / Html entity count as entity chars). -* @param bool $allow_reply Allow Re: in front of string -* NOTE: This parameter can cause undesired behavior (returning strings longer than $max_store_length) and is deprecated. -* @param string $append String to be appended -*/ -function truncate_string($string, $max_length = 60, $max_store_length = 255, $allow_reply = false, $append = '') -{ - $strip_reply = false; - $stripped = false; - if ($allow_reply && strpos($string, 'Re: ') === 0) - { - $strip_reply = true; - $string = substr($string, 4); - } - - $_chars = utf8_str_split(htmlspecialchars_decode($string)); - $chars = array_map('utf8_htmlspecialchars', $_chars); - - // Now check the 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))); - $stripped = true; - } - - // Due to specialchars, we may not be able to store the string... - if (utf8_strlen($string) > $max_store_length) - { - // let's split again, we do not want half-baked strings where entities are split - $_chars = utf8_str_split(htmlspecialchars_decode($string)); - $chars = array_map('utf8_htmlspecialchars', $_chars); - - do - { - array_pop($chars); - $string = implode('', $chars); - } - while (!empty($chars) && utf8_strlen($string) > $max_store_length); - } - - if ($strip_reply) - { - $string = 'Re: ' . $string; - } - - if ($append != '' && $stripped) - { - $string = $string . $append; - } - - return $string; -} - -/** -* 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. -* -* @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 -* @param string $username_colour The users colour -* @param string $guest_username optional parameter to specify the guest username. It will be used in favor of the GUEST language variable then. -* @param string $custom_profile_url optional parameter to specify a profile url. The user id get appended to this url as &u={user_id} -* -* @return string A string consisting of what is wanted based on $mode. -*/ -function get_username_string($mode, $user_id, $username, $username_colour = '', $guest_username = false, $custom_profile_url = false) -{ - static $_profile_cache; - global $phpbb_dispatcher; - - // We cache some common variables we need within this function - if (empty($_profile_cache)) - { - global $phpbb_root_path, $phpEx; - - $_profile_cache['base_url'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u={USER_ID}'); - $_profile_cache['tpl_noprofile'] = '{USERNAME}'; - $_profile_cache['tpl_noprofile_colour'] = '{USERNAME}'; - $_profile_cache['tpl_profile'] = '{USERNAME}'; - $_profile_cache['tpl_profile_colour'] = '{USERNAME}'; - } - - global $user, $auth; - - // This switch makes sure we only run code required for the mode - switch ($mode) - { - case 'full': - case 'no_profile': - case 'colour': - - // Build correct username colour - $username_colour = ($username_colour) ? '#' . $username_colour : ''; - - // Return colour - if ($mode == 'colour') - { - $username_string = $username_colour; - break; - } - - // no break; - - case 'username': - - // Build correct username - if ($guest_username === false) - { - $username = ($username) ? $username : $user->lang['GUEST']; - } - else - { - $username = ($user_id && $user_id != ANONYMOUS) ? $username : ((!empty($guest_username)) ? $guest_username : $user->lang['GUEST']); - } - - // Return username - if ($mode == 'username') - { - $username_string = $username; - 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 ($user_id && $user_id != ANONYMOUS && ($user->data['user_id'] == ANONYMOUS || $auth->acl_get('u_viewprofile'))) - { - $profile_url = ($custom_profile_url !== false) ? $custom_profile_url . '&u=' . (int) $user_id : str_replace(array('={USER_ID}', '=%7BUSER_ID%7D'), '=' . (int) $user_id, $_profile_cache['base_url']); - } - else - { - $profile_url = ''; - } - - // Return profile - if ($mode == 'profile') - { - $username_string = $profile_url; - break; - } - - // no break; - } - - if (!isset($username_string)) - { - if (($mode == 'full' && !$profile_url) || $mode == 'no_profile') - { - $username_string = str_replace(array('{USERNAME_COLOUR}', '{USERNAME}'), array($username_colour, $username), (!$username_colour) ? $_profile_cache['tpl_noprofile'] : $_profile_cache['tpl_noprofile_colour']); - } - else - { - $username_string = str_replace(array('{PROFILE_URL}', '{USERNAME_COLOUR}', '{USERNAME}'), array($profile_url, $username_colour, $username), (!$username_colour) ? $_profile_cache['tpl_profile'] : $_profile_cache['tpl_profile_colour']); - } - } - - /** - * Use this event to change the output of get_username_string() - * - * @event core.modify_username_string - * @var string mode profile|username|colour|full|no_profile - * @var int user_id String or array of additional url - * parameters - * @var string username The user's username - * @var string username_colour The user's colour - * @var string guest_username Optional parameter to specify the - * guest username. - * @var string custom_profile_url Optional parameter to specify a - * profile url. - * @var string username_string The string that has been generated - * @var array _profile_cache Array of original return templates - * @since 3.1.0-a1 - */ - $vars = array( - 'mode', - 'user_id', - 'username', - 'username_colour', - 'guest_username', - 'custom_profile_url', - 'username_string', - '_profile_cache', - ); - extract($phpbb_dispatcher->trigger_event('core.modify_username_string', compact($vars))); - - return $username_string; -} - -/** - * Add an option to the quick-mod tools. - * - * @param string $url The recepting URL for the quickmod actions. - * @param string $option The language key for the value of the option. - * @param string $lang_string The language string to use. - */ -function phpbb_add_quickmod_option($url, $option, $lang_string) -{ - global $template, $user, $phpbb_path_helper; - - $lang_string = $user->lang($lang_string); - $template->assign_block_vars('quickmod', array( - 'VALUE' => $option, - 'TITLE' => $lang_string, - 'LINK' => $phpbb_path_helper->append_url_params($url, array('action' => $option)), - )); -} - -/** -* Concatenate an array into a string list. -* -* @param array $items Array of items to concatenate -* @param object $user The phpBB $user object. -* -* @return string String list. Examples: "A"; "A and B"; "A, B, and C" -*/ -function phpbb_generate_string_list($items, $user) -{ - if (empty($items)) - { - return ''; - } - - $count = count($items); - $last_item = array_pop($items); - $lang_key = 'STRING_LIST_MULTI'; - - if ($count == 1) - { - return $last_item; - } - else if ($count == 2) - { - $lang_key = 'STRING_LIST_SIMPLE'; - } - $list = implode($user->lang['COMMA_SEPARATOR'], $items); - - return $user->lang($lang_key, $list, $last_item); -} - -class bitfield -{ - var $data; - - function __construct($bitfield = '') - { - $this->data = base64_decode($bitfield); - } - - /** - */ - function get($n) - { - // Get the ($n / 8)th char - $byte = $n >> 3; - - if (strlen($this->data) >= $byte + 1) - { - $c = $this->data[$byte]; - - // Lookup the ($n % 8)th bit of the byte - $bit = 7 - ($n & 7); - return (bool) (ord($c) & (1 << $bit)); - } - else - { - return false; - } - } - - function set($n) - { - $byte = $n >> 3; - $bit = 7 - ($n & 7); - - if (strlen($this->data) >= $byte + 1) - { - $this->data[$byte] = $this->data[$byte] | chr(1 << $bit); - } - else - { - $this->data .= str_repeat("\0", $byte - strlen($this->data)); - $this->data .= chr(1 << $bit); - } - } - - function clear($n) - { - $byte = $n >> 3; - - if (strlen($this->data) >= $byte + 1) - { - $bit = 7 - ($n & 7); - $this->data[$byte] = $this->data[$byte] &~ chr(1 << $bit); - } - } - - function get_blob() - { - return $this->data; - } - - function get_base64() - { - return base64_encode($this->data); - } - - function get_bin() - { - $bin = ''; - $len = strlen($this->data); - - for ($i = 0; $i < $len; ++$i) - { - $bin .= str_pad(decbin(ord($this->data[$i])), 8, '0', STR_PAD_LEFT); - } - - return $bin; - } - - function get_all_set() - { - return array_keys(array_filter(str_split($this->get_bin()))); - } - - function merge($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 = "> "; - $message = censor_text(trim($message_parser->message)); - // see if we are nesting. It's easily tricked but should work for one level of nesting - if (strpos($message, ">") !== false) - { - $offset = 10; - } - $message = utf8_wordwrap($message, 75 + $offset, "\n"); - - $message = $quote_string . $message; - $message = str_replace("\n", "\n" . $quote_string, $message); - - $message_parser->message = $quote_attributes['author'] . " " . $language->lang('WROTE') . ":\n" . $message . "\n"; - } - - if ($message_link) - { - $message_parser->message = $message_link . $message_parser->message; - } -} diff --git a/install/update/old/includes/functions_convert.php b/install/update/old/includes/functions_convert.php deleted file mode 100644 index 2cfbe95..0000000 --- a/install/update/old/includes/functions_convert.php +++ /dev/null @@ -1,2514 +0,0 @@ - -* @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; -} - -/** -* Default avatar width/height -* @ignore -*/ -define('DEFAULT_AVATAR_X', 80); -define('DEFAULT_AVATAR_Y', 80); - -// Global functions - all functions can be used by convertors - -// SIMPLE FUNCTIONS - -/** -* Return the preceding value -*/ -function dec($var) -{ - return --$var; -} - -/** -* Return the next value -*/ -function inc($var) -{ - return ++$var; -} - -/** -* Return whether the value is positive -*/ -function is_positive($n) -{ - return ($n > 0) ? 1 : 0; -} - -/** -* Boolean inverse of the value -*/ -function not($var) -{ - return ($var) ? 0 : 1; -} - -/** -* Convert a textual value to it's equivalent boolean value -* -* @param string $str String to convert (converts yes, on, y, 1 and true to boolean true) -* @return boolean The equivalent value -*/ -function str_to_bool($str) -{ - $str = strtolower($str); - return ($str == 'yes' || $str == 'on' || $str == 'y' || $str == 'true' || $str == '1') ? true : false; -} - -/** -* Function to mimic php's empty() function (it is the same) -*/ -function is_empty($mixed) -{ - return empty($mixed); -} - -/** -* Convert the name of a user's primary group to the appropriate equivalent phpBB group id -* -* @param string $status The name of the group -* @return int The group_id corresponding to the equivalent group -*/ -function str_to_primary_group($status) -{ - switch (ucfirst(strtolower($status))) - { - case 'Administrator': - return get_group_id('administrators'); - break; - - case 'Super moderator': - case 'Global moderator': - case 'Moderator': - return get_group_id('global_moderators'); - break; - - case 'Guest': - case 'Anonymous': - return get_group_id('guests'); - break; - - default: - return get_group_id('registered'); - break; - } -} - -/** -* Convert a boolean into the appropriate phpBB constant indicating whether the item is locked -*/ -function is_item_locked($bool) -{ - return ($bool) ? ITEM_LOCKED : ITEM_UNLOCKED; -} - -/** -* Convert a value from days to seconds -*/ -function days_to_seconds($days) -{ - return ($days * 86400); -} - -/** -* Determine whether a user is anonymous and return the appropriate new user_id -*/ -function is_user_anonymous($user_id) -{ - return ($user_id > ANONYMOUS) ? $user_id : ANONYMOUS; -} - -/** -* Generate a key value based on existing values -* -* @param int $pad Amount to add to the maximum value -* @return int Key value -*/ -function auto_id($pad = 0) -{ - global $auto_id, $convert_row; - - if (!empty($convert_row['max_id'])) - { - return $convert_row['max_id'] + $pad; - } - - return $auto_id + $pad; -} - -/** -* Convert a boolean into the appropriate phpBB constant indicating whether the user is active -*/ -function set_user_type($user_active) -{ - return ($user_active) ? USER_NORMAL : USER_INACTIVE; -} - -/** -* Convert a value from minutes to hours -*/ -function minutes_to_hours($minutes) -{ - return ($minutes / 3600); -} - -/** -* Return the group_id for a given group name -*/ -function get_group_id($group_name) -{ - global $db, $group_mapping; - - if (empty($group_mapping)) - { - $sql = 'SELECT group_name, group_id - FROM ' . GROUPS_TABLE; - $result = $db->sql_query($sql); - - $group_mapping = array(); - while ($row = $db->sql_fetchrow($result)) - { - $group_mapping[strtoupper($row['group_name'])] = (int) $row['group_id']; - } - $db->sql_freeresult($result); - } - - if (!count($group_mapping)) - { - add_default_groups(); - return get_group_id($group_name); - } - - if (isset($group_mapping[strtoupper($group_name)])) - { - return $group_mapping[strtoupper($group_name)]; - } - - return $group_mapping['REGISTERED']; -} - -/** -* Generate the email hash stored in the users table -* -* Note: Deprecated, calls should directly go to phpbb_email_hash() -*/ -function gen_email_hash($email) -{ - return phpbb_email_hash($email); -} - -/** -* Convert a boolean into the appropriate phpBB constant indicating whether the topic is locked -*/ -function is_topic_locked($bool) -{ - return (!empty($bool)) ? ITEM_LOCKED : ITEM_UNLOCKED; -} - -/** -* Generate a bbcode_uid value -*/ -function make_uid($timestamp) -{ - static $last_timestamp, $last_uid; - - if (empty($last_timestamp) || $timestamp != $last_timestamp) - { - $last_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN); - } - $last_timestamp = $timestamp; - return $last_uid; -} - - -/** -* Validate a website address -*/ -function validate_website($url) -{ - if ($url === 'http://') - { - return ''; - } - else if (!preg_match('#^http[s]?://#i', $url) && strlen($url) > 0) - { - return 'http://' . $url; - } - return $url; -} - -/** -* Convert nulls to zeros for fields which allowed a NULL value in the source but not the destination -*/ -function null_to_zero($value) -{ - return ($value === NULL) ? 0 : $value; -} - -/** -* Convert nulls to empty strings for fields which allowed a NULL value in the source but not the destination -*/ -function null_to_str($value) -{ - return ($value === NULL) ? '' : $value; -} - -// EXTENDED FUNCTIONS - -/** -* Get old config value -*/ -function get_config_value($config_name) -{ - static $convert_config; - - if (!isset($convert_config)) - { - $convert_config = get_config(); - } - - if (!isset($convert_config[$config_name])) - { - return false; - } - - return (empty($convert_config[$config_name])) ? '' : $convert_config[$config_name]; -} - -/** -* Convert an IP address from the hexadecimal notation to normal dotted-quad notation -*/ -function decode_ip($int_ip) -{ - if (!$int_ip) - { - return $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 (count($hexipbang) < 4) - { - return $int_ip; - } - - return hexdec($hexipbang[0]) . '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]); -} - -/** -* Reverse the encoding of wild-carded bans -*/ -function decode_ban_ip($int_ip) -{ - return str_replace('255', '*', decode_ip($int_ip)); -} - -/** -* Determine the MIME-type of a specified filename -* This does not actually inspect the file, but simply uses the file extension -*/ -function mimetype($filename) -{ - if (!preg_match('/\.([a-z0-9]+)$/i', $filename, $m)) - { - return 'application/octet-stream'; - } - - switch (strtolower($m[1])) - { - case 'zip': return 'application/zip'; - case 'jpeg': return 'image/jpeg'; - case 'jpg': return 'image/jpeg'; - case 'jpe': return 'image/jpeg'; - case 'png': return 'image/png'; - case 'gif': return 'image/gif'; - case 'htm': - case 'html': return 'text/html'; - case 'tif': return 'image/tiff'; - case 'tiff': return 'image/tiff'; - case 'ras': return 'image/x-cmu-raster'; - case 'pnm': return 'image/x-portable-anymap'; - case 'pbm': return 'image/x-portable-bitmap'; - case 'pgm': return 'image/x-portable-graymap'; - case 'ppm': return 'image/x-portable-pixmap'; - case 'rgb': return 'image/x-rgb'; - case 'xbm': return 'image/x-xbitmap'; - case 'xpm': return 'image/x-xpixmap'; - case 'xwd': return 'image/x-xwindowdump'; - case 'z': return 'application/x-compress'; - case 'gtar': return 'application/x-gtar'; - case 'tgz': return 'application/x-gtar'; - case 'gz': return 'application/x-gzip'; - case 'tar': return 'application/x-tar'; - case 'xls': return 'application/excel'; - case 'pdf': return 'application/pdf'; - case 'ppt': return 'application/powerpoint'; - case 'rm': return 'application/vnd.rn-realmedia'; - case 'wma': return 'audio/x-ms-wma'; - case 'swf': return 'application/x-shockwave-flash'; - case 'ief': return 'image/ief'; - case 'doc': - case 'dot': - case 'wrd': return 'application/msword'; - case 'ai': - case 'eps': - case 'ps': return 'application/postscript'; - case 'asc': - case 'txt': - case 'c': - case 'cc': - case 'h': - case 'hh': - case 'cpp': - case 'hpp': - case 'php': - case 'php3': return 'text/plain'; - default: return 'application/octet-stream'; - } -} - -/** -* Obtain the dimensions of all remotely hosted avatars -* This should only be called from execute_last -* There can be significant network overhead if there are a large number of remote avatars -* @todo Look at the option of allowing the user to decide whether this is called or to force the dimensions -*/ -function remote_avatar_dims() -{ - global $db; - - $sql = 'SELECT user_id, user_avatar - FROM ' . USERS_TABLE . ' - WHERE user_avatar_type = ' . AVATAR_REMOTE; - $result = $db->sql_query($sql); - - $remote_avatars = array(); - while ($row = $db->sql_fetchrow($result)) - { - $remote_avatars[(int) $row['user_id']] = $row['user_avatar']; - } - $db->sql_freeresult($result); - - foreach ($remote_avatars as $user_id => $avatar) - { - $width = (int) get_remote_avatar_dim($avatar, 0); - $height = (int) get_remote_avatar_dim($avatar, 1); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_avatar_width = ' . (int) $width . ', user_avatar_height = ' . (int) $height . ' - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - } -} - -function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false) -{ - global $config, $convert, $user; - - $relative_path = empty($convert->convertor['source_path_absolute']); - - // check for trailing slash - if (rtrim($convert->convertor['avatar_gallery_path'], '/') === '') - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'import_avatar_gallery()'), __LINE__, __FILE__); - } - - $src_path = relative_base(path($convert->convertor['avatar_gallery_path'], $relative_path), $relative_path); - - if (is_dir($src_path)) - { - // Do not die on failure... safe mode restrictions may be in effect. - copy_dir($convert->convertor['avatar_gallery_path'], path($config['avatar_gallery_path']) . $gallery_name, !$subdirs_as_galleries, false, false, $relative_path); - - // only doing 1 level deep. (ibf 1.x) - // notes: ibf has 2 tiers: directly in the avatar directory for base gallery (handled in the above statement), plus subdirs(handled below). - // recursive subdirs ignored. -- i don't know if other forums support recursive galleries. if they do, this following code could be upgraded to be recursive. - if ($subdirs_as_galleries) - { - $dirlist = array(); - if ($handle = @opendir($src_path)) - { - while ($entry = readdir($handle)) - { - if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm') - { - continue; - } - - if (is_dir($src_path . $entry)) - { - $dirlist[] = $entry; - } - } - closedir($handle); - } - else if ($dir = @dir($src_path)) - { - while ($entry = $dir->read()) - { - if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm') - { - continue; - } - - if (is_dir($src_path . $entry)) - { - $dirlist[] = $entry; - } - } - $dir->close(); - } - - for ($i = 0, $end = count($dirlist); $i < $end; ++$i) - { - $dir = $dirlist[$i]; - - // Do not die on failure... safe mode restrictions may be in effect. - copy_dir(path($convert->convertor['avatar_gallery_path'], $relative_path) . $dir, path($config['avatar_gallery_path']) . $dir, true, false, false, $relative_path); - } - } - } -} - -function import_attachment_files($category_name = '') -{ - global $config, $convert, $db, $user; - - $sql = 'SELECT config_value AS upload_path - FROM ' . CONFIG_TABLE . " - WHERE config_name = 'upload_path'"; - $result = $db->sql_query($sql); - $config['upload_path'] = $db->sql_fetchfield('upload_path'); - $db->sql_freeresult($result); - - $relative_path = empty($convert->convertor['source_path_absolute']); - - if (empty($convert->convertor['upload_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment_files()'), __LINE__, __FILE__); - } - - if (is_dir(relative_base(path($convert->convertor['upload_path'], $relative_path), $relative_path))) - { - copy_dir($convert->convertor['upload_path'], path($config['upload_path']) . $category_name, true, false, true, $relative_path); - } -} - -function attachment_forum_perms($forum_id) -{ - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - return serialize($forum_id); -} - -// base64todec function -// -> from php manual? -function base64_unpack($string) -{ - $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-'; - $base = strlen($chars); - - $length = strlen($string); - $number = 0; - - for ($i = 1; $i <= $length; $i++) - { - $pos = $length - $i; - $operand = strpos($chars, substr($string, $pos, 1)); - $exponent = pow($base, $i-1); - $dec_value = $operand * $exponent; - $number += $dec_value; - } - - return $number; -} - -function _import_check($config_var, $source, $use_target) -{ - global $convert, $config; - - $result = array( - 'orig_source' => $source, - 'copied' => false, - 'relative_path' => (empty($convert->convertor['source_path_absolute'])) ? true : false, - ); - - // copy file will prepend $phpBB_root_path - $target = $config[$config_var] . '/' . utf8_basename(($use_target === false) ? $source : $use_target); - - if (!empty($convert->convertor[$config_var]) && strpos($source, $convert->convertor[$config_var]) !== 0) - { - $source = $convert->convertor[$config_var] . $source; - } - - $result['source'] = $source; - - if (file_exists(relative_base($source, $result['relative_path'], __LINE__, __FILE__))) - { - $result['copied'] = copy_file($source, $target, false, false, $result['relative_path']); - } - - if ($result['copied']) - { - $result['target'] = utf8_basename($target); - } - else - { - $result['target'] = ($use_target !== false) ? $result['orig_source'] : utf8_basename($target); - } - - return $result; -} - -function import_attachment($source, $use_target = false) -{ - if (empty($source)) - { - return ''; - } - - global $convert, $config, $user; - - // check for trailing slash - if (rtrim($convert->convertor['upload_path'], '/') === '') - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_UPLOAD_DIR'], 'import_attachment()'), __LINE__, __FILE__); - } - - $result = _import_check('upload_path', $source, $use_target); - - if ($result['copied']) - { - // Thumbnails? - if (is_array($convert->convertor['thumbnails'])) - { - $thumb_dir = $convert->convertor['thumbnails'][0]; - $thumb_prefix = $convert->convertor['thumbnails'][1]; - $thumb_source = $thumb_dir . $thumb_prefix . utf8_basename($result['source']); - - if (strpos($thumb_source, $convert->convertor['upload_path']) !== 0) - { - $thumb_source = $convert->convertor['upload_path'] . $thumb_source; - } - $thumb_target = $config['upload_path'] . '/thumb_' . $result['target']; - - if (file_exists(relative_base($thumb_source, $result['relative_path'], __LINE__, __FILE__))) - { - copy_file($thumb_source, $thumb_target, false, false, $result['relative_path']); - } - } - } - - return $result['target']; -} - -function import_rank($source, $use_target = false) -{ - if (empty($source)) - { - return ''; - } - - global $convert, $user; - - if (!isset($convert->convertor['ranks_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_RANKS_PATH'], 'import_rank()'), __LINE__, __FILE__); - } - - $result = _import_check('ranks_path', $source, $use_target); - return $result['target']; -} - -function import_smiley($source, $use_target = false) -{ - if (empty($source)) - { - return ''; - } - - global $convert, $user; - - // check for trailing slash - if (rtrim($convert->convertor['smilies_path'], '/') === '') - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'import_smiley()'), __LINE__, __FILE__); - } - - $result = _import_check('smilies_path', $source, $use_target); - return $result['target']; -} - -/* -*/ -function import_avatar($source, $use_target = false, $user_id = false) -{ - if (empty($source) || preg_match('#^https?:#i', $source) || preg_match('#blank\.(gif|png)$#i', $source)) - { - return; - } - - global $convert, $config, $user; - - // check for trailing slash - if (rtrim($convert->convertor['avatar_path'], '/') === '') - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'import_avatar()'), __LINE__, __FILE__); - } - - if ($use_target === false && $user_id !== false) - { - $use_target = $config['avatar_salt'] . '_' . $user_id . '.' . substr(strrchr($source, '.'), 1); - } - - _import_check('avatar_path', $source, $use_target); - - return ((!empty($user_id)) ? $user_id : $use_target) . '.' . substr(strrchr($source, '.'), 1); -} - -/** -* @todo all image dimension functions below (there are a *lot*) should get revisited and converted to one or two functions (no more needed, really). -*/ - -/** -* Calculate the size of the specified image -* Called from the following functions for calculating the size of specific image types -*/ -function get_image_dim($source) -{ - if (empty($source)) - { - return array(0, 0); - } - - global $convert; - - $relative_path = empty($convert->convertor['source_path_absolute']); - - if (file_exists(relative_base($source, $relative_path))) - { - $image = relative_base($source, $relative_path); - return @getimagesize($image); - } - - return false; -} - -/** -* Obtain the width of the specified smilie -*/ -function get_smiley_width($src) -{ - return get_smiley_dim($src, 0); -} - -/** -* Obtain the height of the specified smilie -*/ -function get_smiley_height($src) -{ - return get_smiley_dim($src, 1); -} - -/** -* Obtain the size of the specified smilie (using the cache if possible) and cache the value -*/ -function get_smiley_dim($source, $axis) -{ - if (empty($source)) - { - return 15; - } - - static $smiley_cache = array(); - - if (isset($smiley_cache[$source])) - { - return $smiley_cache[$source][$axis]; - } - - global $convert, $user; - - $orig_source = $source; - - if (!isset($convert->convertor['smilies_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_SMILIES_PATH'], 'get_smiley_dim()'), __LINE__, __FILE__); - } - - if (!empty($convert->convertor['smilies_path']) && strpos($source, $convert->convertor['smilies_path']) !== 0) - { - $source = $convert->convertor['smilies_path'] . $source; - } - - $smiley_cache[$orig_source] = get_image_dim($source); - - if (empty($smiley_cache[$orig_source]) || empty($smiley_cache[$orig_source][0]) || empty($smiley_cache[$orig_source][1])) - { - $smiley_cache[$orig_source] = array(15, 15); - return 15; - } - - return $smiley_cache[$orig_source][$axis]; -} - -/** -* Obtain the width of the specified avatar -*/ -function get_avatar_width($src, $func = false, $arg1 = false, $arg2 = false) -{ - return get_avatar_dim($src, 0, $func, $arg1, $arg2); -} - -/** -* Obtain the height of the specified avatar -*/ -function get_avatar_height($src, $func = false, $arg1 = false, $arg2 = false) -{ - return get_avatar_dim($src, 1, $func, $arg1, $arg2); -} - -/** -*/ -function get_avatar_dim($src, $axis, $func = false, $arg1 = false, $arg2 = false) -{ - $avatar_type = AVATAR_UPLOAD; - - if ($func) - { - if ($arg1 || $arg2) - { - $ary = array($arg1); - - if ($arg2) - { - $ary[] = $arg2; - } - - $avatar_type = call_user_func_array($func, $ary); - } - else - { - $avatar_type = call_user_func($func); - } - } - - switch ($avatar_type) - { - case AVATAR_UPLOAD: - return get_upload_avatar_dim($src, $axis); - break; - - case AVATAR_GALLERY: - return get_gallery_avatar_dim($src, $axis); - break; - - case AVATAR_REMOTE: - // see notes on this functions usage and (hopefully) model $func to avoid this accordingly - return get_remote_avatar_dim($src, $axis); - break; - - default: - $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X; - $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y; - - return $axis ? $default_y : $default_x; - break; - } -} - -/** -* Obtain the size of the specified uploaded avatar (using the cache if possible) and cache the value -*/ -function get_upload_avatar_dim($source, $axis) -{ - static $cachedims = false; - static $cachekey = false; - - if (empty($source)) - { - return 0; - } - - if ($cachekey == $source) - { - return $cachedims[$axis]; - } - - if (substr($source, 0, 7) == 'upload:') - { - $source = substr($source, 7); - } - - global $convert, $user; - - if (!isset($convert->convertor['avatar_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_AVATAR_PATH'], 'get_upload_avatar_dim()'), __LINE__, __FILE__); - } - - if (!empty($convert->convertor['avatar_path']) && strpos($source, $convert->convertor['avatar_path']) !== 0) - { - $source = path($convert->convertor['avatar_path'], empty($convert->convertor['source_path_absolute'])) . $source; - } - - $cachedims = get_image_dim($source); - - if (empty($cachedims) || empty($cachedims[0]) || empty($cachedims[1])) - { - $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X; - $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y; - - $cachedims = array($default_x, $default_y); - } - - return $cachedims[$axis]; -} - -/** -* Obtain the size of the specified gallery avatar (using the cache if possible) and cache the value -*/ -function get_gallery_avatar_dim($source, $axis) -{ - if (empty($source)) - { - return 0; - } - - static $avatar_cache = array(); - - if (isset($avatar_cache[$source])) - { - return $avatar_cache[$source][$axis]; - } - - global $convert, $user; - - $orig_source = $source; - - if (!isset($convert->convertor['avatar_gallery_path'])) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GALLERY_PATH'], 'get_gallery_avatar_dim()'), __LINE__, __FILE__); - } - - if (!empty($convert->convertor['avatar_gallery_path']) && strpos($source, $convert->convertor['avatar_gallery_path']) !== 0) - { - $source = path($convert->convertor['avatar_gallery_path'], empty($convert->convertor['source_path_absolute'])) . $source; - } - - $avatar_cache[$orig_source] = get_image_dim($source); - - if (empty($avatar_cache[$orig_source]) || empty($avatar_cache[$orig_source][0]) || empty($avatar_cache[$orig_source][1])) - { - $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X; - $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y; - - $avatar_cache[$orig_source] = array($default_x, $default_y); - } - - return $avatar_cache[$orig_source][$axis]; -} - -/** -* Obtain the size of the specified remote avatar (using the cache if possible) and cache the value -* Whilst it's unlikely that remote avatars will be duplicated, it is possible so caching seems the best option -* This should only be called from a post processing step due to the possibility of network timeouts -*/ -function get_remote_avatar_dim($src, $axis) -{ - if (empty($src)) - { - return 0; - } - - static $remote_avatar_cache = array(); - - // an ugly hack: we assume that the dimensions of each remote avatar are accessed exactly twice (x and y) - if (isset($remote_avatar_cache[$src])) - { - $retval = $remote_avatar_cache[$src][$axis]; - unset($remote_avatar_cache); - return $retval; - } - - $url_info = @parse_url($src); - if (empty($url_info['host'])) - { - return 0; - } - $host = $url_info['host']; - $port = (isset($url_info['port'])) ? $url_info['port'] : 0; - $protocol = (isset($url_info['scheme'])) ? $url_info['scheme'] : 'http'; - if (empty($port)) - { - switch (strtolower($protocol)) - { - case 'ftp': - $port = 21; - break; - - case 'https': - $port = 443; - break; - - default: - $port = 80; - } - } - - $timeout = @ini_get('default_socket_timeout'); - @ini_set('default_socket_timeout', 2); - - // We're just trying to reach the server to avoid timeouts - $fp = @fsockopen($host, $port, $errno, $errstr, 1); - if ($fp) - { - $remote_avatar_cache[$src] = @getimagesize($src); - fclose($fp); - } - - $default_x = (defined('DEFAULT_AVATAR_X_CUSTOM')) ? DEFAULT_AVATAR_X_CUSTOM : DEFAULT_AVATAR_X; - $default_y = (defined('DEFAULT_AVATAR_Y_CUSTOM')) ? DEFAULT_AVATAR_Y_CUSTOM : DEFAULT_AVATAR_Y; - $default = array($default_x, $default_y); - - if (empty($remote_avatar_cache[$src]) || empty($remote_avatar_cache[$src][0]) || empty($remote_avatar_cache[$src][1])) - { - $remote_avatar_cache[$src] = $default; - } - else - { - // We trust gallery and uploaded avatars to conform to the size settings; we might have to adjust here - if ($remote_avatar_cache[$src][0] > $default_x || $remote_avatar_cache[$src][1] > $default_y) - { - $bigger = ($remote_avatar_cache[$src][0] > $remote_avatar_cache[$src][1]) ? 0 : 1; - $ratio = $default[$bigger] / $remote_avatar_cache[$src][$bigger]; - $remote_avatar_cache[$src][0] = (int) ($remote_avatar_cache[$src][0] * $ratio); - $remote_avatar_cache[$src][1] = (int) ($remote_avatar_cache[$src][1] * $ratio); - } - } - - @ini_set('default_socket_timeout', $timeout); - return $remote_avatar_cache[$src][$axis]; -} - -function set_user_options() -{ - global $convert_row; - - // Key need to be set in row, else default value is chosen - $keyoptions = array( - 'viewimg' => array('bit' => 0, 'default' => 1), - 'viewflash' => array('bit' => 1, 'default' => 1), - 'viewsmilies' => array('bit' => 2, 'default' => 1), - 'viewsigs' => array('bit' => 3, 'default' => 1), - 'viewavatars' => array('bit' => 4, 'default' => 1), - 'viewcensors' => array('bit' => 5, 'default' => 1), - 'attachsig' => array('bit' => 6, 'default' => 0), - 'bbcode' => array('bit' => 8, 'default' => 1), - 'smilies' => array('bit' => 9, 'default' => 1), - 'sig_bbcode' => array('bit' => 15, 'default' => 1), - 'sig_smilies' => array('bit' => 16, 'default' => 1), - 'sig_links' => array('bit' => 17, 'default' => 1), - ); - - $option_field = 0; - - foreach ($keyoptions as $key => $key_ary) - { - $value = (isset($convert_row[$key])) ? (int) $convert_row[$key] : $key_ary['default']; - - if ($value && !($option_field & 1 << $key_ary['bit'])) - { - $option_field += 1 << $key_ary['bit']; - } - } - - return $option_field; -} - -/** -* Index messages on the fly as we convert them -* @todo naderman, can you check that this works with the new search plugins as it's use is currently disabled (and thus untested) -function search_indexing($message = '') -{ - global $fulltext_search, $convert_row; - - if (!isset($convert_row['post_id'])) - { - return; - } - - if (!$message) - { - if (!isset($convert_row['message'])) - { - return; - } - - $message = $convert_row['message']; - } - - $title = (isset($convert_row['title'])) ? $convert_row['title'] : ''; - - $fulltext_search->index('post', $convert_row['post_id'], $message, $title, $convert_row['poster_id'], $convert_row['forum_id']); -} -*/ - -function make_unique_filename($filename) -{ - if (!strlen($filename)) - { - $filename = md5(unique_id()) . '.dat'; - } - else if ($filename[0] == '.') - { - $filename = md5(unique_id()) . $filename; - } - else if (preg_match('/\.([a-z]+)$/i', $filename, $m)) - { - $filename = preg_replace('/\.([a-z]+)$/i', '_' . md5(unique_id()) . '.\1', $filename); - } - else - { - $filename .= '_' . md5(unique_id()) . '.dat'; - } - - return $filename; -} - -function words_unique(&$words) -{ - reset($words); - $return_array = array(); - - $word = current($words); - do - { - $return_array[$word] = $word; - } - while ($word = next($words)); - - return $return_array; -} - -/** -* Adds a user to the specified group and optionally makes them a group leader -* This function does not create the group if it does not exist and so should only be called after the groups have been created -*/ -function add_user_group($group_id, $user_id, $group_leader = false) -{ - global $db; - - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'group_id' => $group_id, - 'user_id' => $user_id, - 'group_leader' => ($group_leader) ? 1 : 0, - 'user_pending' => 0)); - $db->sql_query($sql); -} - -// STANDALONE FUNCTIONS - -/** -* Add users to the pre-defined "special" groups -* -* @param string $group The name of the special group to add to -* @param string $select_query An SQL query to retrieve the user(s) to add to the group -*/ -function user_group_auth($group, $select_query, $use_src_db) -{ - global $convert, $user, $db, $src_db, $same_db; - - if (!in_array($group, array('guests', 'registered', 'registered_coppa', 'global_moderators', 'administrators', 'bots'))) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_WRONG_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true); - return; - } - - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $db->sql_escape(strtoupper($group)) . "'"; - $result = $db->sql_query($sql); - $group_id = (int) $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - - if (!$group_id) - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_NO_GROUP'], $group, 'user_group_auth()'), __LINE__, __FILE__, true); - return; - } - - if ($same_db || !$use_src_db) - { - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' (user_id, group_id, user_pending) - ' . str_replace('{' . strtoupper($group) . '}', $group_id . ', 0', $select_query); - $db->sql_query($sql); - } - else - { - $result = $src_db->sql_query(str_replace('{' . strtoupper($group) . '}', $group_id . ' ', $select_query)); - while ($row = $src_db->sql_fetchrow($result)) - { - // this might become quite a lot of INSERTS unfortunately - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . " (user_id, group_id, user_pending) - VALUES ({$row['user_id']}, $group_id, 0)"; - $db->sql_query($sql); - } - $src_db->sql_freeresult($result); - } -} - -/** -* Retrieves configuration information from the source forum and caches it as an array -* Both database and file driven configuration formats can be handled -* (the type used is specified in $config_schema, see convert_phpbb20.php for more details) -*/ -function get_config() -{ - static $convert_config; - global $user; - - if (isset($convert_config)) - { - return $convert_config; - } - - global $src_db, $same_db; - global $convert; - - if ($convert->config_schema['table_format'] != 'file') - { - if ($convert->mysql_convert && $same_db) - { - $src_db->sql_query("SET NAMES 'binary'"); - } - - $sql = 'SELECT * FROM ' . $convert->src_table_prefix . $convert->config_schema['table_name']; - $result = $src_db->sql_query($sql); - $row = $src_db->sql_fetchrow($result); - - if (!$row) - { - $convert->p_master->error($user->lang['CONV_ERROR_GET_CONFIG'], __LINE__, __FILE__); - } - } - - if (is_array($convert->config_schema['table_format'])) - { - $convert_config = array(); - list($key, $val) = each($convert->config_schema['table_format']); - - do - { - $convert_config[$row[$key]] = $row[$val]; - } - while ($row = $src_db->sql_fetchrow($result)); - $src_db->sql_freeresult($result); - - if ($convert->mysql_convert && $same_db) - { - $src_db->sql_query("SET NAMES 'utf8'"); - } - } - else if ($convert->config_schema['table_format'] == 'file') - { - $filename = $convert->options['forum_path'] . '/' . $convert->config_schema['filename']; - if (!file_exists($filename)) - { - $convert->p_master->error($user->lang('FILE_NOT_FOUND', $filename), __LINE__, __FILE__); - } - - if (isset($convert->config_schema['array_name'])) - { - unset($convert->config_schema['array_name']); - } - - $convert_config = extract_variables_from_file($filename); - if (!empty($convert->config_schema['array_name'])) - { - $convert_config = $convert_config[$convert->config_schema['array_name']]; - } - } - else - { - $convert_config = $row; - if ($convert->mysql_convert && $same_db) - { - $src_db->sql_query("SET NAMES 'utf8'"); - } - } - - if (!count($convert_config)) - { - $convert->p_master->error($user->lang['CONV_ERROR_CONFIG_EMPTY'], __LINE__, __FILE__); - } - - return $convert_config; -} - -/** -* Transfers the relevant configuration information from the source forum -* The mapping of fields is specified in $config_schema, see convert_phpbb20.php for more details -*/ -function restore_config($schema) -{ - global $config; - - $convert_config = get_config(); - - foreach ($schema['settings'] as $config_name => $src) - { - if (preg_match('/(.*)\((.*)\)/', $src, $m)) - { - $var = (empty($m[2]) || empty($convert_config[$m[2]])) ? "''" : "'" . addslashes($convert_config[$m[2]]) . "'"; - $exec = '$config_value = ' . $m[1] . '(' . $var . ');'; - // @codingStandardsIgnoreStart - eval($exec); - // @codingStandardsIgnoreEnd - } - else - { - if ($schema['table_format'] != 'file' || empty($schema['array_name'])) - { - $config_value = (isset($convert_config[$src])) ? $convert_config[$src] : ''; - } - else if (!empty($schema['array_name'])) - { - $src_ary = $schema['array_name']; - $config_value = (isset($convert_config[$src_ary][$src])) ? $convert_config[$src_ary][$src] : ''; - } - } - - if ($config_value !== '') - { - // Most are... - if (is_string($config_value)) - { - $config_value = truncate_string(utf8_htmlspecialchars($config_value), 255, 255, false); - } - - $config->set($config_name, $config_value); - } - } -} - -/** -* Update the count of PM's in custom folders for all users -*/ -function update_folder_pm_count() -{ - global $db; - - $sql = 'SELECT user_id, folder_id, COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ', ' . PRIVMSGS_INBOX . ', ' . PRIVMSGS_OUTBOX . ', ' . PRIVMSGS_SENTBOX . ') - GROUP BY folder_id, user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . PRIVMSGS_FOLDER_TABLE . ' SET pm_count = ' . $row['num_messages'] . ' - WHERE user_id = ' . $row['user_id'] . ' AND folder_id = ' . $row['folder_id']); - } - $db->sql_freeresult($result); -} - -// Functions mainly used by the main convertor script - -function path($path, $path_relative = true) -{ - if ($path === false) - { - return ''; - } - - if (substr($path, -1) != '/') - { - $path .= '/'; - } - - if (!$path_relative) - { - return $path; - } - - if (substr($path, 0, 1) == '/') - { - $path = substr($path, 1); - } - - return $path; -} - -/** -* Extract the variables defined in a configuration file -* @todo As noted by Xore we need to look at this from a security perspective -*/ -function extract_variables_from_file($_filename) -{ - include($_filename); - - $vars = get_defined_vars(); - unset($vars['_filename']); - - return $vars; -} - -function get_path($src_path, $src_url, $test_file) -{ - global $phpbb_root_path, $phpEx; - - $board_config = get_config(); - - $test_file = preg_replace('/\.php$/i', ".$phpEx", $test_file); - $src_path = path($src_path); - - if (@file_exists($phpbb_root_path . $src_path . $test_file)) - { - return $src_path; - } - - if (!empty($src_url) && !empty($board_config['server_name'])) - { - if (!preg_match('#https?://([^/]+)(.*)#i', $src_url, $m)) - { - return false; - } - - if ($m[1] != $board_config['server_name']) - { - return false; - } - - $url_parts = explode('/', $m[2]); - if (substr($src_url, -1) != '/') - { - if (preg_match('/.*\.([a-z0-9]{3,4})$/i', $url_parts[count($url_parts) - 1])) - { - $url_parts[count($url_parts) - 1] = ''; - } - else - { - $url_parts[] = ''; - } - } - - $script_path = $board_config['script_path']; - if (substr($script_path, -1) == '/') - { - $script_path = substr($script_path, 0, -1); - } - - $path_array = array(); - - $phpbb_parts = explode('/', $script_path); - for ($i = 0, $end = count($url_parts); $i < $end; ++$i) - { - if ($i < count($phpbb_parts[$i]) && $url_parts[$i] == $phpbb_parts[$i]) - { - $path_array[] = $url_parts[$i]; - unset($url_parts[$i]); - } - else - { - $path = ''; - for ($j = $i, $end2 = count($phpbb_parts); $j < $end2; ++$j) - { - $path .= '../'; - } - $path .= implode('/', $url_parts); - break; - } - } - - if (!empty($path)) - { - if (@file_exists($phpbb_root_path . $path . $test_file)) - { - return $path; - } - } - } - - return false; -} - -function compare_table($tables, $tablename, &$prefixes) -{ - for ($i = 0, $table_size = count($tables); $i < $table_size; ++$i) - { - if (preg_match('/(.*)' . $tables[$i] . '$/', $tablename, $m)) - { - if (empty($m[1])) - { - $m[1] = '*'; - } - - if (isset($prefixes[$m[1]])) - { - $prefixes[$m[1]]++; - } - else - { - $prefixes[$m[1]] = 1; - } - } - } -} - -/** -* Grant permissions to a specified user or group -* -* @param string $ug_type user|group|user_role|group_role -* @param mixed $forum_id forum ids (array|int|0) -> 0 == all forums -* @param mixed $ug_id [int] user_id|group_id : [string] usergroup name -* @param mixed $acl_list [string] acl entry : [array] acl entries : [string] role entry -* @param int $setting ACL_YES|ACL_NO|ACL_NEVER -*/ -function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO) -{ - global $db; - static $acl_option_ids, $group_ids; - - if (($ug_type == 'group' || $ug_type == 'group_role') && is_string($ug_id)) - { - if (!isset($group_ids[$ug_id])) - { - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $db->sql_escape(strtoupper($ug_id)) . "'"; - $result = $db->sql_query_limit($sql, 1); - $id = (int) $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - - if (!$id) - { - return; - } - - $group_ids[$ug_id] = $id; - } - - $ug_id = (int) $group_ids[$ug_id]; - } - - $table = ($ug_type == 'user' || $ug_type == 'user_role') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE; - $id_field = ($ug_type == 'user' || $ug_type == 'user_role') ? 'user_id' : 'group_id'; - - // Role based permissions are the simplest to handle so check for them first - if ($ug_type == 'user_role' || $ug_type == 'group_role') - { - if (is_numeric($forum_id)) - { - $sql = 'SELECT role_id - FROM ' . ACL_ROLES_TABLE . " - WHERE role_name = 'ROLE_" . $db->sql_escape($acl_list) . "'"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // If we have no role id there is something wrong here - if ($row) - { - $sql = "INSERT INTO $table ($id_field, forum_id, auth_role_id) VALUES ($ug_id, $forum_id, " . $row['role_id'] . ')'; - $db->sql_query($sql); - } - } - - return; - } - - // Build correct parameters - $auth = array(); - - if (!is_array($acl_list)) - { - $auth = array($acl_list => $setting); - } - else - { - foreach ($acl_list as $auth_option) - { - $auth[$auth_option] = $setting; - } - } - unset($acl_list); - - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - // Set any flags as required - foreach ($auth as $auth_option => $acl_setting) - { - $flag = substr($auth_option, 0, strpos($auth_option, '_') + 1); - if (empty($auth[$flag])) - { - $auth[$flag] = $acl_setting; - } - } - - if (!is_array($acl_option_ids) || empty($acl_option_ids)) - { - $sql = 'SELECT auth_option_id, auth_option - FROM ' . ACL_OPTIONS_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $acl_option_ids[$row['auth_option']] = $row['auth_option_id']; - } - $db->sql_freeresult($result); - } - - $sql_forum = 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id), false, true); - - $sql = ($ug_type == 'user') ? 'SELECT o.auth_option_id, o.auth_option, a.forum_id, a.auth_setting FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " o WHERE a.auth_option_id = o.auth_option_id $sql_forum AND a.user_id = $ug_id" : 'SELECT o.auth_option_id, o.auth_option, a.forum_id, a.auth_setting FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " o WHERE a.auth_option_id = o.auth_option_id $sql_forum AND a.group_id = $ug_id"; - $result = $db->sql_query($sql); - - $cur_auth = array(); - while ($row = $db->sql_fetchrow($result)) - { - $cur_auth[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting']; - } - $db->sql_freeresult($result); - - $sql_ary = array(); - foreach ($forum_id as $forum) - { - foreach ($auth as $auth_option => $setting) - { - $auth_option_id = $acl_option_ids[$auth_option]; - - if (!$auth_option_id) - { - continue; - } - - switch ($setting) - { - case ACL_NO: - if (isset($cur_auth[$forum][$auth_option_id])) - { - $sql_ary['delete'][] = "DELETE FROM $table - WHERE forum_id = $forum - AND auth_option_id = $auth_option_id - AND $id_field = $ug_id"; - } - break; - - default: - if (!isset($cur_auth[$forum][$auth_option_id])) - { - $sql_ary['insert'][] = "$ug_id, $forum, $auth_option_id, $setting"; - } - else if ($cur_auth[$forum][$auth_option_id] != $setting) - { - $sql_ary['update'][] = "UPDATE " . $table . " - SET auth_setting = $setting - WHERE $id_field = $ug_id - AND forum_id = $forum - AND auth_option_id = $auth_option_id"; - } - } - } - } - unset($cur_auth); - - $sql = ''; - foreach ($sql_ary as $sql_type => $sql_subary) - { - switch ($sql_type) - { - case 'insert': - switch ($db->get_sql_layer()) - { - case 'mysql': - case 'mysql4': - $sql = 'VALUES ' . implode(', ', preg_replace('#^(.*?)$#', '(\1)', $sql_subary)); - break; - - case 'sqlite3': - case 'mssqlnative': - $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); - break; - - default: - foreach ($sql_subary as $sql) - { - $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) VALUES ($sql)"; - $db->sql_query($sql); - $sql = ''; - } - } - - if ($sql != '') - { - $sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) $sql"; - $db->sql_query($sql); - } - break; - - case 'update': - case 'delete': - foreach ($sql_subary as $sql) - { - $db->sql_query($sql); - $sql = ''; - } - break; - } - unset($sql_ary[$sql_type]); - } - unset($sql_ary); - -} - -/** -* Update the count of unread private messages for all users -*/ -function update_unread_count() -{ - global $db; - - $sql = 'SELECT user_id, COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE pm_unread = 1 - AND folder_id <> ' . PRIVMSGS_OUTBOX . ' - GROUP BY user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_unread_privmsg = ' . $row['num_messages'] . ' - WHERE user_id = ' . $row['user_id']); - } - $db->sql_freeresult($result); -} - -/** -* Add any of the pre-defined "special" groups which are missing from the database -*/ -function add_default_groups() -{ - global $db; - - $default_groups = array( - 'GUESTS' => array('', 0, 0), - 'REGISTERED' => array('', 0, 0), - 'REGISTERED_COPPA' => array('', 0, 0), - 'GLOBAL_MODERATORS' => array('00AA00', 2, 0), - 'ADMINISTRATORS' => array('AA0000', 1, 1), - 'BOTS' => array('9E8DA7', 0, 0), - 'NEWLY_REGISTERED' => array('', 0, 0), - ); - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_name', array_keys($default_groups)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - unset($default_groups[strtoupper($row['group_name'])]); - } - $db->sql_freeresult($result); - - $sql_ary = array(); - - foreach ($default_groups as $name => $data) - { - $sql_ary[] = array( - 'group_name' => (string) $name, - 'group_desc' => '', - 'group_desc_uid' => '', - 'group_desc_bitfield' => '', - 'group_type' => GROUP_SPECIAL, - 'group_colour' => (string) $data[0], - 'group_legend' => (int) $data[1], - 'group_founder_manage' => (int) $data[2], - ); - } - - if (count($sql_ary)) - { - $db->sql_multi_insert(GROUPS_TABLE, $sql_ary); - } -} - -function add_groups_to_teampage() -{ - global $db; - - $teampage_groups = array( - 'ADMINISTRATORS' => 1, - 'GLOBAL_MODERATORS' => 2, - ); - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_name', array_keys($teampage_groups)); - $result = $db->sql_query($sql); - - $teampage_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $teampage_ary[] = array( - 'group_id' => (int) $row['group_id'], - 'teampage_name' => '', - 'teampage_position' => (int) $teampage_groups[$row['group_name']], - 'teampage_parent' => 0, - ); - } - $db->sql_freeresult($result); - - if (count($teampage_ary)) - { - $db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_ary); - } -} - - -/** -* Sync post count. We might need to do this in batches. -*/ -function sync_post_count($offset, $limit) -{ - global $db; - $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id - FROM ' . POSTS_TABLE . ' - WHERE post_postcount = 1 - AND post_visibility = ' . ITEM_APPROVED . ' - GROUP BY poster_id - ORDER BY poster_id'; - $result = $db->sql_query_limit($sql, $limit, $offset); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}"); - } - $db->sql_freeresult($result); -} - -/** -* Add the search bots into the database -* This code should be used in execute_last if the source database did not have bots -* If you are converting bots this function should not be called -* @todo We might want to look at sharing the bot list between the install code and this code for consistancy -*/ -function add_bots() -{ - global $db, $convert, $user, $config, $phpbb_root_path, $phpEx; - - $db->sql_query($convert->truncate_statement . BOTS_TABLE); - - $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'"; - $result = $db->sql_query($sql); - $group_id = (int) $db->sql_fetchfield('group_id', false, $result); - $db->sql_freeresult($result); - - if (!$group_id) - { - add_default_groups(); - - $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = 'BOTS'"; - $result = $db->sql_query($sql); - $group_id = (int) $db->sql_fetchfield('group_id', false, $result); - $db->sql_freeresult($result); - - if (!$group_id) - { - global $install; - $install->error($user->lang['CONV_ERROR_INCONSISTENT_GROUPS'], __LINE__, __FILE__); - } - } - - $bots = 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/2', ''), - 'Majestic-12 [Bot]' => array('MJ12bot/', ''), - 'Metager [Bot]' => array('MetagerBot/', ''), - 'MSN NewsBlogs' => array('msnbot-NewsBlogs/', ''), - 'MSN [Bot]' => array('msnbot/', ''), - 'MSNbot Media' => array('msnbot-media/', ''), - 'NG-Search [Bot]' => array('NG-Search/', ''), - 'Nutch [Bot]' => array('http://lucene.apache.org/nutch/', ''), - 'Nutch/CVS [Bot]' => array('NutchCVS/', ''), - 'OmniExplorer [Bot]' => array('OmniExplorer_Bot/', ''), - 'Online link [Validator]' => array('online link validator', ''), - 'psbot [Picsearch]' => array('psbot/0', ''), - 'Seekport [Bot]' => array('Seekbot/', ''), - '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/', ''), - 'Synoo [Bot]' => array('SynooBot/', ''), - 'Telekom [Bot]' => array('crawleradmin.t-info@telekom.de', ''), - 'TurnitinBot [Bot]' => array('TurnitinBot/', ''), - 'Voyager [Bot]' => array('voyager/1.0', ''), - 'W3 [Sitesearch]' => array('W3 SiteSearch Crawler', ''), - 'W3C [Linkcheck]' => array('W3C-checklink/', ''), - 'W3C [Validator]' => array('W3C_*Validator', ''), - 'WiseNut [Bot]' => array('http://www.WISEnutbot.com', ''), - '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/', ''), - ); - - if (!function_exists('user_add')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - foreach ($bots 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' => $config['default_lang'], - 'user_style' => 1, - 'user_timezone' => 'UTC', - 'user_allow_massemail' => 0, - ); - - $user_id = user_add($user_row); - - if ($user_id) - { - $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'bot_active' => 1, - 'bot_name' => $bot_name, - 'user_id' => $user_id, - 'bot_agent' => $bot_ary[0], - 'bot_ip' => $bot_ary[1]) - ); - $db->sql_query($sql); - } - } -} - -/** -* Update any dynamic configuration variables after the conversion is finished -* @todo Confirm that this updates all relevant values since it has not necessarily been kept in sync with all changes -*/ -function update_dynamic_config() -{ - global $db, $config; - - // Get latest username - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; - - if (!empty($config['increment_user_id'])) - { - $sql .= ' AND user_id <> ' . $config['increment_user_id']; - } - - $sql .= ' ORDER BY user_id DESC'; - - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $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. -// set_config('record_online_users', 1, true); -// set_config('record_online_date', time(), true); - - $sql = 'SELECT COUNT(post_id) AS stat - FROM ' . POSTS_TABLE . ' - WHERE post_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_posts', (int) $row['stat'], false); - - $sql = 'SELECT COUNT(topic_id) AS stat - FROM ' . TOPICS_TABLE . ' - WHERE topic_visibility = ' . ITEM_APPROVED; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('num_topics', (int) $row['stat'], false); - - $sql = 'SELECT COUNT(user_id) AS stat - FROM ' . USERS_TABLE . ' - WHERE user_type IN (' . USER_NORMAL . ',' . USER_FOUNDER . ')'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $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); - $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); - $config->set('upload_dir_size', (float) $db->sql_fetchfield('stat'), false); - $db->sql_freeresult($result); - - /** - * We do not resync users post counts - this can be done by the admin after conversion if wanted. - $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id - FROM ' . POSTS_TABLE . ' - WHERE post_postcount = 1 - GROUP BY poster_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_posts = {$row['num_posts']} WHERE user_id = {$row['poster_id']}"); - } - $db->sql_freeresult($result); - */ -} - -/** -* Updates topics_posted entries -*/ -function update_topics_posted() -{ - global $db; - - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); - break; - - default: - $db->sql_query('TRUNCATE TABLE ' . TOPICS_POSTED_TABLE); - break; - } - - // This can get really nasty... therefore we only do the last six months - $get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60); - - // Select forum ids, do not include categories - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type <> ' . FORUM_CAT; - $result = $db->sql_query($sql); - - $forum_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $db->sql_freeresult($result); - - // Any global announcements? ;) - $forum_ids[] = 0; - - // Now go through the forums and get us some topics... - foreach ($forum_ids as $forum_id) - { - $sql = 'SELECT p.poster_id, p.topic_id - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t - WHERE t.forum_id = ' . $forum_id . ' - AND t.topic_moved_id = 0 - AND t.topic_last_post_time > ' . $get_from_time . ' - AND t.topic_id = p.topic_id - AND p.poster_id <> ' . ANONYMOUS . ' - GROUP BY p.poster_id, p.topic_id'; - $result = $db->sql_query($sql); - - $posted = array(); - while ($row = $db->sql_fetchrow($result)) - { - $posted[$row['poster_id']][] = $row['topic_id']; - } - $db->sql_freeresult($result); - - $sql_ary = array(); - foreach ($posted as $user_id => $topic_row) - { - foreach ($topic_row as $topic_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user_id, - 'topic_id' => (int) $topic_id, - 'topic_posted' => 1, - ); - } - } - unset($posted); - - if (count($sql_ary)) - { - $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); - } - } -} - -/** -* Ensure that all users have a default group specified and update related information such as their colour -*/ -function fix_empty_primary_groups() -{ - global $db; - - // Set group ids for users not already having it - $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . ' - WHERE group_id = 0 AND user_type = ' . USER_INACTIVE; - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('registered') . ' - WHERE group_id = 0 AND user_type = ' . USER_NORMAL; - $db->sql_query($sql); - - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('guests') . ' WHERE user_id = ' . ANONYMOUS); - - $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('administrators'); - $result = $db->sql_query($sql); - - $user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - 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)); - } - - $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('global_moderators'); - $result = $db->sql_query($sql); - - $user_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - 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)); - } - - // Set user colour - $sql = 'SELECT group_id, group_colour FROM ' . GROUPS_TABLE . " - WHERE group_colour <> ''"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_colour = '{$row['group_colour']}' WHERE group_id = {$row['group_id']}"); - } - $db->sql_freeresult($result); -} - -/** -* Cleanly remove invalid user entries after converting the users table... -*/ -function remove_invalid_users() -{ - global $db, $phpEx, $phpbb_root_path; - - // username_clean is UNIQUE - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE username_clean = ''"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - if (!function_exists('user_delete')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - user_delete('remove', $row['user_id']); - } -} - -function convert_bbcode($message, $convert_size = true, $extended_bbcodes = false) -{ - static $orig, $repl, $origx, $replx, $str_from, $str_to; - - if (empty($orig)) - { - $orig = $repl = array(); - - $orig[] = '#\[(php|sql)\](.*?)\[/(php|sql)\]#is'; - $repl[] = '[code]\2[/code]'; - - $orig[] = '#\[font=[^\]]+\](.*?)\[/font\]#is'; - $repl[] = '\1'; - - $orig[] = '#\[align=[a-z]+\](.*?)\[/align\]#is'; - $repl[] = '\1'; - - $orig[] = '#\[/list=.*?\]#is'; - $repl[] = '[/list]'; - - $origx = array( - '#\[glow[^\]]+\](.*?)\[/glow\]#is', - '#\[shadow[^\]]+\](.*?)\[/shadow\]#is', - '#\[flash[^\]]+\](.*?)\[/flash\]#is' - ); - - $replx = array( - '\1', - '\1', - '[url=\1]Flash[/url]' - ); - - $str_from = array( - '[ftp]', '[/ftp]', - '[ftp=', '[/ftp]', - '[pre]', '[/pre]', - '[table]', '[/table]', - '[td]', '[/td]', - '[tr]', '[/tr]', - '[s]', '[/s]', - '[left]', '[/left]', - '[right]', '[/right]', - '[center]', '[/center]', - '[sub]', '[/sub]', - '[sup]', '[/sup]', - '[tt]', '[/tt]', - '[move]', '[/move]', - '[hr]' - ); - - $str_to = array( - '[url]', '[/url]', - '[url=', '[/url]', - '[code]', '[/code]', - "\n", '', - '', '', - "\n", '', - '', '', - '', '', - '', '', - '', '', - '', '', - '', '', - '', '', - '', '', - "\n\n" - ); - - for ($i = 0, $end = count($str_from); $i < $end; ++$i) - { - $origx[] = '#\\' . str_replace(']', '\\]', $str_from[$i]) . '#is'; - $replx[] = $str_to[$i]; - } - } - - if (preg_match_all('#\[email=([^\]]+)\](.*?)\[/email\]#i', $message, $m)) - { - for ($i = 0, $end = count($m[1]); $i < $end; ++$i) - { - if ($m[1][$i] == $m[2][$i]) - { - $message = str_replace($m[0][$i], '[email]' . $m[1][$i] . '[/email]', $message); - } - else - { - $message = str_replace($m[0][$i], $m[2][$i] . ' ([email]' . $m[1][$i] . '[/email])', $message); - } - } - } - - if ($convert_size && preg_match('#\[size=[0-9]+\].*?\[/size\]#i', $message)) - { - $size = array(9, 9, 12, 15, 18, 24, 29, 29, 29, 29); - $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 = count($size); $i;) - { - $i--; - $message = str_replace('[size=' . $i . ']', '[size=' . $size[$i] . ']', $message); - } - } - - if ($extended_bbcodes) - { - $message = preg_replace($origx, $replx, $message); - } - - $message = preg_replace($orig, $repl, $message); - return $message; -} - - -function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $source_relative_path = true) -{ - global $convert, $phpbb_root_path, $user, $phpbb_filesystem; - - /** @var \phpbb\filesystem\filesystem_interface $filesystem */ - $filesystem = $phpbb_filesystem; - - if (substr($trg, -1) == '/') - { - $trg .= utf8_basename($src); - } - $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__); - $trg_path = $trg; - - if (!$overwrite && @file_exists($trg_path)) - { - return true; - } - - if (!@file_exists($src_path)) - { - return; - } - - $path = $phpbb_root_path; - $parts = explode('/', $trg); - unset($parts[count($parts) - 1]); - - for ($i = 0, $end = count($parts); $i < $end; ++$i) - { - $path .= $parts[$i] . '/'; - - if (!is_dir($path)) - { - @mkdir($path, 0777); - } - } - - if (!$filesystem->is_writable($path)) - { - @chmod($path, 0777); - } - - if (!@copy($src_path, $phpbb_root_path . $trg_path)) - { - $convert->p_master->error(sprintf($user->lang['COULD_NOT_COPY'], $src_path, $phpbb_root_path . $trg_path), __LINE__, __FILE__, !$die_on_failure); - return; - } - - if ($perm = @fileperms($src_path)) - { - @chmod($phpbb_root_path . $trg_path, $perm); - } - - return true; -} - -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, $phpbb_filesystem; - - /** @var \phpbb\filesystem\filesystem_interface $filesystem */ - $filesystem = $phpbb_filesystem; - - $dirlist = $filelist = $bad_dirs = array(); - $src = path($src, $source_relative_path); - $trg = path($trg); - $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__); - $trg_path = $phpbb_root_path . $trg; - - if (!is_dir($trg_path)) - { - @mkdir($trg_path, 0777); - @chmod($trg_path, 0777); - } - - if (!$filesystem->is_writable($trg_path)) - { - $bad_dirs[] = path($config['script_path']) . $trg; - } - - if ($handle = @opendir($src_path)) - { - while ($entry = readdir($handle)) - { - if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm') - { - continue; - } - - if (is_dir($src_path . $entry)) - { - $dirlist[] = $entry; - } - else - { - $filelist[] = $entry; - } - } - closedir($handle); - } - else if ($dir = @dir($src_path)) - { - while ($entry = $dir->read()) - { - if ($entry[0] == '.' || $entry == 'CVS' || $entry == 'index.htm') - { - continue; - } - - if (is_dir($src_path . $entry)) - { - $dirlist[] = $entry; - } - else - { - $filelist[] = $entry; - } - } - $dir->close(); - } - else - { - $convert->p_master->error(sprintf($user->lang['CONV_ERROR_COULD_NOT_READ'], relative_base($src, $source_relative_path)), __LINE__, __FILE__); - } - - if ($copy_subdirs) - { - for ($i = 0, $end = count($dirlist); $i < $end; ++$i) - { - $dir = $dirlist[$i]; - - if ($dir == 'CVS') - { - continue; - } - - if (!is_dir($trg_path . $dir)) - { - @mkdir($trg_path . $dir, 0777); - @chmod($trg_path . $dir, 0777); - } - - if (!$filesystem->is_writable($trg_path . $dir)) - { - $bad_dirs[] = $trg . $dir; - $bad_dirs[] = $trg_path . $dir; - } - - if (!count($bad_dirs)) - { - copy_dir($src . $dir, $trg . $dir, true, $overwrite, $die_on_failure, $source_relative_path); - } - } - } - - if (count($bad_dirs)) - { - $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('
', $bad_dirs)), __LINE__, __FILE__); - } - - for ($i = 0, $end = count($filelist); $i < $end; ++$i) - { - copy_file($src . $filelist[$i], $trg . $filelist[$i], $overwrite, $die_on_failure, $source_relative_path); - } -} - -function relative_base($path, $is_relative = true, $line = false, $file = false) -{ - global $convert, $user; - - if (!$is_relative) - { - return $path; - } - - if (empty($convert->options['forum_path']) && $is_relative) - { - $line = $line ? $line : __LINE__; - $file = $file ? $file : __FILE__; - - $convert->p_master->error($user->lang['CONV_ERROR_NO_FORUM_PATH'], $line, $file); - } - - return $convert->options['forum_path'] . '/' . $path; -} - -function get_smiley_display() -{ - static $smiley_count = 0; - $smiley_count++; - return ($smiley_count < 50) ? 1 : 0; -} - - -function fill_dateformat($user_dateformat) -{ - global $config; - - return ((empty($user_dateformat)) ? $config['default_dateformat'] : $user_dateformat); -} diff --git a/install/update/old/includes/functions_display.php b/install/update/old/includes/functions_display.php deleted file mode 100644 index 7924670..0000000 --- a/install/update/old/includes/functions_display.php +++ /dev/null @@ -1,1733 +0,0 @@ - -* @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; -} - -/** -* Display Forums -*/ -function display_forums($root_data = '', $display_moderators = true, $return_moderators = false) -{ - global $db, $auth, $user, $template; - global $phpbb_root_path, $phpEx, $config; - global $request, $phpbb_dispatcher, $phpbb_container; - - $forum_rows = $subforums = $forum_ids = $forum_ids_moderator = $forum_moderators = $active_forum_ary = array(); - $parent_id = $visible_forums = 0; - - // Mark forums read? - $mark_read = $request->variable('mark', ''); - - if ($mark_read == 'all') - { - $mark_read = ''; - } - - if (!$root_data) - { - if ($mark_read == 'forums') - { - $mark_read = 'all'; - } - - $root_data = array('forum_id' => 0); - $sql_where = ''; - } - else - { - $sql_where = 'left_id > ' . $root_data['left_id'] . ' AND left_id < ' . $root_data['right_id']; - } - - // Handle marking everything read - if ($mark_read == 'all') - { - $redirect = build_url(array('mark', 'hash', 'mark_time')); - meta_refresh(3, $redirect); - - if (check_link_hash($request->variable('hash', ''), 'global')) - { - markread('all', false, false, $request->variable('mark_time', 0)); - - if ($request->is_ajax()) - { - // Tell the ajax script what language vars and URL need to be replaced - $data = array( - 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'], - 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'], - 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}index.$phpEx", 'hash=' . generate_link_hash('global') . '&mark=forums&mark_time=' . time()) : '', - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED'] - ); - $json_response = new \phpbb\json_response(); - $json_response->send($data); - } - - trigger_error( - $user->lang['FORUMS_MARKED'] . '

' . - sprintf($user->lang['RETURN_INDEX'], '', '') - ); - } - else - { - trigger_error(sprintf($user->lang['RETURN_PAGE'], '', '')); - } - } - - // Display list of active topics for this category? - $show_active = (isset($root_data['forum_flags']) && ($root_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) ? true : false; - - $sql_array = array( - 'SELECT' => 'f.*', - 'FROM' => array( - FORUMS_TABLE => 'f' - ), - 'LEFT_JOIN' => array(), - ); - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql_array['LEFT_JOIN'][] = array('FROM' => array(FORUMS_TRACK_TABLE => 'ft'), 'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND ft.forum_id = f.forum_id'); - $sql_array['SELECT'] .= ', ft.mark_time'; - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - } - - if ($show_active) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(FORUMS_ACCESS_TABLE => 'fa'), - 'ON' => "fa.forum_id = f.forum_id AND fa.session_id = '" . $db->sql_escape($user->session_id) . "'" - ); - - $sql_array['SELECT'] .= ', fa.user_id'; - } - - $sql_ary = array( - 'SELECT' => $sql_array['SELECT'], - 'FROM' => $sql_array['FROM'], - 'LEFT_JOIN' => $sql_array['LEFT_JOIN'], - - 'WHERE' => $sql_where, - - 'ORDER_BY' => 'f.left_id', - ); - - /** - * Event to modify the SQL query before the forum data is queried - * - * @event core.display_forums_modify_sql - * @var array sql_ary The SQL array to get the data of the forums - * @since 3.1.0-a1 - */ - $vars = array('sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_sql', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - - $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)) - { - /** - * Event to modify the data set of a forum - * - * This event is triggered once per forum - * - * @event core.display_forums_modify_row - * @var int branch_root_id Last top-level forum - * @var array row The data of the forum - * @since 3.1.0-a1 - */ - $vars = array('branch_root_id', 'row'); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_row', compact($vars))); - - $forum_id = $row['forum_id']; - - // Mark forums read? - if ($mark_read == 'forums') - { - if ($auth->acl_get('f_list', $forum_id)) - { - $forum_ids[] = $forum_id; - } - - continue; - } - - // Category with no members - if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) - { - continue; - } - - // Skip branch - if (isset($right_id)) - { - if ($row['left_id'] < $right_id) - { - continue; - } - unset($right_id); - } - - if (!$auth->acl_get('f_list', $forum_id)) - { - // if the user does not have permissions to list this forum, skip everything until next branch - $right_id = $row['right_id']; - continue; - } - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $forum_tracking_info[$forum_id] = (!empty($row['mark_time'])) ? $row['mark_time'] : $user->data['user_lastmark']; - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - $forum_tracking_info[$forum_id] = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark']; - } - - // Lets check whether there are unapproved topics/posts, so we can display an information to moderators - $row['forum_id_unapproved_topics'] = ($auth->acl_get('m_approve', $forum_id) && $row['forum_topics_unapproved']) ? $forum_id : 0; - $row['forum_id_unapproved_posts'] = ($auth->acl_get('m_approve', $forum_id) && $row['forum_posts_unapproved']) ? $forum_id : 0; - $row['forum_posts'] = $phpbb_content_visibility->get_count('forum_posts', $row, $forum_id); - $row['forum_topics'] = $phpbb_content_visibility->get_count('forum_topics', $row, $forum_id); - - // Display active topics from this forum? - if ($show_active && $row['forum_type'] == FORUM_POST && $auth->acl_get('f_read', $forum_id) && ($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) - { - if (!isset($active_forum_ary['forum_topics'])) - { - $active_forum_ary['forum_topics'] = 0; - } - - if (!isset($active_forum_ary['forum_posts'])) - { - $active_forum_ary['forum_posts'] = 0; - } - - $active_forum_ary['forum_id'][] = $forum_id; - $active_forum_ary['enable_icons'][] = $row['enable_icons']; - $active_forum_ary['forum_topics'] += $row['forum_topics']; - $active_forum_ary['forum_posts'] += $row['forum_posts']; - - // If this is a passworded forum we do not show active topics from it if the user is not authorised to view it... - if ($row['forum_password'] && $row['user_id'] != $user->data['user_id']) - { - $active_forum_ary['exclude_forum_id'][] = $forum_id; - } - } - - // Fill list of categories with forums - if (isset($forum_rows[$row['parent_id']])) - { - $valid_categories[$row['parent_id']] = true; - } - - // - if ($row['parent_id'] == $root_data['forum_id'] || $row['parent_id'] == $branch_root_id) - { - if ($row['forum_type'] != FORUM_CAT) - { - $forum_ids_moderator[] = (int) $forum_id; - } - - // Direct child of current branch - $parent_id = $forum_id; - $forum_rows[$forum_id] = $row; - - if ($row['forum_type'] == FORUM_CAT && $row['parent_id'] == $root_data['forum_id']) - { - $branch_root_id = $forum_id; - } - $forum_rows[$parent_id]['forum_id_last_post'] = $row['forum_id']; - $forum_rows[$parent_id]['forum_password_last_post'] = $row['forum_password']; - $forum_rows[$parent_id]['orig_forum_last_post_time'] = $row['forum_last_post_time']; - } - else if ($row['forum_type'] != FORUM_CAT) - { - $subforums[$parent_id][$forum_id]['display'] = ($row['display_on_index']) ? true : false; - $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']) - { - $subforums[$parent_id][$row['parent_id']]['children'][] = $forum_id; - } - - if (!$forum_rows[$parent_id]['forum_id_unapproved_topics'] && $row['forum_id_unapproved_topics']) - { - $forum_rows[$parent_id]['forum_id_unapproved_topics'] = $forum_id; - } - - if (!$forum_rows[$parent_id]['forum_id_unapproved_posts'] && $row['forum_id_unapproved_posts']) - { - $forum_rows[$parent_id]['forum_id_unapproved_posts'] = $forum_id; - } - - $forum_rows[$parent_id]['forum_topics'] += $row['forum_topics']; - - // Do not list redirects in LINK Forums as Posts. - if ($row['forum_type'] != FORUM_LINK) - { - $forum_rows[$parent_id]['forum_posts'] += $row['forum_posts']; - } - - if ($row['forum_last_post_time'] > $forum_rows[$parent_id]['forum_last_post_time']) - { - $forum_rows[$parent_id]['forum_last_post_id'] = $row['forum_last_post_id']; - $forum_rows[$parent_id]['forum_last_post_subject'] = $row['forum_last_post_subject']; - $forum_rows[$parent_id]['forum_last_post_time'] = $row['forum_last_post_time']; - $forum_rows[$parent_id]['forum_last_poster_id'] = $row['forum_last_poster_id']; - $forum_rows[$parent_id]['forum_last_poster_name'] = $row['forum_last_poster_name']; - $forum_rows[$parent_id]['forum_last_poster_colour'] = $row['forum_last_poster_colour']; - $forum_rows[$parent_id]['forum_id_last_post'] = $forum_id; - $forum_rows[$parent_id]['forum_password_last_post'] = $row['forum_password']; - } - } - - /** - * Event to modify the forum rows data set - * - * This event is triggered once per forum - * - * @event core.display_forums_modify_forum_rows - * @var array forum_rows Data array of all forums we display - * @var array subforums Data array of all subforums we display - * @var int branch_root_id Current top-level forum - * @var int parent_id Current parent forum - * @var array row The data of the forum - * @since 3.1.0-a1 - */ - $vars = array('forum_rows', 'subforums', 'branch_root_id', 'parent_id', 'row'); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_forum_rows', compact($vars))); - } - $db->sql_freeresult($result); - - // Handle marking posts - if ($mark_read == 'forums') - { - $redirect = build_url(array('mark', 'hash', 'mark_time')); - $token = $request->variable('hash', ''); - if (check_link_hash($token, 'global')) - { - markread('topics', $forum_ids, false, $request->variable('mark_time', 0)); - $message = sprintf($user->lang['RETURN_FORUM'], '', ''); - meta_refresh(3, $redirect); - - if ($request->is_ajax()) - { - // Tell the ajax script what language vars and URL need to be replaced - $data = array( - 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'], - 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'], - 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . '&f=' . $root_data['forum_id'] . '&mark=forums&mark_time=' . time()) : '', - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED'] - ); - $json_response = new \phpbb\json_response(); - $json_response->send($data); - } - - trigger_error($user->lang['FORUMS_MARKED'] . '

' . $message); - } - else - { - $message = sprintf($user->lang['RETURN_PAGE'], '', ''); - meta_refresh(3, $redirect); - trigger_error($message); - } - - } - - // Grab moderators ... if necessary - if ($display_moderators) - { - if ($return_moderators) - { - $forum_ids_moderator[] = $root_data['forum_id']; - } - get_moderators($forum_moderators, $forum_ids_moderator); - } - - /** - * Event to perform additional actions before the forum list is being generated - * - * @event core.display_forums_before - * @var array active_forum_ary Array with forum data to display active topics - * @var bool display_moderators Flag indicating if we display forum moderators - * @var array forum_moderators Array with forum moderators list - * @var array forum_rows Data array of all forums we display - * @var bool return_moderators Flag indicating if moderators list should be returned - * @var array root_data Array with the root forum data - * @since 3.1.4-RC1 - */ - $vars = array( - 'active_forum_ary', - 'display_moderators', - 'forum_moderators', - 'forum_rows', - 'return_moderators', - 'root_data', - ); - extract($phpbb_dispatcher->trigger_event('core.display_forums_before', compact($vars))); - - // Used to tell whatever we have to create a dummy category or not. - $last_catless = true; - foreach ($forum_rows as $row) - { - // Category - if ($row['parent_id'] == $root_data['forum_id'] && $row['forum_type'] == FORUM_CAT) - { - // Do not display categories without any forums to display - if (!isset($valid_categories[$row['forum_id']])) - { - continue; - } - - $cat_row = array( - 'S_IS_CAT' => true, - 'FORUM_ID' => $row['forum_id'], - 'FORUM_NAME' => $row['forum_name'], - 'FORUM_DESC' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), - 'FORUM_FOLDER_IMG' => '', - 'FORUM_FOLDER_IMG_SRC' => '', - 'FORUM_IMAGE' => ($row['forum_image']) ? '' . $user->lang['FORUM_CAT'] . '' : '', - 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', - 'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), - ); - - /** - * Modify the template data block of the 'category' - * - * This event is triggered once per 'category' - * - * @event core.display_forums_modify_category_template_vars - * @var array cat_row Template data of the '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', - 'last_catless', - 'root_data', - 'row', - ); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_category_template_vars', compact($vars))); - - $template->assign_block_vars('forumrow', $cat_row); - - continue; - } - - $visible_forums++; - $forum_id = $row['forum_id']; - - $forum_unread = (isset($forum_tracking_info[$forum_id]) && $row['orig_forum_last_post_time'] > $forum_tracking_info[$forum_id]) ? true : false; - - $folder_image = $folder_alt = $l_subforums = ''; - $subforums_list = array(); - - // Generate list of subforums if we need to - if (isset($subforums[$forum_id])) - { - foreach ($subforums[$forum_id] as $subforum_id => $subforum_row) - { - $subforum_unread = (isset($forum_tracking_info[$subforum_id]) && $subforum_row['orig_forum_last_post_time'] > $forum_tracking_info[$subforum_id]) ? true : false; - - if (!$subforum_unread && !empty($subforum_row['children'])) - { - foreach ($subforum_row['children'] as $child_id) - { - if (isset($forum_tracking_info[$child_id]) && $subforums[$forum_id][$child_id]['orig_forum_last_post_time'] > $forum_tracking_info[$child_id]) - { - // Once we found an unread child forum, we can drop out of this loop - $subforum_unread = true; - break; - } - } - } - - if ($subforum_row['display'] && $subforum_row['name']) - { - $subforums_list[] = array( - 'link' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $subforum_id), - 'name' => $subforum_row['name'], - 'unread' => $subforum_unread, - 'type' => $subforum_row['type'], - ); - } - else - { - unset($subforums[$forum_id][$subforum_id]); - } - - // If one subforum is unread the forum gets unread too... - if ($subforum_unread) - { - $forum_unread = true; - } - } - - $l_subforums = (count($subforums[$forum_id]) == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS']; - $folder_image = ($forum_unread) ? 'forum_unread_subforum' : 'forum_read_subforum'; - } - else - { - switch ($row['forum_type']) - { - case FORUM_POST: - $folder_image = ($forum_unread) ? 'forum_unread' : 'forum_read'; - break; - - case FORUM_LINK: - $folder_image = 'forum_link'; - break; - } - } - - // Which folder should we display? - if ($row['forum_status'] == ITEM_LOCKED) - { - $folder_image = ($forum_unread) ? 'forum_unread_locked' : 'forum_read_locked'; - $folder_alt = 'FORUM_LOCKED'; - } - else - { - $folder_alt = ($forum_unread) ? 'UNREAD_POSTS' : 'NO_UNREAD_POSTS'; - } - - // Create last post link information, if appropriate - if ($row['forum_last_post_id']) - { - 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_truncated = truncate_string($last_post_subject, 30, 255, false, $user->lang['ELLIPSIS']); - } - else - { - $last_post_subject = $last_post_subject_truncated = ''; - } - $last_post_time = $user->format_date($row['forum_last_post_time']); - $last_post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id_last_post'] . '&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 = ''; - } - - // Output moderator listing ... if applicable - $l_moderator = $moderators_list = ''; - if ($display_moderators && !empty($forum_moderators[$forum_id])) - { - $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]); - } - - $l_post_click_count = ($row['forum_type'] == FORUM_LINK) ? 'CLICKS' : 'POSTS'; - $post_click_count = ($row['forum_type'] != FORUM_LINK || $row['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? $row['forum_posts'] : ''; - - $s_subforums_list = $subforums_row = array(); - foreach ($subforums_list as $subforum) - { - $s_subforums_list[] = '' . $subforum['name'] . ''; - $subforums_row[] = array( - '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); - $catless = ($row['parent_id'] == $root_data['forum_id']) ? true : false; - - if ($row['forum_type'] != FORUM_LINK) - { - $u_viewforum = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']); - } - else - { - // If the forum is a link and we count redirects we need to visit it - // If the forum is having a password or no read access we do not expose the link, but instead handle it in viewforum - if (($row['forum_flags'] & FORUM_FLAG_LINK_TRACK) || $row['forum_password'] || !$auth->acl_get('f_read', $forum_id)) - { - $u_viewforum = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']); - } - else - { - $u_viewforum = $row['forum_link']; - } - } - - $forum_row = array( - 'S_IS_CAT' => false, - 'S_NO_CAT' => $catless && !$last_catless, - 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK) ? true : false, - 'S_UNREAD_FORUM' => $forum_unread, - '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' => (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, - - 'FORUM_ID' => $row['forum_id'], - 'FORUM_NAME' => $row['forum_name'], - 'FORUM_DESC' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), - 'TOPICS' => $row['forum_topics'], - $l_post_click_count => $post_click_count, - 'FORUM_IMG_STYLE' => $folder_image, - 'FORUM_FOLDER_IMG' => $user->img($folder_image, $folder_alt), - 'FORUM_FOLDER_IMG_ALT' => isset($user->lang[$folder_alt]) ? $user->lang[$folder_alt] : '', - 'FORUM_IMAGE' => ($row['forum_image']) ? '' . $user->lang[$folder_alt] . '' : '', - 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', - 'LAST_POST_SUBJECT' => $last_post_subject, - 'LAST_POST_SUBJECT_TRUNCATED' => $last_post_subject_truncated, - 'LAST_POST_TIME' => $last_post_time, - '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']), - 'MODERATORS' => $moderators_list, - 'SUBFORUMS' => $s_subforums_list, - - 'L_SUBFORUM_STR' => $l_subforums, - 'L_MODERATOR_STR' => $l_moderator, - - 'U_UNAPPROVED_TOPICS' => ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_topics&f=' . $row['forum_id_unapproved_topics']) : '', - 'U_UNAPPROVED_POSTS' => ($row['forum_id_unapproved_posts']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_posts&f=' . $row['forum_id_unapproved_posts']) : '', - 'U_VIEWFORUM' => $u_viewforum, - 'U_LAST_POSTER' => get_username_string('profile', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']), - 'U_LAST_POST' => $last_post_url, - ); - - /** - * Modify the template data block of the forum - * - * This event is triggered once per forum - * - * @event core.display_forums_modify_template_vars - * @var array forum_row Template data of the forum - * @var array row The data of the forum - * @var array subforums_row Template data of subforums - * @since 3.1.0-a1 - * @changed 3.1.0-b5 Added var subforums_row - */ - $vars = array('forum_row', 'row', 'subforums_row'); - extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_template_vars', compact($vars))); - - $template->assign_block_vars('forumrow', $forum_row); - - // Assign subforums loop for style authors - $template->assign_block_vars_array('forumrow.subforum', $subforums_row); - - /** - * Modify and/or assign additional template data for the forum - * after forumrow loop has been assigned. This can be used - * to create additional forumrow subloops in extensions. - * - * This event is triggered once per forum - * - * @event core.display_forums_add_template_data - * @var array forum_row Template data of the forum - * @var array row The data of the forum - * @var array subforums_list The data of subforums - * @var array subforums_row Template data of subforums - * @var bool catless The flag indicating whether a forum has a parent category - * @since 3.1.0-b5 - */ - $vars = array( - 'forum_row', - 'row', - 'subforums_list', - 'subforums_row', - 'catless', - ); - extract($phpbb_dispatcher->trigger_event('core.display_forums_add_template_data', compact($vars))); - - $last_catless = $catless; - } - - $template->assign_vars(array( - '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()) : '', - 'S_HAS_SUBFORUM' => ($visible_forums) ? true : false, - 'L_SUBFORUM' => ($visible_forums == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS'], - 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPICS_UNAPPROVED'), - 'UNAPPROVED_POST_IMG' => $user->img('icon_topic_unapproved', 'POSTS_UNAPPROVED_FORUM'), - )); - - /** - * Event to perform additional actions after the forum list has been generated - * - * @event core.display_forums_after - * @var array active_forum_ary Array with forum data to display active topics - * @var bool display_moderators Flag indicating if we display forum moderators - * @var array forum_moderators Array with forum moderators list - * @var array forum_rows Data array of all forums we display - * @var bool return_moderators Flag indicating if moderators list should be returned - * @var array root_data Array with the root forum data - * @since 3.1.0-RC5 - */ - $vars = array( - 'active_forum_ary', - 'display_moderators', - 'forum_moderators', - 'forum_rows', - 'return_moderators', - 'root_data', - ); - extract($phpbb_dispatcher->trigger_event('core.display_forums_after', compact($vars))); - - if ($return_moderators) - { - return array($active_forum_ary, $forum_moderators); - } - - return array($active_forum_ary, array()); -} - -/** -* Create forum rules for given forum -*/ -function generate_forum_rules(&$forum_data) -{ - if ($forum_data['forum_rules']) - { - $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']); - } - - if (!$forum_data['forum_rules'] && !$forum_data['forum_rules_link']) - { - return; - } - - global $template; - - $template->assign_vars(array( - 'S_FORUM_RULES' => true, - 'U_FORUM_RULES' => $forum_data['forum_rules_link'], - 'FORUM_RULES' => $forum_data['forum_rules']) - ); -} - -/** -* 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_ary) -{ - global $template, $auth, $config; - global $phpEx, $phpbb_root_path, $phpbb_dispatcher; - - if (!$auth->acl_get('f_list', $forum_data_ary['forum_id'])) - { - return; - } - - $navlinks_parents = $forum_template_data = array(); - - // Get forum parents - $forum_parents = get_forum_parents($forum_data_ary); - - $microdata_attr = 'data-forum-id'; - - // Build navigation links - if (!empty($forum_parents)) - { - foreach ($forum_parents as $parent_forum_id => $parent_data) - { - list($parent_name, $parent_type) = array_values($parent_data); - - // Skip this parent if the user does not have the permission to view it - if (!$auth->acl_get('f_list', $parent_forum_id)) - { - continue; - } - - $navlinks_parents[] = array( - 'S_IS_CAT' => ($parent_type == FORUM_CAT) ? true : false, - 'S_IS_LINK' => ($parent_type == FORUM_LINK) ? true : false, - 'S_IS_POST' => ($parent_type == FORUM_POST) ? true : false, - 'FORUM_NAME' => $parent_name, - 'FORUM_ID' => $parent_forum_id, - 'MICRODATA' => $microdata_attr . '="' . $parent_forum_id . '"', - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $parent_forum_id), - ); - } - } - - $navlinks = array( - '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_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_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 - * - * @event core.generate_forum_nav - * @var array forum_data Array with the forum data - * @var array forum_template_data Array with generic forum template data - * @var string microdata_attr The microdata attribute - * @var array navlinks_parents Array with the forum parents navlinks data - * @var array navlinks Array with the forum navlinks data - * @since 3.1.5-RC1 - */ - $vars = array( - 'forum_data', - 'forum_template_data', - 'microdata_attr', - 'navlinks_parents', - '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); - $template->assign_vars($forum_template_data); - - return; -} - -/** -* Returns forum parents as an array. Get them from forum_data if available, or update the database otherwise -*/ -function get_forum_parents(&$forum_data) -{ - global $db; - - $forum_parents = array(); - - if ($forum_data['parent_id'] > 0) - { - if ($forum_data['forum_parents'] == '') - { - $sql = 'SELECT forum_id, forum_name, forum_type - FROM ' . FORUMS_TABLE . ' - WHERE left_id < ' . $forum_data['left_id'] . ' - AND right_id > ' . $forum_data['right_id'] . ' - ORDER BY left_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_parents[$row['forum_id']] = array($row['forum_name'], (int) $row['forum_type']); - } - $db->sql_freeresult($result); - - $forum_data['forum_parents'] = serialize($forum_parents); - - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_parents = '" . $db->sql_escape($forum_data['forum_parents']) . "' - WHERE parent_id = " . $forum_data['parent_id']; - $db->sql_query($sql); - } - else - { - $forum_parents = unserialize($forum_data['forum_parents']); - } - } - - return $forum_parents; -} - -/** -* Obtain list of moderators of each forum -*/ -function get_moderators(&$forum_moderators, $forum_id = false) -{ - global $db, $phpbb_root_path, $phpEx, $user, $auth; - global $phpbb_container; - - $forum_id_ary = array(); - - if ($forum_id !== false) - { - if (!is_array($forum_id)) - { - $forum_id = array($forum_id); - } - - // Exchange key/value pair to be able to faster check for the forum id existence - $forum_id_ary = array_flip($forum_id); - } - - $sql_array = array( - 'SELECT' => 'm.*, u.user_colour, g.group_colour, g.group_type', - - 'FROM' => array( - MODERATOR_CACHE_TABLE => 'm', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(USERS_TABLE => 'u'), - 'ON' => 'm.user_id = u.user_id', - ), - array( - 'FROM' => array(GROUPS_TABLE => 'g'), - 'ON' => 'm.group_id = g.group_id', - ), - ), - - '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); - - while ($row = $db->sql_fetchrow($result)) - { - $f_id = (int) $row['forum_id']; - - if (!isset($forum_id_ary[$f_id])) - { - continue; - } - - if (!empty($row['user_id'])) - { - $forum_moderators[$f_id][] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']); - } - else - { - $group_name = $group_helper->get_name($row['group_name']); - - if ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')) - { - $forum_moderators[$f_id][] = '' . $group_name . ''; - } - else - { - $forum_moderators[$f_id][] = '' . $group_name . ''; - } - } - } - $db->sql_freeresult($result); - - return; -} - -/** -* User authorisation levels output -* -* @param string $mode Can be forum or topic. Not in use at the moment. -* @param int $forum_id The current forum the user is in. -* @param int $forum_status The forums status bit. -*/ -function gen_forum_auth_level($mode, $forum_id, $forum_status) -{ - global $template, $auth, $user, $config; - - $locked = ($forum_status == ITEM_LOCKED && !$auth->acl_get('m_edit', $forum_id)) ? true : false; - - $rules = array( - ($auth->acl_get('f_post', $forum_id) && !$locked) ? $user->lang['RULES_POST_CAN'] : $user->lang['RULES_POST_CANNOT'], - ($auth->acl_get('f_reply', $forum_id) && !$locked) ? $user->lang['RULES_REPLY_CAN'] : $user->lang['RULES_REPLY_CANNOT'], - ($user->data['is_registered'] && $auth->acl_gets('f_edit', 'm_edit', $forum_id) && !$locked) ? $user->lang['RULES_EDIT_CAN'] : $user->lang['RULES_EDIT_CANNOT'], - ($user->data['is_registered'] && ($auth->acl_gets('f_delete', 'm_delete', $forum_id) || $auth->acl_gets('f_softdelete', 'm_softdelete', $forum_id)) && !$locked) ? $user->lang['RULES_DELETE_CAN'] : $user->lang['RULES_DELETE_CANNOT'], - ); - - if ($config['allow_attachments']) - { - $rules[] = ($auth->acl_get('f_attach', $forum_id) && $auth->acl_get('u_attach') && !$locked) ? $user->lang['RULES_ATTACH_CAN'] : $user->lang['RULES_ATTACH_CANNOT']; - } - - foreach ($rules as $rule) - { - $template->assign_block_vars('rules', array('RULE' => $rule)); - } - - return; -} - -/** -* Generate topic status -*/ -function topic_status(&$topic_row, $replies, $unread_topic, &$folder_img, &$folder_alt, &$topic_type) -{ - global $user, $config; - - if ($topic_row['topic_status'] == ITEM_MOVED) - { - $topic_type = $user->lang['VIEW_TOPIC_MOVED']; - $folder_img = 'topic_moved'; - $folder_alt = 'TOPIC_MOVED'; - } - else - { - switch ($topic_row['topic_type']) - { - case POST_GLOBAL: - $topic_type = $user->lang['VIEW_TOPIC_GLOBAL']; - $folder = 'global_read'; - $folder_new = 'global_unread'; - break; - - case POST_ANNOUNCE: - $topic_type = $user->lang['VIEW_TOPIC_ANNOUNCEMENT']; - $folder = 'announce_read'; - $folder_new = 'announce_unread'; - break; - - case POST_STICKY: - $topic_type = $user->lang['VIEW_TOPIC_STICKY']; - $folder = 'sticky_read'; - $folder_new = 'sticky_unread'; - break; - - default: - $topic_type = ''; - $folder = 'topic_read'; - $folder_new = 'topic_unread'; - - // Hot topic threshold is for posts in a topic, which is replies + the first post. ;) - if ($config['hot_threshold'] && ($replies + 1) >= $config['hot_threshold'] && $topic_row['topic_status'] != ITEM_LOCKED) - { - $folder .= '_hot'; - $folder_new .= '_hot'; - } - break; - } - - if ($topic_row['topic_status'] == ITEM_LOCKED) - { - $topic_type = $user->lang['VIEW_TOPIC_LOCKED']; - $folder .= '_locked'; - $folder_new .= '_locked'; - } - - $folder_img = ($unread_topic) ? $folder_new : $folder; - $folder_alt = ($unread_topic) ? 'UNREAD_POSTS' : (($topic_row['topic_status'] == ITEM_LOCKED) ? 'TOPIC_LOCKED' : 'NO_UNREAD_POSTS'); - - // Posted image? - if (!empty($topic_row['topic_posted']) && $topic_row['topic_posted']) - { - $folder_img .= '_mine'; - } - } - - if ($topic_row['poll_start'] && $topic_row['topic_status'] != ITEM_MOVED) - { - $topic_type = $user->lang['VIEW_TOPIC_POLL']; - } -} - -/** -* Assign/Build custom bbcodes for display in screens supporting using of bbcodes -* The custom bbcodes buttons will be placed within the template block 'custom_tags' -*/ -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 = NUM_PREDEFINED_BBCODES; - - $sql_ary = array( - 'SELECT' => 'b.bbcode_id, b.bbcode_tag, b.bbcode_helpline', - 'FROM' => array(BBCODES_TABLE => 'b'), - 'WHERE' => 'b.display_on_posting = 1', - 'ORDER_BY' => 'b.bbcode_tag', - ); - - /** - * Event to modify the SQL query before custom bbcode data is queried - * - * @event core.display_custom_bbcodes_modify_sql - * @var array sql_ary The SQL array to get the bbcode data - * @var int num_predefined_bbcodes The number of predefined core bbcodes - * (multiplied by factor of 2) - * @since 3.1.0-a3 - */ - $vars = array('sql_ary', 'num_predefined_bbcodes'); - extract($phpbb_dispatcher->trigger_event('core.display_custom_bbcodes_modify_sql', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - - $i = 0; - while ($row = $db->sql_fetchrow($result)) - { - // If the helpline is defined within the language file, we will use the localised version, else just use the database entry... - if (isset($user->lang[strtoupper($row['bbcode_helpline'])])) - { - $row['bbcode_helpline'] = $user->lang[strtoupper($row['bbcode_helpline'])]; - } - - $custom_tags = array( - 'BBCODE_NAME' => "'[{$row['bbcode_tag']}]', '[/" . str_replace('=', '', $row['bbcode_tag']) . "]'", - 'BBCODE_ID' => $num_predefined_bbcodes + ($i * 2), - 'BBCODE_TAG' => $row['bbcode_tag'], - 'BBCODE_TAG_CLEAN' => str_replace('=', '-', $row['bbcode_tag']), - 'BBCODE_HELPLINE' => $row['bbcode_helpline'], - 'A_BBCODE_HELPLINE' => str_replace(array('&', '"', "'", '<', '>'), array('&', '"', "\'", '<', '>'), $row['bbcode_helpline']), - ); - - /** - * Event to modify the template data block of a custom bbcode - * - * This event is triggered once per bbcode - * - * @event core.display_custom_bbcodes_modify_row - * @var array custom_tags Template data of the bbcode - * @var array row The data of the bbcode - * @since 3.1.0-a1 - */ - $vars = array('custom_tags', 'row'); - extract($phpbb_dispatcher->trigger_event('core.display_custom_bbcodes_modify_row', compact($vars))); - - $template->assign_block_vars('custom_tags', $custom_tags); - - $i++; - } - $db->sql_freeresult($result); - - /** - * Display custom bbcodes - * - * @event core.display_custom_bbcodes - * @since 3.1.0-a1 - */ - $phpbb_dispatcher->dispatch('core.display_custom_bbcodes'); -} - -/** -* Display reasons -* -* @deprecated 3.2.0-dev -*/ -function display_reasons($reason_id = 0) -{ - global $phpbb_container; - - $phpbb_container->get('phpbb.report.report_reason_list_provider')->display_reasons($reason_id); -} - -/** -* Display user activity (action forum/topic) -*/ -function display_user_activity(&$userdata_ary) -{ - global $auth, $template, $db, $user, $config; - global $phpbb_root_path, $phpEx; - global $phpbb_container, $phpbb_dispatcher; - - // 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; - } - - $forum_ary = array(); - - $forum_read_ary = $auth->acl_getf('f_read'); - foreach ($forum_read_ary as $forum_id => $allowed) - { - if ($allowed['f_read']) - { - $forum_ary[] = (int) $forum_id; - } - } - - $forum_ary = array_diff($forum_ary, $user->get_passworded_forums()); - - $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_ary['user_id'] . ' - AND post_postcount = 1 - AND ' . $phpbb_content_visibility->get_forums_visibility_sql('post', $forum_ary) . ' - GROUP BY forum_id - ORDER BY num_posts DESC'; - $result = $db->sql_query_limit($sql, 1); - $active_f_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!empty($active_f_row)) - { - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $active_f_row['forum_id']; - $result = $db->sql_query($sql, 3600); - $active_f_row['forum_name'] = (string) $db->sql_fetchfield('forum_name'); - $db->sql_freeresult($result); - } - - // Obtain active topic - $sql = 'SELECT topic_id, COUNT(post_id) AS num_posts - FROM ' . POSTS_TABLE . ' - 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 - ORDER BY num_posts DESC'; - $result = $db->sql_query_limit($sql, 1); - $active_t_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!empty($active_t_row)) - { - $sql = 'SELECT topic_title - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $active_t_row['topic_id']; - $result = $db->sql_query($sql); - $active_t_row['topic_title'] = (string) $db->sql_fetchfield('topic_title'); - $db->sql_freeresult($result); - } - } - - $userdata = $userdata_ary; - $show_user_activity = true; - /** - * Alter list of forums and topics to display as active - * - * @event core.display_user_activity_modify_actives - * @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', 'show_user_activity'); - extract($phpbb_dispatcher->trigger_event('core.display_user_activity_modify_actives', compact($vars))); - $userdata_ary = $userdata; - unset($userdata); - - $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'])) - { - $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_ary['user_posts']) ? ($active_f_count / $userdata_ary['user_posts']) * 100 : 0; - } - - $active_t_name = $active_t_id = $active_t_count = $active_t_pct = ''; - if (!empty($active_t_row['num_posts'])) - { - $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_ary['user_posts']) ? ($active_t_count / $userdata_ary['user_posts']) * 100 : 0; - } - - $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, - 'ACTIVE_FORUM_POSTS' => $user->lang('USER_POSTS', (int) $active_f_count), - 'ACTIVE_FORUM_PCT' => sprintf($l_active_pct, $active_f_pct), - 'ACTIVE_TOPIC' => censor_text($active_t_name), - 'ACTIVE_TOPIC_POSTS' => $user->lang('USER_POSTS', (int) $active_t_count), - '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' => $show_user_activity) - ); -} - -/** -* Topic and forum watching common code -*/ -function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $notify_status = 'unset', $start = 0, $item_title = '') -{ - global $db, $user, $phpEx, $start, $phpbb_root_path; - global $request; - - $table_sql = ($mode == 'forum') ? FORUMS_WATCH_TABLE : TOPICS_WATCH_TABLE; - $where_sql = ($mode == 'forum') ? 'forum_id' : 'topic_id'; - $match_id = ($mode == 'forum') ? $forum_id : $topic_id; - $u_url = "uid={$user->data['user_id']}"; - $u_url .= ($mode == 'forum') ? '&f' : '&f=' . $forum_id . '&t'; - $is_watching = 0; - - // Is user watching this topic? - if ($user_id != ANONYMOUS) - { - $can_watch = true; - - if ($notify_status == 'unset') - { - $sql = "SELECT notify_status - FROM $table_sql - WHERE $where_sql = $match_id - AND user_id = $user_id"; - $result = $db->sql_query($sql); - - $notify_status = ($row = $db->sql_fetchrow($result)) ? $row['notify_status'] : NULL; - $db->sql_freeresult($result); - } - - if (!is_null($notify_status) && $notify_status !== '') - { - if (isset($_GET['unwatch'])) - { - $uid = $request->variable('uid', 0); - $token = $request->variable('hash', ''); - - if ($token && check_link_hash($token, "{$mode}_$match_id") || confirm_box(true)) - { - if ($uid != $user_id || $request->variable('unwatch', '', false, \phpbb\request\request_interface::GET) != $mode) - { - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ERR_UNWATCHING']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_' . strtoupper($mode), '', ''); - } - trigger_error($message); - } - - $sql = 'DELETE FROM ' . $table_sql . " - WHERE $where_sql = $match_id - AND user_id = $user_id"; - $db->sql_query($sql); - - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['NOT_WATCHING_' . strtoupper($mode)]; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_' . strtoupper($mode), '', ''); - } - meta_refresh(3, $redirect_url); - trigger_error($message); - } - else - { - $s_hidden_fields = array( - 'uid' => $user->data['user_id'], - 'unwatch' => $mode, - 'start' => $start, - 'f' => $forum_id, - ); - if ($mode != 'forum') - { - $s_hidden_fields['t'] = $topic_id; - } - - if ($item_title == '') - { - $confirm_box_message = 'UNWATCH_' . strtoupper($mode); - } - else - { - $confirm_box_message = $user->lang('UNWATCH_' . strtoupper($mode) . '_DETAILED', $item_title); - } - confirm_box(false, $confirm_box_message, build_hidden_fields($s_hidden_fields)); - } - } - else - { - $is_watching = true; - - if ($notify_status != NOTIFY_YES) - { - $sql = 'UPDATE ' . $table_sql . " - SET notify_status = " . NOTIFY_YES . " - WHERE $where_sql = $match_id - AND user_id = $user_id"; - $db->sql_query($sql); - } - } - } - else - { - if (isset($_GET['watch'])) - { - $uid = $request->variable('uid', 0); - $token = $request->variable('hash', ''); - - if ($token && check_link_hash($token, "{$mode}_$match_id") || confirm_box(true)) - { - if ($uid != $user_id || $request->variable('watch', '', false, \phpbb\request\request_interface::GET) != $mode) - { - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ERR_WATCHING']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_' . strtoupper($mode), '', ''); - } - trigger_error($message); - } - - $is_watching = true; - - $sql = 'INSERT INTO ' . $table_sql . " (user_id, $where_sql, notify_status) - VALUES ($user_id, $match_id, " . NOTIFY_YES . ')'; - $db->sql_query($sql); - - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ARE_WATCHING_' . strtoupper($mode)]; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_' . strtoupper($mode), '', ''); - } - meta_refresh(3, $redirect_url); - trigger_error($message); - } - else - { - $s_hidden_fields = array( - 'uid' => $user->data['user_id'], - 'watch' => $mode, - 'start' => $start, - 'f' => $forum_id, - ); - if ($mode != 'forum') - { - $s_hidden_fields['t'] = $topic_id; - } - - $confirm_box_message = (($item_title == '') ? 'WATCH_' . strtoupper($mode) : $user->lang('WATCH_' . strtoupper($mode) . '_DETAILED', $item_title)); - confirm_box(false, $confirm_box_message, build_hidden_fields($s_hidden_fields)); - } - } - else - { - $is_watching = 0; - } - } - } - else - { - if ((isset($_GET['unwatch']) && $request->variable('unwatch', '', false, \phpbb\request\request_interface::GET) == $mode) || - (isset($_GET['watch']) && $request->variable('watch', '', false, \phpbb\request\request_interface::GET) == $mode)) - { - login_box(); - } - else - { - $can_watch = 0; - $is_watching = 0; - } - } - - if ($can_watch) - { - $s_watching['link'] = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&" . (($is_watching) ? 'unwatch' : 'watch') . "=$mode&start=$start&hash=" . generate_link_hash("{$mode}_$match_id")); - $s_watching['link_toggle'] = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&" . ((!$is_watching) ? 'unwatch' : 'watch') . "=$mode&start=$start&hash=" . generate_link_hash("{$mode}_$match_id")); - $s_watching['title'] = $user->lang[(($is_watching) ? 'STOP' : 'START') . '_WATCHING_' . strtoupper($mode)]; - $s_watching['title_toggle'] = $user->lang[((!$is_watching) ? 'STOP' : 'START') . '_WATCHING_' . strtoupper($mode)]; - $s_watching['is_watching'] = $is_watching; - } - - return; -} - -/** -* Get user rank title and image -* -* @param array $user_data the current stored users data -* @param int $user_posts the users number of posts -* -* @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) -* -* Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false -*/ -function phpbb_get_user_rank($user_data, $user_posts) -{ - global $ranks, $config, $phpbb_root_path, $phpbb_path_helper, $phpbb_dispatcher; - - $user_rank_data = array( - 'title' => null, - 'img' => null, - 'img_src' => null, - ); - - /** - * Preparing a user's rank before displaying - * - * @event core.modify_user_rank - * @var array user_data Array with user's data - * @var int user_posts User_posts to change - * @since 3.1.0-RC4 - */ - - $vars = array('user_data', 'user_posts'); - extract($phpbb_dispatcher->trigger_event('core.modify_user_rank', compact($vars))); - - if (empty($ranks)) - { - global $cache; - $ranks = $cache->obtain_ranks(); - } - - if (!empty($user_data['user_rank'])) - { - - $user_rank_data['title'] = (isset($ranks['special'][$user_data['user_rank']]['rank_title'])) ? $ranks['special'][$user_data['user_rank']]['rank_title'] : ''; - - $user_rank_data['img_src'] = (!empty($ranks['special'][$user_data['user_rank']]['rank_image'])) ? $phpbb_path_helper->update_web_root_path($phpbb_root_path . $config['ranks_path'] . '/' . $ranks['special'][$user_data['user_rank']]['rank_image']) : ''; - - $user_rank_data['img'] = (!empty($ranks['special'][$user_data['user_rank']]['rank_image'])) ? '' . $ranks['special'][$user_data['user_rank']]['rank_title'] . '' : ''; - } - else if ($user_posts !== false) - { - if (!empty($ranks['normal'])) - { - foreach ($ranks['normal'] as $rank) - { - if ($user_posts >= $rank['rank_min']) - { - $user_rank_data['title'] = $rank['rank_title']; - $user_rank_data['img_src'] = (!empty($rank['rank_image'])) ? $phpbb_path_helper->update_web_root_path($phpbb_root_path . $config['ranks_path'] . '/' . $rank['rank_image']) : ''; - $user_rank_data['img'] = (!empty($rank['rank_image'])) ? '' . $rank['rank_title'] . '' : ''; - break; - } - } - } - } - - /** - * Modify a user's rank before displaying - * - * @event core.get_user_rank_after - * @var array user_data Array with user's data - * @var int user_posts User_posts to change - * @var array user_rank_data User rank data - * @since 3.1.11-RC1 - */ - - $vars = array( - 'user_data', - 'user_posts', - 'user_rank_data', - ); - extract($phpbb_dispatcher->trigger_event('core.get_user_rank_after', compact($vars))); - - return $user_rank_data; -} - -/** -* Prepare profile data -*/ -function phpbb_show_profile($data, $user_notes_enabled = false, $warn_user_enabled = false, $check_can_receive_pm = true) -{ - global $config, $auth, $user, $phpEx, $phpbb_root_path, $phpbb_dispatcher; - - $username = $data['username']; - $user_id = $data['user_id']; - - $user_rank_data = phpbb_get_user_rank($data, (($user_id == ANONYMOUS) ? false : $data['user_posts'])); - - if ((!empty($data['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_user')) - { - $email = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=email&u=' . $user_id) : (($config['board_hide_emails'] && !$auth->acl_get('a_user')) ? '' : 'mailto:' . $data['user_email']); - } - else - { - $email = ''; - } - - if ($config['load_onlinetrack']) - { - $update_time = $config['load_online_time'] * 60; - $online = (time() - $update_time < $data['session_time'] && ((isset($data['session_viewonline']) && $data['session_viewonline']) || $auth->acl_get('u_viewonline'))) ? true : false; - } - else - { - $online = false; - } - - if ($data['user_allow_viewonline'] || $auth->acl_get('u_viewonline')) - { - $last_active = (!empty($data['session_time'])) ? $data['session_time'] : $data['user_lastvisit']; - } - else - { - $last_active = ''; - } - - $age = ''; - - if ($config['allow_birthdays'] && $data['user_birthday']) - { - list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $data['user_birthday'])); - - if ($bday_year) - { - $now = $user->create_datetime(); - $now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset()); - - $diff = $now['mon'] - $bday_month; - if ($diff == 0) - { - $diff = ($now['mday'] - $bday_day < 0) ? 1 : 0; - } - else - { - $diff = ($diff < 0) ? 1 : 0; - } - - $age = max(0, (int) ($now['year'] - $bday_year - $diff)); - } - } - - if (!function_exists('phpbb_get_banned_user_ids')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - // Can this user receive a Private Message? - $can_receive_pm = $check_can_receive_pm && ( - // They must be a "normal" user - $data['user_type'] != USER_IGNORE && - - // They must not be deactivated by the administrator - ($data['user_type'] != USER_INACTIVE || $data['user_inactive_reason'] != INACTIVE_MANUAL) && - - // They must be able to read PMs - count($auth->acl_get_list($user_id, 'u_readpm')) && - - // They must not be permanently banned - !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']) - ); - - // Dump it out to the template - $template_data = array( - 'AGE' => $age, - 'RANK_TITLE' => $user_rank_data['title'], - 'JOINED' => $user->format_date($data['user_regdate']), - 'LAST_ACTIVE' => (empty($last_active)) ? ' - ' : $user->format_date($last_active), - 'POSTS' => ($data['user_posts']) ? $data['user_posts'] : 0, - 'WARNINGS' => isset($data['user_warnings']) ? $data['user_warnings'] : 0, - - 'USERNAME_FULL' => get_username_string('full', $user_id, $username, $data['user_colour']), - 'USERNAME' => get_username_string('username', $user_id, $username, $data['user_colour']), - 'USER_COLOR' => get_username_string('colour', $user_id, $username, $data['user_colour']), - 'U_VIEW_PROFILE' => get_username_string('profile', $user_id, $username, $data['user_colour']), - - 'A_USERNAME' => addslashes(get_username_string('username', $user_id, $username, $data['user_colour'])), - - 'AVATAR_IMG' => phpbb_get_user_avatar($data), - 'ONLINE_IMG' => (!$config['load_onlinetrack']) ? '' : (($online) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')), - 'S_ONLINE' => ($config['load_onlinetrack'] && $online) ? true : false, - 'RANK_IMG' => $user_rank_data['img'], - 'RANK_IMG_SRC' => $user_rank_data['img_src'], - 'S_JABBER_ENABLED' => ($config['jab_enable']) ? true : false, - - 'S_WARNINGS' => ($auth->acl_getf_global('m_') || $auth->acl_get('m_warn')) ? true : false, - - 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$user_id&sr=posts") : '', - 'U_NOTES' => ($user_notes_enabled && $auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $user_id, true, $user->session_id) : '', - 'U_WARN' => ($warn_user_enabled && $auth->acl_get('m_warn')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $user_id, true, $user->session_id) : '', - 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $user_id) : '', - 'U_EMAIL' => $email, - 'U_JABBER' => ($data['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=jabber&u=' . $user_id) : '', - - 'USER_JABBER' => ($config['jab_enable']) ? $data['user_jabber'] : '', - 'USER_JABBER_IMG' => ($config['jab_enable'] && $data['user_jabber']) ? $user->img('icon_contact_jabber', $data['user_jabber']) : '', - - 'L_SEND_EMAIL_USER' => $user->lang('SEND_EMAIL_USER', $username), - 'L_CONTACT_USER' => $user->lang('CONTACT_USER', $username), - 'L_VIEWING_PROFILE' => $user->lang('VIEWING_PROFILE', $username), - ); - - /** - * Preparing a user's data before displaying it in profile and memberlist - * - * @event core.memberlist_prepare_profile_data - * @var array data Array with user's data - * @var array template_data Template array with user's data - * @since 3.1.0-a1 - */ - $vars = array('data', 'template_data'); - extract($phpbb_dispatcher->trigger_event('core.memberlist_prepare_profile_data', compact($vars))); - - return $template_data; -} - -function phpbb_sort_last_active($first, $second) -{ - global $id_cache, $sort_dir; - - $lesser_than = ($sort_dir === 'd') ? -1 : 1; - - if (isset($id_cache[$first]['group_leader']) && $id_cache[$first]['group_leader'] && (!isset($id_cache[$second]['group_leader']) || !$id_cache[$second]['group_leader'])) - { - return -1; - } - else if (isset($id_cache[$second]['group_leader']) && (!isset($id_cache[$first]['group_leader']) || !$id_cache[$first]['group_leader']) && $id_cache[$second]['group_leader']) - { - return 1; - } - else - { - return $lesser_than * (int) ($id_cache[$first]['last_visit'] - $id_cache[$second]['last_visit']); - } -} diff --git a/install/update/old/includes/functions_download.php b/install/update/old/includes/functions_download.php deleted file mode 100644 index 7be12ba..0000000 --- a/install/update/old/includes/functions_download.php +++ /dev/null @@ -1,790 +0,0 @@ - -* @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 simplified function to deliver avatars -* The argument needs to be checked before calling this function. -*/ -function send_avatar_to_browser($file, $browser) -{ - global $config, $phpbb_root_path; - - $prefix = $config['avatar_salt'] . '_'; - $image_dir = $config['avatar_path']; - - // Adjust image_dir path (no trailing slash) - if (substr($image_dir, -1, 1) == '/' || substr($image_dir, -1, 1) == '\\') - { - $image_dir = substr($image_dir, 0, -1) . '/'; - } - $image_dir = str_replace(array('../', '..\\', './', '.\\'), '', $image_dir); - - if ($image_dir && ($image_dir[0] == '/' || $image_dir[0] == '\\')) - { - $image_dir = ''; - } - $file_path = $phpbb_root_path . $image_dir . '/' . $prefix . $file; - - if ((@file_exists($file_path) && @is_readable($file_path)) && !headers_sent()) - { - header('Cache-Control: public'); - - $image_data = @getimagesize($file_path); - header('Content-Type: ' . image_type_to_mime_type($image_data[2])); - - if ((strpos(strtolower($browser), 'msie') !== false) && !phpbb_is_greater_ie_version($browser, 7)) - { - header('Content-Disposition: attachment; ' . header_filename($file)); - - if (strpos(strtolower($browser), 'msie 6.0') !== false) - { - header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); - } - else - { - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); - } - } - else - { - header('Content-Disposition: inline; ' . header_filename($file)); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); - } - - $size = @filesize($file_path); - if ($size) - { - header("Content-Length: $size"); - } - - if (@readfile($file_path) == false) - { - $fp = @fopen($file_path, 'rb'); - - if ($fp !== false) - { - while (!feof($fp)) - { - echo fread($fp, 8192); - } - fclose($fp); - } - } - - flush(); - } - else - { - header('HTTP/1.0 404 Not Found'); - } -} - -/** -* Wraps an url into a simple html page. Used to display attachments in IE. -* this is a workaround for now; might be moved to template system later -* direct any complaints to 1 Microsoft Way, Redmond -*/ -function wrap_img_in_html($src, $title) -{ - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '' . $title . ''; - echo ''; - echo ''; - echo '
'; - echo '' . $title . ''; - echo '
'; - echo ''; - echo ''; -} - -/** -* Send file to browser -*/ -function send_file_to_browser($attachment, $upload_dir, $category) -{ - global $user, $db, $phpbb_dispatcher, $phpbb_root_path, $request; - - $filename = $phpbb_root_path . $upload_dir . '/' . $attachment['physical_filename']; - - if (!@file_exists($filename)) - { - send_status_line(404, 'Not Found'); - trigger_error('ERROR_NO_ATTACHMENT'); - } - - // Correct the mime type - we force application/octetstream for all files, except images - // Please do not change this, it is a security precaution - if ($category != ATTACHMENT_CATEGORY_IMAGE || strpos($attachment['mimetype'], 'image') !== 0) - { - $attachment['mimetype'] = (strpos(strtolower($user->browser), 'msie') !== false || strpos(strtolower($user->browser), 'opera') !== false) ? 'application/octetstream' : 'application/octet-stream'; - } - - if (@ob_get_length()) - { - @ob_end_clean(); - } - - // Now send the File Contents to the Browser - $size = @filesize($filename); - - /** - * Event to alter attachment before it is sent to browser. - * - * @event core.send_file_to_browser_before - * @var array attachment Attachment data - * @var string upload_dir Relative path of upload directory - * @var int category Attachment category - * @var string filename Path to file, including filename - * @var int size File size - * @since 3.1.11-RC1 - */ - $vars = array( - 'attachment', - 'upload_dir', - 'category', - 'filename', - 'size', - ); - extract($phpbb_dispatcher->trigger_event('core.send_file_to_browser_before', compact($vars))); - - // To correctly display further errors we need to make sure we are using the correct headers for both (unsetting content-length may not work) - - // Check if headers already sent or not able to get the file contents. - if (headers_sent() || !@file_exists($filename) || !@is_readable($filename)) - { - // PHP track_errors setting On? - if (!empty($php_errormsg)) - { - send_status_line(500, 'Internal Server Error'); - trigger_error($user->lang['UNABLE_TO_DELIVER_FILE'] . '
' . sprintf($user->lang['TRACKED_PHP_ERROR'], $php_errormsg)); - } - - send_status_line(500, 'Internal Server Error'); - trigger_error('UNABLE_TO_DELIVER_FILE'); - } - - // Make sure the database record for the filesize is correct - if ($size > 0 && $size != $attachment['filesize'] && strpos($attachment['physical_filename'], 'thumb_') === false) - { - // Update database record - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET filesize = ' . (int) $size . ' - WHERE attach_id = ' . (int) $attachment['attach_id']; - $db->sql_query($sql); - } - - // Now the tricky part... let's dance - header('Cache-Control: public'); - - // 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']); - - if (phpbb_is_greater_ie_version($user->browser, 7)) - { - header('X-Content-Type-Options: nosniff'); - } - - 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'); - } - else - { - if (empty($user->browser) || ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7))) - { - header('Content-Disposition: attachment; ' . header_filename(htmlspecialchars_decode($attachment['real_filename']))); - if (empty($user->browser) || (strpos(strtolower($user->browser), 'msie 6.0') !== false)) - { - header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); - } - } - else - { - header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(htmlspecialchars_decode($attachment['real_filename']))); - if (phpbb_is_greater_ie_version($user->browser, 7) && (strpos($attachment['mimetype'], 'image') !== 0)) - { - header('X-Download-Options: noopen'); - } - } - } - - // Close the db connection before sending the file etc. - file_gc(false); - - if (!set_modified_headers($attachment['filetime'], $user->browser)) - { - // We make sure those have to be enabled manually by defining a constant - // because of the potential disclosure of full attachment path - // in case support for features is absent in the webserver software. - if (defined('PHPBB_ENABLE_X_ACCEL_REDIRECT') && PHPBB_ENABLE_X_ACCEL_REDIRECT) - { - // X-Accel-Redirect - http://wiki.nginx.org/XSendfile - header('X-Accel-Redirect: ' . $user->page['root_script_path'] . $upload_dir . '/' . $attachment['physical_filename']); - exit; - } - else if (defined('PHPBB_ENABLE_X_SENDFILE') && PHPBB_ENABLE_X_SENDFILE && !phpbb_http_byte_range($size)) - { - // X-Sendfile - http://blog.lighttpd.net/articles/2006/07/02/x-sendfile - // Lighttpd's X-Sendfile does not support range requests as of 1.4.26 - // and always requires an absolute path. - header('X-Sendfile: ' . dirname(__FILE__) . "/../$upload_dir/{$attachment['physical_filename']}"); - exit; - } - - if ($size) - { - header("Content-Length: $size"); - } - - // Try to deliver in chunks - @set_time_limit(0); - - $fp = @fopen($filename, 'rb'); - - if ($fp !== false) - { - // Deliver file partially if requested - if ($range = phpbb_http_byte_range($size)) - { - fseek($fp, $range['byte_pos_start']); - - 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']); - - // 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 - { - while (!feof($fp)) - { - echo fread($fp, 8192); - } - } - fclose($fp); - } - else - { - @readfile($filename); - } - - flush(); - } - - exit; -} - -/** -* Get a browser friendly UTF-8 encoded filename -*/ -function header_filename($file) -{ - global $request; - - $user_agent = $request->header('User-Agent'); - - // There be dragons here. - // Not many follows the RFC... - if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Konqueror') !== false) - { - return "filename=" . rawurlencode($file); - } - - // follow the RFC for extended filename for the rest - return "filename*=UTF-8''" . rawurlencode($file); -} - -/** -* Check if downloading item is allowed -*/ -function download_allowed() -{ - global $config, $user, $db, $request; - - if (!$config['secure_downloads']) - { - return true; - } - - $url = htmlspecialchars_decode($request->header('Referer')); - - if (!$url) - { - return ($config['secure_allow_empty_referer']) ? true : false; - } - - // Split URL into domain and script part - $url = @parse_url($url); - - if ($url === false) - { - return ($config['secure_allow_empty_referer']) ? true : false; - } - - $hostname = $url['host']; - unset($url); - - $allowed = ($config['secure_allow_deny']) ? false : true; - $iplist = array(); - - if (($ip_ary = @gethostbynamel($hostname)) !== false) - { - foreach ($ip_ary as $ip) - { - if ($ip) - { - $iplist[] = $ip; - } - } - } - - // Check for own server... - $server_name = $user->host; - - // Forcing server vars is the only way to specify/override the protocol - if ($config['force_server_vars'] || !$server_name) - { - $server_name = $config['server_name']; - } - - if (preg_match('#^.*?' . preg_quote($server_name, '#') . '.*?$#i', $hostname)) - { - $allowed = true; - } - - // Get IP's and Hostnames - if (!$allowed) - { - $sql = 'SELECT site_ip, site_hostname, ip_exclude - FROM ' . SITELIST_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $site_ip = trim($row['site_ip']); - $site_hostname = trim($row['site_hostname']); - - if ($site_ip) - { - foreach ($iplist as $ip) - { - if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_ip, '#')) . '$#i', $ip)) - { - if ($row['ip_exclude']) - { - $allowed = ($config['secure_allow_deny']) ? false : true; - break 2; - } - else - { - $allowed = ($config['secure_allow_deny']) ? true : false; - } - } - } - } - - if ($site_hostname) - { - if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_hostname, '#')) . '$#i', $hostname)) - { - if ($row['ip_exclude']) - { - $allowed = ($config['secure_allow_deny']) ? false : true; - break; - } - else - { - $allowed = ($config['secure_allow_deny']) ? true : false; - } - } - } - } - $db->sql_freeresult($result); - } - - return $allowed; -} - -/** -* Check if the browser has the file already and set the appropriate headers- -* @returns false if a resend is in order. -*/ -function set_modified_headers($stamp, $browser) -{ - global $request; - - // let's see if we have to send the file at all - $last_load = $request->header('If-Modified-Since') ? strtotime(trim($request->header('If-Modified-Since'))) : false; - - if (strpos(strtolower($browser), 'msie 6.0') === false && !phpbb_is_greater_ie_version($browser, 7)) - { - if ($last_load !== false && $last_load >= $stamp) - { - send_status_line(304, 'Not Modified'); - // seems that we need those too ... browsers - header('Cache-Control: public'); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); - return true; - } - else - { - header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT'); - } - } - return false; -} - -/** -* Garbage Collection -* -* @param bool $exit Whether to die or not. -* -* @return null -*/ -function file_gc($exit = true) -{ - global $cache, $db; - - if (!empty($cache)) - { - $cache->unload(); - } - - $db->sql_close(); - - if ($exit) - { - exit; - } -} - -/** -* HTTP range support (RFC 2616 Section 14.35) -* -* Allows browsers to request partial file content -* in case a download has been interrupted. -* -* @param int $filesize the size of the file in bytes we are about to deliver -* -* @return mixed false if the whole file has to be delivered -* associative array on success -*/ -function phpbb_http_byte_range($filesize) -{ - // Only call find_range_request() once. - static $request_array; - - if (!$filesize) - { - return false; - } - - if (!isset($request_array)) - { - $request_array = phpbb_find_range_request(); - } - - return (empty($request_array)) ? false : phpbb_parse_range_request($request_array, $filesize); -} - -/** -* Searches for HTTP range request in request headers. -* -* @return mixed false if no request found -* array of strings containing the requested ranges otherwise -* e.g. array(0 => '0-0', 1 => '123-125') -*/ -function phpbb_find_range_request() -{ - global $request; - - $value = $request->header('Range'); - - // Make sure range request starts with "bytes=" - if (strpos($value, 'bytes=') === 0) - { - // Strip leading 'bytes=' - // Multiple ranges can be separated by a comma - return explode(',', substr($value, 6)); - } - - return false; -} - -/** -* Analyses a range request array. -* -* A range request can contain multiple ranges, -* we however only handle the first request and -* only support requests from a given byte to the end of the file. -* -* @param array $request_array array of strings containing the requested ranges -* @param int $filesize the full size of the file in bytes that has been requested -* -* @return mixed false if the whole file has to be delivered -* associative array on success -* byte_pos_start the first byte position, can be passed to fseek() -* byte_pos_end the last byte position -* bytes_requested the number of bytes requested -* bytes_total the full size of the file -*/ -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 (count($range) != 2 || $range[0] === '' && $range[1] === '') - { - continue; - } - - // Substitute defaults - if ($range[0] === '') - { - $range[0] = 0; - } - - if ($range[1] === '') - { - $range[1] = $filesize - 1; - } - - if ($last_byte_pos >= 0 && $last_byte_pos + 1 != $range[0]) - { - // We only support contiguous ranges, no multipart stuff :( - return false; - } - - if ($range[1] && $range[1] < $range[0]) - { - // 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 ($first_byte_pos >= $filesize) - { - // Requested range not satisfiable - return false; - } - - // 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 < 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, - ); -} - -/** -* Increments the download count of all provided attachments -* -* @param \phpbb\db\driver\driver_interface $db The database object -* @param array|int $ids The attach_id of each attachment -* -* @return null -*/ -function phpbb_increment_downloads($db, $ids) -{ - if (!is_array($ids)) - { - $ids = array($ids); - } - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET download_count = download_count + 1 - WHERE ' . $db->sql_in_set('attach_id', $ids); - $db->sql_query($sql); -} - -/** -* Handles authentication when downloading attachments from a post or topic -* -* @param \phpbb\db\driver\driver_interface $db The database object -* @param \phpbb\auth\auth $auth The authentication object -* @param int $topic_id The id of the topic that we are downloading from -* -* @return null -*/ -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( - TOPICS_TABLE => 't', - FORUMS_TABLE => 'f', - ), - 'WHERE' => 't.topic_id = ' . (int) $topic_id . ' - AND t.forum_id = f.forum_id', - ); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $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'); - } - else if ($row && $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id'])) - { - if ($row['forum_password']) - { - // Do something else ... ? - login_forum_box($row); - } - } - else - { - send_status_line(403, 'Forbidden'); - trigger_error('SORRY_AUTH_VIEW_ATTACH'); - } -} - -/** -* Handles authentication when downloading attachments from PMs -* -* @param \phpbb\db\driver\driver_interface $db The database object -* @param \phpbb\auth\auth $auth The authentication object -* @param int $user_id The user id -* @param int $msg_id The id of the PM that we are downloading from -* -* @return null -*/ -function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id) -{ - global $phpbb_dispatcher; - - if (!$auth->acl_get('u_pm_download')) - { - send_status_line(403, 'Forbidden'); - trigger_error('SORRY_AUTH_VIEW_ATTACH'); - } - - $allowed = phpbb_download_check_pm_auth($db, $user_id, $msg_id); - - /** - * Event to modify PM attachments download auth - * - * @event core.modify_pm_attach_download_auth - * @var bool allowed Whether the user is allowed to download from that PM or not - * @var int msg_id The id of the PM to download from - * @var int user_id The user id for auth check - * @since 3.1.11-RC1 - */ - $vars = array('allowed', 'msg_id', 'user_id'); - extract($phpbb_dispatcher->trigger_event('core.modify_pm_attach_download_auth', compact($vars))); - - if (!$allowed) - { - send_status_line(403, 'Forbidden'); - trigger_error('ERROR_NO_ATTACHMENT'); - } -} - -/** -* Checks whether a user can download from a particular PM -* -* @param \phpbb\db\driver\driver_interface $db The database object -* @param int $user_id The user id -* @param int $msg_id The id of the PM that we are downloading from -* -* @return bool Whether the user is allowed to download from that PM or not -*/ -function phpbb_download_check_pm_auth($db, $user_id, $msg_id) -{ - // Check if the attachment is within the users scope... - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE msg_id = ' . (int) $msg_id . ' - AND ( - user_id = ' . (int) $user_id . ' - OR author_id = ' . (int) $user_id . ' - )'; - $result = $db->sql_query_limit($sql, 1); - $allowed = (bool) $db->sql_fetchfield('msg_id'); - $db->sql_freeresult($result); - - return $allowed; -} - -/** -* Check if the browser is internet explorer version 7+ -* -* @param string $user_agent User agent HTTP header -* @param int $version IE version to check against -* -* @return bool true if internet explorer version is greater than $version -*/ -function phpbb_is_greater_ie_version($user_agent, $version) -{ - if (preg_match('/msie (\d+)/', strtolower($user_agent), $matches)) - { - $ie_version = (int) $matches[1]; - return ($ie_version > $version); - } - else - { - return false; - } -} diff --git a/install/update/old/includes/functions_messenger.php b/install/update/old/includes/functions_messenger.php deleted file mode 100644 index 4f0d400..0000000 --- a/install/update/old/includes/functions_messenger.php +++ /dev/null @@ -1,1915 +0,0 @@ - -* @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; -} - -/** -* Messenger -*/ -class messenger -{ - var $msg, $replyto, $from, $subject; - var $addresses = array(); - var $extra_headers = array(); - - var $mail_priority = MAIL_NORMAL_PRIORITY; - var $use_queue = true; - - /** @var \phpbb\template\template */ - protected $template; - - /** - * Constructor - */ - function __construct($use_queue = true) - { - global $config; - - $this->use_queue = (!$config['email_package_size']) ? false : $use_queue; - $this->subject = ''; - } - - /** - * Resets all the data (address, template file, etc etc) to default - */ - function reset() - { - $this->addresses = $this->extra_headers = array(); - $this->msg = $this->replyto = $this->from = ''; - $this->mail_priority = MAIL_NORMAL_PRIORITY; - } - - /** - * Set addresses for to/im as available - * - * @param array $user User row - */ - function set_addresses($user) - { - if (isset($user['user_email']) && $user['user_email']) - { - $this->to($user['user_email'], (isset($user['username']) ? $user['username'] : '')); - } - - if (isset($user['user_jabber']) && $user['user_jabber']) - { - $this->im($user['user_jabber'], (isset($user['username']) ? $user['username'] : '')); - } - } - - /** - * Sets an email address to send to - */ - function to($address, $realname = '') - { - global $config; - - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['to']) ? count($this->addresses['to']) : 0; - - $this->addresses['to'][$pos]['email'] = trim($address); - - // If empty sendmail_path on windows, PHP changes the to line - if (!$config['smtp_delivery'] && DIRECTORY_SEPARATOR == '\\') - { - $this->addresses['to'][$pos]['name'] = ''; - } - else - { - $this->addresses['to'][$pos]['name'] = trim($realname); - } - } - - /** - * Sets an cc address to send to - */ - function cc($address, $realname = '') - { - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['cc']) ? count($this->addresses['cc']) : 0; - $this->addresses['cc'][$pos]['email'] = trim($address); - $this->addresses['cc'][$pos]['name'] = trim($realname); - } - - /** - * Sets an bcc address to send to - */ - function bcc($address, $realname = '') - { - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['bcc']) ? count($this->addresses['bcc']) : 0; - $this->addresses['bcc'][$pos]['email'] = trim($address); - $this->addresses['bcc'][$pos]['name'] = trim($realname); - } - - /** - * Sets a im contact to send to - */ - function im($address, $realname = '') - { - // IM-Addresses could be empty - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['im']) ? count($this->addresses['im']) : 0; - $this->addresses['im'][$pos]['uid'] = trim($address); - $this->addresses['im'][$pos]['name'] = trim($realname); - } - - /** - * Set the reply to address - */ - function replyto($address) - { - $this->replyto = trim($address); - } - - /** - * Set the from address - */ - function from($address) - { - $this->from = trim($address); - } - - /** - * set up subject for mail - */ - function subject($subject = '') - { - $this->subject = trim($subject); - } - - /** - * set up extra mail headers - */ - function headers($headers) - { - $this->extra_headers[] = trim($headers); - } - - /** - * Adds X-AntiAbuse headers - * - * @param array $config Configuration array - * @param user $user A user object - * - * @return null - */ - function anti_abuse_headers($config, $user) - { - $this->headers('X-AntiAbuse: Board servername - ' . mail_encode($config['server_name'])); - $this->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']); - $this->headers('X-AntiAbuse: Username - ' . mail_encode($user->data['username'])); - $this->headers('X-AntiAbuse: User IP - ' . $user->ip); - } - - /** - * Set the email priority - */ - function set_mail_priority($priority = MAIL_NORMAL_PRIORITY) - { - $this->mail_priority = $priority; - } - - /** - * Set email template to use - */ - function template($template_file, $template_lang = '', $template_path = '', $template_dir_prefix = '') - { - global $config, $phpbb_root_path, $user; - - $template_dir_prefix = (!$template_dir_prefix || $template_dir_prefix[0] === '/') ? $template_dir_prefix : '/' . $template_dir_prefix; - - $this->setup_template(); - - if (!trim($template_file)) - { - trigger_error('No template file for emailing set.', E_USER_ERROR); - } - - if (!trim($template_lang)) - { - // fall back to board default language if the user's language is - // missing $template_file. If this does not exist either, - // $this->template->set_filenames will do a trigger_error - $template_lang = basename($config['default_lang']); - } - - $ext_template_paths = array( - array( - 'name' => $template_lang . '_email', - 'ext_path' => 'language/' . $template_lang . '/email' . $template_dir_prefix, - ), - ); - - if ($template_path) - { - $template_paths = array( - $template_path . $template_dir_prefix, - ); - } - else - { - $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $template_path .= $template_lang . '/email'; - - $template_paths = array( - $template_path . $template_dir_prefix, - ); - - $board_language = basename($config['default_lang']); - - // we can only specify default language fallback when the path is not a custom one for which we - // do not know the default language alternative - if ($template_lang !== $board_language) - { - $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $fallback_template_path .= $board_language . '/email'; - - $template_paths[] = $fallback_template_path . $template_dir_prefix; - - $ext_template_paths[] = array( - 'name' => $board_language . '_email', - 'ext_path' => 'language/' . $board_language . '/email' . $template_dir_prefix, - ); - } - // If everything fails just fall back to en template - if ($template_lang !== 'en' && $board_language !== 'en') - { - $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $fallback_template_path .= 'en/email'; - - $template_paths[] = $fallback_template_path . $template_dir_prefix; - - $ext_template_paths[] = array( - 'name' => 'en_email', - 'ext_path' => 'language/en/email' . $template_dir_prefix, - ); - } - } - - $this->set_template_paths($ext_template_paths, $template_paths); - - $this->template->set_filenames(array( - 'body' => $template_file . '.txt', - )); - - return true; - } - - /** - * assign variables to email template - */ - function assign_vars($vars) - { - $this->setup_template(); - - $this->template->assign_vars($vars); - } - - function assign_block_vars($blockname, $vars) - { - $this->setup_template(); - - $this->template->assign_block_vars($blockname, $vars); - } - - /** - * Send the mail out to the recipients set previously in var $this->addresses - * - * @param int $method User notification method NOTIFY_EMAIL|NOTIFY_IM|NOTIFY_BOTH - * @param bool $break Flag indicating if the function only formats the subject - * and the message without sending it - * - * @return bool - */ - function send($method = NOTIFY_EMAIL, $break = false) - { - global $config, $user, $phpbb_dispatcher; - - // We add some standard variables we always use, no need to specify them always - $this->assign_vars(array( - 'U_BOARD' => generate_board_url(), - 'EMAIL_SIG' => str_replace('
', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])), - 'SITENAME' => htmlspecialchars_decode($config['sitename']), - )); - - $subject = $this->subject; - $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 after parsing - * - * @event core.modify_notification_message - * @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 string message The message text - * @since 3.1.11-RC1 - */ - $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, $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); - - // We now try and pull a subject from the email body ... if it exists, - // do this here because the subject may contain a variable - $drop_header = ''; - $match = array(); - if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match)) - { - $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']); - $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#'); - } - else - { - $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)); - } - - if ($break) - { - return true; - } - - switch ($method) - { - case NOTIFY_EMAIL: - $result = $this->msg_email(); - break; - - case NOTIFY_IM: - $result = $this->msg_jabber(); - break; - - case NOTIFY_BOTH: - $result = $this->msg_email(); - $this->msg_jabber(); - break; - } - - $this->reset(); - return $result; - } - - /** - * Add error message to log - */ - function error($type, $msg) - { - global $user, $config, $request, $phpbb_log; - - // Session doesn't exist, create it - if (!isset($user->session_id) || $user->session_id === '') - { - $user->session_begin(); - } - - $calling_page = htmlspecialchars_decode($request->server('PHP_SELF')); - - switch ($type) - { - case 'EMAIL': - $message = 'EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/mail()') . ''; - break; - - default: - $message = "$type"; - break; - } - - $message .= '
' . htmlspecialchars($calling_page) . '

' . $msg . '
'; - $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_' . $type, false, array($message)); - } - - /** - * Save to queue - */ - function save_queue() - { - global $config; - - if ($config['email_package_size'] && $this->use_queue && !empty($this->queue)) - { - $this->queue->save(); - return; - } - } - - /** - * Generates a valid message id to be used in emails - * - * @return string message id - */ - function generate_message_id() - { - global $config, $request; - - $domain = ($config['server_name']) ?: $request->server('SERVER_NAME', 'phpbb.generated'); - - return md5(unique_id(time())) . '@' . $domain; - } - - /** - * Return email header - */ - function build_header($to, $cc, $bcc) - { - global $config, $phpbb_dispatcher; - - // We could use keys here, but we won't do this for 3.0.x to retain backwards compatibility - $headers = array(); - - $headers[] = 'From: ' . $this->from; - - if ($cc) - { - $headers[] = 'Cc: ' . $cc; - } - - if ($bcc) - { - $headers[] = 'Bcc: ' . $bcc; - } - - $headers[] = 'Reply-To: ' . $this->replyto; - $headers[] = 'Return-Path: <' . $config['board_email'] . '>'; - $headers[] = 'Sender: <' . $config['board_email'] . '>'; - $headers[] = 'MIME-Version: 1.0'; - $headers[] = 'Message-ID: <' . $this->generate_message_id() . '>'; - $headers[] = 'Date: ' . date('r', time()); - $headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed - $headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit - - $headers[] = 'X-Priority: ' . $this->mail_priority; - $headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High')); - $headers[] = 'X-Mailer: phpBB3'; - $headers[] = 'X-MimeOLE: phpBB3'; - $headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url()); - - /** - * Event to modify email header entries - * - * @event core.modify_email_headers - * @var array headers Array containing email header entries - * @since 3.1.11-RC1 - */ - $vars = array('headers'); - extract($phpbb_dispatcher->trigger_event('core.modify_email_headers', compact($vars))); - - if (count($this->extra_headers)) - { - $headers = array_merge($headers, $this->extra_headers); - } - - return $headers; - } - - /** - * Send out emails - */ - function msg_email() - { - global $config, $phpbb_dispatcher; - - if (empty($config['email_enable'])) - { - return false; - } - - // Addresses to send to? - if (empty($this->addresses) || (empty($this->addresses['to']) && empty($this->addresses['cc']) && empty($this->addresses['bcc']))) - { - // Send was successful. ;) - return true; - } - - $use_queue = false; - if ($config['email_package_size'] && $this->use_queue) - { - if (empty($this->queue)) - { - $this->queue = new queue(); - $this->queue->init('email', $config['email_package_size']); - } - $use_queue = true; - } - - $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; - } - - if (empty($this->from)) - { - $this->from = $board_contact; - } - - $encode_eol = ($config['smtp_delivery']) ? "\r\n" : PHP_EOL; - - // Build to, cc and bcc strings - $to = $cc = $bcc = ''; - foreach ($this->addresses as $type => $address_ary) - { - if ($type == 'im') - { - continue; - } - - foreach ($address_ary as $which_ary) - { - ${$type} .= ((${$type} != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']); - } - } - - // Build header - $headers = $this->build_header($to, $cc, $bcc); - - // Send message ... - if (!$use_queue) - { - $mail_to = ($to == '') ? 'undisclosed-recipients:;' : $to; - $err_msg = ''; - - if ($config['smtp_delivery']) - { - $result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $err_msg, $headers); - } - else - { - $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, PHP_EOL, $err_msg); - } - - if (!$result) - { - $this->error('EMAIL', $err_msg); - return false; - } - } - else - { - $this->queue->put('email', array( - 'to' => $to, - 'addresses' => $this->addresses, - 'subject' => $this->subject, - 'msg' => $this->msg, - 'headers' => $headers) - ); - } - - return true; - } - - /** - * Send jabber message out - */ - function msg_jabber() - { - global $config, $user, $phpbb_root_path, $phpEx; - - if (empty($config['jab_enable']) || empty($config['jab_host']) || empty($config['jab_username']) || empty($config['jab_password'])) - { - return false; - } - - if (empty($this->addresses['im'])) - { - // Send was successful. ;) - return true; - } - - $use_queue = false; - if ($config['jab_package_size'] && $this->use_queue) - { - if (empty($this->queue)) - { - $this->queue = new queue(); - $this->queue->init('jabber', $config['jab_package_size']); - } - $use_queue = true; - } - - $addresses = array(); - foreach ($this->addresses['im'] as $type => $uid_ary) - { - $addresses[] = $uid_ary['uid']; - } - $addresses = array_unique($addresses); - - if (!$use_queue) - { - include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx); - $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl'], $config['jab_verify_peer'], $config['jab_verify_peer_name'], $config['jab_allow_self_signed']); - - if (!$this->jabber->connect()) - { - $this->error('JABBER', $user->lang['ERR_JAB_CONNECT'] . '
' . $this->jabber->get_log()); - return false; - } - - if (!$this->jabber->login()) - { - $this->error('JABBER', $user->lang['ERR_JAB_AUTH'] . '
' . $this->jabber->get_log()); - return false; - } - - foreach ($addresses as $address) - { - $this->jabber->send_message($address, $this->msg, $this->subject); - } - - $this->jabber->disconnect(); - } - else - { - $this->queue->put('jabber', array( - 'addresses' => $addresses, - 'subject' => $this->subject, - 'msg' => $this->msg) - ); - } - unset($addresses); - return true; - } - - /** - * Setup template engine - */ - protected function setup_template() - { - global $phpbb_container, $phpbb_dispatcher; - - if ($this->template instanceof \phpbb\template\template) - { - return; - } - - $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') - ); - } - - /** - * Set template paths to load - */ - protected function set_template_paths($path_name, $paths) - { - $this->setup_template(); - - $this->template->set_custom_style($path_name, $paths); - } -} - -/** -* handling email and jabber queue -*/ -class queue -{ - var $data = array(); - var $queue_data = array(); - var $package_size = 0; - var $cache_file = ''; - var $eol = "\n"; - - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * constructor - */ - function __construct() - { - global $phpEx, $phpbb_root_path, $phpbb_filesystem, $phpbb_container; - - $this->data = array(); - $this->cache_file = $phpbb_container->getParameter('core.cache_dir') . "queue.$phpEx"; - $this->filesystem = $phpbb_filesystem; - } - - /** - * Init a queue object - */ - function init($object, $package_size) - { - $this->data[$object] = array(); - $this->data[$object]['package_size'] = $package_size; - $this->data[$object]['data'] = array(); - } - - /** - * Put object in queue - */ - function put($object, $scope) - { - $this->data[$object]['data'][] = $scope; - } - - /** - * Process queue - * Using lock file - */ - function process() - { - global $config, $phpEx, $phpbb_root_path, $user, $phpbb_dispatcher; - - $lock = new \phpbb\lock\flock($this->cache_file); - $lock->acquire(); - - // avoid races, check file existence once - $have_cache_file = file_exists($this->cache_file); - if (!$have_cache_file || $config['last_queue_run'] > time() - $config['queue_interval']) - { - if (!$have_cache_file) - { - $config->set('last_queue_run', time(), false); - } - - $lock->release(); - return; - } - - $config->set('last_queue_run', time(), false); - - include($this->cache_file); - - foreach ($this->queue_data as $object => $data_ary) - { - @set_time_limit(0); - - if (!isset($data_ary['package_size'])) - { - $data_ary['package_size'] = 0; - } - - $package_size = $data_ary['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. - * The core problem is rather restrictive email sending limits. - * This code is nly useful if you have no such restrictions from the - * 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 (count($data_ary['data']) > $package_size * 2.5) - { - $num_items = count($data_ary['data']); - } - */ - - switch ($object) - { - case 'email': - // Delete the email queued objects if mailing is disabled - if (!$config['email_enable']) - { - unset($this->queue_data['email']); - continue 2; - } - break; - - case 'jabber': - if (!$config['jab_enable']) - { - unset($this->queue_data['jabber']); - continue 2; - } - - include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx); - $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl'], $config['jab_verify_peer'], $config['jab_verify_peer_name'], $config['jab_allow_self_signed']); - - if (!$this->jabber->connect()) - { - $messenger = new messenger(); - $messenger->error('JABBER', $user->lang['ERR_JAB_CONNECT']); - continue 2; - } - - if (!$this->jabber->login()) - { - $messenger = new messenger(); - $messenger->error('JABBER', $user->lang['ERR_JAB_AUTH']); - continue 2; - } - - break; - - default: - $lock->release(); - return; - } - - for ($i = 0; $i < $num_items; $i++) - { - // Make variables available... - extract(array_shift($this->queue_data[$object]['data'])); - - switch ($object) - { - case 'email': - $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) - { - $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 - { - $result = phpbb_mail($to, $subject, $msg, $headers, PHP_EOL, $err_msg); - } - - if (!$result) - { - $messenger = new messenger(); - $messenger->error('EMAIL', $err_msg); - continue 2; - } - } - break; - - case 'jabber': - foreach ($addresses as $address) - { - if ($this->jabber->send_message($address, $msg, $subject) === false) - { - $messenger = new messenger(); - $messenger->error('JABBER', $this->jabber->get_log()); - continue 3; - } - } - break; - } - } - - // No more data for this object? Unset it - if (!count($this->queue_data[$object]['data'])) - { - unset($this->queue_data[$object]); - } - - // Post-object processing - switch ($object) - { - case 'jabber': - // Hang about a couple of secs to ensure the messages are - // handled, then disconnect - $this->jabber->disconnect(); - break; - } - } - - if (!count($this->queue_data)) - { - @unlink($this->cache_file); - } - else - { - if ($fp = @fopen($this->cache_file, 'wb')) - { - fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>"); - fclose($fp); - - if (function_exists('opcache_invalidate')) - { - @opcache_invalidate($this->cache_file); - } - - try - { - $this->filesystem->phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - - $lock->release(); - } - - /** - * Save queue - */ - function save() - { - if (!count($this->data)) - { - return; - } - - $lock = new \phpbb\lock\flock($this->cache_file); - $lock->acquire(); - - if (file_exists($this->cache_file)) - { - include($this->cache_file); - - foreach ($this->queue_data as $object => $data_ary) - { - if (isset($this->data[$object]) && count($this->data[$object])) - { - $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']); - } - else - { - $this->data[$object]['data'] = $data_ary['data']; - } - } - } - - if ($fp = @fopen($this->cache_file, 'w')) - { - fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>"); - fclose($fp); - - if (function_exists('opcache_invalidate')) - { - @opcache_invalidate($this->cache_file); - } - - try - { - $this->filesystem->phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - - $this->data = array(); - } - - $lock->release(); - } -} - -/** -* Replacement or substitute for PHP's mail command -*/ -function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false) -{ - global $config, $user; - - // Fix any bare linefeeds in the message to make it RFC821 Compliant. - $message = preg_replace("#(?lang['NO_EMAIL_SUBJECT'])) ? $user->lang['NO_EMAIL_SUBJECT'] : 'No email subject specified'; - return false; - } - - if (trim($message) == '') - { - $err_msg = (isset($user->lang['NO_EMAIL_MESSAGE'])) ? $user->lang['NO_EMAIL_MESSAGE'] : 'Email message was blank'; - return 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']) && count($addresses['to'])) - { - foreach ($addresses['to'] as $which_ary) - { - $mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; - $mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - if (isset($addresses['bcc']) && count($addresses['bcc'])) - { - foreach ($addresses['bcc'] as $which_ary) - { - $mail_rcpt['bcc'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - if (isset($addresses['cc']) && count($addresses['cc'])) - { - foreach ($addresses['cc'] as $which_ary) - { - $mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; - $mail_rcpt['cc'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - $smtp = new smtp_class(); - - $errno = 0; - $errstr = ''; - - $smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']); - - // Ok we have error checked as much as we can to this point let's get on it already. - if (!class_exists('\phpbb\error_collector')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/error_collector.' . $phpEx); - } - $collector = new \phpbb\error_collector; - $collector->install(); - - $options = array(); - $verify_peer = (bool) $config['smtp_verify_peer']; - $verify_peer_name = (bool) $config['smtp_verify_peer_name']; - $allow_self_signed = (bool) $config['smtp_allow_self_signed']; - $remote_socket = $config['smtp_host'] . ':' . $config['smtp_port']; - - // Set ssl context options, see http://php.net/manual/en/context.ssl.php - $options['ssl'] = array('verify_peer' => $verify_peer, 'verify_peer_name' => $verify_peer_name, 'allow_self_signed' => $allow_self_signed); - $socket_context = stream_context_create($options); - - $smtp->socket = @stream_socket_client($remote_socket, $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $socket_context); - $collector->uninstall(); - $error_contents = $collector->format_errors(); - - if (!$smtp->socket) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - $err_msg .= ($error_contents) ? '

' . htmlspecialchars($error_contents) : ''; - return false; - } - - // Wait for reply - if ($err_msg = $smtp->server_parse('220', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Let me in. This function handles the complete authentication process - if ($err_msg = $smtp->log_into_server($config['smtp_host'], $config['smtp_username'], htmlspecialchars_decode($config['smtp_password']), $config['smtp_auth_method'])) - { - $smtp->close_session($err_msg); - return false; - } - - // From this point onward most server response codes should be 250 - // Specify who the mail is from.... - $smtp->server_send('MAIL FROM:<' . $config['board_email'] . '>'); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Specify each user to send to and build to header. - $to_header = implode(', ', $mail_to); - $cc_header = implode(', ', $mail_cc); - - // Now tell the MTA to send the Message to the following people... [TO, BCC, CC] - $rcpt = false; - foreach ($mail_rcpt as $type => $mail_to_addresses) - { - foreach ($mail_to_addresses as $mail_to_address) - { - // Add an additional bit of error checking to the To field. - if (preg_match('#[^ ]+\@[^ ]+#', $mail_to_address)) - { - $smtp->server_send("RCPT TO:$mail_to_address"); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - // We continue... if users are not resolved we do not care - if ($smtp->numeric_response_code != 550) - { - $smtp->close_session($err_msg); - return false; - } - } - else - { - $rcpt = true; - } - } - } - } - - // We try to send messages even if a few people do not seem to have valid email addresses, but if no one has, we have to exit here. - if (!$rcpt) - { - $user->session_begin(); - $err_msg .= '

'; - $err_msg .= (isset($user->lang['INVALID_EMAIL_LOG'])) ? sprintf($user->lang['INVALID_EMAIL_LOG'], htmlspecialchars($mail_to_address)) : '' . htmlspecialchars($mail_to_address) . ' possibly an invalid email address?'; - $smtp->close_session($err_msg); - return false; - } - - // Ok now we tell the server we are ready to start sending data - $smtp->server_send('DATA'); - - // This is the last response code we look for until the end of the message. - if ($err_msg = $smtp->server_parse('354', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Send the Subject Line... - $smtp->server_send("Subject: $subject"); - - // Now the To Header. - $to_header = ($to_header == '') ? 'undisclosed-recipients:;' : $to_header; - $smtp->server_send("To: $to_header"); - - // Now the CC Header. - if ($cc_header != '') - { - $smtp->server_send("CC: $cc_header"); - } - - // Now any custom headers.... - if ($headers !== false) - { - $smtp->server_send("$headers\r\n"); - } - - // Ok now we are ready for the message... - $smtp->server_send($message); - - // Ok the all the ingredients are mixed in let's cook this puppy... - $smtp->server_send('.'); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Now tell the server we are done and close the socket... - $smtp->server_send('QUIT'); - $smtp->close_session($err_msg); - - return true; -} - -/** -* SMTP Class -* Auth Mechanisms originally taken from the AUTH Modules found within the PHP Extension and Application Repository (PEAR) -* See docs/AUTHORS for more details -*/ -class smtp_class -{ - var $server_response = ''; - var $socket = 0; - protected $socket_tls = false; - var $responses = array(); - var $commands = array(); - var $numeric_response_code = 0; - - var $backtrace = false; - var $backtrace_log = array(); - - function __construct() - { - // Always create a backtrace for admins to identify SMTP problems - $this->backtrace = true; - $this->backtrace_log = array(); - } - - /** - * Add backtrace message for debugging - */ - function add_backtrace($message) - { - if ($this->backtrace) - { - $this->backtrace_log[] = utf8_htmlspecialchars($message); - } - } - - /** - * Send command to smtp server - */ - function server_send($command, $private_info = false) - { - fputs($this->socket, $command . "\r\n"); - - (!$private_info) ? $this->add_backtrace("# $command") : $this->add_backtrace('# Omitting sensitive information'); - - // We could put additional code here - } - - /** - * We use the line to give the support people an indication at which command the error occurred - */ - function server_parse($response, $line) - { - global $user; - - $this->server_response = ''; - $this->responses = array(); - $this->numeric_response_code = 0; - - while (substr($this->server_response, 3, 1) != ' ') - { - if (!($this->server_response = fgets($this->socket, 256))) - { - return (isset($user->lang['NO_EMAIL_RESPONSE_CODE'])) ? $user->lang['NO_EMAIL_RESPONSE_CODE'] : 'Could not get mail server response codes'; - } - $this->responses[] = substr(rtrim($this->server_response), 4); - $this->numeric_response_code = (int) substr($this->server_response, 0, 3); - - $this->add_backtrace("LINE: $line <- {$this->server_response}"); - } - - if (!(substr($this->server_response, 0, 3) == $response)) - { - $this->numeric_response_code = (int) substr($this->server_response, 0, 3); - return (isset($user->lang['EMAIL_SMTP_ERROR_RESPONSE'])) ? sprintf($user->lang['EMAIL_SMTP_ERROR_RESPONSE'], $line, $this->server_response) : "Ran into problems sending Mail at Line $line. Response: $this->server_response"; - } - - return 0; - } - - /** - * Close session - */ - function close_session(&$err_msg) - { - fclose($this->socket); - - if ($this->backtrace) - { - $message = '

Backtrace

' . implode('
', $this->backtrace_log) . '

'; - $err_msg .= $message; - } - } - - /** - * Log into server and get possible auth codes if neccessary - */ - function log_into_server($hostname, $username, $password, $default_auth_method) - { - global $user; - - // Here we try to determine the *real* hostname (reverse DNS entry preferrably) - $local_host = $user->host; - - if (function_exists('php_uname')) - { - $local_host = php_uname('n'); - - // Able to resolve name to IP - if (($addr = @gethostbyname($local_host)) !== $local_host) - { - // Able to resolve IP back to name - if (($name = @gethostbyaddr($addr)) !== $addr) - { - $local_host = $name; - } - } - } - - // If we are authenticating through pop-before-smtp, we - // have to login ones before we get authenticated - // NOTE: on some configurations the time between an update of the auth database takes so - // long that the first email send does not work. This is not a biggie on a live board (only - // the install mail will most likely fail) - but on a dynamic ip connection this might produce - // severe problems and is not fixable! - if ($default_auth_method == 'POP-BEFORE-SMTP' && $username && $password) - { - global $config; - - $errno = 0; - $errstr = ''; - - $this->server_send("QUIT"); - fclose($this->socket); - - $this->pop_before_smtp($hostname, $username, $password); - $username = $password = $default_auth_method = ''; - - // We need to close the previous session, else the server is not - // able to get our ip for matching... - if (!$this->socket = @fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 10)) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - return $err_msg; - } - - // Wait for reply - if ($err_msg = $this->server_parse('220', __LINE__)) - { - $this->close_session($err_msg); - return $err_msg; - } - } - - $hello_result = $this->hello($local_host); - if (!is_null($hello_result)) - { - return $hello_result; - } - - // SMTP STARTTLS (RFC 3207) - if (!$this->socket_tls) - { - $this->socket_tls = $this->starttls(); - - if ($this->socket_tls) - { - // Switched to TLS - // RFC 3207: "The client MUST discard any knowledge obtained from the server, [...]" - // So say hello again - $hello_result = $this->hello($local_host); - - if (!is_null($hello_result)) - { - return $hello_result; - } - } - } - - // If we are not authenticated yet, something might be wrong if no username and passwd passed - if (!$username || !$password) - { - return false; - } - - if (!isset($this->commands['AUTH'])) - { - return (isset($user->lang['SMTP_NO_AUTH_SUPPORT'])) ? $user->lang['SMTP_NO_AUTH_SUPPORT'] : 'SMTP server does not support authentication'; - } - - // Get best authentication method - $available_methods = explode(' ', $this->commands['AUTH']); - - // Define the auth ordering if the default auth method was not found - $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5'); - $method = ''; - - if (in_array($default_auth_method, $available_methods)) - { - $method = $default_auth_method; - } - else - { - foreach ($auth_methods as $_method) - { - if (in_array($_method, $available_methods)) - { - $method = $_method; - break; - } - } - } - - if (!$method) - { - return (isset($user->lang['NO_SUPPORTED_AUTH_METHODS'])) ? $user->lang['NO_SUPPORTED_AUTH_METHODS'] : 'No supported authentication methods'; - } - - $method = strtolower(str_replace('-', '_', $method)); - return $this->$method($username, $password); - } - - /** - * SMTP EHLO/HELO - * - * @return mixed Null if the authentication process is supposed to continue - * False if already authenticated - * Error message (string) otherwise - */ - protected function hello($hostname) - { - // Try EHLO first - $this->server_send("EHLO $hostname"); - if ($err_msg = $this->server_parse('250', __LINE__)) - { - // a 503 response code means that we're already authenticated - if ($this->numeric_response_code == 503) - { - return false; - } - - // If EHLO fails, we try HELO - $this->server_send("HELO $hostname"); - if ($err_msg = $this->server_parse('250', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - } - - foreach ($this->responses as $response) - { - $response = explode(' ', $response); - $response_code = $response[0]; - unset($response[0]); - $this->commands[$response_code] = implode(' ', $response); - } - } - - /** - * SMTP STARTTLS (RFC 3207) - * - * @return bool Returns true if TLS was started - * Otherwise false - */ - protected function starttls() - { - if (!function_exists('stream_socket_enable_crypto')) - { - return false; - } - - if (!isset($this->commands['STARTTLS'])) - { - return false; - } - - $this->server_send('STARTTLS'); - - if ($err_msg = $this->server_parse('220', __LINE__)) - { - return false; - } - - $result = false; - $stream_meta = stream_get_meta_data($this->socket); - - if (socket_set_blocking($this->socket, 1)) - { - $result = stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); - socket_set_blocking($this->socket, (int) $stream_meta['blocked']); - } - - return $result; - } - - /** - * Pop before smtp authentication - */ - function pop_before_smtp($hostname, $username, $password) - { - global $user; - - if (!$this->socket = @fsockopen($hostname, 110, $errno, $errstr, 10)) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - return (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - } - - $this->server_send("USER $username", true); - if ($err_msg = $this->server_parse('+OK', __LINE__)) - { - return $err_msg; - } - - $this->server_send("PASS $password", true); - if ($err_msg = $this->server_parse('+OK', __LINE__)) - { - return $err_msg; - } - - $this->server_send('QUIT'); - fclose($this->socket); - - return false; - } - - /** - * Plain authentication method - */ - function plain($username, $password) - { - $this->server_send('AUTH PLAIN'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $base64_method_plain = base64_encode("\0" . $username . "\0" . $password); - $this->server_send($base64_method_plain, true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * Login authentication method - */ - function login($username, $password) - { - $this->server_send('AUTH LOGIN'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $this->server_send(base64_encode($username), true); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return $err_msg; - } - - $this->server_send(base64_encode($password), true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * cram_md5 authentication method - */ - function cram_md5($username, $password) - { - $this->server_send('AUTH CRAM-MD5'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $md5_challenge = base64_decode($this->responses[0]); - $password = (strlen($password) > 64) ? pack('H32', md5($password)) : ((strlen($password) < 64) ? str_pad($password, 64, chr(0)) : $password); - $md5_digest = md5((substr($password, 0, 64) ^ str_repeat(chr(0x5C), 64)) . (pack('H32', md5((substr($password, 0, 64) ^ str_repeat(chr(0x36), 64)) . $md5_challenge)))); - - $base64_method_cram_md5 = base64_encode($username . ' ' . $md5_digest); - - $this->server_send($base64_method_cram_md5, true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * digest_md5 authentication method - * A real pain in the *** - */ - function digest_md5($username, $password) - { - global $config, $user; - - $this->server_send('AUTH DIGEST-MD5'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $md5_challenge = base64_decode($this->responses[0]); - - // Parse the md5 challenge - from AUTH_SASL (PEAR) - $tokens = array(); - while (preg_match('/^([a-z-]+)=("[^"]+(?host; - } - - // Maxbuf - if (empty($tokens['maxbuf'])) - { - $tokens['maxbuf'] = 65536; - } - - // Required: nonce, algorithm - if (empty($tokens['nonce']) || empty($tokens['algorithm'])) - { - $tokens = array(); - } - $md5_challenge = $tokens; - - if (!empty($md5_challenge)) - { - $str = ''; - for ($i = 0; $i < 32; $i++) - { - $str .= chr(mt_rand(0, 255)); - } - $cnonce = base64_encode($str); - - $digest_uri = 'smtp/' . $config['smtp_host']; - - $auth_1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $username, $md5_challenge['realm'], $password))), $md5_challenge['nonce'], $cnonce); - $auth_2 = 'AUTHENTICATE:' . $digest_uri; - $response_value = md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($auth_1), $md5_challenge['nonce'], $cnonce, md5($auth_2))); - - $input_string = sprintf('username="%s",realm="%s",nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $username, $md5_challenge['realm'], $md5_challenge['nonce'], $cnonce, $digest_uri, $response_value, $md5_challenge['maxbuf']); - } - else - { - return (isset($user->lang['INVALID_DIGEST_CHALLENGE'])) ? $user->lang['INVALID_DIGEST_CHALLENGE'] : 'Invalid digest challenge'; - } - - $base64_method_digest_md5 = base64_encode($input_string); - $this->server_send($base64_method_digest_md5, true); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return $err_msg; - } - - $this->server_send(' '); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } -} - -/** -* Encodes the given string for proper display in UTF-8. -* -* This version is using base64 encoded data. The downside of this -* is if the mail client does not understand this encoding the user -* is basically doomed with an unreadable subject. -* -* Please note that this version fully supports RFC 2045 section 6.8. -* -* @param string $eol End of line we are using (optional to be backwards compatible) -*/ -function mail_encode($str, $eol = "\r\n") -{ - // define start delimimter, end delimiter and spacer - $start = "=?UTF-8?B?"; - $end = "?="; - $delimiter = "$eol "; - - // Maximum length is 75. $split_length *must* be a multiple of 4, but <= 75 - strlen($start . $delimiter . $end)!!! - $split_length = 60; - $encoded_str = base64_encode($str); - - // If encoded string meets the limits, we just return with the correct data. - if (strlen($encoded_str) <= $split_length) - { - return $start . $encoded_str . $end; - } - - // If there is only ASCII data, we just return what we want, correctly splitting the lines. - if (strlen($str) === utf8_strlen($str)) - { - return $start . implode($end . $delimiter . $start, str_split($encoded_str, $split_length)) . $end; - } - - // UTF-8 data, compose encoded lines - $array = utf8_str_split($str); - $str = ''; - - while (count($array)) - { - $text = ''; - - while (count($array) && intval((strlen($text . $array[0]) + 2) / 3) << 2 <= $split_length) - { - $text .= array_shift($array); - } - - $str .= $start . base64_encode($text) . $end . $delimiter; - } - - return substr($str, 0, -strlen($delimiter)); -} - -/** -* Wrapper for sending out emails with the PHP's mail function -*/ -function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg) -{ - global $config, $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 - $headers = implode($eol, $headers); - - if (!class_exists('\phpbb\error_collector')) - { - include($phpbb_root_path . 'includes/error_collector.' . $phpEx); - } - - $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) - $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(); - - return $result; -} diff --git a/install/update/old/includes/functions_module.php b/install/update/old/includes/functions_module.php deleted file mode 100644 index 88dafc4..0000000 --- a/install/update/old/includes/functions_module.php +++ /dev/null @@ -1,1145 +0,0 @@ - -* @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 handling all types of 'plugins' (a future term) -*/ -class p_master -{ - var $p_id; - var $p_class; - var $p_name; - var $p_mode; - var $p_parent; - - var $include_path = false; - var $active_module = false; - var $active_module_row_id = false; - var $acl_forum_id = false; - var $module_ary = array(); - - /** - * Constuctor - * Set module include path - */ - function __construct($include_path = false) - { - global $phpbb_root_path; - - $this->include_path = ($include_path !== false) ? $include_path : $phpbb_root_path . 'includes/'; - - // Make sure the path ends with / - if (substr($this->include_path, -1) !== '/') - { - $this->include_path .= '/'; - } - } - - /** - * Set custom include path for modules - * Schema for inclusion is include_path . modulebase - * - * @param string $include_path include path to be used. - * @access public - */ - function set_custom_include_path($include_path) - { - $this->include_path = $include_path; - - // Make sure the path ends with / - if (substr($this->include_path, -1) !== '/') - { - $this->include_path .= '/'; - } - } - - /** - * List modules - * - * This creates a list, stored in $this->module_ary of all available - * modules for the given class (ucp, mcp and acp). Additionally - * $this->module_y_ary is created with indentation information for - * displaying the module list appropriately. Only modules for which - * the user has access rights are included in these lists. - */ - function list_modules($p_class) - { - 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)); - - // Get cached modules - if (($this->module_cache = $cache->get('_modules_' . $this->p_class)) === false) - { - // Get modules - $sql = 'SELECT * - FROM ' . MODULES_TABLE . " - WHERE module_class = '" . $db->sql_escape($this->p_class) . "' - ORDER BY left_id ASC"; - $result = $db->sql_query($sql); - - $rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rows[$row['module_id']] = $row; - } - $db->sql_freeresult($result); - - $this->module_cache = array(); - foreach ($rows as $module_id => $row) - { - $this->module_cache['modules'][] = $row; - $this->module_cache['parents'][$row['module_id']] = $this->get_parents($row['parent_id'], $row['left_id'], $row['right_id'], $rows); - } - unset($rows); - - $cache->put('_modules_' . $this->p_class, $this->module_cache); - } - - if (empty($this->module_cache)) - { - $this->module_cache = array('modules' => array(), 'parents' => array()); - } - - // We "could" build a true tree with this function - maybe mod authors want to use this... - // Functions for traversing and manipulating the tree are not available though - // We might re-structure the module system to use true trees in 3.2.x... - // $tree = $this->build_tree($this->module_cache['modules'], $this->module_cache['parents']); - - // Clean up module cache array to only let survive modules the user can access - $right_id = false; - - $hide_categories = array(); - foreach ($this->module_cache['modules'] as $key => $row) - { - // When the module has no mode (category) we check whether it has visible children - // before listing it as well. - if (!$row['module_mode']) - { - $hide_categories[(int) $row['module_id']] = $key; - } - - // Not allowed to view module? - if (!$this->module_auth_self($row['module_auth'])) - { - unset($this->module_cache['modules'][$key]); - continue; - } - - // Category with no members, ignore - if (!$row['module_basename'] && ($row['left_id'] + 1 == $row['right_id'])) - { - unset($this->module_cache['modules'][$key]); - continue; - } - - // Skip branch - if ($right_id !== false) - { - if ($row['left_id'] < $right_id) - { - unset($this->module_cache['modules'][$key]); - continue; - } - - $right_id = false; - } - - // Not enabled? - if (!$row['module_enabled']) - { - // If category is disabled then disable every child too - unset($this->module_cache['modules'][$key]); - $right_id = $row['right_id']; - continue; - } - - if ($row['module_mode']) - { - // The parent category has a visible child - // So remove it and all its parents from the hide array - unset($hide_categories[(int) $row['parent_id']]); - foreach ($this->module_cache['parents'][$row['module_id']] as $module_id => $row_id) - { - unset($hide_categories[$module_id]); - } - } - } - - foreach ($hide_categories as $module_id => $row_id) - { - unset($this->module_cache['modules'][$row_id]); - } - - // Re-index (this is needed, else we are not able to array_slice later) - $this->module_cache['modules'] = array_merge($this->module_cache['modules']); - - // Include MOD _info files for populating language entries within the menus - $this->add_mod_info($this->p_class); - - // Now build the module array, but exclude completely empty categories... - $right_id = false; - $names = array(); - - foreach ($this->module_cache['modules'] as $key => $row) - { - // Skip branch - if ($right_id !== false) - { - if ($row['left_id'] < $right_id) - { - continue; - } - - $right_id = false; - } - - // Category with no members on their way down (we have to check every level) - if (!$row['module_basename']) - { - $empty_category = true; - - // We go through the branch and look for an activated module - foreach (array_slice($this->module_cache['modules'], $key + 1) as $temp_row) - { - if ($temp_row['left_id'] > $row['left_id'] && $temp_row['left_id'] < $row['right_id']) - { - // Module there - if ($temp_row['module_basename'] && $temp_row['module_enabled']) - { - $empty_category = false; - break; - } - continue; - } - break; - } - - // Skip the branch - if ($empty_category) - { - $right_id = $row['right_id']; - continue; - } - } - - $depth = count($this->module_cache['parents'][$row['module_id']]); - - // We need to prefix the functions to not create a naming conflict - - // Function for building 'url_extra' - $short_name = $this->get_short_name($row['module_basename']); - - $url_func = 'phpbb_module_' . $short_name . '_url'; - if (!function_exists($url_func)) - { - $url_func = '_module_' . $short_name . '_url'; - } - - // Function for building the language name - $lang_func = 'phpbb_module_' . $short_name . '_lang'; - if (!function_exists($lang_func)) - { - $lang_func = '_module_' . $short_name . '_lang'; - } - - // Custom function for calling parameters on module init (for example assigning template variables) - $custom_func = 'phpbb_module_' . $short_name; - if (!function_exists($custom_func)) - { - $custom_func = '_module_' . $short_name; - } - - $names[$row['module_basename'] . '_' . $row['module_mode']][] = true; - - $module_row = array( - 'depth' => $depth, - - 'id' => (int) $row['module_id'], - 'parent' => (int) $row['parent_id'], - 'cat' => ($row['right_id'] > $row['left_id'] + 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'], - 'display' => (int) $row['module_display'], - - 'url_extra' => (function_exists($url_func)) ? $url_func($row['module_mode'], $row) : '', - - 'lang' => ($row['module_basename'] && function_exists($lang_func)) ? $lang_func($row['module_mode'], $row['module_langname']) : ((!empty($user->lang[$row['module_langname']])) ? $user->lang[$row['module_langname']] : $row['module_langname']), - 'langname' => $row['module_langname'], - - 'left' => $row['left_id'], - 'right' => $row['right_id'], - ); - - if (function_exists($custom_func)) - { - $custom_func($row['module_mode'], $module_row); - } - - /** - * This event allows to modify parameters for building modules list - * - * @event core.modify_module_row - * @var string url_func Function for building 'url_extra' - * @var string lang_func Function for building the language name - * @var string custom_func Custom function for calling parameters on module init - * @var array row Array holding the basic module data - * @var array module_row Array holding the module display parameters - * @since 3.1.0-b3 - */ - $vars = array('url_func', 'lang_func', 'custom_func', 'row', 'module_row'); - extract($phpbb_dispatcher->trigger_event('core.modify_module_row', compact($vars))); - - $this->module_ary[] = $module_row; - } - - unset($this->module_cache['modules'], $names); - } - - /** - * Check if a certain main module is accessible/loaded - * By giving the module mode you are able to additionally check for only one mode within the main module - * - * @param string $module_basename The module base name, for example logs, reports, main (for the mcp). - * @param mixed $module_mode The module mode to check. If provided the mode will be checked in addition for presence. - * - * @return bool Returns true if module is loaded and accessible, else returns false - */ - function loaded($module_basename, $module_mode = false) - { - if (!$this->is_full_class($module_basename)) - { - $module_basename = $this->p_class . '_' . $module_basename; - } - - if (empty($this->loaded_cache)) - { - $this->loaded_cache = array(); - - foreach ($this->module_ary as $row) - { - if (!$row['name']) - { - continue; - } - - if (!isset($this->loaded_cache[$row['name']])) - { - $this->loaded_cache[$row['name']] = array(); - } - - if (!$row['mode']) - { - continue; - } - - $this->loaded_cache[$row['name']][$row['mode']] = true; - } - } - - if ($module_mode === false) - { - return (isset($this->loaded_cache[$module_basename])) ? true : false; - } - - return (!empty($this->loaded_cache[$module_basename][$module_mode])) ? true : false; - } - - /** - * Check module authorisation. - * - * This is a non-static version that uses $this->acl_forum_id - * for the forum id. - */ - function module_auth_self($module_auth) - { - return self::module_auth($module_auth, $this->acl_forum_id); - } - - /** - * Check module authorisation. - * - * This is a static version, it must be given $forum_id. - * See also module_auth_self. - */ - static function module_auth($module_auth, $forum_id) - { - global $auth, $config; - global $request, $phpbb_extension_manager, $phpbb_dispatcher; - - $module_auth = trim($module_auth); - - // Generally allowed to access module if module_auth is empty - if (!$module_auth) - { - return true; - } - - // With the code below we make sure only those elements get eval'd we really want to be checked - preg_match_all('/(?: - "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | - \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | - [(),] | - [^\s(),]+)/x', $module_auth, $match); - - // Valid tokens for auth and their replacements - $valid_tokens = array( - 'acl_([a-z0-9_]+)(,\$id)?' => '(int) $auth->acl_get(\'\\1\'\\2)', - '\$id' => '(int) $forum_id', - 'aclf_([a-z0-9_]+)' => '(int) $auth->acl_getf_global(\'\\1\')', - 'cfg_([a-z0-9_]+)' => '(int) $config[\'\\1\']', - 'request_([a-zA-Z0-9_]+)' => '$request->variable(\'\\1\', false)', - 'ext_([a-zA-Z0-9_/]+)' => 'array_key_exists(\'\\1\', $phpbb_extension_manager->all_enabled())', - 'authmethod_([a-z0-9_\\\\]+)' => '($config[\'auth_method\'] === \'\\1\')', - ); - - /** - * Alter tokens for module authorisation check - * - * @event core.module_auth - * @var array valid_tokens Valid tokens and their auth check - * replacements - * @var string module_auth The module_auth of the current - * module - * @var int forum_id The current forum_id - * @since 3.1.0-a3 - */ - $vars = array('valid_tokens', 'module_auth', 'forum_id'); - extract($phpbb_dispatcher->trigger_event('core.module_auth', compact($vars))); - - $tokens = $match[0]; - for ($i = 0, $size = count($tokens); $i < $size; $i++) - { - $token = &$tokens[$i]; - - switch ($token) - { - case ')': - case '(': - case '&&': - case '||': - case ',': - break; - - default: - if (!preg_match('#(?:' . implode(array_keys($valid_tokens), ')|(?:') . ')#', $token)) - { - $token = ''; - } - break; - } - } - - $module_auth = implode(' ', $tokens); - - // Make sure $id separation is working fine - $module_auth = str_replace(' , ', ',', $module_auth); - - $module_auth = preg_replace( - // Array keys with # prepended/appended - array_map(function($value) { - return '#' . $value . '#'; - }, array_keys($valid_tokens)), - array_values($valid_tokens), - $module_auth - ); - - $is_auth = false; - // @codingStandardsIgnoreStart - eval('$is_auth = (int) (' . $module_auth . ');'); - // @codingStandardsIgnoreEnd - - return $is_auth; - } - - /** - * Set active module - */ - function set_active($id = false, $mode = false) - { - global $request; - - $icat = false; - $this->active_module = false; - - if ($request->variable('icat', '')) - { - $icat = $id; - $id = $request->variable('icat', ''); - } - - // Restore the backslashes in class names - if (strpos($id, '-') !== false) - { - $id = str_replace('-', '\\', $id); - } - - if ($id && !is_numeric($id) && !$this->is_full_class($id)) - { - $id = $this->p_class . '_' . $id; - } - - $category = false; - foreach ($this->module_ary as $row_id => $item_ary) - { - // If this is a module and it's selected, active - // If this is a category and the module is the first within it, active - // If this is a module and no mode selected, select first mode - // If no category or module selected, go active for first module in first category - if ( - (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (($item_ary['mode'] == $mode && !$item_ary['cat']) || ($icat && $item_ary['cat']))) || - ($item_ary['parent'] === $category && !$item_ary['cat'] && !$icat && $item_ary['display']) || - (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) || - (!$id && !$mode && !$item_ary['cat'] && $item_ary['display']) - ) - { - if ($item_ary['cat']) - { - $id = $icat; - $icat = false; - - continue; - } - - $this->p_id = $item_ary['id']; - $this->p_parent = $item_ary['parent']; - $this->p_name = $item_ary['name']; - $this->p_mode = $item_ary['mode']; - $this->p_left = $item_ary['left']; - $this->p_right = $item_ary['right']; - - $this->module_cache['parents'] = $this->module_cache['parents'][$this->p_id]; - $this->active_module = $item_ary['id']; - $this->active_module_row_id = $row_id; - - break; - } - else if (($item_ary['cat'] && $item_ary['id'] === (int) $id) || ($item_ary['parent'] === $category && $item_ary['cat'])) - { - $category = $item_ary['id']; - } - } - } - - /** - * Loads currently active module - * - * This method loads a given module, passing it the relevant id and mode. - * - * @param string|false $mode mode, as passed through to the module - * @param string|false $module_url If supplied, we use this module url - * @param bool $execute_module If true, at the end we execute the main method for the new instance - */ - function load_active($mode = false, $module_url = false, $execute_module = true) - { - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template, $request; - - $module_path = $this->include_path . $this->p_class; - $icat = $request->variable('icat', ''); - - if ($this->active_module === false) - { - trigger_error('MODULE_NOT_ACCESS', E_USER_ERROR); - } - - // new modules use the full class names, old ones are always called _, e.g. acp_board - if (!class_exists($this->p_name)) - { - if (!file_exists("$module_path/{$this->p_name}.$phpEx")) - { - trigger_error($user->lang('MODULE_NOT_FIND', "$module_path/{$this->p_name}.$phpEx"), E_USER_ERROR); - } - - include("$module_path/{$this->p_name}.$phpEx"); - - if (!class_exists($this->p_name)) - { - trigger_error($user->lang('MODULE_FILE_INCORRECT_CLASS', "$module_path/{$this->p_name}.$phpEx", $this->p_name), E_USER_ERROR); - } - } - - if (!empty($mode)) - { - $this->p_mode = $mode; - } - - // Create a new instance of the desired module ... - $class_name = $this->p_name; - - $this->module = new $class_name($this); - - // We pre-define the action parameter we are using all over the place - if (defined('IN_ADMIN')) - { - /* - * If this is an extension module, we'll try to automatically set - * the style paths for the extension (the ext author can change them - * if necessary). - */ - $module_dir = explode('\\', get_class($this->module)); - - // 0 vendor, 1 extension name, ... - if (isset($module_dir[1])) - { - $module_style_dir = $phpbb_root_path . 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/adm/style'; - - if (is_dir($module_style_dir)) - { - $template->set_custom_style(array( - array( - 'name' => 'adm', - 'ext_path' => 'adm/style/', - ), - ), array($module_style_dir, $phpbb_admin_path . 'style')); - } - } - - // Is first module automatically enabled a duplicate and the category not passed yet? - if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate']) - { - $icat = $this->module_ary[$this->active_module_row_id]['parent']; - } - - // Not being able to overwrite ;) - $this->module->u_action = append_sid("{$phpbb_admin_path}index.$phpEx", 'i=' . $this->get_module_identifier($this->p_name)) . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; - } - else - { - /* - * If this is an extension module, we'll try to automatically set - * the style paths for the extension (the ext author can change them - * if necessary). - */ - $module_dir = explode('\\', get_class($this->module)); - - // 0 vendor, 1 extension name, ... - if (isset($module_dir[1])) - { - $module_style_dir = 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/styles'; - - if (is_dir($phpbb_root_path . $module_style_dir)) - { - $template->set_style(array($module_style_dir, 'styles')); - } - } - - // If user specified the module url we will use it... - if ($module_url !== false) - { - $this->module->u_action = $module_url; - } - else - { - $this->module->u_action = $phpbb_root_path . (($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '') . $user->page['page_name']; - } - - $this->module->u_action = append_sid($this->module->u_action, 'i=' . $this->get_module_identifier($this->p_name)) . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; - } - - // Add url_extra parameter to u_action url - if (!empty($this->module_ary) && $this->active_module !== false && $this->module_ary[$this->active_module_row_id]['url_extra']) - { - $this->module->u_action .= $this->module_ary[$this->active_module_row_id]['url_extra']; - } - - // Assign the module path for re-usage - $this->module->module_path = $module_path . '/'; - - // Execute the main method for the new instance, we send the module id and mode as parameters - // Users are able to call the main method after this function to be able to assign additional parameters manually - if ($execute_module) - { - $short_name = preg_replace("#^{$this->p_class}_#", '', $this->p_name); - $this->module->main($short_name, $this->p_mode); - } - } - - /** - * Appending url parameter to the currently active module. - * - * This function is called for adding specific url parameters while executing the current module. - * It is doing the same as the _module_{name}_url() function, apart from being able to be called after - * having dynamically parsed specific parameters. This allows more freedom in choosing additional parameters. - * One example can be seen in /includes/mcp/mcp_notes.php - $this->p_master->adjust_url() call. - * - * @param string $url_extra Extra url parameters, e.g.: &u=$user_id - * - */ - function adjust_url($url_extra) - { - if (empty($this->module_ary[$this->active_module_row_id])) - { - return; - } - - $row = &$this->module_ary[$this->active_module_row_id]; - - // We check for the same url_extra in $row['url_extra'] to overcome doubled additions... - if (strpos($row['url_extra'], $url_extra) === false) - { - $row['url_extra'] .= $url_extra; - } - } - - /** - * Check if a module is active - */ - function is_active($id, $mode = false) - { - // If we find a name by this id and being enabled we have our active one... - foreach ($this->module_ary as $row_id => $item_ary) - { - if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && $item_ary['display'] || $item_ary['name'] === $this->p_class . '_' . $id) - { - if ($mode === false || $mode === $item_ary['mode']) - { - return true; - } - } - } - - return false; - } - - /** - * Get parents - */ - function get_parents($parent_id, $left_id, $right_id, &$all_parents) - { - $parents = array(); - - if ($parent_id > 0) - { - foreach ($all_parents as $module_id => $row) - { - if ($row['left_id'] < $left_id && $row['right_id'] > $right_id) - { - $parents[$module_id] = $row['parent_id']; - } - - if ($row['left_id'] > $left_id) - { - break; - } - } - } - - return $parents; - } - - /** - * Get tree branch - */ - function get_branch($left_id, $right_id, $remaining) - { - $branch = array(); - - foreach ($remaining as $key => $row) - { - if ($row['left_id'] > $left_id && $row['left_id'] < $right_id) - { - $branch[] = $row; - continue; - } - break; - } - - return $branch; - } - - /** - * Build true binary tree from given array - * Not in use - */ - function build_tree(&$modules, &$parents) - { - $tree = array(); - - foreach ($modules as $row) - { - $branch = &$tree; - - if ($row['parent_id']) - { - // Go through the tree to find our branch - $parent_tree = $parents[$row['module_id']]; - - foreach ($parent_tree as $id => $value) - { - if (!isset($branch[$id]) && isset($branch['child'])) - { - $branch = &$branch['child']; - } - $branch = &$branch[$id]; - } - $branch = &$branch['child']; - } - - $branch[$row['module_id']] = $row; - if (!isset($branch[$row['module_id']]['child'])) - { - $branch[$row['module_id']]['child'] = array(); - } - } - - return $tree; - } - - /** - * Build navigation structure - */ - function assign_tpl_vars($module_url) - { - global $template; - - $current_id = $right_id = false; - - // Make sure the module_url has a question mark set, effectively determining the delimiter to use - $delim = (strpos($module_url, '?') === false) ? '?' : '&'; - - $current_depth = 0; - $linear_offset = 'l_block1'; - $tabular_offset = 't_block2'; - - // Generate the list of modules, we'll do this in two ways ... - // 1) In a linear fashion - // 2) In a combined tabbed + linear fashion ... tabs for the categories - // and a linear list for subcategories/items - foreach ($this->module_ary as $row_id => $item_ary) - { - // Skip hidden modules - if (!$item_ary['display']) - { - continue; - } - - // Skip branch - if ($right_id !== false) - { - if ($item_ary['left'] < $right_id) - { - continue; - } - - $right_id = false; - } - - // Category with no members on their way down (we have to check every level) - if (!$item_ary['name']) - { - $empty_category = true; - - // We go through the branch and look for an activated module - foreach (array_slice($this->module_ary, $row_id + 1) as $temp_row) - { - if ($temp_row['left'] > $item_ary['left'] && $temp_row['left'] < $item_ary['right']) - { - // Module there and displayed? - if ($temp_row['name'] && $temp_row['display']) - { - $empty_category = false; - break; - } - continue; - } - break; - } - - // Skip the branch - if ($empty_category) - { - $right_id = $item_ary['right']; - continue; - } - } - - // Select first id we can get - if (!$current_id && (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id)) - { - $current_id = $item_ary['id']; - } - - $depth = $item_ary['depth']; - - if ($depth > $current_depth) - { - $linear_offset = $linear_offset . '.l_block' . ($depth + 1); - $tabular_offset = ($depth + 1 > 2) ? $tabular_offset . '.t_block' . ($depth + 1) : $tabular_offset; - } - else if ($depth < $current_depth) - { - for ($i = $current_depth - $depth; $i > 0; $i--) - { - $linear_offset = substr($linear_offset, 0, strrpos($linear_offset, '.')); - $tabular_offset = ($i + $depth > 1) ? substr($tabular_offset, 0, strrpos($tabular_offset, '.')) : $tabular_offset; - } - } - - $u_title = $module_url . $delim . 'i='; - // if the item has a name use it, else use its id - if (empty($item_ary['name'])) - { - $u_title .= $item_ary['id']; - } - else - { - // if the category has a name, then use it. - $u_title .= $this->get_module_identifier($item_ary['name']); - } - // If the item is not a category append the mode - if (!$item_ary['cat']) - { - if ($item_ary['is_duplicate']) - { - $u_title .= '&icat=' . $current_id; - } - $u_title .= '&mode=' . $item_ary['mode']; - } - - // Was not allowed in categories before - /*!$item_ary['cat'] && */ - $u_title .= (isset($item_ary['url_extra'])) ? $item_ary['url_extra'] : ''; - - // Only output a categories items if it's currently selected - if (!$depth || ($depth && (in_array($item_ary['parent'], array_values($this->module_cache['parents'])) || $item_ary['parent'] == $this->p_parent))) - { - $use_tabular_offset = (!$depth) ? 't_block1' : $tabular_offset; - - $tpl_ary = array( - 'L_TITLE' => $item_ary['lang'], - 'S_SELECTED' => (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) ? true : false, - 'U_TITLE' => $u_title - ); - - $template->assign_block_vars($use_tabular_offset, array_merge($tpl_ary, array_change_key_case($item_ary, CASE_UPPER))); - } - - $tpl_ary = array( - 'L_TITLE' => $item_ary['lang'], - 'S_SELECTED' => (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) ? true : false, - 'U_TITLE' => $u_title - ); - - $template->assign_block_vars($linear_offset, array_merge($tpl_ary, array_change_key_case($item_ary, CASE_UPPER))); - - $current_depth = $depth; - } - } - - /** - * Returns desired template name - */ - function get_tpl_name() - { - return $this->module->tpl_name . '.html'; - } - - /** - * Returns the desired page title - */ - function get_page_title() - { - global $user; - - if (!isset($this->module->page_title)) - { - return ''; - } - - return (isset($user->lang[$this->module->page_title])) ? $user->lang[$this->module->page_title] : $this->module->page_title; - } - - /** - * Load module as the current active one without the need for registering it - * - * @param string $class module class (acp/mcp/ucp) - * @param string $name module name (class name of the module, or its basename - * phpbb_ext_foo_acp_bar_module, ucp_zebra or zebra) - * @param string $mode mode, as passed through to the module - * - */ - function load($class, $name, $mode = false) - { - // new modules use the full class names, old ones are always called _, e.g. acp_board - // in the latter case this function may be called as load('acp', 'board') - if (!class_exists($name) && substr($name, 0, strlen($class) + 1) !== $class . '_') - { - $name = $class . '_' . $name; - } - - $this->p_class = $class; - $this->p_name = $name; - - // Set active module to true instead of using the id - $this->active_module = true; - - $this->load_active($mode); - } - - /** - * Display module - */ - function display($page_title, $display_online_list = false) - { - global $template, $user; - - // Generate the page - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_header($page_title); - } - else - { - page_header($page_title, $display_online_list); - } - - $template->set_filenames(array( - 'body' => $this->get_tpl_name()) - ); - - if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) - { - adm_page_footer(); - } - else - { - page_footer(); - } - } - - /** - * Toggle whether this module will be displayed or not - */ - function set_display($id, $mode = false, $display = true) - { - foreach ($this->module_ary as $row_id => $item_ary) - { - if (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (!$mode || $item_ary['mode'] === $mode)) - { - $this->module_ary[$row_id]['display'] = (int) $display; - } - } - } - - /** - * Add custom MOD info language file - */ - function add_mod_info($module_class) - { - global $config, $user, $phpEx, $phpbb_extension_manager; - - $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('info_' . strtolower($module_class) . '_') - ->suffix(".$phpEx") - ->extension_directory('/language/' . basename($config['default_lang'])) - ->core_path('language/' . basename($config['default_lang']) . '/mods/') - ->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('info_' . strtolower($module_class) . '_') - ->suffix(".$phpEx") - ->extension_directory('/language/en') - ->core_path('language/en/mods/') - ->find(); - } - - // Find files in the user's language - $user_lang_files = $finder - ->prefix('info_' . strtolower($module_class) . '_') - ->suffix(".$phpEx") - ->extension_directory('/language/' . $user->lang_name) - ->core_path('language/' . $user->lang_name . '/mods/') - ->find(); - - $lang_files = array_merge($english_lang_files, $default_lang_files, $user_lang_files); - foreach ($lang_files as $lang_file => $ext_name) - { - $user->add_lang_ext($ext_name, $lang_file); - } - } - - /** - * Retrieve shortened module basename for legacy basenames (with xcp_ prefix) - * - * @param string $basename A module basename - * @return string The basename if it starts with phpbb_ or the basename with - * the current p_class (e.g. acp_) stripped. - */ - protected function get_short_name($basename) - { - if (substr($basename, 0, 6) === 'phpbb\\' || strpos($basename, '\\') !== false) - { - return $basename; - } - - // strip xcp_ prefix from old classes - return substr($basename, strlen($this->p_class) + 1); - } - - /** - * If the basename contains a \ we don't use that for the URL. - * - * Firefox is currently unable to correctly copy a urlencoded \ - * so users will be unable to post links to modules. - * However we can replace them with dashes and re-replace them later - * - * @param string $basename Basename of the module - * @return string Identifier that should be used for - * module link creation - */ - protected function get_module_identifier($basename) - { - if (strpos($basename, '\\') === false) - { - return $basename; - } - - return str_replace('\\', '-', $basename); - } - - /** - * Checks whether the given module basename is a correct class name - * - * @param string $basename A module basename - * @return bool True if the basename starts with phpbb_ or (x)cp_, false otherwise - */ - protected function is_full_class($basename) - { - return (strpos($basename, '\\') !== false || preg_match('/^(ucp|mcp|acp)_/', $basename)); - } -} diff --git a/install/update/old/includes/functions_posting.php b/install/update/old/includes/functions_posting.php deleted file mode 100644 index 3640f54..0000000 --- a/install/update/old/includes/functions_posting.php +++ /dev/null @@ -1,2772 +0,0 @@ - -* @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; -} - -/** -* Fill smiley templates (or just the variables) with smilies, either in a window or inline -*/ -function generate_smilies($mode, $forum_id) -{ - global $db, $user, $config, $template, $phpbb_dispatcher, $request; - global $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_path_helper; - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id); - $start = $request->variable('start', 0); - - if ($mode == 'window') - { - if ($forum_id) - { - $sql = 'SELECT forum_style - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $user->setup('posting', (int) $row['forum_style']); - } - else - { - $user->setup('posting'); - } - - page_header($user->lang['SMILIES']); - - $sql = 'SELECT COUNT(smiley_id) AS item_count - FROM ' . SMILIES_TABLE . ' - GROUP BY smiley_url'; - $result = $db->sql_query($sql, 3600); - - $smiley_count = 0; - while ($row = $db->sql_fetchrow($result)) - { - ++$smiley_count; - } - $db->sql_freeresult($result); - - $template->set_filenames(array( - 'body' => 'posting_smilies.html') - ); - - $start = $pagination->validate_start($start, $config['smilies_per_page'], $smiley_count); - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $smiley_count, $config['smilies_per_page'], $start); - } - - $display_link = false; - if ($mode == 'inline') - { - $sql = 'SELECT smiley_id - FROM ' . SMILIES_TABLE . ' - WHERE display_on_posting = 0'; - $result = $db->sql_query_limit($sql, 1, 0, 3600); - - if ($row = $db->sql_fetchrow($result)) - { - $display_link = true; - } - $db->sql_freeresult($result); - } - - if ($mode == 'window') - { - $sql = 'SELECT smiley_url, MIN(emotion) as emotion, MIN(code) AS code, smiley_width, smiley_height, MIN(smiley_order) AS min_smiley_order - FROM ' . SMILIES_TABLE . ' - GROUP BY smiley_url, smiley_width, smiley_height - ORDER BY min_smiley_order'; - $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $start, 3600); - } - else - { - $sql = 'SELECT * - FROM ' . SMILIES_TABLE . ' - WHERE display_on_posting = 1 - ORDER BY smiley_order'; - $result = $db->sql_query($sql, 3600); - } - - $smilies = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (empty($smilies[$row['smiley_url']])) - { - $smilies[$row['smiley_url']] = $row; - } - } - $db->sql_freeresult($result); - - 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(); - - foreach ($smilies as $row) - { - /** - * Modify smiley root path before populating smiley list - * - * @event core.generate_smilies_before - * @var string root_path root_path for smilies - * @since 3.1.11-RC1 - */ - $vars = array('root_path'); - extract($phpbb_dispatcher->trigger_event('core.generate_smilies_before', compact($vars))); - $template->assign_block_vars('smiley', array( - 'SMILEY_CODE' => $row['code'], - 'A_SMILEY_CODE' => addslashes($row['code']), - 'SMILEY_IMG' => $root_path . $config['smilies_path'] . '/' . $row['smiley_url'], - 'SMILEY_WIDTH' => $row['smiley_width'], - 'SMILEY_HEIGHT' => $row['smiley_height'], - 'SMILEY_DESC' => $row['emotion']) - ); - } - } - - /** - * This event is called after the smilies are populated - * - * @event core.generate_smilies_after - * @var string mode Mode of the smilies: window|inline - * @var int forum_id The forum ID we are currently in - * @var bool display_link Shall we display the "more smilies" link? - * @since 3.1.0-a1 - */ - $vars = array('mode', 'forum_id', 'display_link'); - extract($phpbb_dispatcher->trigger_event('core.generate_smilies_after', compact($vars))); - - if ($mode == 'inline' && $display_link) - { - $template->assign_vars(array( - 'S_SHOW_SMILEY_LINK' => true, - 'U_MORE_SMILIES' => $base_url, - )); - } - - if ($mode == 'window') - { - page_footer(); - } -} - -/** -* Update last post information -* Should be used instead of sync() if only the last post information are out of sync... faster -* -* @param string $type Can be forum|topic -* @param mixed $ids topic/forum ids -* @param bool $return_update_sql true: SQL query shall be returned, false: execute SQL -*/ -function update_post_information($type, $ids, $return_update_sql = false) -{ - global $db; - - if (empty($ids)) - { - return; - } - if (!is_array($ids)) - { - $ids = array($ids); - } - - $update_sql = $empty_forums = $not_empty_forums = array(); - - if ($type != 'topic') - { - $topic_join = ', ' . TOPICS_TABLE . ' t'; - $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_visibility = ' . ITEM_APPROVED; - } - else - { - $topic_join = ''; - $topic_condition = ''; - } - - if (count($ids) == 1) - { - $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 . " - ORDER BY p.post_id DESC"; - $result = $db->sql_query_limit($sql, 1); - } - else - { - $sql = 'SELECT p.' . $type . '_id, MAX(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 . " - GROUP BY p.{$type}_id"; - $result = $db->sql_query($sql); - } - - $last_post_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (count($ids) == 1) - { - $row[$type . '_id'] = $ids[0]; - } - - if ($type == 'forum') - { - $not_empty_forums[] = $row['forum_id']; - - if (empty($row['last_post_id'])) - { - $empty_forums[] = $row['forum_id']; - } - } - - $last_post_ids[] = $row['last_post_id']; - } - $db->sql_freeresult($result); - - if ($type == 'forum') - { - $empty_forums = array_merge($empty_forums, array_diff($ids, $not_empty_forums)); - - foreach ($empty_forums as $void => $forum_id) - { - $update_sql[$forum_id][] = 'forum_last_post_id = 0'; - $update_sql[$forum_id][] = "forum_last_post_subject = ''"; - $update_sql[$forum_id][] = 'forum_last_post_time = 0'; - $update_sql[$forum_id][] = 'forum_last_poster_id = 0'; - $update_sql[$forum_id][] = "forum_last_poster_name = ''"; - $update_sql[$forum_id][] = "forum_last_poster_colour = ''"; - } - } - - 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 - WHERE p.poster_id = u.user_id - AND ' . $db->sql_in_set('p.post_id', $last_post_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $update_sql[$row["{$type}_id"]][] = $type . '_last_post_id = ' . (int) $row['post_id']; - $update_sql[$row["{$type}_id"]][] = "{$type}_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'"; - $update_sql[$row["{$type}_id"]][] = $type . '_last_post_time = ' . (int) $row['post_time']; - $update_sql[$row["{$type}_id"]][] = $type . '_last_poster_id = ' . (int) $row['poster_id']; - $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'"; - $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'"; - } - $db->sql_freeresult($result); - } - unset($empty_forums, $ids, $last_post_ids); - - if ($return_update_sql || !count($update_sql)) - { - return $update_sql; - } - - $table = ($type == 'forum') ? FORUMS_TABLE : TOPICS_TABLE; - - foreach ($update_sql as $update_id => $update_sql_ary) - { - $sql = "UPDATE $table - SET " . implode(', ', $update_sql_ary) . " - WHERE {$type}_id = $update_id"; - $db->sql_query($sql); - } - - return; -} - -/** -* Generate Topic Icons for display -*/ -function posting_gen_topic_icons($mode, $icon_id) -{ - global $phpbb_root_path, $config, $template, $cache; - - // Grab icons - $icons = $cache->obtain_icons(); - - if (!$icon_id) - { - $template->assign_var('S_NO_ICON_CHECKED', ' checked="checked"'); - } - - if (count($icons)) - { - $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; - - foreach ($icons as $id => $data) - { - if ($data['display']) - { - $template->assign_block_vars('topic_icon', array( - 'ICON_ID' => $id, - '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"' : '') - ); - } - } - - return true; - } - - return false; -} - -/** -* Build topic types able to be selected -*/ -function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL) -{ - 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'), - 'announce_global' => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL') - ); - - $topic_type_array = array(); - - foreach ($topic_types as $auth_key => $topic_value) - { - if ($auth->acl_get('f_' . $auth_key, $forum_id)) - { - $toggle = true; - - $topic_type_array[] = array( - 'VALUE' => $topic_value['const'], - 'S_CHECKED' => ($cur_topic_type == $topic_value['const']) ? ' checked="checked"' : '', - 'L_TOPIC_TYPE' => $user->lang[$topic_value['lang']] - ); - } - } - - if ($toggle) - { - $topic_type_array = array_merge(array(0 => array( - 'VALUE' => POST_NORMAL, - 'S_CHECKED' => ($cur_topic_type == POST_NORMAL) ? ' checked="checked"' : '', - 'L_TOPIC_TYPE' => $user->lang['POST_NORMAL'])), - - $topic_type_array - ); - - foreach ($topic_type_array as $array) - { - $template->assign_block_vars('topic_type', $array); - } - - $template->assign_vars(array( - 'S_TOPIC_TYPE_STICKY' => ($auth->acl_get('f_sticky', $forum_id)), - 'S_TOPIC_TYPE_ANNOUNCE' => ($auth->acl_gets('f_announce', 'f_announce_global', $forum_id)), - )); - } - - return $toggle; -} - -// -// Attachment related functions -// - -/** -* 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 array $local_filedata A filespec object created for the local file -* -* @return array File data array -*/ -function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false) -{ - global $phpbb_container; - - /** @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 $file; -} - -/** -* Calculate the needed size for Thumbnail -*/ -function get_img_size_format($width, $height) -{ - global $config; - - // Maximum Width the Image can take - $max_width = ($config['img_max_thumb_width']) ? $config['img_max_thumb_width'] : 400; - - if ($width > $height) - { - return array( - round($width * ($max_width / $width)), - round($height * ($max_width / $width)) - ); - } - else - { - return array( - round($width * ($max_width / $height)), - round($height * ($max_width / $height)) - ); - } -} - -/** -* Return supported image types -*/ -function get_supported_image_types($type = false) -{ - if (@extension_loaded('gd')) - { - $format = imagetypes(); - $new_type = 0; - - if ($type !== false) - { - // Type is one of the IMAGETYPE constants - it is fetched from getimagesize() - switch ($type) - { - // GIF - case IMAGETYPE_GIF: - $new_type = ($format & IMG_GIF) ? IMG_GIF : false; - break; - - // JPG, JPC, JP2 - case IMAGETYPE_JPEG: - case IMAGETYPE_JPC: - case IMAGETYPE_JPEG2000: - case IMAGETYPE_JP2: - case IMAGETYPE_JPX: - case IMAGETYPE_JB2: - $new_type = ($format & IMG_JPG) ? IMG_JPG : false; - break; - - // PNG - case IMAGETYPE_PNG: - $new_type = ($format & IMG_PNG) ? IMG_PNG : false; - break; - - // WBMP - case IMAGETYPE_WBMP: - $new_type = ($format & IMG_WBMP) ? IMG_WBMP : false; - break; - } - } - else - { - $new_type = array(); - $go_through_types = array(IMG_GIF, IMG_JPG, IMG_PNG, IMG_WBMP); - - foreach ($go_through_types as $check_type) - { - if ($format & $check_type) - { - $new_type[] = $check_type; - } - } - } - - return array( - 'gd' => ($new_type) ? true : false, - 'format' => $new_type, - 'version' => (function_exists('imagecreatetruecolor')) ? 2 : 1 - ); - } - - return array('gd' => false); -} - -/** -* Create Thumbnail -*/ -function create_thumbnail($source, $destination, $mimetype) -{ - global $config, $phpbb_filesystem, $phpbb_dispatcher; - - $min_filesize = (int) $config['img_min_thumb_filesize']; - $img_filesize = (file_exists($source)) ? @filesize($source) : false; - - if (!$img_filesize || $img_filesize <= $min_filesize) - { - return false; - } - - $dimension = @getimagesize($source); - - if ($dimension === false) - { - return false; - } - - list($width, $height, $type, ) = $dimension; - - if (empty($width) || empty($height)) - { - return false; - } - - list($new_width, $new_height) = get_img_size_format($width, $height); - - // Do not create a thumbnail if the resulting width/height is bigger than the original one - if ($new_width >= $width && $new_height >= $height) - { - return false; - } - - $thumbnail_created = false; - - /** - * 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 (!$thumbnail_created) - { - $type = get_supported_image_types($type); - - if ($type['gd']) - { - // If the type is not supported, we are not able to create a thumbnail - if ($type['format'] === false) - { - return false; - } - - switch ($type['format']) - { - case IMG_GIF: - $image = @imagecreatefromgif($source); - break; - - case IMG_JPG: - @ini_set('gd.jpeg_ignore_warning', 1); - $image = @imagecreatefromjpeg($source); - break; - - case IMG_PNG: - $image = @imagecreatefrompng($source); - break; - - case IMG_WBMP: - $image = @imagecreatefromwbmp($source); - break; - } - - if (empty($image)) - { - return false; - } - - if ($type['version'] == 1) - { - $new_image = imagecreate($new_width, $new_height); - - if ($new_image === false) - { - return false; - } - - imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); - } - else - { - $new_image = imagecreatetruecolor($new_width, $new_height); - - if ($new_image === false) - { - return false; - } - - // Preserve alpha transparency (png for example) - @imagealphablending($new_image, false); - @imagesavealpha($new_image, true); - - imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); - } - - // If we are in safe mode create the destination file prior to using the gd functions to circumvent a PHP bug - if (@ini_get('safe_mode') || @strtolower(ini_get('safe_mode')) == 'on') - { - @touch($destination); - } - - switch ($type['format']) - { - case IMG_GIF: - imagegif($new_image, $destination); - break; - - case IMG_JPG: - imagejpeg($new_image, $destination, 90); - break; - - case IMG_PNG: - imagepng($new_image, $destination); - break; - - case IMG_WBMP: - imagewbmp($new_image, $destination); - break; - } - - imagedestroy($new_image); - } - else - { - return false; - } - } - - if (!file_exists($destination)) - { - return false; - } - - try - { - $phpbb_filesystem->phpbb_chmod($destination, CHMOD_READ | CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - - return true; -} - -/** -* Assign Inline attachments (build option fields) -*/ -function posting_gen_inline_attachments(&$attachment_data) -{ - global $template; - - if (count($attachment_data)) - { - $s_inline_attachment_options = ''; - - foreach ($attachment_data as $i => $attachment) - { - $s_inline_attachment_options .= ''; - } - - $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options); - - return true; - } - - return false; -} - -/** -* Generate inline attachment entry -*/ -function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true) -{ - 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' => count($attachment_data), - 'FILESIZE' => $config['max_filesize'], - 'FILE_COMMENT' => (isset($filename_data['filecomment'])) ? $filename_data['filecomment'] : '', - )); - - 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 = ''; - $attach_row['real_filename'] = utf8_basename($attach_row['real_filename']); - - foreach ($attach_row as $key => $value) - { - $hidden .= ''; - } - - $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&id=' . (int) $attach_row['attach_id'], true, ($attach_row['is_orphan']) ? $user->session_id : false); - - $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'], - 'ATTACH_ID' => $attach_row['attach_id'], - 'S_IS_ORPHAN' => $attach_row['is_orphan'], - 'ASSOC_INDEX' => $count, - 'FILESIZE' => get_formatted_filesize($attach_row['filesize']), - - 'U_VIEW_ATTACHMENT' => $download_link, - '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 count($attachment_data); -} - -// -// General Post functions -// - -/** -* Load Drafts -*/ -function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $msg_id = 0) -{ - global $user, $db, $template, $auth; - global $phpbb_root_path, $phpbb_dispatcher, $phpEx; - - $topic_ids = $forum_ids = $draft_rows = array(); - - // Load those drafts not connected to forums/topics - // If forum_id == 0 AND topic_id == 0 then this is a PM draft - if (!$topic_id && !$forum_id) - { - $sql_and = ' AND d.forum_id = 0 AND d.topic_id = 0'; - } - else - { - $sql_and = ''; - $sql_and .= ($forum_id) ? ' AND d.forum_id = ' . (int) $forum_id : ''; - $sql_and .= ($topic_id) ? ' AND d.topic_id = ' . (int) $topic_id : ''; - } - - $sql = 'SELECT d.*, f.forum_id, f.forum_name - FROM ' . DRAFTS_TABLE . ' d - LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = d.forum_id) - WHERE d.user_id = ' . $user->data['user_id'] . " - $sql_and - ORDER BY d.save_time DESC"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_id']) - { - $topic_ids[] = (int) $row['topic_id']; - } - $draft_rows[] = $row; - } - $db->sql_freeresult($result); - - if (!count($draft_rows)) - { - return; - } - - $topic_rows = array(); - if (count($topic_ids)) - { - $sql = 'SELECT topic_id, forum_id, topic_title, topic_poster - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', array_unique($topic_ids)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $topic_rows[$row['topic_id']] = $row; - } - $db->sql_freeresult($result); - } - - /** - * Drafts found and their topics - * Edit $draft_rows in order to add or remove drafts loaded - * - * @event core.load_drafts_draft_list_result - * @var array draft_rows The drafts query result. Includes its forum id and everything about the draft - * @var array topic_ids The list of topics got from the topics table - * @var array topic_rows The topics that draft_rows references - * @since 3.1.0-RC3 - */ - $vars = array('draft_rows', 'topic_ids', 'topic_rows'); - extract($phpbb_dispatcher->trigger_event('core.load_drafts_draft_list_result', compact($vars))); - - unset($topic_ids); - - $template->assign_var('S_SHOW_DRAFTS', true); - - foreach ($draft_rows as $draft) - { - $link_topic = $link_forum = $link_pm = false; - $view_url = $title = ''; - - if (isset($topic_rows[$draft['topic_id']]) - && ( - ($topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_get('f_read', $topic_rows[$draft['topic_id']]['forum_id'])) - || - (!$topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_getf_global('f_read')) - )) - { - $topic_forum_id = ($topic_rows[$draft['topic_id']]['forum_id']) ? $topic_rows[$draft['topic_id']]['forum_id'] : $forum_id; - - $link_topic = true; - $view_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_forum_id . '&t=' . $draft['topic_id']); - $title = $topic_rows[$draft['topic_id']]['topic_title']; - - $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $topic_forum_id . '&t=' . $draft['topic_id'] . '&mode=reply&d=' . $draft['draft_id']); - } - else if ($draft['forum_id'] && $auth->acl_get('f_read', $draft['forum_id'])) - { - $link_forum = true; - $view_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $draft['forum_id']); - $title = $draft['forum_name']; - - $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $draft['forum_id'] . '&mode=post&d=' . $draft['draft_id']); - } - else - { - // Either display as PM draft if forum_id and topic_id are empty or if access to the forums has been denied afterwards... - $link_pm = true; - $insert_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=compose&d={$draft['draft_id']}" . (($pm_action) ? "&action=$pm_action" : '') . (($msg_id) ? "&p=$msg_id" : '')); - } - - $template->assign_block_vars('draftrow', array( - 'DRAFT_ID' => $draft['draft_id'], - 'DATE' => $user->format_date($draft['save_time']), - 'DRAFT_SUBJECT' => $draft['draft_subject'], - - 'TITLE' => $title, - 'U_VIEW' => $view_url, - 'U_INSERT' => $insert_url, - - 'S_LINK_PM' => $link_pm, - 'S_LINK_TOPIC' => $link_topic, - 'S_LINK_FORUM' => $link_forum) - ); - } -} - -/** -* Topic Review -*/ -function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true) -{ - 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'; - - // Go ahead and pull all data for this topic - $sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p' . " - WHERE p.topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . ' - ' . (($mode == 'post_review') ? " AND p.post_id > $cur_post_id" : '') . ' - ' . (($mode == 'post_review_edit') ? " AND p.post_id = $cur_post_id" : '') . ' - ORDER BY p.post_time ' . $sql_sort . ', p.post_id ' . $sql_sort; - $result = $db->sql_query_limit($sql, $config['posts_per_page']); - - $post_list = array(); - - while ($row = $db->sql_fetchrow($result)) - { - $post_list[] = $row['post_id']; - } - - $db->sql_freeresult($result); - - if (!count($post_list)) - { - return false; - } - - // Handle 'post_review_edit' like 'post_review' from now on - if ($mode == 'post_review_edit') - { - $mode = 'post_review'; - } - - $sql_ary = array( - 'SELECT' => 'u.username, u.user_id, u.user_colour, p.*, z.friend, z.foe, uu.username as post_delete_username, uu.user_colour as post_delete_user_colour', - - 'FROM' => array( - USERS_TABLE => 'u', - POSTS_TABLE => 'p', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ZEBRA_TABLE => 'z'), - 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id', - ), - array( - 'FROM' => array(USERS_TABLE => 'uu'), - 'ON' => 'uu.user_id = p.post_delete_user', - ), - ), - - 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . ' - AND u.user_id = p.poster_id', - ); - - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - - $rowset = array(); - $has_attachments = false; - while ($row = $db->sql_fetchrow($result)) - { - $rowset[$row['post_id']] = $row; - - if ($row['post_attachment']) - { - $has_attachments = true; - } - } - $db->sql_freeresult($result); - - // Grab extensions - $attachments = array(); - if ($has_attachments && $auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id)) - { - // Get attachments... - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $post_list) . ' - AND in_message = 0 - ORDER BY filetime DESC, post_msg_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $attachments[$row['post_msg_id']][] = $row; - } - $db->sql_freeresult($result); - } - - /** - * Event to modify the posts list for topic reviews - * - * @event core.topic_review_modify_post_list - * @var array attachments Array with the post attachments data - * @var int cur_post_id Post offset ID - * @var int forum_id The topic's forum ID - * @var string mode The topic review mode - * @var array post_list Array with the post IDs - * @var array rowset Array with the posts data - * @var bool show_quote_button Flag indicating if the quote button should be displayed - * @var int topic_id The topic ID that is being reviewed - * @since 3.1.9-RC1 - */ - $vars = array( - 'attachments', - 'cur_post_id', - 'forum_id', - 'mode', - 'post_list', - 'rowset', - 'show_quote_button', - 'topic_id', - ); - extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_post_list', compact($vars))); - - 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. - if (!isset($rowset[$post_list[$i]])) - { - continue; - } - - $row = $rowset[$post_list[$i]]; - - $poster_id = $row['user_id']; - $post_subject = $row['post_subject']; - - $decoded_message = false; - - if ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) - { - $decoded_message = censor_text($row['post_text']); - decode_message($decoded_message, $row['bbcode_uid']); - - $decoded_message = bbcode_nl2br($decoded_message); - } - - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); - $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0); - $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true); - - if (!empty($attachments[$row['post_id']])) - { - $update_count = array(); - parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count); - } - - $post_subject = censor_text($post_subject); - - $post_anchor = ($mode == 'post_review') ? 'ppr' . $row['post_id'] : 'pr' . $row['post_id']; - $u_show_post = append_sid($phpbb_root_path . 'viewtopic.' . $phpEx, "f=$forum_id&t=$topic_id&p={$row['post_id']}&view=show#p{$row['post_id']}"); - - $l_deleted_message = ''; - if ($row['post_visibility'] == ITEM_DELETED) - { - $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); - - // User having deleted the post also being the post author? - if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id) - { - $display_username = $display_postername; - } - else - { - $display_username = get_username_string('full', $row['post_delete_user'], $row['post_delete_username'], $row['post_delete_user_colour']); - } - - if ($row['post_delete_reason']) - { - $l_deleted_message = $user->lang('POST_DELETED_BY_REASON', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true), $row['post_delete_reason']); - } - else - { - $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true)); - } - } - - $post_row = array( - 'POST_AUTHOR_FULL' => get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - - 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false, - 'S_FRIEND' => ($row['friend']) ? 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']), "", '') : '', - 'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED) ? true : false, - 'L_DELETE_POST' => $l_deleted_message, - - 'POST_SUBJECT' => $post_subject, - 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['POST']), - 'POST_DATE' => $user->format_date($row['post_time']), - '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&mode=post_details&f=' . $forum_id . '&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'])) : '', - ); - - $current_row_number = $i; - - /** - * Event to modify the template data block for topic reviews - * - * @event core.topic_review_modify_row - * @var string mode The review mode - * @var int topic_id The topic that is being reviewed - * @var int forum_id The topic's forum - * @var int cur_post_id Post offset id - * @var int current_row_number Number of the current row being iterated - * @var array post_row Template block array of the current post - * @var array row Array with original post and user data - * @since 3.1.4-RC1 - */ - $vars = array( - 'mode', - 'topic_id', - 'forum_id', - 'cur_post_id', - 'current_row_number', - 'post_row', - 'row', - ); - extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_row', compact($vars))); - - $template->assign_block_vars($mode . '_row', $post_row); - - // Display not already displayed Attachments for this post, we already parsed them. ;) - if (!empty($attachments[$row['post_id']])) - { - foreach ($attachments[$row['post_id']] as $attachment) - { - $template->assign_block_vars($mode . '_row.attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - } - - unset($rowset[$post_list[$i]]); - } - - if ($mode == 'topic_review') - { - $template->assign_var('QUOTE_IMG', $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE'])); - } - - return true; -} - -// -// Post handling functions -// - -/** -* Delete Post -*/ -function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '') -{ - global $db, $user, $phpbb_container, $phpbb_dispatcher; - global $config, $phpEx, $phpbb_root_path; - - // Specify our post mode - $post_mode = 'delete'; - if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1)) - { - $post_mode = 'delete_topic'; - } - else if ($data['topic_first_post_id'] == $post_id) - { - $post_mode = 'delete_first_post'; - } - else if ($data['topic_last_post_id'] == $post_id) - { - $post_mode = 'delete_last_post'; - } - $sql_data = array(); - $next_post_id = false; - - include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - - $db->sql_transaction('begin'); - - // we must make sure to update forums that contain the shadow'd topic - if ($post_mode == 'delete_topic') - { - $shadow_forum_ids = array(); - - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_moved_id', $topic_id); - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($shadow_forum_ids[(int) $row['forum_id']])) - { - $shadow_forum_ids[(int) $row['forum_id']] = 1; - } - else - { - $shadow_forum_ids[(int) $row['forum_id']]++; - } - } - $db->sql_freeresult($result); - } - - /* @var $phpbb_content_visibility \phpbb\content_visibility */ - $phpbb_content_visibility = $phpbb_container->get('content.visibility'); - - // (Soft) delete the post - if ($is_soft && ($post_mode != 'delete_topic')) - { - $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $post_id, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason, ($data['topic_first_post_id'] == $post_id), ($data['topic_last_post_id'] == $post_id)); - } - else if (!$is_soft) - { - if (!delete_posts('post_id', array($post_id), false, false, false)) - { - // Try to delete topic, we may had an previous error causing inconsistency - if ($post_mode == 'delete_topic') - { - delete_topics('topic_id', array($topic_id), false); - } - trigger_error('ALREADY_DELETED'); - } - } - - $db->sql_transaction('commit'); - - // Collect the necessary information for updating the tables - $sql_data[FORUMS_TABLE] = $sql_data[TOPICS_TABLE] = ''; - switch ($post_mode) - { - case 'delete_topic': - - foreach ($shadow_forum_ids as $updated_forum => $topic_count) - { - // 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 . ' - WHERE forum_id = ' . $updated_forum; - $db->sql_query($sql); - update_post_information('forum', $updated_forum); - } - - if ($is_soft) - { - $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason); - } - else - { - delete_topics('topic_id', array($topic_id), false); - - $phpbb_content_visibility->remove_topic_from_statistic($data, $sql_data); - - $update_sql = update_post_information('forum', $forum_id, true); - if (count($update_sql)) - { - $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : ''; - $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]); - } - } - - break; - - case 'delete_first_post': - $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE p.topic_id = $topic_id - AND p.poster_id = u.user_id - AND p.post_visibility = " . ITEM_APPROVED . ' - ORDER BY p.post_time ASC, p.post_id ASC'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - // No approved post, so the first is a not-approved post (unapproved or soft deleted) - $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE p.topic_id = $topic_id - AND p.poster_id = u.user_id - ORDER BY p.post_time ASC, p.post_id ASC"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - $next_post_id = (int) $row['post_id']; - - $sql_data[TOPICS_TABLE] = $db->sql_build_array('UPDATE', array( - 'topic_poster' => (int) $row['poster_id'], - 'topic_first_post_id' => (int) $row['post_id'], - 'topic_first_poster_colour' => $row['user_colour'], - 'topic_first_poster_name' => ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'], - 'topic_time' => (int) $row['post_time'], - )); - break; - - case 'delete_last_post': - if (!$is_soft) - { - // Update last post information when hard deleting. Soft delete already did that by itself. - $update_sql = update_post_information('forum', $forum_id, true); - if (count($update_sql)) - { - $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . implode(', ', $update_sql[$forum_id]); - } - - $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_bumped = 0, topic_bumper = 0'; - - $update_sql = update_post_information('topic', $topic_id, true); - if (!empty($update_sql)) - { - $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]); - $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]); - } - } - - if (!$next_post_id) - { - $sql = 'SELECT MAX(post_id) as last_post_id - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id); - $result = $db->sql_query($sql); - $next_post_id = (int) $db->sql_fetchfield('last_post_id'); - $db->sql_freeresult($result); - } - break; - - case 'delete': - $sql = 'SELECT post_id - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . ' - AND post_time > ' . $data['post_time'] . ' - ORDER BY post_time ASC, post_id ASC'; - $result = $db->sql_query_limit($sql, 1); - $next_post_id = (int) $db->sql_fetchfield('post_id'); - $db->sql_freeresult($result); - break; - } - - if (($post_mode == 'delete') || ($post_mode == 'delete_last_post') || ($post_mode == 'delete_first_post')) - { - if (!$is_soft) - { - $phpbb_content_visibility->remove_post_from_statistic($data, $sql_data); - } - - $sql = 'SELECT 1 AS has_attachments - FROM ' . ATTACHMENTS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query_limit($sql, 1); - $has_attachments = (int) $db->sql_fetchfield('has_attachments'); - $db->sql_freeresult($result); - - if (!$has_attachments) - { - $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_attachment = 0'; - } - } - - $db->sql_transaction('begin'); - - $where_sql = array( - FORUMS_TABLE => "forum_id = $forum_id", - TOPICS_TABLE => "topic_id = $topic_id", - USERS_TABLE => 'user_id = ' . $data['poster_id'], - ); - - foreach ($sql_data as $table => $update_sql) - { - if ($update_sql) - { - $db->sql_query("UPDATE $table SET $update_sql WHERE " . $where_sql[$table]); - } - } - - // Adjust posted info for this user by looking for a post by him/her within this topic... - if ($post_mode != 'delete_topic' && $config['load_db_track'] && $data['poster_id'] != ANONYMOUS) - { - $sql = 'SELECT poster_id - FROM ' . POSTS_TABLE . ' - WHERE topic_id = ' . $topic_id . ' - AND poster_id = ' . $data['poster_id']; - $result = $db->sql_query_limit($sql, 1); - $poster_id = (int) $db->sql_fetchfield('poster_id'); - $db->sql_freeresult($result); - - // The user is not having any more posts within this topic - if (!$poster_id) - { - $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . ' - WHERE topic_id = ' . $topic_id . ' - AND user_id = ' . $data['poster_id']; - $db->sql_query($sql); - } - } - - $db->sql_transaction('commit'); - - if ($data['post_reported'] && ($post_mode != 'delete_topic')) - { - sync('topic_reported', 'topic_id', array($topic_id)); - } - - /** - * This event is used for performing actions directly after a post or topic - * has been deleted. - * - * @event core.delete_post_after - * @var int forum_id Post forum ID - * @var int topic_id Post topic ID - * @var int post_id Post ID - * @var array data Post data - * @var bool is_soft Soft delete flag - * @var string softdelete_reason Soft delete reason - * @var string post_mode delete_topic, delete_first_post, delete_last_post or delete - * @var mixed next_post_id Next post ID in the topic (post ID or false) - * - * @since 3.1.11-RC1 - */ - $vars = array( - 'forum_id', - 'topic_id', - 'post_id', - 'data', - 'is_soft', - 'softdelete_reason', - 'post_mode', - 'next_post_id', - ); - extract($phpbb_dispatcher->trigger_event('core.delete_post_after', compact($vars))); - - return $next_post_id; -} - -/** -* Submit Post -* @todo Split up and create lightweight, simple API for this. -*/ -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, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $phpbb_log, $request; - - $poll = $poll_ary; - $data = $data_ary; - /** - * Modify the data for post submitting - * - * @event core.modify_submit_post_data - * @var string mode Variable containing posting mode value - * @var string subject Variable containing post subject value - * @var string username Variable containing post author name - * @var int topic_type Variable containing topic type value - * @var array poll Array with the poll data for the post - * @var array data Array with the data for the post - * @var bool update_message Flag indicating if the post will be updated - * @var bool update_search_index Flag indicating if the search index will be updated - * @since 3.1.0-a4 - */ - $vars = array( - 'mode', - 'subject', - 'username', - 'topic_type', - 'poll', - 'data', - 'update_message', - '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') - { - return false; - } - - if (!empty($data_ary['post_time'])) - { - $current_time = $data_ary['post_time']; - } - else - { - $current_time = time(); - } - - if ($mode == 'post') - { - $post_mode = 'post'; - $update_message = true; - } - else if ($mode != 'edit') - { - $post_mode = 'reply'; - $update_message = true; - } - else if ($mode == '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_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_ary['poster_id'] : (int) $user->data['user_id']; - - // Retrieve some additional information if not present - 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_ary['post_id']; - $result = $db->sql_query($sql); - $topic_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $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 - $post_visibility = ITEM_APPROVED; - - // Check the permissions for post approval. - // Moderators must go through post approval like ordinary users. - if (!$auth->acl_get('f_noapprove', $data_ary['forum_id'])) - { - // Post not approved, but in queue - $post_visibility = ITEM_UNAPPROVED; - switch ($post_mode) - { - case 'edit_first_post': - case 'edit': - case 'edit_last_post': - case 'edit_topic': - $post_visibility = ITEM_REAPPROVE; - break; - } - } - else if (isset($data_ary['post_visibility']) && $data_ary['post_visibility'] !== false) - { - $post_visibility = $data_ary['post_visibility']; - } - - // MODs/Extensions are able to force any visibility on posts - if (isset($data_ary['force_approved_state'])) - { - $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_ary['force_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 - $db->sql_transaction('begin'); - - // Collect Information - switch ($post_mode) - { - case 'post': - case 'reply': - $sql_data[POSTS_TABLE]['sql'] = array( - 'forum_id' => $data_ary['forum_id'], - 'poster_id' => (int) $user->data['user_id'], - 'icon_id' => $data_ary['icon_id'], - 'poster_ip' => $user->ip, - 'post_time' => $current_time, - 'post_visibility' => $post_visibility, - '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_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; - - case 'edit_first_post': - case 'edit': - - case 'edit_last_post': - case 'edit_topic': - - // If edit reason is given always display edit info - - // If editing last post then display no edit info - // If m_edit permission then display no edit info - // 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_ary['post_edit_reason'] || (!$auth->acl_get('m_edit', $data_ary['forum_id']) && ($post_mode == 'edit' || $post_mode == 'edit_first_post'))) - { - $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_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_ary['post_edit_reason'] && $mode == 'edit' && $auth->acl_get('m_edit', $data_ary['forum_id'])) - { - $sql_data[POSTS_TABLE]['sql'] = array( - 'post_edit_reason' => '', - ); - } - - // If the person editing this post is different to the one having posted then we will add a log entry stating the edit - // 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_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'])) - { - $sql_data[POSTS_TABLE]['sql'] = array(); - } - - $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array( - '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_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_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_ary['message']; - } - - break; - } - - // And the topic ladies and gentlemen - switch ($post_mode) - { - case 'post': - $sql_data[TOPICS_TABLE]['sql'] = array( - 'topic_poster' => (int) $user->data['user_id'], - 'topic_time' => $current_time, - 'topic_last_view_time' => $current_time, - '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, - 'topic_visibility' => $post_visibility, - 'topic_delete_user' => ($post_visibility != ITEM_APPROVED) ? (int) $user->data['user_id'] : 0, - 'topic_title' => $subject, - 'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''), - 'topic_first_poster_colour' => $user->data['user_colour'], - 'topic_type' => $topic_type, - '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_ary['poll_options']) && !empty($poll_ary['poll_options'])) - { - $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; - if ($poll_start < 0) - { - $poll_start = 0; - } - $poll_length = 1; - } - - $sql_data[TOPICS_TABLE]['sql'] = array_merge($sql_data[TOPICS_TABLE]['sql'], array( - 'poll_title' => $poll_ary['poll_title'], - 'poll_start' => $poll_start, - 'poll_max_options' => $poll_ary['poll_max_options'], - 'poll_length' => $poll_length, - 'poll_vote_change' => $poll_ary['poll_vote_change']) - ); - } - - $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) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_approved = forum_topics_approved + 1'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1'; - } - else if ($post_visibility == ITEM_UNAPPROVED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_unapproved = forum_topics_unapproved + 1'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1'; - } - else if ($post_visibility == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_softdeleted = forum_topics_softdeleted + 1'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1'; - } - break; - - case 'reply': - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_view_time = ' . $current_time . ', - topic_bumped = 0, - topic_bumper = 0' . - (($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_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_ary['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : ''); - - if ($post_visibility == ITEM_APPROVED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1'; - } - else if ($post_visibility == ITEM_UNAPPROVED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1'; - } - else if ($post_visibility == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1'; - } - break; - - case 'edit_topic': - case 'edit_first_post': - if (isset($poll_ary['poll_options'])) - { - $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; - if ($poll_start < 0) - { - $poll_start = 0; - } - $poll_length = 1; - } - } - - $sql_data[TOPICS_TABLE]['sql'] = array( - '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_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_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 - * - * @event core.submit_post_modify_sql_data - * @var array data Array with the data for the post - * @var array poll Array with the poll data for the post - * @var string post_mode Variable containing posting mode value - * @var bool sql_data Array with the data for the posting SQL query - * @var string subject Variable containing post subject value - * @var int topic_type Variable containing topic type value - * @var string username Variable containing post author name - * @since 3.1.3-RC1 - */ - $vars = array( - 'data', - 'poll', - 'post_mode', - 'sql_data', - 'subject', - 'topic_type', - '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') - { - $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . - $db->sql_build_array('INSERT', $sql_data[TOPICS_TABLE]['sql']); - $db->sql_query($sql); - - $data_ary['topic_id'] = $db->sql_nextid(); - - $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array( - 'topic_id' => $data_ary['topic_id']) - ); - unset($sql_data[TOPICS_TABLE]['sql']); - } - - // Submit new post - if ($post_mode == 'post' || $post_mode == 'reply') - { - if ($post_mode == 'reply') - { - $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array( - '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_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_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'], - 'topic_last_poster_colour' => $user->data['user_colour'], - 'topic_last_post_subject' => (string) $subject, - ); - } - - if ($post_mode == 'post') - { - $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data_ary['post_id']; - } - - // Update total post count and forum information - if ($post_visibility == ITEM_APPROVED) - { - if ($post_mode == 'post') - { - $config->increment('num_topics', 1, false); - } - $config->increment('num_posts', 1, false); - - $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']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'"; - } - - unset($sql_data[POSTS_TABLE]['sql']); - } - - // Update the topics table - if (isset($sql_data[TOPICS_TABLE]['sql'])) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . ' - WHERE topic_id = ' . $data_ary['topic_id']; - $db->sql_query($sql); - - unset($sql_data[TOPICS_TABLE]['sql']); - } - - // Update the posts table - if (isset($sql_data[POSTS_TABLE]['sql'])) - { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . ' - WHERE post_id = ' . $data_ary['post_id']; - $db->sql_query($sql); - - unset($sql_data[POSTS_TABLE]['sql']); - } - - // Update Poll Tables - if (isset($poll_ary['poll_options'])) - { - $cur_poll_options = array(); - - if ($mode == 'edit') - { - $sql = 'SELECT * - FROM ' . POLL_OPTIONS_TABLE . ' - WHERE topic_id = ' . $data_ary['topic_id'] . ' - ORDER BY poll_option_id'; - $result = $db->sql_query($sql); - - $cur_poll_options = array(); - while ($row = $db->sql_fetchrow($result)) - { - $cur_poll_options[] = $row; - } - $db->sql_freeresult($result); - } - - $sql_insert_ary = array(); - - for ($i = 0, $size = count($poll_ary['poll_options']); $i < $size; $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) 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_ary['poll_options'][$i] != $cur_poll_options[$i]) - { - $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . " - 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_ary['topic_id']; - $db->sql_query($sql); - } - } - } - - $db->sql_multi_insert(POLL_OPTIONS_TABLE, $sql_insert_ary); - - if (count($poll_ary['poll_options']) < count($cur_poll_options)) - { - $sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . ' - 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' && count($poll_ary['poll_options']) != count($cur_poll_options)) - { - $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_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_ary['attachment_data'] as $pos => $attach_row) - { - $orphan_rows[(int) $attach_row['attach_id']] = array(); - } - - if (count($orphan_rows)) - { - $sql = 'SELECT attach_id, filesize, physical_filename - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . ' - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - $orphan_rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $orphan_rows[$row['attach_id']] = $row; - } - $db->sql_freeresult($result); - } - - foreach ($data_ary['attachment_data'] as $pos => $attach_row) - { - if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']])) - { - continue; - } - - if (!$attach_row['is_orphan']) - { - // update entry in db if attachment already stored in db and filespace - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "' - WHERE attach_id = " . (int) $attach_row['attach_id'] . ' - AND is_orphan = 0'; - $db->sql_query($sql); - } - else - { - // insert attachment into db - if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) - { - continue; - } - - $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize']; - $files_added++; - - $attach_sql = array( - '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'], - ); - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . ' - WHERE attach_id = ' . $attach_row['attach_id'] . ' - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $db->sql_query($sql); - } - } - - if ($space_taken && $files_added) - { - $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_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_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_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_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_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_ary['poster_id'] == ANONYMOUS) - { - $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'"; - } - - if ($post_visibility == ITEM_APPROVED) - { - // this does not _necessarily_ mean that we must update the info again, - // it just means that we might have to - $sql = 'SELECT forum_last_post_id, forum_last_post_subject - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . (int) $data_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_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) - { - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'"; - } - - // Update the user name if poster is anonymous... just in case a moderator changed it - if ($data_ary['poster_id'] == ANONYMOUS) - { - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'"; - } - } - } - } - } - - // Update forum stats - $where_sql = array( - POSTS_TABLE => 'post_id = ' . $data_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 - ); - - foreach ($sql_data as $table => $update_ary) - { - if (isset($update_ary['stat']) && implode('', $update_ary['stat'])) - { - $sql = "UPDATE $table SET " . implode(', ', $update_ary['stat']) . ' WHERE ' . $where_sql[$table]; - $db->sql_query($sql); - } - } - - // Delete topic shadows (if any exist). We do not need a shadow topic for an global announcement - if ($topic_type == POST_GLOBAL) - { - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE topic_moved_id = ' . $data_ary['topic_id']; - $db->sql_query($sql); - } - - // Committing the transaction before updating search index - $db->sql_transaction('commit'); - - // Delete draft if post was loaded... - $draft_id = $request->variable('draft_loaded', 0); - if ($draft_id) - { - $sql = 'DELETE FROM ' . DRAFTS_TABLE . " - WHERE draft_id = $draft_id - AND user_id = {$user->data['user_id']}"; - $db->sql_query($sql); - } - - // Index message contents - 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']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if ($error) - { - trigger_error($error); - } - - $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_ary['notify_set'] && $data_ary['notify']) - { - $sql = 'INSERT INTO ' . TOPICS_WATCH_TABLE . ' (user_id, topic_id) - VALUES (' . $user->data['user_id'] . ', ' . $data_ary['topic_id'] . ')'; - $db->sql_query($sql); - } - 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_ary['topic_id']; - $db->sql_query($sql); - } - } - - if ($mode == 'post' || $mode == 'reply' || $mode == 'quote') - { - // Mark this topic as posted to - 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_ary['forum_id'], $data_ary['topic_id'], time()); - - // - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql = 'SELECT mark_time - FROM ' . FORUMS_TRACK_TABLE . ' - WHERE user_id = ' . $user->data['user_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); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $f_mark_time = false; - } - - if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) - { - // Update forum info - $sql = 'SELECT forum_last_post_time - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $data_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_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. - // Doing it this way we can use "...post by guest-username..." in notifications when - // "guest-username" is supplied or ommit the username if it is not. - $username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username']; - - // Send Notifications - $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_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) - { - switch ($mode) - { - case 'post': - $phpbb_notifications->add_notifications(array( - 'notification.type.quote', - 'notification.type.topic', - ), $notification_data); - break; - - case 'reply': - case 'quote': - $phpbb_notifications->add_notifications(array( - 'notification.type.quote', - 'notification.type.bookmark', - 'notification.type.post', - ), $notification_data); - break; - - case 'edit_topic': - 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.bookmark', - 'notification.type.topic', - 'notification.type.post', - ), $notification_data); - break; - } - } - else if ($post_visibility == ITEM_UNAPPROVED) - { - switch ($mode) - { - case 'post': - $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data); - break; - - case 'reply': - case 'quote': - $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data); - break; - - case 'edit_topic': - case 'edit_first_post': - case 'edit': - case 'edit_last_post': - // Nothing to do here - break; - } - } - else if ($post_visibility == ITEM_REAPPROVE) - { - switch ($mode) - { - case 'edit_topic': - case 'edit_first_post': - $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data); - - // Delete the approve_post notification so we can notify the user again, - // when his post got reapproved - $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']); - break; - - case 'edit': - case 'edit_last_post': - $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data); - - // Delete the approve_post notification so we can notify the user again, - // when his post got reapproved - $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']); - break; - - case 'post': - case 'reply': - case 'quote': - // Nothing to do here - break; - } - } - else if ($post_visibility == ITEM_DELETED) - { - switch ($mode) - { - case 'post': - case 'reply': - case 'quote': - case 'edit_topic': - case 'edit_first_post': - case 'edit': - case 'edit_last_post': - // Nothing to do here - break; - } - } - - $params = $add_anchor = ''; - - if ($post_visibility == ITEM_APPROVED || - ($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 .= '&t=' . $data_ary['topic_id']; - - if ($mode != 'post') - { - $params .= '&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 .= '&t=' . $data_ary['topic_id']; - } - - $url = (!$params) ? "{$phpbb_root_path}viewforum.$phpEx" : "{$phpbb_root_path}viewtopic.$phpEx"; - $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 - * available in the $data array. - * - * The only action that can be done by altering data made available to this - * event is to modify the return URL ($url). - * - * @event core.submit_post_end - * @var string mode Variable containing posting mode value - * @var string subject Variable containing post subject value - * @var string username Variable containing post author name - * @var int topic_type Variable containing topic type value - * @var array poll Array with the poll data for the post - * @var array data Array with the data for the post - * @var int post_visibility Variable containing up to date post visibility - * @var bool update_message Flag indicating if the post will be updated - * @var bool update_search_index Flag indicating if the search index will be updated - * @var string url The "Return to topic" URL - * - * @since 3.1.0-a3 - * @changed 3.1.0-RC3 Added vars mode, subject, username, topic_type, - * poll, update_message, update_search_index - */ - $vars = array( - 'mode', - 'subject', - 'username', - 'topic_type', - 'poll', - 'data', - 'post_visibility', - 'update_message', - 'update_search_index', - 'url', - ); - extract($phpbb_dispatcher->trigger_event('core.submit_post_end', compact($vars))); - $data_ary = $data; - $poll_ary = $poll; - unset($data); - unset($poll); - - return $url; -} - -/** -* Handle topic bumping -* @param int $forum_id The ID of the forum the topic is being bumped belongs to -* @param int $topic_id The ID of the topic is being bumping -* @param array $post_data Passes some topic parameters: -* - 'topic_title' -* - 'topic_last_post_id' -* - 'topic_last_poster_id' -* - 'topic_last_post_subject' -* - 'topic_last_poster_name' -* - 'topic_last_poster_colour' -* @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time(). -* @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&topic_id=2&p=3#p3 -*/ -function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false) -{ - global $config, $db, $user, $phpEx, $phpbb_root_path, $phpbb_log; - - if ($bump_time === false) - { - $bump_time = time(); - } - - // Begin bumping - $db->sql_transaction('begin'); - - // Update the topic's last post post_time - $sql = 'UPDATE ' . POSTS_TABLE . " - SET post_time = $bump_time - WHERE post_id = {$post_data['topic_last_post_id']} - AND topic_id = $topic_id"; - $db->sql_query($sql); - - // Sync the topic's last post time, the rest of the topic's last post data isn't changed - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_last_post_time = $bump_time, - topic_bumped = 1, - topic_bumper = " . $user->data['user_id'] . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - // Update the forum's last post info - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ", - forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ", - forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "', - forum_last_post_time = $bump_time, - forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "', - forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "' - WHERE forum_id = $forum_id"; - $db->sql_query($sql); - - // Update bumper's time of the last posting to prevent flood - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastpost_time = $bump_time - WHERE user_id = " . $user->data['user_id']; - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - // Mark this topic as posted to - markread('post', $forum_id, $topic_id, $bump_time); - - // Mark this topic as read - markread('topic', $forum_id, $topic_id, $bump_time); - - // Update forum tracking info - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $sql = 'SELECT mark_time - FROM ' . FORUMS_TRACK_TABLE . ' - WHERE user_id = ' . $user->data['user_id'] . ' - AND forum_id = ' . $forum_id; - $result = $db->sql_query($sql); - $f_mark_time = (int) $db->sql_fetchfield('mark_time'); - $db->sql_freeresult($result); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $f_mark_time = false; - } - - if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) - { - // Update forum info - $sql = 'SELECT forum_last_post_time - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $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($forum_id, $forum_last_post_time, $f_mark_time, false); - } - - $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&t=$topic_id&p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}"; - - return $url; -} - -/** -* Show upload popup (progress bar) -*/ -function phpbb_upload_popup($forum_style = 0) -{ - global $template, $user; - - ($forum_style) ? $user->setup('posting', $forum_style) : $user->setup('posting'); - - page_header($user->lang['PROGRESS_BAR']); - - $template->set_filenames(array( - 'popup' => 'posting_progress_bar.html') - ); - - $template->assign_vars(array( - 'PROGRESS_BAR' => $user->img('upload_bar', $user->lang['UPLOAD_IN_PROGRESS'])) - ); - - $template->display('popup'); - - garbage_collection(); - exit_handler(); -} - -/** -* Do the various checks required for removing posts as well as removing it -* -* @param int $forum_id The id of the forum -* @param int $topic_id The id of the topic -* @param int $post_id The id of the post -* @param array $post_data Array with the post data -* @param bool $is_soft The flag indicating whether it is the soft delete mode -* @param string $delete_reason Description for the post deletion reason -* -* @return null -*/ -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_log, $phpbb_dispatcher; - - $force_delete_allowed = $force_softdelete_allowed = false; - $perm_check = ($is_soft) ? 'softdelete' : 'delete'; - - /** - * This event allows to modify the conditions for the post deletion - * - * @event core.handle_post_delete_conditions - * @var int forum_id The id of the forum - * @var int topic_id The id of the topic - * @var int post_id The id of the post - * @var array post_data Array with the post data - * @var bool is_soft The flag indicating whether it is the soft delete mode - * @var string delete_reason Description for the post deletion reason - * @var bool force_delete_allowed Allow the user to delete the post (all permissions and conditions are ignored) - * @var bool force_softdelete_allowed Allow the user to softdelete the post (all permissions and conditions are ignored) - * @var string perm_check The deletion mode softdelete|delete - * @since 3.1.11-RC1 - */ - $vars = array( - 'forum_id', - 'topic_id', - 'post_id', - 'post_data', - 'is_soft', - 'delete_reason', - 'force_delete_allowed', - 'force_softdelete_allowed', - 'perm_check', - ); - extract($phpbb_dispatcher->trigger_event('core.handle_post_delete_conditions', compact($vars))); - - // If moderator removing post or user itself removing post, present a confirmation screen - if ($force_delete_allowed || ($is_soft && $force_softdelete_allowed) || $auth->acl_get("m_$perm_check", $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get("f_$perm_check", $forum_id) && $post_id == $post_data['topic_last_post_id'] && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time']))) - { - $s_hidden_fields = array( - 'p' => $post_id, - 'f' => $forum_id, - 'mode' => ($is_soft) ? 'soft_delete' : 'delete', - ); - - if (confirm_box(true)) - { - $data = array( - 'topic_first_post_id' => $post_data['topic_first_post_id'], - 'topic_last_post_id' => $post_data['topic_last_post_id'], - 'topic_posts_approved' => $post_data['topic_posts_approved'], - 'topic_posts_unapproved' => $post_data['topic_posts_unapproved'], - 'topic_posts_softdeleted' => $post_data['topic_posts_softdeleted'], - 'topic_visibility' => $post_data['topic_visibility'], - 'topic_type' => $post_data['topic_type'], - 'post_visibility' => $post_data['post_visibility'], - 'post_reported' => $post_data['post_reported'], - 'post_time' => $post_data['post_time'], - 'poster_id' => $post_data['poster_id'], - 'post_postcount' => $post_data['post_postcount'], - ); - - $next_post_id = delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $delete_reason); - $post_username = ($post_data['poster_id'] == ANONYMOUS && !empty($post_data['post_username'])) ? $post_data['post_username'] : $post_data['username']; - - if ($next_post_id === false) - { - $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 - { - $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&t=$topic_id&p=$next_post_id") . "#p$next_post_id"; - $message = $user->lang['POST_DELETED']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_TOPIC', '', ''); - } - } - - meta_refresh(3, $meta_info); - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_FORUM', '', ''); - } - trigger_error($message); - } - else - { - global $template; - - $can_delete = $force_delete_allowed || ($auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_delete', $forum_id))); - $can_softdelete = $force_softdelete_allowed || ($auth->acl_get('m_softdelete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_softdelete', $forum_id))); - - $template->assign_vars(array( - 'S_SOFTDELETED' => $post_data['post_visibility'] == ITEM_DELETED, - 'S_CHECKED_PERMANENT' => $request->is_set_post('delete_permanent') ? ' checked="checked"' : '', - 'S_ALLOWED_DELETE' => $can_delete, - 'S_ALLOWED_SOFTDELETE' => $can_softdelete, - )); - - $l_confirm = 'DELETE_POST'; - if ($post_data['post_visibility'] == ITEM_DELETED) - { - $l_confirm .= '_PERMANENTLY'; - $s_hidden_fields['delete_permanent'] = '1'; - } - else if (!$can_softdelete) - { - $s_hidden_fields['delete_permanent'] = '1'; - } - - confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); - } - } - - // If we are here the user is not able to delete - present the correct error message - if ($post_data['poster_id'] != $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id)) - { - trigger_error('DELETE_OWN_POSTS'); - } - - if ($post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && $post_id != $post_data['topic_last_post_id']) - { - trigger_error('CANNOT_DELETE_REPLIED'); - } - - trigger_error('USER_CANNOT_DELETE'); -} diff --git a/install/update/old/includes/functions_privmsgs.php b/install/update/old/includes/functions_privmsgs.php deleted file mode 100644 index 444bf2c..0000000 --- a/install/update/old/includes/functions_privmsgs.php +++ /dev/null @@ -1,2264 +0,0 @@ - -* @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; -} - -/* - Ability to simply add own rules by doing three things: - 1) Add an appropriate constant - 2) Add a new check array to the global_privmsgs_rules variable and the condition array (if one is required) - 3) Implement the rule logic in the check_rule() function - 4) Add a new language variable to ucp.php - - The user is then able to select the new rule. It will be checked against and handled as specified. - To add new actions (yes, checks can be added here too) to the rule management, the core code has to be modified. -*/ - -define('RULE_IS_LIKE', 1); // Is Like -define('RULE_IS_NOT_LIKE', 2); // Is Not Like -define('RULE_IS', 3); // Is -define('RULE_IS_NOT', 4); // Is Not -define('RULE_BEGINS_WITH', 5); // Begins with -define('RULE_ENDS_WITH', 6); // Ends with -define('RULE_IS_FRIEND', 7); // Is Friend -define('RULE_IS_FOE', 8); // Is Foe -define('RULE_IS_USER', 9); // Is User -define('RULE_IS_GROUP', 10); // Is In Usergroup -define('RULE_ANSWERED', 11); // Answered -define('RULE_FORWARDED', 12); // Forwarded -define('RULE_TO_GROUP', 14); // Usergroup -define('RULE_TO_ME', 15); // Me - -define('ACTION_PLACE_INTO_FOLDER', 1); -define('ACTION_MARK_AS_READ', 2); -define('ACTION_MARK_AS_IMPORTANT', 3); -define('ACTION_DELETE_MESSAGE', 4); - -define('CHECK_SUBJECT', 1); -define('CHECK_SENDER', 2); -define('CHECK_MESSAGE', 3); -define('CHECK_STATUS', 4); -define('CHECK_TO', 5); - -/** -* Global private message rules -* These rules define what to do if a rule is hit -*/ -$global_privmsgs_rules = array( - CHECK_SUBJECT => array( - RULE_IS_LIKE => array('check0' => 'message_subject'), - RULE_IS_NOT_LIKE => array('check0' => 'message_subject'), - RULE_IS => array('check0' => 'message_subject'), - RULE_IS_NOT => array('check0' => 'message_subject'), - RULE_BEGINS_WITH => array('check0' => 'message_subject'), - RULE_ENDS_WITH => array('check0' => 'message_subject'), - ), - - CHECK_SENDER => array( - RULE_IS_LIKE => array('check0' => 'username'), - RULE_IS_NOT_LIKE => array('check0' => 'username'), - RULE_IS => array('check0' => 'username'), - RULE_IS_NOT => array('check0' => 'username'), - RULE_BEGINS_WITH => array('check0' => 'username'), - RULE_ENDS_WITH => array('check0' => 'username'), - RULE_IS_FRIEND => array('check0' => 'friend'), - RULE_IS_FOE => array('check0' => 'foe'), - RULE_IS_USER => array('check0' => 'author_id'), - RULE_IS_GROUP => array('check0' => 'author_in_group'), - ), - - CHECK_MESSAGE => array( - RULE_IS_LIKE => array('check0' => 'message_text'), - RULE_IS_NOT_LIKE => array('check0' => 'message_text'), - RULE_IS => array('check0' => 'message_text'), - RULE_IS_NOT => array('check0' => 'message_text'), - ), - - CHECK_STATUS => array( - RULE_ANSWERED => array('check0' => 'pm_replied'), - RULE_FORWARDED => array('check0' => 'pm_forwarded'), - ), - - CHECK_TO => array( - RULE_TO_GROUP => array('check0' => 'to', 'check1' => 'bcc', 'check2' => 'user_in_group'), - RULE_TO_ME => array('check0' => 'to', 'check1' => 'bcc'), - ) -); - -/** -* This is for defining which condition fields to show for which Rule -*/ -$global_rule_conditions = array( - RULE_IS_LIKE => 'text', - RULE_IS_NOT_LIKE => 'text', - RULE_IS => 'text', - RULE_IS_NOT => 'text', - RULE_BEGINS_WITH => 'text', - RULE_ENDS_WITH => 'text', - RULE_IS_USER => 'user', - RULE_IS_GROUP => 'group' -); - -/** -* Get all folder -*/ -function get_folder($user_id, $folder_id = false) -{ - global $db, $user, $template; - global $phpbb_root_path, $phpEx; - - $folder = array(); - - // Get folder information - $sql = 'SELECT folder_id, COUNT(msg_id) as num_messages, SUM(pm_unread) as num_unread - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id <> " . PRIVMSGS_NO_BOX . ' - GROUP BY folder_id'; - $result = $db->sql_query($sql); - - $num_messages = $num_unread = array(); - while ($row = $db->sql_fetchrow($result)) - { - $num_messages[(int) $row['folder_id']] = $row['num_messages']; - $num_unread[(int) $row['folder_id']] = $row['num_unread']; - } - $db->sql_freeresult($result); - - // Make sure the default boxes are defined - $available_folder = array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX); - - foreach ($available_folder as $default_folder) - { - if (!isset($num_messages[$default_folder])) - { - $num_messages[$default_folder] = 0; - } - - if (!isset($num_unread[$default_folder])) - { - $num_unread[$default_folder] = 0; - } - } - - // Adjust unread status for outbox - $num_unread[PRIVMSGS_OUTBOX] = $num_messages[PRIVMSGS_OUTBOX]; - - $folder[PRIVMSGS_INBOX] = array( - 'folder_name' => $user->lang['PM_INBOX'], - 'num_messages' => $num_messages[PRIVMSGS_INBOX], - 'unread_messages' => $num_unread[PRIVMSGS_INBOX] - ); - - // Custom Folder - $sql = 'SELECT folder_id, folder_name, pm_count - FROM ' . PRIVMSGS_FOLDER_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $folder[$row['folder_id']] = array( - 'folder_name' => $row['folder_name'], - 'num_messages' => $row['pm_count'], - 'unread_messages' => ((isset($num_unread[$row['folder_id']])) ? $num_unread[$row['folder_id']] : 0) - ); - } - $db->sql_freeresult($result); - - $folder[PRIVMSGS_OUTBOX] = array( - 'folder_name' => $user->lang['PM_OUTBOX'], - 'num_messages' => $num_messages[PRIVMSGS_OUTBOX], - 'unread_messages' => $num_unread[PRIVMSGS_OUTBOX] - ); - - $folder[PRIVMSGS_SENTBOX] = array( - 'folder_name' => $user->lang['PM_SENTBOX'], - 'num_messages' => $num_messages[PRIVMSGS_SENTBOX], - 'unread_messages' => $num_unread[PRIVMSGS_SENTBOX] - ); - - // Define Folder Array for template designers (and for making custom folders usable by the template too) - foreach ($folder as $f_id => $folder_ary) - { - $folder_id_name = ($f_id == PRIVMSGS_INBOX) ? 'inbox' : (($f_id == PRIVMSGS_OUTBOX) ? 'outbox' : 'sentbox'); - - $template->assign_block_vars('folder', array( - 'FOLDER_ID' => $f_id, - 'FOLDER_NAME' => $folder_ary['folder_name'], - 'NUM_MESSAGES' => $folder_ary['num_messages'], - 'UNREAD_MESSAGES' => $folder_ary['unread_messages'], - - 'U_FOLDER' => ($f_id > 0) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $f_id) : append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id_name), - - 'S_CUR_FOLDER' => ($f_id === $folder_id) ? true : false, - 'S_UNREAD_MESSAGES' => ($folder_ary['unread_messages']) ? true : false, - 'S_CUSTOM_FOLDER' => ($f_id > 0) ? true : false) - ); - } - - if ($folder_id !== false && $folder_id !== PRIVMSGS_HOLD_BOX && !isset($folder[$folder_id])) - { - trigger_error('UNKNOWN_FOLDER'); - } - - return $folder; -} - -/** -* Delete Messages From Sentbox -* we are doing this here because this saves us a bunch of checks and queries -*/ -function clean_sentbox($num_sentbox_messages) -{ - global $db, $user; - - // Check Message Limit - if ($user->data['message_limit'] && $num_sentbox_messages > $user->data['message_limit']) - { - // Delete old messages - $sql = 'SELECT t.msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p - WHERE t.msg_id = p.msg_id - AND t.user_id = ' . $user->data['user_id'] . ' - AND t.folder_id = ' . PRIVMSGS_SENTBOX . ' - ORDER BY p.message_time ASC'; - $result = $db->sql_query_limit($sql, ($num_sentbox_messages - $user->data['message_limit'])); - - $delete_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $delete_ids[] = $row['msg_id']; - } - $db->sql_freeresult($result); - delete_pm($user->data['user_id'], $delete_ids, PRIVMSGS_SENTBOX); - } -} - -/** -* Check Rule against Message Information -*/ -function check_rule(&$rules, &$rule_row, &$message_row, $user_id) -{ - if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']])) - { - return false; - } - - $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']]; - - $result = false; - - $check0 = $message_row[$check_ary['check0']]; - - switch ($rule_row['rule_connection']) - { - case RULE_IS_LIKE: - $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); - break; - - case RULE_IS_NOT_LIKE: - $result = !preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); - break; - - case RULE_IS: - $result = ($check0 == $rule_row['rule_string']); - break; - - case RULE_IS_NOT: - $result = ($check0 != $rule_row['rule_string']); - break; - - case RULE_BEGINS_WITH: - $result = preg_match("/^" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); - break; - - case RULE_ENDS_WITH: - $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '$/i', $check0); - break; - - case RULE_IS_FRIEND: - case RULE_IS_FOE: - case RULE_ANSWERED: - case RULE_FORWARDED: - $result = ($check0 == 1); - break; - - case RULE_IS_USER: - $result = ($check0 == $rule_row['rule_user_id']); - break; - - case RULE_IS_GROUP: - $result = in_array($rule_row['rule_group_id'], $check0); - break; - - case RULE_TO_GROUP: - $result = (in_array('g_' . $message_row[$check_ary['check2']], $check0) || in_array('g_' . $message_row[$check_ary['check2']], $message_row[$check_ary['check1']])); - break; - - case RULE_TO_ME: - $result = (in_array('u_' . $user_id, $check0) || in_array('u_' . $user_id, $message_row[$check_ary['check1']])); - break; - } - - if (!$result) - { - return false; - } - - switch ($rule_row['rule_action']) - { - case ACTION_PLACE_INTO_FOLDER: - return array('action' => $rule_row['rule_action'], 'folder_id' => $rule_row['rule_folder_id']); - break; - - case ACTION_MARK_AS_READ: - case ACTION_MARK_AS_IMPORTANT: - return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']); - break; - - case ACTION_DELETE_MESSAGE: - 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 - $sql = 'SELECT user_id, user_type, user_permissions - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $message_row['author_id']; - $result = $db->sql_query($sql); - $userdata = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($userdata); - - if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_')) - { - return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']); - } - - return false; - break; - - default: - return false; - } - - return false; -} - -/** -* Update user PM count -*/ -function update_pm_counts() -{ - global $user, $db; - - // Update unread count - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE pm_unread = 1 - AND folder_id <> ' . PRIVMSGS_OUTBOX . ' - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $user->data['user_unread_privmsg'] = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - - // Update new pm count - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE pm_new = 1 - AND folder_id IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ') - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $user->data['user_new_privmsg'] = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( - 'user_unread_privmsg' => (int) $user->data['user_unread_privmsg'], - 'user_new_privmsg' => (int) $user->data['user_new_privmsg'], - )) . ' WHERE user_id = ' . $user->data['user_id']); - - // Ok, here we need to repair something, other boxes than privmsgs_no_box and privmsgs_hold_box should not carry the pm_new flag. - if (!$user->data['user_new_privmsg']) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET pm_new = 0 - WHERE pm_new = 1 - AND folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ') - AND user_id = ' . $user->data['user_id']; - $db->sql_query($sql); - } -} - -/** -* Place new messages into appropriate folder -*/ -function place_pm_into_folder(&$global_privmsgs_rules, $release = false) -{ - global $db, $user, $config; - - if (!$user->data['user_new_privmsg']) - { - return array('not_moved' => 0, 'removed' => 0); - } - - $user_message_rules = (int) $user->data['user_message_rules']; - $user_id = (int) $user->data['user_id']; - - $action_ary = $move_into_folder = array(); - $num_removed = 0; - - // Newly processing on-hold messages - if ($release) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET folder_id = ' . PRIVMSGS_NO_BOX . ' - WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . " - AND user_id = $user_id"; - $db->sql_query($sql); - } - - // Get those messages not yet placed into any box - $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE t.user_id = $user_id - AND p.author_id = u.user_id - AND t.folder_id = " . PRIVMSGS_NO_BOX . ' - AND t.msg_id = p.msg_id'; - - // Just place into the appropriate arrays if no rules need to be checked - if (!$user_message_rules) - { - $result = $db->sql_query($retrieve_sql); - - while ($row = $db->sql_fetchrow($result)) - { - $action_ary[$row['msg_id']][] = array('action' => false); - } - $db->sql_freeresult($result); - } - else - { - $user_rules = $zebra = $check_rows = array(); - $user_ids = $memberships = array(); - - // First of all, grab all rules and retrieve friends/foes - $sql = 'SELECT * - FROM ' . PRIVMSGS_RULES_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query($sql); - $user_rules = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - if (count($user_rules)) - { - $sql = 'SELECT zebra_id, friend, foe - FROM ' . ZEBRA_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $zebra[$row['zebra_id']] = $row; - } - $db->sql_freeresult($result); - } - - // Now build a bare-bone check_row array - $result = $db->sql_query($retrieve_sql); - - while ($row = $db->sql_fetchrow($result)) - { - $check_rows[] = array_merge($row, array( - 'to' => explode(':', $row['to_address']), - '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']), - 'author_in_group' => array()) - ); - - $user_ids[] = $row['user_id']; - } - $db->sql_freeresult($result); - - // Retrieve user memberships - if (count($user_ids)) - { - $sql = 'SELECT * - FROM ' . USER_GROUP_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_ids) . ' - AND user_pending = 0'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $memberships[$row['user_id']][] = $row['group_id']; - } - $db->sql_freeresult($result); - } - - // Now place into the appropriate folder - foreach ($check_rows as $row) - { - // Add membership if set - if (isset($memberships[$row['author_id']])) - { - $row['author_in_group'] = $memberships[$row['user_id']]; - } - - // Check Rule - this should be very quick since we have all information we need - $is_match = false; - foreach ($user_rules as $rule_row) - { - if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false) - { - $is_match = true; - $action_ary[$row['msg_id']][] = $action; - } - } - - if (!$is_match) - { - $action_ary[$row['msg_id']][] = array('action' => false); - } - } - - unset($user_rules, $zebra, $check_rows, $user_ids, $memberships); - } - - // We place actions into arrays, to save queries. - $unread_ids = $delete_ids = $important_ids = array(); - - foreach ($action_ary as $msg_id => $msg_ary) - { - // It is allowed to execute actions more than once, except placing messages into folder - $folder_action = $message_removed = false; - - foreach ($msg_ary as $pos => $rule_ary) - { - if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER) - { - continue; - } - - switch ($rule_ary['action']) - { - case ACTION_PLACE_INTO_FOLDER: - // Folder actions have precedence, so we will remove any other ones - $folder_action = true; - $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id; - break; - - case ACTION_MARK_AS_READ: - if ($rule_ary['pm_unread']) - { - $unread_ids[] = $msg_id; - } - break; - - case ACTION_DELETE_MESSAGE: - $delete_ids[] = $msg_id; - $message_removed = true; - break; - - case ACTION_MARK_AS_IMPORTANT: - if (!$rule_ary['pm_marked']) - { - $important_ids[] = $msg_id; - } - break; - } - } - - // We place this here because it could happen that the messages are doubled if a rule marks a message and then moves it into a specific - // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder. - if (!$folder_action && !$message_removed) - { - $move_into_folder[PRIVMSGS_INBOX][] = $msg_id; - } - } - - // Do not change the order of processing - // The number of queries needed to be executed here highly depends on the defined rules and are - // only gone through if new messages arrive. - - // Delete messages - if (count($delete_ids)) - { - $num_removed += count($delete_ids); - delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX); - } - - // Set messages to Unread - if (count($unread_ids)) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET pm_unread = 0 - WHERE ' . $db->sql_in_set('msg_id', $unread_ids) . " - AND user_id = $user_id - AND folder_id = " . PRIVMSGS_NO_BOX; - $db->sql_query($sql); - } - - // mark messages as important - if (count($important_ids)) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET pm_marked = 1 - pm_marked - WHERE folder_id = ' . PRIVMSGS_NO_BOX . " - AND user_id = $user_id - AND " . $db->sql_in_set('msg_id', $important_ids); - $db->sql_query($sql); - } - - // Move into folder - $folder = array(); - - 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']; - - $sql_folder = array_keys($move_into_folder); - if ($full_folder_action >= 0) - { - $sql_folder[] = $full_folder_action; - } - - $sql = 'SELECT folder_id, pm_count - FROM ' . PRIVMSGS_FOLDER_TABLE . ' - WHERE ' . $db->sql_in_set('folder_id', $sql_folder) . " - AND user_id = $user_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $folder[(int) $row['folder_id']] = (int) $row['pm_count']; - } - $db->sql_freeresult($result); - - unset($sql_folder); - - if (isset($move_into_folder[PRIVMSGS_INBOX])) - { - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id = " . PRIVMSGS_INBOX; - $result = $db->sql_query($sql); - $folder[PRIVMSGS_INBOX] = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - } - } - - // Here we have ideally only one folder to move into - foreach ($move_into_folder as $folder_id => $msg_ary) - { - $dest_folder = $folder_id; - $full_folder_action = FULL_FOLDER_NONE; - - // 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] + 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] + count($msg_ary)) > $user->data['message_limit']) - { - $full_folder_action = $config['full_folder_action'] - (FULL_FOLDER_NONE*(-1)); - } - - // If Full Folder Action is to move to another folder, we simply adjust the destination folder - if ($full_folder_action >= 0) - { - $dest_folder = $full_folder_action; - } - else if ($full_folder_action == FULL_FOLDER_DELETE) - { - // Delete some messages. NOTE: Ordered by msg_id here instead of message_time! - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id = $dest_folder - ORDER BY msg_id ASC"; - $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)) - { - $delete_ids[] = $row['msg_id']; - } - $db->sql_freeresult($result); - - $num_removed += count($delete_ids); - delete_pm($user_id, $delete_ids, $dest_folder); - } - } - - // - if ($full_folder_action == FULL_FOLDER_HOLD) - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET folder_id = ' . PRIVMSGS_HOLD_BOX . ' - WHERE folder_id = ' . PRIVMSGS_NO_BOX . " - AND user_id = $user_id - AND " . $db->sql_in_set('msg_id', $msg_ary); - $db->sql_query($sql); - } - else - { - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " - SET folder_id = $dest_folder, pm_new = 0 - WHERE folder_id = " . PRIVMSGS_NO_BOX . " - AND user_id = $user_id - AND pm_new = 1 - AND " . $db->sql_in_set('msg_id', $msg_ary); - $db->sql_query($sql); - - if ($dest_folder != PRIVMSGS_INBOX) - { - $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . ' - SET pm_count = pm_count + ' . (int) $db->sql_affectedrows() . " - WHERE folder_id = $dest_folder - AND user_id = $user_id"; - $db->sql_query($sql); - } - } - } - - 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) - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET folder_id = ' . PRIVMSGS_SENTBOX . ' - WHERE folder_id = ' . PRIVMSGS_OUTBOX . ' - AND ' . $db->sql_in_set('msg_id', array_keys($action_ary)); - $db->sql_query($sql); - } - - // Update new/unread count - update_pm_counts(); - - // Now check how many messages got not moved... - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id = " . PRIVMSGS_HOLD_BOX; - $result = $db->sql_query($sql); - $num_not_moved = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - - return array('not_moved' => $num_not_moved, 'removed' => $num_removed); -} - -/** -* Move PM from one to another folder -*/ -function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_folder_id) -{ - global $db, $user; - global $phpbb_root_path, $phpEx; - - $num_moved = 0; - - if (!is_array($move_msg_ids)) - { - $move_msg_ids = array($move_msg_ids); - } - - 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 ;) - if ($dest_folder != PRIVMSGS_INBOX) - { - $sql = 'SELECT folder_id, folder_name, pm_count - FROM ' . PRIVMSGS_FOLDER_TABLE . " - WHERE folder_id = $dest_folder - AND user_id = $user_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } - - if ($message_limit && $row['pm_count'] + count($move_msg_ids) > $message_limit) - { - $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '

'; - $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $row['folder_name']); - trigger_error($message); - } - } - else - { - $sql = 'SELECT COUNT(msg_id) as num_messages - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE folder_id = ' . PRIVMSGS_INBOX . " - AND user_id = $user_id"; - $result = $db->sql_query($sql); - $num_messages = (int) $db->sql_fetchfield('num_messages'); - $db->sql_freeresult($result); - - if ($message_limit && $num_messages + count($move_msg_ids) > $message_limit) - { - $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $user->lang['PM_INBOX']) . '

'; - $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_INBOX']); - trigger_error($message); - } - } - - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " - SET folder_id = $dest_folder - WHERE folder_id = $cur_folder_id - AND user_id = $user_id - AND " . $db->sql_in_set('msg_id', $move_msg_ids); - $db->sql_query($sql); - $num_moved = $db->sql_affectedrows(); - - // Update pm counts - if ($num_moved) - { - if (!in_array($cur_folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX))) - { - $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . " - SET pm_count = pm_count - $num_moved - WHERE folder_id = $cur_folder_id - AND user_id = $user_id"; - $db->sql_query($sql); - } - - if ($dest_folder != PRIVMSGS_INBOX) - { - $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . " - SET pm_count = pm_count + $num_moved - WHERE folder_id = $dest_folder - AND user_id = $user_id"; - $db->sql_query($sql); - } - } - } - else if (in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX))) - { - trigger_error('CANNOT_MOVE_SPECIAL'); - } - - return $num_moved; -} - -/** -* Update unread message status -*/ -function update_unread_status($unread, $msg_id, $user_id, $folder_id) -{ - if (!$unread) - { - return; - } - - global $db, $user, $phpbb_container; - - /* @var $phpbb_notifications \phpbb\notification\manager */ - $phpbb_notifications = $phpbb_container->get('notification_manager'); - - $phpbb_notifications->mark_notifications('notification.type.pm', $msg_id, $user_id); - - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " - SET pm_unread = 0 - WHERE msg_id = $msg_id - AND user_id = $user_id - AND folder_id = $folder_id - AND pm_unread = 1"; - $db->sql_query($sql); - - // If the message is already marked as read, we just skip the rest to avoid negative PM count - if (!$db->sql_affectedrows()) - { - return; - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_unread_privmsg = user_unread_privmsg - 1 - WHERE user_id = $user_id"; - $db->sql_query($sql); - - if ($user->data['user_id'] == $user_id) - { - $user->data['user_unread_privmsg']--; - - // Try to cope with previous wrong conversions... - if ($user->data['user_unread_privmsg'] < 0) - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_unread_privmsg = 0 - WHERE user_id = $user_id"; - $db->sql_query($sql); - - $user->data['user_unread_privmsg'] = 0; - } - } -} - -function mark_folder_read($user_id, $folder_id) -{ - global $db; - - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE folder_id = ' . ((int) $folder_id) . ' - AND user_id = ' . ((int) $user_id) . ' - AND pm_unread = 1'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - update_unread_status(true, $row['msg_id'], $user_id, $folder_id); - } - $db->sql_freeresult($result); -} - -/** -* Handle all actions possible with marked messages -*/ -function handle_mark_actions($user_id, $mark_action) -{ - global $db, $user, $phpbb_root_path, $phpEx, $request; - - $msg_ids = $request->variable('marked_msg_id', array(0)); - $cur_folder_id = $request->variable('cur_folder_id', PRIVMSGS_NO_BOX); - - if (!count($msg_ids)) - { - return false; - } - - switch ($mark_action) - { - case 'mark_important': - - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " - SET pm_marked = 1 - pm_marked - WHERE folder_id = $cur_folder_id - AND user_id = $user_id - AND " . $db->sql_in_set('msg_id', $msg_ids); - $db->sql_query($sql); - - break; - - case 'delete_marked': - - global $auth; - - if (!$auth->acl_get('u_pm_delete')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_DELETE_MESSAGE'); - } - - if (confirm_box(true)) - { - delete_pm($user_id, $msg_ids, $cur_folder_id); - - $success_msg = (count($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED'; - $redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $cur_folder_id); - - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . sprintf($user->lang['RETURN_FOLDER'], '', '')); - } - else - { - $s_hidden_fields = array( - 'cur_folder_id' => $cur_folder_id, - 'mark_option' => 'delete_marked', - 'submit_mark' => true, - 'marked_msg_id' => $msg_ids - ); - - confirm_box(false, 'DELETE_MARKED_PM', build_hidden_fields($s_hidden_fields)); - } - - break; - - default: - return false; - } - - return true; -} - -/** -* Delete PM(s) -*/ -function delete_pm($user_id, $msg_ids, $folder_id) -{ - global $db, $user, $phpbb_container, $phpbb_dispatcher; - - $user_id = (int) $user_id; - $folder_id = (int) $folder_id; - - if (!$user_id) - { - return false; - } - - if (!is_array($msg_ids)) - { - if (!$msg_ids) - { - return false; - } - $msg_ids = array($msg_ids); - } - - if (!count($msg_ids)) - { - return false; - } - - /** - * Get all info for PM(s) before they are deleted - * - * @event core.delete_pm_before - * @var int user_id ID of the user requested the message delete - * @var array msg_ids array of all messages to be deleted - * @var int folder_id ID of the user folder where the messages are stored - * @since 3.1.0-b5 - */ - $vars = array('user_id', 'msg_ids', 'folder_id'); - extract($phpbb_dispatcher->trigger_event('core.delete_pm_before', compact($vars))); - - // Get PM Information for later deleting - $sql = 'SELECT msg_id, pm_unread, pm_new - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', array_map('intval', $msg_ids)) . " - AND folder_id = $folder_id - AND user_id = $user_id"; - $result = $db->sql_query($sql); - - $delete_rows = array(); - $num_unread = $num_new = $num_deleted = 0; - while ($row = $db->sql_fetchrow($result)) - { - $num_unread += (int) $row['pm_unread']; - $num_new += (int) $row['pm_new']; - - $delete_rows[$row['msg_id']] = 1; - } - $db->sql_freeresult($result); - unset($msg_ids); - - if (!count($delete_rows)) - { - return false; - } - - $db->sql_transaction('begin'); - - // if no one has read the message yet (meaning it is in users outbox) - // then mark the message as deleted... - if ($folder_id == PRIVMSGS_OUTBOX) - { - // Remove PM from Outbox - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id AND folder_id = " . PRIVMSGS_OUTBOX . ' - AND ' . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $db->sql_query($sql); - - // Update PM Information for safety - $sql = 'UPDATE ' . PRIVMSGS_TABLE . " SET message_text = '' - WHERE " . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $db->sql_query($sql); - - // Set delete flag for those intended to receive the PM - // We do not remove the message actually, to retain some basic information (sent time for example) - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET pm_deleted = 1 - WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $db->sql_query($sql); - - $num_deleted = $db->sql_affectedrows(); - } - else - { - // Delete private message data - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . " - WHERE user_id = $user_id - AND folder_id = $folder_id - AND " . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $db->sql_query($sql); - $num_deleted = $db->sql_affectedrows(); - } - - // if folder id is user defined folder then decrease pm_count - if (!in_array($folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX, PRIVMSGS_NO_BOX))) - { - $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . " - SET pm_count = pm_count - $num_deleted - WHERE folder_id = $folder_id"; - $db->sql_query($sql); - } - - // Update unread and new status field - if ($num_unread || $num_new) - { - $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : ''; - - if ($num_new) - { - $set_sql .= ($set_sql != '') ? ', ' : ''; - $set_sql .= 'user_new_privmsg = user_new_privmsg - ' . $num_new; - } - - $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id"); - - $user->data['user_new_privmsg'] -= $num_new; - $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)); - - // Now we have to check which messages we can delete completely - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - unset($delete_rows[$row['msg_id']]); - } - $db->sql_freeresult($result); - - $delete_ids = array_keys($delete_rows); - - if (count($delete_ids)) - { - // Check if there are any attachments we need to remove - /** @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); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - return true; -} - -/** -* Delete all PM(s) for a given user and delete the ones without references -* -* @param int $user_id ID of the user whose private messages we want to delete -* -* @return boolean False if there were no pms found, true otherwise. -*/ -function phpbb_delete_user_pms($user_id) -{ - $user_id = (int) $user_id; - - if (!$user_id) - { - return false; - } - - return phpbb_delete_users_pms(array($user_id)); -} - -/** -* Delete all PM(s) for given users and delete the ones without references -* -* @param array $user_ids IDs of the users whose private messages we want to delete -* -* @return boolean False if there were no pms found, true otherwise. -*/ -function phpbb_delete_users_pms($user_ids) -{ - 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); - - // Get PM Information for later deleting - // The two queries where split, so we can use our indexes - $undelivered_msg = $delete_ids = array(); - - // Part 1: get PMs the user received - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $user_id_sql; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $msg_id = (int) $row['msg_id']; - $delete_ids[$msg_id] = $msg_id; - } - $db->sql_freeresult($result); - - // Part 2: get PMs the users sent, but are yet to be received. - // We cannot simply delete them. First we have to check - // whether another user already received and read the message. - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $author_id_sql . ' - AND folder_id = ' . PRIVMSGS_NO_BOX; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $msg_id = (int) $row['msg_id']; - $undelivered_msg[$msg_id] = $msg_id; - } - $db->sql_freeresult($result); - - if (empty($delete_ids) && empty($undelivered_msg)) - { - return false; - } - - $db->sql_transaction('begin'); - - /* @var $phpbb_notifications \phpbb\notification\manager */ - $phpbb_notifications = $phpbb_container->get('notification_manager'); - - if (!empty($undelivered_msg)) - { - // A pm is delivered, if for any recipient the message was moved - // from their NO_BOX to another folder. We do not delete such - // messages, but only delete them for users, who have not yet - // received them. - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $author_id_sql . ' - AND folder_id <> ' . PRIVMSGS_NO_BOX . ' - AND folder_id <> ' . PRIVMSGS_OUTBOX . ' - AND folder_id <> ' . PRIVMSGS_SENTBOX; - $result = $db->sql_query($sql); - - $delivered_msg = array(); - while ($row = $db->sql_fetchrow($result)) - { - $msg_id = (int) $row['msg_id']; - $delivered_msg[$msg_id] = $msg_id; - unset($undelivered_msg[$msg_id]); - } - $db->sql_freeresult($result); - - $undelivered_user = array(); - - // Count the messages we delete, so we can correct the user pm data - $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $author_id_sql . ' - AND folder_id = ' . PRIVMSGS_NO_BOX . ' - AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . ' - GROUP BY user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $num_pms = (int) $row['num_undelivered_privmsgs']; - $undelivered_user[$num_pms][] = (int) $row['user_id']; - - 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. - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ', - user_unread_privmsg = user_unread_privmsg - ' . $num_pms . ' - WHERE ' . $db->sql_in_set('user_id', $undelivered_user[$num_pms]); - $db->sql_query($sql); - unset($undelivered_user[$num_pms]); - } - } - $db->sql_freeresult($result); - - foreach ($undelivered_user as $num_pms => $undelivered_user_set) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ', - user_unread_privmsg = user_unread_privmsg - ' . $num_pms . ' - WHERE ' . $db->sql_in_set('user_id', $undelivered_user_set); - $db->sql_query($sql); - } - - if (!empty($delivered_msg)) - { - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE folder_id = ' . PRIVMSGS_NO_BOX . ' - AND ' . $db->sql_in_set('msg_id', $delivered_msg); - $db->sql_query($sql); - - $phpbb_notifications->delete_notifications('notification.type.pm', $delivered_msg); - } - - if (!empty($undelivered_msg)) - { - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); - $db->sql_query($sql); - - $phpbb_notifications->delete_notifications('notification.type.pm', $undelivered_msg); - } - } - - // Reset the user's pm count to 0 - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = 0, - user_unread_privmsg = 0 - WHERE ' . $user_id_sql; - $db->sql_query($sql); - - // Delete private message data of the user - $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $user_id_sql; - $db->sql_query($sql); - - if (!empty($delete_ids)) - { - // Now we have to check which messages we can delete completely - $sql = 'SELECT msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE ' . $db->sql_in_set('msg_id', $delete_ids); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - unset($delete_ids[$row['msg_id']]); - } - $db->sql_freeresult($result); - - if (!empty($delete_ids)) - { - // Check if there are any attachments we need to remove - /** @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); - $db->sql_query($sql); - - $phpbb_notifications->delete_notifications('notification.type.pm', $delete_ids); - } - } - - // Set the remaining author id to anonymous - // This way users are still able to read messages from users being removed - $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' - SET author_id = ' . ANONYMOUS . ' - WHERE ' . $author_id_sql; - $db->sql_query($sql); - - $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' - SET author_id = ' . ANONYMOUS . ' - WHERE ' . $author_id_sql; - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - return true; -} - -/** -* Rebuild message header -*/ -function rebuild_header($check_ary) -{ - $address = array(); - - foreach ($check_ary as $check_type => $address_field) - { - // Split Addresses into users and groups - preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match); - - $u = $g = array(); - foreach ($match[1] as $id => $type) - { - ${$type}[] = (int) $match[2][$id]; - } - - $_types = array('u', 'g'); - foreach ($_types as $type) - { - if (count(${$type})) - { - foreach (${$type} as $id) - { - $address[$type][$id] = $check_type; - } - } - } - } - - return $address; -} - -/** -* Print out/assign recipient information -*/ -function write_pm_addresses($check_ary, $author_id, $plaintext = false) -{ - 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(); - - foreach ($check_ary as $check_type => $address_field) - { - if (!is_array($address_field)) - { - // Split Addresses into users and groups - preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match); - - $u = $g = array(); - foreach ($match[1] as $id => $type) - { - ${$type}[] = (int) $match[2][$id]; - } - } - else - { - $u = $address_field['u']; - $g = $address_field['g']; - } - - $address = array(); - if (count($u)) - { - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $u); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id']) - { - if ($plaintext) - { - $address[] = $row['username']; - } - else - { - $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']); - } - } - } - $db->sql_freeresult($result); - } - - if (count($g)) - { - if ($plaintext) - { - $sql = 'SELECT group_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_id', $g); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id']) - { - $address[] = $group_helper->get_name($row['group_name']); - } - } - $db->sql_freeresult($result); - } - else - { - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id - FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug - WHERE ' . $db->sql_in_set('g.group_id', $g) . ' - AND g.group_id = ug.group_id - AND ug.user_pending = 0'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($address['group'][$row['group_id']])) - { - if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id']) - { - $row['group_name'] = $group_helper->get_name($row['group_name']); - $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']); - } - } - - if (isset($address['user'][$row['user_id']])) - { - $address['user'][$row['user_id']]['in_group'] = $row['group_id']; - } - } - $db->sql_freeresult($result); - } - } - - if (count($address) && !$plaintext) - { - $template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true); - - foreach ($address as $type => $adr_ary) - { - foreach ($adr_ary as $id => $row) - { - $tpl_ary = array( - 'IS_GROUP' => ($type == 'group') ? true : false, - 'IS_USER' => ($type == 'user') ? true : false, - 'UG_ID' => $id, - 'NAME' => $row['name'], - 'COLOUR' => ($row['colour']) ? '#' . $row['colour'] : '', - 'TYPE' => $type, - ); - - if ($type == 'user') - { - $tpl_ary = array_merge($tpl_ary, array( - 'U_VIEW' => get_username_string('profile', $id, $row['name'], $row['colour']), - 'NAME_FULL' => get_username_string('full', $id, $row['name'], $row['colour']), - )); - } - else - { - $tpl_ary = array_merge($tpl_ary, array( - 'U_VIEW' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $id), - )); - } - - $template->assign_block_vars($check_type . '_recipient', $tpl_ary); - } - } - } - - $addresses[$check_type] = $address; - } - - return $addresses; -} - -/** -* Get folder status -*/ -function get_folder_status($folder_id, $folder) -{ - global $user; - - if (isset($folder[$folder_id])) - { - $folder = $folder[$folder_id]; - } - else - { - return false; - } - - $return = array( - 'folder_name' => $folder['folder_name'], - 'cur' => $folder['num_messages'], - 'remaining' => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0, - 'max' => $user->data['message_limit'], - 'percent' => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? floor(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0, - ); - - $return['message'] = $user->lang('FOLDER_STATUS_MSG', $user->lang('MESSAGES_COUNT', (int) $return['max']), (int) $return['cur'], $return['percent']); - - return $return; -} - -// -// COMPOSE MESSAGES -// - -/** -* Submit PM -*/ -function submit_pm($mode, $subject, &$data_ary, $put_in_outbox = true) -{ - global $db, $auth, $config, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $request; - - // We do not handle erasing pms here - if ($mode == 'delete') - { - return false; - } - - $current_time = time(); - - $data = $data_ary; - /** - * Get all parts of the PM that are to be submited to the DB. - * - * @event core.submit_pm_before - * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit - * @var string subject Subject of the private message - * @var array data The whole row data of the PM. - * @since 3.1.0-b3 - */ - $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(); - $root_level = 0; - - // Recipient Information - $recipients = $to = $bcc = array(); - - if ($mode != 'edit') - { - // Build Recipient List - // u|g => array($user_id => 'to'|'bcc') - $_types = array('u', 'g'); - foreach ($_types as $ug_type) - { - if (isset($data_ary['address_list'][$ug_type]) && count($data_ary['address_list'][$ug_type])) - { - foreach ($data_ary['address_list'][$ug_type] as $id => $field) - { - $id = (int) $id; - - // Do not rely on the address list being "valid" - if (!$id || ($ug_type == 'u' && $id == ANONYMOUS)) - { - continue; - } - - $field = ($field == 'to') ? 'to' : 'bcc'; - if ($ug_type == 'u') - { - $recipients[$id] = $field; - } - ${$field}[] = $ug_type . '_' . $id; - } - } - } - - 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 - $sql_allow_pm = (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) ? ' AND u.user_allow_pm = 1' : ''; - - $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_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 . ')' . - $sql_allow_pm; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $field = ($data_ary['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc'; - $recipients[$row['user_id']] = $field; - } - $db->sql_freeresult($result); - } - - if (!count($recipients)) - { - trigger_error('NO_RECIPIENT'); - } - } - - // First of all make sure the subject are having the correct length. - $subject = truncate_string($subject); - - $db->sql_transaction('begin'); - - $sql = ''; - - switch ($mode) - { - case 'reply': - case 'quote': - $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_ary['from_user_id'] . ' - AND msg_id = ' . $data_ary['reply_from_msg_id']; - - // no break - - case 'forward': - case 'post': - case 'quotepost': - $sql_data = array( - 'root_level' => $root_level, - '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_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_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, - ); - break; - - case 'edit': - $sql_data = array( - 'icon_id' => $data_ary['icon_id'], - 'message_edit_time' => $current_time, - '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_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 (count($sql_data)) - { - 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_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_ary['msg_id']; - $db->sql_query($sql); - } - } - - if ($mode != 'edit') - { - if ($sql) - { - $db->sql_query($sql); - } - unset($sql); - - $sql_ary = array(); - foreach ($recipients as $user_id => $type) - { - $sql_ary[] = array( - 'msg_id' => (int) $data_ary['msg_id'], - 'user_id' => (int) $user_id, - 'author_id' => (int) $data_ary['from_user_id'], - 'folder_id' => PRIVMSGS_NO_BOX, - 'pm_new' => 1, - 'pm_unread' => 1, - 'pm_forwarded' => ($mode == 'forward') ? 1 : 0 - ); - } - - $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($recipients)); - $db->sql_query($sql); - - // Put PM into outbox - if ($put_in_outbox) - { - $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array( - '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, - 'pm_forwarded' => ($mode == 'forward') ? 1 : 0)) - ); - } - } - - // Set user last post time - if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post') - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastpost_time = $current_time - WHERE user_id = " . $data_ary['from_user_id']; - $db->sql_query($sql); - } - - // Submit Attachments - 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_ary['attachment_data'] as $pos => $attach_row) - { - $orphan_rows[(int) $attach_row['attach_id']] = array(); - } - - if (count($orphan_rows)) - { - $sql = 'SELECT attach_id, filesize, physical_filename - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . ' - AND in_message = 1 - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - $orphan_rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $orphan_rows[$row['attach_id']] = $row; - } - $db->sql_freeresult($result); - } - - foreach ($data_ary['attachment_data'] as $pos => $attach_row) - { - if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']])) - { - continue; - } - - if (!$attach_row['is_orphan']) - { - // update entry in db if attachment already stored in db and filespace - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "' - WHERE attach_id = " . (int) $attach_row['attach_id'] . ' - AND is_orphan = 0'; - $db->sql_query($sql); - } - else - { - // insert attachment into db - if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) - { - continue; - } - - $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize']; - $files_added++; - - $attach_sql = array( - 'post_msg_id' => $data_ary['msg_id'], - 'topic_id' => 0, - 'is_orphan' => 0, - 'poster_id' => $data_ary['from_user_id'], - 'attach_comment' => $attach_row['attach_comment'], - ); - - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . ' - WHERE attach_id = ' . $attach_row['attach_id'] . ' - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $db->sql_query($sql); - } - } - - if ($space_taken && $files_added) - { - $config->increment('upload_dir_size', $space_taken, false); - $config->increment('num_files', $files_added, false); - } - } - - // Delete draft if post was loaded... - $draft_id = $request->variable('draft_loaded', 0); - if ($draft_id) - { - $sql = 'DELETE FROM ' . DRAFTS_TABLE . " - WHERE draft_id = $draft_id - AND user_id = " . $data_ary['from_user_id']; - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - // Send Notifications - $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') - { - $phpbb_notifications->update_notifications('notification.type.pm', $pm_data); - } - else - { - $phpbb_notifications->add_notifications('notification.type.pm', $pm_data); - } - - $data = $data_ary; - /** - * Get PM message ID after submission to DB - * - * @event core.submit_pm_after - * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit - * @var string subject Subject of the private message - * @var array data The whole row data of the PM. - * @var array pm_data The data sent to notification class - * @since 3.1.0-b5 - */ - $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_ary['msg_id']; -} - -/** -* Display Message History -*/ -function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false) -{ - global $db, $user, $template, $phpbb_root_path, $phpEx, $auth; - - // Select all receipts and the author from the pm we currently view, to only display their pm-history - $sql = 'SELECT author_id, user_id - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE msg_id = $msg_id - AND folder_id <> " . PRIVMSGS_HOLD_BOX; - $result = $db->sql_query($sql); - - $recipients = array(); - while ($row = $db->sql_fetchrow($result)) - { - $recipients[] = (int) $row['user_id']; - $recipients[] = (int) $row['author_id']; - } - $db->sql_freeresult($result); - $recipients = array_unique($recipients); - - // Get History Messages (could be newer) - $sql = 'SELECT t.*, p.*, u.* - FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u - WHERE t.msg_id = p.msg_id - AND p.author_id = u.user_id - AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ') - AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . " - AND t.user_id = $user_id"; - - // We no longer need those. - unset($recipients); - - if (!$message_row['root_level']) - { - $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))"; - } - else - { - $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')'; - } - $sql .= ' ORDER BY p.message_time DESC'; - - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - - if (!$row) - { - $db->sql_freeresult($result); - return false; - } - - $title = $row['message_subject']; - - $rowset = array(); - $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&folder='; - - do - { - $folder_id = (int) $row['folder_id']; - - $row['folder'][] = (isset($folder[$folder_id])) ? '' . $folder[$folder_id]['folder_name'] . '' : $user->lang['UNKNOWN_FOLDER']; - - if (isset($rowset[$row['msg_id']])) - { - $rowset[$row['msg_id']]['folder'][] = (isset($folder[$folder_id])) ? '' . $folder[$folder_id]['folder_name'] . '' : $user->lang['UNKNOWN_FOLDER']; - } - else - { - $rowset[$row['msg_id']] = $row; - } - } - while ($row = $db->sql_fetchrow($result)); - $db->sql_freeresult($result); - - if (count($rowset) == 1 && !$in_post_mode) - { - return false; - } - - $title = censor_text($title); - - $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm'); - $next_history_pm = $previous_history_pm = $prev_id = 0; - - // Re-order rowset to be able to get the next/prev message rows... - $rowset = array_values($rowset); - - for ($i = 0, $size = count($rowset); $i < $size; $i++) - { - $row = &$rowset[$i]; - $id = (int) $row['msg_id']; - - $author_id = $row['author_id']; - $folder_id = (int) $row['folder_id']; - - $subject = $row['message_subject']; - $message = $row['message_text']; - - $message = censor_text($message); - - $decoded_message = false; - - if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) - { - $decoded_message = $message; - decode_message($decoded_message, $row['bbcode_uid']); - - $decoded_message = bbcode_nl2br($decoded_message); - } - - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); - $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0); - - $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); - - $subject = censor_text($subject); - - if ($id == $msg_id) - { - $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0; - $previous_history_pm = $prev_id; - } - - $template->assign_block_vars('history_row', 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']), - 'MESSAGE_AUTHOR' => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']), - 'U_MESSAGE_AUTHOR' => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']), - - 'SUBJECT' => $subject, - 'SENT_DATE' => $user->format_date($row['message_time']), - 'MESSAGE' => $message, - 'FOLDER' => implode($user->lang['COMMA_SEPARATOR'], $row['folder']), - 'DECODED_MESSAGE' => $decoded_message, - - 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id), - 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false, - '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&f=$folder_id&p=" . $row['msg_id'], - 'U_QUOTE' => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=quote&f=" . $folder_id . "&p=" . $row['msg_id'] : '', - 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $row['msg_id'] : '') - ); - unset($rowset[$i]); - $prev_id = $id; - } - - $template->assign_vars(array( - 'QUOTE_IMG' => $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']), - 'HISTORY_TITLE' => $title, - - 'U_VIEW_NEXT_HISTORY' => ($next_history_pm) ? "$url&p=" . $next_history_pm : '', - 'U_VIEW_PREVIOUS_HISTORY' => ($previous_history_pm) ? "$url&p=" . $previous_history_pm : '', - )); - - return true; -} - -/** -* Set correct users max messages in PM folder. -* If several group memberships define different amount of messages, the highest will be chosen. -*/ -function set_user_message_limit() -{ - global $user, $db, $config; - - // 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 = ' . (int) $user_id . ' - AND ug.user_pending = 0 - AND ug.group_id = g.group_id'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - $max_setting = (int) $row['max_setting']; - - return $max_setting; -} - -/** -* Generates an array of coloured recipient names from a list of PMs - (groups & users) -* -* @param array $pm_by_id An array of rows from PRIVMSGS_TABLE, keys are the msg_ids. -* -* @return array 2D Array: array(msg_id => array('username or group string', ...), ...) -* Usernames are generated with {@link get_username_string get_username_string} -* Groups are coloured and have a link to the membership page -*/ -function get_recipient_strings($pm_by_id) -{ - global $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(); - - $_types = array('u', 'g'); - - foreach ($pm_by_id as $message_id => $row) - { - $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address'])); - - foreach ($_types as $ug_type) - { - if (isset($address[$message_id][$ug_type]) && count($address[$message_id][$ug_type])) - { - foreach ($address[$message_id][$ug_type] as $ug_id => $in_to) - { - $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => ''); - } - } - } - } - - foreach ($_types as $ug_type) - { - if (!empty($recipient_list[$ug_type])) - { - if ($ug_type == 'u') - { - $sql = 'SELECT user_id as id, username as name, user_colour as colour - FROM ' . USERS_TABLE . ' - WHERE '; - } - else - { - $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type - FROM ' . GROUPS_TABLE . ' - WHERE '; - } - $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type]))); - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($ug_type == 'g') - { - $row['name'] = $group_helper->get_name($row['name']); - } - - $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']); - } - $db->sql_freeresult($result); - } - } - - foreach ($address as $message_id => $adr_ary) - { - foreach ($adr_ary as $type => $id_ary) - { - foreach ($id_ary as $ug_id => $_id) - { - if ($type == 'u') - { - $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']); - } - else - { - $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : ''; - $link = ''; - $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '' : ''); - } - } - } - } - - return $address_list; -} diff --git a/install/update/old/includes/functions_transfer.php b/install/update/old/includes/functions_transfer.php deleted file mode 100644 index 7427b89..0000000 --- a/install/update/old/includes/functions_transfer.php +++ /dev/null @@ -1,899 +0,0 @@ - -* @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; -} - -/** -* Transfer class, wrapper for ftp/sftp/ssh -*/ -class transfer -{ - var $connection; - var $host; - var $port; - var $username; - var $password; - var $timeout; - var $root_path; - var $tmp_path; - var $file_perms; - var $dir_perms; - - /** - * Constructor - init some basic values - */ - function __construct() - { - global $phpbb_root_path; - - $this->file_perms = 0644; - $this->dir_perms = 0777; - - // We use the store directory as temporary path to circumvent open basedir restrictions - $this->tmp_path = $phpbb_root_path . 'store/'; - } - - /** - * Write file to location - */ - function write_file($destination_file = '', $contents = '') - { - global $phpbb_root_path; - - $destination_file = $this->root_path . str_replace($phpbb_root_path, '', $destination_file); - - // need to create a temp file and then move that temp file. - // ftp functions can only move files around and can't create. - // This means that the users will need to have access to write - // temporary files or have write access on a folder within phpBB - // like the cache folder. If the user can't do either, then - // he/she needs to use the fsock ftp method - $temp_name = tempnam($this->tmp_path, 'transfer_'); - @unlink($temp_name); - - $fp = @fopen($temp_name, 'w'); - - if (!$fp) - { - trigger_error('Unable to create temporary file ' . $temp_name, E_USER_ERROR); - } - - @fwrite($fp, $contents); - @fclose($fp); - - $result = $this->overwrite_file($temp_name, $destination_file); - - // remove temporary file now - @unlink($temp_name); - - return $result; - } - - /** - * Moving file into location. If the destination file already exists it gets overwritten - */ - function overwrite_file($source_file, $destination_file) - { - /** - * @todo generally think about overwriting files in another way, by creating a temporary file and then renaming it - * @todo check for the destination file existance too - */ - $this->_delete($destination_file); - $result = $this->_put($source_file, $destination_file); - $this->_chmod($destination_file, $this->file_perms); - - return $result; - } - - /** - * Create directory structure - */ - function make_dir($dir) - { - global $phpbb_root_path; - - $dir = str_replace($phpbb_root_path, '', $dir); - $dir = explode('/', $dir); - $dirs = ''; - - for ($i = 0, $total = count($dir); $i < $total; $i++) - { - $result = true; - - if (strpos($dir[$i], '.') === 0) - { - continue; - } - $cur_dir = $dir[$i] . '/'; - - if (!file_exists($phpbb_root_path . $dirs . $cur_dir)) - { - // create the directory - $result = $this->_mkdir($dir[$i]); - $this->_chmod($dir[$i], $this->dir_perms); - } - - $this->_chdir($this->root_path . $dirs . $dir[$i]); - $dirs .= $cur_dir; - } - - $this->_chdir($this->root_path); - - /** - * @todo stack result into array to make sure every path creation has been taken care of - */ - return $result; - } - - /** - * Copy file from source location to destination location - */ - function copy_file($from_loc, $to_loc) - { - global $phpbb_root_path; - - $from_loc = ((strpos($from_loc, $phpbb_root_path) !== 0) ? $phpbb_root_path : '') . $from_loc; - $to_loc = $this->root_path . str_replace($phpbb_root_path, '', $to_loc); - - if (!file_exists($from_loc)) - { - return false; - } - - $result = $this->overwrite_file($from_loc, $to_loc); - - return $result; - } - - /** - * Remove file - */ - function delete_file($file) - { - global $phpbb_root_path; - - $file = $this->root_path . str_replace($phpbb_root_path, '', $file); - - return $this->_delete($file); - } - - /** - * Remove directory - * @todo remove child directories? - */ - function remove_dir($dir) - { - global $phpbb_root_path; - - $dir = $this->root_path . str_replace($phpbb_root_path, '', $dir); - - return $this->_rmdir($dir); - } - - /** - * Rename a file or folder - */ - function rename($old_handle, $new_handle) - { - global $phpbb_root_path; - - $old_handle = $this->root_path . str_replace($phpbb_root_path, '', $old_handle); - - return $this->_rename($old_handle, $new_handle); - } - - /** - * Check if a specified file exist... - */ - function file_exists($directory, $filename) - { - global $phpbb_root_path; - - $directory = $this->root_path . str_replace($phpbb_root_path, '', $directory); - - $this->_chdir($directory); - $result = $this->_ls(); - - if ($result !== false && is_array($result)) - { - return (in_array($filename, $result)) ? true : false; - } - - return false; - } - - /** - * Open session - */ - function open_session() - { - return $this->_init(); - } - - /** - * Close current session - */ - function close_session() - { - return $this->_close(); - } - - /** - * Determine methods able to be used - */ - static public function methods() - { - $methods = array(); - $disabled_functions = explode(',', @ini_get('disable_functions')); - - if (@extension_loaded('ftp')) - { - $methods[] = 'ftp'; - } - - if (!in_array('fsockopen', $disabled_functions)) - { - $methods[] = 'ftp_fsock'; - } - - return $methods; - } -} - -/** -* FTP transfer class -*/ -class ftp extends transfer -{ - /** - * Standard parameters for FTP session - */ - function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10) - { - $this->host = $host; - $this->port = $port; - $this->username = $username; - $this->password = $password; - $this->timeout = $timeout; - - // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end) - $this->root_path = str_replace('\\', '/', $this->root_path); - - if (!empty($root_path)) - { - $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/'); - } - - // Init some needed values - $this->transfer(); - - return; - } - - /** - * Requests data - */ - static public function data() - { - global $user; - - return array( - 'host' => 'localhost', - 'username' => 'anonymous', - 'password' => '', - 'root_path' => $user->page['root_script_path'], - 'port' => 21, - 'timeout' => 10 - ); - } - - /** - * Init FTP Session - * @access private - */ - function _init() - { - // connect to the server - $this->connection = @ftp_connect($this->host, $this->port, $this->timeout); - - if (!$this->connection) - { - return 'ERR_CONNECTING_SERVER'; - } - - // login to the server - if (!@ftp_login($this->connection, $this->username, $this->password)) - { - return 'ERR_UNABLE_TO_LOGIN'; - } - - // attempt to turn pasv mode on - @ftp_pasv($this->connection, true); - - // change to the root directory - if (!$this->_chdir($this->root_path)) - { - return 'ERR_CHANGING_DIRECTORY'; - } - - return true; - } - - /** - * Create Directory (MKDIR) - * @access private - */ - function _mkdir($dir) - { - return @ftp_mkdir($this->connection, $dir); - } - - /** - * Remove directory (RMDIR) - * @access private - */ - function _rmdir($dir) - { - return @ftp_rmdir($this->connection, $dir); - } - - /** - * Rename file - * @access private - */ - function _rename($old_handle, $new_handle) - { - return @ftp_rename($this->connection, $old_handle, $new_handle); - } - - /** - * Change current working directory (CHDIR) - * @access private - */ - function _chdir($dir = '') - { - if ($dir && $dir !== '/') - { - if (substr($dir, -1, 1) == '/') - { - $dir = substr($dir, 0, -1); - } - } - - return @ftp_chdir($this->connection, $dir); - } - - /** - * change file permissions (CHMOD) - * @access private - */ - function _chmod($file, $perms) - { - if (function_exists('ftp_chmod')) - { - $err = @ftp_chmod($this->connection, $perms, $file); - } - else - { - // Unfortunatly CHMOD is not expecting an octal value... - // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;) - $chmod_cmd = 'CHMOD ' . base_convert($perms, 10, 8) . ' ' . $file; - $err = $this->_site($chmod_cmd); - } - - return $err; - } - - /** - * Upload file to location (PUT) - * @access private - */ - function _put($from_file, $to_file) - { - // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced) - $mode = FTP_BINARY; - - $to_dir = dirname($to_file); - $to_file = basename($to_file); - $this->_chdir($to_dir); - - $result = @ftp_put($this->connection, $to_file, $from_file, $mode); - $this->_chdir($this->root_path); - - return $result; - } - - /** - * Delete file (DELETE) - * @access private - */ - function _delete($file) - { - return @ftp_delete($this->connection, $file); - } - - /** - * Close ftp session (CLOSE) - * @access private - */ - function _close() - { - if (!$this->connection) - { - return false; - } - - return @ftp_quit($this->connection); - } - - /** - * Return current working directory (CWD) - * At the moment not used by parent class - * @access private - */ - function _cwd() - { - return @ftp_pwd($this->connection); - } - - /** - * Return list of files in a given directory (LS) - * @access private - */ - function _ls($dir = './') - { - $list = @ftp_nlist($this->connection, $dir); - - // See bug #46295 - Some FTP daemons don't like './' - if ($dir === './') - { - // Let's try some alternatives - $list = (empty($list)) ? @ftp_nlist($this->connection, '.') : $list; - $list = (empty($list)) ? @ftp_nlist($this->connection, '') : $list; - } - - // Return on error - if ($list === false) - { - return false; - } - - // Remove path if prepended - foreach ($list as $key => $item) - { - // Use same separator for item and dir - $item = str_replace('\\', '/', $item); - $dir = str_replace('\\', '/', $dir); - - if (!empty($dir) && strpos($item, $dir) === 0) - { - $item = substr($item, strlen($dir)); - } - - $list[$key] = $item; - } - - return $list; - } - - /** - * FTP SITE command (ftp-only function) - * @access private - */ - function _site($command) - { - return @ftp_site($this->connection, $command); - } -} - -/** -* FTP fsock transfer class -*/ -class ftp_fsock extends transfer -{ - var $data_connection; - - /** - * Standard parameters for FTP session - */ - function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10) - { - $this->host = $host; - $this->port = $port; - $this->username = $username; - $this->password = $password; - $this->timeout = $timeout; - - // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end) - $this->root_path = str_replace('\\', '/', $this->root_path); - - if (!empty($root_path)) - { - $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/'); - } - - // Init some needed values - parent::__construct(); - - return; - } - - /** - * Requests data - */ - static public function data() - { - global $user; - - return array( - 'host' => 'localhost', - 'username' => 'anonymous', - 'password' => '', - 'root_path' => $user->page['root_script_path'], - 'port' => 21, - 'timeout' => 10 - ); - } - - /** - * Init FTP Session - * @access private - */ - function _init() - { - $errno = 0; - $errstr = ''; - - // connect to the server - $this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout); - - if (!$this->connection || !$this->_check_command()) - { - return 'ERR_CONNECTING_SERVER'; - } - - @stream_set_timeout($this->connection, $this->timeout); - - // login - if (!$this->_send_command('USER', $this->username)) - { - return 'ERR_UNABLE_TO_LOGIN'; - } - - if (!$this->_send_command('PASS', $this->password)) - { - return 'ERR_UNABLE_TO_LOGIN'; - } - - // change to the root directory - if (!$this->_chdir($this->root_path)) - { - return 'ERR_CHANGING_DIRECTORY'; - } - - return true; - } - - /** - * Create Directory (MKDIR) - * @access private - */ - function _mkdir($dir) - { - return $this->_send_command('MKD', $dir); - } - - /** - * Remove directory (RMDIR) - * @access private - */ - function _rmdir($dir) - { - return $this->_send_command('RMD', $dir); - } - - /** - * Rename File - * @access private - */ - function _rename($old_handle, $new_handle) - { - $this->_send_command('RNFR', $old_handle); - return $this->_send_command('RNTO', $new_handle); - } - - /** - * Change current working directory (CHDIR) - * @access private - */ - function _chdir($dir = '') - { - if ($dir && $dir !== '/') - { - if (substr($dir, -1, 1) == '/') - { - $dir = substr($dir, 0, -1); - } - } - - return $this->_send_command('CWD', $dir); - } - - /** - * change file permissions (CHMOD) - * @access private - */ - function _chmod($file, $perms) - { - // Unfortunatly CHMOD is not expecting an octal value... - // We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;) - return $this->_send_command('SITE CHMOD', base_convert($perms, 10, 8) . ' ' . $file); - } - - /** - * Upload file to location (PUT) - * @access private - */ - function _put($from_file, $to_file) - { - // We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced) - // 'I' == BINARY - // 'A' == ASCII - if (!$this->_send_command('TYPE', 'I')) - { - return false; - } - - // open the connection to send file over - if (!$this->_open_data_connection()) - { - return false; - } - - $this->_send_command('STOR', $to_file, false); - - // send the file - $fp = @fopen($from_file, 'rb'); - while (!@feof($fp)) - { - @fwrite($this->data_connection, @fread($fp, 4096)); - } - @fclose($fp); - - // close connection - $this->_close_data_connection(); - - return $this->_check_command(); - } - - /** - * Delete file (DELETE) - * @access private - */ - function _delete($file) - { - return $this->_send_command('DELE', $file); - } - - /** - * Close ftp session (CLOSE) - * @access private - */ - function _close() - { - if (!$this->connection) - { - return false; - } - - return $this->_send_command('QUIT'); - } - - /** - * Return current working directory (CWD) - * At the moment not used by parent class - * @access private - */ - function _cwd() - { - $this->_send_command('PWD', '', false); - return preg_replace('#^[0-9]{3} "(.+)" .+\r\n#', '\\1', $this->_check_command(true)); - } - - /** - * Return list of files in a given directory (LS) - * @access private - */ - function _ls($dir = './') - { - if (!$this->_open_data_connection()) - { - return false; - } - - $this->_send_command('NLST', $dir); - - $list = array(); - while (!@feof($this->data_connection)) - { - $filename = preg_replace('#[\r\n]#', '', @fgets($this->data_connection, 512)); - - if ($filename !== '') - { - $list[] = $filename; - } - } - $this->_close_data_connection(); - - // Clear buffer - $this->_check_command(); - - // See bug #46295 - Some FTP daemons don't like './' - if ($dir === './' && empty($list)) - { - // Let's try some alternatives - $list = $this->_ls('.'); - - if (empty($list)) - { - $list = $this->_ls(''); - } - - return $list; - } - - // Remove path if prepended - foreach ($list as $key => $item) - { - // Use same separator for item and dir - $item = str_replace('\\', '/', $item); - $dir = str_replace('\\', '/', $dir); - - if (!empty($dir) && strpos($item, $dir) === 0) - { - $item = substr($item, strlen($dir)); - } - - $list[$key] = $item; - } - - return $list; - } - - /** - * Send a command to server (FTP fsock only function) - * @access private - */ - function _send_command($command, $args = '', $check = true) - { - if (!empty($args)) - { - $command = "$command $args"; - } - - fwrite($this->connection, $command . "\r\n"); - - if ($check === true && !$this->_check_command()) - { - return false; - } - - return true; - } - - /** - * Opens a connection to send data (FTP fosck only function) - * @access private - */ - function _open_data_connection() - { - // Try to find out whether we have a IPv4 or IPv6 (control) connection - if (function_exists('stream_socket_get_name')) - { - $socket_name = stream_socket_get_name($this->connection, true); - $server_ip = substr($socket_name, 0, strrpos($socket_name, ':')); - } - - if (!isset($server_ip) || preg_match(get_preg_expression('ipv4'), $server_ip)) - { - // Passive mode - $this->_send_command('PASV', '', false); - - if (!$ip_port = $this->_check_command(true)) - { - return false; - } - - // open the connection to start sending the file - if (!preg_match('#[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+#', $ip_port, $temp)) - { - // bad ip and port - return false; - } - - $temp = explode(',', $temp[0]); - $server_ip = $temp[0] . '.' . $temp[1] . '.' . $temp[2] . '.' . $temp[3]; - $server_port = $temp[4] * 256 + $temp[5]; - } - else - { - // Extended Passive Mode - RFC2428 - $this->_send_command('EPSV', '', false); - - if (!$epsv_response = $this->_check_command(true)) - { - return false; - } - - // Response looks like "229 Entering Extended Passive Mode (|||12345|)" - // where 12345 is the tcp port for the data connection - if (!preg_match('#\(\|\|\|([0-9]+)\|\)#', $epsv_response, $match)) - { - return false; - } - $server_port = (int) $match[1]; - - // fsockopen expects IPv6 address in square brackets - $server_ip = "[$server_ip]"; - } - - $errno = 0; - $errstr = ''; - - if (!$this->data_connection = @fsockopen($server_ip, $server_port, $errno, $errstr, $this->timeout)) - { - return false; - } - @stream_set_timeout($this->data_connection, $this->timeout); - - return true; - } - - /** - * Closes a connection used to send data - * @access private - */ - function _close_data_connection() - { - return @fclose($this->data_connection); - } - - /** - * Check to make sure command was successful (FTP fsock only function) - * @access private - */ - function _check_command($return = false) - { - $response = ''; - - do - { - $result = @fgets($this->connection, 512); - $response .= $result; - } - while (substr($result, 3, 1) !== ' '); - - if (!preg_match('#^[123]#', $response)) - { - return false; - } - - return ($return) ? $response : true; - } -} diff --git a/install/update/old/includes/functions_user.php b/install/update/old/includes/functions_user.php deleted file mode 100644 index fb9241d..0000000 --- a/install/update/old/includes/functions_user.php +++ /dev/null @@ -1,3759 +0,0 @@ - -* @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; -} - -/** -* Obtain user_ids from usernames or vice versa. Returns false on -* success else the error string -* -* @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, $update_references = false) -{ - global $db; - - // Are both arrays already filled? Yep, return else - // are neither array filled? - if ($user_id_ary && $username_ary) - { - return false; - } - else if (!$user_id_ary && !$username_ary) - { - return 'NO_USERS'; - } - - $which_ary = ($user_id_ary) ? 'user_id_ary' : 'username_ary'; - - if (${$which_ary} && !is_array(${$which_ary})) - { - ${$which_ary} = array(${$which_ary}); - } - - $sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', ${$which_ary}) : array_map('utf8_clean_string', ${$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(); - - // Grab the user id/username records - $sql_where = ($which_ary == 'user_id_ary') ? 'user_id' : 'username_clean'; - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set($sql_where, $sql_in); - - if ($user_type !== false && !empty($user_type)) - { - $sql .= ' AND ' . $db->sql_in_set('user_type', $user_type); - } - - $result = $db->sql_query($sql); - - if (!($row = $db->sql_fetchrow($result))) - { - $db->sql_freeresult($result); - return 'NO_USERS'; - } - - do - { - $username_ary[$row['user_id']] = $row['username']; - $user_id_ary[] = $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); - $db->sql_freeresult($result); - - return false; -} - -/** -* Get latest registered username and update database to reflect it -*/ -function update_last_username() -{ - global $config, $db; - - // Get latest username - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') - ORDER BY user_id DESC'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $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); - } -} - -/** -* Updates a username across all relevant tables/fields -* -* @param string $old_name the old/current username -* @param string $new_name the new username -*/ -function user_update_name($old_name, $new_name) -{ - global $config, $db, $cache, $phpbb_dispatcher; - - $update_ary = array( - FORUMS_TABLE => array( - 'forum_last_poster_id' => 'forum_last_poster_name', - ), - MODERATOR_CACHE_TABLE => array( - 'user_id' => 'username', - ), - POSTS_TABLE => array( - 'poster_id' => 'post_username', - ), - TOPICS_TABLE => array( - 'topic_poster' => 'topic_first_poster_name', - 'topic_last_poster_id' => 'topic_last_poster_name', - ), - ); - - foreach ($update_ary as $table => $field_ary) - { - foreach ($field_ary as $id_field => $name_field) - { - $sql = "UPDATE $table - SET $name_field = '" . $db->sql_escape($new_name) . "' - WHERE $name_field = '" . $db->sql_escape($old_name) . "' - AND $id_field <> " . ANONYMOUS; - $db->sql_query($sql); - } - } - - if ($config['newest_username'] == $old_name) - { - $config->set('newest_username', $new_name, false); - } - - /** - * Update a username when it is changed - * - * @event core.update_username - * @var string old_name The old username that is replaced - * @var string new_name The new username - * @since 3.1.0-a1 - */ - $vars = array('old_name', 'new_name'); - extract($phpbb_dispatcher->trigger_event('core.update_username', compact($vars))); - - // Because some tables/caches use username-specific data we need to purge this here. - $cache->destroy('sql', MODERATOR_CACHE_TABLE); -} - -/** -* 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 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, $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'])) - { - return false; - } - - $username_clean = utf8_clean_string($user_row['username']); - - if (empty($username_clean)) - { - return false; - } - - $sql_ary = array( - 'username' => $user_row['username'], - 'username_clean' => $username_clean, - 'user_password' => (isset($user_row['user_password'])) ? $user_row['user_password'] : '', - 'user_email' => strtolower($user_row['user_email']), - 'user_email_hash' => phpbb_email_hash($user_row['user_email']), - 'group_id' => $user_row['group_id'], - 'user_type' => $user_row['user_type'], - ); - - // These are the additional vars able to be specified - $additional_vars = array( - 'user_permissions' => '', - 'user_timezone' => $config['board_timezone'], - 'user_dateformat' => $config['default_dateformat'], - 'user_lang' => $config['default_lang'], - 'user_style' => (int) $config['default_style'], - 'user_actkey' => '', - 'user_ip' => '', - 'user_regdate' => time(), - 'user_passchg' => time(), - 'user_options' => 230271, - // We do not set the new flag here - registration scripts need to specify it - 'user_new' => 0, - - 'user_inactive_reason' => 0, - 'user_inactive_time' => 0, - 'user_lastmark' => time(), - 'user_lastvisit' => 0, - 'user_lastpost_time' => 0, - 'user_lastpage' => '', - 'user_posts' => 0, - 'user_colour' => '', - 'user_avatar' => '', - 'user_avatar_type' => '', - 'user_avatar_width' => 0, - 'user_avatar_height' => 0, - 'user_new_privmsg' => 0, - 'user_unread_privmsg' => 0, - 'user_last_privmsg' => 0, - 'user_message_rules' => 0, - 'user_full_folder' => PRIVMSGS_NO_BOX, - 'user_emailtime' => 0, - - 'user_notify' => 0, - 'user_notify_pm' => 1, - 'user_notify_type' => NOTIFY_EMAIL, - 'user_allow_pm' => 1, - 'user_allow_viewonline' => 1, - 'user_allow_viewemail' => 1, - 'user_allow_massemail' => 1, - - 'user_sig' => '', - 'user_sig_bbcode_uid' => '', - 'user_sig_bbcode_bitfield' => '', - - 'user_form_salt' => unique_id(), - ); - - // Now fill the sql array with not required variables - foreach ($additional_vars as $key => $default_value) - { - $sql_ary[$key] = (isset($user_row[$key])) ? $user_row[$key] : $default_value; - } - - // Any additional variables in $user_row not covered above? - $remaining_vars = array_diff(array_keys($user_row), array_keys($sql_ary)); - - // Now fill our sql array with the remaining vars - if (count($remaining_vars)) - { - foreach ($remaining_vars as $key) - { - $sql_ary[$key] = $user_row[$key]; - } - } - - /** - * 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 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 - * @changed 3.1.0-b5 Added user_row and cp_data - * @changed 3.1.11-RC1 Added notifications_data - */ - $vars = array('user_row', 'cp_data', 'sql_ary', 'notifications_data'); - extract($phpbb_dispatcher->trigger_event('core.user_add_modify_data', compact($vars))); - - $sql = 'INSERT INTO ' . USERS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $user_id = $db->sql_nextid(); - - // Insert Custom Profile Fields - 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)); - $db->sql_query($sql); - } - - // Place into appropriate group... - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'user_id' => (int) $user_id, - 'group_id' => (int) $user_row['group_id'], - 'user_pending' => 0) - ); - $db->sql_query($sql); - - // Now make it the users default group... - group_set_user_default($user_row['group_id'], array($user_id), false); - - // Add to newly registered users group if user_new is 1 - if ($config['new_member_post_limit'] && $sql_ary['user_new']) - { - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = 'NEWLY_REGISTERED' - AND group_type = " . GROUP_SPECIAL; - $result = $db->sql_query($sql); - $add_group_id = (int) $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - - if ($add_group_id) - { - global $phpbb_log; - - // 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. - if ($config['new_member_group_default']) - { - group_user_add($add_group_id, $user_id, false, false, true); - $user_row['group_id'] = $add_group_id; - } - else - { - group_user_add($add_group_id, $user_id); - } - - $phpbb_log->enable('admin'); - } - } - - // 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) - { - $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 . ' - WHERE group_id = ' . (int) $user_row['group_id']; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $config->set('newest_user_colour', $row['group_colour'], false); - } - - // Use default notifications settings if notifications_data is not set - if ($notifications_data === null) - { - $notifications_data = array( - array( - 'item_type' => 'notification.type.post', - 'method' => 'notification.method.email', - ), - array( - 'item_type' => 'notification.type.topic', - 'method' => 'notification.method.email', - ), - ); - } - - /** - * 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) - { - $phpbb_notifications->add_subscription($subscription['item_type'], 0, $subscription['method'], $user_id); - } - } - - /** - * 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 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'); - extract($phpbb_dispatcher->trigger_event('core.user_add_after', compact($vars))); - - return $user_id; -} - -/** - * Remove User - * - * @param string $mode Either 'retain' or 'remove' - * @param mixed $user_ids Either an array of integers or an integer - * @param bool $retain_username - * @return bool - */ -function user_delete($mode, $user_ids, $retain_username = true) -{ - global $cache, $config, $db, $user, $phpbb_dispatcher, $phpbb_container; - global $phpbb_root_path, $phpEx; - - $db->sql_transaction('begin'); - - $user_rows = array(); - if (!is_array($user_ids)) - { - $user_ids = array($user_ids); - } - - $user_id_sql = $db->sql_in_set('user_id', $user_ids); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE ' . $user_id_sql; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $user_rows[(int) $row['user_id']] = $row; - } - $db->sql_freeresult($result); - - if (empty($user_rows)) - { - return false; - } - - /** - * Event before a user is deleted - * - * @event core.delete_user_before - * @var string mode Mode of deletion (retain/delete posts) - * @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', 'user_rows'); - extract($phpbb_dispatcher->trigger_event('core.delete_user_before', compact($vars))); - - // Before we begin, we will remove the reports the user issued. - $sql = 'SELECT r.post_id, p.topic_id - FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . ' p - WHERE ' . $db->sql_in_set('r.user_id', $user_ids) . ' - AND p.post_id = r.post_id'; - $result = $db->sql_query($sql); - - $report_posts = $report_topics = array(); - while ($row = $db->sql_fetchrow($result)) - { - $report_posts[] = $row['post_id']; - $report_topics[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (count($report_posts)) - { - $report_posts = array_unique($report_posts); - $report_topics = array_unique($report_topics); - - // Get a list of topics that still contain reported posts - $sql = 'SELECT DISTINCT topic_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $report_topics) . ' - AND post_reported = 1 - AND ' . $db->sql_in_set('post_id', $report_posts, true); - $result = $db->sql_query($sql); - - $keep_report_topics = array(); - while ($row = $db->sql_fetchrow($result)) - { - $keep_report_topics[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (count($keep_report_topics)) - { - $report_topics = array_diff($report_topics, $keep_report_topics); - } - unset($keep_report_topics); - - // Now set the flags back - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_reported = 0 - WHERE ' . $db->sql_in_set('post_id', $report_posts); - $db->sql_query($sql); - - if (count($report_topics)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_reported = 0 - WHERE ' . $db->sql_in_set('topic_id', $report_topics); - $db->sql_query($sql); - } - } - - // Remove reports - $db->sql_query('DELETE FROM ' . REPORTS_TABLE . ' WHERE ' . $user_id_sql); - - $num_users_delta = 0; - - // Get auth provider collection in case accounts might need to be unlinked - $provider_collection = $phpbb_container->get('auth.provider_collection'); - - // Some things need to be done in the loop (if the query changes based - // on which user is currently being deleted) - $added_guest_posts = 0; - foreach ($user_rows as $user_id => $user_row) - { - if ($user_row['user_avatar'] && $user_row['user_avatar_type'] == 'avatar.driver.upload') - { - avatar_delete('user', $user_row); - } - - // Unlink accounts - foreach ($provider_collection as $provider_name => $auth_provider) - { - $provider_data = $auth_provider->get_auth_link_data($user_id); - - if ($provider_data !== null) - { - $link_data = array( - 'user_id' => $user_id, - 'link_method' => 'user_delete', - ); - - // BLOCK_VARS might contain hidden fields necessary for unlinking accounts - if (isset($provider_data['BLOCK_VARS']) && is_array($provider_data['BLOCK_VARS'])) - { - foreach ($provider_data['BLOCK_VARS'] as $provider_service) - { - if (!array_key_exists('HIDDEN_FIELDS', $provider_service)) - { - $provider_service['HIDDEN_FIELDS'] = array(); - } - - $auth_provider->unlink_account(array_merge($link_data, $provider_service['HIDDEN_FIELDS'])); - } - } - else - { - $auth_provider->unlink_account($link_data); - } - } - } - - // Decrement number of users if this user is active - if ($user_row['user_type'] != USER_INACTIVE && $user_row['user_type'] != USER_IGNORE) - { - --$num_users_delta; - } - - switch ($mode) - { - case 'retain': - if ($retain_username === false) - { - $post_username = $user->lang['GUEST']; - } - else - { - $post_username = $user_row['username']; - } - - // If the user is inactive and newly registered - // we assume no posts from the user, and save - // the queries - if ($user_row['user_type'] != USER_INACTIVE || $user_row['user_inactive_reason'] != INACTIVE_REGISTER || $user_row['user_posts']) - { - // When we delete these users and retain the posts, we must assign all the data to the guest user - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_last_poster_id = ' . ANONYMOUS . ", forum_last_poster_name = '" . $db->sql_escape($post_username) . "', forum_last_poster_colour = '' - WHERE forum_last_poster_id = $user_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET poster_id = ' . ANONYMOUS . ", post_username = '" . $db->sql_escape($post_username) . "' - WHERE poster_id = $user_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_poster = ' . ANONYMOUS . ", topic_first_poster_name = '" . $db->sql_escape($post_username) . "', topic_first_poster_colour = '' - WHERE topic_poster = $user_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_last_poster_id = ' . ANONYMOUS . ", topic_last_poster_name = '" . $db->sql_escape($post_username) . "', topic_last_poster_colour = '' - WHERE topic_last_poster_id = $user_id"; - $db->sql_query($sql); - - // Since we change every post by this author, we need to count this amount towards the anonymous user - - if ($user_row['user_posts']) - { - $added_guest_posts += $user_row['user_posts']; - } - } - break; - - case 'remove': - // there is nothing variant specific to deleting posts - break; - } - } - - if ($num_users_delta != 0) - { - $config->increment('num_users', $num_users_delta, false); - } - - // Now do the invariant tasks - // all queries performed in one call of this function are in a single transaction - // so this is kosher - if ($mode == 'retain') - { - // Assign more data to the Anonymous user - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET poster_id = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('poster_id', $user_ids); - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts + ' . $added_guest_posts . ' - WHERE user_id = ' . ANONYMOUS; - $db->sql_query($sql); - } - else if ($mode == 'remove') - { - if (!function_exists('delete_posts')) - { - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - - // Delete posts, attachments, etc. - // delete_posts can handle any number of IDs in its second argument - delete_posts('poster_id', $user_ids); - } - - $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) - { - $sql = "DELETE FROM $table - WHERE " . $user_id_sql; - $db->sql_query($sql); - } - $db->sql_return_on_error(); - - $cache->destroy('sql', MODERATOR_CACHE_TABLE); - - // Change user_id to anonymous for posts edited by this user - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_edit_user = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('post_edit_user', $user_ids); - $db->sql_query($sql); - - // Change user_id to anonymous for pms edited by this user - $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' - SET message_edit_user = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('message_edit_user', $user_ids); - $db->sql_query($sql); - - // Change user_id to anonymous for posts deleted by this user - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_delete_user = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('post_delete_user', $user_ids); - $db->sql_query($sql); - - // Change user_id to anonymous for topics deleted by this user - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_delete_user = ' . ANONYMOUS . ' - WHERE ' . $db->sql_in_set('topic_delete_user', $user_ids); - $db->sql_query($sql); - - // Delete user log entries about this user - $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE ' . $db->sql_in_set('reportee_id', $user_ids); - $db->sql_query($sql); - - // Change user_id to anonymous for this users triggered events - $sql = 'UPDATE ' . LOG_TABLE . ' - SET user_id = ' . ANONYMOUS . ' - WHERE ' . $user_id_sql; - $db->sql_query($sql); - - // Delete the user_id from the zebra table - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $user_id_sql . ' - OR ' . $db->sql_in_set('zebra_id', $user_ids); - $db->sql_query($sql); - - // Delete the user_id from the banlist - $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_userid', $user_ids); - $db->sql_query($sql); - - // Delete the user_id from the session table - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('session_user_id', $user_ids); - $db->sql_query($sql); - - // Clean the private messages tables from the user - if (!function_exists('phpbb_delete_user_pms')) - { - include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - } - phpbb_delete_users_pms($user_ids); - - $phpbb_notifications = $phpbb_container->get('notification_manager'); - $phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_ids); - - $db->sql_transaction('commit'); - - /** - * Event after a user is deleted - * - * @event core.delete_user_after - * @var string mode Mode of deletion (retain/delete posts) - * @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', 'user_rows'); - extract($phpbb_dispatcher->trigger_event('core.delete_user_after', compact($vars))); - - // Reset newest user info if appropriate - if (in_array($config['newest_user_id'], $user_ids)) - { - update_last_username(); - } - - return false; -} - -/** -* Flips user_type from active to inactive and vice versa, handles group membership updates -* -* @param string $mode can be flip for flipping from active/inactive, activate or deactivate -*/ -function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL) -{ - global $config, $db, $user, $auth, $phpbb_dispatcher; - - $deactivated = $activated = 0; - $sql_statements = array(); - - if (!is_array($user_id_ary)) - { - $user_id_ary = array($user_id_ary); - } - - if (!count($user_id_ary)) - { - return; - } - - $sql = 'SELECT user_id, group_id, user_type, user_inactive_reason - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary = array(); - - if ($row['user_type'] == USER_IGNORE || $row['user_type'] == USER_FOUNDER || - ($mode == 'activate' && $row['user_type'] != USER_INACTIVE) || - ($mode == 'deactivate' && $row['user_type'] == USER_INACTIVE)) - { - continue; - } - - if ($row['user_type'] == USER_INACTIVE) - { - $activated++; - } - else - { - $deactivated++; - - // Remove the users session key... - $user->reset_login_keys($row['user_id']); - } - - $sql_ary += array( - 'user_type' => ($row['user_type'] == USER_NORMAL) ? USER_INACTIVE : USER_NORMAL, - 'user_inactive_time' => ($row['user_type'] == USER_NORMAL) ? time() : 0, - 'user_inactive_reason' => ($row['user_type'] == USER_NORMAL) ? $reason : 0, - ); - - $sql_statements[$row['user_id']] = $sql_ary; - } - $db->sql_freeresult($result); - - /** - * Check or modify activated/deactivated users data before submitting it to the database - * - * @event core.user_active_flip_before - * @var string mode User type changing mode, can be: flip|activate|deactivate - * @var int reason Reason for changing user type, can be: INACTIVE_REGISTER|INACTIVE_PROFILE|INACTIVE_MANUAL|INACTIVE_REMIND - * @var int activated The number of users to be activated - * @var int deactivated The number of users to be deactivated - * @var array user_id_ary Array with user ids to change user type - * @var array sql_statements Array with users data to submit to the database, keys: user ids, values: arrays with user data - * @since 3.1.4-RC1 - */ - $vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements'); - extract($phpbb_dispatcher->trigger_event('core.user_active_flip_before', compact($vars))); - - if (count($sql_statements)) - { - foreach ($sql_statements as $user_id => $sql_ary) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - } - - $auth->acl_clear_prefetch(array_keys($sql_statements)); - } - - /** - * Perform additional actions after the users have been activated/deactivated - * - * @event core.user_active_flip_after - * @var string mode User type changing mode, can be: flip|activate|deactivate - * @var int reason Reason for changing user type, can be: INACTIVE_REGISTER|INACTIVE_PROFILE|INACTIVE_MANUAL|INACTIVE_REMIND - * @var int activated The number of users to be activated - * @var int deactivated The number of users to be deactivated - * @var array user_id_ary Array with user ids to change user type - * @var array sql_statements Array with users data to submit to the database, keys: user ids, values: arrays with user data - * @since 3.1.4-RC1 - */ - $vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements'); - extract($phpbb_dispatcher->trigger_event('core.user_active_flip_after', compact($vars))); - - if ($deactivated) - { - $config->increment('num_users', $deactivated * (-1), false); - } - - if ($activated) - { - $config->increment('num_users', $activated, false); - } - - // Update latest username - update_last_username(); -} - -/** -* Add a ban or ban exclusion to the banlist. Bans either a user, an IP or an email address -* -* @param string $mode Type of ban. One of the following: user, ip, email -* @param mixed $ban Banned entity. Either string or array with usernames, ips or email addresses -* @param int $ban_len Ban length in minutes -* @param string $ban_len_other Ban length as a date (YYYY-MM-DD) -* @param boolean $ban_exclude Exclude these entities from banning? -* @param string $ban_reason String describing the reason for this ban -* @return boolean -*/ -function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reason, $ban_give_reason = '') -{ - global $db, $user, $cache, $phpbb_log; - - // Delete stale bans - $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ban_end < ' . time() . ' - AND ban_end <> 0'; - $db->sql_query($sql); - - $ban_list = (!is_array($ban)) ? array_unique(explode("\n", $ban)) : $ban; - $ban_list_log = implode(', ', $ban_list); - - $current_time = time(); - - // Set $ban_end to the unix time when the ban should end. 0 is a permanent ban. - if ($ban_len) - { - if ($ban_len != -1 || !$ban_len_other) - { - $ban_end = max($current_time, $current_time + ($ban_len) * 60); - } - else - { - $ban_other = explode('-', $ban_len_other); - 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() - ->setDate((int) $ban_other[0], (int) $ban_other[1], (int) $ban_other[2]) - ->setTime(0, 0, 0) - ->getTimestamp() + $user->timezone->getOffset(new DateTime('UTC'))); - } - else - { - trigger_error('LENGTH_BAN_INVALID', E_USER_WARNING); - } - } - } - else - { - $ban_end = 0; - } - - $founder = $founder_names = array(); - - if (!$ban_exclude) - { - // Create a list of founder... - $sql = 'SELECT user_id, user_email, username_clean - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_FOUNDER; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $founder[$row['user_id']] = $row['user_email']; - $founder_names[$row['user_id']] = $row['username_clean']; - } - $db->sql_freeresult($result); - } - - $banlist_ary = array(); - - switch ($mode) - { - case 'user': - $type = 'ban_userid'; - - // At the moment we do not support wildcard username banning - - // Select the relevant user_ids. - $sql_usernames = array(); - - foreach ($ban_list as $username) - { - $username = trim($username); - if ($username != '') - { - $clean_name = utf8_clean_string($username); - if ($clean_name == $user->data['username_clean']) - { - trigger_error('CANNOT_BAN_YOURSELF', E_USER_WARNING); - } - if (in_array($clean_name, $founder_names)) - { - trigger_error('CANNOT_BAN_FOUNDER', E_USER_WARNING); - } - $sql_usernames[] = $clean_name; - } - } - - // Make sure we have been given someone to ban - if (!count($sql_usernames)) - { - trigger_error('NO_USER_SPECIFIED', E_USER_WARNING); - } - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('username_clean', $sql_usernames); - - // Do not allow banning yourself, the guest account, or founders. - $non_bannable = array($user->data['user_id'], ANONYMOUS); - if (count($founder)) - { - $sql .= ' AND ' . $db->sql_in_set('user_id', array_merge(array_keys($founder), $non_bannable), true); - } - else - { - $sql .= ' AND ' . $db->sql_in_set('user_id', $non_bannable, true); - } - - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - do - { - $banlist_ary[] = (int) $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); - } - else - { - $db->sql_freeresult($result); - trigger_error('NO_USERS', E_USER_WARNING); - } - $db->sql_freeresult($result); - break; - - case 'ip': - $type = 'ban_ip'; - - foreach ($ban_list as $ban_item) - { - if (preg_match('#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})[ ]*\-[ ]*([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#', trim($ban_item), $ip_range_explode)) - { - // This is an IP range - // Don't ask about all this, just don't ask ... ! - $ip_1_counter = $ip_range_explode[1]; - $ip_1_end = $ip_range_explode[5]; - - while ($ip_1_counter <= $ip_1_end) - { - $ip_2_counter = ($ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[2] : 0; - $ip_2_end = ($ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[6]; - - if ($ip_2_counter == 0 && $ip_2_end == 254) - { - $ip_2_counter = 256; - - $banlist_ary[] = "$ip_1_counter.*"; - } - - while ($ip_2_counter <= $ip_2_end) - { - $ip_3_counter = ($ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[3] : 0; - $ip_3_end = ($ip_2_counter < $ip_2_end || $ip_1_counter < $ip_1_end) ? 254 : $ip_range_explode[7]; - - if ($ip_3_counter == 0 && $ip_3_end == 254) - { - $ip_3_counter = 256; - - $banlist_ary[] = "$ip_1_counter.$ip_2_counter.*"; - } - - while ($ip_3_counter <= $ip_3_end) - { - $ip_4_counter = ($ip_3_counter == $ip_range_explode[3] && $ip_2_counter == $ip_range_explode[2] && $ip_1_counter == $ip_range_explode[1]) ? $ip_range_explode[4] : 0; - $ip_4_end = ($ip_3_counter < $ip_3_end || $ip_2_counter < $ip_2_end) ? 254 : $ip_range_explode[8]; - - if ($ip_4_counter == 0 && $ip_4_end == 254) - { - $ip_4_counter = 256; - - $banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.*"; - } - - while ($ip_4_counter <= $ip_4_end) - { - $banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.$ip_4_counter"; - $ip_4_counter++; - } - $ip_3_counter++; - } - $ip_2_counter++; - } - $ip_1_counter++; - } - } - else if (preg_match('#^([0-9]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})\.([0-9\*]{1,3})$#', trim($ban_item)) || preg_match('#^[a-f0-9:]+\*?$#i', trim($ban_item))) - { - // Normal IP address - $banlist_ary[] = trim($ban_item); - } - else if (preg_match('#^\*$#', trim($ban_item))) - { - // Ban all IPs - $banlist_ary[] = '*'; - } - else if (preg_match('#^([\w\-_]\.?){2,}$#is', trim($ban_item))) - { - // hostname - $ip_ary = gethostbynamel(trim($ban_item)); - - if (!empty($ip_ary)) - { - foreach ($ip_ary as $ip) - { - if ($ip) - { - if (strlen($ip) > 40) - { - continue; - } - - $banlist_ary[] = $ip; - } - } - } - } - - if (empty($banlist_ary)) - { - trigger_error('NO_IPS_DEFINED', E_USER_WARNING); - } - } - break; - - case 'email': - $type = 'ban_email'; - - foreach ($ban_list as $ban_item) - { - $ban_item = trim($ban_item); - - if (preg_match('#^.*?@*|(([a-z0-9\-]+\.)+([a-z]{2,3}))$#i', $ban_item)) - { - if (strlen($ban_item) > 100) - { - continue; - } - - if (!count($founder) || !in_array($ban_item, $founder)) - { - $banlist_ary[] = $ban_item; - } - } - } - - if (count($ban_list) == 0) - { - trigger_error('NO_EMAILS_DEFINED', E_USER_WARNING); - } - break; - - default: - trigger_error('NO_MODE', E_USER_WARNING); - break; - } - - // Fetch currently set bans of the specified type and exclude state. Prevent duplicate bans. - $sql_where = ($type == 'ban_userid') ? 'ban_userid <> 0' : "$type <> ''"; - - $sql = "SELECT $type - FROM " . BANLIST_TABLE . " - WHERE $sql_where - AND ban_exclude = " . (int) $ban_exclude; - $result = $db->sql_query($sql); - - // Reset $sql_where, because we use it later... - $sql_where = ''; - - if ($row = $db->sql_fetchrow($result)) - { - $banlist_ary_tmp = array(); - do - { - switch ($mode) - { - case 'user': - $banlist_ary_tmp[] = $row['ban_userid']; - break; - - case 'ip': - $banlist_ary_tmp[] = $row['ban_ip']; - break; - - case 'email': - $banlist_ary_tmp[] = $row['ban_email']; - break; - } - } - while ($row = $db->sql_fetchrow($result)); - - $banlist_ary_tmp = array_intersect($banlist_ary, $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 . ' - WHERE ' . $db->sql_in_set($type, $banlist_ary_tmp) . ' - AND ban_exclude = ' . (int) $ban_exclude; - $db->sql_query($sql); - } - - unset($banlist_ary_tmp); - } - $db->sql_freeresult($result); - - // We have some entities to ban - if (count($banlist_ary)) - { - $sql_ary = array(); - - foreach ($banlist_ary as $ban_entry) - { - $sql_ary[] = array( - $type => $ban_entry, - 'ban_start' => (int) $current_time, - 'ban_end' => (int) $ban_end, - 'ban_exclude' => (int) $ban_exclude, - 'ban_reason' => (string) $ban_reason, - 'ban_give_reason' => (string) $ban_give_reason, - ); - } - - $db->sql_multi_insert(BANLIST_TABLE, $sql_ary); - - // If we are banning we want to logout anyone matching the ban - if (!$ban_exclude) - { - switch ($mode) - { - case 'user': - $sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $banlist_ary); - break; - - case 'ip': - $sql_where = 'WHERE ' . $db->sql_in_set('session_ip', $banlist_ary); - break; - - case 'email': - $banlist_ary_sql = array(); - - foreach ($banlist_ary as $ban_entry) - { - $banlist_ary_sql[] = (string) str_replace('*', '%', $ban_entry); - } - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_email', $banlist_ary_sql); - $result = $db->sql_query($sql); - - $sql_in = array(); - - if ($row = $db->sql_fetchrow($result)) - { - do - { - $sql_in[] = $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); - - $sql_where = 'WHERE ' . $db->sql_in_set('session_user_id', $sql_in); - } - $db->sql_freeresult($result); - break; - } - - if (isset($sql_where) && $sql_where) - { - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - $sql_where"; - $db->sql_query($sql); - - if ($mode == 'user') - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' ' . ((in_array('*', $banlist_ary)) ? '' : 'WHERE ' . $db->sql_in_set('user_id', $banlist_ary)); - $db->sql_query($sql); - } - } - } - - // Update log - $log_entry = ($ban_exclude) ? 'LOG_BAN_EXCLUDE_' : 'LOG_BAN_'; - - // Add to admin log, moderator log and user notes - $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) - { - $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 - )); - } - } - - $cache->destroy('sql', BANLIST_TABLE); - - return true; - } - - // There was nothing to ban/exclude. But destroying the cache because of the removal of stale bans. - $cache->destroy('sql', BANLIST_TABLE); - - return false; -} - -/** -* Unban User -*/ -function user_unban($mode, $ban) -{ - global $db, $user, $cache, $phpbb_log, $phpbb_dispatcher; - - // Delete stale bans - $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ban_end < ' . time() . ' - AND ban_end <> 0'; - $db->sql_query($sql); - - if (!is_array($ban)) - { - $ban = array($ban); - } - - $unban_sql = array_map('intval', $ban); - - if (count($unban_sql)) - { - // Grab details of bans for logging information later - switch ($mode) - { - case 'user': - $sql = 'SELECT u.username AS unban_info, u.user_id - FROM ' . USERS_TABLE . ' u, ' . BANLIST_TABLE . ' b - WHERE ' . $db->sql_in_set('b.ban_id', $unban_sql) . ' - AND u.user_id = b.ban_userid'; - break; - - case 'email': - $sql = 'SELECT ban_email AS unban_info - FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_id', $unban_sql); - break; - - case 'ip': - $sql = 'SELECT ban_ip AS unban_info - FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_id', $unban_sql); - break; - } - $result = $db->sql_query($sql); - - $l_unban_list = ''; - $user_ids_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $l_unban_list .= (($l_unban_list != '') ? ', ' : '') . $row['unban_info']; - if ($mode == 'user') - { - $user_ids_ary[] = $row['user_id']; - } - } - $db->sql_freeresult($result); - - $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ' . $db->sql_in_set('ban_id', $unban_sql); - $db->sql_query($sql); - - // Add to moderator log, admin log and user notes - $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) - { - $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_UNBAN_' . strtoupper($mode), false, array( - 'reportee_id' => $user_id, - $l_unban_list - )); - } - } - - /** - * Use this event to perform actions after the unban has been performed - * - * @event core.user_unban - * @var string mode One of the following: user, ip, email - * @var array user_ids_ary Array with user_ids - * @since 3.1.11-RC1 - */ - $vars = array( - 'mode', - 'user_ids_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.user_unban', compact($vars))); - } - - $cache->destroy('sql', BANLIST_TABLE); - - return false; -} - -/** -* Internet Protocol Address Whois -* RFC3912: WHOIS Protocol Specification -* -* @param string $ip Ip address, either IPv4 or IPv6. -* -* @return string Empty string if not a valid ip address. -* Otherwise make_clickable()'ed whois result. -*/ -function user_ipwhois($ip) -{ - if (empty($ip)) - { - return ''; - } - - 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))) - { - // CRLF as per RFC3912 - fputs($fsk, "$ip\r\n"); - while (!feof($fsk)) - { - $ipwhois .= fgets($fsk, 1024); - } - @fclose($fsk); - } - - $match = array(); - - // Test for referrals from $whois_host to other whois databases, roll on rwhois - if (preg_match('#ReferralServer:[\x20]*whois://(.+)#im', $ipwhois, $match)) - { - if (strpos($match[1], ':') !== false) - { - $pos = strrpos($match[1], ':'); - $server = substr($match[1], 0, $pos); - $port = (int) substr($match[1], $pos + 1); - unset($pos); - } - else - { - $server = $match[1]; - $port = 43; - } - - $buffer = ''; - - if (($fsk = @fsockopen($server, $port))) - { - fputs($fsk, "$ip\r\n"); - while (!feof($fsk)) - { - $buffer .= fgets($fsk, 1024); - } - @fclose($fsk); - } - - // Use the result from $whois_host if we don't get any result here - $ipwhois = (empty($buffer)) ? $ipwhois : $buffer; - } - - $ipwhois = htmlspecialchars($ipwhois); - - // Magic URL ;) - return trim(make_clickable($ipwhois, false, '')); -} - -/** -* Data validation ... used primarily but not exclusively by ucp modules -* -* "Master" function for validating a range of data types -*/ -function validate_data($data, $val_ary) -{ - global $user; - - $error = array(); - - foreach ($val_ary as $var => $val_seq) - { - if (!is_array($val_seq[0])) - { - $val_seq = array($val_seq); - } - - foreach ($val_seq as $validate) - { - $function = array_shift($validate); - array_unshift($validate, $data[$var]); - - if (is_array($function)) - { - $result = call_user_func_array(array($function[0], 'validate_' . $function[1]), $validate); - } - else - { - $function_prefix = (function_exists('phpbb_validate_' . $function)) ? 'phpbb_validate_' : 'validate_'; - $result = call_user_func_array($function_prefix . $function, $validate); - } - - if ($result) - { - // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted. - $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var); - } - } - } - - return $error; -} - -/** -* Validate String -* -* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function validate_string($string, $optional = false, $min = 0, $max = 0) -{ - if (empty($string) && $optional) - { - return false; - } - - if ($min && utf8_strlen(htmlspecialchars_decode($string)) < $min) - { - return 'TOO_SHORT'; - } - else if ($max && utf8_strlen(htmlspecialchars_decode($string)) > $max) - { - return 'TOO_LONG'; - } - - return false; -} - -/** -* Validate Number -* -* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function validate_num($num, $optional = false, $min = 0, $max = 1E99) -{ - if (empty($num) && $optional) - { - return false; - } - - if ($num < $min) - { - return 'TOO_SMALL'; - } - else if ($num > $max) - { - return 'TOO_LARGE'; - } - - return false; -} - -/** -* Validate Date -* @param String $string a date in the dd-mm-yyyy format -* @return boolean -*/ -function validate_date($date_string, $optional = false) -{ - $date = explode('-', $date_string); - if ((empty($date) || count($date) != 3) && $optional) - { - return false; - } - else if ($optional) - { - for ($field = 0; $field <= 1; $field++) - { - $date[$field] = (int) $date[$field]; - if (empty($date[$field])) - { - $date[$field] = 1; - } - } - $date[2] = (int) $date[2]; - // assume an arbitrary leap year - if (empty($date[2])) - { - $date[2] = 1980; - } - } - - if (count($date) != 3 || !checkdate($date[1], $date[0], $date[2])) - { - return 'INVALID'; - } - - return false; -} - - -/** -* Validate Match -* -* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function validate_match($string, $optional = false, $match = '') -{ - if (empty($string) && $optional) - { - return false; - } - - if (empty($match)) - { - return false; - } - - if (!preg_match($match, $string)) - { - return 'WRONG_DATA'; - } - - return false; -} - -/** -* Validate Language Pack ISO Name -* -* Tests whether a language name is valid and installed -* -* @param string $lang_iso The language string to test -* -* @return bool|string Either false if validation succeeded or -* a string which will be used as the error message -* (with the variable name appended) -*/ -function validate_language_iso_name($lang_iso) -{ - global $db; - - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($lang_iso) . "'"; - $result = $db->sql_query($sql); - $lang_id = (int) $db->sql_fetchfield('lang_id'); - $db->sql_freeresult($result); - - return ($lang_id) ? false : 'WRONG_DATA'; -} - -/** -* Validate Timezone Name -* -* Tests whether a timezone name is valid -* -* @param string $timezone The timezone string to test -* -* @return bool|string Either false if validation succeeded or -* a string which will be used as the error message -* (with the variable name appended) -*/ -function phpbb_validate_timezone($timezone) -{ - return (in_array($timezone, phpbb_get_timezone_identifiers($timezone))) ? false : 'TIMEZONE_INVALID'; -} - -/*** - * 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) -{ - global $config, $db, $user, $cache; - - $clean_username = utf8_clean_string($username); - $allowed_username = ($allowed_username === false) ? $user->data['username_clean'] : utf8_clean_string($allowed_username); - - if ($allowed_username == $clean_username) - { - return false; - } - - // 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_EMOJIS'; - } - - // ... fast checks first. - if (strpos($username, '"') !== false || strpos($username, '"') !== false || empty($clean_username)) - { - return 'INVALID_CHARS'; - } - - switch ($config['allow_name_chars']) - { - case 'USERNAME_CHARS_ANY': - $regex = '.+'; - break; - - case 'USERNAME_ALPHA_ONLY': - $regex = '[A-Za-z0-9]+'; - break; - - case 'USERNAME_ALPHA_SPACERS': - $regex = '[A-Za-z0-9-[\]_+ ]+'; - break; - - case 'USERNAME_LETTER_NUM': - $regex = '[\p{Lu}\p{Ll}\p{N}]+'; - break; - - case 'USERNAME_LETTER_NUM_SPACERS': - $regex = '[-\]_+ [\p{Lu}\p{Ll}\p{N}]+'; - break; - - case 'USERNAME_ASCII': - default: - $regex = '[\x01-\x7F]+'; - break; - } - - if (!preg_match('#^' . $regex . '$#u', $username)) - { - return 'INVALID_CHARS'; - } - - $sql = 'SELECT username - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape($clean_username) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return 'USERNAME_TAKEN'; - } - - $sql = 'SELECT group_name - FROM ' . GROUPS_TABLE . " - WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($username)) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return 'USERNAME_TAKEN'; - } - - $bad_usernames = $cache->obtain_disallowed_usernames(); - - foreach ($bad_usernames as $bad_username) - { - if (preg_match('#^' . $bad_username . '$#', $clean_username)) - { - return 'USERNAME_DISALLOWED'; - } - } - - return false; -} - -/** -* Check to see if the password meets the complexity settings -* -* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function validate_password($password) -{ - global $config; - - if ($password === '' || $config['pass_complex'] === 'PASS_TYPE_ANY') - { - // Password empty or no password complexity required. - return false; - } - - $upp = '\p{Lu}'; - $low = '\p{Ll}'; - $num = '\p{N}'; - $sym = '[^\p{Lu}\p{Ll}\p{N}]'; - $chars = array(); - - switch ($config['pass_complex']) - { - // No break statements below ... - // We require strong passwords in case pass_complex is not set or is invalid - default: - - // Require mixed case letters, numbers and symbols - case 'PASS_TYPE_SYMBOL': - $chars[] = $sym; - - // Require mixed case letters and numbers - case 'PASS_TYPE_ALPHA': - $chars[] = $num; - - // Require mixed case letters - case 'PASS_TYPE_CASE': - $chars[] = $low; - $chars[] = $upp; - } - - foreach ($chars as $char) - { - if (!preg_match('#' . $char . '#u', $password)) - { - return 'INVALID_CHARS'; - } - } - - return false; -} - -/** -* Check to see if email address is a valid address and contains a MX record -* -* @param string $email The email to check -* -* @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) -*/ -function phpbb_validate_email($email, $config = null) -{ - if ($config === null) - { - global $config; - } - - $email = strtolower($email); - - if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email)) - { - return 'EMAIL_INVALID'; - } - - // Check MX record. - // The idea for this is from reading the UseBB blog/announcement. :) - if ($config['email_check_mx']) - { - list(, $domain) = explode('@', $email); - - if (phpbb_checkdnsrr($domain, 'A') === false && phpbb_checkdnsrr($domain, 'MX') === false) - { - return 'DOMAIN_NO_MX_RECORD'; - } - } - - return false; -} - -/** -* Check to see if email address is banned or already present in the DB -* -* @param string $email The email to check -* @param string $allowed_email An allowed email, default being $user->data['user_email'] -* -* @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_user_email($email, $allowed_email = false) -{ - global $config, $db, $user; - - $email = strtolower($email); - $allowed_email = ($allowed_email === false) ? strtolower($user->data['user_email']) : strtolower($allowed_email); - - if ($allowed_email == $email) - { - return false; - } - - $validate_email = phpbb_validate_email($email, $config); - if ($validate_email) - { - return $validate_email; - } - - if (($ban = $user->check_ban(false, false, $email, true)) !== false) - { - return ($ban === true) ? 'EMAIL_BANNED' : (!empty($ban['ban_give_reason']) ? $ban['ban_give_reason'] : $ban); - } - - if (!$config['allow_emailreuse']) - { - $sql = 'SELECT user_email_hash - FROM ' . USERS_TABLE . " - WHERE user_email_hash = " . $db->sql_escape(phpbb_email_hash($email)); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return 'EMAIL_TAKEN'; - } - } - - return false; -} - -/** -* Validate jabber address -* Taken from the jabber class within flyspray (see author notes) -* -* @author flyspray.org -*/ -function validate_jabber($jid) -{ - if (!$jid) - { - return false; - } - - $separator_pos = strpos($jid, '@'); - - if ($separator_pos === false) - { - return 'WRONG_DATA'; - } - - $username = substr($jid, 0, $separator_pos); - $realm = substr($jid, $separator_pos + 1); - - if (strlen($username) == 0 || strlen($realm) < 3) - { - return 'WRONG_DATA'; - } - - $arr = explode('.', $realm); - - if (count($arr) == 0) - { - return 'WRONG_DATA'; - } - - foreach ($arr as $part) - { - if (substr($part, 0, 1) == '-' || substr($part, -1, 1) == '-') - { - return 'WRONG_DATA'; - } - - if (!preg_match("@^[a-zA-Z0-9-.]+$@", $part)) - { - return 'WRONG_DATA'; - } - } - - $boundary = array(array(0, 127), array(192, 223), array(224, 239), array(240, 247), array(248, 251), array(252, 253)); - - // Prohibited Characters RFC3454 + RFC3920 - $prohibited = array( - // Table C.1.1 - array(0x0020, 0x0020), // SPACE - // Table C.1.2 - array(0x00A0, 0x00A0), // NO-BREAK SPACE - array(0x1680, 0x1680), // OGHAM SPACE MARK - array(0x2000, 0x2001), // EN QUAD - array(0x2001, 0x2001), // EM QUAD - array(0x2002, 0x2002), // EN SPACE - array(0x2003, 0x2003), // EM SPACE - array(0x2004, 0x2004), // THREE-PER-EM SPACE - array(0x2005, 0x2005), // FOUR-PER-EM SPACE - array(0x2006, 0x2006), // SIX-PER-EM SPACE - array(0x2007, 0x2007), // FIGURE SPACE - array(0x2008, 0x2008), // PUNCTUATION SPACE - array(0x2009, 0x2009), // THIN SPACE - array(0x200A, 0x200A), // HAIR SPACE - array(0x200B, 0x200B), // ZERO WIDTH SPACE - array(0x202F, 0x202F), // NARROW NO-BREAK SPACE - array(0x205F, 0x205F), // MEDIUM MATHEMATICAL SPACE - array(0x3000, 0x3000), // IDEOGRAPHIC SPACE - // Table C.2.1 - array(0x0000, 0x001F), // [CONTROL CHARACTERS] - array(0x007F, 0x007F), // DELETE - // Table C.2.2 - array(0x0080, 0x009F), // [CONTROL CHARACTERS] - array(0x06DD, 0x06DD), // ARABIC END OF AYAH - array(0x070F, 0x070F), // SYRIAC ABBREVIATION MARK - array(0x180E, 0x180E), // MONGOLIAN VOWEL SEPARATOR - array(0x200C, 0x200C), // ZERO WIDTH NON-JOINER - array(0x200D, 0x200D), // ZERO WIDTH JOINER - array(0x2028, 0x2028), // LINE SEPARATOR - array(0x2029, 0x2029), // PARAGRAPH SEPARATOR - array(0x2060, 0x2060), // WORD JOINER - array(0x2061, 0x2061), // FUNCTION APPLICATION - array(0x2062, 0x2062), // INVISIBLE TIMES - array(0x2063, 0x2063), // INVISIBLE SEPARATOR - array(0x206A, 0x206F), // [CONTROL CHARACTERS] - array(0xFEFF, 0xFEFF), // ZERO WIDTH NO-BREAK SPACE - array(0xFFF9, 0xFFFC), // [CONTROL CHARACTERS] - array(0x1D173, 0x1D17A), // [MUSICAL CONTROL CHARACTERS] - // Table C.3 - array(0xE000, 0xF8FF), // [PRIVATE USE, PLANE 0] - array(0xF0000, 0xFFFFD), // [PRIVATE USE, PLANE 15] - array(0x100000, 0x10FFFD), // [PRIVATE USE, PLANE 16] - // Table C.4 - array(0xFDD0, 0xFDEF), // [NONCHARACTER CODE POINTS] - array(0xFFFE, 0xFFFF), // [NONCHARACTER CODE POINTS] - array(0x1FFFE, 0x1FFFF), // [NONCHARACTER CODE POINTS] - array(0x2FFFE, 0x2FFFF), // [NONCHARACTER CODE POINTS] - array(0x3FFFE, 0x3FFFF), // [NONCHARACTER CODE POINTS] - array(0x4FFFE, 0x4FFFF), // [NONCHARACTER CODE POINTS] - array(0x5FFFE, 0x5FFFF), // [NONCHARACTER CODE POINTS] - array(0x6FFFE, 0x6FFFF), // [NONCHARACTER CODE POINTS] - array(0x7FFFE, 0x7FFFF), // [NONCHARACTER CODE POINTS] - array(0x8FFFE, 0x8FFFF), // [NONCHARACTER CODE POINTS] - array(0x9FFFE, 0x9FFFF), // [NONCHARACTER CODE POINTS] - array(0xAFFFE, 0xAFFFF), // [NONCHARACTER CODE POINTS] - array(0xBFFFE, 0xBFFFF), // [NONCHARACTER CODE POINTS] - array(0xCFFFE, 0xCFFFF), // [NONCHARACTER CODE POINTS] - array(0xDFFFE, 0xDFFFF), // [NONCHARACTER CODE POINTS] - array(0xEFFFE, 0xEFFFF), // [NONCHARACTER CODE POINTS] - array(0xFFFFE, 0xFFFFF), // [NONCHARACTER CODE POINTS] - array(0x10FFFE, 0x10FFFF), // [NONCHARACTER CODE POINTS] - // Table C.5 - array(0xD800, 0xDFFF), // [SURROGATE CODES] - // Table C.6 - array(0xFFF9, 0xFFF9), // INTERLINEAR ANNOTATION ANCHOR - array(0xFFFA, 0xFFFA), // INTERLINEAR ANNOTATION SEPARATOR - array(0xFFFB, 0xFFFB), // INTERLINEAR ANNOTATION TERMINATOR - array(0xFFFC, 0xFFFC), // OBJECT REPLACEMENT CHARACTER - array(0xFFFD, 0xFFFD), // REPLACEMENT CHARACTER - // Table C.7 - array(0x2FF0, 0x2FFB), // [IDEOGRAPHIC DESCRIPTION CHARACTERS] - // Table C.8 - array(0x0340, 0x0340), // COMBINING GRAVE TONE MARK - array(0x0341, 0x0341), // COMBINING ACUTE TONE MARK - array(0x200E, 0x200E), // LEFT-TO-RIGHT MARK - array(0x200F, 0x200F), // RIGHT-TO-LEFT MARK - array(0x202A, 0x202A), // LEFT-TO-RIGHT EMBEDDING - array(0x202B, 0x202B), // RIGHT-TO-LEFT EMBEDDING - array(0x202C, 0x202C), // POP DIRECTIONAL FORMATTING - array(0x202D, 0x202D), // LEFT-TO-RIGHT OVERRIDE - array(0x202E, 0x202E), // RIGHT-TO-LEFT OVERRIDE - array(0x206A, 0x206A), // INHIBIT SYMMETRIC SWAPPING - array(0x206B, 0x206B), // ACTIVATE SYMMETRIC SWAPPING - array(0x206C, 0x206C), // INHIBIT ARABIC FORM SHAPING - array(0x206D, 0x206D), // ACTIVATE ARABIC FORM SHAPING - array(0x206E, 0x206E), // NATIONAL DIGIT SHAPES - array(0x206F, 0x206F), // NOMINAL DIGIT SHAPES - // Table C.9 - array(0xE0001, 0xE0001), // LANGUAGE TAG - array(0xE0020, 0xE007F), // [TAGGING CHARACTERS] - // RFC3920 - array(0x22, 0x22), // " - array(0x26, 0x26), // & - array(0x27, 0x27), // ' - array(0x2F, 0x2F), // / - array(0x3A, 0x3A), // : - array(0x3C, 0x3C), // < - array(0x3E, 0x3E), // > - array(0x40, 0x40) // @ - ); - - $pos = 0; - $result = true; - - while ($pos < strlen($username)) - { - $len = $uni = 0; - for ($i = 0; $i <= 5; $i++) - { - if (ord($username[$pos]) >= $boundary[$i][0] && ord($username[$pos]) <= $boundary[$i][1]) - { - $len = $i + 1; - $uni = (ord($username[$pos]) - $boundary[$i][0]) * pow(2, $i * 6); - - for ($k = 1; $k < $len; $k++) - { - $uni += (ord($username[$pos + $k]) - 128) * pow(2, ($i - $k) * 6); - } - - break; - } - } - - if ($len == 0) - { - return 'WRONG_DATA'; - } - - foreach ($prohibited as $pval) - { - if ($uni >= $pval[0] && $uni <= $pval[1]) - { - $result = false; - break 2; - } - } - - $pos = $pos + $len; - } - - if (!$result) - { - return 'WRONG_DATA'; - } - - return false; -} - -/** -* Validate hex colour value -* -* @param string $colour The hex colour value -* @param bool $optional Whether the colour value is optional. True if an empty -* string will be accepted as correct input, false if not. -* @return bool|string Error message if colour value is incorrect, false if it -* fits the hex colour code -*/ -function phpbb_validate_hex_colour($colour, $optional = false) -{ - if ($colour === '') - { - return (($optional) ? false : 'WRONG_DATA'); - } - - if (!preg_match('/^([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/', $colour)) - { - return 'WRONG_DATA'; - } - - return false; -} - -/** -* Verifies whether a style ID corresponds to an active style. -* -* @param int $style_id The style_id of a style which should be checked if activated or not. -* @return boolean -*/ -function phpbb_style_is_active($style_id) -{ - global $db; - - $sql = 'SELECT style_active - FROM ' . STYLES_TABLE . ' - WHERE style_id = '. (int) $style_id; - $result = $db->sql_query($sql); - - $style_is_active = (bool) $db->sql_fetchfield('style_active'); - $db->sql_freeresult($result); - - return $style_is_active; -} - -/** -* Remove avatar -*/ -function avatar_delete($mode, $row, $clean_db = false) -{ - global $phpbb_root_path, $config; - - // Check if the users avatar is actually *not* a group avatar - if ($mode == 'user') - { - if (strpos($row['user_avatar'], 'g') === 0 || (((int) $row['user_avatar'] !== 0) && ((int) $row['user_avatar'] !== (int) $row['user_id']))) - { - return false; - } - } - - if ($clean_db) - { - avatar_remove_db($row[$mode . '_avatar']); - } - $filename = get_avatar_filename($row[$mode . '_avatar']); - - if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . $filename)) - { - @unlink($phpbb_root_path . $config['avatar_path'] . '/' . $filename); - return true; - } - - return false; -} - -/** -* Generates avatar filename from the database entry -*/ -function get_avatar_filename($avatar_entry) -{ - global $config; - - if ($avatar_entry[0] === 'g') - { - $avatar_group = true; - $avatar_entry = substr($avatar_entry, 1); - } - else - { - $avatar_group = false; - } - $ext = substr(strrchr($avatar_entry, '.'), 1); - $avatar_entry = intval($avatar_entry); - return $config['avatar_salt'] . '_' . (($avatar_group) ? 'g' : '') . $avatar_entry . '.' . $ext; -} - -/** -* Returns an explanation string with maximum avatar settings -* -* @return string -*/ -function phpbb_avatar_explanation_string() -{ - global $config, $user; - - return $user->lang(($config['avatar_filesize'] == 0) ? 'AVATAR_EXPLAIN_NO_FILESIZE' : 'AVATAR_EXPLAIN', - $user->lang('PIXELS', (int) $config['avatar_max_width']), - $user->lang('PIXELS', (int) $config['avatar_max_height']), - round($config['avatar_filesize'] / 1024)); -} - -// -// Usergroup functions -// - -/** -* Add or edit a group. If we're editing a group we only update user -* parameters such as rank, etc. if they are changed -*/ -function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false) -{ - global $db, $user, $phpbb_container, $phpbb_log; - - /** @var \phpbb\group\helper $group_helper */ - $group_helper = $phpbb_container->get('group_helper'); - - $error = array(); - - // Attributes which also affect the users table - $user_attribute_ary = array('group_colour', 'group_rank', 'group_avatar', 'group_avatar_type', 'group_avatar_width', 'group_avatar_height'); - - // Check data. Limit group name length. - if (!utf8_strlen($name) || utf8_strlen($name) > 60) - { - $error[] = (!utf8_strlen($name)) ? $user->lang['GROUP_ERR_USERNAME'] : $user->lang['GROUP_ERR_USER_LONG']; - } - - $err = group_validate_groupname($group_id, $name); - if (!empty($err)) - { - $error[] = $user->lang[$err]; - } - - if (!in_array($type, array(GROUP_OPEN, GROUP_CLOSED, GROUP_HIDDEN, GROUP_SPECIAL, GROUP_FREE))) - { - $error[] = $user->lang['GROUP_ERR_TYPE']; - } - - $group_teampage = !empty($group_attributes['group_teampage']); - unset($group_attributes['group_teampage']); - - 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 - { - $current_legend = $legend->get_group_value($group_id); - $current_teampage = $teampage->get_group_value($group_id); - } - catch (\phpbb\groupposition\exception $exception) - { - trigger_error($user->lang($exception->getMessage())); - } - } - - if (!empty($group_attributes['group_legend'])) - { - if (($group_id && ($current_legend == \phpbb\groupposition\legend::GROUP_DISABLED)) || !$group_id) - { - // Old group currently not in the legend or new group, add at the end. - $group_attributes['group_legend'] = 1 + $legend->get_group_count(); - } - else - { - // Group stayes in the legend - $group_attributes['group_legend'] = $current_legend; - } - } - else if ($group_id && ($current_legend != \phpbb\groupposition\legend::GROUP_DISABLED)) - { - // Group is removed from the legend - try - { - $legend->delete_group($group_id, true); - } - catch (\phpbb\groupposition\exception $exception) - { - trigger_error($user->lang($exception->getMessage())); - } - $group_attributes['group_legend'] = \phpbb\groupposition\legend::GROUP_DISABLED; - } - else - { - $group_attributes['group_legend'] = \phpbb\groupposition\legend::GROUP_DISABLED; - } - - // Unset the objects, we don't need them anymore. - unset($legend); - - $user_ary = array(); - $sql_ary = array( - 'group_name' => (string) $name, - 'group_desc' => (string) $desc, - 'group_desc_uid' => '', - 'group_desc_bitfield' => '', - 'group_type' => (int) $type, - ); - - // Parse description - if ($desc) - { - 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 (count($group_attributes)) - { - // Merge them with $sql_ary to properly update the group - $sql_ary = array_merge($sql_ary, $group_attributes); - } - - // Setting the log message before we set the group id (if group gets added) - $log = ($group_id) ? 'LOG_GROUP_UPDATED' : 'LOG_GROUP_CREATED'; - - if ($group_id) - { - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE group_id = ' . $group_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $user_ary[] = $row['user_id']; - } - $db->sql_freeresult($result); - - if (isset($sql_ary['group_avatar'])) - { - remove_default_avatar($group_id, $user_ary); - } - - if (isset($sql_ary['group_rank'])) - { - remove_default_rank($group_id, $user_ary); - } - - $sql = 'UPDATE ' . GROUPS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE group_id = $group_id"; - $db->sql_query($sql); - - // Since we may update the name too, we need to do this on other tables too... - $sql = 'UPDATE ' . MODERATOR_CACHE_TABLE . " - SET group_name = '" . $db->sql_escape($sql_ary['group_name']) . "' - WHERE group_id = $group_id"; - $db->sql_query($sql); - - // One special case is the group skip auth setting. If this was changed we need to purge permissions for this group - if (isset($group_attributes['group_skip_auth'])) - { - // Get users within this group... - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . ' - WHERE group_id = ' . $group_id . ' - AND user_pending = 0'; - $result = $db->sql_query($sql); - - $user_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_id_ary[] = $row['user_id']; - } - $db->sql_freeresult($result); - - if (!empty($user_id_ary)) - { - global $auth; - - // Clear permissions cache of relevant users - $auth->acl_clear_prefetch($user_id_ary); - } - } - } - else - { - $sql = 'INSERT INTO ' . GROUPS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - } - - // Remove the group from the teampage, only if unselected and we are editing a group, - // which is currently displayed. - if (!$group_teampage && $group_id && $current_teampage != \phpbb\groupposition\teampage::GROUP_DISABLED) - { - try - { - $teampage->delete_group($group_id); - } - catch (\phpbb\groupposition\exception $exception) - { - trigger_error($user->lang($exception->getMessage())); - } - } - - if (!$group_id) - { - $group_id = $db->sql_nextid(); - - if (isset($sql_ary['group_avatar_type']) && $sql_ary['group_avatar_type'] == 'avatar.driver.upload') - { - group_correct_avatar($group_id, $sql_ary['group_avatar']); - } - } - - try - { - if ($group_teampage && $current_teampage == \phpbb\groupposition\teampage::GROUP_DISABLED) - { - $teampage->add_group($group_id); - } - - if ($group_teampage) - { - if ($current_teampage == \phpbb\groupposition\teampage::GROUP_DISABLED) - { - $teampage->add_group($group_id); - } - } - else if ($group_id && ($current_teampage != \phpbb\groupposition\teampage::GROUP_DISABLED)) - { - $teampage->delete_group($group_id); - } - } - catch (\phpbb\groupposition\exception $exception) - { - trigger_error($user->lang($exception->getMessage())); - } - unset($teampage); - - // Set user attributes - $sql_ary = array(); - if (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) - { - if (!isset($group_attributes[$attribute])) - { - continue; - } - - // If we are about to set an avatar, we will not overwrite user avatars if no group avatar is set... - if (strpos($attribute, 'group_avatar') === 0 && !$group_attributes[$attribute]) - { - continue; - } - - $sql_ary[$attribute] = $group_attributes[$attribute]; - } - } - - if (count($sql_ary) && count($user_ary)) - { - group_set_user_default($group_id, $user_ary, $sql_ary); - } - - $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 (count($error)) ? $error : false; -} - - -/** -* Changes a group avatar's filename to conform to the naming scheme -*/ -function group_correct_avatar($group_id, $old_entry) -{ - global $config, $db, $phpbb_root_path; - - $group_id = (int) $group_id; - $ext = substr(strrchr($old_entry, '.'), 1); - $old_filename = get_avatar_filename($old_entry); - $new_filename = $config['avatar_salt'] . "_g$group_id.$ext"; - $new_entry = 'g' . $group_id . '_' . substr(time(), -5) . ".$ext"; - - $avatar_path = $phpbb_root_path . $config['avatar_path']; - if (@rename($avatar_path . '/'. $old_filename, $avatar_path . '/' . $new_filename)) - { - $sql = 'UPDATE ' . GROUPS_TABLE . ' - SET group_avatar = \'' . $db->sql_escape($new_entry) . "' - WHERE group_id = $group_id"; - $db->sql_query($sql); - } -} - - -/** -* Remove avatar also for users not having the group as default -*/ -function avatar_remove_db($avatar_name) -{ - global $db; - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_avatar = '', - user_avatar_type = '' - WHERE user_avatar = '" . $db->sql_escape($avatar_name) . '\''; - $db->sql_query($sql); -} - - -/** -* Group Delete -*/ -function group_delete($group_id, $group_name = false) -{ - global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container, $phpbb_log; - - if (!$group_name) - { - $group_name = get_group_name($group_id); - } - - $start = 0; - - do - { - $user_id_ary = $username_ary = array(); - - // Batch query for group members, call group_user_del - $sql = 'SELECT u.user_id, u.username - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . " u - WHERE ug.group_id = $group_id - AND u.user_id = ug.user_id"; - $result = $db->sql_query_limit($sql, 200, $start); - - if ($row = $db->sql_fetchrow($result)) - { - do - { - $user_id_ary[] = $row['user_id']; - $username_ary[] = $row['username']; - - $start++; - } - while ($row = $db->sql_fetchrow($result)); - - group_user_del($group_id, $user_id_ary, $username_ary, $group_name); - } - else - { - $start = 0; - } - $db->sql_freeresult($result); - } - while ($start); - - // 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); - } - catch (\phpbb\groupposition\exception $exception) - { - // The group we want to delete does not exist. - // No reason to worry, we just continue the deleting process. - //trigger_error($user->lang($exception->getMessage())); - } - - try - { - /* @var $teampage \phpbb\groupposition\teampage */ - $teampage = $phpbb_container->get('groupposition.teampage'); - $teampage->delete_group($group_id); - unset($teampage); - } - catch (\phpbb\groupposition\exception $exception) - { - // The group we want to delete does not exist. - // No reason to worry, we just continue the deleting process. - //trigger_error($user->lang($exception->getMessage())); - } - - // Delete group - $sql = 'DELETE FROM ' . GROUPS_TABLE . " - WHERE group_id = $group_id"; - $db->sql_query($sql); - - // Delete auth entries from the groups table - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " - WHERE group_id = $group_id"; - $db->sql_query($sql); - - /** - * Event after a group is deleted - * - * @event core.delete_group_after - * @var int group_id ID of the deleted group - * @var string group_name Name of the deleted group - * @since 3.1.0-a1 - */ - $vars = array('group_id', 'group_name'); - extract($phpbb_dispatcher->trigger_event('core.delete_group_after', compact($vars))); - - // Re-cache moderators - if (!function_exists('phpbb_cache_moderators')) - { - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - - phpbb_cache_moderators($db, $cache, $auth); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_GROUP_DELETE', false, array($group_name)); - - // Return false - no error - return false; -} - -/** -* Add user(s) to group -* -* @return mixed false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER' -*/ -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, $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 (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 . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary) . " - AND group_id = $group_id"; - $result = $db->sql_query($sql); - - $add_id_ary = $update_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $add_id_ary[] = (int) $row['user_id']; - - if ($leader && !$row['group_leader']) - { - $update_id_ary[] = (int) $row['user_id']; - } - } - $db->sql_freeresult($result); - - // Do all the users exist in this group? - $add_id_ary = array_diff($user_id_ary, $add_id_ary); - - // If we have no users - if (!count($add_id_ary) && !count($update_id_ary)) - { - return 'GROUP_USERS_EXIST'; - } - - $db->sql_transaction('begin'); - - // Insert the new users - if (count($add_id_ary)) - { - $sql_ary = array(); - - foreach ($add_id_ary as $user_id) - { - $sql_ary[] = array( - 'user_id' => (int) $user_id, - 'group_id' => (int) $group_id, - 'group_leader' => (int) $leader, - 'user_pending' => (int) $pending, - ); - } - - $db->sql_multi_insert(USER_GROUP_TABLE, $sql_ary); - } - - if (count($update_id_ary)) - { - $sql = 'UPDATE ' . USER_GROUP_TABLE . ' - SET group_leader = 1 - WHERE ' . $db->sql_in_set('user_id', $update_id_ary) . " - AND group_id = $group_id"; - $db->sql_query($sql); - } - - if ($default) - { - group_user_attributes('default', $group_id, $user_id_ary, false, $group_name, $group_attributes); - } - - $db->sql_transaction('commit'); - - // Clear permissions cache of relevant users - $auth->acl_clear_prefetch($user_id_ary); - - /** - * Event after users are added to a group - * - * @event core.group_add_user_after - * @var int group_id ID of the group to which users are added - * @var string group_name Name of the group - * @var array user_id_ary IDs of the users which are added - * @var array username_ary names of the users which are added - * @var int pending Pending setting, 1 if user(s) added are pending - * @since 3.1.7-RC1 - */ - $vars = array( - 'group_id', - 'group_name', - 'user_id_ary', - 'username_ary', - 'pending', - ); - extract($phpbb_dispatcher->trigger_event('core.group_add_user_after', compact($vars))); - - if (!$group_name) - { - $group_name = get_group_name($group_id); - } - - $log = ($leader) ? 'LOG_MODS_ADDED' : (($pending) ? 'LOG_USERS_PENDING' : 'LOG_USERS_ADDED'); - - $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) - { - $phpbb_notifications->add_notifications('notification.type.group_request', array( - 'group_id' => $group_id, - 'user_id' => $user_id, - 'group_name' => $group_name, - )); - } - } - - // Return false - no error - return false; -} - -/** -* Remove a user/s from a given group. When we remove users we update their -* default group_id. We do this by examining which "special" groups they belong -* to. The selection is made based on a reasonable priority system -* -* @return false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER' -*/ -function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $log_action = true) -{ - global $db, $auth, $config, $user, $phpbb_dispatcher, $phpbb_container, $phpbb_log; - - if ($config['coppa_enable']) - { - $group_order = array('ADMINISTRATORS', 'GLOBAL_MODERATORS', 'NEWLY_REGISTERED', 'REGISTERED_COPPA', 'REGISTERED', 'BOTS', 'GUESTS'); - } - else - { - $group_order = array('ADMINISTRATORS', 'GLOBAL_MODERATORS', 'NEWLY_REGISTERED', 'REGISTERED', 'BOTS', 'GUESTS'); - } - - // We need both username and user_id info - $result = user_get_id_name($user_id_ary, $username_ary); - - if (empty($user_id_ary) || $result !== false) - { - return 'NO_USER'; - } - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE ' . $db->sql_in_set('group_name', $group_order); - $result = $db->sql_query($sql); - - $group_order_id = $special_group_data = array(); - while ($row = $db->sql_fetchrow($result)) - { - $group_order_id[$row['group_name']] = $row['group_id']; - - $special_group_data[$row['group_id']] = array( - 'group_colour' => $row['group_colour'], - 'group_rank' => $row['group_rank'], - ); - - // Only set the group avatar if one is defined... - if ($row['group_avatar']) - { - $special_group_data[$row['group_id']] = array_merge($special_group_data[$row['group_id']], array( - 'group_avatar' => $row['group_avatar'], - 'group_avatar_type' => $row['group_avatar_type'], - 'group_avatar_width' => $row['group_avatar_width'], - 'group_avatar_height' => $row['group_avatar_height']) - ); - } - } - $db->sql_freeresult($result); - - // Get users default groups - we only need to reset default group membership if the group from which the user gets removed is set as default - $sql = 'SELECT user_id, group_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary); - $result = $db->sql_query($sql); - - $default_groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - $default_groups[$row['user_id']] = $row['group_id']; - } - $db->sql_freeresult($result); - - // What special group memberships exist for these users? - $sql = 'SELECT g.group_id, g.group_name, ug.user_id - FROM ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g - WHERE ' . $db->sql_in_set('ug.user_id', $user_id_ary) . " - AND g.group_id = ug.group_id - AND g.group_id <> $group_id - AND g.group_type = " . GROUP_SPECIAL . ' - ORDER BY ug.user_id, g.group_id'; - $result = $db->sql_query($sql); - - $temp_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($default_groups[$row['user_id']] == $group_id && (!isset($temp_ary[$row['user_id']]) || $group_order_id[$row['group_name']] < $temp_ary[$row['user_id']])) - { - $temp_ary[$row['user_id']] = $row['group_id']; - } - } - $db->sql_freeresult($result); - - // sql_where_ary holds the new default groups and their users - $sql_where_ary = array(); - foreach ($temp_ary as $uid => $gid) - { - $sql_where_ary[$gid][] = $uid; - } - unset($temp_ary); - - foreach ($special_group_data as $gid => $default_data_ary) - { - 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]); - group_set_user_default($gid, $sql_where_ary[$gid], $default_data_ary); - } - } - unset($special_group_data); - - /** - * Event before users are removed from a group - * - * @event core.group_delete_user_before - * @var int group_id ID of the group from which users are deleted - * @var string group_name Name of the group - * @var array user_id_ary IDs of the users which are removed - * @var array username_ary names of the users which are removed - * @since 3.1.0-a1 - */ - $vars = array('group_id', 'group_name', 'user_id_ary', 'username_ary'); - extract($phpbb_dispatcher->trigger_event('core.group_delete_user_before', compact($vars))); - - $sql = 'DELETE FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - AND " . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - - // Clear permissions cache of relevant users - $auth->acl_clear_prefetch($user_id_ary); - - /** - * Event after users are removed from a group - * - * @event core.group_delete_user_after - * @var int group_id ID of the group from which users are deleted - * @var string group_name Name of the group - * @var array user_id_ary IDs of the users which are removed - * @var array username_ary names of the users which are removed - * @since 3.1.7-RC1 - */ - $vars = array('group_id', 'group_name', 'user_id_ary', 'username_ary'); - extract($phpbb_dispatcher->trigger_event('core.group_delete_user_after', compact($vars))); - - if ($log_action) - { - if (!$group_name) - { - $group_name = get_group_name($group_id); - } - - $log = 'LOG_GROUP_REMOVE'; - - if ($group_name) - { - $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); - - // Return false - no error - return false; -} - - -/** -* Removes the group avatar of the default group from the users in user_ids who have that group as default. -*/ -function remove_default_avatar($group_id, $user_ids) -{ - global $db; - - if (!is_array($user_ids)) - { - $user_ids = array($user_ids); - } - if (empty($user_ids)) - { - return false; - } - - $user_ids = array_map('intval', $user_ids); - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - if (!$row = $db->sql_fetchrow($result)) - { - $db->sql_freeresult($result); - return false; - } - $db->sql_freeresult($result); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_avatar = '', - user_avatar_type = '', - user_avatar_width = 0, - user_avatar_height = 0 - WHERE group_id = " . (int) $group_id . " - AND user_avatar = '" . $db->sql_escape($row['group_avatar']) . "' - AND " . $db->sql_in_set('user_id', $user_ids); - - $db->sql_query($sql); -} - -/** -* Removes the group rank of the default group from the users in user_ids who have that group as default. -*/ -function remove_default_rank($group_id, $user_ids) -{ - global $db; - - if (!is_array($user_ids)) - { - $user_ids = array($user_ids); - } - if (empty($user_ids)) - { - return false; - } - - $user_ids = array_map('intval', $user_ids); - - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - if (!$row = $db->sql_fetchrow($result)) - { - $db->sql_freeresult($result); - return false; - } - $db->sql_freeresult($result); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_rank = 0 - WHERE group_id = ' . (int) $group_id . ' - AND user_rank <> 0 - AND user_rank = ' . (int) $row['group_rank'] . ' - AND ' . $db->sql_in_set('user_id', $user_ids); - $db->sql_query($sql); -} - -/** -* This is used to promote (to leader), demote or set as default a member/s -*/ -function group_user_attributes($action, $group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $group_attributes = false) -{ - 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 (empty($user_id_ary) || $result !== false) - { - return 'NO_USERS'; - } - - if (!$group_name) - { - $group_name = get_group_name($group_id); - } - - switch ($action) - { - case 'demote': - case 'promote': - - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - AND user_pending = 1 - AND " . $db->sql_in_set('user_id', $user_id_ary); - $result = $db->sql_query_limit($sql, 1); - $not_empty = ($db->sql_fetchrow($result)); - $db->sql_freeresult($result); - if ($not_empty) - { - return 'NO_VALID_USERS'; - } - - $sql = 'UPDATE ' . USER_GROUP_TABLE . ' - SET group_leader = ' . (($action == 'promote') ? 1 : 0) . " - WHERE group_id = $group_id - AND user_pending = 0 - AND " . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - - $log = ($action == 'promote') ? 'LOG_GROUP_PROMOTED' : 'LOG_GROUP_DEMOTED'; - break; - - case 'approve': - // Make sure we only approve those which are pending ;) - $sql = 'SELECT u.user_id, u.user_email, u.username, u.username_clean, u.user_notify_type, u.user_jabber, u.user_lang - FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug - WHERE ug.group_id = ' . $group_id . ' - AND ug.user_pending = 1 - AND ug.user_id = u.user_id - AND ' . $db->sql_in_set('ug.user_id', $user_id_ary); - $result = $db->sql_query($sql); - - $user_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_id_ary[] = $row['user_id']; - } - $db->sql_freeresult($result); - - if (!count($user_id_ary)) - { - return false; - } - - $sql = 'UPDATE ' . USER_GROUP_TABLE . " - SET user_pending = 0 - WHERE group_id = $group_id - 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( - 'user_ids' => $user_id_ary, - 'group_id' => $group_id, - 'group_name' => $group_name, - )); - $phpbb_notifications->delete_notifications('notification.type.group_request', $user_id_ary, $group_id); - - $log = 'LOG_USERS_APPROVED'; - break; - - case 'default': - // We only set default group for approved members of the group - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - AND user_pending = 0 - AND " . $db->sql_in_set('user_id', $user_id_ary); - $result = $db->sql_query($sql); - - $user_id_ary = $username_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_id_ary[] = $row['user_id']; - } - $db->sql_freeresult($result); - - $result = user_get_id_name($user_id_ary, $username_ary); - if (!count($user_id_ary) || $result !== false) - { - return 'NO_USERS'; - } - - $sql = 'SELECT user_id, group_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary, false, true); - $result = $db->sql_query($sql); - - $groups = array(); - while ($row = $db->sql_fetchrow($result)) - { - if (!isset($groups[$row['group_id']])) - { - $groups[$row['group_id']] = array(); - } - $groups[$row['group_id']][] = $row['user_id']; - } - $db->sql_freeresult($result); - - foreach ($groups as $gid => $uids) - { - remove_default_rank($gid, $uids); - remove_default_avatar($gid, $uids); - } - group_set_user_default($group_id, $user_id_ary, $group_attributes); - $log = 'LOG_GROUP_DEFAULTS'; - break; - } - - /** - * Event to perform additional actions on setting user group attributes - * - * @event core.user_set_group_attributes - * @var int group_id ID of the group - * @var string group_name Name of the group - * @var array user_id_ary IDs of the users to set group attributes - * @var array username_ary Names of the users to set group attributes - * @var array group_attributes Group attributes which were changed - * @var string action Action to perform over the group members - * @since 3.1.10-RC1 - */ - $vars = array( - 'group_id', - 'group_name', - 'user_id_ary', - 'username_ary', - 'group_attributes', - 'action', - ); - extract($phpbb_dispatcher->trigger_event('core.user_set_group_attributes', compact($vars))); - - // Clear permissions cache of relevant users - $auth->acl_clear_prefetch($user_id_ary); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log, false, array($group_name, implode(', ', $username_ary))); - - group_update_listings($group_id); - - return false; -} - -/** -* A small version of validate_username to check for a group name's existence. To be called directly. -*/ -function group_validate_groupname($group_id, $group_name) -{ - global $db; - - $group_name = utf8_clean_string($group_name); - - if (!empty($group_id)) - { - $sql = 'SELECT group_name - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - return false; - } - - $allowed_groupname = utf8_clean_string($row['group_name']); - - if ($allowed_groupname == $group_name) - { - return false; - } - } - - $sql = 'SELECT group_name - FROM ' . GROUPS_TABLE . " - WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($group_name)) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return 'GROUP_NAME_TAKEN'; - } - - return false; -} - -/** -* Set users default group -* -* @access private -*/ -function group_set_user_default($group_id, $user_id_ary, $group_attributes = false, $update_listing = false) -{ - global $config, $phpbb_container, $db, $phpbb_dispatcher; - - if (empty($user_id_ary)) - { - return; - } - - $attribute_ary = array( - 'group_colour' => 'string', - 'group_rank' => 'int', - 'group_avatar' => 'string', - 'group_avatar_type' => 'string', - 'group_avatar_width' => 'int', - 'group_avatar_height' => 'int', - ); - - $sql_ary = array( - 'group_id' => $group_id - ); - - // Were group attributes passed to the function? If not we need to obtain them - if ($group_attributes === false) - { - $sql = 'SELECT ' . implode(', ', array_keys($attribute_ary)) . ' - FROM ' . GROUPS_TABLE . " - WHERE group_id = $group_id"; - $result = $db->sql_query($sql); - $group_attributes = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - foreach ($attribute_ary as $attribute => $type) - { - if (isset($group_attributes[$attribute])) - { - // If we are about to set an avatar or rank, we will not overwrite with empty, unless we are not actually changing the default group - if ((strpos($attribute, 'group_avatar') === 0 || strpos($attribute, 'group_rank') === 0) && !$group_attributes[$attribute]) - { - continue; - } - - settype($group_attributes[$attribute], $type); - $sql_ary[str_replace('group_', 'user_', $attribute)] = $group_attributes[$attribute]; - } - } - - $updated_sql_ary = $sql_ary; - - // Before we update the user attributes, we will update the rank for users that don't have a custom rank - if (isset($sql_ary['user_rank'])) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', array('user_rank' => $sql_ary['user_rank'])) . ' - WHERE user_rank = 0 - AND ' . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - unset($sql_ary['user_rank']); - } - - // Before we update the user attributes, we will update the avatar for users that don't have a custom avatar - $avatar_options = array('user_avatar', 'user_avatar_type', 'user_avatar_height', 'user_avatar_width'); - - if (isset($sql_ary['user_avatar'])) - { - $avatar_sql_ary = array(); - foreach ($avatar_options as $avatar_option) - { - if (isset($sql_ary[$avatar_option])) - { - $avatar_sql_ary[$avatar_option] = $sql_ary[$avatar_option]; - } - } - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $avatar_sql_ary) . " - WHERE user_avatar = '' - AND " . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - } - - // Remove the avatar options, as we already updated them - foreach ($avatar_options as $avatar_option) - { - unset($sql_ary[$avatar_option]); - } - - if (!empty($sql_ary)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); - } - - if (isset($sql_ary['user_colour'])) - { - // Update any cached colour information for these users - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' - WHERE " . $db->sql_in_set('forum_last_poster_id', $user_id_ary); - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' - WHERE " . $db->sql_in_set('topic_poster', $user_id_ary); - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' - WHERE " . $db->sql_in_set('topic_last_poster_id', $user_id_ary); - $db->sql_query($sql); - - if (in_array($config['newest_user_id'], $user_id_ary)) - { - $config->set('newest_user_colour', $sql_ary['user_colour'], false); - } - } - - // Make all values available for the event - $sql_ary = $updated_sql_ary; - - /** - * Event when the default group is set for an array of users - * - * @event core.user_set_default_group - * @var int group_id ID of the group - * @var array user_id_ary IDs of the users - * @var array group_attributes Group attributes which were changed - * @var array update_listing Update the list of moderators and foes - * @var array sql_ary User attributes which were changed - * @since 3.1.0-a1 - */ - $vars = array('group_id', 'user_id_ary', 'group_attributes', 'update_listing', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.user_set_default_group', compact($vars))); - - if ($update_listing) - { - group_update_listings($group_id); - } - - // Because some tables/caches use usercolour-specific data we need to purge this here. - $phpbb_container->get('cache.driver')->destroy('sql', MODERATOR_CACHE_TABLE); -} - -/** -* Get group name -*/ -function get_group_name($group_id) -{ - global $db, $phpbb_container; - - $sql = 'SELECT group_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int) $group_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - return ''; - } - - /** @var \phpbb\group\helper $group_helper */ - $group_helper = $phpbb_container->get('group_helper'); - - return $group_helper->get_name($row['group_name']); -} - -/** -* Obtain either the members of a specified group, the groups the specified user is subscribed to -* or checking if a specified user is in a specified group. This function does not return pending memberships. -* -* Note: Never use this more than once... first group your users/groups -*/ -function group_memberships($group_id_ary = false, $user_id_ary = false, $return_bool = false) -{ - global $db; - - if (!$group_id_ary && !$user_id_ary) - { - return true; - } - - if ($user_id_ary) - { - $user_id_ary = (!is_array($user_id_ary)) ? array($user_id_ary) : $user_id_ary; - } - - if ($group_id_ary) - { - $group_id_ary = (!is_array($group_id_ary)) ? array($group_id_ary) : $group_id_ary; - } - - $sql = 'SELECT ug.*, u.username, u.username_clean, u.user_email - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u - WHERE ug.user_id = u.user_id - AND ug.user_pending = 0 AND '; - - if ($group_id_ary) - { - $sql .= ' ' . $db->sql_in_set('ug.group_id', $group_id_ary); - } - - if ($user_id_ary) - { - $sql .= ($group_id_ary) ? ' AND ' : ' '; - $sql .= $db->sql_in_set('ug.user_id', $user_id_ary); - } - - $result = ($return_bool) ? $db->sql_query_limit($sql, 1) : $db->sql_query($sql); - - $row = $db->sql_fetchrow($result); - - if ($return_bool) - { - $db->sql_freeresult($result); - return ($row) ? true : false; - } - - if (!$row) - { - return false; - } - - $return = array(); - - do - { - $return[] = $row; - } - while ($row = $db->sql_fetchrow($result)); - - $db->sql_freeresult($result); - - return $return; -} - -/** -* Re-cache moderators and foes if group has a_ or m_ permissions -*/ -function group_update_listings($group_id) -{ - global $db, $cache, $auth; - - $hold_ary = $auth->acl_group_raw_data($group_id, array('a_', 'm_')); - - if (empty($hold_ary)) - { - return; - } - - $mod_permissions = $admin_permissions = false; - - foreach ($hold_ary as $g_id => $forum_ary) - { - foreach ($forum_ary as $forum_id => $auth_ary) - { - foreach ($auth_ary as $auth_option => $setting) - { - if ($mod_permissions && $admin_permissions) - { - break 3; - } - - if ($setting != ACL_YES) - { - continue; - } - - if ($auth_option == 'm_') - { - $mod_permissions = true; - } - - if ($auth_option == 'a_') - { - $admin_permissions = true; - } - } - } - } - - if ($mod_permissions) - { - if (!function_exists('phpbb_cache_moderators')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - phpbb_cache_moderators($db, $cache, $auth); - } - - if ($mod_permissions || $admin_permissions) - { - if (!function_exists('phpbb_update_foes')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - phpbb_update_foes($db, $auth, array($group_id)); - } -} - - - -/** -* Funtion to make a user leave the NEWLY_REGISTERED system group. -* @access public -* @param $user_id The id of the user to remove from the group -*/ -function remove_newly_registered($user_id, $user_data = false) -{ - global $db; - - if ($user_data === false) - { - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - return false; - } - else - { - $user_data = $user_row; - } - } - - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = 'NEWLY_REGISTERED' - AND group_type = " . GROUP_SPECIAL; - $result = $db->sql_query($sql); - $group_id = (int) $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - - if (!$group_id) - { - return false; - } - - // We need to call group_user_del here, because this function makes sure everything is correctly changed. - // Force function to not log the removal of users from newly registered users group - group_user_del($group_id, $user_id, false, false, false); - - // Set user_new to 0 to let this not be triggered again - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_new = 0 - WHERE user_id = ' . $user_id; - $db->sql_query($sql); - - // The new users group was the users default group? - if ($user_data['group_id'] == $group_id) - { - // Which group is now the users default one? - $sql = 'SELECT group_id - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - $user_data['group_id'] = $db->sql_fetchfield('group_id'); - $db->sql_freeresult($result); - } - - return $user_data['group_id']; -} - -/** -* Gets user ids of currently banned registered users. -* -* @param array $user_ids Array of users' ids to check for banning, -* leave empty to get complete list of banned ids -* @param bool|int $ban_end Bool True to get users currently banned -* Bool False to only get permanently banned users -* Int Unix timestamp to get users banned until that time -* @return array Array of banned users' ids if any, empty array otherwise -*/ -function phpbb_get_banned_user_ids($user_ids = array(), $ban_end = true) -{ - global $db; - - $sql_user_ids = (!empty($user_ids)) ? $db->sql_in_set('ban_userid', $user_ids) : 'ban_userid <> 0'; - - // Get banned User ID's - // Ignore stale bans which were not wiped yet - $banned_ids_list = array(); - $sql = 'SELECT ban_userid - FROM ' . BANLIST_TABLE . " - WHERE $sql_user_ids - AND ban_exclude <> 1"; - - if ($ban_end === true) - { - // Banned currently - $sql .= " AND (ban_end > " . time() . ' - OR ban_end = 0)'; - } - else if ($ban_end === false) - { - // Permanently banned - $sql .= " AND ban_end = 0"; - } - else - { - // Banned until a specified time - $sql .= " AND (ban_end > " . (int) $ban_end . ' - OR ban_end = 0)'; - } - - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $user_id = (int) $row['ban_userid']; - $banned_ids_list[$user_id] = $user_id; - } - $db->sql_freeresult($result); - - return $banned_ids_list; -} - -/** -* Function for assigning a template var if the zebra module got included -*/ -function phpbb_module_zebra($mode, &$module_row) -{ - global $template; - - $template->assign_var('S_ZEBRA_ENABLED', true); - - if ($mode == 'friends') - { - $template->assign_var('S_ZEBRA_FRIENDS_ENABLED', true); - } - - if ($mode == 'foes') - { - $template->assign_var('S_ZEBRA_FOES_ENABLED', true); - } -} diff --git a/install/update/old/includes/mcp/mcp_ban.php b/install/update/old/includes/mcp/mcp_ban.php deleted file mode 100644 index 8797f06..0000000 --- a/install/update/old/includes/mcp/mcp_ban.php +++ /dev/null @@ -1,301 +0,0 @@ - -* @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 mcp_ban -{ - var $u_action; - - function main($id, $mode) - { - global $db, $user, $auth, $template, $request, $phpbb_dispatcher; - global $phpbb_root_path, $phpEx; - - if (!function_exists('user_ban')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - // Include the admin banning interface... - 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'); - - $user->add_lang(array('acp/ban', 'acp/users')); - $this->tpl_name = 'mcp_ban'; - - /** - * Use this event to pass perform actions when a ban is issued or revoked - * - * @event core.mcp_ban_main - * @var bool bansubmit True if a ban is issued - * @var bool unbansubmit True if a ban is removed - * @var string mode Mode of the ban that is being worked on - * @since 3.1.0-RC5 - */ - $vars = array( - 'bansubmit', - 'unbansubmit', - 'mode', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_ban_main', compact($vars))); - - // Ban submitted? - if ($bansubmit) - { - // Grab the list of entries - $ban = $request->variable('ban', '', $mode === 'user'); - $ban_length = $request->variable('banlength', 0); - $ban_length_other = $request->variable('banlengthother', ''); - $ban_exclude = $request->variable('banexclude', 0); - $ban_reason = $request->variable('banreason', '', true); - $ban_give_reason = $request->variable('bangivereason', '', true); - - if ($ban) - { - if (confirm_box(true)) - { - $abort_ban = false; - /** - * Use this event to modify the ban details before the ban is performed - * - * @event core.mcp_ban_before - * @var string mode One of the following: user, ip, email - * @var string ban Either string or array with usernames, ips or email addresses - * @var int ban_length Ban length in minutes - * @var string ban_length_other Ban length as a date (YYYY-MM-DD) - * @var bool ban_exclude Are we banning or excluding from another ban - * @var string ban_reason Ban reason displayed to moderators - * @var string ban_give_reason Ban reason displayed to the banned user - * @var mixed abort_ban Either false, or an error message that is displayed to the user. - * If a string is given the bans are not issued. - * @since 3.1.0-RC5 - */ - $vars = array( - 'mode', - 'ban', - 'ban_length', - 'ban_length_other', - 'ban_exclude', - 'ban_reason', - 'ban_give_reason', - 'abort_ban', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_ban_before', compact($vars))); - - if ($abort_ban) - { - trigger_error($abort_ban); - } - user_ban($mode, $ban, $ban_length, $ban_length_other, $ban_exclude, $ban_reason, $ban_give_reason); - - /** - * Use this event to perform actions after the ban has been performed - * - * @event core.mcp_ban_after - * @var string mode One of the following: user, ip, email - * @var string ban Either string or array with usernames, ips or email addresses - * @var int ban_length Ban length in minutes - * @var string ban_length_other Ban length as a date (YYYY-MM-DD) - * @var bool ban_exclude Are we banning or excluding from another ban - * @var string ban_reason Ban reason displayed to moderators - * @var string ban_give_reason Ban reason displayed to the banned user - * @since 3.1.0-RC5 - */ - $vars = array( - 'mode', - 'ban', - 'ban_length', - 'ban_length_other', - 'ban_exclude', - 'ban_reason', - 'ban_give_reason', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_ban_after', compact($vars))); - - trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . '

« ' . $user->lang['BACK_TO_PREV'] . ''); - } - else - { - $hidden_fields = array( - 'mode' => $mode, - 'ban' => $ban, - 'bansubmit' => true, - 'banlength' => $ban_length, - 'banlengthother' => $ban_length_other, - 'banexclude' => $ban_exclude, - 'banreason' => $ban_reason, - 'bangivereason' => $ban_give_reason, - ); - - /** - * Use this event to pass data from the ban form to the confirmation screen - * - * @event core.mcp_ban_confirm - * @var array hidden_fields Hidden fields that are passed through the confirm screen - * @since 3.1.0-RC5 - */ - $vars = array('hidden_fields'); - extract($phpbb_dispatcher->trigger_event('core.mcp_ban_confirm', compact($vars))); - - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($hidden_fields)); - } - } - } - else if ($unbansubmit) - { - $ban = $request->variable('unban', array('')); - - if ($ban) - { - if (confirm_box(true)) - { - user_unban($mode, $ban); - - trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . '

« ' . $user->lang['BACK_TO_PREV'] . ''); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'mode' => $mode, - 'unbansubmit' => true, - 'unban' => $ban))); - } - } - } - - // Ban length options - $ban_end_text = array(0 => $user->lang['PERMANENT'], 30 => $user->lang['30_MINS'], 60 => $user->lang['1_HOUR'], 360 => $user->lang['6_HOURS'], 1440 => $user->lang['1_DAY'], 10080 => $user->lang['7_DAYS'], 20160 => $user->lang['2_WEEKS'], 40320 => $user->lang['1_MONTH'], -1 => $user->lang['UNTIL'] . ' -> '); - - $ban_end_options = ''; - foreach ($ban_end_text as $length => $text) - { - $ban_end_options .= ''; - } - - // Define language vars - $this->page_title = $user->lang[strtoupper($mode) . '_BAN']; - - $l_ban_explain = $user->lang[strtoupper($mode) . '_BAN_EXPLAIN']; - $l_ban_exclude_explain = $user->lang[strtoupper($mode) . '_BAN_EXCLUDE_EXPLAIN']; - $l_unban_title = $user->lang[strtoupper($mode) . '_UNBAN']; - $l_unban_explain = $user->lang[strtoupper($mode) . '_UNBAN_EXPLAIN']; - $l_no_ban_cell = $user->lang[strtoupper($mode) . '_NO_BANNED']; - - switch ($mode) - { - case 'user': - $l_ban_cell = $user->lang['USERNAME']; - break; - - case 'ip': - $l_ban_cell = $user->lang['IP_HOSTNAME']; - break; - - case 'email': - $l_ban_cell = $user->lang['EMAIL_ADDRESS']; - break; - } - - acp_ban::display_ban_options($mode); - - $template->assign_vars(array( - 'L_TITLE' => $this->page_title, - 'L_EXPLAIN' => $l_ban_explain, - 'L_UNBAN_TITLE' => $l_unban_title, - 'L_UNBAN_EXPLAIN' => $l_unban_explain, - 'L_BAN_CELL' => $l_ban_cell, - 'L_BAN_EXCLUDE_EXPLAIN' => $l_ban_exclude_explain, - 'L_NO_BAN_CELL' => $l_no_ban_cell, - - 'S_USERNAME_BAN' => ($mode == 'user') ? true : false, - - 'U_ACTION' => $this->u_action, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=mcp_ban&field=ban'), - )); - - if ($mode === 'email' && !$auth->acl_get('a_user')) - { - return; - } - - // As a "service" we will check if any post id is specified and populate the username of the poster id if given - $post_id = $request->variable('p', 0); - $user_id = $request->variable('u', 0); - $pre_fill = false; - - if ($user_id && $user_id <> ANONYMOUS) - { - $sql = 'SELECT username, user_email, user_ip - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - switch ($mode) - { - case 'user': - $pre_fill = (string) $db->sql_fetchfield('username'); - break; - - case 'ip': - $pre_fill = (string) $db->sql_fetchfield('user_ip'); - break; - - case 'email': - $pre_fill = (string) $db->sql_fetchfield('user_email'); - break; - } - $db->sql_freeresult($result); - } - else if ($post_id) - { - $post_info = phpbb_get_post_data($post_id, 'm_ban'); - - if (count($post_info) && !empty($post_info[$post_id])) - { - switch ($mode) - { - case 'user': - $pre_fill = $post_info[$post_id]['username']; - break; - - case 'ip': - $pre_fill = $post_info[$post_id]['poster_ip']; - break; - - case 'email': - $pre_fill = $post_info[$post_id]['user_email']; - break; - } - - } - } - - if ($pre_fill) - { - // left for legacy template compatibility - $template->assign_var('USERNAMES', $pre_fill); - $template->assign_var('BAN_QUANTIFIER', $pre_fill); - } - } -} diff --git a/install/update/old/includes/mcp/mcp_logs.php b/install/update/old/includes/mcp/mcp_logs.php deleted file mode 100644 index 79f9d35..0000000 --- a/install/update/old/includes/mcp/mcp_logs.php +++ /dev/null @@ -1,230 +0,0 @@ - -* @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; -} - -/** -* mcp_logs -* Handling warning the users -*/ -class mcp_logs -{ - var $u_action; - var $p_master; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $auth, $db, $user, $template, $request; - global $config, $phpbb_container, $phpbb_log; - - $user->add_lang('acp/common'); - - $action = $request->variable('action', array('' => '')); - - if (is_array($action)) - { - list($action, ) = each($action); - } - else - { - $action = $request->variable('action', ''); - } - - // Set up general vars - $start = $request->variable('start', 0); - $deletemark = ($action == 'del_marked') ? true : false; - $deleteall = ($action == 'del_all') ? true : false; - $marked = $request->variable('mark', array(0)); - - // Sort keys - $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_'))); - $forum_list[] = 0; - - $forum_id = $topic_id = 0; - - switch ($mode) - { - case 'front': - break; - - case 'forum_logs': - $forum_id = $request->variable('f', 0); - - if (!in_array($forum_id, $forum_list)) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } - - $forum_list = array($forum_id); - break; - - case 'topic_logs': - $topic_id = $request->variable('t', 0); - - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $forum_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - if (!in_array($forum_id, $forum_list)) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } - - $forum_list = array($forum_id); - break; - } - - // Delete entries if requested and able - if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs')) - { - if (confirm_box(true)) - { - if ($deletemark && count($marked)) - { - $conditions = array( - 'forum_id' => array('IN' => $forum_list), - 'log_id' => array('IN' => $marked), - ); - - $phpbb_log->delete('mod', $conditions); - } - else if ($deleteall) - { - $keywords = $request->variable('keywords', '', true); - - $conditions = array( - 'forum_id' => array('IN' => $forum_list), - 'keywords' => $keywords, - ); - - if ($sort_days) - { - $conditions['log_time'] = array('>=', time() - ($sort_days * 86400)); - } - - if ($mode == 'topic_logs') - { - $conditions['topic_id'] = $topic_id; - } - - $phpbb_log->delete('mod', $conditions); - } - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'f' => $forum_id, - 't' => $topic_id, - 'start' => $start, - 'delmarked' => $deletemark, - 'delall' => $deleteall, - 'mark' => $marked, - 'st' => $sort_days, - 'sk' => $sort_key, - 'sd' => $sort_dir, - 'i' => $id, - 'mode' => $mode, - 'action' => $request->variable('action', array('' => '')))) - ); - } - } - - // Sorting - $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_text = array('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'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - - // Define where and sort sql for use in displaying logs - $sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0; - $sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); - - $keywords = $request->variable('keywords', '', true); - $keywords_param = !empty($keywords) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; - - // Grab log data - $log_data = array(); - $log_count = 0; - $start = view_log('mod', $log_data, $log_count, $config['topics_per_page'], $start, $forum_list, $topic_id, 0, $sql_where, $sql_sort, $keywords); - - $base_url = $this->u_action . "&$u_sort_param$keywords_param"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'TOTAL' => $user->lang('TOTAL_LOGS', (int) $log_count), - - 'L_TITLE' => $user->lang['MCP_LOGS'], - - 'U_POST_ACTION' => $this->u_action . "&$u_sort_param$keywords_param&start=$start", - 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_LOGS' => ($log_count > 0), - 'S_KEYWORDS' => $keywords, - ) - ); - - foreach ($log_data as $row) - { - $data = array(); - - $checks = array('viewpost', 'viewtopic', 'viewforum'); - foreach ($checks as $check) - { - if (isset($row[$check]) && $row[$check]) - { - $data[] = '' . $user->lang['LOGVIEW_' . strtoupper($check)] . ''; - } - } - - $template->assign_block_vars('log', array( - 'USERNAME' => $row['username_full'], - 'IP' => $row['ip'], - 'DATE' => $user->format_date($row['time']), - 'ACTION' => $row['action'], - 'DATA' => (count($data)) ? implode(' | ', $data) : '', - 'ID' => $row['id'], - ) - ); - } - } -} diff --git a/install/update/old/includes/mcp/mcp_main.php b/install/update/old/includes/mcp/mcp_main.php deleted file mode 100644 index 4bd783b..0000000 --- a/install/update/old/includes/mcp/mcp_main.php +++ /dev/null @@ -1,1701 +0,0 @@ - -* @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; -} - -/** -* mcp_main -* Handling mcp actions -*/ -class mcp_main -{ - var $p_master; - var $u_action; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $auth, $user, $action; - global $phpbb_root_path, $phpEx, $request; - global $phpbb_dispatcher; - - $quickmod = ($mode == 'quickmod') ? true : false; - - switch ($action) - { - case 'lock': - case 'unlock': - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - lock_unlock($action, $topic_ids); - break; - - case 'lock_post': - case 'unlock_post': - - $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0)); - - if (!count($post_ids)) - { - trigger_error('NO_POST_SELECTED'); - } - - lock_unlock($action, $post_ids); - break; - - case 'make_announce': - case 'make_sticky': - case 'make_global': - case 'make_normal': - - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - change_topic_type($action, $topic_ids); - break; - - case 'move': - $user->add_lang('viewtopic'); - - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - mcp_move_topic($topic_ids); - break; - - case 'fork': - $user->add_lang('viewtopic'); - - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - mcp_fork_topic($topic_ids); - break; - - case 'delete_topic': - $user->add_lang('viewtopic'); - - // f parameter is not reliable for permission usage, however we just use it to decide - // which permission we will check later on. So if it is manipulated, we will still catch it later on. - $forum_id = $request->variable('f', 0); - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false; - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - mcp_delete_topic($topic_ids, $soft_delete, $request->variable('delete_reason', '', true)); - break; - - case 'delete_post': - $user->add_lang('posting'); - - // f parameter is not reliable for permission usage, however we just use it to decide - // which permission we will check later on. So if it is manipulated, we will still catch it later on. - $forum_id = $request->variable('f', 0); - $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0)); - $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false; - - if (!count($post_ids)) - { - trigger_error('NO_POST_SELECTED'); - } - - mcp_delete_post($post_ids, $soft_delete, $request->variable('delete_reason', '', true)); - break; - - case 'restore_topic': - $user->add_lang('posting'); - - $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); - - if (!count($topic_ids)) - { - trigger_error('NO_TOPIC_SELECTED'); - } - - mcp_restore_topic($topic_ids); - break; - - default: - /** - * This event allows you to handle custom quickmod options - * - * @event core.modify_quickmod_actions - * @var string action Topic quick moderation action name - * @var bool quickmod Flag indicating whether MCP is in quick moderation mode - * @since 3.1.0-a4 - * @changed 3.1.0-RC4 Added variables: action, quickmod - */ - $vars = array('action', 'quickmod'); - extract($phpbb_dispatcher->trigger_event('core.modify_quickmod_actions', compact($vars))); - break; - } - - switch ($mode) - { - case 'front': - if (!function_exists('mcp_front_view')) - { - include($phpbb_root_path . 'includes/mcp/mcp_front.' . $phpEx); - } - - $user->add_lang('acp/common'); - - mcp_front_view($id, $mode, $action); - - $this->tpl_name = 'mcp_front'; - $this->page_title = 'MCP_MAIN'; - break; - - case 'forum_view': - if (!function_exists('mcp_forum_view')) - { - include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx); - } - - $user->add_lang('viewforum'); - - $forum_id = $request->variable('f', 0); - - $forum_info = phpbb_get_forum_data($forum_id, 'm_', true); - - if (!count($forum_info)) - { - $this->main('main', 'front'); - return; - } - - $forum_info = $forum_info[$forum_id]; - - mcp_forum_view($id, $mode, $action, $forum_info); - - $this->tpl_name = 'mcp_forum'; - $this->page_title = 'MCP_MAIN_FORUM_VIEW'; - break; - - case 'topic_view': - if (!function_exists('mcp_topic_view')) - { - include($phpbb_root_path . 'includes/mcp/mcp_topic.' . $phpEx); - } - - mcp_topic_view($id, $mode, $action); - - $this->tpl_name = 'mcp_topic'; - $this->page_title = 'MCP_MAIN_TOPIC_VIEW'; - break; - - case 'post_details': - if (!function_exists('mcp_post_details')) - { - include($phpbb_root_path . 'includes/mcp/mcp_post.' . $phpEx); - } - - mcp_post_details($id, $mode, $action); - - $this->tpl_name = ($action == 'whois') ? 'mcp_whois' : 'mcp_post'; - $this->page_title = 'MCP_MAIN_POST_DETAILS'; - break; - - default: - if ($quickmod) - { - switch ($action) - { - case 'lock': - case 'unlock': - case 'make_announce': - case 'make_sticky': - case 'make_global': - case 'make_normal': - case 'make_onindex': - case 'move': - case 'fork': - case 'delete_topic': - trigger_error('TOPIC_NOT_EXIST'); - break; - - case 'lock_post': - case 'unlock_post': - case 'delete_post': - trigger_error('POST_NOT_EXIST'); - break; - } - } - - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - } -} - -/** -* Lock/Unlock Topic/Post -*/ -function lock_unlock($action, $ids) -{ - global $user, $db, $request, $phpbb_log, $phpbb_dispatcher; - - if ($action == 'lock' || $action == 'unlock') - { - $table = TOPICS_TABLE; - $sql_id = 'topic_id'; - $set_id = 'topic_status'; - $l_prefix = 'TOPIC'; - } - else - { - $table = POSTS_TABLE; - $sql_id = 'post_id'; - $set_id = 'post_edit_locked'; - $l_prefix = 'POST'; - } - - $orig_ids = $ids; - - if (!phpbb_check_ids($ids, $table, $sql_id, array('m_lock'))) - { - // Make sure that for f_user_lock only the lock action is triggered. - if ($action != 'lock') - { - return; - } - - $ids = $orig_ids; - - if (!phpbb_check_ids($ids, $table, $sql_id, array('f_user_lock'))) - { - return; - } - } - unset($orig_ids); - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $redirect = reapply_sid($redirect); - - $s_hidden_fields = build_hidden_fields(array( - $sql_id . '_list' => $ids, - 'action' => $action, - 'redirect' => $redirect) - ); - - if (confirm_box(true)) - { - $sql = "UPDATE $table - SET $set_id = " . (($action == 'lock' || $action == 'lock_post') ? ITEM_LOCKED : ITEM_UNLOCKED) . ' - WHERE ' . $db->sql_in_set($sql_id, $ids); - $db->sql_query($sql); - - $data = ($action == 'lock' || $action == 'unlock') ? phpbb_get_topic_data($ids) : phpbb_get_post_data($ids); - - foreach ($data as $id => $row) - { - $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'] - )); - } - - /** - * Perform additional actions after locking/unlocking posts/topics - * - * @event core.mcp_lock_unlock_after - * @var string action Variable containing the action we perform on the posts/topics ('lock', 'unlock', 'lock_post' or 'unlock_post') - * @var array ids Array containing the post/topic IDs that have been locked/unlocked - * @var array data Array containing posts/topics data - * @since 3.1.7-RC1 - */ - $vars = array( - 'action', - 'ids', - 'data', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_lock_unlock_after', compact($vars))); - - $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]; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_PAGE', '', ''); - } - trigger_error($message); - } - else - { - confirm_box(false, strtoupper($action) . '_' . $l_prefix . ((count($ids) == 1) ? '' : 'S'), $s_hidden_fields); - } - - redirect($redirect); -} - -/** -* Change Topic Type -*/ -function change_topic_type($action, $topic_ids) -{ - 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 = (count($topic_ids) == 1) ? 'MCP_MAKE_ANNOUNCEMENT' : 'MCP_MAKE_ANNOUNCEMENTS'; - break; - - case 'make_global': - $new_topic_type = POST_GLOBAL; - $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 = (count($topic_ids) == 1) ? 'MCP_MAKE_STICKY' : 'MCP_MAKE_STICKIES'; - break; - - default: - $new_topic_type = POST_NORMAL; - $check_acl = false; - $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_NORMAL' : 'MCP_MAKE_NORMALS'; - break; - } - - $forum_id = phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', $check_acl, true); - - if ($forum_id === false) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $redirect = reapply_sid($redirect); - - $s_hidden_fields = array( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => $action, - 'redirect' => $redirect, - ); - - 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) && 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); - } - - $db->sql_transaction('commit'); - - $success_msg = (count($topic_ids) == 1) ? 'TOPIC_TYPE_CHANGED' : 'TOPICS_TYPE_CHANGED'; - - if (count($topic_ids)) - { - $data = phpbb_get_topic_data($topic_ids); - - foreach ($data as $topic_id => $row) - { - $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]; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_PAGE', '', ''); - } - trigger_error($message); - } - else - { - confirm_box(false, $l_new_type, build_hidden_fields($s_hidden_fields)); - } - - redirect($redirect); -} - -/** -* Move Topic -*/ -function mcp_move_topic($topic_ids) -{ - global $auth, $user, $db, $template, $phpbb_log, $request, $phpbb_dispatcher; - global $phpEx, $phpbb_root_path; - - // Here we limit the operation to one forum only - $forum_id = phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_move'), true); - - if ($forum_id === false) - { - return; - } - - $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( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => 'move', - 'redirect' => $redirect) - ); - - if ($to_forum_id) - { - $forum_data = phpbb_get_forum_data($to_forum_id, 'f_post'); - - if (!count($forum_data)) - { - $additional_msg = $user->lang['FORUM_NOT_EXIST']; - } - else - { - $forum_data = $forum_data[$to_forum_id]; - - if ($forum_data['forum_type'] != FORUM_POST) - { - $additional_msg = $user->lang['FORUM_NOT_POSTABLE']; - } - else if (!$auth->acl_get('f_post', $to_forum_id) || (!$auth->acl_get('m_approve', $to_forum_id) && !$auth->acl_get('f_noapprove', $to_forum_id))) - { - $additional_msg = $user->lang['USER_CANNOT_POST']; - } - else if ($forum_id == $to_forum_id) - { - $additional_msg = $user->lang['CANNOT_MOVE_SAME_FORUM']; - } - } - } - else if (isset($_POST['confirm'])) - { - $additional_msg = $user->lang['FORUM_NOT_EXIST']; - } - - if (!$to_forum_id || $additional_msg) - { - $request->overwrite('confirm', null, \phpbb\request\request_interface::POST); - $request->overwrite('confirm_key', null); - } - - if (confirm_box(true)) - { - $topic_data = phpbb_get_topic_data($topic_ids); - $leave_shadow = (isset($_POST['move_leave_shadow'])) ? true : false; - - $forum_sync_data = array(); - - $forum_sync_data[$forum_id] = current($topic_data); - $forum_sync_data[$to_forum_id] = $forum_data; - - $topics_moved = $topics_moved_unapproved = $topics_moved_softdeleted = 0; - $posts_moved = $posts_moved_unapproved = $posts_moved_softdeleted = 0; - - foreach ($topic_data as $topic_id => $topic_info) - { - if ($topic_info['topic_visibility'] == ITEM_APPROVED) - { - $topics_moved++; - } - else if ($topic_info['topic_visibility'] == ITEM_UNAPPROVED || $topic_info['topic_visibility'] == ITEM_REAPPROVE) - { - $topics_moved_unapproved++; - } - else if ($topic_info['topic_visibility'] == ITEM_DELETED) - { - $topics_moved_softdeleted++; - } - - $posts_moved += $topic_info['topic_posts_approved']; - $posts_moved_unapproved += $topic_info['topic_posts_unapproved']; - $posts_moved_softdeleted += $topic_info['topic_posts_softdeleted']; - } - - $db->sql_transaction('begin'); - - // Move topics, but do not resync yet - move_topics($topic_ids, $to_forum_id, false); - - if ($request->is_set_post('move_lock_topics') && $auth->acl_get('m_lock', $to_forum_id)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_status = ' . ITEM_LOCKED . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - - $shadow_topics = 0; - $forum_ids = array($to_forum_id); - foreach ($topic_data as $topic_id => $row) - { - // Get the list of forums to resync - $forum_ids[] = $row['forum_id']; - - // We add the $to_forum_id twice, because 'forum_id' is updated - // when the topic is moved again later. - $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_MOVE', false, array( - 'forum_id' => (int) $to_forum_id, - 'topic_id' => (int) $topic_id, - $row['forum_name'], - $forum_data['forum_name'], - (int) $row['forum_id'], - (int) $forum_data['forum_id'], - )); - - // Leave a redirection if required and only if the topic is visible to users - if ($leave_shadow && $row['topic_visibility'] == ITEM_APPROVED && $row['topic_type'] != POST_GLOBAL) - { - $shadow = array( - 'forum_id' => (int) $row['forum_id'], - 'icon_id' => (int) $row['icon_id'], - 'topic_attachment' => (int) $row['topic_attachment'], - 'topic_visibility' => ITEM_APPROVED, // a shadow topic is always approved - 'topic_reported' => 0, // a shadow topic is never reported - 'topic_title' => (string) $row['topic_title'], - 'topic_poster' => (int) $row['topic_poster'], - 'topic_time' => (int) $row['topic_time'], - 'topic_time_limit' => (int) $row['topic_time_limit'], - 'topic_views' => (int) $row['topic_views'], - 'topic_posts_approved' => (int) $row['topic_posts_approved'], - 'topic_posts_unapproved'=> (int) $row['topic_posts_unapproved'], - 'topic_posts_softdeleted'=> (int) $row['topic_posts_softdeleted'], - 'topic_status' => ITEM_MOVED, - 'topic_type' => POST_NORMAL, - 'topic_first_post_id' => (int) $row['topic_first_post_id'], - 'topic_first_poster_colour'=>(string) $row['topic_first_poster_colour'], - 'topic_first_poster_name'=> (string) $row['topic_first_poster_name'], - 'topic_last_post_id' => (int) $row['topic_last_post_id'], - 'topic_last_poster_id' => (int) $row['topic_last_poster_id'], - 'topic_last_poster_colour'=>(string) $row['topic_last_poster_colour'], - 'topic_last_poster_name'=> (string) $row['topic_last_poster_name'], - 'topic_last_post_subject'=> (string) $row['topic_last_post_subject'], - 'topic_last_post_time' => (int) $row['topic_last_post_time'], - 'topic_last_view_time' => (int) $row['topic_last_view_time'], - 'topic_moved_id' => (int) $row['topic_id'], - 'topic_bumped' => (int) $row['topic_bumped'], - 'topic_bumper' => (int) $row['topic_bumper'], - 'poll_title' => (string) $row['poll_title'], - 'poll_start' => (int) $row['poll_start'], - 'poll_length' => (int) $row['poll_length'], - 'poll_max_options' => (int) $row['poll_max_options'], - 'poll_last_vote' => (int) $row['poll_last_vote'] - ); - - /** - * Perform actions before shadow topic is created. - * - * @event core.mcp_main_modify_shadow_sql - * @var array shadow SQL array to be used by $db->sql_build_array - * @var array row Topic data - * @since 3.1.11-RC1 - * @changed 3.1.11-RC1 Added variable: row - */ - $vars = array( - 'shadow', - 'row', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_main_modify_shadow_sql', compact($vars))); - - $db->sql_query('INSERT INTO ' . TOPICS_TABLE . $db->sql_build_array('INSERT', $shadow)); - - // Shadow topics only count on new "topics" and not posts... a shadow topic alone has 0 posts - $shadow_topics++; - } - } - unset($topic_data); - - $sync_sql = array(); - if ($posts_moved) - { - $sync_sql[$to_forum_id][] = 'forum_posts_approved = forum_posts_approved + ' . (int) $posts_moved; - $sync_sql[$forum_id][] = 'forum_posts_approved = forum_posts_approved - ' . (int) $posts_moved; - } - if ($posts_moved_unapproved) - { - $sync_sql[$to_forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved + ' . (int) $posts_moved_unapproved; - $sync_sql[$forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved - ' . (int) $posts_moved_unapproved; - } - if ($posts_moved_softdeleted) - { - $sync_sql[$to_forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted + ' . (int) $posts_moved_softdeleted; - $sync_sql[$forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted - ' . (int) $posts_moved_softdeleted; - } - - if ($topics_moved) - { - $sync_sql[$to_forum_id][] = 'forum_topics_approved = forum_topics_approved + ' . (int) $topics_moved; - if ($topics_moved - $shadow_topics > 0) - { - $sync_sql[$forum_id][] = 'forum_topics_approved = forum_topics_approved - ' . (int) ($topics_moved - $shadow_topics); - } - } - if ($topics_moved_unapproved) - { - $sync_sql[$to_forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved + ' . (int) $topics_moved_unapproved; - $sync_sql[$forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved - ' . (int) $topics_moved_unapproved; - } - if ($topics_moved_softdeleted) - { - $sync_sql[$to_forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted + ' . (int) $topics_moved_softdeleted; - $sync_sql[$forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted - ' . (int) $topics_moved_softdeleted; - } - - $success_msg = (count($topic_ids) == 1) ? 'TOPIC_MOVED_SUCCESS' : 'TOPICS_MOVED_SUCCESS'; - - foreach ($sync_sql as $forum_id_key => $array) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . implode(', ', $array) . ' - WHERE forum_id = ' . $forum_id_key; - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); - - sync('forum', 'forum_id', array($forum_id, $to_forum_id)); - } - else - { - $template->assign_vars(array( - 'S_FORUM_SELECT' => make_forum_select($to_forum_id, $forum_id, false, true, true, true), - 'S_CAN_LEAVE_SHADOW' => true, - 'S_CAN_LOCK_TOPIC' => ($auth->acl_get('m_lock', $to_forum_id)) ? true : false, - 'ADDITIONAL_MSG' => $additional_msg) - ); - - confirm_box(false, 'MOVE_TOPIC' . ((count($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html'); - } - - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - - if (!$success_msg) - { - redirect($redirect); - } - else - { - meta_refresh(3, $redirect); - - $message = $user->lang[$success_msg]; - $message .= '

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

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

' . sprintf($user->lang['RETURN_NEW_FORUM'], '', ''); - - trigger_error($message); - } -} - -/** -* Restore Topics -*/ -function mcp_restore_topic($topic_ids) -{ - global $user, $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_log; - - if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_approve'))) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $forum_id = $request->variable('f', 0); - - $s_hidden_fields = build_hidden_fields(array( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => 'restore_topic', - 'redirect' => $redirect, - )); - $success_msg = ''; - - if (confirm_box(true)) - { - $success_msg = (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)) - { - $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, (count($topic_ids) == 1) ? 'RESTORE_TOPIC' : 'RESTORE_TOPICS', $s_hidden_fields); - } - - $topic_id = $request->variable('t', 0); - if (!$request->is_set('quickmod', \phpbb\request\request_interface::REQUEST)) - { - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - $redirect_message = 'PAGE'; - } - else if ($topic_id) - { - $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id); - $redirect_message = 'TOPIC'; - } - else - { - $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); - $redirect_message = 'FORUM'; - } - - if (!$success_msg) - { - redirect($redirect); - } - else - { - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . sprintf($user->lang['RETURN_' . $redirect_message], '', '')); - } -} - -/** -* Delete Topics -*/ -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, $phpbb_log; - - $check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete'; - if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array($check_permission))) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $forum_id = $request->variable('f', 0); - - $s_hidden_fields = array( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => $action, - 'redirect' => $redirect, - ); - $success_msg = ''; - - if (confirm_box(true)) - { - $success_msg = (count($topic_ids) == 1) ? 'TOPIC_DELETED_SUCCESS' : 'TOPICS_DELETED_SUCCESS'; - - $data = phpbb_get_topic_data($topic_ids); - - foreach ($data as $topic_id => $row) - { - if ($row['topic_moved_id']) - { - $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)) - { - $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 - { - $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) - { - delete_topics('topic_id', $topic_ids); - } - } - else - { - global $template; - - $user->add_lang('posting'); - - // If there are only shadow topics, we neither need a reason nor softdelete - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - AND topic_moved_id = 0'; - $result = $db->sql_query_limit($sql, 1); - $only_shadow = !$db->sql_fetchfield('topic_id'); - $db->sql_freeresult($result); - - $only_softdeleted = false; - if (!$only_shadow && $auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id)) - { - // If there are only soft deleted topics, we display a message why the option is not available - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - AND topic_visibility <> ' . ITEM_DELETED; - $result = $db->sql_query_limit($sql, 1); - $only_softdeleted = !$db->sql_fetchfield('topic_id'); - $db->sql_freeresult($result); - } - - $template->assign_vars(array( - 'S_SHADOW_TOPICS' => $only_shadow, - 'S_SOFTDELETED' => $only_softdeleted, - 'S_TOPIC_MODE' => true, - 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id), - 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id), - 'DELETE_TOPIC_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_TOPIC_PERMANENTLY', count($topic_ids)), - )); - - $count = count($topic_ids); - $l_confirm = $count === 1 ? 'DELETE_TOPIC' : 'DELETE_TOPICS'; - if ($only_softdeleted) - { - $l_confirm = array($l_confirm . '_PERMANENTLY', $count); - $s_hidden_fields['delete_permanent'] = '1'; - } - else if ($only_shadow || !$auth->acl_get('m_softdelete', $forum_id)) - { - $s_hidden_fields['delete_permanent'] = '1'; - } - - confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); - } - - $topic_id = $request->variable('t', 0); - if (!$request->is_set('quickmod', \phpbb\request\request_interface::REQUEST)) - { - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - $redirect_message = 'PAGE'; - } - else if ($is_soft && $topic_id) - { - $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id); - $redirect_message = 'TOPIC'; - } - else - { - $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); - $redirect_message = 'FORUM'; - } - - if (!$success_msg) - { - redirect($redirect); - } - else - { - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . sprintf($user->lang['RETURN_' . $redirect_message], '', '')); - } -} - -/** -* Delete Posts -*/ -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, $phpbb_log; - - $check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete'; - if (!phpbb_check_ids($post_ids, POSTS_TABLE, 'post_id', array($check_permission))) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); - $forum_id = $request->variable('f', 0); - - $s_hidden_fields = array( - 'post_id_list' => $post_ids, - 'f' => $forum_id, - 'action' => $action, - 'redirect' => $redirect, - ); - $success_msg = ''; - - if (confirm_box(true) && $is_soft) - { - $post_info = phpbb_get_post_data($post_ids); - - $topic_info = $approve_log = array(); - - // Group the posts by topic_id - foreach ($post_info as $post_id => $post_data) - { - if ($post_data['post_visibility'] != ITEM_APPROVED) - { - continue; - } - $topic_id = (int) $post_data['topic_id']; - - $topic_info[$topic_id]['posts'][] = (int) $post_id; - $topic_info[$topic_id]['forum_id'] = (int) $post_data['forum_id']; - - if ($post_id == $post_data['topic_first_post_id']) - { - $topic_info[$topic_id]['first_post'] = true; - } - - if ($post_id == $post_data['topic_last_post_id']) - { - $topic_info[$topic_id]['last_post'] = true; - } - - $approve_log[] = array( - 'forum_id' => $post_data['forum_id'], - 'topic_id' => $post_data['topic_id'], - 'post_id' => $post_id, - 'post_subject' => $post_data['post_subject'], - 'poster_id' => $post_data['poster_id'], - 'post_username' => $post_data['post_username'], - 'username' => $post_data['username'], - ); - } - - /* @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 = count($topic_info); - // None of the topics is really deleted, so a redirect won't hurt much. - $deleted_topics = 0; - - $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']; - $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); - - // Return links - $return_link = array(); - if ($affected_topics == 1 && $topic_id) - { - $return_link[] = sprintf($user->lang['RETURN_TOPIC'], '', ''); - } - $return_link[] = sprintf($user->lang['RETURN_FORUM'], '', ''); - - } - else if (confirm_box(true)) - { - if (!function_exists('delete_posts')) - { - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - - // Count the number of topics that are affected - // I did not use COUNT(DISTINCT ...) because I remember having problems - // with it on older versions of MySQL -- Ashe - - $sql = 'SELECT DISTINCT topic_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $result = $db->sql_query($sql); - - $topic_id_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_id_list[] = $row['topic_id']; - } - $affected_topics = count($topic_id_list); - $db->sql_freeresult($result); - - $post_data = phpbb_get_post_data($post_ids); - - foreach ($post_data as $id => $row) - { - $post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username']; - $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 - delete_posts('post_id', $post_ids); - - $sql = 'SELECT COUNT(topic_id) AS topics_left - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_id_list); - $result = $db->sql_query_limit($sql, 1); - - $deleted_topics = ($row = $db->sql_fetchrow($result)) ? ($affected_topics - $row['topics_left']) : $affected_topics; - $db->sql_freeresult($result); - - $topic_id = $request->variable('t', 0); - - // Return links - $return_link = array(); - if ($affected_topics == 1 && !$deleted_topics && $topic_id) - { - $return_link[] = sprintf($user->lang['RETURN_TOPIC'], '', ''); - } - $return_link[] = sprintf($user->lang['RETURN_FORUM'], '', ''); - - if (count($post_ids) == 1) - { - if ($deleted_topics) - { - // We deleted the only post of a topic, which in turn has - // been removed from the database - $success_msg = $user->lang['TOPIC_DELETED_SUCCESS']; - } - else - { - $success_msg = $user->lang['POST_DELETED_SUCCESS']; - } - } - else - { - if ($deleted_topics) - { - // Some of topics disappeared - $success_msg = $user->lang['POSTS_DELETED_SUCCESS'] . '

' . $user->lang['EMPTY_TOPICS_REMOVED_WARNING']; - } - else - { - $success_msg = $user->lang['POSTS_DELETED_SUCCESS']; - } - } - } - else - { - global $template; - - $user->add_lang('posting'); - - $only_softdeleted = false; - if ($auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id)) - { - // If there are only soft deleted posts, we display a message why the option is not available - $sql = 'SELECT post_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids) . ' - AND post_visibility <> ' . ITEM_DELETED; - $result = $db->sql_query_limit($sql, 1); - $only_softdeleted = !$db->sql_fetchfield('post_id'); - $db->sql_freeresult($result); - } - - $template->assign_vars(array( - 'S_SOFTDELETED' => $only_softdeleted, - 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id), - 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id), - 'DELETE_POST_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_POST_PERMANENTLY', count($post_ids)), - )); - - $count = count($post_ids); - $l_confirm = $count === 1 ? 'DELETE_POST' : 'DELETE_POSTS'; - if ($only_softdeleted) - { - $l_confirm = array($l_confirm . '_PERMANENTLY', $count); - $s_hidden_fields['delete_permanent'] = '1'; - } - else if (!$auth->acl_get('m_softdelete', $forum_id)) - { - $s_hidden_fields['delete_permanent'] = '1'; - } - - confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); - } - - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - - if (!$success_msg) - { - redirect($redirect); - } - else - { - if ($affected_topics != 1 || $deleted_topics || !$topic_id) - { - $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "f=$forum_id&i=main&mode=forum_view", false); - } - - meta_refresh(3, $redirect); - trigger_error($success_msg . '

' . sprintf($user->lang['RETURN_PAGE'], '', '') . '

' . implode('

', $return_link)); - } -} - -/** -* Fork Topic -*/ -function mcp_fork_topic($topic_ids) -{ - global $auth, $user, $db, $template, $config; - 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->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(); - - $s_hidden_fields = build_hidden_fields(array( - 'topic_id_list' => $topic_ids, - 'f' => $forum_id, - 'action' => 'fork', - 'redirect' => $redirect) - ); - - if ($to_forum_id) - { - $forum_data = phpbb_get_forum_data($to_forum_id, 'f_post'); - - if (!count($topic_ids)) - { - $additional_msg = $user->lang['NO_TOPIC_SELECTED']; - } - else if (!count($forum_data)) - { - $additional_msg = $user->lang['FORUM_NOT_EXIST']; - } - else - { - $forum_data = $forum_data[$to_forum_id]; - - if ($forum_data['forum_type'] != FORUM_POST) - { - $additional_msg = $user->lang['FORUM_NOT_POSTABLE']; - } - else if (!$auth->acl_get('f_post', $to_forum_id)) - { - $additional_msg = $user->lang['USER_CANNOT_POST']; - } - } - } - else if (isset($_POST['confirm'])) - { - $additional_msg = $user->lang['FORUM_NOT_EXIST']; - } - - if ($additional_msg) - { - $request->overwrite('confirm', null, \phpbb\request\request_interface::POST); - $request->overwrite('confirm_key', null); - } - - if (confirm_box(true)) - { - $topic_data = phpbb_get_topic_data($topic_ids, 'f_post'); - - $total_topics = $total_topics_unapproved = $total_topics_softdeleted = 0; - $total_posts = $total_posts_unapproved = $total_posts_softdeleted = 0; - $new_topic_id_list = array(); - - foreach ($topic_data as $topic_id => $topic_row) - { - if (!isset($search_type) && $topic_row['enable_indexing']) - { - // Select the search method and do some additional checks to ensure it can actually be utilised - $search_type = $config['search_type']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - $search_mode = 'post'; - - if ($error) - { - trigger_error($error); - } - } - else if (!isset($search_type) && !$topic_row['enable_indexing']) - { - $search_type = false; - } - - $sql_ary = array( - 'forum_id' => (int) $to_forum_id, - 'icon_id' => (int) $topic_row['icon_id'], - 'topic_attachment' => (int) $topic_row['topic_attachment'], - 'topic_visibility' => (int) $topic_row['topic_visibility'], - 'topic_reported' => 0, - 'topic_title' => (string) $topic_row['topic_title'], - 'topic_poster' => (int) $topic_row['topic_poster'], - 'topic_time' => (int) $topic_row['topic_time'], - 'topic_posts_approved' => (int) $topic_row['topic_posts_approved'], - 'topic_posts_unapproved' => (int) $topic_row['topic_posts_unapproved'], - 'topic_posts_softdeleted' => (int) $topic_row['topic_posts_softdeleted'], - 'topic_status' => (int) $topic_row['topic_status'], - 'topic_type' => (int) $topic_row['topic_type'], - 'topic_first_poster_name' => (string) $topic_row['topic_first_poster_name'], - 'topic_last_poster_id' => (int) $topic_row['topic_last_poster_id'], - 'topic_last_poster_name' => (string) $topic_row['topic_last_poster_name'], - 'topic_last_post_time' => (int) $topic_row['topic_last_post_time'], - 'topic_last_view_time' => (int) $topic_row['topic_last_view_time'], - 'topic_bumped' => (int) $topic_row['topic_bumped'], - 'topic_bumper' => (int) $topic_row['topic_bumper'], - 'poll_title' => (string) $topic_row['poll_title'], - 'poll_start' => (int) $topic_row['poll_start'], - 'poll_length' => (int) $topic_row['poll_length'], - 'poll_max_options' => (int) $topic_row['poll_max_options'], - 'poll_vote_change' => (int) $topic_row['poll_vote_change'], - ); - - /** - * Perform actions before forked topic is created. - * - * @event core.mcp_main_modify_fork_sql - * @var array sql_ary SQL array to be used by $db->sql_build_array - * @var array topic_row Topic data - * @since 3.1.11-RC1 - * @changed 3.1.11-RC1 Added variable: topic_row - */ - $vars = array( - 'sql_ary', - 'topic_row', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_main_modify_fork_sql', compact($vars))); - - $db->sql_query('INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - $new_topic_id = $db->sql_nextid(); - $new_topic_id_list[$topic_id] = $new_topic_id; - - switch ($topic_row['topic_visibility']) - { - case ITEM_APPROVED: - $total_topics++; - break; - case ITEM_UNAPPROVED: - case ITEM_REAPPROVE: - $total_topics_unapproved++; - break; - case ITEM_DELETED: - $total_topics_softdeleted++; - break; - } - - if ($topic_row['poll_start']) - { - $sql = 'SELECT * - FROM ' . POLL_OPTIONS_TABLE . " - WHERE topic_id = $topic_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary = array( - 'poll_option_id' => (int) $row['poll_option_id'], - 'topic_id' => (int) $new_topic_id, - 'poll_option_text' => (string) $row['poll_option_text'], - 'poll_option_total' => 0 - ); - - $db->sql_query('INSERT INTO ' . POLL_OPTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - } - $db->sql_freeresult($result); - } - - $sql = 'SELECT * - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - ORDER BY post_time ASC, post_id ASC"; - $result = $db->sql_query($sql); - - $post_rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $post_rows[] = $row; - } - $db->sql_freeresult($result); - - if (!count($post_rows)) - { - continue; - } - - foreach ($post_rows as $row) - { - $sql_ary = array( - 'topic_id' => (int) $new_topic_id, - 'forum_id' => (int) $to_forum_id, - 'poster_id' => (int) $row['poster_id'], - 'icon_id' => (int) $row['icon_id'], - 'poster_ip' => (string) $row['poster_ip'], - 'post_time' => (int) $row['post_time'], - 'post_visibility' => (int) $row['post_visibility'], - 'post_reported' => 0, - 'enable_bbcode' => (int) $row['enable_bbcode'], - 'enable_smilies' => (int) $row['enable_smilies'], - 'enable_magic_url' => (int) $row['enable_magic_url'], - 'enable_sig' => (int) $row['enable_sig'], - 'post_username' => (string) $row['post_username'], - 'post_subject' => (string) $row['post_subject'], - 'post_text' => (string) $row['post_text'], - 'post_edit_reason' => (string) $row['post_edit_reason'], - 'post_edit_user' => (int) $row['post_edit_user'], - 'post_checksum' => (string) $row['post_checksum'], - 'post_attachment' => (int) $row['post_attachment'], - 'bbcode_bitfield' => $row['bbcode_bitfield'], - 'bbcode_uid' => (string) $row['bbcode_uid'], - 'post_edit_time' => (int) $row['post_edit_time'], - 'post_edit_count' => (int) $row['post_edit_count'], - 'post_edit_locked' => (int) $row['post_edit_locked'], - 'post_postcount' => $row['post_postcount'], - ); - // Adjust post count only if the post can be incremented to the user counter - if ($row['post_postcount']) - { - if (isset($counter[$row['poster_id']])) - { - ++$counter[$row['poster_id']]; - } - else - { - $counter[$row['poster_id']] = 1; - } - } - $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: - $total_posts++; - break; - case ITEM_UNAPPROVED: - case ITEM_REAPPROVE: - $total_posts_unapproved++; - break; - case ITEM_DELETED: - $total_posts_softdeleted++; - break; - } - - // Copy whether the topic is dotted - markread('post', $to_forum_id, $new_topic_id, 0, $row['poster_id']); - - if (!empty($search_type)) - { - $search->index($search_mode, $new_post_id, $sql_ary['post_text'], $sql_ary['post_subject'], $sql_ary['poster_id'], ($topic_row['topic_type'] == POST_GLOBAL) ? 0 : $to_forum_id); - $search_mode = 'reply'; // After one we index replies - } - - // Copy Attachments - if ($row['post_attachment']) - { - $sql = 'SELECT * FROM ' . ATTACHMENTS_TABLE . " - WHERE post_msg_id = {$row['post_id']} - AND topic_id = $topic_id - AND in_message = 0"; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($attach_row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'post_msg_id' => (int) $new_post_id, - 'topic_id' => (int) $new_topic_id, - 'in_message' => 0, - 'is_orphan' => (int) $attach_row['is_orphan'], - 'poster_id' => (int) $attach_row['poster_id'], - 'physical_filename' => (string) utf8_basename($attach_row['physical_filename']), - 'real_filename' => (string) utf8_basename($attach_row['real_filename']), - 'download_count' => (int) $attach_row['download_count'], - 'attach_comment' => (string) $attach_row['attach_comment'], - 'extension' => (string) $attach_row['extension'], - 'mimetype' => (string) $attach_row['mimetype'], - 'filesize' => (int) $attach_row['filesize'], - 'filetime' => (int) $attach_row['filetime'], - 'thumbnail' => (int) $attach_row['thumbnail'] - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(ATTACHMENTS_TABLE, $sql_ary); - } - } - } - - // Copy topic subscriptions to new topic - $sql = 'SELECT user_id, notify_status - FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'topic_id' => (int) $new_topic_id, - 'user_id' => (int) $row['user_id'], - 'notify_status' => (int) $row['notify_status'], - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); - } - - // Copy bookmarks to new topic - $sql = 'SELECT user_id - FROM ' . BOOKMARKS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'topic_id' => (int) $new_topic_id, - 'user_id' => (int) $row['user_id'], - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); - } - } - - // Sync new topics, parent forums and board stats - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_posts_approved = forum_posts_approved + ' . $total_posts . ', - forum_posts_unapproved = forum_posts_unapproved + ' . $total_posts_unapproved . ', - forum_posts_softdeleted = forum_posts_softdeleted + ' . $total_posts_softdeleted . ', - forum_topics_approved = forum_topics_approved + ' . $total_topics . ', - forum_topics_unapproved = forum_topics_unapproved + ' . $total_topics_unapproved . ', - forum_topics_softdeleted = forum_topics_softdeleted + ' . $total_topics_softdeleted . ' - WHERE forum_id = ' . $to_forum_id; - $db->sql_query($sql); - - if (!empty($counter)) - { - // Do only one query per user and not a query per post. - foreach ($counter as $user_id => $count) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts + ' . (int) $count . ' - WHERE user_id = ' . (int) $user_id; - $db->sql_query($sql); - } - } - - sync('topic', 'topic_id', $new_topic_id_list); - sync('forum', 'forum_id', $to_forum_id); - - $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) - { - $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 = (count($topic_ids) == 1) ? 'TOPIC_FORKED_SUCCESS' : 'TOPICS_FORKED_SUCCESS'; - } - else - { - $template->assign_vars(array( - 'S_FORUM_SELECT' => make_forum_select($to_forum_id, false, false, true, true, true), - 'S_CAN_LEAVE_SHADOW' => false, - 'ADDITIONAL_MSG' => $additional_msg) - ); - - confirm_box(false, 'FORK_TOPIC' . ((count($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html'); - } - - $redirect = $request->variable('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - - if (!$success_msg) - { - redirect($redirect); - } - else - { - $redirect_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); - meta_refresh(3, $redirect_url); - $return_link = sprintf($user->lang['RETURN_FORUM'], '', ''); - - if ($forum_id != $to_forum_id) - { - $return_link .= '

' . sprintf($user->lang['RETURN_NEW_FORUM'], '', ''); - } - - trigger_error($user->lang[$success_msg] . '

' . $return_link); - } -} diff --git a/install/update/old/includes/mcp/mcp_notes.php b/install/update/old/includes/mcp/mcp_notes.php deleted file mode 100644 index a4c2356..0000000 --- a/install/update/old/includes/mcp/mcp_notes.php +++ /dev/null @@ -1,258 +0,0 @@ - -* @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; -} - -/** -* mcp_notes -* Displays notes about a user -*/ -class mcp_notes -{ - var $p_master; - var $u_action; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $user, $template, $request; - global $phpbb_root_path, $phpEx; - - $action = $request->variable('action', array('' => '')); - - if (is_array($action)) - { - list($action, ) = each($action); - } - - $this->page_title = 'MCP_NOTES'; - - switch ($mode) - { - case 'front': - $template->assign_vars(array( - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=mcp&field=username&select_single=true'), - 'U_POST_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes'), - - 'L_TITLE' => $user->lang['MCP_NOTES'], - )); - - $this->tpl_name = 'mcp_notes_front'; - break; - - case 'user_notes': - $user->add_lang('acp/common'); - - $this->mcp_notes_user_view($action); - $this->tpl_name = 'mcp_notes_user'; - break; - } - } - - /** - * Display user notes - */ - function mcp_notes_user_view($action) - { - global $config, $phpbb_log, $request; - global $template, $db, $user, $auth, $phpbb_container; - - $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'); - - $sql_where = ($user_id) ? "user_id = $user_id" : "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE $sql_where"; - $result = $db->sql_query($sql); - $userrow = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$userrow) - { - trigger_error('NO_USER'); - } - - $user_id = $userrow['user_id']; - - // Populate user id to the currently active module (this module) - // The following method is another way of adjusting module urls. It is the easy variant if we want - // to directly adjust the current module url based on data retrieved within the same module. - if (strpos($this->u_action, "&u=$user_id") === false) - { - $this->p_master->adjust_url('&u=' . $user_id); - $this->u_action .= "&u=$user_id"; - } - - $deletemark = ($action == 'del_marked') ? true : false; - $deleteall = ($action == 'del_all') ? true : false; - $marked = $request->variable('marknote', array(0)); - $usernote = $request->variable('usernote', '', true); - - // Handle any actions - if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs')) - { - $where_sql = ''; - if ($deletemark && $marked) - { - $sql_in = array(); - foreach ($marked as $mark) - { - $sql_in[] = $mark; - } - $where_sql = ' AND ' . $db->sql_in_set('log_id', $sql_in); - unset($sql_in); - } - - if ($where_sql || $deleteall) - { - if (check_form_key('mcp_notes')) - { - $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE log_type = ' . LOG_USERS . " - AND reportee_id = $user_id - $where_sql"; - $db->sql_query($sql); - - $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'; - } - else - { - $msg = 'FORM_INVALID'; - } - $redirect = $this->u_action . '&u=' . $user_id; - meta_refresh(3, $redirect); - trigger_error($user->lang[$msg] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - } - - if ($usernote && $action == 'add_feedback') - { - if (check_form_key('mcp_notes')) - { - $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 - )); - - $msg = $user->lang['USER_FEEDBACK_ADDED']; - } - else - { - $msg = $user->lang['FORM_INVALID']; - } - $redirect = $this->u_action; - meta_refresh(3, $redirect); - - trigger_error($msg . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - - // Generate the appropriate user information for the user we are looking at - - $rank_title = $rank_img = ''; - $avatar_img = phpbb_get_user_avatar($userrow); - - $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_text = array('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_DATE'], 'c' => $user->lang['SORT_IP'], 'd' => $user->lang['SORT_ACTION']); - $sort_by_sql = array('a' => 'u.username_clean', 'b' => 'l.log_time', 'c' => 'l.log_ip', 'd' => 'l.log_operation'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $st, $sk, $sd, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - - // Define where and sort sql for use in displaying logs - $sql_where = ($st) ? (time() - ($st * 86400)) : 0; - $sql_sort = $sort_by_sql[$sk] . ' ' . (($sd == 'd') ? 'DESC' : 'ASC'); - - $keywords = $request->variable('keywords', '', true); - $keywords_param = !empty($keywords) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; - - $log_data = array(); - $log_count = 0; - $start = view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort, $keywords); - - if ($log_count) - { - $template->assign_var('S_USER_NOTES', true); - - foreach ($log_data as $row) - { - $template->assign_block_vars('usernotes', array( - 'REPORT_BY' => $row['username_full'], - 'REPORT_AT' => $user->format_date($row['time']), - 'ACTION' => $row['action'], - 'IP' => $row['ip'], - 'ID' => $row['id']) - ); - } - } - - $base_url = $this->u_action . "&$u_sort_param$keywords_param"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'U_POST_ACTION' => $this->u_action, - 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_KEYWORDS' => $keywords, - - 'L_TITLE' => $user->lang['MCP_NOTES_USER'], - - 'TOTAL_REPORTS' => $user->lang('LIST_REPORTS', (int) $log_count), - - 'RANK_TITLE' => $rank_title, - 'JOINED' => $user->format_date($userrow['user_regdate']), - 'POSTS' => ($userrow['user_posts']) ? $userrow['user_posts'] : 0, - 'WARNINGS' => ($userrow['user_warnings']) ? $userrow['user_warnings'] : 0, - - 'USERNAME_FULL' => get_username_string('full', $userrow['user_id'], $userrow['username'], $userrow['user_colour']), - 'USERNAME_COLOUR' => get_username_string('colour', $userrow['user_id'], $userrow['username'], $userrow['user_colour']), - 'USERNAME' => get_username_string('username', $userrow['user_id'], $userrow['username'], $userrow['user_colour']), - 'U_PROFILE' => get_username_string('profile', $userrow['user_id'], $userrow['username'], $userrow['user_colour']), - - 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $rank_img, - ) - ); - } - -} diff --git a/install/update/old/includes/mcp/mcp_topic.php b/install/update/old/includes/mcp/mcp_topic.php deleted file mode 100644 index 68a65aa..0000000 --- a/install/update/old/includes/mcp/mcp_topic.php +++ /dev/null @@ -1,812 +0,0 @@ - -* @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; -} - -/** -* View topic in MCP -*/ -function mcp_topic_view($id, $mode, $action) -{ - 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()); - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - $user->add_lang('viewtopic'); - - $topic_id = $request->variable('t', 0); - $topic_info = phpbb_get_topic_data(array($topic_id), false, true); - - if (!count($topic_info)) - { - trigger_error('TOPIC_NOT_EXIST'); - } - - $topic_info = $topic_info[$topic_id]; - - // Set up some vars - $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->variable('post_ids', array(0)); - $checked_ids = $post_id_list = $request->variable('post_id_list', array(0)); - - // Resync Topic? - if ($action == 'resync') - { - if (!function_exists('mcp_resync_topics')) - { - include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx); - } - mcp_resync_topics(array($topic_id)); - } - - // Split Topic? - if ($action == 'split_all' || $action == 'split_beyond') - { - if (!$sort) - { - split_topic($action, $topic_id, $to_forum_id, $subject); - } - $action = 'split'; - } - - // Merge Posts? - if ($action == 'merge_posts') - { - if (!$sort) - { - merge_posts($topic_id, $to_topic_id); - } - $action = 'merge'; - } - - if ($action == 'split' && !$subject) - { - $subject = $topic_info['topic_title']; - } - - // Restore or pprove posts? - if (($action == 'restore' || $action == 'approve') && $auth->acl_get('m_approve', $topic_info['forum_id'])) - { - 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 (!count($post_id_list)) - { - trigger_error('NO_POST_SELECTED'); - } - - if (!$sort) - { - mcp_queue::approve_posts($action, $post_id_list, $id, $mode); - } - } - - // Jumpbox, sort selects and that kind of things - make_jumpbox($url . "&i=$id&mode=forum_view", $topic_info['forum_id'], false, 'm_', true); - $where_sql = ($action == 'reports') ? 'WHERE post_reported = 1 AND ' : 'WHERE'; - - $sort_days = $total = 0; - $sort_key = $sort_dir = ''; - $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); - - /* @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->variable('posts_per_page', intval($config['posts_per_page']))); - if ($posts_per_page == 0) - { - $posts_per_page = $total; - } - - if ((!empty($sort_days_old) && $sort_days_old != $sort_days) || $total <= $posts_per_page) - { - $start = 0; - } - $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 ' : '') . ' - 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; - $result = $db->sql_query_limit($sql, $posts_per_page, $start); - - $rowset = $post_id_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[] = $row; - $post_id_list[] = $row['post_id']; - } - $db->sql_freeresult($result); - - // Get topic tracking info - if ($config['load_db_lastread']) - { - $tmp_topic_data = array($topic_id => $topic_info); - $topic_tracking_info = get_topic_tracking($topic_info['forum_id'], $topic_id, $tmp_topic_data, array($topic_info['forum_id'] => $topic_info['forum_mark_time'])); - unset($tmp_topic_data); - } - else - { - $topic_tracking_info = get_complete_topic_tracking($topic_info['forum_id'], $topic_id); - } - - $has_unapproved_posts = $has_deleted_posts = false; - - // Grab extensions - $attachments = array(); - if ($topic_info['topic_attachment'] && count($post_id_list)) - { - // Get attachments... - if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $topic_info['forum_id'])) - { - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $post_id_list) . ' - AND in_message = 0 - ORDER BY filetime DESC, post_msg_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $attachments[$row['post_msg_id']][] = $row; - } - $db->sql_freeresult($result); - } - } - - /** - * Event to modify the post data for the MCP topic review before assigning the posts - * - * @event core.mcp_topic_modify_post_data - * @var array attachments List of attachments post_id => array of attachments - * @var int forum_id The forum ID we are currently in - * @var int id ID of the tab we are displaying - * @var string mode Mode of the MCP page we are displaying - * @var array post_id_list Array with post ids we are going to display - * @var array rowset Array with the posts data - * @var int topic_id The topic ID we are currently reviewing - * @since 3.1.7-RC1 - */ - $vars = array( - 'attachments', - 'forum_id', - 'id', - 'mode', - 'post_id_list', - 'rowset', - 'topic_id', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_topic_modify_post_data', compact($vars))); - - foreach ($rowset as $i => $row) - { - $message = $row['post_text']; - $post_subject = ($row['post_subject'] != '') ? $row['post_subject'] : $topic_info['topic_title']; - - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); - - if (!empty($attachments[$row['post_id']])) - { - $update_count = array(); - parse_attachments($topic_info['forum_id'], $message, $attachments[$row['post_id']], $update_count); - } - - if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) - { - $has_unapproved_posts = true; - } - - if ($row['post_visibility'] == ITEM_DELETED) - { - $has_deleted_posts = true; - } - - $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false; - - $post_row = array( - 'POST_AUTHOR_FULL' => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - - 'POST_DATE' => $user->format_date($row['post_time']), - 'POST_SUBJECT' => $post_subject, - 'MESSAGE' => $message, - 'POST_ID' => $row['post_id'], - 'RETURN_TOPIC' => sprintf($user->lang['RETURN_TOPIC'], '', ''), - - 'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'), - - 'S_POST_REPORTED' => ($row['post_reported'] && $auth->acl_get('m_report', $topic_info['forum_id'])), - 'S_POST_UNAPPROVED' => (($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $topic_info['forum_id'])), - 'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED && $auth->acl_get('m_approve', $topic_info['forum_id'])), - 'S_CHECKED' => (($submitted_id_list && !in_array(intval($row['post_id']), $submitted_id_list)) || in_array(intval($row['post_id']), $checked_ids)) ? true : false, - 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false, - - 'U_POST_DETAILS' => "$url&i=$id&p={$row['post_id']}&mode=post_details" . (($forum_id) ? "&f=$forum_id" : ''), - 'U_MCP_APPROVE' => ($auth->acl_get('m_approve', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=approve_details&f=' . $topic_info['forum_id'] . '&p=' . $row['post_id']) : '', - 'U_MCP_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&f=' . $topic_info['forum_id'] . '&p=' . $row['post_id']) : '', - ); - - /** - * Event to modify the template data block for topic reviews in the MCP - * - * @event core.mcp_topic_review_modify_row - * @var int id ID of the tab we are displaying - * @var string mode Mode of the MCP page we are displaying - * @var int topic_id The topic ID we are currently reviewing - * @var int forum_id The forum ID we are currently in - * @var int start Start item of this page - * @var int current_row_number Number of the post on this page - * @var array post_row Template block array of the current post - * @var array row Array with original post and user data - * @var array topic_info Array with topic data - * @var int total Total posts count - * @since 3.1.4-RC1 - */ - $vars = array( - 'id', - 'mode', - 'topic_id', - 'forum_id', - 'start', - 'current_row_number', - 'post_row', - 'row', - 'topic_info', - 'total', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_topic_review_modify_row', compact($vars))); - - $template->assign_block_vars('postrow', $post_row); - - // Display not already displayed Attachments for this post, we already parsed them. ;) - if (!empty($attachments[$row['post_id']])) - { - foreach ($attachments[$row['post_id']] as $attachment) - { - $template->assign_block_vars('postrow.attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - } - - unset($rowset[$i]); - } - - // Display topic icons for split topic - $s_topic_icons = false; - - if ($auth->acl_gets('m_split', 'm_merge', (int) $topic_info['forum_id'])) - { - include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - $s_topic_icons = posting_gen_topic_icons('', $icon_id); - - // Has the user selected a topic for merge? - if ($to_topic_id) - { - $to_topic_info = phpbb_get_topic_data(array($to_topic_id), 'm_merge'); - - if (!count($to_topic_info)) - { - $to_topic_id = 0; - } - else - { - $to_topic_info = $to_topic_info[$to_topic_id]; - - if (!$to_topic_info['enable_icons'] || $auth->acl_get('!f_icons', $topic_info['forum_id'])) - { - $s_topic_icons = false; - } - } - } - } - - $s_hidden_fields = build_hidden_fields(array( - 'st_old' => $sort_days, - 'post_ids' => $post_id_list, - )); - - $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&t={$topic_info['topic_id']}&mode=$mode&action=$action&to_topic_id=$to_topic_id&posts_per_page=$posts_per_page&st=$sort_days&sk=$sort_key&sd=$sort_dir"); - if ($posts_per_page) - { - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total, $posts_per_page, $start); - } - - $template->assign_vars(array( - 'TOPIC_TITLE' => $topic_info['topic_title'], - 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_info['forum_id'] . '&t=' . $topic_info['topic_id']), - - 'TO_TOPIC_ID' => $to_topic_id, - 'TO_TOPIC_INFO' => ($to_topic_id) ? sprintf($user->lang['YOU_SELECTED_TOPIC'], $to_topic_id, '' . $to_topic_info['topic_title'] . '') : '', - - 'SPLIT_SUBJECT' => $subject, - 'POSTS_PER_PAGE' => $posts_per_page, - 'ACTION' => $action, - - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'), - 'DELETED_IMG' => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'), - 'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'), - - 'S_MCP_ACTION' => "$url&i=$id&mode=$mode&action=$action&start=$start", - 'S_FORUM_SELECT' => ($to_forum_id) ? make_forum_select($to_forum_id, false, false, true, true, true) : make_forum_select($topic_info['forum_id'], false, false, true, true, true), - 'S_CAN_SPLIT' => ($auth->acl_get('m_split', $topic_info['forum_id'])) ? true : false, - 'S_CAN_MERGE' => ($auth->acl_get('m_merge', $topic_info['forum_id'])) ? true : false, - 'S_CAN_DELETE' => ($auth->acl_get('m_delete', $topic_info['forum_id'])) ? true : false, - 'S_CAN_APPROVE' => ($has_unapproved_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false, - 'S_CAN_RESTORE' => ($has_deleted_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false, - 'S_CAN_LOCK' => ($auth->acl_get('m_lock', $topic_info['forum_id'])) ? true : false, - 'S_CAN_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? true : false, - 'S_CAN_SYNC' => $auth->acl_get('m_', $topic_info['forum_id']), - 'S_REPORT_VIEW' => ($action == 'reports') ? true : false, - 'S_MERGE_VIEW' => ($action == 'merge') ? true : false, - 'S_SPLIT_VIEW' => ($action == 'split') ? true : false, - - 'S_HIDDEN_FIELDS' => $s_hidden_fields, - - 'S_SHOW_TOPIC_ICONS' => $s_topic_icons, - 'S_TOPIC_ICON' => $icon_id, - - 'U_SELECT_TOPIC' => "$url&i=$id&mode=forum_view&action=merge_select" . (($forum_id) ? "&f=$forum_id" : ''), - - 'RETURN_TOPIC' => sprintf($user->lang['RETURN_TOPIC'], '', ''), - 'RETURN_FORUM' => sprintf($user->lang['RETURN_FORUM'], '', ''), - - 'TOTAL_POSTS' => $user->lang('VIEW_TOPIC_POSTS', (int) $total), - )); -} - -/** -* Split topic -*/ -function split_topic($action, $topic_id, $to_forum_id, $subject) -{ - global $db, $template, $user, $phpEx, $phpbb_root_path, $auth, $config, $phpbb_log, $request, $phpbb_dispatcher; - - $post_id_list = $request->variable('post_id_list', array(0)); - $forum_id = $request->variable('forum_id', 0); - $start = $request->variable('start', 0); - - if (!count($post_id_list)) - { - $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']); - return; - } - - if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_split'))) - { - return; - } - - $post_id = $post_id_list[0]; - $post_info = phpbb_get_post_data(array($post_id)); - - if (!count($post_info)) - { - $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']); - return; - } - - $post_info = $post_info[$post_id]; - $subject = trim($subject); - - // Make some tests - if (!$subject) - { - $template->assign_var('MESSAGE', $user->lang['EMPTY_SUBJECT']); - return; - } - - if ($to_forum_id <= 0) - { - $template->assign_var('MESSAGE', $user->lang['NO_DESTINATION_FORUM']); - return; - } - - $forum_info = phpbb_get_forum_data(array($to_forum_id), 'f_post'); - - if (!count($forum_info)) - { - $template->assign_var('MESSAGE', $user->lang['USER_CANNOT_POST']); - return; - } - - $forum_info = $forum_info[$to_forum_id]; - - if ($forum_info['forum_type'] != FORUM_POST) - { - $template->assign_var('MESSAGE', $user->lang['FORUM_NOT_POSTABLE']); - return; - } - - $redirect = $request->variable('redirect', build_url(array('quickmod'))); - - $s_hidden_fields = build_hidden_fields(array( - 'i' => 'main', - 'post_id_list' => $post_id_list, - 'f' => $forum_id, - 'mode' => 'topic_view', - 'start' => $start, - 'action' => $action, - 't' => $topic_id, - 'redirect' => $redirect, - 'subject' => $subject, - 'to_forum_id' => $to_forum_id, - 'icon' => $request->variable('icon', 0)) - ); - - if (confirm_box(true)) - { - if ($action == 'split_beyond') - { - $sort_days = $total = 0; - $sort_key = $sort_dir = ''; - $sort_by_sql = $sort_order_sql = array(); - phpbb_mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); - - $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; - - if ($sort_order_sql[0] == 'u') - { - $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE p.topic_id = $topic_id - AND p.poster_id = u.user_id - $limit_time_sql - ORDER BY $sort_order_sql"; - } - else - { - $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility - FROM ' . POSTS_TABLE . " p - WHERE p.topic_id = $topic_id - $limit_time_sql - ORDER BY $sort_order_sql"; - } - $result = $db->sql_query_limit($sql, 0, $start); - - $store = false; - $post_id_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - // If split from selected post (split_beyond), we split the unapproved items too. - if (($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $row['forum_id'])) - { -// continue; - } - - // Start to store post_ids as soon as we see the first post that was selected - if ($row['post_id'] == $post_id) - { - $store = true; - } - - if ($store) - { - $post_id_list[] = $row['post_id']; - } - } - $db->sql_freeresult($result); - } - - if (!count($post_id_list)) - { - trigger_error('NO_POST_SELECTED'); - } - - $icon_id = $request->variable('icon', 0); - - $sql_ary = array( - 'forum_id' => $to_forum_id, - 'topic_title' => $subject, - 'icon_id' => $icon_id, - 'topic_visibility' => 1 - ); - - $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $to_topic_id = $db->sql_nextid(); - move_posts($post_id_list, $to_topic_id); - - $topic_info = phpbb_get_topic_data(array($topic_id)); - $topic_info = $topic_info[$topic_id]; - - $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 . " - SET post_subject = '" . $db->sql_escape($subject) . "' - WHERE post_id = {$post_id_list[0]}"; - $db->sql_query($sql); - - // Grab data for first post in split topic - $sql_array = array( - 'SELECT' => 'p.post_id, p.forum_id, p.poster_id, p.post_text, f.enable_indexing', - 'FROM' => array( - POSTS_TABLE => 'p', - ), - 'LEFT_JOIN' => array( - array( - 'FROM' => array(FORUMS_TABLE => 'f'), - 'ON' => 'p.forum_id = f.forum_id', - ) - ), - 'WHERE' => "post_id = {$post_id_list[0]}", - ); - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query($sql); - $first_post_data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Index first post as if it were edited - if ($first_post_data['enable_indexing']) - { - // Select the search method and do some additional checks to ensure it can actually be utilised - $search_type = $config['search_type']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if ($error) - { - trigger_error($error); - } - - $search->index('edit', $first_post_data['post_id'], $first_post_data['post_text'], $subject, $first_post_data['poster_id'], $first_post_data['forum_id']); - } - - // Copy topic subscriptions to new topic - $sql = 'SELECT user_id, notify_status - FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'topic_id' => (int) $to_topic_id, - 'user_id' => (int) $row['user_id'], - 'notify_status' => (int) $row['notify_status'], - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary); - } - - // Copy bookmarks to new topic - $sql = 'SELECT user_id - FROM ' . BOOKMARKS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_ary[] = array( - 'topic_id' => (int) $to_topic_id, - 'user_id' => (int) $row['user_id'], - ); - } - $db->sql_freeresult($result); - - if (count($sql_ary)) - { - $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); - } - - $success_msg = 'TOPIC_SPLIT_SUCCESS'; - - // Update forum statistics - $config->increment('num_topics', 1, false); - - // Link back to both topics - $return_link = sprintf($user->lang['RETURN_TOPIC'], '', '') . '

' . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); - $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&t=$to_topic_id"); - $redirect = reapply_sid($redirect); - - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . $return_link); - } - else - { - confirm_box(false, ($action == 'split_all') ? 'SPLIT_TOPIC_ALL' : 'SPLIT_TOPIC_BEYOND', $s_hidden_fields); - } -} - -/** -* Merge selected posts into selected topic -*/ -function merge_posts($topic_id, $to_topic_id) -{ - global $db, $template, $user, $phpEx, $phpbb_root_path, $phpbb_log, $request, $phpbb_dispatcher; - - if (!$to_topic_id) - { - $template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']); - return; - } - - $sync_topics = array($topic_id, $to_topic_id); - - $topic_data = phpbb_get_topic_data($sync_topics, 'm_merge'); - - if (!count($topic_data) || empty($topic_data[$to_topic_id])) - { - $template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']); - return; - } - - $sync_forums = array(); - foreach ($topic_data as $data) - { - $sync_forums[$data['forum_id']] = $data['forum_id']; - } - - $topic_data = $topic_data[$to_topic_id]; - - $post_id_list = $request->variable('post_id_list', array(0)); - $start = $request->variable('start', 0); - - if (!count($post_id_list)) - { - $template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']); - return; - } - - if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_merge'))) - { - return; - } - - $redirect = $request->variable('redirect', build_url(array('quickmod'))); - - $s_hidden_fields = build_hidden_fields(array( - 'i' => 'main', - 'post_id_list' => $post_id_list, - 'to_topic_id' => $to_topic_id, - 'mode' => 'topic_view', - 'action' => 'merge_posts', - 'start' => $start, - 'redirect' => $redirect, - 't' => $topic_id) - ); - $return_link = ''; - - if (confirm_box(true)) - { - $to_forum_id = $topic_data['forum_id']; - - move_posts($post_id_list, $to_topic_id, false); - - $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'; - - // Does the original topic still exist? If yes, link back to it - $sql = 'SELECT forum_id - FROM ' . POSTS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $return_link .= sprintf($user->lang['RETURN_TOPIC'], '', ''); - } - else - { - if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status')) - { - include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx); - } - - // If the topic no longer exist, we will update the topic watch table. - phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', array($topic_id), $to_topic_id); - - // If the topic no longer exist, we will update the bookmarks table. - phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', array($topic_id), $to_topic_id); - } - - // Re-sync the topics and forums because the auto-sync was deactivated in the call of move_posts() - sync('topic_reported', 'topic_id', $sync_topics); - sync('topic_attachment', 'topic_id', $sync_topics); - sync('topic', 'topic_id', $sync_topics, true); - sync('forum', 'forum_id', $sync_forums, true, true); - - // Link to the new topic - $return_link .= (($return_link) ? '

' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); - $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&t=$to_topic_id"); - $redirect = reapply_sid($redirect); - - /** - * Perform additional actions after merging posts. - * - * @event core.mcp_topics_merge_posts_after - * @var int topic_id The topic ID from which posts are being moved - * @var int to_topic_id The topic ID to which posts are being moved - * @since 3.1.11-RC1 - */ - $vars = array( - 'topic_id', - 'to_topic_id', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_topics_merge_posts_after', compact($vars))); - - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '

' . $return_link); - } - else - { - confirm_box(false, 'MERGE_POSTS', $s_hidden_fields); - } -} diff --git a/install/update/old/includes/mcp/mcp_warn.php b/install/update/old/includes/mcp/mcp_warn.php deleted file mode 100644 index df17513..0000000 --- a/install/update/old/includes/mcp/mcp_warn.php +++ /dev/null @@ -1,610 +0,0 @@ - -* @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; -} - -/** -* mcp_warn -* Handling warning the users -*/ -class mcp_warn -{ - var $p_master; - var $u_action; - - function __construct($p_master) - { - $this->p_master = $p_master; - } - - function main($id, $mode) - { - global $request; - - $action = $request->variable('action', array('' => '')); - - if (is_array($action)) - { - list($action, ) = each($action); - } - - $this->page_title = 'MCP_WARN'; - - add_form_key('mcp_warn'); - - switch ($mode) - { - case 'front': - $this->mcp_warn_front_view(); - $this->tpl_name = 'mcp_warn_front'; - break; - - case 'list': - $this->mcp_warn_list_view($action); - $this->tpl_name = 'mcp_warn_list'; - break; - - case 'warn_post': - $this->mcp_warn_post_view($action); - $this->tpl_name = 'mcp_warn_post'; - break; - - case 'warn_user': - $this->mcp_warn_user_view($action); - $this->tpl_name = 'mcp_warn_user'; - break; - } - } - - /** - * Generates the summary on the main page of the warning module - */ - function mcp_warn_front_view() - { - 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&form=mcp&field=username&select_single=true'), - 'U_POST_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user'), - )); - - // Obtain a list of the 5 naughtiest users.... - // These are the 5 users with the highest warning count - $highest = array(); - $count = 0; - - view_warned_users($highest, $count, 5); - - foreach ($highest as $row) - { - $template->assign_block_vars('highest', array( - 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - - 'WARNING_TIME' => $user->format_date($row['user_last_warning']), - 'WARNINGS' => $row['user_warnings'], - )); - } - - // And now the 5 most recent users to get in trouble - $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_colour, u.user_warnings, w.warning_time - FROM ' . USERS_TABLE . ' u, ' . WARNINGS_TABLE . ' w - WHERE u.user_id = w.user_id - ORDER BY w.warning_time DESC'; - $result = $db->sql_query_limit($sql, 5); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('latest', array( - 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - - 'WARNING_TIME' => $user->format_date($row['warning_time']), - 'WARNINGS' => $row['user_warnings'], - )); - } - $db->sql_freeresult($result); - } - - /** - * Lists all users with warnings - */ - function mcp_warn_list_view($action) - { - global $phpEx, $phpbb_root_path, $config, $phpbb_container; - global $template, $user, $auth, $request; - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - $user->add_lang('memberlist'); - - $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']); - $sort_by_sql = array('a' => 'username_clean', 'b' => 'user_last_warning', 'c' => 'user_warnings'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $st, $sk, $sd, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - - // Define where and sort sql for use in displaying logs - $sql_where = ($st) ? (time() - ($st * 86400)) : 0; - $sql_sort = $sort_by_sql[$sk] . ' ' . (($sd == 'd') ? 'DESC' : 'ASC'); - - $users = array(); - $user_count = 0; - - view_warned_users($users, $user_count, $config['topics_per_page'], $start, $sql_where, $sql_sort); - - foreach ($users as $row) - { - $template->assign_block_vars('user', array( - 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - - 'WARNING_TIME' => $user->format_date($row['user_last_warning']), - 'WARNINGS' => $row['user_warnings'], - )); - } - - $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=warn&mode=list&st=$st&sk=$sk&sd=$sd"); - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $user_count, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'U_POST_ACTION' => $this->u_action, - 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - - 'TOTAL_USERS' => $user->lang('LIST_USERS', (int) $user_count), - )); - } - - /** - * Handles warning the user when the warning is for a specific post - */ - function mcp_warn_post_view($action) - { - global $phpEx, $phpbb_root_path, $config, $request; - global $template, $db, $user, $phpbb_dispatcher; - - $post_id = $request->variable('p', 0); - $forum_id = $request->variable('f', 0); - $notify = (isset($_REQUEST['notify_user'])) ? true : false; - $warning = $request->variable('warning', '', true); - - $sql = 'SELECT u.*, p.* - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE p.post_id = $post_id - AND u.user_id = p.poster_id"; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error('NO_POST'); - } - - // There is no point issuing a warning to ignored users (ie anonymous and bots) - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error('CANNOT_WARN_ANONYMOUS'); - } - - // Prevent someone from warning themselves - if ($user_row['user_id'] == $user->data['user_id']) - { - trigger_error('CANNOT_WARN_SELF'); - } - - // Check if there is already a warning for this post to prevent multiple - // warnings for the same offence - $sql = 'SELECT post_id - FROM ' . WARNINGS_TABLE . " - WHERE post_id = $post_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - trigger_error('ALREADY_WARNED'); - } - - $user_id = $user_row['user_id']; - - if (strpos($this->u_action, "&f=$forum_id&p=$post_id") === false) - { - $this->p_master->adjust_url("&f=$forum_id&p=$post_id"); - $this->u_action .= "&f=$forum_id&p=$post_id"; - } - - // Check if can send a notification - if ($config['allow_privmsg']) - { - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($user_row); - $s_can_notify = ($auth2->acl_get('u_readpm')) ? true : false; - unset($auth2); - } - else - { - $s_can_notify = false; - } - - // Prevent against clever people - if ($notify && !$s_can_notify) - { - $notify = false; - } - - if ($warning && $action == 'add_warning') - { - if (check_form_key('mcp_warn')) - { - $s_mcp_warn_post = true; - - /** - * Event for before warning a user for a post. - * - * @event core.mcp_warn_post_before - * @var array user_row The entire user row - * @var string warning The warning message - * @var bool notify If true, we notify the user for the warning - * @var int post_id The post id for which the warning is added - * @var bool s_mcp_warn_post If true, we add the warning else we omit it - * @since 3.1.0-b4 - */ - $vars = array( - 'user_row', - 'warning', - 'notify', - 'post_id', - 's_mcp_warn_post', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_warn_post_before', compact($vars))); - - if ($s_mcp_warn_post) - { - add_warning($user_row, $warning, $notify, $post_id); - $message = $user->lang['USER_WARNING_ADDED']; - - /** - * Event for after warning a user for a post. - * - * @event core.mcp_warn_post_after - * @var array user_row The entire user row - * @var string warning The warning message - * @var bool notify If true, the user was notified for the warning - * @var int post_id The post id for which the warning is added - * @var string message Message displayed to the moderator - * @since 3.1.0-b4 - */ - $vars = array( - 'user_row', - 'warning', - 'notify', - 'post_id', - 'message', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_warn_post_after', compact($vars))); - } - } - else - { - $message = $user->lang['FORM_INVALID']; - } - - if (!empty($message)) - { - $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=notes&mode=user_notes&u=$user_id"); - meta_refresh(2, $redirect); - trigger_error($message . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - } - - // OK, they didn't submit a warning so lets build the page for them to do so - - // We want to make the message available here as a reminder - // Parse the message and subject - $parse_flags = OPTION_FLAG_SMILIES | ($user_row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); - $message = generate_text_for_display($user_row['post_text'], $user_row['bbcode_uid'], $user_row['bbcode_bitfield'], $parse_flags, true); - - // Generate the appropriate user information for the user we are looking at - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $user_rank_data = phpbb_get_user_rank($user_row, $user_row['user_posts']); - $avatar_img = phpbb_get_user_avatar($user_row); - - $template->assign_vars(array( - 'U_POST_ACTION' => $this->u_action, - - 'POST' => $message, - 'USERNAME' => $user_row['username'], - 'USER_COLOR' => (!empty($user_row['user_colour'])) ? $user_row['user_colour'] : '', - 'RANK_TITLE' => $user_rank_data['title'], - 'JOINED' => $user->format_date($user_row['user_regdate']), - 'POSTS' => ($user_row['user_posts']) ? $user_row['user_posts'] : 0, - 'WARNINGS' => ($user_row['user_warnings']) ? $user_row['user_warnings'] : 0, - - 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $user_rank_data['img'], - - 'L_WARNING_POST_DEFAULT' => sprintf($user->lang['WARNING_POST_DEFAULT'], generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&p=$post_id#p$post_id"), - - 'S_CAN_NOTIFY' => $s_can_notify, - )); - } - - /** - * Handles warning the user - */ - function mcp_warn_user_view($action) - { - global $phpEx, $phpbb_root_path, $config, $request; - global $template, $db, $user, $phpbb_dispatcher; - - $user_id = $request->variable('u', 0); - $username = $request->variable('username', '', true); - $notify = (isset($_REQUEST['notify_user'])) ? true : false; - $warning = $request->variable('warning', '', true); - - $sql_where = ($user_id) ? "user_id = $user_id" : "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE ' . $sql_where; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error('NO_USER'); - } - - // Prevent someone from warning themselves - if ($user_row['user_id'] == $user->data['user_id']) - { - trigger_error('CANNOT_WARN_SELF'); - } - - $user_id = $user_row['user_id']; - - if (strpos($this->u_action, "&u=$user_id") === false) - { - $this->p_master->adjust_url('&u=' . $user_id); - $this->u_action .= "&u=$user_id"; - } - - // Check if can send a notification - if ($config['allow_privmsg']) - { - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($user_row); - $s_can_notify = ($auth2->acl_get('u_readpm')) ? true : false; - unset($auth2); - } - else - { - $s_can_notify = false; - } - - // Prevent against clever people - if ($notify && !$s_can_notify) - { - $notify = false; - } - - if ($warning && $action == 'add_warning') - { - if (check_form_key('mcp_warn')) - { - $s_mcp_warn_user = true; - - /** - * Event for before warning a user from MCP. - * - * @event core.mcp_warn_user_before - * @var array user_row The entire user row - * @var string warning The warning message - * @var bool notify If true, we notify the user for the warning - * @var bool s_mcp_warn_user If true, we add the warning else we omit it - * @since 3.1.0-b4 - */ - $vars = array( - 'user_row', - 'warning', - 'notify', - 's_mcp_warn_user', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_warn_user_before', compact($vars))); - - if ($s_mcp_warn_user) - { - add_warning($user_row, $warning, $notify); - $message = $user->lang['USER_WARNING_ADDED']; - - /** - * Event for after warning a user from MCP. - * - * @event core.mcp_warn_user_after - * @var array user_row The entire user row - * @var string warning The warning message - * @var bool notify If true, the user was notified for the warning - * @var string message Message displayed to the moderator - * @since 3.1.0-b4 - */ - $vars = array( - 'user_row', - 'warning', - 'notify', - 'message', - ); - extract($phpbb_dispatcher->trigger_event('core.mcp_warn_user_after', compact($vars))); - } - } - else - { - $message = $user->lang['FORM_INVALID']; - } - - if (!empty($message)) - { - $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=notes&mode=user_notes&u=$user_id"); - meta_refresh(2, $redirect); - trigger_error($message . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - } - - // Generate the appropriate user information for the user we are looking at - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - $user_rank_data = phpbb_get_user_rank($user_row, $user_row['user_posts']); - $avatar_img = phpbb_get_user_avatar($user_row); - - // OK, they didn't submit a warning so lets build the page for them to do so - $template->assign_vars(array( - 'U_POST_ACTION' => $this->u_action, - - 'RANK_TITLE' => $user_rank_data['title'], - 'JOINED' => $user->format_date($user_row['user_regdate']), - 'POSTS' => ($user_row['user_posts']) ? $user_row['user_posts'] : 0, - 'WARNINGS' => ($user_row['user_warnings']) ? $user_row['user_warnings'] : 0, - - 'USERNAME_FULL' => get_username_string('full', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), - 'USERNAME_COLOUR' => get_username_string('colour', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), - 'USERNAME' => get_username_string('username', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), - 'U_PROFILE' => get_username_string('profile', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), - - 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $user_rank_data['img'], - - 'S_CAN_NOTIFY' => $s_can_notify, - )); - - return $user_id; - } -} - -/** -* Insert the warning into the database -*/ -function add_warning($user_row, $warning, $send_pm = true, $post_id = 0) -{ - global $phpEx, $phpbb_root_path, $config, $phpbb_log; - global $db, $user; - - if ($send_pm) - { - include_once($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx); - - // Attempt to translate warning to language of user being warned if user's language differs from issuer's language - if ($user_row['user_lang'] != $user->lang_name) - { - $lang = array(); - - $user_row['user_lang'] = (file_exists($phpbb_root_path . 'language/' . basename($user_row['user_lang']) . "/mcp." . $phpEx)) ? $user_row['user_lang'] : $config['default_lang']; - include($phpbb_root_path . 'language/' . basename($user_row['user_lang']) . "/mcp." . $phpEx); - - $warn_pm_subject = $lang['WARNING_PM_SUBJECT']; - $warn_pm_body = sprintf($lang['WARNING_PM_BODY'], $warning); - - unset($lang); - } - else - { - $warn_pm_subject = $user->lang('WARNING_PM_SUBJECT'); - $warn_pm_body = $user->lang('WARNING_PM_BODY', $warning); - } - - $message_parser = new parse_message(); - - $message_parser->message = $warn_pm_body; - $message_parser->parse(true, true, true, false, false, true, true); - - $pm_data = array( - 'from_user_id' => $user->data['user_id'], - 'from_user_ip' => $user->ip, - 'from_username' => $user->data['username'], - 'enable_sig' => false, - 'enable_bbcode' => true, - 'enable_smilies' => true, - 'enable_urls' => false, - 'icon_id' => 0, - 'bbcode_bitfield' => $message_parser->bbcode_bitfield, - 'bbcode_uid' => $message_parser->bbcode_uid, - 'message' => $message_parser->message, - 'address_list' => array('u' => array($user_row['user_id'] => 'to')), - ); - - submit_pm('post', $warn_pm_subject, $pm_data, false); - } - - $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'], - 'post_id' => $post_id, - 'log_id' => $log_id, - 'warning_time' => time(), - ); - - $db->sql_query('INSERT INTO ' . WARNINGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_warnings = user_warnings + 1, - user_last_warning = ' . time() . ' - WHERE user_id = ' . $user_row['user_id']; - $db->sql_query($sql); - - // We add this to the mod log too for moderators to see that a specific user got warned. - $sql = 'SELECT forum_id, topic_id - FROM ' . POSTS_TABLE . ' - WHERE post_id = ' . $post_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $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/install/update/old/includes/message_parser.php b/install/update/old/includes/message_parser.php deleted file mode 100644 index 0b79cca..0000000 --- a/install/update/old/includes/message_parser.php +++ /dev/null @@ -1,2059 +0,0 @@ - -* @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; -} - -if (!class_exists('bbcode')) -{ - // The following lines are for extensions which include message_parser.php - // while $phpbb_root_path and $phpEx are out of the script scope - // which may lead to the 'Undefined variable' and 'failed to open stream' errors - if (!isset($phpbb_root_path)) - { - global $phpbb_root_path; - } - - if (!isset($phpEx)) - { - global $phpEx; - } - - include($phpbb_root_path . 'includes/bbcode.' . $phpEx); -} - -/** -* BBCODE FIRSTPASS -* BBCODE first pass class (functions for parsing messages for db storage) -*/ -class bbcode_firstpass extends bbcode -{ - var $message = ''; - var $warn_msg = array(); - var $parsed_items = array(); - - /** - * Parse BBCode - */ - function parse_bbcode() - { - if (!$this->bbcodes) - { - $this->bbcode_init(); - } - - global $user; - - $this->bbcode_bitfield = ''; - $bitfield = new bitfield(); - - foreach ($this->bbcodes as $bbcode_name => $bbcode_data) - { - if (isset($bbcode_data['disabled']) && $bbcode_data['disabled']) - { - foreach ($bbcode_data['regexp'] as $regexp => $replacement) - { - if (preg_match($regexp, $this->message)) - { - $this->warn_msg[] = sprintf($user->lang['UNAUTHORISED_BBCODE'] , '[' . $bbcode_name . ']'); - continue; - } - } - } - else - { - foreach ($bbcode_data['regexp'] as $regexp => $replacement) - { - // The pattern gets compiled and cached by the PCRE extension, - // it should not demand recompilation - if (preg_match($regexp, $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']); - } - } - } - } - - $this->bbcode_bitfield = $bitfield->get_base64(); - } - - /** - * Prepare some bbcodes for better parsing - */ - function prepare_bbcodes() - { - // Ok, seems like users instead want the no-parsing of urls, smilies, etc. after and before and within quote tags being tagged as "not a bug". - // Fine by me ;) Will ease our live... but do not come back and cry at us, we won't hear you. - - /* Add newline at the end and in front of each quote block to prevent parsing errors (urls, smilies, etc.) - if (strpos($this->message, '[quote') !== false && strpos($this->message, '[/quote]') !== false) - { - $this->message = str_replace("\r\n", "\n", $this->message); - - // We strip newlines and spaces after and before quotes in quotes (trimming) and then add exactly one newline - $this->message = preg_replace('#\[quote(=".*?")?\]\s*(.*?)\s*\[/quote\]#siu', '[quote\1]' . "\n" . '\2' ."\n[/quote]", $this->message); - } - */ - - // Add other checks which needs to be placed before actually parsing anything (be it bbcodes, smilies, urls...) - } - - /** - * Init bbcode data for later parsing - */ - function bbcode_init($allow_custom_bbcode = true) - { - global $phpbb_dispatcher; - - 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. - // To parse multiline URL we enable dotall option setting only for URL text - // but not for link itself, thus [url][/url] is not affected. - // - // 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' => 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(?:="(.*?)")?\](.+)\[/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 - $this->parsed_items = array(); - - foreach ($this->bbcodes as $tag => $bbcode_data) - { - $this->parsed_items[$tag] = 0; - } - - if (!$allow_custom_bbcode) - { - return; - } - - if (!is_array($rowset)) - { - global $db; - $rowset = array(); - - $sql = 'SELECT * - FROM ' . BBCODES_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $rowset[] = $row; - } - $db->sql_freeresult($result); - } - - foreach ($rowset as $row) - { - $this->bbcodes[$row['bbcode_tag']] = array( - 'bbcode_id' => (int) $row['bbcode_id'], - 'regexp' => array($row['first_pass_match'] => str_replace('$uid', $this->bbcode_uid, $row['first_pass_replace'])) - ); - } - - $bbcodes = $this->bbcodes; - - /** - * Event to modify the bbcode data for later parsing - * - * @event core.modify_bbcode_init - * @var array bbcodes Array of bbcode data for use in parsing - * @var array rowset Array of bbcode data from the database - * @since 3.1.0-a3 - */ - $vars = array('bbcodes', 'rowset'); - extract($phpbb_dispatcher->trigger_event('core.modify_bbcode_init', compact($vars))); - - $this->bbcodes = $bbcodes; - } - - /** - * Making some pre-checks for bbcodes as well as increasing the number of parsed items - */ - function check_bbcode($bbcode, &$in) - { - // when using the /e modifier, preg_replace slashes double-quotes but does not - // seem to slash anything else - $in = str_replace("\r\n", "\n", str_replace('\"', '"', $in)); - - // Trimming here to make sure no empty bbcodes are parsed accidently - if (trim($in) == '') - { - return false; - } - - $this->parsed_items[$bbcode]++; - - return true; - } - - /** - * Transform some characters in valid bbcodes - */ - function bbcode_specialchars($text) - { - $str_from = array('<', '>', '[', ']', '.', ':'); - $str_to = array('<', '>', '[', ']', '.', ':'); - - return str_replace($str_from, $str_to, $text); - } - - /** - * Parse size tag - */ - function bbcode_size($stx, $in) - { - global $user, $config; - - if (!$this->check_bbcode('size', $in)) - { - return $in; - } - - if ($config['max_' . $this->mode . '_font_size'] && $config['max_' . $this->mode . '_font_size'] < $stx) - { - $this->warn_msg[] = $user->lang('MAX_FONT_SIZE_EXCEEDED', (int) $config['max_' . $this->mode . '_font_size']); - - return '[size=' . $stx . ']' . $in . '[/size]'; - } - - // Do not allow size=0 - if ($stx <= 0) - { - return '[size=' . $stx . ']' . $in . '[/size]'; - } - - return '[size=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/size:' . $this->bbcode_uid . ']'; - } - - /** - * Parse color tag - */ - function bbcode_color($stx, $in) - { - if (!$this->check_bbcode('color', $in)) - { - return $in; - } - - return '[color=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/color:' . $this->bbcode_uid . ']'; - } - - /** - * Parse u tag - */ - function bbcode_underline($in) - { - if (!$this->check_bbcode('u', $in)) - { - return $in; - } - - return '[u:' . $this->bbcode_uid . ']' . $in . '[/u:' . $this->bbcode_uid . ']'; - } - - /** - * Parse b tag - */ - function bbcode_strong($in) - { - if (!$this->check_bbcode('b', $in)) - { - return $in; - } - - return '[b:' . $this->bbcode_uid . ']' . $in . '[/b:' . $this->bbcode_uid . ']'; - } - - /** - * Parse i tag - */ - function bbcode_italic($in) - { - if (!$this->check_bbcode('i', $in)) - { - return $in; - } - - return '[i:' . $this->bbcode_uid . ']' . $in . '[/i:' . $this->bbcode_uid . ']'; - } - - /** - * Parse img tag - */ - function bbcode_img($in) - { - global $user, $config; - - if (!$this->check_bbcode('img', $in)) - { - return $in; - } - - $in = trim($in); - $error = false; - - $in = str_replace(' ', '%20', $in); - - // Checking urls - if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $in) && !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $in)) - { - return '[img]' . $in . '[/img]'; - } - - // Try to cope with a common user error... not specifying a protocol but only a subdomain - if (!preg_match('#^[a-z0-9]+://#i', $in)) - { - $in = 'http://' . $in; - } - - if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width']) - { - $imagesize = new \FastImageSize\FastImageSize(); - $size_info = $imagesize->getImageSize(htmlspecialchars_decode($in)); - - 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'] < $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'] < $size_info['width']) - { - $error = true; - $this->warn_msg[] = $user->lang('MAX_IMG_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']); - } - } - } - - if ($error || $this->path_in_domain($in)) - { - return '[img]' . $in . '[/img]'; - } - - return '[img:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/img:' . $this->bbcode_uid . ']'; - } - - /** - * Parse flash tag - */ - function bbcode_flash($width, $height, $in) - { - global $user, $config; - - if (!$this->check_bbcode('flash', $in)) - { - return $in; - } - - $in = trim($in); - $error = false; - - // Do not allow 0-sizes generally being entered - if ($width <= 0 || $height <= 0) - { - return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; - } - - $in = str_replace(' ', '%20', $in); - - // Make sure $in is a URL. - if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $in) && - !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $in)) - { - return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; - } - - // Apply the same size checks on flash files as on images - if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width']) - { - if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $height) - { - $error = true; - $this->warn_msg[] = $user->lang('MAX_FLASH_HEIGHT_EXCEEDED', (int) $config['max_' . $this->mode . '_img_height']); - } - - if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $width) - { - $error = true; - $this->warn_msg[] = $user->lang('MAX_FLASH_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']); - } - } - - if ($error || $this->path_in_domain($in)) - { - return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; - } - - return '[flash=' . $width . ',' . $height . ':' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/flash:' . $this->bbcode_uid . ']'; - } - - /** - * Parse inline attachments [ia] - */ - function bbcode_attachment($stx, $in) - { - if (!$this->check_bbcode('attachment', $in)) - { - return $in; - } - - return '[attachment=' . $stx . ':' . $this->bbcode_uid . ']' . trim($in) . '[/attachment:' . $this->bbcode_uid . ']'; - } - - /** - * Parse code text from code tag - * @access private - */ - function bbcode_parse_code($stx, &$code) - { - switch (strtolower($stx)) - { - case 'php': - - $remove_tags = false; - - $str_from = array('<', '>', '[', ']', '.', ':', ':'); - $str_to = array('<', '>', '[', ']', '.', ':', ':'); - $code = str_replace($str_from, $str_to, $code); - - if (!preg_match('/\<\?.*?\?\>/is', $code)) - { - $remove_tags = true; - $code = ""; - } - - $conf = array('highlight.bg', 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string'); - foreach ($conf as $ini_var) - { - @ini_set($ini_var, str_replace('highlight.', 'syntax', $ini_var)); - } - - // Because highlight_string is specialcharing the text (but we already did this before), we have to reverse this in order to get correct results - $code = htmlspecialchars_decode($code); - $code = highlight_string($code, true); - - $str_from = array('', '', '','[', ']', '.', ':'); - $str_to = array('', '', '', '[', ']', '.', ':'); - - if ($remove_tags) - { - $str_from[] = '<?php '; - $str_to[] = ''; - $str_from[] = '<?php '; - $str_to[] = ''; - } - - $code = str_replace($str_from, $str_to, $code); - $code = preg_replace('#^()\n?(.*?)\n?()$#is', '$1$2$3', $code); - - if ($remove_tags) - { - $code = preg_replace('#()?\?>()#', '$1 $2', $code); - } - - $code = preg_replace('#^(.*)#s', '$2', $code); - $code = preg_replace('#(?:\s++| )*+$#u', '', $code); - - // remove newline at the end - if (!empty($code) && substr($code, -1) == "\n") - { - $code = substr($code, 0, -1); - } - - return "[code=$stx:" . $this->bbcode_uid . ']' . $code . '[/code:' . $this->bbcode_uid . ']'; - break; - - default: - return '[code:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($code) . '[/code:' . $this->bbcode_uid . ']'; - break; - } - } - - /** - * Parse code tag - * Expects the argument to start right after the opening [code] tag and to end with [/code] - */ - function bbcode_code($stx, $in) - { - if (!$this->check_bbcode('code', $in)) - { - return $in; - } - - // We remove the hardcoded elements from the code block here because it is not used in code blocks - // Having it here saves us one preg_replace per message containing [code] blocks - // Additionally, magic url parsing should go after parsing bbcodes, but for safety those are stripped out too... - $htm_match = get_preg_expression('bbcode_htm'); - unset($htm_match[4], $htm_match[5]); - $htm_replace = array('\1', '\1', '\2', '\1'); - - $out = $code_block = ''; - $open = 1; - - while ($in) - { - // Determine position and tag length of next code block - preg_match('#(.*?)(\[code(?:=([a-z]+))?\])(.+)#is', $in, $buffer); - $pos = (isset($buffer[1])) ? strlen($buffer[1]) : false; - $tag_length = (isset($buffer[2])) ? strlen($buffer[2]) : false; - - // Determine position of ending code tag - $pos2 = stripos($in, '[/code]'); - - // Which is the next block, ending code or code block - if ($pos !== false && $pos < $pos2) - { - // Open new block - if (!$open) - { - $out .= substr($in, 0, $pos); - $in = substr($in, $pos); - $stx = (isset($buffer[3])) ? $buffer[3] : ''; - $code_block = ''; - } - else - { - // Already opened block, just append to the current block - $code_block .= substr($in, 0, $pos) . ((isset($buffer[2])) ? $buffer[2] : ''); - $in = substr($in, $pos); - } - - $in = substr($in, $tag_length); - $open++; - } - else - { - // Close the block - if ($open == 1) - { - $code_block .= substr($in, 0, $pos2); - $code_block = preg_replace($htm_match, $htm_replace, $code_block); - - // Parse this code block - $out .= $this->bbcode_parse_code($stx, $code_block); - $code_block = ''; - $open--; - } - else if ($open) - { - // Close one open tag... add to the current code block - $code_block .= substr($in, 0, $pos2 + 7); - $open--; - } - else - { - // end code without opening code... will be always outside code block - $out .= substr($in, 0, $pos2 + 7); - } - - $in = substr($in, $pos2 + 7); - } - } - - // if now $code_block has contents we need to parse the remaining code while removing the last closing tag to match up. - if ($code_block) - { - $code_block = substr($code_block, 0, -7); - $code_block = preg_replace($htm_match, $htm_replace, $code_block); - - $out .= $this->bbcode_parse_code($stx, $code_block); - } - - return $out; - } - - /** - * Parse list bbcode - * Expects the argument to start with a tag - */ - function bbcode_parse_list($in) - { - if (!$this->check_bbcode('list', $in)) - { - return $in; - } - - // $tok holds characters to stop at. Since the string starts with a '[' we'll get everything up to the first ']' which should be the opening [list] tag - $tok = ']'; - $out = '['; - - // First character is [ - $in = substr($in, 1); - $list_end_tags = $item_end_tags = array(); - - do - { - $pos = strlen($in); - - for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i) - { - $tmp_pos = strpos($in, $tok[$i]); - - if ($tmp_pos !== false && $tmp_pos < $pos) - { - $pos = $tmp_pos; - } - } - - $buffer = substr($in, 0, $pos); - $tok = $in[$pos]; - - $in = substr($in, $pos + 1); - - if ($tok == ']') - { - // if $tok is ']' the buffer holds a tag - if (strtolower($buffer) == '/list' && count($list_end_tags)) - { - // valid [/list] tag, check nesting so that we don't hit false positives - 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) . ']['; - } - - $out .= array_pop($list_end_tags) . ']'; - $tok = '['; - } - else if (preg_match('#^list(=[0-9a-z]+)?$#i', $buffer, $m)) - { - // sub-list, add a closing tag - if (empty($m[1]) || preg_match('/^=(?:disc|square|circle)$/i', $m[1])) - { - array_push($list_end_tags, '/list:u:' . $this->bbcode_uid); - } - else - { - array_push($list_end_tags, '/list:o:' . $this->bbcode_uid); - } - $out .= 'list' . substr($buffer, 4) . ':' . $this->bbcode_uid . ']'; - $tok = '['; - } - else - { - if (($buffer == '*' || substr($buffer, -2) == '[*') && count($list_end_tags)) - { - // the buffer holds a bullet tag and we have a [list] tag open - if (count($item_end_tags) >= count($list_end_tags)) - { - if (substr($buffer, -2) == '[*') - { - $out .= substr($buffer, 0, -2) . '['; - } - // current li tag has not been closed - if (preg_match('/\n\[$/', $out, $m)) - { - $out = preg_replace('/\n\[$/', '[', $out); - $buffer = array_pop($item_end_tags) . "]\n[*:" . $this->bbcode_uid; - } - else - { - $buffer = array_pop($item_end_tags) . '][*:' . $this->bbcode_uid; - } - } - else - { - $buffer = '*:' . $this->bbcode_uid; - } - - $item_end_tags[] = '/*:m:' . $this->bbcode_uid; - } - else if ($buffer == '/*') - { - array_pop($item_end_tags); - $buffer = '/*:' . $this->bbcode_uid; - } - - $out .= $buffer . $tok; - $tok = '[]'; - } - } - else - { - // Not within a tag, just add buffer to the return string - $out .= $buffer . $tok; - $tok = ($tok == '[') ? ']' : '[]'; - } - } - while ($in); - - // do we have some tags open? close them now - if (count($item_end_tags)) - { - $out .= '[' . implode('][', $item_end_tags) . ']'; - } - if (count($list_end_tags)) - { - $out .= '[' . implode('][', $list_end_tags) . ']'; - } - - return $out; - } - - /** - * Parse quote bbcode - * Expects the argument to start with a tag - */ - function bbcode_quote($in) - { - $in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in))); - - if (!$in) - { - return ''; - } - - // To let the parser not catch tokens within quote_username quotes we encode them before we start this... - $in = preg_replace_callback('#quote="(.*?)"\]#i', function ($match) { - return 'quote="' . str_replace(array('[', ']', '\\\"'), array('[', ']', '\"'), $match[1]) . '"]'; - }, $in); - - $tok = ']'; - $out = '['; - - $in = substr($in, 1); - $close_tags = $error_ary = array(); - $buffer = ''; - - do - { - $pos = strlen($in); - for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i) - { - $tmp_pos = strpos($in, $tok[$i]); - if ($tmp_pos !== false && $tmp_pos < $pos) - { - $pos = $tmp_pos; - } - } - - $buffer .= substr($in, 0, $pos); - $tok = $in[$pos]; - $in = substr($in, $pos + 1); - - if ($tok == ']') - { - if (strtolower($buffer) == '/quote' && count($close_tags) && substr($out, -1, 1) == '[') - { - // we have found a closing tag - $out .= array_pop($close_tags) . ']'; - $tok = '['; - $buffer = ''; - - /* Add space at the end of the closing tag if not happened before to allow following urls/smilies to be parsed correctly - * Do not try to think for the user. :/ Do not parse urls/smilies if there is no space - is the same as with other bbcodes too. - * Also, we won't have any spaces within $in anyway, only adding up spaces -> #10982 - if (!$in || $in[0] !== ' ') - { - $out .= ' '; - }*/ - } - else if (preg_match('#^quote(?:="(.*?)")?$#is', $buffer, $m) && substr($out, -1, 1) == '[') - { - $this->parsed_items['quote']++; - array_push($close_tags, '/quote:' . $this->bbcode_uid); - - if (isset($m[1]) && $m[1]) - { - $username = str_replace(array('[', ']'), array('[', ']'), $m[1]); - $username = preg_replace('#\[(?!b|i|u|color|url|email|/b|/i|/u|/color|/url|/email)#iU', '[$1', $username); - - $end_tags = array(); - $error = false; - - preg_match_all('#\[((?:/)?(?:[a-z]+))#i', $username, $tags); - foreach ($tags[1] as $tag) - { - if ($tag[0] != '/') - { - $end_tags[] = '/' . $tag; - } - else - { - $end_tag = array_pop($end_tags); - $error = ($end_tag != $tag) ? true : false; - } - } - - if ($error) - { - $username = $m[1]; - } - - $out .= 'quote="' . $username . '":' . $this->bbcode_uid . ']'; - } - else - { - $out .= 'quote:' . $this->bbcode_uid . ']'; - } - - $tok = '['; - $buffer = ''; - } - else if (preg_match('#^quote="(.*?)#is', $buffer, $m)) - { - // the buffer holds an invalid opening tag - $buffer .= ']'; - } - else - { - $out .= $buffer . $tok; - $tok = '[]'; - $buffer = ''; - } - } - else - { -/** -* Old quote code working fine, but having errors listed in bug #3572 -* -* $out .= $buffer . $tok; -* $tok = ($tok == '[') ? ']' : '[]'; -* $buffer = ''; -*/ - - $out .= $buffer . $tok; - - if ($tok == '[') - { - // Search the text for the next tok... if an ending quote comes first, then change tok to [] - $pos1 = stripos($in, '[/quote'); - // If the token ] comes first, we change it to ] - $pos2 = strpos($in, ']'); - // If the token [ comes first, we change it to [ - $pos3 = strpos($in, '['); - - if ($pos1 !== false && ($pos2 === false || $pos1 < $pos2) && ($pos3 === false || $pos1 < $pos3)) - { - $tok = '[]'; - } - else if ($pos3 !== false && ($pos2 === false || $pos3 < $pos2)) - { - $tok = '['; - } - else - { - $tok = ']'; - } - } - else - { - $tok = '[]'; - } - $buffer = ''; - } - } - while ($in); - - $out .= $buffer; - - if (count($close_tags)) - { - $out .= '[' . implode('][', $close_tags) . ']'; - } - - foreach ($error_ary as $error_msg) - { - $this->warn_msg[] = $error_msg; - } - - return $out; - } - - /** - * Validate email - */ - function validate_email($var1, $var2) - { - $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1))); - $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2))); - - $txt = $var2; - $email = ($var1) ? $var1 : $var2; - - $validated = true; - - if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email)) - { - $validated = false; - } - - if (!$validated) - { - return '[email' . (($var1) ? "=$var1" : '') . ']' . $var2 . '[/email]'; - } - - $this->parsed_items['email']++; - - if ($var1) - { - $retval = '[email=' . $this->bbcode_specialchars($email) . ':' . $this->bbcode_uid . ']' . $txt . '[/email:' . $this->bbcode_uid . ']'; - } - else - { - $retval = '[email:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($email) . '[/email:' . $this->bbcode_uid . ']'; - } - - return $retval; - } - - /** - * Validate url - * - * @param string $var1 optional url parameter for url bbcode: [url(=$var1)]$var2[/url] - * @param string $var2 url bbcode content: [url(=$var1)]$var2[/url] - */ - function validate_url($var1, $var2) - { - $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1))); - $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2))); - - $url = ($var1) ? $var1 : $var2; - - if ($var1 && !$var2) - { - $var2 = $var1; - } - - if (!$url) - { - return '[url' . (($var1) ? '=' . $var1 : '') . ']' . $var2 . '[/url]'; - } - - $valid = false; - - $url = str_replace(' ', '%20', $url); - - // Checking urls - if (preg_match('#^' . get_preg_expression('url') . '$#iu', $url) || - preg_match('#^' . get_preg_expression('www_url') . '$#iu', $url) || - preg_match('#^' . preg_quote(generate_board_url(), '#') . get_preg_expression('relative_url') . '$#iu', $url)) - { - $valid = true; - } - - if ($valid) - { - $this->parsed_items['url']++; - - // if there is no scheme, then add http schema - if (!preg_match('#^[a-z][a-z\d+\-.]*:/{2}#i', $url)) - { - $url = 'http://' . $url; - } - - // Is this a link to somewhere inside this board? If so then remove the session id from the url - if (strpos($url, generate_board_url()) !== false && strpos($url, 'sid=') !== false) - { - $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}&/', '\1', $url); - $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}$/', '', $url); - $url = append_sid($url); - } - - return ($var1) ? '[url=' . $this->bbcode_specialchars($url) . ':' . $this->bbcode_uid . ']' . $var2 . '[/url:' . $this->bbcode_uid . ']' : '[url:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($url) . '[/url:' . $this->bbcode_uid . ']'; - } - - return '[url' . (($var1) ? '=' . $var1 : '') . ']' . $var2 . '[/url]'; - } - - /** - * Check if url is pointing to this domain/script_path/php-file - * - * @param string $url the url to check - * @return true if the url is pointing to this domain/script_path/php-file, false if not - * - * @access private - */ - function path_in_domain($url) - { - global $config, $phpEx, $user; - - if ($config['force_server_vars']) - { - $check_path = !empty($config['script_path']) ? $config['script_path'] : '/'; - } - else - { - $check_path = ($user->page['root_script_path'] != '/') ? substr($user->page['root_script_path'], 0, -1) : '/'; - } - - // Is the user trying to link to a php file in this domain and script path? - if (strpos($url, ".{$phpEx}") !== false && strpos($url, $check_path) !== false) - { - $server_name = $user->host; - - // Forcing server vars is the only way to specify/override the protocol - if ($config['force_server_vars'] || !$server_name) - { - $server_name = $config['server_name']; - } - - // Check again in correct order... - $pos_ext = strpos($url, ".{$phpEx}"); - $pos_path = strpos($url, $check_path); - $pos_domain = strpos($url, $server_name); - - if ($pos_domain !== false && $pos_path >= $pos_domain && $pos_ext >= $pos_path) - { - // Ok, actually we allow linking to some files (this may be able to be extended in some way later...) - if (strpos($url, '/' . $check_path . '/download/file.' . $phpEx) !== 0) - { - return false; - } - - return true; - } - } - - return false; - } -} - -/** -* Main message parser for posting, pm, etc. takes raw message -* and parses it for attachments, bbcode and smilies -*/ -class parse_message extends bbcode_firstpass -{ - var $attachment_data = array(); - var $filename_data = array(); - - // Helps ironing out user error - var $message_status = ''; - - var $allow_img_bbcode = true; - var $allow_flash_bbcode = true; - var $allow_quote_bbcode = true; - var $allow_url_bbcode = true; - - var $mode; - - /** - * The plupload object used for dealing with attachments - * @var \phpbb\plupload\plupload - */ - protected $plupload; - - /** - * Init - give message here or manually - */ - function __construct($message = '') - { - // Init BBCode UID - $this->bbcode_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN); - $this->message = $message; - } - - /** - * Parse Message - */ - 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, $user, $phpbb_dispatcher, $phpbb_container; - - $this->mode = $mode; - - foreach (array('chars', 'smilies', 'urls', 'font_size', 'img_height', 'img_width') as $key) - { - if (!isset($config['max_' . $mode . '_' . $key])) - { - $config['max_' . $mode . '_' . $key] = 0; - } - } - - $this->allow_img_bbcode = $allow_img_bbcode; - $this->allow_flash_bbcode = $allow_flash_bbcode; - $this->allow_quote_bbcode = $allow_quote_bbcode; - $this->allow_url_bbcode = $allow_url_bbcode; - - // If false, then $this->message won't be altered, the text will be returned instead. - if (!$update_this_message) - { - $tmp_message = $this->message; - $return_message = &$this->message; - } - - if ($this->message_status == 'display') - { - $this->decode_message(); - } - - // Store message length... - $message_length = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)); - - // Maximum message length check. 0 disables this check completely. - if ((int) $config['max_' . $mode . '_chars'] > 0 && $message_length > (int) $config['max_' . $mode . '_chars']) - { - $this->warn_msg[] = $user->lang('CHARS_' . strtoupper($mode) . '_CONTAINS', $message_length) . '
' . $user->lang('TOO_MANY_CHARS_LIMIT', (int) $config['max_' . $mode . '_chars']); - return (!$update_this_message) ? $return_message : $this->warn_msg; - } - - // Minimum message length check for post only - if ($mode === 'post') - { - if (!$message_length || $message_length < (int) $config['min_post_chars']) - { - $this->warn_msg[] = (!$message_length) ? $user->lang['TOO_FEW_CHARS'] : ($user->lang('CHARS_POST_CONTAINS', $message_length) . '
' . $user->lang('TOO_FEW_CHARS_LIMIT', (int) $config['min_post_chars'])); - return (!$update_this_message) ? $return_message : $this->warn_msg; - } - } - - /** - * This event can be used for additional message checks/cleanup before parsing - * - * @event core.message_parser_check_message - * @var bool allow_bbcode Do we allow BBCodes - * @var bool allow_magic_url Do we allow magic urls - * @var bool allow_smilies Do we allow smilies - * @var bool allow_img_bbcode Do we allow image BBCode - * @var bool allow_flash_bbcode Do we allow flash BBCode - * @var bool allow_quote_bbcode Do we allow quote BBCode - * @var bool allow_url_bbcode Do we allow url BBCode - * @var bool update_this_message Do we alter the parsed message - * @var string mode Posting mode - * @var string message The message text to parse - * @var string bbcode_bitfield The bbcode_bitfield before parsing - * @var string bbcode_uid The bbcode_uid before parsing - * @var bool return Do we return after the event is triggered if $warn_msg is not empty - * @var array warn_msg Array of the warning messages - * @since 3.1.2-RC1 - * @changed 3.1.3-RC1 Added vars $bbcode_bitfield and $bbcode_uid - */ - $message = $this->message; - $warn_msg = $this->warn_msg; - $return = false; - $bbcode_bitfield = $this->bbcode_bitfield; - $bbcode_uid = $this->bbcode_uid; - $vars = array( - 'allow_bbcode', - 'allow_magic_url', - 'allow_smilies', - 'allow_img_bbcode', - 'allow_flash_bbcode', - 'allow_quote_bbcode', - 'allow_url_bbcode', - 'update_this_message', - 'mode', - 'message', - 'bbcode_bitfield', - 'bbcode_uid', - 'return', - 'warn_msg', - ); - extract($phpbb_dispatcher->trigger_event('core.message_parser_check_message', compact($vars))); - $this->message = $message; - $this->warn_msg = $warn_msg; - $this->bbcode_bitfield = $bbcode_bitfield; - $this->bbcode_uid = $bbcode_uid; - if ($return && !empty($this->warn_msg)) - { - return (!$update_this_message) ? $return_message : $this->warn_msg; - } - - // Get the parser - $parser = $phpbb_container->get('text_formatter.parser'); - - // 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'); - - // 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 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) - { - $this->remove_nested_quotes($config['max_quote_depth']); - } - - // Check for "empty" message. We do not check here for maximum length, because bbcode, smilies, etc. can add to the length. - // The maximum length check happened before any parsings. - if ($mode === 'post' && utf8_clean_string($this->message) === '') - { - $this->warn_msg[] = $user->lang['TOO_FEW_CHARS']; - return (!$update_this_message) ? $return_message : $this->warn_msg; - } - - // 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) - { - 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; - } - - if (!$update_this_message) - { - unset($this->message); - $this->message = $tmp_message; - return $return_message; - } - - $this->message_status = 'parsed'; - return false; - } - - /** - * Formatting text for display - */ - function format_display($allow_bbcode, $allow_magic_url, $allow_smilies, $update_this_message = true) - { - global $phpbb_container, $phpbb_dispatcher; - - // If false, then the parsed message get returned but internal message not processed. - if (!$update_this_message) - { - $tmp_message = $this->message; - $return_message = &$this->message; - } - - $text = $this->message; - $uid = $this->bbcode_uid; - - /** - * Event to modify the text before it is parsed - * - * @event core.modify_format_display_text_before - * @var string text The message text to parse - * @var string uid The bbcode uid - * @var bool allow_bbcode Do we allow bbcodes - * @var bool allow_magic_url Do we allow magic urls - * @var bool allow_smilies Do we allow smilies - * @var bool update_this_message Do we update the internal message - * with the parsed result - * @since 3.1.6-RC1 - */ - $vars = array('text', 'uid', 'allow_bbcode', 'allow_magic_url', 'allow_smilies', 'update_this_message'); - extract($phpbb_dispatcher->trigger_event('core.modify_format_display_text_before', compact($vars))); - - $this->message = $text; - $this->bbcode_uid = $uid; - unset($text, $uid); - - // 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); - } - - // 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->message = $phpbb_container->get('text_formatter.parser')->parse($this->message); - } - - $this->message = $phpbb_container->get('text_formatter.renderer')->render($this->message); - - $text = $this->message; - $uid = $this->bbcode_uid; - - /** - * Event to modify the text after it is parsed - * - * @event core.modify_format_display_text_after - * @var string text The message text to parse - * @var string uid The bbcode uid - * @var bool allow_bbcode Do we allow bbcodes - * @var bool allow_magic_url Do we allow magic urls - * @var bool allow_smilies Do we allow smilies - * @var bool update_this_message Do we update the internal message - * with the parsed result - * @since 3.1.0-a3 - */ - $vars = array('text', 'uid', 'allow_bbcode', 'allow_magic_url', 'allow_smilies', 'update_this_message'); - extract($phpbb_dispatcher->trigger_event('core.modify_format_display_text_after', compact($vars))); - - $this->message = $text; - $this->bbcode_uid = $uid; - - if (!$update_this_message) - { - unset($this->message); - $this->message = $tmp_message; - return $return_message; - } - - $this->message_status = 'display'; - return false; - } - - /** - * Decode message to be placed back into form box - */ - function decode_message($custom_bbcode_uid = '', $update_this_message = true) - { - // If false, then the parsed message get returned but internal message not processed. - if (!$update_this_message) - { - $tmp_message = $this->message; - $return_message = &$this->message; - } - - ($custom_bbcode_uid) ? decode_message($this->message, $custom_bbcode_uid) : decode_message($this->message, $this->bbcode_uid); - - if (!$update_this_message) - { - unset($this->message); - $this->message = $tmp_message; - return $return_message; - } - - $this->message_status = 'plain'; - return false; - } - - /** - * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx. - * Cuts down displayed size of link if over 50 chars, turns absolute links - * into relative versions when the server/script path matches the link - */ - function magic_url($server_url) - { - // We use the global make_clickable function - $this->message = make_clickable($this->message, $server_url); - } - - /** - * Parse Smilies - */ - function smilies($max_smilies = 0) - { - global $db, $user; - static $match; - static $replace; - - // See if the static arrays have already been filled on an earlier invocation - if (!is_array($match)) - { - $match = $replace = array(); - - // NOTE: obtain_* function? chaching the table contents? - - // For now setting the ttl to 10 minutes - switch ($db->get_sql_layer()) - { - case 'mssql_odbc': - case 'mssqlnative': - $sql = 'SELECT * - FROM ' . SMILIES_TABLE . ' - ORDER BY LEN(code) DESC'; - break; - - // LENGTH supported by MySQL, IBM DB2, Oracle and Access for sure... - default: - $sql = 'SELECT * - FROM ' . SMILIES_TABLE . ' - ORDER BY LENGTH(code) DESC'; - break; - } - $result = $db->sql_query($sql, 600); - - while ($row = $db->sql_fetchrow($result)) - { - if (empty($row['code'])) - { - continue; - } - - // (assertion) - $match[] = preg_quote($row['code'], '#'); - $replace[] = '' . $row['code'] . ''; - } - $db->sql_freeresult($result); - } - - if (count($match)) - { - if ($max_smilies) - { - // 'u' modifier has been added to correctly parse smilies within unicode strings - // For details: http://tracker.phpbb.com/browse/PHPBB3-10117 - $num_matches = preg_match_all('#(?<=^|[\n .])(?:' . implode('|', $match) . ')(?![^<>]*>)#u', $this->message, $matches); - unset($matches); - - if ($num_matches !== false && $num_matches > $max_smilies) - { - $this->warn_msg[] = sprintf($user->lang['TOO_MANY_SMILIES'], $max_smilies); - return; - } - } - - // Make sure the delimiter # is added in front and at the end of every element within $match - // 'u' modifier has been added to correctly parse smilies within unicode strings - // For details: http://tracker.phpbb.com/browse/PHPBB3-10117 - - $this->message = trim(preg_replace(explode(chr(0), '#(?<=^|[\n .])' . implode('(?![^<>]*>)#u' . chr(0) . '#(?<=^|[\n .])', $match) . '(?![^<>]*>)#u'), $replace, $this->message)); - } - } - - /** - * 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 = 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'])); - - $add_file = (isset($_POST['add_file'])) ? true : false; - $delete_file = (isset($_POST['delete_file'])) ? true : false; - - // First of all adjust comments if changed - $actual_comment_list = $request->variable('comment_list', array(''), true); - - foreach ($actual_comment_list as $comment_key => $comment) - { - if (!isset($this->attachment_data[$comment_key])) - { - continue; - } - - if ($this->attachment_data[$comment_key]['attach_comment'] != $actual_comment_list[$comment_key]) - { - $this->attachment_data[$comment_key]['attach_comment'] = $actual_comment_list[$comment_key]; - } - } - - $cfg = array(); - $cfg['max_attachments'] = ($is_message) ? $config['max_attachments_pm'] : $config['max_attachments']; - $forum_id = ($is_message) ? 0 : $forum_id; - - if ($submit && in_array($mode, array('post', 'reply', 'quote', 'edit')) && $upload_file) - { - if ($num_attachments < $cfg['max_attachments'] || $auth->acl_get('a_') || $auth->acl_get('m_', $forum_id)) - { - /** @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'] && !count($error)) - { - $sql_ary = array( - 'physical_filename' => $filedata['physical_filename'], - 'attach_comment' => $this->filename_data['filecomment'], - 'real_filename' => $filedata['real_filename'], - 'extension' => $filedata['extension'], - 'mimetype' => $filedata['mimetype'], - 'filesize' => $filedata['filesize'], - 'filetime' => $filedata['filetime'], - 'thumbnail' => $filedata['thumbnail'], - 'is_orphan' => 1, - 'in_message' => ($is_message) ? 1 : 0, - '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( - 'attach_id' => $db->sql_nextid(), - 'is_orphan' => 1, - 'real_filename' => $filedata['real_filename'], - 'attach_comment'=> $this->filename_data['filecomment'], - 'filesize' => $filedata['filesize'], - ); - - $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); - - /** - * 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'] = ''; - - // This Variable is set to false here, because Attachments are entered into the - // Database in two modes, one if the id_list is 0 and the second one if post_attach is true - // Since post_attach is automatically switched to true if an Attachment got added to the filesystem, - // but we are assigning an id of 0 here, we have to reset the post_attach variable to false. - // - // This is very relevant, because it could happen that the post got not submitted, but we do not - // know this circumstance here. We could be at the posting page or we could be redirected to the entered - // post. :) - $filedata['post_attach'] = false; - } - } - else - { - $error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']); - } - } - - if ($preview || $refresh || count($error)) - { - if (isset($this->plupload) && $this->plupload->is_active()) - { - $json_response = new \phpbb\json_response(); - } - - // Perform actions on temporary attachments - if ($delete_file) - { - include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - - $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']) - { - $sql = 'SELECT attach_id, physical_filename, thumbnail - FROM ' . ATTACHMENTS_TABLE . ' - WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id'] . ' - AND is_orphan = 1 - AND poster_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $attachment_manager->unlink($row['physical_filename'], 'file'); - - if ($row['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']); - } - } - else - { - $attachment_manager->delete('attach', $this->attachment_data[$index]['attach_id']); - } - - unset($this->attachment_data[$index]); - $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); - if (isset($this->plupload) && $this->plupload->is_active()) - { - $json_response->send($this->attachment_data); - } - } - } - else if (($add_file || $preview) && $upload_file) - { - if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id)) - { - /** @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 (!count($error)) - { - $sql_ary = array( - 'physical_filename' => $filedata['physical_filename'], - 'attach_comment' => $this->filename_data['filecomment'], - 'real_filename' => $filedata['real_filename'], - 'extension' => $filedata['extension'], - 'mimetype' => $filedata['mimetype'], - 'filesize' => $filedata['filesize'], - 'filetime' => $filedata['filetime'], - 'thumbnail' => $filedata['thumbnail'], - 'is_orphan' => 1, - 'in_message' => ($is_message) ? 1 : 0, - '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( - 'attach_id' => $db->sql_nextid(), - 'is_orphan' => 1, - 'real_filename' => $filedata['real_filename'], - 'attach_comment'=> $this->filename_data['filecomment'], - 'filesize' => $filedata['filesize'], - ); - - $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); - - /** - * 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()) - { - $download_url = append_sid("{$phpbb_root_path}download/file.{$phpEx}", 'mode=view&id=' . $new_entry['attach_id']); - - // Send the client the attachment data to maintain state - $json_response->send(array('data' => $this->attachment_data, 'download_url' => $download_url)); - } - } - } - else - { - $error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']); - } - - if (!empty($error) && isset($this->plupload) && $this->plupload->is_active()) - { - // If this is a plupload (and thus ajax) request, give the - // client the first error we have - $json_response->send(array( - 'jsonrpc' => '2.0', - 'id' => 'id', - 'error' => array( - 'code' => 105, - 'message' => current($error), - ), - )); - } - } - } - - foreach ($error as $error_msg) - { - $this->warn_msg[] = $error_msg; - } - } - - /** - * Get Attachment Data - */ - function get_submitted_attachment_data($check_user_id = false) - { - global $user, $db; - global $request; - - $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 (!count($attachment_data)) - { - return; - } - - $not_orphan = $orphan = array(); - - foreach ($attachment_data as $pos => $var_ary) - { - if ($var_ary['is_orphan']) - { - $orphan[(int) $var_ary['attach_id']] = $pos; - } - else - { - $not_orphan[(int) $var_ary['attach_id']] = $pos; - } - } - - // Regenerate already posted attachments - if (count($not_orphan)) - { - // Get the attachment data, based on the poster id... - $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($not_orphan)) . ' - AND poster_id = ' . $check_user_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $pos = $not_orphan[$row['attach_id']]; - $this->attachment_data[$pos] = $row; - $this->attachment_data[$pos]['attach_comment'] = $attachment_data[$pos]['attach_comment']; - - unset($not_orphan[$row['attach_id']]); - } - $db->sql_freeresult($result); - } - - if (count($not_orphan)) - { - trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR); - } - - // Regenerate newly uploaded attachments - if (count($orphan)) - { - $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan)) . ' - AND poster_id = ' . $user->data['user_id'] . ' - AND is_orphan = 1'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $pos = $orphan[$row['attach_id']]; - $this->attachment_data[$pos] = $row; - $this->attachment_data[$pos]['attach_comment'] = $attachment_data[$pos]['attach_comment']; - - unset($orphan[$row['attach_id']]); - } - $db->sql_freeresult($result); - } - - if (count($orphan)) - { - trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR); - } - - ksort($this->attachment_data); - } - - /** - * Parse Poll - */ - function parse_poll(&$poll) - { - global $user, $config; - - $poll_max_options = $poll['poll_max_options']; - - // Parse Poll Option text - $tmp_message = $this->message; - - $poll['poll_options'] = preg_split('/\s*?\n\s*/', trim($poll['poll_option_text'])); - $poll['poll_options_size'] = count($poll['poll_options']); - - 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 - $this->message = $poll['poll_title']; - if (!$poll['poll_title'] && $poll['poll_options_size']) - { - $this->warn_msg[] = $user->lang['NO_POLL_TITLE']; - } - else - { - if (utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)) > 100) - { - $this->warn_msg[] = $user->lang['POLL_TITLE_TOO_LONG']; - } - $poll['poll_title'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false, 'poll'); - if (strlen($poll['poll_title']) > 255) - { - $this->warn_msg[] = $user->lang['POLL_TITLE_COMP_TOO_LONG']; - } - } - - if (count($poll['poll_options']) == 1) - { - $this->warn_msg[] = $user->lang['TOO_FEW_POLL_OPTIONS']; - } - else if ($poll['poll_options_size'] > (int) $config['max_poll_options']) - { - $this->warn_msg[] = $user->lang['TOO_MANY_POLL_OPTIONS']; - } - else if ($poll_max_options > $poll['poll_options_size']) - { - $this->warn_msg[] = $user->lang['TOO_MANY_USER_OPTIONS']; - } - - $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; - } - - /** - * Remove nested quotes at given depth in current parsed message - * - * @param integer $max_depth Depth limit - * @return null - */ - 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(?:="(.*?)")?:' . $this->bbcode_uid . '\\])', $this->message, $matches, PREG_OFFSET_CAPTURE); - - // Iterate over the quote tags to mark the ranges that must be removed - $depth = 0; - $ranges = array(); - $start_pos = 0; - foreach ($matches[0] as $match) - { - if ($match[0][1] === '/') - { - --$depth; - if ($depth == $max_depth) - { - $end_pos = $match[1] + strlen($match[0]); - $length = $end_pos - $start_pos; - $ranges[] = array($start_pos, $length); - } - } - else - { - ++$depth; - if ($depth == $max_depth + 1) - { - $start_pos = $match[1]; - } - } - } - - foreach (array_reverse($ranges) as $range) - { - list($start_pos, $length) = $range; - $this->message = substr_replace($this->message, '', $start_pos, $length); - } - } - - /** - * Setter function for passing the plupload object - * - * @param \phpbb\plupload\plupload $plupload The plupload object - * - * @return null - */ - public function set_plupload(\phpbb\plupload\plupload $plupload) - { - $this->plupload = $plupload; - } - - /** - * 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')") - * - * Accepts variable number of parameters - * - * @return mixed Validation result - */ - public function validate_bbcode_by_extension() - { - global $phpbb_dispatcher; - - $return = false; - $params_array = func_get_args(); - - /** - * Event to validate bbcode with the custom validating methods - * provided by extensions - * - * @event core.validate_bbcode_by_extension - * @var array params_array Array with the function parameters - * @var mixed return Validation result to return - * - * @since 3.1.5-RC1 - */ - $vars = array('params_array', 'return'); - extract($phpbb_dispatcher->trigger_event('core.validate_bbcode_by_extension', compact($vars))); - - return $return; - } -} diff --git a/install/update/old/includes/questionnaire/questionnaire.php b/install/update/old/includes/questionnaire/questionnaire.php deleted file mode 100644 index 2f80582..0000000 --- a/install/update/old/includes/questionnaire/questionnaire.php +++ /dev/null @@ -1,501 +0,0 @@ - -* @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; -} - -/** -* This class collects data which is used to create some usage statistics. -* -* The collected data is - after authorization of the administrator - submitted -* to a central server. For privacy reasons we try to collect only data which aren't private -* or don't give any information which might help to identify the user. -* -* @author Johannes Schlueter -* @copyright (c) 2007-2008 Johannes Schlueter -*/ -class phpbb_questionnaire_data_collector -{ - var $providers; - var $data = null; - var $install_id = ''; - - /** - * Constructor. - * - * @param string - */ - function __construct($install_id) - { - $this->install_id = $install_id; - $this->providers = array(); - } - - function add_data_provider($provider) - { - $this->providers[] = $provider; - } - - /** - * Get data as an array. - * - * @return array All Data - */ - function get_data_raw() - { - if (!$this->data) - { - $this->collect(); - } - - return $this->data; - } - - function get_data_for_form() - { - return base64_encode(serialize($this->get_data_raw())); - } - - /** - * Collect info into the data property. - * - * @return null - */ - function collect() - { - foreach (array_keys($this->providers) as $key) - { - $provider = $this->providers[$key]; - $this->data[$provider->get_identifier()] = $provider->get_data(); - } - $this->data['install_id'] = $this->install_id; - } -} - -/** interface: get_indentifier(), get_data() */ - -/** -* Questionnaire PHP data provider -*/ -class phpbb_questionnaire_php_data_provider -{ - function get_identifier() - { - return 'PHP'; - } - - /** - * Get data about the PHP runtime setup. - * - * @return array - */ - function get_data() - { - return array( - 'version' => PHP_VERSION, - 'sapi' => PHP_SAPI, - 'int_size' => defined('PHP_INT_SIZE') ? PHP_INT_SIZE : '', - 'safe_mode' => (int) @ini_get('safe_mode'), - 'open_basedir' => (int) @ini_get('open_basedir'), - 'memory_limit' => @ini_get('memory_limit'), - 'allow_url_fopen' => (int) @ini_get('allow_url_fopen'), - 'allow_url_include' => (int) @ini_get('allow_url_include'), - 'file_uploads' => (int) @ini_get('file_uploads'), - 'upload_max_filesize' => @ini_get('upload_max_filesize'), - 'post_max_size' => @ini_get('post_max_size'), - 'disable_functions' => @ini_get('disable_functions'), - 'disable_classes' => @ini_get('disable_classes'), - 'enable_dl' => (int) @ini_get('enable_dl'), - 'magic_quotes_gpc' => (int) @ini_get('magic_quotes_gpc'), - 'register_globals' => (int) @ini_get('register_globals'), - 'filter.default' => @ini_get('filter.default'), - 'zend.ze1_compatibility_mode' => (int) @ini_get('zend.ze1_compatibility_mode'), - 'unicode.semantics' => (int) @ini_get('unicode.semantics'), - 'zend_thread_safty' => (int) function_exists('zend_thread_id'), - 'extensions' => get_loaded_extensions(), - ); - } -} - -/** -* Questionnaire System data provider -*/ -class phpbb_questionnaire_system_data_provider -{ - function get_identifier() - { - return 'System'; - } - - /** - * Get data about the general system information, like OS or IP (shortened). - * - * @return array - */ - function get_data() - { - global $request; - - // Start discovering the IPV4 server address, if available - // Try apache, IIS, fall back to 0.0.0.0 - $server_address = htmlspecialchars_decode($request->server('SERVER_ADDR', $request->server('LOCAL_ADDR', '0.0.0.0'))); - - return array( - 'os' => PHP_OS, - 'httpd' => htmlspecialchars_decode($request->server('SERVER_SOFTWARE')), - // we don't want the real IP address (for privacy policy reasons) but only - // a network address to see whether your installation is running on a private or public network. - 'private_ip' => $this->is_private_ip($server_address), - 'ipv6' => strpos($server_address, ':') !== false, - ); - } - - /** - * Checks whether the given IP is in a private network. - * - * @param string $ip IP in v4 dot-decimal or v6 hex format - * @return bool true if the IP is from a private network, else false - */ - function is_private_ip($ip) - { - // IPv4 - if (strpos($ip, ':') === false) - { - $ip_address_ary = explode('.', $ip); - - // build ip - if (!isset($ip_address_ary[0]) || !isset($ip_address_ary[1])) - { - $ip_address_ary = explode('.', '0.0.0.0'); - } - - // IANA reserved addresses for private networks (RFC 1918) are: - // - 10.0.0.0/8 - // - 172.16.0.0/12 - // - 192.168.0.0/16 - 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')) - { - return true; - } - } - // IPv6 - else - { - // unique local unicast - $prefix = substr($ip, 0, 2); - if ($prefix == 'fc' || $prefix == 'fd') - { - return true; - } - } - - return false; - } -} - -/** -* Questionnaire phpBB data provider -*/ -class phpbb_questionnaire_phpbb_data_provider -{ - var $config; - var $unique_id; - - /** - * Constructor. - * - * @param array $config - */ - function __construct($config) - { - // generate a unique id if necessary - if (empty($config['questionnaire_unique_id'])) - { - $this->unique_id = unique_id(); - $config->set('questionnaire_unique_id', $this->unique_id); - } - else - { - $this->unique_id = $config['questionnaire_unique_id']; - } - - $this->config = $config; - } - - /** - * Returns a string identifier for this data provider - * - * @return string "phpBB" - */ - function get_identifier() - { - return 'phpBB'; - } - - /** - * Get data about this phpBB installation. - * - * @return array Relevant anonymous config options - */ - function get_data() - { - global $phpbb_config_php_file; - - extract($phpbb_config_php_file->get_all()); - unset($dbhost, $dbport, $dbname, $dbuser, $dbpasswd); // Just a precaution - - $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms); - - // Only send certain config vars - $config_vars = array( - 'active_sessions' => true, - 'allow_attachments' => true, - 'allow_autologin' => true, - 'allow_avatar' => true, - 'allow_avatar_local' => true, - 'allow_avatar_remote' => true, - 'allow_avatar_upload' => true, - 'allow_bbcode' => true, - 'allow_birthdays' => true, - 'allow_bookmarks' => true, - 'allow_emailreuse' => true, - 'allow_forum_notify' => true, - 'allow_mass_pm' => true, - 'allow_name_chars' => true, - 'allow_namechange' => true, - 'allow_nocensors' => true, - 'allow_pm_attach' => true, - 'allow_pm_report' => true, - 'allow_post_flash' => true, - 'allow_post_links' => true, - 'allow_privmsg' => true, - 'allow_quick_reply' => true, - 'allow_sig' => true, - 'allow_sig_bbcode' => true, - 'allow_sig_flash' => true, - 'allow_sig_img' => true, - 'allow_sig_links' => true, - 'allow_sig_pm' => true, - 'allow_sig_smilies' => true, - 'allow_smilies' => true, - 'allow_topic_notify' => true, - 'attachment_quota' => true, - 'auth_bbcode_pm' => true, - 'auth_flash_pm' => true, - 'auth_img_pm' => true, - 'auth_method' => true, - 'auth_smilies_pm' => true, - 'avatar_filesize' => true, - 'avatar_max_height' => true, - 'avatar_max_width' => true, - 'avatar_min_height' => true, - 'avatar_min_width' => true, - 'board_email_form' => true, - 'board_hide_emails' => true, - 'board_timezone' => true, - 'browser_check' => true, - 'bump_interval' => true, - 'bump_type' => true, - 'cache_gc' => true, - 'captcha_plugin' => true, - 'captcha_gd' => true, - 'captcha_gd_foreground_noise' => true, - 'captcha_gd_x_grid' => true, - 'captcha_gd_y_grid' => true, - 'captcha_gd_wave' => true, - 'captcha_gd_3d_noise' => true, - 'captcha_gd_fonts' => true, - 'confirm_refresh' => true, - 'check_attachment_content' => true, - 'check_dnsbl' => true, - 'chg_passforce' => true, - 'cookie_secure' => true, - 'coppa_enable' => true, - 'database_gc' => true, - 'dbms_version' => true, - 'default_dateformat' => true, - 'default_lang' => true, - 'display_last_edited' => true, - 'display_order' => true, - 'edit_time' => true, - 'email_check_mx' => true, - 'email_enable' => true, - 'email_force_sender' => true, - 'email_package_size' => true, - 'enable_confirm' => true, - 'enable_pm_icons' => true, - 'enable_post_confirm' => true, - 'feed_enable' => true, - 'feed_http_auth' => true, - 'feed_limit_post' => true, - 'feed_limit_topic' => true, - 'feed_overall' => true, - 'feed_overall_forums' => true, - 'feed_forum' => true, - 'feed_topic' => true, - 'feed_topics_new' => true, - 'feed_topics_active' => true, - 'feed_item_statistics' => true, - 'flood_interval' => true, - 'force_server_vars' => true, - 'form_token_lifetime' => true, - 'form_token_mintime' => true, - 'form_token_sid_guests' => true, - 'forward_pm' => true, - 'forwarded_for_check' => true, - 'full_folder_action' => true, - 'fulltext_native_common_thres' => true, - 'fulltext_native_load_upd' => true, - 'fulltext_native_max_chars' => true, - 'fulltext_native_min_chars' => true, - 'gzip_compress' => true, - 'hot_threshold' => true, - 'img_create_thumbnail' => true, - 'img_display_inlined' => true, - 'img_link_height' => true, - 'img_link_width' => true, - 'img_max_height' => true, - 'img_max_thumb_width' => true, - 'img_max_width' => true, - 'img_min_thumb_filesize' => true, - 'ip_check' => true, - 'jab_enable' => true, - 'jab_package_size' => true, - 'jab_use_ssl' => true, - 'limit_load' => true, - 'limit_search_load' => true, - 'load_anon_lastread' => true, - 'load_birthdays' => true, - 'load_cpf_memberlist' => true, - 'load_cpf_viewprofile' => true, - 'load_cpf_viewtopic' => true, - 'load_db_lastread' => true, - 'load_db_track' => true, - 'load_jumpbox' => true, - 'load_moderators' => true, - 'load_online' => true, - 'load_online_guests' => true, - 'load_online_time' => true, - 'load_onlinetrack' => true, - 'load_search' => true, - 'load_tplcompile' => true, - 'load_user_activity' => true, - 'max_attachments' => true, - 'max_attachments_pm' => true, - 'max_autologin_time' => true, - 'max_filesize' => true, - 'max_filesize_pm' => true, - 'max_login_attempts' => true, - 'max_name_chars' => true, - 'max_num_search_keywords' => true, - 'max_pass_chars' => true, - 'max_poll_options' => true, - 'max_post_chars' => true, - 'max_post_font_size' => true, - 'max_post_img_height' => true, - 'max_post_img_width' => true, - 'max_post_smilies' => true, - 'max_post_urls' => true, - 'max_quote_depth' => true, - 'max_reg_attempts' => true, - 'max_sig_chars' => true, - 'max_sig_font_size' => true, - 'max_sig_img_height' => true, - 'max_sig_img_width' => true, - 'max_sig_smilies' => true, - 'max_sig_urls' => true, - 'min_name_chars' => true, - 'min_pass_chars' => true, - 'min_post_chars' => true, - 'min_search_author_chars' => true, - 'mime_triggers' => true, - 'new_member_post_limit' => true, - 'new_member_group_default' => true, - 'override_user_style' => true, - 'pass_complex' => true, - 'pm_edit_time' => true, - 'pm_max_boxes' => true, - 'pm_max_msgs' => true, - 'pm_max_recipients' => true, - 'posts_per_page' => true, - 'print_pm' => true, - 'queue_interval' => true, - 'require_activation' => true, - 'referer_validation' => true, - 'search_block_size' => true, - 'search_gc' => true, - 'search_interval' => true, - 'search_anonymous_interval' => true, - 'search_type' => true, - 'search_store_results' => true, - 'secure_allow_deny' => true, - 'secure_allow_empty_referer' => true, - 'secure_downloads' => true, - 'session_gc' => true, - 'session_length' => true, - 'smtp_auth_method' => true, - 'smtp_delivery' => true, - 'topics_per_page' => true, - 'tpl_allow_php' => true, - 'version' => true, - 'warnings_expire_days' => true, - 'warnings_gc' => true, - - 'num_files' => true, - 'num_posts' => true, - 'num_topics' => true, - 'num_users' => true, - 'record_online_users' => true, - ); - - $result = array(); - foreach ($config_vars as $name => $void) - { - if (isset($this->config[$name])) - { - $result['config_' . $name] = $this->config[$name]; - } - } - - global $db, $request; - - $result['dbms'] = $dbms; - $result['acm_type'] = $acm_type; - $result['user_agent'] = 'Unknown'; - $result['dbms_version'] = $db->sql_server_info(true); - - // Try to get user agent vendor and version - $match = array(); - $user_agent = $request->header('User-Agent'); - $agents = array('firefox', 'msie', 'opera', 'chrome', 'safari', 'mozilla', 'seamonkey', 'konqueror', 'netscape', 'gecko', 'navigator', 'mosaic', 'lynx', 'amaya', 'omniweb', 'avant', 'camino', 'flock', 'aol'); - - // We check here 1 by 1 because some strings occur after others (for example Mozilla [...] Firefox/) - foreach ($agents as $agent) - { - if (preg_match('#(' . $agent . ')[/ ]?([0-9.]*)#i', $user_agent, $match)) - { - $result['user_agent'] = $match[1] . ' ' . $match[2]; - break; - } - } - - return $result; - } -} diff --git a/install/update/old/includes/startup.php b/install/update/old/includes/startup.php deleted file mode 100644 index 66f8565..0000000 --- a/install/update/old/includes/startup.php +++ /dev/null @@ -1,86 +0,0 @@ - -* @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; -} - -// Report all errors, except notices and deprecation messages -$level = E_ALL & ~E_NOTICE & ~E_DEPRECATED; -error_reporting($level); - -/** -* Minimum Requirement: PHP 5.4.0 -*/ -if (version_compare(PHP_VERSION, '5.4') < 0) -{ - 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 - - -// 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. - -// 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()); - -// Autoloading of dependencies. -// Three options are supported: -// 1. If dependencies are installed with Composer, Composer will create a -// vendor/autoload.php. If this file exists it will be -// automatically used by phpBB. This is the default mode that phpBB -// will use when shipped. -// 2. To disable composer autoloading, PHPBB_NO_COMPOSER_AUTOLOAD can be specified. -// Additionally specify PHPBB_AUTOLOAD=/path/to/autoload.php in the -// environment. This is useful for running CLI scripts and tests. -// /path/to/autoload.php should define and register class loaders -// for all of phpBB's dependencies. -// 3. You can also set PHPBB_NO_COMPOSER_AUTOLOAD without setting PHPBB_AUTOLOAD. -// In this case autoloading needs to be defined before running any phpBB -// script. This might be useful in cases when phpBB is integrated into a -// larger program. -if (getenv('PHPBB_NO_COMPOSER_AUTOLOAD')) -{ - if (getenv('PHPBB_AUTOLOAD')) - { - require(getenv('PHPBB_AUTOLOAD')); - } -} -else -{ - if (!file_exists($phpbb_root_path . 'vendor/autoload.php')) - { - trigger_error( - 'Composer dependencies have not been set up yet, run ' . - "'php ../composer.phar install' from the phpBB directory to do so.", - E_USER_ERROR - ); - } - require($phpbb_root_path . 'vendor/autoload.php'); -} - -$starttime = microtime(true); diff --git a/install/update/old/includes/ucp/ucp_attachments.php b/install/update/old/includes/ucp/ucp_attachments.php deleted file mode 100644 index c1b623c..0000000 --- a/install/update/old/includes/ucp/ucp_attachments.php +++ /dev/null @@ -1,205 +0,0 @@ - -* @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; -} - -/** -* ucp_attachments -* User attachments -*/ -class ucp_attachments -{ - var $u_action; - - function main($id, $mode) - { - global $template, $user, $db, $config, $phpEx, $phpbb_root_path, $phpbb_container, $request; - - $start = $request->variable('start', 0); - $sort_key = $request->variable('sk', 'a'); - $sort_dir = $request->variable('sd', 'a'); - - $delete = (isset($_POST['delete'])) ? true : false; - $delete_ids = array_keys($request->variable('attachment', array(0))); - - 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); - $result = $db->sql_query($sql); - - $delete_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $delete_ids[] = $row['attach_id']; - } - $db->sql_freeresult($result); - } - - if ($delete && count($delete_ids)) - { - $s_hidden_fields = array( - 'delete' => 1 - ); - - foreach ($delete_ids as $attachment_id) - { - $s_hidden_fields['attachment'][$attachment_id] = 1; - } - - if (confirm_box(true)) - { - /** @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 = ((count($delete_ids) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED']) . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - else - { - confirm_box(false, (count($delete_ids) == 1) ? 'DELETE_ATTACHMENT' : 'DELETE_ATTACHMENTS', build_hidden_fields($s_hidden_fields)); - } - } - - // Select box eventually - $sort_key_text = array('a' => $user->lang['SORT_FILENAME'], 'b' => $user->lang['SORT_COMMENT'], 'c' => $user->lang['SORT_EXTENSION'], 'd' => $user->lang['SORT_SIZE'], 'e' => $user->lang['SORT_DOWNLOADS'], 'f' => $user->lang['SORT_POST_TIME'], 'g' => $user->lang['SORT_TOPIC_TITLE']); - $sort_key_sql = array('a' => 'a.real_filename', 'b' => 'a.attach_comment', 'c' => 'a.extension', 'd' => 'a.filesize', 'e' => 'a.download_count', 'f' => 'a.filetime', 'g' => 't.topic_title'); - - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - $s_sort_key = ''; - foreach ($sort_key_text as $key => $value) - { - $selected = ($sort_key == $key) ? ' selected="selected"' : ''; - $s_sort_key .= ''; - } - - $s_sort_dir = ''; - foreach ($sort_dir_text as $key => $value) - { - $selected = ($sort_dir == $key) ? ' selected="selected"' : ''; - $s_sort_dir .= ''; - } - - if (!isset($sort_key_sql[$sort_key])) - { - $sort_key = 'a'; - } - - $order_by = $sort_key_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); - - $sql = 'SELECT COUNT(attach_id) as num_attachments - FROM ' . ATTACHMENTS_TABLE . ' - WHERE poster_id = ' . $user->data['user_id'] . ' - AND is_orphan = 0'; - $result = $db->sql_query($sql); - $num_attachments = $db->sql_fetchfield('num_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 - FROM ' . ATTACHMENTS_TABLE . ' a - 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) - WHERE a.poster_id = ' . $user->data['user_id'] . " - AND a.is_orphan = 0 - ORDER BY $order_by"; - $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); - - $row_count = 0; - if ($row = $db->sql_fetchrow($result)) - { - $template->assign_var('S_ATTACHMENT_ROWS', true); - - do - { - if ($row['in_message']) - { - $view_topic = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&p={$row['post_msg_id']}"); - } - else - { - $view_topic = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}") . "#p{$row['post_msg_id']}"; - } - - $template->assign_block_vars('attachrow', array( - 'ROW_NUMBER' => $row_count + ($start + 1), - 'FILENAME' => $row['real_filename'], - 'COMMENT' => bbcode_nl2br($row['attach_comment']), - 'EXTENSION' => $row['extension'], - 'SIZE' => get_formatted_filesize($row['filesize']), - 'DOWNLOAD_COUNT' => $row['download_count'], - 'POST_TIME' => $user->format_date($row['filetime']), - 'TOPIC_TITLE' => ($row['in_message']) ? $row['message_title'] : $row['topic_title'], - - 'ATTACH_ID' => $row['attach_id'], - 'POST_ID' => $row['post_msg_id'], - 'TOPIC_ID' => $row['topic_id'], - - 'S_IN_MESSAGE' => $row['in_message'], - - 'U_VIEW_ATTACHMENT' => append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $row['attach_id']), - 'U_VIEW_TOPIC' => $view_topic) - ); - - $row_count++; - } - while ($row = $db->sql_fetchrow($result)); - } - $db->sql_freeresult($result); - - $base_url = $this->u_action . "&sk=$sort_key&sd=$sort_dir"; - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_attachments, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'TOTAL_ATTACHMENTS' => $num_attachments, - 'NUM_ATTACHMENTS' => $user->lang('NUM_ATTACHMENTS', $num_attachments), - - 'L_TITLE' => $user->lang['UCP_ATTACHMENTS'], - - 'U_SORT_FILENAME' => $this->u_action . "&sk=a&sd=" . (($sort_key == 'a' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_FILE_COMMENT' => $this->u_action . "&sk=b&sd=" . (($sort_key == 'b' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_EXTENSION' => $this->u_action . "&sk=c&sd=" . (($sort_key == 'c' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_FILESIZE' => $this->u_action . "&sk=d&sd=" . (($sort_key == 'd' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_DOWNLOADS' => $this->u_action . "&sk=e&sd=" . (($sort_key == 'e' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_POST_TIME' => $this->u_action . "&sk=f&sd=" . (($sort_key == 'f' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_TOPIC_TITLE' => $this->u_action . "&sk=g&sd=" . (($sort_key == 'g' && $sort_dir == 'a') ? 'd' : 'a'), - - 'S_DISPLAY_MARK_ALL' => ($num_attachments) ? true : false, - 'S_DISPLAY_PAGINATION' => ($num_attachments) ? true : false, - 'S_UCP_ACTION' => $this->u_action, - 'S_SORT_OPTIONS' => $s_sort_key, - 'S_ORDER_SELECT' => $s_sort_dir) - ); - - $this->tpl_name = 'ucp_attachments'; - $this->page_title = 'UCP_ATTACHMENTS'; - } -} diff --git a/install/update/old/includes/ucp/ucp_groups.php b/install/update/old/includes/ucp/ucp_groups.php deleted file mode 100644 index 2423af8..0000000 --- a/install/update/old/includes/ucp/ucp_groups.php +++ /dev/null @@ -1,1137 +0,0 @@ - -* @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; -} - -/** -* ucp_groups -*/ -class ucp_groups -{ - var $u_action; - - function main($id, $mode) - { - global $config, $phpbb_root_path, $phpEx, $phpbb_admin_path; - global $db, $user, $auth, $cache, $template; - global $request, $phpbb_container, $phpbb_log; - - /** @var \phpbb\language\language $language Language object */ - $language = $phpbb_container->get('language'); - - $user->add_lang('groups'); - - $return_page = '

' . sprintf($user->lang['RETURN_PAGE'], '', ''); - - $mark_ary = $request->variable('mark', array(0)); - $submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST); - - /** @var \phpbb\group\helper $group_helper */ - $group_helper = $phpbb_container->get('group_helper'); - - switch ($mode) - { - case 'membership': - - $this->page_title = 'UCP_USERGROUPS_MEMBER'; - - if ($submit || isset($_POST['change_default'])) - { - $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) - { - trigger_error('NO_GROUP_SELECTED'); - } - - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE . " - WHERE group_id IN ($group_id, {$user->data['group_id']})"; - $result = $db->sql_query($sql); - - $group_row = array(); - while ($row = $db->sql_fetchrow($result)) - { - $row['group_name'] = $group_helper->get_name($row['group_name']); - $group_row[$row['group_id']] = $row; - } - $db->sql_freeresult($result); - - if (!count($group_row)) - { - trigger_error('GROUP_NOT_EXIST'); - } - - switch ($action) - { - case 'change_default': - // User already having this group set as default? - if ($group_id == $user->data['group_id']) - { - trigger_error($user->lang['ALREADY_DEFAULT_GROUP'] . $return_page); - } - - if (!$auth->acl_get('u_chggrp')) - { - send_status_line(403, 'Forbidden'); - trigger_error($user->lang['NOT_AUTHORISED'] . $return_page); - } - - // User needs to be member of the group in order to make it default - if (!group_memberships($group_id, $user->data['user_id'], true)) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - - if (confirm_box(true)) - { - group_user_attributes('default', $group_id, $user->data['user_id']); - - $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); - } - else - { - $s_hidden_fields = array( - 'default' => $group_id, - 'change_default'=> true - ); - - confirm_box(false, sprintf($user->lang['GROUP_CHANGE_DEFAULT'], $group_row[$group_id]['group_name']), build_hidden_fields($s_hidden_fields)); - } - - break; - - case 'resign': - - // User tries to resign from default group but is not allowed to change it? - if ($group_id == $user->data['group_id'] && !$auth->acl_get('u_chggrp')) - { - trigger_error($user->lang['NOT_RESIGN_FROM_DEFAULT_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - list(, $row) = each($row); - - $sql = 'SELECT group_type - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . $group_id; - $result = $db->sql_query($sql); - $group_type = (int) $db->sql_fetchfield('group_type'); - $db->sql_freeresult($result); - - if ($group_type != GROUP_OPEN && $group_type != GROUP_FREE) - { - trigger_error($user->lang['CANNOT_RESIGN_GROUP'] . $return_page); - } - - if (confirm_box(true)) - { - group_user_del($group_id, $user->data['user_id']); - - $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); - } - else - { - $s_hidden_fields = array( - 'selected' => $group_id, - 'action' => 'resign', - 'submit' => true - ); - - confirm_box(false, ($row['user_pending']) ? 'GROUP_RESIGN_PENDING' : 'GROUP_RESIGN_MEMBERSHIP', build_hidden_fields($s_hidden_fields)); - } - - break; - - case 'join': - - $sql = 'SELECT ug.*, u.username, u.username_clean, u.user_email - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u - WHERE ug.user_id = u.user_id - AND ug.group_id = ' . $group_id . ' - AND ug.user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - if ($row['user_pending']) - { - trigger_error($user->lang['ALREADY_IN_GROUP_PENDING'] . $return_page); - } - - trigger_error($user->lang['ALREADY_IN_GROUP'] . $return_page); - } - - // Check permission to join (open group or request) - if ($group_row[$group_id]['group_type'] != GROUP_OPEN && $group_row[$group_id]['group_type'] != GROUP_FREE) - { - trigger_error($user->lang['CANNOT_JOIN_GROUP'] . $return_page); - } - - if (confirm_box(true)) - { - if ($group_row[$group_id]['group_type'] == GROUP_FREE) - { - group_user_add($group_id, $user->data['user_id']); - } - else - { - group_user_add($group_id, $user->data['user_id'], false, false, false, 0, 1); - } - - $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); - } - else - { - $s_hidden_fields = array( - 'selected' => $group_id, - 'action' => 'join', - 'submit' => true - ); - - confirm_box(false, ($group_row[$group_id]['group_type'] == GROUP_FREE) ? 'GROUP_JOIN' : 'GROUP_JOIN_PENDING', build_hidden_fields($s_hidden_fields)); - } - - break; - - case 'demote': - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - list(, $row) = each($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - if (confirm_box(true)) - { - group_user_attributes('demote', $group_id, $user->data['user_id']); - - $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); - } - else - { - $s_hidden_fields = array( - 'selected' => $group_id, - 'action' => 'demote', - 'submit' => true - ); - - confirm_box(false, 'USER_GROUP_DEMOTE', build_hidden_fields($s_hidden_fields)); - } - - break; - } - } - - $sql = 'SELECT g.*, ug.group_leader, ug.user_pending - FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug - WHERE ug.user_id = ' . $user->data['user_id'] . ' - AND g.group_id = ug.group_id - ORDER BY g.group_type DESC, g.group_name'; - $result = $db->sql_query($sql); - - $group_id_ary = array(); - $leader_count = $member_count = $pending_count = 0; - while ($row = $db->sql_fetchrow($result)) - { - $block = ($row['group_leader']) ? 'leader' : (($row['user_pending']) ? 'pending' : 'member'); - - switch ($row['group_type']) - { - case GROUP_OPEN: - $group_status = 'OPEN'; - break; - - case GROUP_CLOSED: - $group_status = 'CLOSED'; - break; - - case GROUP_HIDDEN: - $group_status = 'HIDDEN'; - break; - - case GROUP_SPECIAL: - $group_status = 'SPECIAL'; - break; - - case GROUP_FREE: - $group_status = 'FREE'; - break; - } - - $template->assign_block_vars($block, array( - 'GROUP_ID' => $row['group_id'], - '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], - 'GROUP_COLOUR' => $row['group_colour'], - - 'U_VIEW_GROUP' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $row['group_id']), - - 'S_GROUP_DEFAULT' => ($row['group_id'] == $user->data['group_id']) ? true : false, - 'S_ROW_COUNT' => ${$block . '_count'}++) - ); - - $group_id_ary[] = (int) $row['group_id']; - } - $db->sql_freeresult($result); - - // Hide hidden groups unless user is an admin with group privileges - $sql_and = ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? '<> ' . GROUP_SPECIAL : 'NOT IN (' . GROUP_SPECIAL . ', ' . GROUP_HIDDEN . ')'; - - $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 ' . ((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); - - $nonmember_count = 0; - while ($row = $db->sql_fetchrow($result)) - { - switch ($row['group_type']) - { - case GROUP_OPEN: - $group_status = 'OPEN'; - break; - - case GROUP_CLOSED: - $group_status = 'CLOSED'; - break; - - case GROUP_HIDDEN: - $group_status = 'HIDDEN'; - break; - - case GROUP_SPECIAL: - $group_status = 'SPECIAL'; - break; - - case GROUP_FREE: - $group_status = 'FREE'; - break; - } - - $template->assign_block_vars('nonmember', array( - 'GROUP_ID' => $row['group_id'], - '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, - 'GROUP_STATUS' => $user->lang['GROUP_IS_' . $group_status], - 'S_CAN_JOIN' => ($row['group_type'] == GROUP_OPEN || $row['group_type'] == GROUP_FREE) ? true : false, - 'GROUP_COLOUR' => $row['group_colour'], - - 'U_VIEW_GROUP' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $row['group_id']), - - 'S_ROW_COUNT' => $nonmember_count++) - ); - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_CHANGE_DEFAULT' => ($auth->acl_get('u_chggrp')) ? true : false, - 'S_LEADER_COUNT' => $leader_count, - 'S_MEMBER_COUNT' => $member_count, - 'S_PENDING_COUNT' => $pending_count, - 'S_NONMEMBER_COUNT' => $nonmember_count, - - 'S_UCP_ACTION' => $this->u_action) - ); - - break; - - case 'manage': - - $this->page_title = 'UCP_USERGROUPS_MANAGE'; - $action = (isset($_POST['addusers'])) ? 'addusers' : $request->variable('action', ''); - $group_id = $request->variable('g', 0); - - if (!function_exists('phpbb_get_user_rank')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - add_form_key('ucp_groups'); - - if ($group_id) - { - $sql = 'SELECT g.*, t.teampage_position AS group_teampage - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . TEAMPAGE_TABLE . ' t - ON (t.group_id = g.group_id) - WHERE g.group_id = ' . $group_id; - $result = $db->sql_query($sql); - $group_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$group_row) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - // Check if the user is allowed to manage this group if set to founder only. - if ($user->data['user_type'] != USER_FOUNDER && $group_row['group_founder_manage']) - { - trigger_error($user->lang['NOT_ALLOWED_MANAGE_GROUP'] . $return_page, E_USER_WARNING); - } - - $group_name = $group_row['group_name']; - $group_type = $group_row['group_type']; - - $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true); - - $template->assign_vars(array( - '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']), - 'GROUP_TYPE' => $group_row['group_type'], - - 'AVATAR' => (empty($avatar) ? '' : $avatar), - 'AVATAR_IMAGE' => (empty($avatar) ? '' : $avatar), - 'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '', - 'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '', - )); - } - - switch ($action) - { - case 'edit': - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - list(, $row) = each($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $user->add_lang(array('acp/groups', 'acp/common')); - - $update = (isset($_POST['update'])) ? true : false; - - $error = array(); - - // Setup avatar data for later - $avatars_enabled = false; - $avatar_drivers = null; - $avatar_data = null; - $avatar_error = array(); - - /** @var \phpbb\avatar\manager $phpbb_avatar_manager */ - $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); - - if ($config['allow_avatar']) - { - $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers(); - - // This is normalised data, without the group_ prefix - $avatar_data = \phpbb\avatar\manager::clean_row($group_row, 'group'); - } - - // Handle deletion of avatars - if ($request->is_set_post('avatar_delete')) - { - if (confirm_box(true)) - { - $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, GROUPS_TABLE, 'group_'); - $cache->destroy('sql', GROUPS_TABLE); - - $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; - trigger_error($user->lang[$message] . $return_page); - } - else - { - confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( - 'avatar_delete' => true, - 'i' => $id, - 'mode' => $mode, - 'g' => $group_id, - 'action' => $action)) - ); - } - } - - // Did we submit? - if ($update) - { - $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->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->variable('group_colour', ''), - 'rank' => $request->variable('group_rank', 0), - 'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 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']) - { - // Handle avatar - $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); - - if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) - { - $driver = $phpbb_avatar_manager->get_driver($driver_name); - $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error); - - if ($result && empty($avatar_error)) - { - $result['avatar_type'] = $driver_name; - - $submit_ary = array_merge($submit_ary, $result); - } - } - - // Merge any avatars errors into the primary error array - $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); - } - - if (!check_form_key('ucp_groups')) - { - $error[] = $user->lang['FORM_INVALID']; - } - - // Validate submitted colour value - if ($colour_error = validate_data($submit_ary, array('colour' => array('hex_colour', true)))) - { - // Replace "error" string with its real, localised form - $error = array_merge($error, $colour_error); - } - - if (!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 - // were made. - // However there are some attributes that need to be set everytime, - // otherwise the group gets removed from the feature. - $set_attributes = array('legend', 'teampage'); - - $group_attributes = array(); - $test_variables = array( - 'rank' => 'int', - 'colour' => 'string', - 'avatar' => 'string', - 'avatar_type' => 'string', - 'avatar_width' => 'int', - 'avatar_height' => 'int', - 'receive_pm' => 'int', - 'legend' => 'int', - 'teampage' => 'int', - 'message_limit' => 'int', - 'max_recipients'=> 'int', - ); - - foreach ($test_variables as $test => $type) - { - if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test] || isset($group_attributes['group_avatar']) && strpos($test, 'avatar') === 0 || in_array($test, $set_attributes))) - { - settype($submit_ary[$test], $type); - $group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test]; - } - } - - if (!($error = group_create($group_id, $group_type, $group_name, $group_desc, $group_attributes, $allow_desc_bbcode, $allow_desc_urls, $allow_desc_smilies))) - { - $cache->destroy('sql', GROUPS_TABLE); - $cache->destroy('sql', TEAMPAGE_TABLE); - - $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; - trigger_error($user->lang[$message] . $return_page); - } - } - - if (count($error)) - { - $error = array_map(array(&$user, 'lang'), $error); - $group_rank = $submit_ary['rank']; - - $group_desc_data = array( - 'text' => $group_desc, - 'allow_bbcode' => $allow_desc_bbcode, - 'allow_smilies' => $allow_desc_smilies, - 'allow_urls' => $allow_desc_urls - ); - } - } - else if (!$group_id) - { - $group_desc_data = array( - 'text' => '', - 'allow_bbcode' => true, - 'allow_smilies' => true, - 'allow_urls' => true - ); - $group_rank = 0; - $group_type = GROUP_OPEN; - } - else - { - $group_desc_data = generate_text_for_edit($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_options']); - $group_rank = $group_row['group_rank']; - } - - $sql = 'SELECT * - FROM ' . RANKS_TABLE . ' - WHERE rank_special = 1 - ORDER BY rank_title'; - $result = $db->sql_query($sql); - - $rank_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $selected = ($group_rank && $row['rank_id'] == $group_rank) ? ' selected="selected"' : ''; - $rank_options .= ''; - } - $db->sql_freeresult($result); - - $type_free = ($group_type == GROUP_FREE) ? ' checked="checked"' : ''; - $type_open = ($group_type == GROUP_OPEN) ? ' checked="checked"' : ''; - $type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : ''; - $type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : ''; - - // Load up stuff for avatars - if ($config['allow_avatar']) - { - $avatars_enabled = false; - $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type'])); - - // Assign min and max values before generating avatar driver html - $template->assign_vars(array( - 'AVATAR_MIN_WIDTH' => $config['avatar_min_width'], - 'AVATAR_MAX_WIDTH' => $config['avatar_max_width'], - 'AVATAR_MIN_HEIGHT' => $config['avatar_min_height'], - 'AVATAR_MAX_HEIGHT' => $config['avatar_max_height'], - )); - - foreach ($avatar_drivers as $current_driver) - { - $driver = $phpbb_avatar_manager->get_driver($current_driver); - - $avatars_enabled = true; - $template->set_filenames(array( - 'avatar' => $driver->get_template_name(), - )); - - if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error)) - { - $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); - $driver_upper = strtoupper($driver_name); - $template->assign_block_vars('avatar_drivers', array( - 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), - 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), - - 'DRIVER' => $driver_name, - 'SELECTED' => $current_driver == $selected_driver, - 'OUTPUT' => $template->assign_display('avatar'), - )); - } - } - } - - if (isset($phpbb_avatar_manager) && !$update) - { - // Merge any avatars errors into the primary error array - $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); - } - - $template->assign_vars(array( - 'S_EDIT' => true, - 'S_INCLUDE_SWATCH' => true, - 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', - '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' => (count($error)) ? implode('
', $error) : '', - 'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '', - 'GROUP_MESSAGE_LIMIT' => (isset($group_row['group_message_limit'])) ? $group_row['group_message_limit'] : 0, - 'GROUP_MAX_RECIPIENTS' => (isset($group_row['group_max_recipients'])) ? $group_row['group_max_recipients'] : 0, - - 'GROUP_DESC' => $group_desc_data['text'], - 'S_DESC_BBCODE_CHECKED' => $group_desc_data['allow_bbcode'], - 'S_DESC_URLS_CHECKED' => $group_desc_data['allow_urls'], - 'S_DESC_SMILIES_CHECKED'=> $group_desc_data['allow_smilies'], - - 'S_RANK_OPTIONS' => $rank_options, - - 'GROUP_TYPE_FREE' => GROUP_FREE, - 'GROUP_TYPE_OPEN' => GROUP_OPEN, - 'GROUP_TYPE_CLOSED' => GROUP_CLOSED, - 'GROUP_TYPE_HIDDEN' => GROUP_HIDDEN, - 'GROUP_TYPE_SPECIAL' => GROUP_SPECIAL, - - 'GROUP_FREE' => $type_free, - 'GROUP_OPEN' => $type_open, - 'GROUP_CLOSED' => $type_closed, - 'GROUP_HIDDEN' => $type_hidden, - - 'S_UCP_ACTION' => $this->u_action . "&action=$action&g=$group_id", - 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(), - )); - - break; - - case 'list': - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - list(, $row) = each($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $user->add_lang(array('acp/groups', 'acp/common')); - $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 - FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . " ug - WHERE ug.group_id = $group_id - AND u.user_id = ug.user_id - AND ug.group_leader = 1 - ORDER BY ug.user_pending DESC, u.username_clean"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('leader', array( - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => $row['user_colour'], - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'U_USER_VIEW' => get_username_string('profile', $row['user_id'], $row['username']), - 'S_GROUP_DEFAULT' => ($row['group_id'] == $group_id) ? true : false, - 'JOINED' => ($row['user_regdate']) ? $user->format_date($row['user_regdate']) : ' - ', - 'USER_POSTS' => $row['user_posts'], - 'USER_ID' => $row['user_id']) - ); - } - $db->sql_freeresult($result); - - // Total number of group members (non-leaders) - $sql = 'SELECT COUNT(user_id) AS total_members - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - AND group_leader = 0"; - $result = $db->sql_query($sql); - $total_members = (int) $db->sql_fetchfield('total_members'); - $db->sql_freeresult($result); - - // Grab the members - $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_colour, u.user_regdate, u.user_posts, u.group_id, ug.group_leader, ug.user_pending - FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . " ug - WHERE ug.group_id = $group_id - AND u.user_id = ug.user_id - AND ug.group_leader = 0 - ORDER BY ug.user_pending DESC, u.username_clean"; - $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); - - $pending = false; - $approved = false; - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['user_pending'] && !$pending) - { - $template->assign_block_vars('member', array( - 'S_PENDING' => true) - ); - $template->assign_var('S_PENDING_SET', true); - - $pending = true; - } - else if (!$row['user_pending'] && !$approved) - { - $template->assign_block_vars('member', array( - 'S_APPROVED' => true) - ); - $template->assign_var('S_APPROVED_SET', true); - - $approved = true; - } - - $template->assign_block_vars('member', array( - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => $row['user_colour'], - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'U_USER_VIEW' => get_username_string('profile', $row['user_id'], $row['username']), - 'S_GROUP_DEFAULT' => ($row['group_id'] == $group_id) ? true : false, - 'JOINED' => ($row['user_regdate']) ? $user->format_date($row['user_regdate']) : ' - ', - 'USER_POSTS' => $row['user_posts'], - 'USER_ID' => $row['user_id']) - ); - } - $db->sql_freeresult($result); - - $s_action_options = ''; - $options = array('default' => 'DEFAULT', 'approve' => 'APPROVE', 'deleteusers' => 'DELETE'); - - foreach ($options as $option => $lang) - { - $s_action_options .= ''; - } - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - $base_url = $this->u_action . "&action=$action&g=$group_id"; - $start = $pagination->validate_start($start, $config['topics_per_page'], $total_members); - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_members, $config['topics_per_page'], $start); - - $template->assign_vars(array( - 'S_LIST' => true, - 'S_ACTION_OPTIONS' => $s_action_options, - - 'U_ACTION' => $this->u_action . "&g=$group_id", - 'S_UCP_ACTION' => $this->u_action . "&g=$group_id", - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=usernames'), - )); - - break; - - case 'approve': - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - list(, $row) = each($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $user->add_lang('acp/groups'); - - // Approve, demote or promote - group_user_attributes('approve', $group_id, $mark_ary, false, false); - - trigger_error($user->lang['USERS_APPROVED'] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - - break; - - case 'default': - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - list(, $row) = each($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $group_row['group_name'] = $group_helper->get_name($group_row['group_name']); - - if (confirm_box(true)) - { - if (!count($mark_ary)) - { - $start = 0; - - do - { - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . " - WHERE group_id = $group_id - ORDER BY user_id"; - $result = $db->sql_query_limit($sql, 200, $start); - - $mark_ary = array(); - if ($row = $db->sql_fetchrow($result)) - { - do - { - $mark_ary[] = $row['user_id']; - } - while ($row = $db->sql_fetchrow($result)); - - group_user_attributes('default', $group_id, $mark_ary, false, $group_row['group_name'], $group_row); - - $start = (count($mark_ary) < 200) ? 0 : $start + 200; - } - else - { - $start = 0; - } - $db->sql_freeresult($result); - } - while ($start); - } - else - { - group_user_attributes('default', $group_id, $mark_ary, false, $group_row['group_name'], $group_row); - } - - $user->add_lang('acp/groups'); - - trigger_error($user->lang['GROUP_DEFS_UPDATED'] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - else - { - $user->add_lang('acp/common'); - - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'mark' => $mark_ary, - 'g' => $group_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action)) - ); - } - - // redirect to last screen - redirect($this->u_action . '&action=list&g=' . $group_id); - - break; - - case 'deleteusers': - - $user->add_lang(array('acp/groups', 'acp/common')); - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - list(, $row) = each($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $group_row['group_name'] = $group_helper->get_name($group_row['group_name']); - - if (confirm_box(true)) - { - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - $error = group_user_del($group_id, $mark_ary, false, $group_row['group_name']); - - if ($error) - { - trigger_error($user->lang[$error] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - - trigger_error($user->lang['GROUP_USERS_REMOVE'] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'mark' => $mark_ary, - 'g' => $group_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action)) - ); - } - - // redirect to last screen - redirect($this->u_action . '&action=list&g=' . $group_id); - - break; - - case 'addusers': - - $user->add_lang(array('acp/groups', 'acp/common')); - - $names = $request->variable('usernames', '', true); - - if (!$group_id) - { - trigger_error($user->lang['NO_GROUP'] . $return_page); - } - - if (!$names) - { - trigger_error($user->lang['NO_USERS'] . $return_page); - } - - if (!($row = group_memberships($group_id, $user->data['user_id']))) - { - trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page); - } - list(, $row) = each($row); - - if (!$row['group_leader']) - { - trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page); - } - - $name_ary = array_unique(explode("\n", $names)); - $group_name = $group_helper->get_name($group_row['group_name']); - - $default = $request->variable('default', 0); - - if (confirm_box(true)) - { - $return_manage_page = '

' . $language->lang('RETURN_PAGE', '', ''); - - // Add user/s to group - if ($error = group_user_add($group_id, false, $name_ary, $group_name, $default, 0, 0, $group_row)) - { - $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($language->lang('GROUP_USERS_ADDED') . $return_manage_page); - } - else - { - $s_hidden_fields = array( - 'default' => $default, - 'usernames' => $names, - 'g' => $group_id, - 'i' => $id, - 'mode' => $mode, - 'action' => $action - ); - - 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'] . '

' . sprintf($user->lang['RETURN_PAGE'], '', '')); - - break; - - default: - $user->add_lang('acp/common'); - - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_desc, g.group_desc_uid, g.group_desc_bitfield, g.group_desc_options, g.group_type, ug.group_leader - FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug - WHERE ug.user_id = ' . $user->data['user_id'] . ' - AND g.group_id = ug.group_id - AND ug.group_leader = 1 - ORDER BY g.group_type DESC, g.group_name'; - $result = $db->sql_query($sql); - - while ($value = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('leader', array( - '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'], - 'GROUP_COLOUR' => $value['group_colour'], - - 'U_LIST' => $this->u_action . "&action=list&g={$value['group_id']}", - 'U_EDIT' => $this->u_action . "&action=edit&g={$value['group_id']}") - ); - } - $db->sql_freeresult($result); - - break; - } - - break; - } - - $this->tpl_name = 'ucp_groups_' . $mode; - } -} diff --git a/install/update/old/includes/ucp/ucp_pm.php b/install/update/old/includes/ucp/ucp_pm.php deleted file mode 100644 index 4d02620..0000000 --- a/install/update/old/includes/ucp/ucp_pm.php +++ /dev/null @@ -1,435 +0,0 @@ - -* @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; -} - -/** -* Private Message Class -* -* $_REQUEST['folder'] display folder with the id used -* $_REQUEST['folder'] inbox|outbox|sentbox display folder with the associated name -* -* Display Messages (default to inbox) - mode=view -* Display single message - mode=view&p=[msg_id] or &p=[msg_id] (short linkage) -* -* if the folder id with (&f=[folder_id]) is used when displaying messages, one query will be saved. If it is not used, phpBB needs to grab -* the folder id first in order to display the input boxes and folder names and such things. ;) phpBB always checks this against the database to make -* sure the user is able to view the message. -* -* Composing Messages (mode=compose): -* To specific user (u=[user_id]) -* To specific group (g=[group_id]) -* Quoting a post (action=quotepost&p=[post_id]) -* Quoting a PM (action=quote&p=[msg_id]) -* Forwarding a PM (action=forward&p=[msg_id]) -*/ -class ucp_pm -{ - var $u_action; - - function main($id, $mode) - { - global $user, $template, $phpbb_root_path, $auth, $phpEx, $db, $config, $request; - - if (!$user->data['is_registered']) - { - trigger_error('NO_MESSAGE'); - } - - // Is PM disabled? - if (!$config['allow_privmsg']) - { - trigger_error('PM_DISABLED'); - } - - $user->add_lang('posting'); - $template->assign_var('S_PRIVMSGS', true); - - // Folder directly specified? - $folder_specified = $request->variable('folder', ''); - - if (!in_array($folder_specified, array('inbox', 'outbox', 'sentbox'))) - { - $folder_specified = (int) $folder_specified; - } - else - { - $folder_specified = ($folder_specified == 'inbox') ? PRIVMSGS_INBOX : (($folder_specified == 'outbox') ? PRIVMSGS_OUTBOX : PRIVMSGS_SENTBOX); - } - - if (!$folder_specified) - { - $mode = (!$mode) ? $request->variable('mode', 'view') : $mode; - } - else - { - $mode = 'view'; - } - - if (!function_exists('get_folder')) - { - include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - } - - switch ($mode) - { - // Compose message - case 'compose': - $action = $request->variable('action', 'post'); - - $user_folders = get_folder($user->data['user_id']); - - if ($action != 'delete' && !$auth->acl_get('u_sendpm')) - { - // trigger_error('NO_AUTH_SEND_MESSAGE'); - $template->assign_vars(array( - 'S_NO_AUTH_SEND_MESSAGE' => true, - 'S_COMPOSE_PM_VIEW' => true, - )); - - $tpl_file = 'ucp_pm_viewfolder'; - break; - } - - 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'; - break; - - case 'options': - set_user_message_limit(); - get_folder($user->data['user_id']); - - 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'; - break; - - case 'drafts': - - get_folder($user->data['user_id']); - $this->p_name = 'pm'; - - 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; - $module->main($id, $mode); - - $this->tpl_name = $module->tpl_name; - $this->page_title = 'UCP_PM_DRAFTS'; - - unset($module); - return; - - break; - - case 'view': - - set_user_message_limit(); - - if ($folder_specified) - { - $folder_id = $folder_specified; - $action = 'view_folder'; - } - else - { - $folder_id = $request->variable('f', PRIVMSGS_NO_BOX); - $action = $request->variable('action', 'view_folder'); - } - - $msg_id = $request->variable('p', 0); - $view = $request->variable('view', ''); - - // View message if specified - if ($msg_id) - { - $action = 'view_message'; - } - - 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'); - } - - // 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->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) - { - $move_pm = true; - $dest_folder = (int) $mark_option; - $submit_mark = false; - } - - // Move PM - if ($move_pm) - { - $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)) - { - // Return to folder view if single message moved - if ($action == 'view_message') - { - $msg_id = 0; - $folder_id = $request->variable('cur_folder_id', PRIVMSGS_NO_BOX); - $action = 'view_folder'; - } - } - } - - // Message Mark Options - if ($submit_mark) - { - handle_mark_actions($user->data['user_id'], $mark_option); - } - - // If new messages arrived, place them into the appropriate folder - $num_not_moved = $num_removed = 0; - $release = $request->variable('release', 0); - - if ($user->data['user_new_privmsg'] && ($action == 'view_folder' || $action == 'view_message')) - { - $return = place_pm_into_folder($global_privmsgs_rules, $release); - $num_not_moved = $return['not_moved']; - $num_removed = $return['removed']; - } - - if (!$msg_id && $folder_id == PRIVMSGS_NO_BOX) - { - $folder_id = PRIVMSGS_INBOX; - } - else if ($msg_id && $folder_id == PRIVMSGS_NO_BOX) - { - $sql = 'SELECT folder_id - FROM ' . PRIVMSGS_TO_TABLE . " - WHERE msg_id = $msg_id - AND folder_id <> " . PRIVMSGS_NO_BOX . ' - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_MESSAGE'); - } - $folder_id = (int) $row['folder_id']; - } - - if ($request->variable('mark', '') == 'all' && check_link_hash($request->variable('token', ''), 'mark_all_pms_read')) - { - mark_folder_read($user->data['user_id'], $folder_id); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PM_MARK_ALL_READ_SUCCESS']; - - if ($request->is_ajax()) - { - $json_response = new \phpbb\json_response(); - $json_response->send(array( - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $message, - 'success' => true, - )); - } - $message .= '

' . $user->lang('RETURN_UCP', '', ''); - - trigger_error($message); - } - - $message_row = array(); - if ($action == 'view_message' && $msg_id) - { - // Get Message user want to see - if ($view == 'next' || $view == 'previous') - { - $sql_condition = ($view == 'next') ? '>' : '<'; - $sql_ordering = ($view == 'next') ? 'ASC' : 'DESC'; - - $sql = 'SELECT t.msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TABLE . " p2 - WHERE p2.msg_id = $msg_id - AND t.folder_id = $folder_id - AND t.user_id = " . $user->data['user_id'] . " - AND t.msg_id = p.msg_id - AND p.message_time $sql_condition p2.message_time - ORDER BY p.message_time $sql_ordering"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $message = ($view == 'next') ? 'NO_NEWER_PM' : 'NO_OLDER_PM'; - trigger_error($message); - } - else - { - $msg_id = $row['msg_id']; - } - } - - $sql = 'SELECT t.*, p.*, u.* - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE t.user_id = ' . $user->data['user_id'] . " - AND p.author_id = u.user_id - AND t.folder_id = $folder_id - AND t.msg_id = p.msg_id - AND p.msg_id = $msg_id"; - $result = $db->sql_query($sql); - $message_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$message_row) - { - trigger_error('NO_MESSAGE'); - } - - // Update unread status - update_unread_status($message_row['pm_unread'], $message_row['msg_id'], $user->data['user_id'], $folder_id); - } - - $folder = get_folder($user->data['user_id'], $folder_id); - - $s_folder_options = $s_to_folder_options = ''; - foreach ($folder as $f_id => $folder_ary) - { - $option = '' . $folder_ary['folder_name'] . (($folder_ary['unread_messages']) ? ' [' . $folder_ary['unread_messages'] . '] ' : '') . ''; - - $s_to_folder_options .= ($f_id != PRIVMSGS_OUTBOX && $f_id != PRIVMSGS_SENTBOX) ? $option : ''; - $s_folder_options .= $option; - } - clean_sentbox($folder[PRIVMSGS_SENTBOX]['num_messages']); - - // Header for message view - folder and so on - $folder_status = get_folder_status($folder_id, $folder); - - $template->assign_vars(array( - 'CUR_FOLDER_ID' => $folder_id, - 'CUR_FOLDER_NAME' => $folder_status['folder_name'], - 'NUM_NOT_MOVED' => $num_not_moved, - 'NUM_REMOVED' => $num_removed, - 'RELEASE_MESSAGE_INFO' => sprintf($user->lang['RELEASE_MESSAGES'], '', ''), - 'NOT_MOVED_MESSAGES' => $user->lang('NOT_MOVED_MESSAGES', (int) $num_not_moved), - 'RULE_REMOVED_MESSAGES' => $user->lang('RULE_REMOVED_MESSAGES', (int) $num_removed), - - 'S_FOLDER_OPTIONS' => $s_folder_options, - 'S_TO_FOLDER_OPTIONS' => $s_to_folder_options, - 'S_FOLDER_ACTION' => $this->u_action . '&action=view_folder', - 'S_PM_ACTION' => $this->u_action . '&action=' . $action, - - 'U_INBOX' => $this->u_action . '&folder=inbox', - 'U_OUTBOX' => $this->u_action . '&folder=outbox', - 'U_SENTBOX' => $this->u_action . '&folder=sentbox', - 'U_CREATE_FOLDER' => $this->u_action . '&mode=options', - 'U_CURRENT_FOLDER' => $this->u_action . '&folder=' . $folder_id, - 'U_MARK_ALL' => $this->u_action . '&folder=' . $folder_id . '&mark=all&token=' . generate_link_hash('mark_all_pms_read'), - - 'S_IN_INBOX' => ($folder_id == PRIVMSGS_INBOX) ? true : false, - 'S_IN_OUTBOX' => ($folder_id == PRIVMSGS_OUTBOX) ? true : false, - 'S_IN_SENTBOX' => ($folder_id == PRIVMSGS_SENTBOX) ? true : false, - - 'FOLDER_STATUS' => $folder_status['message'], - 'FOLDER_MAX_MESSAGES' => $folder_status['max'], - 'FOLDER_CUR_MESSAGES' => $folder_status['cur'], - 'FOLDER_REMAINING_MESSAGES' => $folder_status['remaining'], - 'FOLDER_PERCENT' => $folder_status['percent']) - ); - - if ($action == 'view_folder') - { - 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'; - } - else if ($action == 'view_message') - { - $template->assign_vars(array( - 'S_VIEW_MESSAGE' => true, - 'L_RETURN_TO_FOLDER' => $user->lang('RETURN_TO', $folder_status['folder_name']), - 'MSG_ID' => $msg_id, - )); - - if (!$msg_id) - { - trigger_error('NO_MESSAGE'); - } - - 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'; - } - - break; - - default: - trigger_error('NO_ACTION_MODE', E_USER_ERROR); - break; - } - - $template->assign_vars(array( - 'L_TITLE' => $user->lang['UCP_PM_' . strtoupper($mode)], - 'S_UCP_ACTION' => $this->u_action . ((isset($action)) ? "&action=$action" : '')) - ); - - // Set desired template - $this->tpl_name = $tpl_file; - $this->page_title = 'UCP_PM_' . strtoupper($mode); - } -} diff --git a/install/update/old/includes/ucp/ucp_pm_compose.php b/install/update/old/includes/ucp/ucp_pm_compose.php deleted file mode 100644 index 543db4f..0000000 --- a/install/update/old/includes/ucp/ucp_pm_compose.php +++ /dev/null @@ -1,1546 +0,0 @@ - -* @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; -} - -/** -* Compose private message -* Called from ucp_pm with mode == 'compose' -*/ -function compose_pm($id, $mode, $action, $user_folders = array()) -{ - global $template, $db, $auth, $user, $cache; - global $phpbb_root_path, $phpEx, $config; - 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; - - 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) - { - $action = 'post'; - } - add_form_key('ucp_pm_compose'); - - // Grab only parameters needed here - $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->variable('reply_to_all', 0); - - $address_list = $request->variable('address_list', array('' => array(0 => ''))); - - $preview = (isset($_POST['preview'])) ? true : false; - $save = (isset($_POST['save'])) ? true : false; - $load = (isset($_POST['load'])) ? true : false; - $cancel = (isset($_POST['cancel']) && !isset($_POST['save'])) ? true : false; - $delete = (isset($_POST['delete'])) ? true : false; - - $remove_u = (isset($_REQUEST['remove_u'])) ? true : false; - $remove_g = (isset($_REQUEST['remove_g'])) ? true : false; - $add_to = (isset($_REQUEST['add_to'])) ? true : false; - $add_bcc = (isset($_REQUEST['add_bcc'])) ? true : false; - - $refresh = isset($_POST['add_file']) || isset($_POST['delete_file']) || $save || $load - || $remove_u || $remove_g || $add_to || $add_bcc; - $submit = $request->is_set_post('post') && !$refresh && !$preview; - - $action = ($delete && !$preview && !$refresh && $submit) ? 'delete' : $action; - $select_single = ($config['allow_mass_pm'] && $auth->acl_get('u_masspm')) ? false : true; - - $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) - { - if ($msg_id) - { - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&action=view_message&p=' . $msg_id)); - } - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm')); - } - - // Since viewtopic.php language entries are used in several modes, - // we include the language file here - $user->add_lang('viewtopic'); - - /** - * Modify the default vars before composing a PM - * - * @event core.ucp_pm_compose_modify_data - * @var int msg_id post_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 the message is to - * @var bool submit Whether the form has been submitted - * @var bool preview Whether the user is previewing the PM or not - * @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. - * @since 3.1.4-RC1 - */ - $vars = array( - 'msg_id', - 'to_user_id', - 'to_group_id', - 'submit', - 'preview', - 'action', - 'delete', - 'reply_to_all', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_modify_data', compact($vars))); - - // Output PM_TO box if message composing - if ($action != 'edit') - { - // 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, g.group_colour - FROM ' . GROUPS_TABLE . ' g'; - - if (!$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) - { - $sql .= ' LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ')'; - } - - $sql .= ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? ' WHERE ' : ' AND '; - - $sql .= 'g.group_receive_pm = 1 - ORDER BY g.group_type DESC, g.group_name ASC'; - $result = $db->sql_query($sql); - - $group_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - $group_options .= '' . $group_helper->get_name($row['group_name']) . ''; - } - $db->sql_freeresult($result); - } - - $template->assign_vars(array( - 'S_SHOW_PM_BOX' => true, - 'S_ALLOW_MASS_PM' => ($config['allow_mass_pm'] && $auth->acl_get('u_masspm')) ? true : false, - 'S_GROUP_OPTIONS' => ($config['allow_mass_pm'] && $auth->acl_get('u_masspm_group')) ? $group_options : '', - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=searchuser&form=postform&field=username_list&select_single=" . (int) $select_single), - )); - } - - $sql = ''; - $folder_id = 0; - - // What is all this following SQL for? Well, we need to know - // some basic information in all cases before we do anything. - switch ($action) - { - case 'post': - if (!$auth->acl_get('u_sendpm')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_SEND_MESSAGE'); - } - break; - - case 'reply': - case 'quote': - case 'forward': - case 'quotepost': - if (!$msg_id) - { - trigger_error('NO_MESSAGE'); - } - - if (!$auth->acl_get('u_sendpm')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_SEND_MESSAGE'); - } - - if ($action == 'quotepost') - { - $sql = 'SELECT p.post_id as msg_id, p.forum_id, p.post_text as message_text, p.poster_id as author_id, p.post_time as message_time, p.bbcode_bitfield, p.bbcode_uid, p.enable_sig, p.enable_smilies, p.enable_magic_url, t.topic_title as message_subject, u.username as quote_username - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . USERS_TABLE . " u - WHERE p.post_id = $msg_id - AND t.topic_id = p.topic_id - AND u.user_id = p.poster_id"; - } - else - { - $sql = 'SELECT t.folder_id, p.*, u.username as quote_username - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE t.user_id = ' . $user->data['user_id'] . " - AND p.author_id = u.user_id - AND t.msg_id = p.msg_id - AND p.msg_id = $msg_id"; - } - break; - - case 'edit': - if (!$msg_id) - { - trigger_error('NO_MESSAGE'); - } - - // check for outbox (not read) status, we do not allow editing if one user already having the message - $sql = 'SELECT p.*, t.folder_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p - WHERE t.user_id = ' . $user->data['user_id'] . ' - AND t.folder_id = ' . PRIVMSGS_OUTBOX . " - AND t.msg_id = $msg_id - AND t.msg_id = p.msg_id"; - break; - - case 'delete': - if (!$auth->acl_get('u_pm_delete')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_DELETE_MESSAGE'); - } - - if (!$msg_id) - { - trigger_error('NO_MESSAGE'); - } - - $sql = 'SELECT msg_id, pm_unread, pm_new, author_id, folder_id - FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE user_id = ' . $user->data['user_id'] . " - AND msg_id = $msg_id"; - break; - - case 'smilies': - generate_smilies('window', 0); - break; - - default: - trigger_error('NO_ACTION_MODE', E_USER_ERROR); - break; - } - - 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'); - } - - if ($sql) - { - /** - * Alter sql query to get message for user to write the PM - * - * @event core.ucp_pm_compose_compose_pm_basic_info_query_before - * @var string sql String with the query to be executed - * @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 - * @var bool submit Whether the user is sending the PM or not - * @var bool preview Whether the user is previewing the PM or not - * @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. - * @since 3.1.0-RC5 - * @changed 3.2.0-a1 Removed undefined variables - */ - $vars = array( - 'sql', - 'msg_id', - 'to_user_id', - 'to_group_id', - 'submit', - 'preview', - 'action', - 'delete', - 'reply_to_all', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_compose_pm_basic_info_query_before', compact($vars))); - - $result = $db->sql_query($sql); - $post = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$post) - { - // If editing it could be the recipient already read the message... - if ($action == 'edit') - { - $sql = 'SELECT p.*, t.folder_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p - WHERE t.user_id = ' . $user->data['user_id'] . " - AND t.msg_id = $msg_id - AND t.msg_id = p.msg_id"; - $result = $db->sql_query($sql); - $post = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($post) - { - trigger_error('NO_EDIT_READ_MESSAGE'); - } - } - - trigger_error('NO_MESSAGE'); - } - - if ($action == 'quotepost') - { - 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'); - } - - /** - * Get the result of querying for the post to be quoted in the pm message - * - * @event core.ucp_pm_compose_quotepost_query_after - * @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 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 - * @var bool preview Whether the user is previewing the PM or not - * @var string action One of: post, reply, quote, forward, quotepost, edit, delete, smilies - * @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', - 'to_user_id', - 'to_group_id', - 'submit', - 'preview', - 'action', - 'delete', - 'reply_to_all', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_quotepost_query_after', compact($vars))); - - // Passworded forum? - if ($post['forum_id']) - { - $sql = 'SELECT forum_id, forum_name, forum_password - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . (int) $post['forum_id']; - $result = $db->sql_query($sql); - $forum_data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!empty($forum_data['forum_password'])) - { - login_forum_box($forum_data); - } - } - } - - $msg_id = (int) $post['msg_id']; - $folder_id = (isset($post['folder_id'])) ? $post['folder_id'] : 0; - $message_text = (isset($post['message_text'])) ? $post['message_text'] : ''; - - if ((!$post['author_id'] || ($post['author_id'] == ANONYMOUS && $action != 'delete')) && $msg_id) - { - trigger_error('NO_AUTHOR'); - } - - if ($action == 'quotepost') - { - // Decode text for message display - decode_message($message_text, $post['bbcode_uid']); - } - - if ($action != 'delete') - { - $enable_urls = $post['enable_magic_url']; - $enable_sig = (isset($post['enable_sig'])) ? $post['enable_sig'] : 0; - - $message_attachment = (isset($post['message_attachment'])) ? $post['message_attachment'] : 0; - $message_subject = $post['message_subject']; - $message_time = $post['message_time']; - $bbcode_uid = $post['bbcode_uid']; - - $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') && !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) - { - $address_list = array('u' => array($post['author_id'] => 'to')); - } - else - { - // We try to include every previously listed member from the TO Header - Reply to all - $address_list = rebuild_header(array('to' => $post['to_address'])); - - // Add the author (if he is already listed then this is no shame (it will be overwritten)) - $address_list['u'][$post['author_id']] = 'to'; - - // Now, make sure the user itself is not listed. ;) - if (isset($address_list['u'][$user->data['user_id']])) - { - unset($address_list['u'][$user->data['user_id']]); - } - } - } - 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'])); - } - - if ($action == 'quotepost') - { - $check_value = 0; - } - else - { - $check_value = (($post['enable_bbcode']+1) << 8) + (($post['enable_smilies']+1) << 4) + (($enable_urls+1) << 2) + (($post['enable_sig']+1) << 1); - } - } - } - else - { - $message_attachment = 0; - $message_text = $message_subject = ''; - - /** - * Predefine message text and subject - * - * @event core.ucp_pm_compose_predefined_message - * @var string message_text Message text - * @var string message_subject Messate subject - * @since 3.1.11-RC1 - */ - $vars = array('message_text', 'message_subject'); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_predefined_message', compact($vars))); - - if ($to_user_id && $to_user_id != ANONYMOUS && $action == 'post') - { - $address_list['u'][$to_user_id] = 'to'; - } - else if ($to_group_id && $action == 'post') - { - $address_list['g'][$to_group_id] = 'to'; - } - $check_value = 0; - } - - 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'); - } - - if ($action == 'edit' && !$refresh && !$preview && !$submit) - { - if (!($message_time > time() - ($config['pm_edit_time'] * 60) || !$config['pm_edit_time'])) - { - trigger_error('CANNOT_EDIT_MESSAGE_TIME'); - } - } - - if ($action == 'post') - { - $template->assign_var('S_NEW_MESSAGE', true); - } - - if (!isset($icon_id)) - { - $icon_id = 0; - } - - /* @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; - unset($message_text); - - $s_action = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=$mode&action=$action", true, $user->session_id); - $s_action .= (($folder_id) ? "&f=$folder_id" : '') . (($msg_id) ? "&p=$msg_id" : ''); - - // Delete triggered ? - if ($action == 'delete') - { - // Folder id has been determined by the SQL Statement - // $folder_id = $request->variable('f', PRIVMSGS_NO_BOX); - - // Do we need to confirm ? - if (confirm_box(true)) - { - delete_pm($user->data['user_id'], $msg_id, $folder_id); - - // jump to next message in "history"? nope, not for the moment. But able to be included later. - $meta_info = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&folder=$folder_id"); - $message = $user->lang['MESSAGE_DELETED']; - - meta_refresh(3, $meta_info); - $message .= '

' . sprintf($user->lang['RETURN_FOLDER'], '', ''); - trigger_error($message); - } - else - { - $s_hidden_fields = array( - 'p' => $msg_id, - 'f' => $folder_id, - 'action' => 'delete' - ); - - // "{$phpbb_root_path}ucp.$phpEx?i=pm&mode=compose" - confirm_box(false, 'DELETE_MESSAGE', build_hidden_fields($s_hidden_fields)); - } - - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&action=view_message&p=' . $msg_id)); - } - - // Get maximum number of allowed recipients - $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 - if (($action == 'reply' || $action == 'quote') && $max_recipients && $reply_to_all) - { - // We try to include every previously listed member from the TO Header - $list = rebuild_header(array('to' => $post['to_address'])); - - // Can be an empty array too ;) - $list = (!empty($list['u'])) ? $list['u'] : array(); - $list[$post['author_id']] = 'to'; - - if (isset($list[$user->data['user_id']])) - { - unset($list[$user->data['user_id']]); - } - - $max_recipients = ($max_recipients < count($list)) ? count($list) : $max_recipients; - - unset($list); - } - - // Handle User/Group adding/removing - handle_message_list_actions($address_list, $error, $remove_u, $remove_g, $add_to, $add_bcc); - - // Check mass pm to group permission - if ((!$config['allow_mass_pm'] || !$auth->acl_get('u_masspm_group')) && !empty($address_list['g'])) - { - $address_list = array(); - $error[] = $user->lang['NO_AUTH_GROUP_MESSAGE']; - } - - // Check mass pm to users permission - if ((!$config['allow_mass_pm'] || !$auth->acl_get('u_masspm')) && num_recipients($address_list) > 1) - { - $address_list = get_recipients($address_list, 1); - $error[] = $user->lang('TOO_MANY_RECIPIENTS', 1); - } - - // Check for too many 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); - } - - // Always check if the submitted attachment data is valid and belongs to the user. - // Further down (especially in submit_post()) we do not check this again. - $message_parser->get_submitted_attachment_data(); - - if ($message_attachment && !$submit && !$refresh && !$preview && $action == 'edit') - { - // Do not change to SELECT * - $sql = 'SELECT attach_id, is_orphan, attach_comment, real_filename, filesize - FROM ' . ATTACHMENTS_TABLE . " - WHERE post_msg_id = $msg_id - AND in_message = 1 - AND is_orphan = 0 - ORDER BY filetime DESC"; - $result = $db->sql_query($sql); - $message_parser->attachment_data = array_merge($message_parser->attachment_data, $db->sql_fetchrowset($result)); - $db->sql_freeresult($result); - } - - if (!in_array($action, array('quote', 'edit', 'delete', 'forward'))) - { - $enable_sig = ($config['allow_sig'] && $config['allow_sig_pm'] && $auth->acl_get('u_sig') && $user->optionget('attachsig')); - $enable_smilies = ($config['allow_smilies'] && $auth->acl_get('u_pm_smilies') && $user->optionget('smilies')); - $enable_bbcode = ($config['allow_bbcode'] && $auth->acl_get('u_pm_bbcode') && $user->optionget('bbcode')); - $enable_urls = true; - } - - $drafts = false; - - // User own some drafts? - if ($auth->acl_get('u_savedrafts') && $action != 'delete') - { - $sql = 'SELECT draft_id - FROM ' . DRAFTS_TABLE . ' - WHERE forum_id = 0 - AND topic_id = 0 - AND user_id = ' . $user->data['user_id'] . - (($draft_id) ? " AND draft_id <> $draft_id" : ''); - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $drafts = true; - } - } - - if ($action == 'edit') - { - $message_parser->bbcode_uid = $bbcode_uid; - } - - $bbcode_status = ($config['allow_bbcode'] && $config['auth_bbcode_pm'] && $auth->acl_get('u_pm_bbcode')) ? true : false; - $smilies_status = ($config['allow_smilies'] && $config['auth_smilies_pm'] && $auth->acl_get('u_pm_smilies')) ? true : false; - $img_status = ($config['auth_img_pm'] && $auth->acl_get('u_pm_img')) ? true : false; - $flash_status = ($config['auth_flash_pm'] && $auth->acl_get('u_pm_flash')) ? true : false; - $url_status = ($config['allow_post_links']) ? true : false; - - // Save Draft - if ($save && $auth->acl_get('u_savedrafts')) - { - $subject = $request->variable('subject', '', true); - $subject = (!$subject && $action != 'post') ? $user->lang['NEW_MESSAGE'] : $subject; - $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_parser->message, - ) - ); - $db->sql_query($sql); - - $redirect_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=$mode"); - - meta_refresh(3, $redirect_url); - $message = $user->lang['DRAFT_SAVED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - - trigger_error($message); - } - else - { - $s_hidden_fields = build_hidden_fields(array( - 'mode' => $mode, - 'action' => $action, - 'save' => true, - 'subject' => $subject, - 'message' => $message, - 'u' => $to_user_id, - 'g' => $to_group_id, - 'p' => $msg_id) - ); - $s_hidden_fields .= build_address_field($address_list); - - confirm_box(false, 'SAVE_DRAFT', $s_hidden_fields); - } - } - else - { - if (utf8_clean_string($subject) === '') - { - $error[] = $user->lang['EMPTY_MESSAGE_SUBJECT']; - } - - if (utf8_clean_string($message) === '') - { - $error[] = $user->lang['TOO_FEW_CHARS']; - } - } - - unset($subject, $message); - } - - // Load Draft - if ($draft_id && $auth->acl_get('u_savedrafts')) - { - $sql = 'SELECT draft_subject, draft_message - FROM ' . DRAFTS_TABLE . " - WHERE draft_id = $draft_id - AND topic_id = 0 - AND forum_id = 0 - AND user_id = " . $user->data['user_id']; - $result = $db->sql_query_limit($sql, 1); - - if ($row = $db->sql_fetchrow($result)) - { - $message_parser->message = $row['draft_message']; - $message_subject = $row['draft_subject']; - - $template->assign_var('S_DRAFT_LOADED', true); - } - else - { - $draft_id = 0; - } - $db->sql_freeresult($result); - } - - // Load Drafts - if ($load && $drafts) - { - load_drafts(0, 0, $id, $action, $msg_id); - } - - if ($submit || $preview || $refresh) - { - if (($submit || $preview) && !check_form_key('ucp_pm_compose')) - { - $error[] = $user->lang['FORM_INVALID']; - } - $subject = $request->variable('subject', '', true); - $message_parser->message = $request->variable('message', '', true); - - $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; - $enable_urls = (isset($_POST['disable_magic_url'])) ? 0 : 1; - $enable_sig = (!$config['allow_sig'] ||!$config['allow_sig_pm']) ? false : ((isset($_POST['attach_sig'])) ? true : false); - - /** - * Modify private message - * - * @event core.ucp_pm_compose_modify_parse_before - * @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 bool enable_sig Whether or not signature is enabled - * @var string subject PM subject text - * @var object message_parser The message parser object - * @var bool submit Whether or not the form has been sumitted - * @var bool preview Whether or not the signature is being previewed - * @var array error Any error strings - * @since 3.1.10-RC1 - */ - $vars = array( - 'enable_bbcode', - 'enable_smilies', - 'enable_urls', - 'enable_sig', - 'subject', - 'message_parser', - 'submit', - 'preview', - 'error', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_modify_parse_before', compact($vars))); - - // Parse Attachments - before checksum is calculated - $message_parser->parse_attachments('fileupload', $action, 0, $submit, $preview, $refresh, true); - - if (count($message_parser->warn_msg) && !($remove_u || $remove_g || $add_to || $add_bcc)) - { - $error[] = implode('
', $message_parser->warn_msg); - $message_parser->warn_msg = array(); - } - - // Parse message - $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 (count($message_parser->warn_msg) && !$refresh) - { - $error[] = implode('
', $message_parser->warn_msg); - } - - if ($action != 'edit' && !$preview && !$refresh && $config['flood_interval'] && !$auth->acl_get('u_ignoreflood')) - { - // Flood check - $last_post_time = $user->data['user_lastpost_time']; - - if ($last_post_time) - { - if ($last_post_time && ($current_time - $last_post_time) < intval($config['flood_interval'])) - { - $error[] = $user->lang['FLOOD_ERROR']; - } - } - } - - // Subject defined - if ($submit) - { - if (utf8_clean_string($subject) === '') - { - $error[] = $user->lang['EMPTY_MESSAGE_SUBJECT']; - } - - if (!count($address_list)) - { - $error[] = $user->lang['NO_RECIPIENT']; - } - } - - // Store message, sync counters - if (!count($error) && $submit) - { - $pm_data = array( - 'msg_id' => (int) $msg_id, - 'from_user_id' => $user->data['user_id'], - 'from_user_ip' => $user->ip, - 'from_username' => $user->data['username'], - 'reply_from_root_level' => (isset($post['root_level'])) ? (int) $post['root_level'] : 0, - 'reply_from_msg_id' => (int) $msg_id, - 'icon_id' => (int) $icon_id, - 'enable_sig' => (bool) $enable_sig, - 'enable_bbcode' => (bool) $enable_bbcode, - 'enable_smilies' => (bool) $enable_smilies, - 'enable_urls' => (bool) $enable_urls, - 'bbcode_bitfield' => $message_parser->bbcode_bitfield, - 'bbcode_uid' => $message_parser->bbcode_uid, - 'message' => $message_parser->message, - 'attachment_data' => $message_parser->attachment_data, - 'filename_data' => $message_parser->filename_data, - 'address_list' => $address_list - ); - - // ((!$message_subject) ? $subject : $message_subject) - $msg_id = submit_pm($action, $subject, $pm_data); - - $return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&p=' . $msg_id); - $inbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'); - $outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); - - $folder_url = ''; - if (($folder_id > 0) && isset($user_folders[$folder_id])) - { - $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id); - } - - $return_box_url = ($action === 'post' || $action === 'edit') ? $outbox_folder_url : $inbox_folder_url; - $return_box_lang = ($action === 'post' || $action === 'edit') ? 'PM_OUTBOX' : 'PM_INBOX'; - - $save_message = ($action === 'edit') ? $user->lang['MESSAGE_EDITED'] : $user->lang['MESSAGE_STORED']; - $message = $save_message . '

' . $user->lang('VIEW_PRIVATE_MESSAGE', '', ''); - - $last_click_type = 'CLICK_RETURN_FOLDER'; - if ($folder_url) - { - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); - $last_click_type = 'CLICK_GOTO_FOLDER'; - } - $message .= '

' . sprintf($user->lang[$last_click_type], '', '', $user->lang[$return_box_lang]); - - meta_refresh(3, $return_message_url); - trigger_error($message); - } - - $message_subject = $subject; - } - - // Preview - if (!count($error) && $preview) - { - $preview_message = $message_parser->format_display($enable_bbcode, $enable_urls, $enable_smilies, false); - - $preview_signature = $user->data['user_sig']; - $preview_signature_uid = $user->data['user_sig_bbcode_uid']; - $preview_signature_bitfield = $user->data['user_sig_bbcode_bitfield']; - - // Signature - if ($enable_sig && $config['allow_sig'] && $preview_signature) - { - $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 - { - $preview_signature = ''; - } - - // Attachment Preview - if (count($message_parser->attachment_data)) - { - $template->assign_var('S_HAS_ATTACHMENTS', true); - - $update_count = array(); - $attachment_data = $message_parser->attachment_data; - - parse_attachments(false, $preview_message, $attachment_data, $update_count, true); - - foreach ($attachment_data as $i => $attachment) - { - $template->assign_block_vars('attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - unset($attachment_data); - } - - $preview_subject = censor_text($subject); - - if (!count($error)) - { - $template->assign_vars(array( - 'PREVIEW_SUBJECT' => $preview_subject, - 'PREVIEW_MESSAGE' => $preview_message, - 'PREVIEW_SIGNATURE' => $preview_signature, - - 'S_DISPLAY_PREVIEW' => true) - ); - } - unset($message_text); - } - - // Decode text for message display - $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); - - if (($action == 'quote' || $action == 'quotepost') && !$preview && !$refresh && !$submit) - { - if ($action == 'quotepost') - { - $post_id = $request->variable('p', 0); - if ($config['allow_post_links']) - { - $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 - { - $message_link = $user->lang['SUBJECT'] . $user->lang['COLON'] . ' ' . $message_subject . " (" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id})\n\n"; - } - } - else - { - $message_link = ''; - } - $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']; - } - - /** @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); - } - - if ($action == 'forward' && !$preview && !$refresh && !$submit) - { - $fwd_to_field = write_pm_addresses(array('to' => $post['to_address']), 0, true); - - if ($config['allow_post_links']) - { - $quote_username_text = '[url=' . generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$post['author_id']}]{$quote_username}[/url]"; - } - else - { - $quote_username_text = $quote_username . ' (' . generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$post['author_id']})"; - } - - $forward_text = array(); - $forward_text[] = $user->lang['FWD_ORIGINAL_MESSAGE']; - $forward_text[] = sprintf($user->lang['FWD_SUBJECT'], censor_text($message_subject)); - $forward_text[] = sprintf($user->lang['FWD_DATE'], $user->format_date($message_time, false, true)); - $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'])); - - $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); - } - - $attachment_data = $message_parser->attachment_data; - $filename_data = $message_parser->filename_data; - $message_text = $message_parser->message; - - // MAIN PM PAGE BEGINS HERE - - // Generate smiley listing - generate_smilies('inline', 0); - - // Generate PM Icons - $s_pm_icons = false; - if ($config['enable_pm_icons']) - { - $s_pm_icons = posting_gen_topic_icons($action, $icon_id); - } - - // Generate inline attachment select box - posting_gen_inline_attachments($attachment_data); - - // Build address list for display - // array('u' => array($author_id => 'to')); - if (count($address_list)) - { - // Get Usernames and Group Names - $result = array(); - if (!empty($address_list['u'])) - { - $sql = 'SELECT user_id as id, username as name, user_colour as colour - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_map('intval', array_keys($address_list['u']))) . ' - ORDER BY username_clean ASC'; - $result['u'] = $db->sql_query($sql); - } - - if (!empty($address_list['g'])) - { - $sql = 'SELECT g.group_id AS id, g.group_name AS name, g.group_colour AS colour, g.group_type - FROM ' . GROUPS_TABLE . ' g'; - - if (!$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) - { - $sql .= ' LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ')'; - } - - $sql .= ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? ' WHERE ' : ' AND '; - - $sql .= 'g.group_receive_pm = 1 - AND ' . $db->sql_in_set('g.group_id', array_map('intval', array_keys($address_list['g']))) . ' - ORDER BY g.group_name ASC'; - - $result['g'] = $db->sql_query($sql); - } - - $u = $g = array(); - $_types = array('u', 'g'); - foreach ($_types as $type) - { - if (isset($result[$type]) && $result[$type]) - { - while ($row = $db->sql_fetchrow($result[$type])) - { - if ($type == 'g') - { - $row['name'] = $group_helper->get_name($row['name']); - } - - ${$type}[$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']); - } - $db->sql_freeresult($result[$type]); - } - } - - // Now Build the address list - foreach ($address_list as $type => $adr_ary) - { - foreach ($adr_ary as $id => $field) - { - if (!isset(${$type}[$id])) - { - unset($address_list[$type][$id]); - continue; - } - - $field = ($field == 'to') ? 'to' : 'bcc'; - $type = ($type == 'u') ? 'u' : 'g'; - $id = (int) $id; - - $tpl_ary = array( - 'IS_GROUP' => ($type == 'g') ? true : false, - 'IS_USER' => ($type == 'u') ? true : false, - 'UG_ID' => $id, - 'NAME' => ${$type}[$id]['name'], - 'COLOUR' => (${$type}[$id]['colour']) ? '#' . ${$type}[$id]['colour'] : '', - 'TYPE' => $type, - ); - - if ($type == 'u') - { - $tpl_ary = array_merge($tpl_ary, array( - 'U_VIEW' => get_username_string('profile', $id, ${$type}[$id]['name'], ${$type}[$id]['colour']), - 'NAME_FULL' => get_username_string('full', $id, ${$type}[$id]['name'], ${$type}[$id]['colour']), - )); - } - else - { - $tpl_ary = array_merge($tpl_ary, array( - 'U_VIEW' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $id), - )); - } - - $template->assign_block_vars($field . '_recipient', $tpl_ary); - } - } - } - - // Build hidden address list - $s_hidden_address_field = build_address_field($address_list); - - $bbcode_checked = (isset($enable_bbcode)) ? !$enable_bbcode : (($config['allow_bbcode'] && $auth->acl_get('u_pm_bbcode')) ? !$user->optionget('bbcode') : 1); - $smilies_checked = (isset($enable_smilies)) ? !$enable_smilies : (($config['allow_smilies'] && $auth->acl_get('u_pm_smilies')) ? !$user->optionget('smilies') : 1); - $urls_checked = (isset($enable_urls)) ? !$enable_urls : 0; - $sig_checked = $enable_sig; - - switch ($action) - { - case 'post': - $page_title = $user->lang['POST_NEW_PM']; - break; - - case 'quote': - $page_title = $user->lang['POST_QUOTE_PM']; - break; - - case 'quotepost': - $page_title = $user->lang['POST_PM_POST']; - break; - - case 'reply': - $page_title = $user->lang['POST_REPLY_PM']; - break; - - case 'edit': - $page_title = $user->lang['POST_EDIT_PM']; - break; - - case 'forward': - $page_title = $user->lang['POST_FORWARD_PM']; - break; - - default: - trigger_error('NO_ACTION_MODE', E_USER_ERROR); - break; - } - - $s_hidden_fields = (isset($check_value)) ? '' : ''; - $s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '' : ''; - - $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_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' => $user->lang(($bbcode_status ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '', ''), - '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' => (count($error)) ? implode('
', $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, - 'S_EDIT_POST' => ($action == 'edit'), - 'S_SHOW_PM_ICONS' => $s_pm_icons, - 'S_BBCODE_ALLOWED' => ($bbcode_status) ? 1 : 0, - 'S_BBCODE_CHECKED' => ($bbcode_checked) ? ' checked="checked"' : '', - 'S_SMILIES_ALLOWED' => $smilies_status, - 'S_SMILIES_CHECKED' => ($smilies_checked) ? ' checked="checked"' : '', - 'S_SIG_ALLOWED' => ($config['allow_sig'] && $config['allow_sig_pm'] && $auth->acl_get('u_sig')), - 'S_SIGNATURE_CHECKED' => ($sig_checked) ? ' checked="checked"' : '', - 'S_LINKS_ALLOWED' => $url_status, - 'S_MAGIC_URL_CHECKED' => ($urls_checked) ? ' checked="checked"' : '', - 'S_SAVE_ALLOWED' => ($auth->acl_get('u_savedrafts') && $action != 'edit') ? true : false, - 'S_HAS_DRAFTS' => ($auth->acl_get('u_savedrafts') && $drafts), - 'S_FORM_ENCTYPE' => $form_enctype, - 'S_ATTACH_DATA' => json_encode($message_parser->attachment_data), - - 'S_BBCODE_IMG' => $img_status, - 'S_BBCODE_FLASH' => $flash_status, - 'S_BBCODE_QUOTE' => true, - 'S_BBCODE_URL' => $url_status, - - 'S_POST_ACTION' => $s_action, - 'S_HIDDEN_ADDRESS_FIELD' => $s_hidden_address_field, - 'S_HIDDEN_FIELDS' => $s_hidden_fields, - - 'S_CLOSE_PROGRESS_WINDOW' => isset($_POST['add_file']), - 'U_PROGRESS_BAR' => append_sid("{$phpbb_root_path}posting.$phpEx", 'f=0&mode=popup'), - 'UA_PROGRESS_BAR' => addslashes(append_sid("{$phpbb_root_path}posting.$phpEx", 'f=0&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(); - - // Show attachment box for adding attachments if true - $allowed = ($auth->acl_get('u_pm_attach') && $config['allow_pm_attach'] && $form_enctype); - - if ($allowed) - { - $max_files = ($auth->acl_gets('a_', 'm_')) ? 0 : (int) $config['max_attachments_pm']; - $plupload->configure($cache, $template, $s_action, false, $max_files); - } - - // Attachment entry - posting_gen_attachment_entry($attachment_data, $filename_data, $allowed); - - // Message History - if ($action == 'reply' || $action == 'quote' || $action == 'forward') - { - if (message_history($msg_id, $user->data['user_id'], $post, array(), true)) - { - $template->assign_var('S_DISPLAY_HISTORY', true); - } - } -} - -/** -* For composing messages, handle list actions -*/ -function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove_g, $add_to, $add_bcc) -{ - global $auth, $db, $user; - global $request, $phpbb_dispatcher; - - // Delete User [TO/BCC] - if ($remove_u && $request->variable('remove_u', array(0 => ''))) - { - $remove_user_id = array_keys($request->variable('remove_u', array(0 => ''))); - - if (isset($remove_user_id[0])) - { - unset($address_list['u'][(int) $remove_user_id[0]]); - } - } - - // Delete Group [TO/BCC] - if ($remove_g && $request->variable('remove_g', array(0 => ''))) - { - $remove_group_id = array_keys($request->variable('remove_g', array(0 => ''))); - - if (isset($remove_group_id[0])) - { - unset($address_list['g'][(int) $remove_group_id[0]]); - } - } - - // Add Selected Groups - $group_list = $request->variable('group_list', array(0)); - - // Build usernames to add - $usernames = $request->variable('username', '', true); - $usernames = (empty($usernames)) ? array() : array($usernames); - - $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 && (count($group_list) || count($usernames))) - { - $add_to = true; - - global $refresh, $submit, $preview; - - $refresh = true; - $submit = false; - - // Preview is only true if there was also a message entered - if ($request->variable('message', '')) - { - $preview = true; - } - } - - // Add User/Group [TO] - if ($add_to || $add_bcc) - { - $type = ($add_to) ? 'to' : 'bcc'; - - if (count($group_list)) - { - foreach ($group_list as $group_id) - { - $address_list['g'][$group_id] = $type; - } - } - - // User ID's to add... - $user_id_ary = array(); - - // Reveal the correct user_ids - 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 (!count($user_id_ary)) - { - $error[] = $user->lang['PM_NO_USERS']; - } - } - - // Add Friends if specified - $friend_list = array_keys($request->variable('add_' . $type, array(0))); - $user_id_ary = array_merge($user_id_ary, $friend_list); - - foreach ($user_id_ary as $user_id) - { - if ($user_id == ANONYMOUS) - { - continue; - } - - $address_list['u'][$user_id] = $type; - } - } - - // Check for disallowed recipients - if (!empty($address_list['u'])) - { - $can_ignore_allow_pm = $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'); - - // Administrator deactivated users check and we need to check their - // PM status (do they want to receive PM's?) - // Only check PM status if not a moderator or admin, since they - // are allowed to override this user setting - $sql = 'SELECT user_id, user_allow_pm - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($address_list['u'])) . ' - AND ( - (user_type = ' . USER_INACTIVE . ' - AND user_inactive_reason = ' . INACTIVE_MANUAL . ') - ' . ($can_ignore_allow_pm ? '' : ' OR user_allow_pm = 0') . ' - )'; - - $result = $db->sql_query($sql); - - $removed_no_pm = $removed_no_permission = false; - while ($row = $db->sql_fetchrow($result)) - { - if (!$can_ignore_allow_pm && !$row['user_allow_pm']) - { - $removed_no_pm = true; - } - else - { - $removed_no_permission = true; - } - - unset($address_list['u'][$row['user_id']]); - } - $db->sql_freeresult($result); - - // print a notice about users not being added who do not want to receive pms - if ($removed_no_pm) - { - $error[] = $user->lang['PM_USERS_REMOVED_NO_PM']; - } - - // print a notice about users not being added who do not have permission to receive PMs - if ($removed_no_permission) - { - $error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION']; - } - - if (!count(array_keys($address_list['u']))) - { - return; - } - - // Check if users have permission to read PMs - $can_read = $auth->acl_get_list(array_keys($address_list['u']), 'u_readpm'); - $can_read = (empty($can_read) || !isset($can_read[0]['u_readpm'])) ? array() : $can_read[0]['u_readpm']; - $cannot_read_list = array_diff(array_keys($address_list['u']), $can_read); - if (!empty($cannot_read_list)) - { - foreach ($cannot_read_list as $cannot_read) - { - unset($address_list['u'][$cannot_read]); - } - - $error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION']; - } - - // Check if users are banned - $banned_user_list = phpbb_get_banned_user_ids(array_keys($address_list['u']), false); - if (!empty($banned_user_list)) - { - foreach ($banned_user_list as $banned_user) - { - unset($address_list['u'][$banned_user]); - } - - $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->variable(). -*/ -function build_address_field($address_list) -{ - $s_hidden_address_field = ''; - foreach ($address_list as $type => $adr_ary) - { - foreach ($adr_ary as $id => $field) - { - $s_hidden_address_field .= ''; - } - } - return $s_hidden_address_field; -} - -/** -* Return number of private message recipients -*/ -function num_recipients($address_list) -{ - $num_recipients = 0; - - foreach ($address_list as $field => $adr_ary) - { - $num_recipients += count($adr_ary); - } - - return $num_recipients; -} - -/** -* Get number of 'num_recipients' recipients from first position -*/ -function get_recipients($address_list, $num_recipients = 1) -{ - $recipient = array(); - - $count = 0; - foreach ($address_list as $field => $adr_ary) - { - foreach ($adr_ary as $id => $type) - { - if ($count >= $num_recipients) - { - break 2; - } - $recipient[$field][$id] = $type; - $count++; - } - } - - return $recipient; -} diff --git a/install/update/old/includes/ucp/ucp_pm_viewfolder.php b/install/update/old/includes/ucp/ucp_pm_viewfolder.php deleted file mode 100644 index 09e7bf4..0000000 --- a/install/update/old/includes/ucp/ucp_pm_viewfolder.php +++ /dev/null @@ -1,604 +0,0 @@ - -* @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; -} - -/** -* View message folder -* Called from ucp_pm with mode == 'view' && action == 'view_folder' -*/ -function view_folder($id, $mode, $folder_id, $folder) -{ - 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']); - - if (!$submit_export) - { - $user->add_lang('viewforum'); - - // Grab icons - $icons = $cache->obtain_icons(); - - $color_rows = array('message_reported', 'marked', 'replied'); - - $_module = new p_master(); - $_module->list_modules('ucp'); - $_module->set_active('zebra'); - - $zebra_enabled = ($_module->active_module === false) ? false : true; - - unset($_module); - - if ($zebra_enabled) - { - $color_rows = array_merge($color_rows, array('friend', 'foe')); - } - - foreach ($color_rows as $var) - { - $template->assign_block_vars('pm_colour_info', array( - 'IMG' => $user->img("pm_{$var}", ''), - 'CLASS' => "pm_{$var}_colour", - 'LANG' => $user->lang[strtoupper($var) . '_MESSAGE']) - ); - } - - $mark_options = array('mark_important', 'delete_marked'); - - // Minimise edits - if (!$auth->acl_get('u_pm_delete') && $key = array_search('delete_marked', $mark_options)) - { - unset($mark_options[$key]); - } - - $s_mark_options = ''; - foreach ($mark_options as $mark_option) - { - $s_mark_options .= ''; - } - - // We do the folder moving options here too, for template authors to use... - $s_folder_move_options = ''; - if ($folder_id != PRIVMSGS_NO_BOX && $folder_id != PRIVMSGS_OUTBOX) - { - foreach ($folder as $f_id => $folder_ary) - { - if ($f_id == PRIVMSGS_OUTBOX || $f_id == PRIVMSGS_SENTBOX || $f_id == $folder_id) - { - continue; - } - - $s_folder_move_options .= ''; - $s_folder_move_options .= sprintf($user->lang['MOVE_MARKED_TO_FOLDER'], $folder_ary['folder_name']); - $s_folder_move_options .= (($folder_ary['unread_messages']) ? ' [' . $folder_ary['unread_messages'] . '] ' : '') . ''; - } - } - $friend = $foe = array(); - - // Get friends and foes - $sql = 'SELECT * - FROM ' . ZEBRA_TABLE . ' - WHERE user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $friend[$row['zebra_id']] = $row['friend']; - $foe[$row['zebra_id']] = $row['foe']; - } - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'S_MARK_OPTIONS' => $s_mark_options, - 'S_MOVE_MARKED_OPTIONS' => $s_folder_move_options) - ); - - // Okay, lets dump out the page ... - if (count($folder_info['pm_list'])) - { - $address_list = array(); - - // Build Recipient List if in outbox/sentbox - max two additional queries - if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) - { - $address_list = get_recipient_strings($folder_info['rowset']); - } - - foreach ($folder_info['pm_list'] as $message_id) - { - $row = &$folder_info['rowset'][$message_id]; - - $folder_img = ($row['pm_unread']) ? 'pm_unread' : 'pm_read'; - $folder_alt = ($row['pm_unread']) ? 'NEW_MESSAGES' : 'NO_NEW_MESSAGES'; - - // Generate all URIs ... - $view_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=view&f=$folder_id&p=$message_id"); - $remove_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=compose&action=delete&p=$message_id"); - - $row_indicator = ''; - foreach ($color_rows as $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']])) - { - $row_indicator = $var; - break; - } - } - - // Send vars to template - $template->assign_block_vars('messagerow', array( - 'PM_CLASS' => ($row_indicator) ? 'pm_' . $row_indicator . '_colour' : '', - - 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $row['author_id'], $row['username'], $row['user_colour'], $row['username']), - 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $row['author_id'], $row['username'], $row['user_colour'], $row['username']), - 'MESSAGE_AUTHOR' => get_username_string('username', $row['author_id'], $row['username'], $row['user_colour'], $row['username']), - 'U_MESSAGE_AUTHOR' => get_username_string('profile', $row['author_id'], $row['username'], $row['user_colour'], $row['username']), - - 'FOLDER_ID' => $folder_id, - 'MESSAGE_ID' => $message_id, - 'SENT_TIME' => $user->format_date($row['message_time']), - 'SUBJECT' => censor_text($row['message_subject']), - 'FOLDER' => (isset($folder[$row['folder_id']])) ? $folder[$row['folder_id']]['folder_name'] : '', - 'U_FOLDER' => (isset($folder[$row['folder_id']])) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'folder=' . $row['folder_id']) : '', - 'PM_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? '' : '', - 'PM_ICON_URL' => (!empty($icons[$row['icon_id']])) ? $config['icons_path'] . '/' . $icons[$row['icon_id']]['img'] : '', - 'FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'FOLDER_IMG_STYLE' => $folder_img, - 'PM_IMG' => ($row_indicator) ? $user->img('pm_' . $row_indicator, '') : '', - 'ATTACH_ICON_IMG' => ($auth->acl_get('u_pm_download') && $row['message_attachment'] && $config['allow_pm_attach']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', - - 'S_PM_UNREAD' => ($row['pm_unread']) ? true : false, - 'S_PM_DELETED' => ($row['pm_deleted']) ? true : false, - 'S_PM_REPORTED' => (isset($row['report_id'])) ? true : false, - 'S_AUTHOR_DELETED' => ($row['author_id'] == ANONYMOUS) ? true : false, - - 'U_VIEW_PM' => ($row['pm_deleted']) ? '' : $view_message_url, - 'U_REMOVE_PM' => ($row['pm_deleted']) ? $remove_message_url : '', - 'U_MCP_REPORT' => (isset($row['report_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=pm_reports&mode=pm_report_details&r=' . $row['report_id']) : '', - 'RECIPIENTS' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? implode($user->lang['COMMA_SEPARATOR'], $address_list[$message_id]) : '') - ); - } - unset($folder_info['rowset']); - - $template->assign_vars(array( - 'S_SHOW_RECIPIENTS' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? true : false, - 'S_SHOW_COLOUR_LEGEND' => true, - - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'PM_REPORTED'), - 'S_PM_ICONS' => ($config['enable_pm_icons']) ? true : false) - ); - } - } - else - { - $export_type = $request->variable('export_option', ''); - $enclosure = $request->variable('enclosure', ''); - $delimiter = $request->variable('delimiter', ''); - - if ($export_type == 'CSV' && ($delimiter === '' || $enclosure === '')) - { - $template->assign_var('PROMPT', true); - } - else - { - // Build Recipient List if in outbox/sentbox - - $address_temp = $address = $data = array(); - - if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) - { - foreach ($folder_info['rowset'] as $message_id => $row) - { - $address_temp[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address'])); - $address[$message_id] = array(); - } - } - - foreach ($folder_info['pm_list'] as $message_id) - { - $row = &$folder_info['rowset'][$message_id]; - - include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - - $sql = 'SELECT p.message_text, p.bbcode_uid - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE t.user_id = ' . $user->data['user_id'] . " - AND p.author_id = u.user_id - AND t.folder_id = $folder_id - AND t.msg_id = p.msg_id - AND p.msg_id = $message_id"; - $result = $db->sql_query_limit($sql, 1); - $message_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $_types = array('u', 'g'); - foreach ($_types as $ug_type) - { - if (isset($address_temp[$message_id][$ug_type]) && count($address_temp[$message_id][$ug_type])) - { - if (!isset($address[$message_id][$ug_type])) - { - $address[$message_id][$ug_type] = array(); - } - if ($ug_type == 'u') - { - $sql = 'SELECT user_id as id, username as name - FROM ' . USERS_TABLE . ' - WHERE '; - } - else - { - $sql = 'SELECT group_id as id, group_name as name - FROM ' . GROUPS_TABLE . ' - WHERE '; - } - $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($address_temp[$message_id][$ug_type]))); - - $result = $db->sql_query($sql); - - while ($info_row = $db->sql_fetchrow($result)) - { - $address[$message_id][$ug_type][$address_temp[$message_id][$ug_type][$info_row['id']]][] = $info_row['name']; - unset($address_temp[$message_id][$ug_type][$info_row['id']]); - } - $db->sql_freeresult($result); - } - } - - // 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']) && 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(); - $address[$message_id]['u']['to'][] = $user->lang['UNDISCLOSED_RECIPIENT']; - } - - decode_message($message_row['message_text'], $message_row['bbcode_uid']); - - $data[] = array( - 'subject' => censor_text($row['message_subject']), - 'sender' => $row['username'], - // ISO 8601 date. For PHP4 we are able to hardcode the timezone because $user->format_date() does not set it. - 'date' => $user->format_date($row['message_time'], 'c', true), - 'to' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? $address[$message_id] : '', - 'message' => $message_row['message_text'] - ); - } - - switch ($export_type) - { - case 'CSV': - case 'CSV_EXCEL': - $mimetype = 'text/csv'; - $filetype = 'csv'; - - if ($export_type == 'CSV_EXCEL') - { - $enclosure = '"'; - $delimiter = ','; - $newline = "\r\n"; - } - else - { - $newline = "\n"; - } - - $string = ''; - foreach ($data as $value) - { - $recipients = $value['to']; - $value['to'] = $value['bcc'] = ''; - - if (is_array($recipients)) - { - foreach ($recipients as $values) - { - $value['bcc'] .= (isset($values['bcc']) && is_array($values['bcc'])) ? ',' . implode(',', $values['bcc']) : ''; - $value['to'] .= (isset($values['to']) && is_array($values['to'])) ? ',' . implode(',', $values['to']) : ''; - } - - // Remove the commas which will appear before the first entry. - $value['to'] = substr($value['to'], 1); - $value['bcc'] = substr($value['bcc'], 1); - } - - foreach ($value as $tag => $text) - { - $cell = str_replace($enclosure, $enclosure . $enclosure, $text); - - if (strpos($cell, $enclosure) !== false || strpos($cell, $delimiter) !== false || strpos($cell, $newline) !== false) - { - $string .= $enclosure . $text . $enclosure . $delimiter; - } - else - { - $string .= $cell . $delimiter; - } - } - $string = substr($string, 0, -1) . $newline; - } - break; - - case 'XML': - $mimetype = 'application/xml'; - $filetype = 'xml'; - $string = '' . "\n"; - $string .= "\n"; - - foreach ($data as $value) - { - $string .= "\t\n"; - - if (is_array($value['to'])) - { - foreach ($value['to'] as $key => $values) - { - foreach ($values as $type => $types) - { - foreach ($types as $name) - { - $string .= "\t\t$name\n"; - } - } - } - } - - unset($value['to']); - - foreach ($value as $tag => $text) - { - $string .= "\t\t<$tag>$text\n"; - } - - $string .= "\t\n"; - } - $string .= ''; - break; - } - - header('Cache-Control: private, no-cache'); - header("Content-Type: $mimetype; name=\"data.$filetype\""); - header("Content-disposition: attachment; filename=data.$filetype"); - echo $string; - exit; - } - } -} - -/** -* Get Messages from folder/user -*/ -function get_pm_from($folder_id, $folder, $user_id) -{ - global $user, $db, $template, $config, $auth, $phpbb_container, $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher; - - $start = $request->variable('start', 0); - - // Additional vars later, pm ordering is mostly different from post ordering. :/ - $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 - $limit_days = array(0 => $user->lang['ALL_MESSAGES'], 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']); - - // No sort by Author for sentbox/outbox (already only author available) - // Also, sort by msg_id for the time - private messages are not as prone to errors as posts are. - if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) - { - $sort_by_text = array('t' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); - $sort_by_sql = array('t' => 'p.message_time', 's' => array('p.message_subject', 'p.message_time')); - } - else - { - $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); - $sort_by_sql = array('a' => array('u.username_clean', 'p.message_time'), 't' => 'p.message_time', 's' => array('p.message_subject', 'p.message_time')); - } - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - 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); - - $folder_sql = 't.folder_id = ' . (int) $folder_id; - - // Limit pms to certain time frame, obtain correct pm count - if ($sort_days) - { - $min_post_time = time() - ($sort_days * 86400); - - if (isset($_POST['sort'])) - { - $start = 0; - } - - $sql = 'SELECT COUNT(t.msg_id) AS pm_count - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . " p - WHERE $folder_sql - AND t.user_id = $user_id - AND t.msg_id = p.msg_id - AND p.message_time >= $min_post_time"; - $result = $db->sql_query_limit($sql, 1); - $pm_count = (int) $db->sql_fetchfield('pm_count'); - $db->sql_freeresult($result); - - $sql_limit_time = "AND p.message_time >= $min_post_time"; - } - else - { - $pm_count = (!empty($folder[$folder_id]['num_messages'])) ? $folder[$folder_id]['num_messages'] : 0; - $sql_limit_time = ''; - } - - $base_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=view&action=view_folder&f=$folder_id&$u_sort_param"); - $start = $pagination->validate_start($start, $config['topics_per_page'], $pm_count); - $pagination->generate_template_pagination($base_url, 'pagination', 'start', $pm_count, $config['topics_per_page'], $start); - - $template_vars = array( - 'TOTAL_MESSAGES' => $user->lang('VIEW_PM_MESSAGES', (int) $pm_count), - - 'POST_IMG' => (!$auth->acl_get('u_sendpm')) ? $user->img('button_topic_locked', 'POST_PM_LOCKED') : $user->img('button_pm_new', 'POST_NEW_PM'), - - 'S_NO_AUTH_SEND_MESSAGE' => !$auth->acl_get('u_sendpm'), - - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_TOPIC_ICONS' => ($config['enable_pm_icons']) ? true : false, - - 'U_POST_NEW_TOPIC' => ($auth->acl_get('u_sendpm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose') : '', - 'S_PM_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=view&action=view_folder&f=$folder_id" . (($start !== 0) ? "&start=$start" : '')), - ); - - /** - * Modify template variables before they are assigned - * - * @event core.ucp_pm_view_folder_get_pm_from_template - * @var int folder_id Folder ID - * @var array folder Folder data - * @var int user_id User ID - * @var string base_url Pagination base URL - * @var int start Pagination start - * @var int pm_count Count of PMs - * @var array template_vars Template variables to be assigned - * @since 3.1.11-RC1 - */ - $vars = array( - 'folder_id', - 'folder', - 'user_id', - 'base_url', - 'start', - 'pm_count', - 'template_vars', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_view_folder_get_pm_from_template', compact($vars))); - - $template->assign_vars($template_vars); - - // Grab all pm data - $rowset = $pm_list = array(); - - // If the user is trying to reach late pages, start searching from the end - $store_reverse = false; - $sql_limit = $config['topics_per_page']; - if ($start > $pm_count / 2) - { - $store_reverse = true; - - // Select the sort order - $direction = ($sort_dir == 'd') ? 'ASC' : 'DESC'; - $sql_limit = $pagination->reverse_limit($start, $sql_limit, $pm_count); - $sql_start = $pagination->reverse_start($start, $sql_limit, $pm_count); - } - else - { - // Select the sort order - $direction = ($sort_dir == 'd') ? 'DESC' : 'ASC'; - $sql_start = $start; - } - - // Sql sort order - if (is_array($sort_by_sql[$sort_key])) - { - $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction; - } - else - { - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction; - } - - $sql_ary = array( - 'SELECT' => 't.*, p.root_level, p.message_time, p.message_subject, p.icon_id, p.to_address, p.message_attachment, p.bcc_address, u.username, u.username_clean, u.user_colour, p.message_reported', - 'FROM' => array( - PRIVMSGS_TO_TABLE => 't', - PRIVMSGS_TABLE => 'p', - USERS_TABLE => 'u', - ), - 'WHERE' => "t.user_id = $user_id - AND p.author_id = u.user_id - AND $folder_sql - AND t.msg_id = p.msg_id - $sql_limit_time", - 'ORDER_BY' => $sql_sort_order, - ); - - /** - * Modify SQL before it is executed - * - * @event core.ucp_pm_view_folder_get_pm_from_sql - * @var array sql_ary SQL array - * @var int sql_limit SQL limit - * @var int sql_start SQL start - * @since 3.1.11-RC1 - */ - $vars = array( - 'sql_ary', - 'sql_limit', - 'sql_start', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_pm_view_folder_get_pm_from_sql', compact($vars))); - - $result = $db->sql_query_limit($db->sql_build_query('SELECT', $sql_ary), $sql_limit, $sql_start); - - $pm_reported = array(); - while ($row = $db->sql_fetchrow($result)) - { - $rowset[$row['msg_id']] = $row; - $pm_list[] = $row['msg_id']; - if ($row['message_reported']) - { - $pm_reported[] = $row['msg_id']; - } - } - $db->sql_freeresult($result); - - // Fetch the report_ids, if there are any reported pms. - if (!empty($pm_reported) && $auth->acl_getf_global('m_report')) - { - $sql = 'SELECT pm_id, report_id - FROM ' . REPORTS_TABLE . ' - WHERE report_closed = 0 - AND ' . $db->sql_in_set('pm_id', $pm_reported); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $rowset[$row['pm_id']]['report_id'] = $row['report_id']; - } - $db->sql_freeresult($result); - } - - $pm_list = ($store_reverse) ? array_reverse($pm_list) : $pm_list; - - return array( - 'pm_count' => $pm_count, - 'pm_list' => $pm_list, - 'rowset' => $rowset - ); -} diff --git a/install/update/old/includes/ucp/ucp_profile.php b/install/update/old/includes/ucp/ucp_profile.php deleted file mode 100644 index 9a12840..0000000 --- a/install/update/old/includes/ucp/ucp_profile.php +++ /dev/null @@ -1,847 +0,0 @@ - -* @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; -} - -/** -* ucp_profile -* Changing profile settings -* -* @todo what about pertaining user_sig_options? -*/ -class ucp_profile -{ - var $u_action; - - function main($id, $mode) - { - global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; - global $request, $phpbb_container, $phpbb_log, $phpbb_dispatcher; - - $user->add_lang('posting'); - - $submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST); - $error = $data = array(); - $s_hidden_fields = ''; - - switch ($mode) - { - case 'reg_details': - - $data = array( - '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), - ); - - /** - * Modify user registration data on editing account settings in UCP - * - * @event core.ucp_profile_reg_details_data - * @var array data Array with current or updated user registration data - * @var bool submit Flag indicating if submit button has been pressed - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_data', compact($vars))); - - add_form_key('ucp_reg_details'); - - if ($submit) - { - // Do not check cur_password, it is the old one. - $check_ary = array( - 'new_password' => array( - array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), - array('password')), - 'password_confirm' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), - 'email' => array( - array('string', false, 6, 60), - array('user_email')), - ); - - if ($auth->acl_get('u_chgname') && $config['allow_namechange']) - { - $check_ary['username'] = array( - array('string', false, $config['min_name_chars'], $config['max_name_chars']), - array('username'), - ); - } - - $error = validate_data($data, $check_ary); - - if ($auth->acl_get('u_chgpasswd') && $data['new_password'] && $data['password_confirm'] != $data['new_password']) - { - $error[] = ($data['password_confirm']) ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; - } - - // 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 (!count($error) && $auth->acl_get('u_chgpasswd') && $data['new_password'] && $passwords_manager->check($data['new_password'], $user->data['user_password'])) - { - $error[] = 'SAME_PASSWORD_ERROR'; - } - - if (!$passwords_manager->check($data['cur_password'], $user->data['user_password'])) - { - $error[] = ($data['cur_password']) ? 'CUR_PASSWORD_ERROR' : 'CUR_PASSWORD_EMPTY'; - } - - if (!check_form_key('ucp_reg_details')) - { - $error[] = 'FORM_INVALID'; - } - - /** - * Validate user data on editing registration data in UCP - * - * @event core.ucp_profile_reg_details_validate - * @var array data Array with user profile data - * @var bool submit Flag indicating if submit button has been pressed - * @var array error Array of any generated errors - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit', 'error'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_validate', compact($vars))); - - if (!count($error)) - { - $sql_ary = array( - 'username' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? $data['username'] : $user->data['username'], - 'username_clean' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? utf8_clean_string($data['username']) : $user->data['username_clean'], - 'user_email' => ($auth->acl_get('u_chgemail')) ? $data['email'] : $user->data['user_email'], - 'user_email_hash' => ($auth->acl_get('u_chgemail')) ? 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']) - { - $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'])) - { - $user->reset_login_keys(); - $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']) - { - $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'; - - if ($auth->acl_get('u_chgemail') && $config['email_enable'] && $data['email'] != $user->data['user_email'] && $user->data['user_type'] != USER_FOUNDER && ($config['require_activation'] == USER_ACTIVATION_SELF || $config['require_activation'] == USER_ACTIVATION_ADMIN)) - { - $message = ($config['require_activation'] == USER_ACTIVATION_SELF) ? 'ACCOUNT_EMAIL_CHANGED' : 'ACCOUNT_EMAIL_CHANGED_ADMIN'; - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $server_url = generate_board_url(); - - $user_actkey = gen_rand_string(mt_rand(6, 10)); - - $messenger = new messenger(false); - - $template_file = ($config['require_activation'] == USER_ACTIVATION_ADMIN) ? 'user_activate_inactive' : 'user_activate'; - $messenger->template($template_file, $user->data['user_lang']); - - $messenger->to($data['email'], $data['username']); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($data['username']), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user->data['user_id']}&k=$user_actkey") - ); - - $messenger->send(NOTIFY_EMAIL); - - if ($config['require_activation'] == USER_ACTIVATION_ADMIN) - { - $notifications_manager = $phpbb_container->get('notification_manager'); - $notifications_manager->add_notifications('notification.type.admin_activate_user', array( - 'user_id' => $user->data['user_id'], - 'user_actkey' => $user_actkey, - 'user_regdate' => time(), // Notification time - )); - } - - user_active_flip('deactivate', $user->data['user_id'], INACTIVE_PROFILE); - - // Because we want the profile to be reactivated we set user_newpasswd to empty (else the reactivation will fail) - $sql_ary['user_actkey'] = $user_actkey; - $sql_ary['user_newpasswd'] = ''; - } - - /** - * Modify user registration data before submitting it to the database - * - * @event core.ucp_profile_reg_details_sql_ary - * @var array data Array with current or updated user registration data - * @var array sql_ary Array with user registration data to submit to the database - * @since 3.1.4-RC1 - */ - $vars = array('data', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_sql_ary', compact($vars))); - - if (count($sql_ary)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . $user->data['user_id']; - $db->sql_query($sql); - } - - // Need to update config, forum, topic, posting, messages, etc. - if ($data['username'] != $user->data['username'] && $auth->acl_get('u_chgname') && $config['allow_namechange']) - { - user_update_name($user->data['username'], $data['username']); - } - - // Now, we can remove the user completely (kill the session) - NOT BEFORE!!! - if (!empty($sql_ary['user_actkey'])) - { - meta_refresh(5, append_sid($phpbb_root_path . 'index.' . $phpEx)); - $message = $user->lang[$message] . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - - // Because the user gets deactivated we log him out too, killing his session - $user->session_kill(); - } - else - { - meta_refresh(3, $this->u_action); - $message = $user->lang[$message] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - } - - trigger_error($message); - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $error) : '', - - 'USERNAME' => $data['username'], - 'EMAIL' => $data['email'], - 'PASSWORD_CONFIRM' => $data['password_confirm'], - 'NEW_PASSWORD' => $data['new_password'], - 'CUR_PASSWORD' => '', - - 'L_USERNAME_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), - - 'S_FORCE_PASSWORD' => ($auth->acl_get('u_chgpasswd') && $config['chg_passforce'] && $user->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) ? true : false, - 'S_CHANGE_USERNAME' => ($config['allow_namechange'] && $auth->acl_get('u_chgname')) ? true : false, - 'S_CHANGE_EMAIL' => ($auth->acl_get('u_chgemail')) ? true : false, - 'S_CHANGE_PASSWORD' => ($auth->acl_get('u_chgpasswd')) ? true : false) - ); - break; - - case 'profile_info': - // 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' => $request->variable('jabber', $user->data['user_jabber'], true), - ); - - if ($config['allow_birthdays']) - { - $data['bday_day'] = $data['bday_month'] = $data['bday_year'] = 0; - - if ($user->data['user_birthday']) - { - list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user->data['user_birthday']); - } - - $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']); - } - - /** - * Modify user data on editing profile in UCP - * - * @event core.ucp_profile_modify_profile_info - * @var array data Array with user profile data - * @var bool submit Flag indicating if submit button has been pressed - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_profile_info', compact($vars))); - - add_form_key('ucp_profile_info'); - - if ($submit) - { - $validate_array = array( - 'jabber' => array( - array('string', true, 5, 255), - array('jabber')), - ); - - if ($config['allow_birthdays']) - { - $validate_array = array_merge($validate_array, array( - 'bday_day' => array('num', true, 1, 31), - 'bday_month' => array('num', true, 1, 12), - 'bday_year' => array('num', true, 1901, gmdate('Y', time()) + 50), - 'user_birthday' => array('date', true), - )); - } - - $error = validate_data($data, $validate_array); - - // validate custom profile fields - $cp->submit_cp_field('profile', $user->get_iso_lang_id(), $cp_data, $cp_error); - - if (count($cp_error)) - { - $error = array_merge($error, $cp_error); - } - - if (!check_form_key('ucp_profile_info')) - { - $error[] = 'FORM_INVALID'; - } - - /** - * Validate user data on editing profile in UCP - * - * @event core.ucp_profile_validate_profile_info - * @var array data Array with user profile data - * @var bool submit Flag indicating if submit button has been pressed - * @var array error Array of any generated errors - * @since 3.1.4-RC1 - */ - $vars = array('data', 'submit', 'error'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_validate_profile_info', compact($vars))); - - if (!count($error)) - { - $data['notify'] = $user->data['user_notify_type']; - - if ($data['notify'] == NOTIFY_IM && (!$config['jab_enable'] || !$data['jabber'] || !@extension_loaded('xml'))) - { - // User has not filled in a jabber address (Or one of the modules is disabled or jabber is disabled) - // Disable notify by Jabber now for this user. - $data['notify'] = NOTIFY_EMAIL; - } - - $sql_ary = array( - 'user_jabber' => $data['jabber'], - 'user_notify_type' => $data['notify'], - ); - - if ($config['allow_birthdays']) - { - $sql_ary['user_birthday'] = $data['user_birthday']; - } - - /** - * Modify profile data in UCP before submitting to the database - * - * @event core.ucp_profile_info_modify_sql_ary - * @var array cp_data Array with the user custom profile fields data - * @var array data Array with user profile data - * @var array sql_ary user options data we update - * @since 3.1.4-RC1 - */ - $vars = array('cp_data', 'data', 'sql_ary'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_info_modify_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); - - // Update Custom Fields - $cp->update_profile_field_data($user->data['user_id'], $cp_data); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PROFILE_UPDATED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - if ($config['allow_birthdays']) - { - $s_birthday_day_options = ''; - for ($i = 1; $i < 32; $i++) - { - $selected = ($i == $data['bday_day']) ? ' selected="selected"' : ''; - $s_birthday_day_options .= ""; - } - - $s_birthday_month_options = ''; - for ($i = 1; $i < 13; $i++) - { - $selected = ($i == $data['bday_month']) ? ' selected="selected"' : ''; - $s_birthday_month_options .= ""; - } - - $now = getdate(); - $s_birthday_year_options = ''; - for ($i = $now['year'] - 100; $i <= $now['year']; $i++) - { - $selected = ($i == $data['bday_year']) ? ' selected="selected"' : ''; - $s_birthday_year_options .= ""; - } - unset($now); - - $template->assign_vars(array( - 'S_BIRTHDAY_DAY_OPTIONS' => $s_birthday_day_options, - 'S_BIRTHDAY_MONTH_OPTIONS' => $s_birthday_month_options, - 'S_BIRTHDAY_YEAR_OPTIONS' => $s_birthday_year_options, - 'S_BIRTHDAYS_ENABLED' => true, - )); - } - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $error) : '', - 'S_JABBER_ENABLED' => $config['jab_enable'], - 'JABBER' => $data['jabber'], - )); - - // Get additional profile fields and assign them to the template block var 'profile_fields' - $user->get_profile_fields($user->data['user_id']); - - $cp->generate_profile_fields('profile', $user->get_iso_lang_id()); - - break; - - case 'signature': - - if (!$auth->acl_get('u_sig')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NO_AUTH_SIGNATURE'); - } - - 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']) ? $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; - - $bbcode_flags = ($enable_bbcode ? OPTION_FLAG_BBCODE : 0) + ($enable_smilies ? OPTION_FLAG_SMILIES : 0) + ($enable_urls ? OPTION_FLAG_LINKS : 0); - - $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) - { - $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'; - } - } - - /** - * 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 (!$submit) - { - // Parse it for displaying - $signature_preview = generate_text_for_display($signature, $bbcode_uid, $bbcode_bitfield, $bbcode_flags); - } - else - { - if (!count($error)) - { - $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 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); - - $message = $user->lang['PROFILE_UPDATED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - - if ($request->is_set_post('preview')) - { - $decoded_message = generate_text_for_edit($signature, $bbcode_uid, $bbcode_flags); - } - - /** @var \phpbb\controller\helper $controller_helper */ - $controller_helper = $phpbb_container->get('controller.helper'); - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $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' => $user->lang(($config['allow_sig_bbcode'] ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '', ''), - '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'], - 'URL_STATUS' => ($config['allow_sig_links']) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], - 'MAX_FONT_SIZE' => (int) $config['max_sig_font_size'], - - 'L_SIGNATURE_EXPLAIN' => $user->lang('SIGNATURE_EXPLAIN', (int) $config['max_sig_chars']), - - 'S_BBCODE_ALLOWED' => $config['allow_sig_bbcode'], - 'S_SMILIES_ALLOWED' => $config['allow_sig_smilies'], - 'S_BBCODE_IMG' => ($config['allow_sig_img']) ? true : false, - 'S_BBCODE_FLASH' => ($config['allow_sig_flash']) ? true : false, - 'S_LINKS_ALLOWED' => ($config['allow_sig_links']) ? true : false) - ); - - add_form_key('ucp_sig'); - - // Build custom bbcodes array - display_custom_bbcodes(); - - // Generate smiley listing - generate_smilies('inline', 0); - - break; - - case 'avatar': - - add_form_key('ucp_avatar'); - - $avatars_enabled = false; - - 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(); - - // This is normalised data, without the user_ prefix - $avatar_data = \phpbb\avatar\manager::clean_row($user->data, 'user'); - - if ($submit) - { - if (check_form_key('ucp_avatar')) - { - $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); - - if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) - { - $driver = $phpbb_avatar_manager->get_driver($driver_name); - $result = $driver->process_form($request, $template, $user, $avatar_data, $error); - - if ($result && empty($error)) - { - // Success! Lets save the result in the database - $result = array( - 'user_avatar_type' => $driver_name, - 'user_avatar' => $result['avatar'], - 'user_avatar_width' => $result['avatar_width'], - 'user_avatar_height' => $result['avatar_height'], - ); - - /** - * Trigger events on successfull avatar change - * - * @event core.ucp_profile_avatar_sql - * @var array result Array with data to be stored in DB - * @since 3.1.11-RC1 - */ - $vars = array('result'); - extract($phpbb_dispatcher->trigger_event('core.ucp_profile_avatar_sql', compact($vars))); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $result) . ' - WHERE user_id = ' . (int) $user->data['user_id']; - $db->sql_query($sql); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PROFILE_UPDATED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - } - } - else - { - $error[] = 'FORM_INVALID'; - } - } - - // Handle deletion of avatars - if ($request->is_set_post('avatar_delete')) - { - if (!confirm_box(true)) - { - confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( - 'avatar_delete' => true, - 'i' => $id, - 'mode' => $mode)) - ); - } - else - { - $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, USERS_TABLE, 'user_'); - - meta_refresh(3, $this->u_action); - $message = $user->lang['PROFILE_UPDATED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - } - - $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user->data['user_avatar_type'])); - - $template->assign_vars(array( - 'AVATAR_MIN_WIDTH' => $config['avatar_min_width'], - 'AVATAR_MAX_WIDTH' => $config['avatar_max_width'], - 'AVATAR_MIN_HEIGHT' => $config['avatar_min_height'], - 'AVATAR_MAX_HEIGHT' => $config['avatar_max_height'], - )); - - foreach ($avatar_drivers as $current_driver) - { - $driver = $phpbb_avatar_manager->get_driver($current_driver); - - $avatars_enabled = true; - $template->set_filenames(array( - 'avatar' => $driver->get_template_name(), - )); - - if ($driver->prepare_form($request, $template, $user, $avatar_data, $error)) - { - $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); - $driver_upper = strtoupper($driver_name); - - $template->assign_block_vars('avatar_drivers', array( - 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), - 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), - - 'DRIVER' => $driver_name, - 'SELECTED' => $current_driver == $selected_driver, - 'OUTPUT' => $template->assign_display('avatar'), - )); - } - } - - // Replace "error" strings with their real, localised form - $error = $phpbb_avatar_manager->localize_errors($user, $error); - } - - $avatar = phpbb_get_user_avatar($user->data, 'USER_AVATAR', true); - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $error) : '', - 'AVATAR' => $avatar, - - 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', - - 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(), - - 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled), - )); - - break; - - case 'autologin_keys': - - add_form_key('ucp_autologin_keys'); - - if ($submit) - { - $keys = $request->variable('keys', array('')); - - if (!check_form_key('ucp_autologin_keys')) - { - $error[] = 'FORM_INVALID'; - } - - if (!count($error)) - { - if (!empty($keys)) - { - foreach ($keys as $key => $id) - { - $keys[$key] = $db->sql_like_expression($id . $db->get_any_char()); - } - $sql_where = '(key_id ' . implode(' OR key_id ', $keys) . ')'; - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $user->data['user_id'] . ' - AND ' . $sql_where ; - - $db->sql_query($sql); - - meta_refresh(3, $this->u_action); - $message = $user->lang['AUTOLOGIN_SESSION_KEYS_DELETED'] . '

' . sprintf($user->lang['RETURN_UCP'], '', ''); - trigger_error($message); - } - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - } - - $sql = 'SELECT key_id, last_ip, last_login - FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $user->data['user_id'] . ' - ORDER BY last_login ASC'; - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $template->assign_block_vars('sessions', array( - 'KEY' => substr($row['key_id'], 0, 8), - 'IP' => $row['last_ip'], - 'LOGIN_TIME' => $user->format_date($row['last_login']), - )); - } - - $db->sql_freeresult($result); - - break; - } - - $template->assign_vars(array( - 'ERROR' => (count($error)) ? implode('
', $error) : '', - - 'L_TITLE' => $user->lang['UCP_PROFILE_' . strtoupper($mode)], - - 'S_HIDDEN_FIELDS' => $s_hidden_fields, - 'S_UCP_ACTION' => $this->u_action) - ); - - // Set desired template - $this->tpl_name = 'ucp_profile_' . $mode; - $this->page_title = 'UCP_PROFILE_' . strtoupper($mode); - } -} diff --git a/install/update/old/includes/ucp/ucp_register.php b/install/update/old/includes/ucp/ucp_register.php deleted file mode 100644 index 0e673cb..0000000 --- a/install/update/old/includes/ucp/ucp_register.php +++ /dev/null @@ -1,709 +0,0 @@ - -* @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; -} - -/** -* ucp_register -* Board registration -*/ -class ucp_register -{ - var $u_action; - - function main($id, $mode) - { - global $config, $db, $user, $template, $phpbb_root_path, $phpEx; - global $request, $phpbb_container, $phpbb_dispatcher; - - // - if ($config['require_activation'] == USER_ACTIVATION_DISABLE || - (in_array($config['require_activation'], array(USER_ACTIVATION_SELF, USER_ACTIVATION_ADMIN)) && !$config['email_enable'])) - { - trigger_error('UCP_REGISTER_DISABLE'); - } - - $coppa = $request->is_set('coppa') ? (int) $request->variable('coppa', false) : false; - $agreed = $request->variable('agreed', false); - $submit = $request->is_set_post('submit'); - $change_lang = $request->variable('change_lang', ''); - $user_lang = $request->variable('lang', $user->lang_name); - - /** - * Add UCP register data before they are assigned to the template or submitted - * - * To assign data to the template, use $template->assign_vars() - * - * @event core.ucp_register_requests_after - * @var bool coppa Is set coppa - * @var bool agreed Did user agree to coppa? - * @var bool submit Is set post submit? - * @var string change_lang Change language request - * @var string user_lang User language request - * @since 3.1.11-RC1 - */ - $vars = array( - 'coppa', - 'agreed', - 'submit', - 'change_lang', - 'user_lang', - ); - 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'); - } - - if ($change_lang || $user_lang != $config['default_lang']) - { - $use_lang = ($change_lang) ? basename($change_lang) : basename($user_lang); - - if (!validate_language_iso_name($use_lang)) - { - if ($change_lang) - { - $submit = false; - - // Setting back agreed to let the user view the agreement in his/her language - $agreed = false; - } - - $user_lang = $use_lang; - } - else - { - $change_lang = ''; - $user_lang = $user->lang_name; - } - } - - /* @var $cp \phpbb\profilefields\manager */ - $cp = $phpbb_container->get('profilefields.manager'); - - $error = $cp_data = $cp_error = array(); - $s_hidden_fields = array(); - - // Handle login_link data added to $_hidden_fields - $login_link_data = $this->get_login_link_data_array(); - - 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', '')); - - $result = $auth_provider->login_link_has_necessary_data($login_link_data); - if ($result !== null) - { - $error[] = $user->lang[$result]; - } - - $s_hidden_fields = array_merge($s_hidden_fields, $this->get_login_link_data_for_hidden_fields($login_link_data)); - } - - if (!$agreed || ($coppa === false && $config['coppa_enable']) || ($coppa && !$config['coppa_enable'])) - { - $add_coppa = ($coppa !== false) ? '&coppa=' . $coppa : ''; - - $s_hidden_fields = array_merge($s_hidden_fields, array( - 'change_lang' => '', - )); - - // If we change the language, we want to pass on some more possible parameter. - if ($change_lang) - { - // We do not include the password - $s_hidden_fields = array_merge($s_hidden_fields, array( - 'username' => $request->variable('username', '', true), - 'email' => strtolower($request->variable('email', '')), - 'lang' => $user->lang_name, - 'tz' => $request->variable('tz', $config['board_timezone']), - )); - - } - - // Checking amount of available languages - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE; - $result = $db->sql_query($sql); - - $lang_row = array(); - while ($row = $db->sql_fetchrow($result)) - { - $lang_row[] = $row; - } - $db->sql_freeresult($result); - - if ($coppa === false && $config['coppa_enable']) - { - $now = getdate(); - $coppa_birthday = $user->create_datetime() - ->setDate($now['year'] - 13, $now['mon'], $now['mday'] - 1) - ->setTime(0, 0, 0) - ->format($user->lang['DATE_FORMAT'], true); - unset($now); - - $template_vars = array( - 'S_LANG_OPTIONS' => (count($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&coppa=0'), - 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=1'), - - 'S_SHOW_COPPA' => true, - 'S_HIDDEN_FIELDS' => build_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'], - ); - } - else - { - $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, - 'S_REGISTRATION' => true, - 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_coppa), - - '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. - * - * To assign data to the template, use $template->assign_vars() - * - * @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 = $tpl_name; - return; - } - - // The CAPTCHA kicks in here. We can't help that the information gets lost on language change. - if ($config['enable_confirm']) - { - $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); - $captcha->init(CONFIRM_REG); - } - - $timezone = $config['board_timezone']; - - $data = array( - 'username' => $request->variable('username', '', true), - 'new_password' => $request->variable('new_password', '', true), - 'password_confirm' => $request->variable('password_confirm', '', true), - '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 - * - * To assign data to the template, use $template->assign_vars() - * - * @event core.ucp_register_data_before - * @var bool submit Do we display the form only - * or did the user press submit - * @var array data Array with current ucp registration data - * @since 3.1.4-RC1 - */ - $vars = array('submit', 'data'); - extract($phpbb_dispatcher->trigger_event('core.ucp_register_data_before', compact($vars))); - - // Check and initialize some variables if needed - if ($submit) - { - $error = validate_data($data, array( - 'username' => array( - array('string', false, $config['min_name_chars'], $config['max_name_chars']), - array('username', '')), - 'new_password' => array( - array('string', false, $config['min_pass_chars'], $config['max_pass_chars']), - array('password')), - 'password_confirm' => array('string', false, $config['min_pass_chars'], $config['max_pass_chars']), - 'email' => array( - array('string', false, 6, 60), - array('user_email')), - 'tz' => array('timezone'), - 'lang' => array('language_iso_name'), - )); - - if (!check_form_key('ucp_register')) - { - $error[] = $user->lang['FORM_INVALID']; - } - - // Replace "error" strings with their real, localised form - $error = array_map(array($user, 'lang'), $error); - - if ($config['enable_confirm']) - { - $vc_response = $captcha->validate($data); - if ($vc_response !== false) - { - $error[] = $vc_response; - } - - if ($config['max_reg_attempts'] && $captcha->get_attempt_count() > $config['max_reg_attempts']) - { - $error[] = $user->lang['TOO_MANY_REGISTERS']; - } - } - - // DNSBL check - if ($config['check_dnsbl']) - { - if (($dnsbl = $user->check_dnsbl('register')) !== false) - { - $error[] = sprintf($user->lang['IP_BLACKLISTED'], $user->ip, $dnsbl[1]); - } - } - - // validate custom profile fields - $cp->submit_cp_field('register', $user->get_iso_lang_id(), $cp_data, $error); - - if (!count($error)) - { - if ($data['new_password'] != $data['password_confirm']) - { - $error[] = $user->lang['NEW_PASSWORD_ERROR']; - } - } - /** - * Check UCP registration data after they are submitted - * - * @event core.ucp_register_data_after - * @var bool submit Do we display the form only - * or did the user press submit - * @var array data Array with current ucp registration data - * @var array cp_data Array with custom profile fields data - * @var array error Array with list of errors - * @since 3.1.4-RC1 - */ - $vars = array('submit', 'data', 'cp_data', 'error'); - extract($phpbb_dispatcher->trigger_event('core.ucp_register_data_after', compact($vars))); - - if (!count($error)) - { - $server_url = generate_board_url(); - - // Which group by default? - $group_name = ($coppa) ? 'REGISTERED_COPPA' : 'REGISTERED'; - - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $db->sql_escape($group_name) . "' - AND group_type = " . GROUP_SPECIAL; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_GROUP'); - } - - $group_id = $row['group_id']; - - if (($coppa || - $config['require_activation'] == USER_ACTIVATION_SELF || - $config['require_activation'] == USER_ACTIVATION_ADMIN) && $config['email_enable']) - { - $user_actkey = gen_rand_string(mt_rand(6, 10)); - $user_type = USER_INACTIVE; - $user_inactive_reason = INACTIVE_REGISTER; - $user_inactive_time = time(); - } - else - { - $user_type = USER_NORMAL; - $user_actkey = ''; - $user_inactive_reason = 0; - $user_inactive_time = 0; - } - - // Instantiate passwords manager - /* @var $passwords_manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('passwords.manager'); - - $user_row = array( - 'username' => $data['username'], - 'user_password' => $passwords_manager->hash($data['new_password']), - 'user_email' => $data['email'], - 'group_id' => (int) $group_id, - 'user_timezone' => $data['tz'], - 'user_lang' => $data['lang'], - 'user_type' => $user_type, - 'user_actkey' => $user_actkey, - 'user_ip' => $user->ip, - 'user_regdate' => time(), - 'user_inactive_reason' => $user_inactive_reason, - 'user_inactive_time' => $user_inactive_time, - ); - - if ($config['new_member_post_limit']) - { - $user_row['user_new'] = 1; - } - /** - * Add into $user_row before user_add - * - * user_add allows adding more data into the users table - * - * @event core.ucp_register_user_row_after - * @var bool submit Do we display the form only - * or did the user press submit - * @var array cp_data Array with custom profile fields data - * @var array user_row Array with current ucp registration data - * @since 3.1.4-RC1 - */ - $vars = array('submit', 'cp_data', 'user_row'); - extract($phpbb_dispatcher->trigger_event('core.ucp_register_user_row_after', compact($vars))); - - // Register user... - $user_id = user_add($user_row, $cp_data); - - // This should not happen, because the required variables are listed above... - if ($user_id === false) - { - trigger_error('NO_USER', E_USER_ERROR); - } - - // Okay, captcha, your job is done. - if ($config['enable_confirm'] && isset($captcha)) - { - $captcha->reset(); - } - - if ($coppa && $config['email_enable']) - { - $message = $user->lang['ACCOUNT_COPPA']; - $email_template = 'coppa_welcome_inactive'; - } - else if ($config['require_activation'] == USER_ACTIVATION_SELF && $config['email_enable']) - { - $message = $user->lang['ACCOUNT_INACTIVE']; - $email_template = 'user_welcome_inactive'; - } - else if ($config['require_activation'] == USER_ACTIVATION_ADMIN && $config['email_enable']) - { - $message = $user->lang['ACCOUNT_INACTIVE_ADMIN']; - $email_template = 'admin_welcome_inactive'; - } - else - { - $message = $user->lang['ACCOUNT_ADDED']; - $email_template = 'user_welcome'; - } - - if ($config['email_enable']) - { - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $messenger = new messenger(false); - - $messenger->template($email_template, $data['lang']); - - $messenger->to($data['email'], $data['username']); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), - 'USERNAME' => htmlspecialchars_decode($data['username']), - 'PASSWORD' => htmlspecialchars_decode($data['new_password']), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey") - ); - - if ($coppa) - { - $messenger->assign_vars(array( - 'FAX_INFO' => $config['coppa_fax'], - 'MAIL_INFO' => $config['coppa_mail'], - 'EMAIL_ADDRESS' => $data['email']) - ); - } - - /** - * 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, - 'user_actkey' => $user_row['user_actkey'], - 'user_regdate' => $user_row['user_regdate'], - )); - } - - // Perform account linking if necessary - if (!empty($login_link_data)) - { - $login_link_data['user_id'] = $user_id; - - $result = $auth_provider->link_account($login_link_data); - - if ($result) - { - $message = $message . '

' . $user->lang[$result]; - } - } - - /** - * 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 . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - trigger_error($message); - } - } - - $s_hidden_fields = array_merge($s_hidden_fields, array( - 'agreed' => 'true', - 'change_lang' => 0, - )); - - if ($config['coppa_enable']) - { - $s_hidden_fields['coppa'] = $coppa; - } - - if ($config['enable_confirm']) - { - $s_hidden_fields = array_merge($s_hidden_fields, $captcha->get_hidden_fields()); - } - - // Visual Confirmation - Show images - if ($config['enable_confirm']) - { - $template->assign_vars(array( - 'CAPTCHA_TEMPLATE' => $captcha->get_template(), - )); - } - - // - $l_reg_cond = ''; - switch ($config['require_activation']) - { - case USER_ACTIVATION_SELF: - $l_reg_cond = $user->lang['UCP_EMAIL_ACTIVATE']; - break; - - case USER_ACTIVATION_ADMIN: - $l_reg_cond = $user->lang['UCP_ADMIN_ACTIVATE']; - break; - } - - // 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'], - 'EMAIL' => $data['email'], - - 'L_REG_COND' => $l_reg_cond, - 'L_USERNAME_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), - - 'S_LANG_OPTIONS' => language_select($data['lang']), - 'S_TZ_PRESELECT' => !$submit, - 'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false, - 'S_REGISTRATION' => true, - 'S_COPPA' => $coppa, - '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('
', $error) : '', - 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - )); - - $template->assign_vars($template_vars); - - // - $user->profile_fields = array(); - - // Generate profile fields -> Template Block Variable profile_fields - $cp->generate_profile_fields('register', $user->get_iso_lang_id()); - - // - $this->tpl_name = $tpl_name; - } - - /** - * Creates the login_link data array - * - * @return array Returns an array of all POST paramaters whose names - * begin with 'login_link_' - */ - protected function get_login_link_data_array() - { - global $request; - - $var_names = $request->variable_names(\phpbb\request\request_interface::POST); - $login_link_data = array(); - $string_start_length = strlen('login_link_'); - - foreach ($var_names as $var_name) - { - if (strpos($var_name, 'login_link_') === 0) - { - $key_name = substr($var_name, $string_start_length); - $login_link_data[$key_name] = $request->variable($var_name, '', false, \phpbb\request\request_interface::POST); - } - } - - return $login_link_data; - } - - /** - * Prepends they key names of an associative array with 'login_link_' for - * inclusion on the page as hidden fields. - * - * @param array $data The array to be modified - * @return array The modified array - */ - protected function get_login_link_data_for_hidden_fields($data) - { - $new_data = array(); - - foreach ($data as $key => $value) - { - $new_data['login_link_' . $key] = $value; - } - - return $new_data; - } -} diff --git a/install/update/old/includes/ucp/ucp_resend.php b/install/update/old/includes/ucp/ucp_resend.php deleted file mode 100644 index 44c5410..0000000 --- a/install/update/old/includes/ucp/ucp_resend.php +++ /dev/null @@ -1,163 +0,0 @@ - -* @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; -} - -/** -* ucp_resend -* Resending activation emails -*/ -class ucp_resend -{ - var $u_action; - - function main($id, $mode) - { - global $config, $phpbb_root_path, $phpEx; - global $db, $user, $auth, $template, $request; - - $username = $request->variable('username', '', true); - $email = strtolower($request->variable('email', '')); - $submit = (isset($_POST['submit'])) ? true : false; - - add_form_key('ucp_resend'); - - if ($submit) - { - if (!check_form_key('ucp_resend')) - { - trigger_error('FORM_INVALID'); - } - - $sql = 'SELECT user_id, group_id, username, user_email, user_type, user_lang, user_actkey, user_inactive_reason - FROM ' . USERS_TABLE . " - WHERE user_email_hash = '" . $db->sql_escape(phpbb_email_hash($email)) . "' - AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error('NO_EMAIL_USER'); - } - - if ($user_row['user_type'] == USER_IGNORE) - { - trigger_error('NO_USER'); - } - - if (!$user_row['user_actkey'] && $user_row['user_type'] != USER_INACTIVE) - { - trigger_error('ACCOUNT_ALREADY_ACTIVATED'); - } - - if (!$user_row['user_actkey'] || ($user_row['user_type'] == USER_INACTIVE && $user_row['user_inactive_reason'] == INACTIVE_MANUAL)) - { - trigger_error('ACCOUNT_DEACTIVATED'); - } - - // Determine coppa status on group (REGISTERED(_COPPA)) - $sql = 'SELECT group_name, group_type - FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . $user_row['group_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_GROUP'); - } - - $coppa = ($row['group_name'] == 'REGISTERED_COPPA' && $row['group_type'] == GROUP_SPECIAL) ? true : false; - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $messenger = new messenger(false); - - if ($config['require_activation'] == USER_ACTIVATION_SELF || $coppa) - { - $messenger->template(($coppa) ? 'coppa_resend_inactive' : 'user_resend_inactive', $user_row['user_lang']); - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}") - ); - - if ($coppa) - { - $messenger->assign_vars(array( - 'FAX_INFO' => $config['coppa_fax'], - 'MAIL_INFO' => $config['coppa_mail'], - 'EMAIL_ADDRESS' => $user_row['user_email']) - ); - } - - $messenger->send(NOTIFY_EMAIL); - } - - if ($config['require_activation'] == USER_ACTIVATION_ADMIN) - { - // Grab an array of user_id's with a_user permissions ... these users can activate a user - $admin_ary = $auth->acl_get_list(false, 'a_user', false); - - $sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $admin_ary[0]['a_user']); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $messenger->template('admin_activate', $row['user_lang']); - $messenger->set_addresses($row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_USER_DETAILS' => generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$user_row['user_id']}", - 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}") - ); - - $messenger->send($row['user_notify_type']); - } - $db->sql_freeresult($result); - } - - meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx")); - - $message = ($config['require_activation'] == USER_ACTIVATION_ADMIN) ? $user->lang['ACTIVATION_EMAIL_SENT_ADMIN'] : $user->lang['ACTIVATION_EMAIL_SENT']; - $message .= '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - trigger_error($message); - } - - $template->assign_vars(array( - 'USERNAME' => $username, - 'EMAIL' => $email, - 'S_PROFILE_ACTION' => append_sid($phpbb_root_path . 'ucp.' . $phpEx, 'mode=resend_act')) - ); - - $this->tpl_name = 'ucp_resend'; - $this->page_title = 'UCP_RESEND'; - } -} diff --git a/install/update/old/includes/utf/utf_tools.php b/install/update/old/includes/utf/utf_tools.php deleted file mode 100644 index 89de454..0000000 --- a/install/update/old/includes/utf/utf_tools.php +++ /dev/null @@ -1,1450 +0,0 @@ - -* @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; -} - -// Enforce ASCII only string handling -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 -* extensions, otherwise they will default to custom routines. -* -*/ - -/** -* 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) -{ - if (is_null($offset)) - { - return mb_strpos($str, $needle); - } - else - { - return mb_strpos($str, $needle, $offset); - } -} - -/** -* UTF-8 aware alternative to strtolower -* @ignore -*/ -function utf8_strtolower($str) -{ - return mb_strtolower($str); -} - -/** -* UTF-8 aware alternative to strtoupper -* @ignore -*/ -function utf8_strtoupper($str) -{ - return mb_strtoupper($str); -} - -/** -* UTF-8 aware alternative to substr -* @ignore -*/ -function utf8_substr($str, $offset, $length = null) -{ - if (is_null($length)) - { - return mb_substr($str, $offset); - } - else - { - return mb_substr($str, $offset, $length); - } -} - -/** -* Return the length (in characters) of a UTF-8 string -* @ignore -*/ -function utf8_strlen($text) -{ - return mb_strlen($text, 'utf-8'); -} - -/** -* UTF-8 aware alternative to str_split -* Convert a string to an array -* -* @author Harry Fuecks -* @param string $str UTF-8 encoded -* @param int $split_len number to characters to split string by -* @return array characters in string reverses -*/ -function utf8_str_split($str, $split_len = 1) -{ - if (!is_int($split_len) || $split_len < 1) - { - return false; - } - - $len = utf8_strlen($str); - if ($len <= $split_len) - { - return array($str); - } - - preg_match_all('/.{' . $split_len . '}|[^\x00]{1,' . $split_len . '}$/us', $str, $ar); - return $ar[0]; -} - -/** -* UTF-8 aware alternative to strspn -* Find length of initial segment matching the mask -* -* @author Harry Fuecks -*/ -function utf8_strspn($str, $mask, $start = null, $length = null) -{ - if ($start !== null || $length !== null) - { - $str = utf8_substr($str, $start, $length); - } - - preg_match('/^[' . $mask . ']+/u', $str, $matches); - - if (isset($matches[0])) - { - return utf8_strlen($matches[0]); - } - - return 0; -} - -/** -* UTF-8 aware alternative to ucfirst -* Make a string's first character uppercase -* -* @author Harry Fuecks -* @param string -* @return string with first character as upper case (if applicable) -*/ -function utf8_ucfirst($str) -{ - switch (utf8_strlen($str)) - { - case 0: - return ''; - break; - - case 1: - return utf8_strtoupper($str); - break; - - default: - preg_match('/^(.{1})(.*)$/us', $str, $matches); - return utf8_strtoupper($matches[1]) . $matches[2]; - break; - } -} - -/** -* Recode a string to UTF-8 -* -* If the encoding is not supported, the string is returned as-is -* -* @param string $string Original string -* @param string $encoding Original encoding (lowered) -* @return string The string, encoded in UTF-8 -*/ -function utf8_recode($string, $encoding) -{ - $encoding = strtolower($encoding); - - if ($encoding == 'utf-8' || !is_string($string) || empty($string)) - { - return $string; - } - - // we force iso-8859-1 to be cp1252 - if ($encoding == 'iso-8859-1') - { - $encoding = 'cp1252'; - } - // convert iso-8859-8-i to iso-8859-8 - else if ($encoding == 'iso-8859-8-i') - { - $encoding = 'iso-8859-8'; - $string = hebrev($string); - } - - // First, try iconv() - if (function_exists('iconv')) - { - $ret = @iconv($encoding, 'utf-8', $string); - - if (!empty($ret)) - { - return $ret; - } - } - - // Try the mb_string extension - if (function_exists('mb_convert_encoding')) - { - // mbstring is nasty on PHP4, we must make *sure* that we send a good encoding - switch ($encoding) - { - case 'iso-8859-1': - case 'iso-8859-2': - case 'iso-8859-4': - case 'iso-8859-7': - case 'iso-8859-9': - case 'iso-8859-15': - case 'windows-1251': - case 'windows-1252': - case 'cp1252': - case 'shift_jis': - case 'euc-kr': - case 'big5': - case 'gb2312': - $ret = @mb_convert_encoding($string, 'utf-8', $encoding); - - if (!empty($ret)) - { - return $ret; - } - } - } - - // Try the recode extension - if (function_exists('recode_string')) - { - $ret = @recode_string($encoding . '..utf-8', $string); - - if (!empty($ret)) - { - return $ret; - } - } - - // If nothing works, check if we have a custom transcoder available - if (!preg_match('#^[a-z0-9_ \\-]+$#', $encoding)) - { - // Make sure the encoding name is alphanumeric, we don't want it to be abused into loading arbitrary files - trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); - } - - global $phpbb_root_path, $phpEx; - - // iso-8859-* character encoding - if (preg_match('/iso[_ -]?8859[_ -]?(\\d+)/', $encoding, $array)) - { - switch ($array[1]) - { - case '1': - case '2': - case '4': - case '7': - case '8': - case '9': - case '15': - if (!function_exists('iso_8859_' . $array[1])) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx)) - { - trigger_error('Basic reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx); - } - return call_user_func('iso_8859_' . $array[1], $string); - break; - - default: - trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); - break; - } - } - - // CP/WIN character encoding - if (preg_match('/(?:cp|windows)[_\- ]?(\\d+)/', $encoding, $array)) - { - switch ($array[1]) - { - case '932': - break; - case '1250': - case '1251': - case '1252': - case '1254': - case '1255': - case '1256': - case '1257': - case '874': - if (!function_exists('cp' . $array[1])) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx)) - { - trigger_error('Basic reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx); - } - return call_user_func('cp' . $array[1], $string); - break; - - default: - trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); - break; - } - } - - // TIS-620 - if (preg_match('/tis[_ -]?620/', $encoding)) - { - if (!function_exists('tis_620')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx)) - { - trigger_error('Basic reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx); - } - return tis_620($string); - } - - // SJIS - if (preg_match('/sjis(?:[_ -]?win)?|(?:cp|ibm)[_ -]?932|shift[_ -]?jis/', $encoding)) - { - if (!function_exists('sjis')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx)) - { - trigger_error('CJK reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx); - } - return sjis($string); - } - - // EUC_KR - if (preg_match('/euc[_ -]?kr/', $encoding)) - { - if (!function_exists('euc_kr')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx)) - { - trigger_error('CJK reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx); - } - return euc_kr($string); - } - - // BIG-5 - if (preg_match('/big[_ -]?5/', $encoding)) - { - if (!function_exists('big5')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx)) - { - trigger_error('CJK reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx); - } - return big5($string); - } - - // GB2312 - if (preg_match('/gb[_ -]?2312/', $encoding)) - { - if (!function_exists('gb2312')) - { - if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx)) - { - trigger_error('CJK reencoder file is missing', E_USER_ERROR); - } - include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx); - } - return gb2312($string); - } - - // Trigger an error?! Fow now just give bad data :-( - trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); -} - -/** -* 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 -*/ -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 -*/ -function utf8_encode_ncr_callback($m) -{ - return '&#' . utf8_ord($m[0]) . ';'; -} - -/** -* Converts a UTF-8 char to an NCR -* -* @param string $chr UTF-8 char -* @return integer UNICODE code point -*/ -function utf8_ord($chr) -{ - switch (strlen($chr)) - { - case 1: - return ord($chr); - break; - - case 2: - return ((ord($chr[0]) & 0x1F) << 6) | (ord($chr[1]) & 0x3F); - break; - - case 3: - return ((ord($chr[0]) & 0x0F) << 12) | ((ord($chr[1]) & 0x3F) << 6) | (ord($chr[2]) & 0x3F); - break; - - case 4: - return ((ord($chr[0]) & 0x07) << 18) | ((ord($chr[1]) & 0x3F) << 12) | ((ord($chr[2]) & 0x3F) << 6) | (ord($chr[3]) & 0x3F); - break; - - default: - return $chr; - } -} - -/** -* Converts an NCR to a UTF-8 char -* -* @param int $cp UNICODE code point -* @return string UTF-8 char -*/ -function utf8_chr($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); - } -} - -/** -* Convert Numeric Character References to UTF-8 chars -* -* Notes: -* - we do not convert NCRs recursively, if you pass &#38; it will return & -* - we DO NOT check for the existence of the Unicode characters, therefore an entity may be converted to an inexistent codepoint -* -* @param string $text String to convert, encoded in UTF-8 (no normal form required) -* @return string UTF-8 string where NCRs have been replaced with the actual chars -*/ -function utf8_decode_ncr($text) -{ - return preg_replace_callback('/&#([0-9]{1,6}|x[0-9A-F]{1,5});/i', 'utf8_decode_ncr_callback', $text); -} - -/** -* Callback used in decode_ncr() -* -* Takes a NCR (in decimal or hexadecimal) and returns a UTF-8 char. Attention, $m is an array. -* It will ignore most of invalid NCRs, but not all! -* -* @param array $m 0-based numerically indexed array passed by preg_replace_callback() -* @return string UTF-8 char -*/ -function utf8_decode_ncr_callback($m) -{ - $cp = (strncasecmp($m[1], 'x', 1)) ? $m[1] : hexdec(substr($m[1], 1)); - - return utf8_chr($cp); -} - -/** -* Case folds a unicode string as per Unicode 5.0, section 3.13 -* -* @param string $text text to be case folded -* @param string $option determines how we will fold the cases -* @return string case folded text -*/ -function utf8_case_fold($text, $option = 'full') -{ - static $uniarray = array(); - global $phpbb_root_path, $phpEx; - - // common is always set - if (!isset($uniarray['c'])) - { - $uniarray['c'] = include($phpbb_root_path . 'includes/utf/data/case_fold_c.' . $phpEx); - } - - // only set full if we need to - if ($option === 'full' && !isset($uniarray['f'])) - { - $uniarray['f'] = include($phpbb_root_path . 'includes/utf/data/case_fold_f.' . $phpEx); - } - - // only set simple if we need to - if ($option !== 'full' && !isset($uniarray['s'])) - { - $uniarray['s'] = include($phpbb_root_path . 'includes/utf/data/case_fold_s.' . $phpEx); - } - - // common is always replaced - $text = strtr($text, $uniarray['c']); - - if ($option === 'full') - { - // full replaces a character with multiple characters - $text = strtr($text, $uniarray['f']); - } - else - { - // simple replaces a character with another character - $text = strtr($text, $uniarray['s']); - } - - return $text; -} - -/** -* Takes the input and does a "special" case fold. It does minor normalization -* and returns NFKC compatable text -* -* @param string $text text to be case folded -* @param string $option determines how we will fold the cases -* @return string case folded text -*/ -function utf8_case_fold_nfkc($text, $option = 'full') -{ - static $fc_nfkc_closure = array( - "\xCD\xBA" => "\x20\xCE\xB9", - "\xCF\x92" => "\xCF\x85", - "\xCF\x93" => "\xCF\x8D", - "\xCF\x94" => "\xCF\x8B", - "\xCF\xB2" => "\xCF\x83", - "\xCF\xB9" => "\xCF\x83", - "\xE1\xB4\xAC" => "\x61", - "\xE1\xB4\xAD" => "\xC3\xA6", - "\xE1\xB4\xAE" => "\x62", - "\xE1\xB4\xB0" => "\x64", - "\xE1\xB4\xB1" => "\x65", - "\xE1\xB4\xB2" => "\xC7\x9D", - "\xE1\xB4\xB3" => "\x67", - "\xE1\xB4\xB4" => "\x68", - "\xE1\xB4\xB5" => "\x69", - "\xE1\xB4\xB6" => "\x6A", - "\xE1\xB4\xB7" => "\x6B", - "\xE1\xB4\xB8" => "\x6C", - "\xE1\xB4\xB9" => "\x6D", - "\xE1\xB4\xBA" => "\x6E", - "\xE1\xB4\xBC" => "\x6F", - "\xE1\xB4\xBD" => "\xC8\xA3", - "\xE1\xB4\xBE" => "\x70", - "\xE1\xB4\xBF" => "\x72", - "\xE1\xB5\x80" => "\x74", - "\xE1\xB5\x81" => "\x75", - "\xE1\xB5\x82" => "\x77", - "\xE2\x82\xA8" => "\x72\x73", - "\xE2\x84\x82" => "\x63", - "\xE2\x84\x83" => "\xC2\xB0\x63", - "\xE2\x84\x87" => "\xC9\x9B", - "\xE2\x84\x89" => "\xC2\xB0\x66", - "\xE2\x84\x8B" => "\x68", - "\xE2\x84\x8C" => "\x68", - "\xE2\x84\x8D" => "\x68", - "\xE2\x84\x90" => "\x69", - "\xE2\x84\x91" => "\x69", - "\xE2\x84\x92" => "\x6C", - "\xE2\x84\x95" => "\x6E", - "\xE2\x84\x96" => "\x6E\x6F", - "\xE2\x84\x99" => "\x70", - "\xE2\x84\x9A" => "\x71", - "\xE2\x84\x9B" => "\x72", - "\xE2\x84\x9C" => "\x72", - "\xE2\x84\x9D" => "\x72", - "\xE2\x84\xA0" => "\x73\x6D", - "\xE2\x84\xA1" => "\x74\x65\x6C", - "\xE2\x84\xA2" => "\x74\x6D", - "\xE2\x84\xA4" => "\x7A", - "\xE2\x84\xA8" => "\x7A", - "\xE2\x84\xAC" => "\x62", - "\xE2\x84\xAD" => "\x63", - "\xE2\x84\xB0" => "\x65", - "\xE2\x84\xB1" => "\x66", - "\xE2\x84\xB3" => "\x6D", - "\xE2\x84\xBB" => "\x66\x61\x78", - "\xE2\x84\xBE" => "\xCE\xB3", - "\xE2\x84\xBF" => "\xCF\x80", - "\xE2\x85\x85" => "\x64", - "\xE3\x89\x90" => "\x70\x74\x65", - "\xE3\x8B\x8C" => "\x68\x67", - "\xE3\x8B\x8E" => "\x65\x76", - "\xE3\x8B\x8F" => "\x6C\x74\x64", - "\xE3\x8D\xB1" => "\x68\x70\x61", - "\xE3\x8D\xB3" => "\x61\x75", - "\xE3\x8D\xB5" => "\x6F\x76", - "\xE3\x8D\xBA" => "\x69\x75", - "\xE3\x8E\x80" => "\x70\x61", - "\xE3\x8E\x81" => "\x6E\x61", - "\xE3\x8E\x82" => "\xCE\xBC\x61", - "\xE3\x8E\x83" => "\x6D\x61", - "\xE3\x8E\x84" => "\x6B\x61", - "\xE3\x8E\x85" => "\x6B\x62", - "\xE3\x8E\x86" => "\x6D\x62", - "\xE3\x8E\x87" => "\x67\x62", - "\xE3\x8E\x8A" => "\x70\x66", - "\xE3\x8E\x8B" => "\x6E\x66", - "\xE3\x8E\x8C" => "\xCE\xBC\x66", - "\xE3\x8E\x90" => "\x68\x7A", - "\xE3\x8E\x91" => "\x6B\x68\x7A", - "\xE3\x8E\x92" => "\x6D\x68\x7A", - "\xE3\x8E\x93" => "\x67\x68\x7A", - "\xE3\x8E\x94" => "\x74\x68\x7A", - "\xE3\x8E\xA9" => "\x70\x61", - "\xE3\x8E\xAA" => "\x6B\x70\x61", - "\xE3\x8E\xAB" => "\x6D\x70\x61", - "\xE3\x8E\xAC" => "\x67\x70\x61", - "\xE3\x8E\xB4" => "\x70\x76", - "\xE3\x8E\xB5" => "\x6E\x76", - "\xE3\x8E\xB6" => "\xCE\xBC\x76", - "\xE3\x8E\xB7" => "\x6D\x76", - "\xE3\x8E\xB8" => "\x6B\x76", - "\xE3\x8E\xB9" => "\x6D\x76", - "\xE3\x8E\xBA" => "\x70\x77", - "\xE3\x8E\xBB" => "\x6E\x77", - "\xE3\x8E\xBC" => "\xCE\xBC\x77", - "\xE3\x8E\xBD" => "\x6D\x77", - "\xE3\x8E\xBE" => "\x6B\x77", - "\xE3\x8E\xBF" => "\x6D\x77", - "\xE3\x8F\x80" => "\x6B\xCF\x89", - "\xE3\x8F\x81" => "\x6D\xCF\x89", - "\xE3\x8F\x83" => "\x62\x71", - "\xE3\x8F\x86" => "\x63\xE2\x88\x95\x6B\x67", - "\xE3\x8F\x87" => "\x63\x6F\x2E", - "\xE3\x8F\x88" => "\x64\x62", - "\xE3\x8F\x89" => "\x67\x79", - "\xE3\x8F\x8B" => "\x68\x70", - "\xE3\x8F\x8D" => "\x6B\x6B", - "\xE3\x8F\x8E" => "\x6B\x6D", - "\xE3\x8F\x97" => "\x70\x68", - "\xE3\x8F\x99" => "\x70\x70\x6D", - "\xE3\x8F\x9A" => "\x70\x72", - "\xE3\x8F\x9C" => "\x73\x76", - "\xE3\x8F\x9D" => "\x77\x62", - "\xE3\x8F\x9E" => "\x76\xE2\x88\x95\x6D", - "\xE3\x8F\x9F" => "\x61\xE2\x88\x95\x6D", - "\xF0\x9D\x90\x80" => "\x61", - "\xF0\x9D\x90\x81" => "\x62", - "\xF0\x9D\x90\x82" => "\x63", - "\xF0\x9D\x90\x83" => "\x64", - "\xF0\x9D\x90\x84" => "\x65", - "\xF0\x9D\x90\x85" => "\x66", - "\xF0\x9D\x90\x86" => "\x67", - "\xF0\x9D\x90\x87" => "\x68", - "\xF0\x9D\x90\x88" => "\x69", - "\xF0\x9D\x90\x89" => "\x6A", - "\xF0\x9D\x90\x8A" => "\x6B", - "\xF0\x9D\x90\x8B" => "\x6C", - "\xF0\x9D\x90\x8C" => "\x6D", - "\xF0\x9D\x90\x8D" => "\x6E", - "\xF0\x9D\x90\x8E" => "\x6F", - "\xF0\x9D\x90\x8F" => "\x70", - "\xF0\x9D\x90\x90" => "\x71", - "\xF0\x9D\x90\x91" => "\x72", - "\xF0\x9D\x90\x92" => "\x73", - "\xF0\x9D\x90\x93" => "\x74", - "\xF0\x9D\x90\x94" => "\x75", - "\xF0\x9D\x90\x95" => "\x76", - "\xF0\x9D\x90\x96" => "\x77", - "\xF0\x9D\x90\x97" => "\x78", - "\xF0\x9D\x90\x98" => "\x79", - "\xF0\x9D\x90\x99" => "\x7A", - "\xF0\x9D\x90\xB4" => "\x61", - "\xF0\x9D\x90\xB5" => "\x62", - "\xF0\x9D\x90\xB6" => "\x63", - "\xF0\x9D\x90\xB7" => "\x64", - "\xF0\x9D\x90\xB8" => "\x65", - "\xF0\x9D\x90\xB9" => "\x66", - "\xF0\x9D\x90\xBA" => "\x67", - "\xF0\x9D\x90\xBB" => "\x68", - "\xF0\x9D\x90\xBC" => "\x69", - "\xF0\x9D\x90\xBD" => "\x6A", - "\xF0\x9D\x90\xBE" => "\x6B", - "\xF0\x9D\x90\xBF" => "\x6C", - "\xF0\x9D\x91\x80" => "\x6D", - "\xF0\x9D\x91\x81" => "\x6E", - "\xF0\x9D\x91\x82" => "\x6F", - "\xF0\x9D\x91\x83" => "\x70", - "\xF0\x9D\x91\x84" => "\x71", - "\xF0\x9D\x91\x85" => "\x72", - "\xF0\x9D\x91\x86" => "\x73", - "\xF0\x9D\x91\x87" => "\x74", - "\xF0\x9D\x91\x88" => "\x75", - "\xF0\x9D\x91\x89" => "\x76", - "\xF0\x9D\x91\x8A" => "\x77", - "\xF0\x9D\x91\x8B" => "\x78", - "\xF0\x9D\x91\x8C" => "\x79", - "\xF0\x9D\x91\x8D" => "\x7A", - "\xF0\x9D\x91\xA8" => "\x61", - "\xF0\x9D\x91\xA9" => "\x62", - "\xF0\x9D\x91\xAA" => "\x63", - "\xF0\x9D\x91\xAB" => "\x64", - "\xF0\x9D\x91\xAC" => "\x65", - "\xF0\x9D\x91\xAD" => "\x66", - "\xF0\x9D\x91\xAE" => "\x67", - "\xF0\x9D\x91\xAF" => "\x68", - "\xF0\x9D\x91\xB0" => "\x69", - "\xF0\x9D\x91\xB1" => "\x6A", - "\xF0\x9D\x91\xB2" => "\x6B", - "\xF0\x9D\x91\xB3" => "\x6C", - "\xF0\x9D\x91\xB4" => "\x6D", - "\xF0\x9D\x91\xB5" => "\x6E", - "\xF0\x9D\x91\xB6" => "\x6F", - "\xF0\x9D\x91\xB7" => "\x70", - "\xF0\x9D\x91\xB8" => "\x71", - "\xF0\x9D\x91\xB9" => "\x72", - "\xF0\x9D\x91\xBA" => "\x73", - "\xF0\x9D\x91\xBB" => "\x74", - "\xF0\x9D\x91\xBC" => "\x75", - "\xF0\x9D\x91\xBD" => "\x76", - "\xF0\x9D\x91\xBE" => "\x77", - "\xF0\x9D\x91\xBF" => "\x78", - "\xF0\x9D\x92\x80" => "\x79", - "\xF0\x9D\x92\x81" => "\x7A", - "\xF0\x9D\x92\x9C" => "\x61", - "\xF0\x9D\x92\x9E" => "\x63", - "\xF0\x9D\x92\x9F" => "\x64", - "\xF0\x9D\x92\xA2" => "\x67", - "\xF0\x9D\x92\xA5" => "\x6A", - "\xF0\x9D\x92\xA6" => "\x6B", - "\xF0\x9D\x92\xA9" => "\x6E", - "\xF0\x9D\x92\xAA" => "\x6F", - "\xF0\x9D\x92\xAB" => "\x70", - "\xF0\x9D\x92\xAC" => "\x71", - "\xF0\x9D\x92\xAE" => "\x73", - "\xF0\x9D\x92\xAF" => "\x74", - "\xF0\x9D\x92\xB0" => "\x75", - "\xF0\x9D\x92\xB1" => "\x76", - "\xF0\x9D\x92\xB2" => "\x77", - "\xF0\x9D\x92\xB3" => "\x78", - "\xF0\x9D\x92\xB4" => "\x79", - "\xF0\x9D\x92\xB5" => "\x7A", - "\xF0\x9D\x93\x90" => "\x61", - "\xF0\x9D\x93\x91" => "\x62", - "\xF0\x9D\x93\x92" => "\x63", - "\xF0\x9D\x93\x93" => "\x64", - "\xF0\x9D\x93\x94" => "\x65", - "\xF0\x9D\x93\x95" => "\x66", - "\xF0\x9D\x93\x96" => "\x67", - "\xF0\x9D\x93\x97" => "\x68", - "\xF0\x9D\x93\x98" => "\x69", - "\xF0\x9D\x93\x99" => "\x6A", - "\xF0\x9D\x93\x9A" => "\x6B", - "\xF0\x9D\x93\x9B" => "\x6C", - "\xF0\x9D\x93\x9C" => "\x6D", - "\xF0\x9D\x93\x9D" => "\x6E", - "\xF0\x9D\x93\x9E" => "\x6F", - "\xF0\x9D\x93\x9F" => "\x70", - "\xF0\x9D\x93\xA0" => "\x71", - "\xF0\x9D\x93\xA1" => "\x72", - "\xF0\x9D\x93\xA2" => "\x73", - "\xF0\x9D\x93\xA3" => "\x74", - "\xF0\x9D\x93\xA4" => "\x75", - "\xF0\x9D\x93\xA5" => "\x76", - "\xF0\x9D\x93\xA6" => "\x77", - "\xF0\x9D\x93\xA7" => "\x78", - "\xF0\x9D\x93\xA8" => "\x79", - "\xF0\x9D\x93\xA9" => "\x7A", - "\xF0\x9D\x94\x84" => "\x61", - "\xF0\x9D\x94\x85" => "\x62", - "\xF0\x9D\x94\x87" => "\x64", - "\xF0\x9D\x94\x88" => "\x65", - "\xF0\x9D\x94\x89" => "\x66", - "\xF0\x9D\x94\x8A" => "\x67", - "\xF0\x9D\x94\x8D" => "\x6A", - "\xF0\x9D\x94\x8E" => "\x6B", - "\xF0\x9D\x94\x8F" => "\x6C", - "\xF0\x9D\x94\x90" => "\x6D", - "\xF0\x9D\x94\x91" => "\x6E", - "\xF0\x9D\x94\x92" => "\x6F", - "\xF0\x9D\x94\x93" => "\x70", - "\xF0\x9D\x94\x94" => "\x71", - "\xF0\x9D\x94\x96" => "\x73", - "\xF0\x9D\x94\x97" => "\x74", - "\xF0\x9D\x94\x98" => "\x75", - "\xF0\x9D\x94\x99" => "\x76", - "\xF0\x9D\x94\x9A" => "\x77", - "\xF0\x9D\x94\x9B" => "\x78", - "\xF0\x9D\x94\x9C" => "\x79", - "\xF0\x9D\x94\xB8" => "\x61", - "\xF0\x9D\x94\xB9" => "\x62", - "\xF0\x9D\x94\xBB" => "\x64", - "\xF0\x9D\x94\xBC" => "\x65", - "\xF0\x9D\x94\xBD" => "\x66", - "\xF0\x9D\x94\xBE" => "\x67", - "\xF0\x9D\x95\x80" => "\x69", - "\xF0\x9D\x95\x81" => "\x6A", - "\xF0\x9D\x95\x82" => "\x6B", - "\xF0\x9D\x95\x83" => "\x6C", - "\xF0\x9D\x95\x84" => "\x6D", - "\xF0\x9D\x95\x86" => "\x6F", - "\xF0\x9D\x95\x8A" => "\x73", - "\xF0\x9D\x95\x8B" => "\x74", - "\xF0\x9D\x95\x8C" => "\x75", - "\xF0\x9D\x95\x8D" => "\x76", - "\xF0\x9D\x95\x8E" => "\x77", - "\xF0\x9D\x95\x8F" => "\x78", - "\xF0\x9D\x95\x90" => "\x79", - "\xF0\x9D\x95\xAC" => "\x61", - "\xF0\x9D\x95\xAD" => "\x62", - "\xF0\x9D\x95\xAE" => "\x63", - "\xF0\x9D\x95\xAF" => "\x64", - "\xF0\x9D\x95\xB0" => "\x65", - "\xF0\x9D\x95\xB1" => "\x66", - "\xF0\x9D\x95\xB2" => "\x67", - "\xF0\x9D\x95\xB3" => "\x68", - "\xF0\x9D\x95\xB4" => "\x69", - "\xF0\x9D\x95\xB5" => "\x6A", - "\xF0\x9D\x95\xB6" => "\x6B", - "\xF0\x9D\x95\xB7" => "\x6C", - "\xF0\x9D\x95\xB8" => "\x6D", - "\xF0\x9D\x95\xB9" => "\x6E", - "\xF0\x9D\x95\xBA" => "\x6F", - "\xF0\x9D\x95\xBB" => "\x70", - "\xF0\x9D\x95\xBC" => "\x71", - "\xF0\x9D\x95\xBD" => "\x72", - "\xF0\x9D\x95\xBE" => "\x73", - "\xF0\x9D\x95\xBF" => "\x74", - "\xF0\x9D\x96\x80" => "\x75", - "\xF0\x9D\x96\x81" => "\x76", - "\xF0\x9D\x96\x82" => "\x77", - "\xF0\x9D\x96\x83" => "\x78", - "\xF0\x9D\x96\x84" => "\x79", - "\xF0\x9D\x96\x85" => "\x7A", - "\xF0\x9D\x96\xA0" => "\x61", - "\xF0\x9D\x96\xA1" => "\x62", - "\xF0\x9D\x96\xA2" => "\x63", - "\xF0\x9D\x96\xA3" => "\x64", - "\xF0\x9D\x96\xA4" => "\x65", - "\xF0\x9D\x96\xA5" => "\x66", - "\xF0\x9D\x96\xA6" => "\x67", - "\xF0\x9D\x96\xA7" => "\x68", - "\xF0\x9D\x96\xA8" => "\x69", - "\xF0\x9D\x96\xA9" => "\x6A", - "\xF0\x9D\x96\xAA" => "\x6B", - "\xF0\x9D\x96\xAB" => "\x6C", - "\xF0\x9D\x96\xAC" => "\x6D", - "\xF0\x9D\x96\xAD" => "\x6E", - "\xF0\x9D\x96\xAE" => "\x6F", - "\xF0\x9D\x96\xAF" => "\x70", - "\xF0\x9D\x96\xB0" => "\x71", - "\xF0\x9D\x96\xB1" => "\x72", - "\xF0\x9D\x96\xB2" => "\x73", - "\xF0\x9D\x96\xB3" => "\x74", - "\xF0\x9D\x96\xB4" => "\x75", - "\xF0\x9D\x96\xB5" => "\x76", - "\xF0\x9D\x96\xB6" => "\x77", - "\xF0\x9D\x96\xB7" => "\x78", - "\xF0\x9D\x96\xB8" => "\x79", - "\xF0\x9D\x96\xB9" => "\x7A", - "\xF0\x9D\x97\x94" => "\x61", - "\xF0\x9D\x97\x95" => "\x62", - "\xF0\x9D\x97\x96" => "\x63", - "\xF0\x9D\x97\x97" => "\x64", - "\xF0\x9D\x97\x98" => "\x65", - "\xF0\x9D\x97\x99" => "\x66", - "\xF0\x9D\x97\x9A" => "\x67", - "\xF0\x9D\x97\x9B" => "\x68", - "\xF0\x9D\x97\x9C" => "\x69", - "\xF0\x9D\x97\x9D" => "\x6A", - "\xF0\x9D\x97\x9E" => "\x6B", - "\xF0\x9D\x97\x9F" => "\x6C", - "\xF0\x9D\x97\xA0" => "\x6D", - "\xF0\x9D\x97\xA1" => "\x6E", - "\xF0\x9D\x97\xA2" => "\x6F", - "\xF0\x9D\x97\xA3" => "\x70", - "\xF0\x9D\x97\xA4" => "\x71", - "\xF0\x9D\x97\xA5" => "\x72", - "\xF0\x9D\x97\xA6" => "\x73", - "\xF0\x9D\x97\xA7" => "\x74", - "\xF0\x9D\x97\xA8" => "\x75", - "\xF0\x9D\x97\xA9" => "\x76", - "\xF0\x9D\x97\xAA" => "\x77", - "\xF0\x9D\x97\xAB" => "\x78", - "\xF0\x9D\x97\xAC" => "\x79", - "\xF0\x9D\x97\xAD" => "\x7A", - "\xF0\x9D\x98\x88" => "\x61", - "\xF0\x9D\x98\x89" => "\x62", - "\xF0\x9D\x98\x8A" => "\x63", - "\xF0\x9D\x98\x8B" => "\x64", - "\xF0\x9D\x98\x8C" => "\x65", - "\xF0\x9D\x98\x8D" => "\x66", - "\xF0\x9D\x98\x8E" => "\x67", - "\xF0\x9D\x98\x8F" => "\x68", - "\xF0\x9D\x98\x90" => "\x69", - "\xF0\x9D\x98\x91" => "\x6A", - "\xF0\x9D\x98\x92" => "\x6B", - "\xF0\x9D\x98\x93" => "\x6C", - "\xF0\x9D\x98\x94" => "\x6D", - "\xF0\x9D\x98\x95" => "\x6E", - "\xF0\x9D\x98\x96" => "\x6F", - "\xF0\x9D\x98\x97" => "\x70", - "\xF0\x9D\x98\x98" => "\x71", - "\xF0\x9D\x98\x99" => "\x72", - "\xF0\x9D\x98\x9A" => "\x73", - "\xF0\x9D\x98\x9B" => "\x74", - "\xF0\x9D\x98\x9C" => "\x75", - "\xF0\x9D\x98\x9D" => "\x76", - "\xF0\x9D\x98\x9E" => "\x77", - "\xF0\x9D\x98\x9F" => "\x78", - "\xF0\x9D\x98\xA0" => "\x79", - "\xF0\x9D\x98\xA1" => "\x7A", - "\xF0\x9D\x98\xBC" => "\x61", - "\xF0\x9D\x98\xBD" => "\x62", - "\xF0\x9D\x98\xBE" => "\x63", - "\xF0\x9D\x98\xBF" => "\x64", - "\xF0\x9D\x99\x80" => "\x65", - "\xF0\x9D\x99\x81" => "\x66", - "\xF0\x9D\x99\x82" => "\x67", - "\xF0\x9D\x99\x83" => "\x68", - "\xF0\x9D\x99\x84" => "\x69", - "\xF0\x9D\x99\x85" => "\x6A", - "\xF0\x9D\x99\x86" => "\x6B", - "\xF0\x9D\x99\x87" => "\x6C", - "\xF0\x9D\x99\x88" => "\x6D", - "\xF0\x9D\x99\x89" => "\x6E", - "\xF0\x9D\x99\x8A" => "\x6F", - "\xF0\x9D\x99\x8B" => "\x70", - "\xF0\x9D\x99\x8C" => "\x71", - "\xF0\x9D\x99\x8D" => "\x72", - "\xF0\x9D\x99\x8E" => "\x73", - "\xF0\x9D\x99\x8F" => "\x74", - "\xF0\x9D\x99\x90" => "\x75", - "\xF0\x9D\x99\x91" => "\x76", - "\xF0\x9D\x99\x92" => "\x77", - "\xF0\x9D\x99\x93" => "\x78", - "\xF0\x9D\x99\x94" => "\x79", - "\xF0\x9D\x99\x95" => "\x7A", - "\xF0\x9D\x99\xB0" => "\x61", - "\xF0\x9D\x99\xB1" => "\x62", - "\xF0\x9D\x99\xB2" => "\x63", - "\xF0\x9D\x99\xB3" => "\x64", - "\xF0\x9D\x99\xB4" => "\x65", - "\xF0\x9D\x99\xB5" => "\x66", - "\xF0\x9D\x99\xB6" => "\x67", - "\xF0\x9D\x99\xB7" => "\x68", - "\xF0\x9D\x99\xB8" => "\x69", - "\xF0\x9D\x99\xB9" => "\x6A", - "\xF0\x9D\x99\xBA" => "\x6B", - "\xF0\x9D\x99\xBB" => "\x6C", - "\xF0\x9D\x99\xBC" => "\x6D", - "\xF0\x9D\x99\xBD" => "\x6E", - "\xF0\x9D\x99\xBE" => "\x6F", - "\xF0\x9D\x99\xBF" => "\x70", - "\xF0\x9D\x9A\x80" => "\x71", - "\xF0\x9D\x9A\x81" => "\x72", - "\xF0\x9D\x9A\x82" => "\x73", - "\xF0\x9D\x9A\x83" => "\x74", - "\xF0\x9D\x9A\x84" => "\x75", - "\xF0\x9D\x9A\x85" => "\x76", - "\xF0\x9D\x9A\x86" => "\x77", - "\xF0\x9D\x9A\x87" => "\x78", - "\xF0\x9D\x9A\x88" => "\x79", - "\xF0\x9D\x9A\x89" => "\x7A", - "\xF0\x9D\x9A\xA8" => "\xCE\xB1", - "\xF0\x9D\x9A\xA9" => "\xCE\xB2", - "\xF0\x9D\x9A\xAA" => "\xCE\xB3", - "\xF0\x9D\x9A\xAB" => "\xCE\xB4", - "\xF0\x9D\x9A\xAC" => "\xCE\xB5", - "\xF0\x9D\x9A\xAD" => "\xCE\xB6", - "\xF0\x9D\x9A\xAE" => "\xCE\xB7", - "\xF0\x9D\x9A\xAF" => "\xCE\xB8", - "\xF0\x9D\x9A\xB0" => "\xCE\xB9", - "\xF0\x9D\x9A\xB1" => "\xCE\xBA", - "\xF0\x9D\x9A\xB2" => "\xCE\xBB", - "\xF0\x9D\x9A\xB3" => "\xCE\xBC", - "\xF0\x9D\x9A\xB4" => "\xCE\xBD", - "\xF0\x9D\x9A\xB5" => "\xCE\xBE", - "\xF0\x9D\x9A\xB6" => "\xCE\xBF", - "\xF0\x9D\x9A\xB7" => "\xCF\x80", - "\xF0\x9D\x9A\xB8" => "\xCF\x81", - "\xF0\x9D\x9A\xB9" => "\xCE\xB8", - "\xF0\x9D\x9A\xBA" => "\xCF\x83", - "\xF0\x9D\x9A\xBB" => "\xCF\x84", - "\xF0\x9D\x9A\xBC" => "\xCF\x85", - "\xF0\x9D\x9A\xBD" => "\xCF\x86", - "\xF0\x9D\x9A\xBE" => "\xCF\x87", - "\xF0\x9D\x9A\xBF" => "\xCF\x88", - "\xF0\x9D\x9B\x80" => "\xCF\x89", - "\xF0\x9D\x9B\x93" => "\xCF\x83", - "\xF0\x9D\x9B\xA2" => "\xCE\xB1", - "\xF0\x9D\x9B\xA3" => "\xCE\xB2", - "\xF0\x9D\x9B\xA4" => "\xCE\xB3", - "\xF0\x9D\x9B\xA5" => "\xCE\xB4", - "\xF0\x9D\x9B\xA6" => "\xCE\xB5", - "\xF0\x9D\x9B\xA7" => "\xCE\xB6", - "\xF0\x9D\x9B\xA8" => "\xCE\xB7", - "\xF0\x9D\x9B\xA9" => "\xCE\xB8", - "\xF0\x9D\x9B\xAA" => "\xCE\xB9", - "\xF0\x9D\x9B\xAB" => "\xCE\xBA", - "\xF0\x9D\x9B\xAC" => "\xCE\xBB", - "\xF0\x9D\x9B\xAD" => "\xCE\xBC", - "\xF0\x9D\x9B\xAE" => "\xCE\xBD", - "\xF0\x9D\x9B\xAF" => "\xCE\xBE", - "\xF0\x9D\x9B\xB0" => "\xCE\xBF", - "\xF0\x9D\x9B\xB1" => "\xCF\x80", - "\xF0\x9D\x9B\xB2" => "\xCF\x81", - "\xF0\x9D\x9B\xB3" => "\xCE\xB8", - "\xF0\x9D\x9B\xB4" => "\xCF\x83", - "\xF0\x9D\x9B\xB5" => "\xCF\x84", - "\xF0\x9D\x9B\xB6" => "\xCF\x85", - "\xF0\x9D\x9B\xB7" => "\xCF\x86", - "\xF0\x9D\x9B\xB8" => "\xCF\x87", - "\xF0\x9D\x9B\xB9" => "\xCF\x88", - "\xF0\x9D\x9B\xBA" => "\xCF\x89", - "\xF0\x9D\x9C\x8D" => "\xCF\x83", - "\xF0\x9D\x9C\x9C" => "\xCE\xB1", - "\xF0\x9D\x9C\x9D" => "\xCE\xB2", - "\xF0\x9D\x9C\x9E" => "\xCE\xB3", - "\xF0\x9D\x9C\x9F" => "\xCE\xB4", - "\xF0\x9D\x9C\xA0" => "\xCE\xB5", - "\xF0\x9D\x9C\xA1" => "\xCE\xB6", - "\xF0\x9D\x9C\xA2" => "\xCE\xB7", - "\xF0\x9D\x9C\xA3" => "\xCE\xB8", - "\xF0\x9D\x9C\xA4" => "\xCE\xB9", - "\xF0\x9D\x9C\xA5" => "\xCE\xBA", - "\xF0\x9D\x9C\xA6" => "\xCE\xBB", - "\xF0\x9D\x9C\xA7" => "\xCE\xBC", - "\xF0\x9D\x9C\xA8" => "\xCE\xBD", - "\xF0\x9D\x9C\xA9" => "\xCE\xBE", - "\xF0\x9D\x9C\xAA" => "\xCE\xBF", - "\xF0\x9D\x9C\xAB" => "\xCF\x80", - "\xF0\x9D\x9C\xAC" => "\xCF\x81", - "\xF0\x9D\x9C\xAD" => "\xCE\xB8", - "\xF0\x9D\x9C\xAE" => "\xCF\x83", - "\xF0\x9D\x9C\xAF" => "\xCF\x84", - "\xF0\x9D\x9C\xB0" => "\xCF\x85", - "\xF0\x9D\x9C\xB1" => "\xCF\x86", - "\xF0\x9D\x9C\xB2" => "\xCF\x87", - "\xF0\x9D\x9C\xB3" => "\xCF\x88", - "\xF0\x9D\x9C\xB4" => "\xCF\x89", - "\xF0\x9D\x9D\x87" => "\xCF\x83", - "\xF0\x9D\x9D\x96" => "\xCE\xB1", - "\xF0\x9D\x9D\x97" => "\xCE\xB2", - "\xF0\x9D\x9D\x98" => "\xCE\xB3", - "\xF0\x9D\x9D\x99" => "\xCE\xB4", - "\xF0\x9D\x9D\x9A" => "\xCE\xB5", - "\xF0\x9D\x9D\x9B" => "\xCE\xB6", - "\xF0\x9D\x9D\x9C" => "\xCE\xB7", - "\xF0\x9D\x9D\x9D" => "\xCE\xB8", - "\xF0\x9D\x9D\x9E" => "\xCE\xB9", - "\xF0\x9D\x9D\x9F" => "\xCE\xBA", - "\xF0\x9D\x9D\xA0" => "\xCE\xBB", - "\xF0\x9D\x9D\xA1" => "\xCE\xBC", - "\xF0\x9D\x9D\xA2" => "\xCE\xBD", - "\xF0\x9D\x9D\xA3" => "\xCE\xBE", - "\xF0\x9D\x9D\xA4" => "\xCE\xBF", - "\xF0\x9D\x9D\xA5" => "\xCF\x80", - "\xF0\x9D\x9D\xA6" => "\xCF\x81", - "\xF0\x9D\x9D\xA7" => "\xCE\xB8", - "\xF0\x9D\x9D\xA8" => "\xCF\x83", - "\xF0\x9D\x9D\xA9" => "\xCF\x84", - "\xF0\x9D\x9D\xAA" => "\xCF\x85", - "\xF0\x9D\x9D\xAB" => "\xCF\x86", - "\xF0\x9D\x9D\xAC" => "\xCF\x87", - "\xF0\x9D\x9D\xAD" => "\xCF\x88", - "\xF0\x9D\x9D\xAE" => "\xCF\x89", - "\xF0\x9D\x9E\x81" => "\xCF\x83", - "\xF0\x9D\x9E\x90" => "\xCE\xB1", - "\xF0\x9D\x9E\x91" => "\xCE\xB2", - "\xF0\x9D\x9E\x92" => "\xCE\xB3", - "\xF0\x9D\x9E\x93" => "\xCE\xB4", - "\xF0\x9D\x9E\x94" => "\xCE\xB5", - "\xF0\x9D\x9E\x95" => "\xCE\xB6", - "\xF0\x9D\x9E\x96" => "\xCE\xB7", - "\xF0\x9D\x9E\x97" => "\xCE\xB8", - "\xF0\x9D\x9E\x98" => "\xCE\xB9", - "\xF0\x9D\x9E\x99" => "\xCE\xBA", - "\xF0\x9D\x9E\x9A" => "\xCE\xBB", - "\xF0\x9D\x9E\x9B" => "\xCE\xBC", - "\xF0\x9D\x9E\x9C" => "\xCE\xBD", - "\xF0\x9D\x9E\x9D" => "\xCE\xBE", - "\xF0\x9D\x9E\x9E" => "\xCE\xBF", - "\xF0\x9D\x9E\x9F" => "\xCF\x80", - "\xF0\x9D\x9E\xA0" => "\xCF\x81", - "\xF0\x9D\x9E\xA1" => "\xCE\xB8", - "\xF0\x9D\x9E\xA2" => "\xCF\x83", - "\xF0\x9D\x9E\xA3" => "\xCF\x84", - "\xF0\x9D\x9E\xA4" => "\xCF\x85", - "\xF0\x9D\x9E\xA5" => "\xCF\x86", - "\xF0\x9D\x9E\xA6" => "\xCF\x87", - "\xF0\x9D\x9E\xA7" => "\xCF\x88", - "\xF0\x9D\x9E\xA8" => "\xCF\x89", - "\xF0\x9D\x9E\xBB" => "\xCF\x83", - "\xF0\x9D\x9F\x8A" => "\xCF\x9D", - ); - - // do the case fold - $text = utf8_case_fold($text, $option); - - // convert to NFKC - 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); - - return $text; -} - -/** -* Assume the input is NFC: -* Takes the input and does a "special" case fold. It does minor normalization as well. -* -* @param string $text text to be case folded -* @param string $option determines how we will fold the cases -* @return string case folded text -*/ -function utf8_case_fold_nfc($text, $option = 'full') -{ - static $uniarray = array(); - static $ypogegrammeni = array( - "\xCD\xBA" => "\x20\xCD\x85", - "\xE1\xBE\x80" => "\xE1\xBC\x80\xCD\x85", - "\xE1\xBE\x81" => "\xE1\xBC\x81\xCD\x85", - "\xE1\xBE\x82" => "\xE1\xBC\x82\xCD\x85", - "\xE1\xBE\x83" => "\xE1\xBC\x83\xCD\x85", - "\xE1\xBE\x84" => "\xE1\xBC\x84\xCD\x85", - "\xE1\xBE\x85" => "\xE1\xBC\x85\xCD\x85", - "\xE1\xBE\x86" => "\xE1\xBC\x86\xCD\x85", - "\xE1\xBE\x87" => "\xE1\xBC\x87\xCD\x85", - "\xE1\xBE\x88" => "\xE1\xBC\x88\xCD\x85", - "\xE1\xBE\x89" => "\xE1\xBC\x89\xCD\x85", - "\xE1\xBE\x8A" => "\xE1\xBC\x8A\xCD\x85", - "\xE1\xBE\x8B" => "\xE1\xBC\x8B\xCD\x85", - "\xE1\xBE\x8C" => "\xE1\xBC\x8C\xCD\x85", - "\xE1\xBE\x8D" => "\xE1\xBC\x8D\xCD\x85", - "\xE1\xBE\x8E" => "\xE1\xBC\x8E\xCD\x85", - "\xE1\xBE\x8F" => "\xE1\xBC\x8F\xCD\x85", - "\xE1\xBE\x90" => "\xE1\xBC\xA0\xCD\x85", - "\xE1\xBE\x91" => "\xE1\xBC\xA1\xCD\x85", - "\xE1\xBE\x92" => "\xE1\xBC\xA2\xCD\x85", - "\xE1\xBE\x93" => "\xE1\xBC\xA3\xCD\x85", - "\xE1\xBE\x94" => "\xE1\xBC\xA4\xCD\x85", - "\xE1\xBE\x95" => "\xE1\xBC\xA5\xCD\x85", - "\xE1\xBE\x96" => "\xE1\xBC\xA6\xCD\x85", - "\xE1\xBE\x97" => "\xE1\xBC\xA7\xCD\x85", - "\xE1\xBE\x98" => "\xE1\xBC\xA8\xCD\x85", - "\xE1\xBE\x99" => "\xE1\xBC\xA9\xCD\x85", - "\xE1\xBE\x9A" => "\xE1\xBC\xAA\xCD\x85", - "\xE1\xBE\x9B" => "\xE1\xBC\xAB\xCD\x85", - "\xE1\xBE\x9C" => "\xE1\xBC\xAC\xCD\x85", - "\xE1\xBE\x9D" => "\xE1\xBC\xAD\xCD\x85", - "\xE1\xBE\x9E" => "\xE1\xBC\xAE\xCD\x85", - "\xE1\xBE\x9F" => "\xE1\xBC\xAF\xCD\x85", - "\xE1\xBE\xA0" => "\xE1\xBD\xA0\xCD\x85", - "\xE1\xBE\xA1" => "\xE1\xBD\xA1\xCD\x85", - "\xE1\xBE\xA2" => "\xE1\xBD\xA2\xCD\x85", - "\xE1\xBE\xA3" => "\xE1\xBD\xA3\xCD\x85", - "\xE1\xBE\xA4" => "\xE1\xBD\xA4\xCD\x85", - "\xE1\xBE\xA5" => "\xE1\xBD\xA5\xCD\x85", - "\xE1\xBE\xA6" => "\xE1\xBD\xA6\xCD\x85", - "\xE1\xBE\xA7" => "\xE1\xBD\xA7\xCD\x85", - "\xE1\xBE\xA8" => "\xE1\xBD\xA8\xCD\x85", - "\xE1\xBE\xA9" => "\xE1\xBD\xA9\xCD\x85", - "\xE1\xBE\xAA" => "\xE1\xBD\xAA\xCD\x85", - "\xE1\xBE\xAB" => "\xE1\xBD\xAB\xCD\x85", - "\xE1\xBE\xAC" => "\xE1\xBD\xAC\xCD\x85", - "\xE1\xBE\xAD" => "\xE1\xBD\xAD\xCD\x85", - "\xE1\xBE\xAE" => "\xE1\xBD\xAE\xCD\x85", - "\xE1\xBE\xAF" => "\xE1\xBD\xAF\xCD\x85", - "\xE1\xBE\xB2" => "\xE1\xBD\xB0\xCD\x85", - "\xE1\xBE\xB3" => "\xCE\xB1\xCD\x85", - "\xE1\xBE\xB4" => "\xCE\xAC\xCD\x85", - "\xE1\xBE\xB7" => "\xE1\xBE\xB6\xCD\x85", - "\xE1\xBE\xBC" => "\xCE\x91\xCD\x85", - "\xE1\xBF\x82" => "\xE1\xBD\xB4\xCD\x85", - "\xE1\xBF\x83" => "\xCE\xB7\xCD\x85", - "\xE1\xBF\x84" => "\xCE\xAE\xCD\x85", - "\xE1\xBF\x87" => "\xE1\xBF\x86\xCD\x85", - "\xE1\xBF\x8C" => "\xCE\x97\xCD\x85", - "\xE1\xBF\xB2" => "\xE1\xBD\xBC\xCD\x85", - "\xE1\xBF\xB3" => "\xCF\x89\xCD\x85", - "\xE1\xBF\xB4" => "\xCF\x8E\xCD\x85", - "\xE1\xBF\xB7" => "\xE1\xBF\xB6\xCD\x85", - "\xE1\xBF\xBC" => "\xCE\xA9\xCD\x85", - ); - - // perform a small trick, avoid further normalization on composed points that contain U+0345 in their decomposition - $text = strtr($text, $ypogegrammeni); - - // do the case fold - $text = utf8_case_fold($text, $option); - - return $text; -} - -/** -* 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)) - { - 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; -} - -/** -* This function is used to generate a "clean" version of a string. -* Clean means that it is a case insensitive form (case folding) and that it is normalized (NFC). -* Additionally a homographs of one character are transformed into one specific character (preferably ASCII -* if it is an ASCII character). -* -* Please be aware that if you change something within this function or within -* functions used here you need to rebuild/update the username_clean column in the users table. And all other -* columns that store a clean string otherwise you will break this functionality. -* -* @param string $text An unclean string, mabye user input (has to be valid UTF-8!) -* @return string Cleaned up version of the input string -*/ -function utf8_clean_string($text) -{ - global $phpbb_root_path, $phpEx; - - static $homographs = array(); - if (empty($homographs)) - { - $homographs = include($phpbb_root_path . 'includes/utf/data/confusables.' . $phpEx); - } - - $text = utf8_case_fold_nfkc($text); - $text = strtr($text, $homographs); - // Other control characters - $text = preg_replace('#(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)#', '', $text); - - // we need to reduce multiple spaces to a single one - $text = preg_replace('# {2,}#', ' ', $text); - - // we can use trim here as all the other space characters should have been turned - // into normal ASCII spaces by now - return trim($text); -} - -/** -* A wrapper for htmlspecialchars($value, ENT_COMPAT, 'UTF-8') -*/ -function utf8_htmlspecialchars($value) -{ - return htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); -} - -/** -* Trying to convert returned system message to utf8 -* -* PHP assumes such messages are ISO-8859-1 so we'll do that too -* and if it breaks messages we'll blame it on them ;-) -*/ -function utf8_convert_message($message) -{ - // First of all check if conversion is neded at all, as there is no point - // in converting ASCII messages from ISO-8859-1 to UTF-8 - if (!preg_match('/[\x80-\xFF]/', $message)) - { - return utf8_htmlspecialchars($message); - } - - // else we need to convert some part of the message - return utf8_htmlspecialchars(utf8_recode($message, 'ISO-8859-1')); -} - -/** -* UTF8-compatible wordwrap replacement -* -* @param string $string The input string -* @param int $width The column width. Defaults to 75. -* @param string $break The line is broken using the optional break parameter. Defaults to '\n'. -* @param bool $cut If the cut is set to TRUE, the string is always wrapped at the specified width. So if you have a word that is larger than the given width, it is broken apart. -* -* @return string the given string wrapped at the specified column. -* -*/ -function utf8_wordwrap($string, $width = 75, $break = "\n", $cut = false) -{ - // We first need to explode on $break, not destroying existing (intended) breaks - $lines = explode($break, $string); - $new_lines = array(0 => ''); - $index = 0; - - foreach ($lines as $line) - { - $words = explode(' ', $line); - - for ($i = 0, $size = count($words); $i < $size; $i++) - { - $word = $words[$i]; - - // If cut is true we need to cut the word if it is > width chars - if ($cut && utf8_strlen($word) > $width) - { - $words[$i] = utf8_substr($word, $width); - $word = utf8_substr($word, 0, $width); - $i--; - } - - if (utf8_strlen($new_lines[$index] . $word) > $width) - { - $new_lines[$index] = substr($new_lines[$index], 0, -1); - $index++; - $new_lines[$index] = ''; - } - - $new_lines[$index] .= $word . ' '; - } - - $new_lines[$index] = substr($new_lines[$index], 0, -1); - $index++; - $new_lines[$index] = ''; - } - - unset($new_lines[$index]); - return implode($break, $new_lines); -} - -/** -* UTF8-safe basename() function -* -* basename() has some limitations and is dependent on the locale setting -* according to the PHP manual. Therefore we provide our own locale independent -* basename function. -* -* @param string $filename The filename basename() should be applied to -* @return string The basenamed filename -*/ -function utf8_basename($filename) -{ - // We always check for forward slash AND backward slash - // because they could be mixed or "sneaked" in. ;) - // You know, never trust user input... - if (strpos($filename, '/') !== false) - { - $filename = utf8_substr($filename, utf8_strrpos($filename, '/') + 1); - } - - if (strpos($filename, '\\') !== false) - { - $filename = utf8_substr($filename, utf8_strrpos($filename, '\\') + 1); - } - - return $filename; -} diff --git a/install/update/old/index.php b/install/update/old/index.php deleted file mode 100644 index 5eee772..0000000 --- a/install/update/old/index.php +++ /dev/null @@ -1,260 +0,0 @@ - -* @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); -$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('viewforum'); - -// Mark notifications read -if (($mark_notification = $request->variable('mark_notification', 0))) -{ - if ($user->data['user_id'] == ANONYMOUS) - { - if ($request->is_ajax()) - { - trigger_error('LOGIN_REQUIRED'); - } - login_box('', $user->lang['LOGIN_REQUIRED']); - } - - 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('notification.method.board', array( - 'notification_id' => $mark_notification, - )); - - if (isset($notification['notifications'][$mark_notification])) - { - $notification = $notification['notifications'][$mark_notification]; - - $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(); - $json_response->send(array( - 'success' => true, - )); - } - - if (($redirect = $request->variable('redirect', ''))) - { - redirect(append_sid($phpbb_root_path . $redirect)); - } - - redirect($notification->get_redirect_url()); - } - } -} - -display_forums('', $config['load_moderators']); - -$order_legend = ($config['legend_sort_groupname']) ? 'group_name' : 'group_legend'; -// Grab group details for legend display -if ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) -{ - $sql = 'SELECT group_id, group_name, group_colour, group_type, group_legend - FROM ' . GROUPS_TABLE . ' - WHERE group_legend > 0 - ORDER BY ' . $order_legend . ' ASC'; -} -else -{ - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, g.group_legend - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE g.group_legend > 0 - AND (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ') - ORDER BY g.' . $order_legend . ' ASC'; -} -$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 = $group_helper->get_name($row['group_name']); - - if ($row['group_name'] == 'BOTS' || ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile'))) - { - $legend[] = '' . $group_name . '
'; - } - else - { - $legend[] = '' . $group_name . ''; - } -} -$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 ($show_birthdays) -{ - $time = $user->create_datetime(); - $now = phpbb_gmgetdate($time->getTimestamp() + $time->getOffset()); - - // Display birthdays of 29th february on 28th february in non-leap-years - $leap_year_birthdays = ''; - if ($now['mday'] == 28 && $now['mon'] == 2 && !$time->format('L')) - { - $leap_year_birthdays = " OR u.user_birthday LIKE '" . $db->sql_escape(sprintf('%2d-%2d-', 29, 2)) . "%'"; - } - - $sql_ary = array( - 'SELECT' => 'u.user_id, u.username, u.user_colour, u.user_birthday', - 'FROM' => array( - USERS_TABLE => 'u', - ), - 'LEFT_JOIN' => array( - array( - 'FROM' => array(BANLIST_TABLE => 'b'), - 'ON' => 'u.user_id = b.ban_userid', - ), - ), - 'WHERE' => "(b.ban_id IS NULL OR b.ban_exclude = 1) - AND (u.user_birthday LIKE '" . $db->sql_escape(sprintf('%2d-%2d-', $now['mday'], $now['mon'])) . "%' $leap_year_birthdays) - AND u.user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')', - ); - - /** - * Event to modify the SQL query to get birthdays data - * - * @event core.index_modify_birthdays_sql - * @var array now The assoc array with the 'now' local timestamp data - * @var array sql_ary The SQL array to get the birthdays data - * @var object time The user related Datetime object - * @since 3.1.7-RC1 - */ - $vars = array('now', 'sql_ary', 'time'); - extract($phpbb_dispatcher->trigger_event('core.index_modify_birthdays_sql', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - $rows = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - foreach ($rows as $row) - { - $birthday_username = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']); - $birthday_year = (int) substr($row['user_birthday'], -4); - $birthday_age = ($birthday_year) ? max(0, $now['year'] - $birthday_year) : ''; - - $birthdays[] = array( - 'USERNAME' => $birthday_username, - 'AGE' => $birthday_age, - ); - - // For 3.0 compatibility - $birthday_list[] = $birthday_username . (($birthday_age) ? " ({$birthday_age})" : ''); - } - - /** - * Event to modify the birthdays list - * - * @event core.index_modify_birthdays_list - * @var array birthdays Array with the users birthdays data - * @var array rows Array with the birthdays SQL query result - * @since 3.1.7-RC1 - */ - $vars = array('birthdays', 'rows'); - extract($phpbb_dispatcher->trigger_event('core.index_modify_birthdays_list', compact($vars))); - - $template->assign_block_vars_array('birthdays', $birthdays); -} - -// Add form token for login box -add_form_key('login', '_LOGIN'); - -// Assign index specific vars -$template->assign_vars(array( - 'TOTAL_POSTS' => $user->lang('TOTAL_POSTS_COUNT', (int) $config['num_posts']), - 'TOTAL_TOPICS' => $user->lang('TOTAL_TOPICS', (int) $config['num_topics']), - 'TOTAL_USERS' => $user->lang('TOTAL_USERS', (int) $config['num_users']), - 'NEWEST_USER' => $user->lang('NEWEST_USER', get_username_string('full', $config['newest_user_id'], $config['newest_username'], $config['newest_user_colour'])), - - 'LEGEND' => $legend, - 'BIRTHDAY_LIST' => (empty($birthday_list)) ? '' : implode($user->lang['COMMA_SEPARATOR'], $birthday_list), - - 'FORUM_IMG' => $user->img('forum_read', 'NO_UNREAD_POSTS'), - 'FORUM_UNREAD_IMG' => $user->img('forum_unread', 'UNREAD_POSTS'), - 'FORUM_LOCKED_IMG' => $user->img('forum_read_locked', 'NO_UNREAD_POSTS_LOCKED'), - 'FORUM_UNREAD_LOCKED_IMG' => $user->img('forum_unread_locked', 'UNREAD_POSTS_LOCKED'), - - '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' => $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') . '&mark=forums&mark_time=' . time()) : '', - 'U_MCP' => ($auth->acl_get('m_') || $auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=front', true, $user->session_id) : '') -); - -$page_title = ($config['board_index_text'] !== '') ? $config['board_index_text'] : $user->lang['INDEX']; - -/** -* You can use this event to modify the page title and load data for the index -* -* @event core.index_modify_page_title -* @var string page_title Title of the index page -* @since 3.1.0-a1 -*/ -$vars = array('page_title'); -extract($phpbb_dispatcher->trigger_event('core.index_modify_page_title', compact($vars))); - -// Output page -page_header($page_title, true); - -$template->set_filenames(array( - 'body' => 'index_body.html') -); - -page_footer(); diff --git a/install/update/old/language/en/acp/attachments.php b/install/update/old/language/en/acp/attachments.php deleted file mode 100644 index 86430f4..0000000 --- a/install/update/old/language/en/acp/attachments.php +++ /dev/null @@ -1,169 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - 'ACP_ATTACHMENT_SETTINGS_EXPLAIN' => 'Here you can configure the main settings for attachments and the associated special categories.', - 'ACP_EXTENSION_GROUPS_EXPLAIN' => 'Here you can add, delete, modify or disable your extension groups. Further options include the assignment of a special category to them, changing the download mechanism and defining an upload icon which will be displayed in front of the attachment which belongs to the group.', - 'ACP_MANAGE_EXTENSIONS_EXPLAIN' => 'Here you can manage your allowed extensions. To activate your extensions, please refer to the extension groups management panel. We strongly recommend not to allow scripting extensions (such as php, php3, php4, phtml, pl, cgi, py, rb, asp, aspx, and so forth…).', - 'ACP_ORPHAN_ATTACHMENTS_EXPLAIN' => 'Here you are able to see orphaned files. This happens mostly if users are attaching files but not submitting the post. You are able to delete the files or attach them to existing posts. Attaching to posts requires a valid post ID, you have to determine this ID by yourself. This will assign the already uploaded attachment to the post you entered.', - 'ADD_EXTENSION' => 'Add extension', - 'ADD_EXTENSION_GROUP' => 'Add extension group', - 'ADMIN_UPLOAD_ERROR' => 'Errors while trying to attach file: “%s”.', - 'ALLOWED_FORUMS' => 'Allowed forums', - 'ALLOWED_FORUMS_EXPLAIN' => 'Able to post the assigned extensions at the selected (or all if selected) forums.', - 'ALLOWED_IN_PM_POST' => 'Allowed', - 'ALLOW_ATTACHMENTS' => 'Allow attachments', - 'ALLOW_ALL_FORUMS' => 'Allow all forums', - 'ALLOW_IN_PM' => 'Allowed in private messaging', - 'ALLOW_PM_ATTACHMENTS' => 'Allow attachments in private messages', - 'ALLOW_SELECTED_FORUMS' => 'Only forums selected below', - 'ASSIGNED_EXTENSIONS' => 'Assigned extensions', - 'ASSIGNED_GROUP' => 'Assigned extension group', - 'ATTACH_EXTENSIONS_URL' => 'Extensions', - 'ATTACH_EXT_GROUPS_URL' => 'Extension groups', - 'ATTACH_ID' => 'ID', - 'ATTACH_MAX_FILESIZE' => 'Maximum file size', - 'ATTACH_MAX_FILESIZE_EXPLAIN' => 'Maximum size of each file. If this value is 0, the uploadable filesize is only limited by your PHP configuration.', - 'ATTACH_MAX_PM_FILESIZE' => 'Maximum file size messaging', - 'ATTACH_MAX_PM_FILESIZE_EXPLAIN' => 'Maximum size of each file, with 0 being unlimited, attached to a private message.', - 'ATTACH_ORPHAN_URL' => 'Orphan attachments', - 'ATTACH_POST_ID' => 'Post ID', - 'ATTACH_POST_TYPE' => 'Post type', - 'ATTACH_QUOTA' => 'Total attachment quota', - 'ATTACH_QUOTA_EXPLAIN' => 'Maximum drive space available for attachments for the whole board, with 0 being unlimited.', - 'ATTACH_TO_POST' => 'Attach file to post', - - 'CAT_FLASH_FILES' => 'Flash files', - 'CAT_IMAGES' => 'Images', - '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', - 'CREATE_THUMBNAIL' => 'Create thumbnail', - 'CREATE_THUMBNAIL_EXPLAIN' => 'Create a thumbnail in all possible situations.', - - 'DEFINE_ALLOWED_IPS' => 'Define allowed IPs/hostnames', - 'DEFINE_DISALLOWED_IPS' => 'Define disallowed IPs/hostnames', - 'DOWNLOAD_ADD_IPS_EXPLAIN' => 'To specify several different IPs or hostnames enter each on a new line. To specify a range of IP addresses separate the start and end with a hyphen (-), to specify a wildcard use “*”.', - 'DOWNLOAD_REMOVE_IPS_EXPLAIN' => 'You can remove (or un-exclude) multiple IP addresses in one go using the appropriate combination of mouse and keyboard for your computer and browser. Excluded IPs have a blue background.', - 'DISPLAY_INLINED' => 'Display images inline', - 'DISPLAY_INLINED_EXPLAIN' => 'If set to No image attachments will show as a link.', - 'DISPLAY_ORDER' => 'Attachment display order', - 'DISPLAY_ORDER_EXPLAIN' => 'Display attachments ordered by time.', - - 'EDIT_EXTENSION_GROUP' => 'Edit extension group', - 'EXCLUDE_ENTERED_IP' => 'Enable this to exclude the entered IP/hostname.', - 'EXCLUDE_FROM_ALLOWED_IP' => 'Exclude IP from allowed IPs/hostnames', - 'EXCLUDE_FROM_DISALLOWED_IP' => 'Exclude IP from disallowed IPs/hostnames', - 'EXTENSIONS_UPDATED' => 'Extensions successfully updated.', - 'EXTENSION_EXIST' => 'The extension %s already exists.', - 'EXTENSION_GROUP' => 'Extension group', - 'EXTENSION_GROUPS' => 'Extension groups', - 'EXTENSION_GROUP_DELETED' => 'Extension group successfully deleted.', - 'EXTENSION_GROUP_EXIST' => 'The extension group %s already exists.', - - 'EXT_GROUP_ARCHIVES' => 'Archives', - 'EXT_GROUP_DOCUMENTS' => 'Documents', - 'EXT_GROUP_DOWNLOADABLE_FILES' => 'Downloadable Files', - 'EXT_GROUP_FLASH_FILES' => 'Flash Files', - 'EXT_GROUP_IMAGES' => 'Images', - 'EXT_GROUP_PLAIN_TEXT' => 'Plain Text', - - '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.
Click %3$shere%4$s to resynchronise them.', - - 'GO_TO_EXTENSIONS' => 'Go to extension management screen', - 'GROUP_NAME' => 'Group name', - - '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.', - - 'MAX_ATTACHMENTS' => 'Maximum number of attachments per post', - 'MAX_ATTACHMENTS_PM' => 'Maximum number of attachments per private message', - 'MAX_EXTGROUP_FILESIZE' => 'Maximum file size', - 'MAX_IMAGE_SIZE' => 'Maximum image dimensions', - 'MAX_IMAGE_SIZE_EXPLAIN' => 'Maximum size of image attachments. Set both values to 0px by 0px to disable dimension checking.', - 'MAX_THUMB_WIDTH' => 'Maximum thumbnail width/height in pixel', - 'MAX_THUMB_WIDTH_EXPLAIN' => 'A generated thumbnail will not exceed the width set here.', - 'MIN_THUMB_FILESIZE' => 'Minimum thumbnail file size', - 'MIN_THUMB_FILESIZE_EXPLAIN' => 'Do not create a thumbnail for images smaller than this.', - 'MODE_INLINE' => 'Inline', - 'MODE_PHYSICAL' => 'Physical', - - 'NOT_ALLOWED_IN_PM' => 'Only allowed in posts', - 'NOT_ALLOWED_IN_PM_POST' => 'Not allowed', - 'NOT_ASSIGNED' => 'Not assigned', - 'NO_ATTACHMENTS' => 'No attachments found for this period.', - 'NO_EXT_GROUP' => 'None', - 'NO_EXT_GROUP_NAME' => 'No group name entered', - 'NO_EXT_GROUP_SPECIFIED' => 'No extension group specified.', - 'NO_FILE_CAT' => 'None', - 'NO_IMAGE' => 'No image', - '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.', - - 'ONLY_ALLOWED_IN_PM' => 'Only allowed in private messages', - 'ORDER_ALLOW_DENY' => 'Allow', - 'ORDER_DENY_ALLOW' => 'Deny', - - 'REMOVE_ALLOWED_IPS' => 'Remove or un-exclude allowed IPs/hostnames', - 'REMOVE_DISALLOWED_IPS' => 'Remove or un-exclude disallowed IPs/hostnames', - 'RESYNC_FILES_STATS_CONFIRM' => 'Are you sure you wish to resynchronise file statistics?', - - '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 whitelist (Allow) or a blacklist (Deny).', - 'SECURE_DOWNLOADS' => 'Enable secure downloads', - 'SECURE_DOWNLOADS_EXPLAIN' => 'With this option enabled, downloads are limited to IP’s/hostnames you define.', - 'SECURE_DOWNLOAD_NOTICE' => 'Secure Downloads are not enabled. The settings below will be applied after enabling secure downloads.', - 'SECURE_DOWNLOAD_UPDATE_SUCCESS'=> 'The IP list has been updated successfully.', - 'SECURE_EMPTY_REFERRER' => 'Allow empty referrer', - 'SECURE_EMPTY_REFERRER_EXPLAIN' => 'Secure downloads are based on referrers. Do you want to allow downloads for those omitting the referrer?', - 'SETTINGS_CAT_IMAGES' => 'Image category settings', - 'SPECIAL_CATEGORY' => 'Special category', - 'SPECIAL_CATEGORY_EXPLAIN' => 'Special categories differ between the way presented within posts.', - 'SUCCESSFULLY_UPLOADED' => 'Successfully uploaded.', - 'SUCCESS_EXTENSION_GROUP_ADD' => 'Extension group successfully added.', - 'SUCCESS_EXTENSION_GROUP_EDIT' => 'Extension group successfully updated.', - - 'UPLOADING_FILES' => 'Uploading files', - 'UPLOADING_FILE_TO' => 'Uploading file “%1$s” to post number %2$d…', - 'UPLOAD_DENIED_FORUM' => 'You do not have the permission to upload files to forum “%s”.', - 'UPLOAD_DIR' => 'Upload directory', - 'UPLOAD_DIR_EXPLAIN' => 'Storage path for attachments. Please note that if you change this directory while already having uploaded attachments you need to manually copy the files to their new location.', - 'UPLOAD_ICON' => 'Upload icon', - 'UPLOAD_NOT_DIR' => 'The upload location you specified does not appear to be a directory.', -)); diff --git a/install/update/old/language/en/acp/board.php b/install/update/old/language/en/acp/board.php deleted file mode 100644 index 9b45ffa..0000000 --- a/install/update/old/language/en/acp/board.php +++ /dev/null @@ -1,631 +0,0 @@ - -* @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(); -} - -// 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 - -// Board Settings -$lang = array_merge($lang, array( - 'ACP_BOARD_SETTINGS_EXPLAIN' => 'Here you can determine the basic operation of your board, give it a fitting name and description, and among other settings adjust the default values for timezone and language.', - 'BOARD_INDEX_TEXT' => 'Board index text', - 'BOARD_INDEX_TEXT_EXPLAIN' => 'This text is displayed as the board index in the board’s breadcrumbs. If not specified, it will default to “Board index”.', - '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 date function.', - 'DEFAULT_LANGUAGE' => 'Default language', - 'DEFAULT_STYLE' => 'Default style', - 'DEFAULT_STYLE_EXPLAIN' => 'The default style for new users.', - 'DISABLE_BOARD' => 'Disable board', - 'DISABLE_BOARD_EXPLAIN' => 'This will make the board unavailable to users who are neither administrators nor moderators. You can also enter a short (255 character) message to display if you wish.', - 'DISPLAY_LAST_SUBJECT' => 'Display subject of last added post on forum list', - 'DISPLAY_LAST_SUBJECT_EXPLAIN' => 'The subject of the last added post will be displayed in the forum list with a hyperlink to the post. Subjects from password protected forums and forums in which user doesn’t have read access are not shown.', - 'GUEST_STYLE' => 'Guest style', - 'GUEST_STYLE_EXPLAIN' => 'The board style for guests.', - 'OVERRIDE_STYLE' => 'Override user style', - 'OVERRIDE_STYLE_EXPLAIN' => 'Replaces user’s (and guest’s) style with the style as defined under "Default style".', - 'SITE_DESC' => 'Site description', - 'SITE_HOME_TEXT' => 'Main website text', - 'SITE_HOME_TEXT_EXPLAIN' => 'This text will be displayed as a link to your website homepage in the board’s breadcrumbs. If not specified, it will default to “Home”.', - 'SITE_HOME_URL' => 'Main website URL', - 'SITE_HOME_URL_EXPLAIN' => 'If specified, a link to this URL will be prepended to your board’s breadcrumbs and the board logo will link to this URL instead of the forum index. An absolute URL is required, e.g. http://www.phpbb.com.', - 'SITE_NAME' => 'Site name', - 'SYSTEM_TIMEZONE' => 'Guest timezone', - 'SYSTEM_TIMEZONE_EXPLAIN' => 'Timezone to use for displaying times to users who are not logged in (guests, bots). Logged in users set their timezone during registration and can change it in their user control panel.', - 'WARNINGS_EXPIRE' => 'Warning duration', - 'WARNINGS_EXPIRE_EXPLAIN' => 'Number of days that will elapse before a warning will automatically expire from a user’s record. Set this value to 0 to make warnings permanent.', -)); - -// Board Features -$lang = array_merge($lang, array( - 'ACP_BOARD_FEATURES_EXPLAIN' => 'Here you can enable/disable several board features.', - - 'ALLOW_ATTACHMENTS' => 'Allow attachments', - 'ALLOW_BIRTHDAYS' => 'Allow birthdays', - 'ALLOW_BIRTHDAYS_EXPLAIN' => 'Allow birthdays to be entered and age being displayed in profiles. Please note the birthday list within the board index is controlled by a separate load setting.', - 'ALLOW_BOOKMARKS' => 'Allow bookmarking topics', - 'ALLOW_BOOKMARKS_EXPLAIN' => 'User is able to store personal bookmarks.', - 'ALLOW_BBCODE' => 'Allow BBCode', - 'ALLOW_FORUM_NOTIFY' => 'Allow subscribing to forums', - 'ALLOW_NAME_CHANGE' => 'Allow username changes', - 'ALLOW_NO_CENSORS' => 'Allow disabling of word censoring', - 'ALLOW_NO_CENSORS_EXPLAIN' => 'Users can choose to disable the automatic word censoring of posts and private messages.', - 'ALLOW_PM_ATTACHMENTS' => 'Allow attachments in private messages', - 'ALLOW_PM_REPORT' => 'Allow users to report private messages', - 'ALLOW_PM_REPORT_EXPLAIN' => 'If this setting is enabled, users have the option of reporting a private message they have received or sent to the board’s moderators. These private messages will then be visible in the Moderator Control Panel.', - 'ALLOW_QUICK_REPLY' => 'Allow quick reply', - 'ALLOW_QUICK_REPLY_EXPLAIN' => 'This switch allows for the quick reply to be disabled board-wide. When enabled, forum specific settings will be used to determine whether the quick reply is displayed in individual forums.', - 'ALLOW_QUICK_REPLY_BUTTON' => 'Submit and enable quick reply in all forums', - 'ALLOW_SIG' => 'Allow signatures', - 'ALLOW_SIG_BBCODE' => 'Allow BBCode in user signatures', - 'ALLOW_SIG_FLASH' => 'Allow use of [FLASH] BBCode tag in user signatures', - 'ALLOW_SIG_IMG' => 'Allow use of [IMG] BBCode tag in user signatures', - 'ALLOW_SIG_LINKS' => 'Allow use of links in user signatures', - 'ALLOW_SIG_LINKS_EXPLAIN' => 'If disallowed the [URL] BBCode tag and automatic/magic URLs are disabled.', - 'ALLOW_SIG_SMILIES' => 'Allow use of smilies in user signatures', - 'ALLOW_SMILIES' => 'Allow smilies', - '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 -$lang = array_merge($lang, array( - 'ACP_AVATAR_SETTINGS_EXPLAIN' => 'Avatars are generally small, unique images a user can associate with themselves. Depending on the style they are usually displayed below the username when viewing topics. Here you can determine how users can define their avatars. Please note that in order to upload avatars you need to have created the directory you name below and ensure it can be written to by the web server. Please also note that file size limits are only imposed on uploaded avatars, they do not apply to remotely linked images.', - - 'ALLOW_AVATARS' => 'Enable avatars', - 'ALLOW_AVATARS_EXPLAIN' => 'Allow general usage of avatars;
If you disable avatars in general or avatars of a certain mode, the disabled avatars will no longer be shown on the board, but users will still be able to download their own avatars in the User Control Panel.', - 'ALLOW_GRAVATAR' => 'Enable gravatar avatars', - 'ALLOW_LOCAL' => 'Enable gallery avatars', - 'ALLOW_REMOTE' => 'Enable remote avatars', - 'ALLOW_REMOTE_EXPLAIN' => 'Avatars linked to from another website.
Warning: Enabling this feature might allow users to check for the existence of files and services that are only accessible on the local network.', - 'ALLOW_REMOTE_UPLOAD' => 'Enable remote avatar uploading', - 'ALLOW_REMOTE_UPLOAD_EXPLAIN' => 'Allow uploading of avatars from another website.
Warning: Enabling this feature might allow users to check for the existence of files and services that are only accessible on the local network.', - 'ALLOW_UPLOAD' => 'Enable avatar uploading', - 'AVATAR_GALLERY_PATH' => 'Avatar gallery path', - 'AVATAR_GALLERY_PATH_EXPLAIN' => 'Path under your phpBB root directory for pre-loaded images, e.g. images/avatars/gallery.
Double dots like ../ 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. images/avatars/upload.
Avatar uploading will not be available if this path is not writable.
Double dots like ../ 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', - 'MAX_FILESIZE_EXPLAIN' => 'For uploaded avatar files. If this value is 0, the uploaded filesize is only limited by your PHP configuration.', - 'MIN_AVATAR_SIZE' => 'Minimum avatar dimensions', - 'MIN_AVATAR_SIZE_EXPLAIN' => 'Width x Height in pixels.', -)); - -// Message Settings -$lang = array_merge($lang, array( - 'ACP_MESSAGE_SETTINGS_EXPLAIN' => 'Here you can set all default settings for private messaging.', - - 'ALLOW_BBCODE_PM' => 'Allow BBCode in private messages', - 'ALLOW_FLASH_PM' => 'Allow use of [FLASH] BBCode tag', - 'ALLOW_FLASH_PM_EXPLAIN' => 'Note that the ability to use flash in private messages, if enabled here, also depends on the permissions.', - 'ALLOW_FORWARD_PM' => 'Allow forwarding of private messages', - 'ALLOW_IMG_PM' => 'Allow use of [IMG] BBCode tag', - 'ALLOW_MASS_PM' => 'Allow sending of private messages to multiple users and groups', - 'ALLOW_MASS_PM_EXPLAIN' => 'Sending to groups can be adjusted per group within the group settings page.', - 'ALLOW_PRINT_PM' => 'Allow print view in private messaging', - 'ALLOW_QUOTE_PM' => 'Allow quotes in private messages', - 'ALLOW_SIG_PM' => 'Allow signature in private messages', - 'ALLOW_SMILIES_PM' => 'Allow smilies in private messages', - 'BOXES_LIMIT' => 'Maximum private messages per box', - 'BOXES_LIMIT_EXPLAIN' => 'Users may receive no more than this many messages in each of their private message boxes. Set this value to 0 to allow unlimited messages.', - 'BOXES_MAX' => 'Maximum private message folders', - 'BOXES_MAX_EXPLAIN' => 'By default users may create this many personal folders for private messages.', - 'ENABLE_PM_ICONS' => 'Enable use of topic icons in private messages', - 'FULL_FOLDER_ACTION' => 'Full folder default action', - 'FULL_FOLDER_ACTION_EXPLAIN'=> 'Default action to take if a user’s folder is full assuming the user’s folder action, if set at all, is not applicable. The only exception is for the “Sent messages” folder where the default action is always to delete old messages.', - 'HOLD_NEW_MESSAGES' => 'Hold new messages', - 'PM_EDIT_TIME' => 'Limit editing time', - 'PM_EDIT_TIME_EXPLAIN' => 'Limits the time available to edit a private message not already delivered. Setting the value to 0 disables this behaviour.', - 'PM_MAX_RECIPIENTS' => 'Maximum number of allowed recipients', - 'PM_MAX_RECIPIENTS_EXPLAIN' => 'The maximum number of allowed recipients in a private message. If 0 is entered, an unlimited number is allowed. This setting can be adjusted for every group within the group settings page.', -)); - -// Post Settings -$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 [URL] 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 [FLASH] BBCode tag in posts', - 'ALLOW_POST_FLASH_EXPLAIN' => 'If disallowed the [FLASH] BBCode tag is disabled in posts. Otherwise the permission system controls which users can use the [FLASH] BBCode tag.', - - 'BUMP_INTERVAL' => 'Bump interval', - 'BUMP_INTERVAL_EXPLAIN' => 'Number of minutes, hours or days between the last post to a topic and the ability to bump that topic. Setting the value to 0 disables bumping entirely.', - 'CHAR_LIMIT' => 'Maximum characters per post/message', - 'CHAR_LIMIT_EXPLAIN' => 'The number of characters allowed within a post/private message. Set to 0 for unlimited characters.', - 'DELETE_TIME' => 'Limit deleting time', - 'DELETE_TIME_EXPLAIN' => 'Limits the time available to delete a new post. Setting the value to 0 disables this behaviour.', - 'DISPLAY_LAST_EDITED' => 'Display last edited time information', - 'DISPLAY_LAST_EDITED_EXPLAIN' => 'Choose if the last edited by information to be displayed on posts.', - 'EDIT_TIME' => 'Limit editing time', - 'EDIT_TIME_EXPLAIN' => 'Limits the time available to edit a new post. Setting the value to 0 disables this behaviour.', - 'FLOOD_INTERVAL' => 'Flood interval', - 'FLOOD_INTERVAL_EXPLAIN' => 'Number of seconds a user must wait between posting new messages. To enable users to ignore this alter their permissions.', - 'HOT_THRESHOLD' => 'Popular topic threshold', - 'HOT_THRESHOLD_EXPLAIN' => 'Posts per topic threshold required for the popular topic annotation. Set to 0 to disable popular topics.', - 'MAX_POLL_OPTIONS' => 'Maximum number of poll options', - 'MAX_POST_FONT_SIZE' => 'Maximum font size per post', - 'MAX_POST_FONT_SIZE_EXPLAIN' => 'Maximum font size allowed in a post. Set to 0 for unlimited font size.', - 'MAX_POST_IMG_HEIGHT' => 'Maximum image height per post', - 'MAX_POST_IMG_HEIGHT_EXPLAIN' => 'Maximum height of an image/flash file in postings. Set to 0 for unlimited size.', - 'MAX_POST_IMG_WIDTH' => 'Maximum image width per post', - 'MAX_POST_IMG_WIDTH_EXPLAIN' => 'Maximum width of an image/flash file in postings. Set to 0 for unlimited size.', - 'MAX_POST_URLS' => 'Maximum links per post', - 'MAX_POST_URLS_EXPLAIN' => 'Maximum number of URLs in a post. Set to 0 for unlimited links.', - 'MIN_CHAR_LIMIT' => 'Minimum characters per post/message', - 'MIN_CHAR_LIMIT_EXPLAIN' => 'The minimum number of characters the user need to enter within a post/private message. The minimum for this setting is 1.', - 'POSTING' => 'Posting', - 'POSTS_PER_PAGE' => 'Posts per page', - 'QUOTE_DEPTH_LIMIT' => 'Maximum nesting depth for quotes', - 'QUOTE_DEPTH_LIMIT_EXPLAIN' => 'Maximum quote nesting depth in a post. Set to 0 for unlimited depth.', - 'SMILIES_LIMIT' => 'Maximum smilies per post', - 'SMILIES_LIMIT_EXPLAIN' => 'Maximum number of smilies in a post. Set to 0 for unlimited smilies.', - 'SMILIES_PER_PAGE' => 'Smilies per page', - 'TOPICS_PER_PAGE' => 'Topics per page', -)); - -// Signature Settings -$lang = array_merge($lang, array( - 'ACP_SIGNATURE_SETTINGS_EXPLAIN' => 'Here you can set all default settings for signatures.', - - 'MAX_SIG_FONT_SIZE' => 'Maximum signature font size', - 'MAX_SIG_FONT_SIZE_EXPLAIN' => 'Maximum font size allowed in user signatures. Set to 0 for unlimited size.', - 'MAX_SIG_IMG_HEIGHT' => 'Maximum signature image height', - 'MAX_SIG_IMG_HEIGHT_EXPLAIN' => 'Maximum height of an image/flash file in user signatures. Set to 0 for unlimited height.', - 'MAX_SIG_IMG_WIDTH' => 'Maximum signature image width', - 'MAX_SIG_IMG_WIDTH_EXPLAIN' => 'Maximum width of an image/flash file in user signatures. Set to 0 for unlimited width.', - 'MAX_SIG_LENGTH' => 'Maximum signature length', - 'MAX_SIG_LENGTH_EXPLAIN' => 'Maximum number of characters in user signatures.', - 'MAX_SIG_SMILIES' => 'Maximum smilies per signature', - 'MAX_SIG_SMILIES_EXPLAIN' => 'Maximum smilies allowed in user signatures. Set to 0 for unlimited smilies.', - 'MAX_SIG_URLS' => 'Maximum signature links', - 'MAX_SIG_URLS_EXPLAIN' => 'Maximum number of links in user signatures. Set to 0 for unlimited links.', -)); - -// Registration Settings -$lang = array_merge($lang, array( - 'ACP_REGISTER_SETTINGS_EXPLAIN' => 'Here you are able to define registration and profile related settings.', - - 'ACC_ACTIVATION' => 'Account activation', - 'ACC_ACTIVATION_EXPLAIN' => 'This determines whether users have immediate access to the board or if confirmation is required. You can also completely disable new registrations. “Board-wide email” must be enabled in order to use user or admin activation.', - 'ACC_ACTIVATION_WARNING' => 'Please note that the currently selected activation method requires emails to be enabled, otherwise registration will be disabled. We recommend to either select a different activation method or reenable emails.', - 'NEW_MEMBER_POST_LIMIT' => 'New member post limit', - 'NEW_MEMBER_POST_LIMIT_EXPLAIN' => 'New members are within the Newly Registered Users group until they reach this number of posts. You can use this group to keep them from using the PM system or to review their posts. A value of 0 disables this feature.', - 'NEW_MEMBER_GROUP_DEFAULT' => 'Set Newly Registered Users group to default', - 'NEW_MEMBER_GROUP_DEFAULT_EXPLAIN' => 'If set to yes, and a new member post limit is specified, newly registered users will not only be put into the Newly Registered Users group, but this group will also be their default one. This may come in handy if you want to assign a group default rank and/or avatar the user then inherits.', - - 'ACC_ADMIN' => 'By admin', - 'ACC_DISABLE' => 'Disable registration', - 'ACC_NONE' => 'No activation (immediate access)', - 'ACC_USER' => 'By user (email verification)', -// 'ACC_USER_ADMIN' => 'User + Admin', - 'ALLOW_EMAIL_REUSE' => 'Allow email address re-use', - 'ALLOW_EMAIL_REUSE_EXPLAIN' => 'Different users can register with the same email address.', - 'COPPA' => 'COPPA', - 'COPPA_FAX' => 'COPPA fax number', - 'COPPA_MAIL' => 'COPPA mailing address', - 'COPPA_MAIL_EXPLAIN' => 'This is the mailing address where parents will send COPPA registration forms.', - 'ENABLE_COPPA' => 'Enable COPPA', - 'ENABLE_COPPA_EXPLAIN' => 'This requires users to declare whether they are 13 or over for compliance with the U.S. COPPA. If this is disabled the COPPA specific groups will no longer be displayed.', - 'MAX_CHARS' => 'Max', - 'MIN_CHARS' => 'Min', - 'NO_AUTH_PLUGIN' => 'No suitable auth plugin found.', - 'PASSWORD_LENGTH' => 'Password length', - 'PASSWORD_LENGTH_EXPLAIN' => 'Minimum and maximum number of characters in passwords.', - 'REG_LIMIT' => 'Registration attempts', - 'REG_LIMIT_EXPLAIN' => 'Number of attempts users can make at solving the anti-spambot task before being locked out of that session.', - 'USERNAME_ALPHA_ONLY' => 'Alphanumeric only', - 'USERNAME_ALPHA_SPACERS' => 'Alphanumeric and spacers', - 'USERNAME_ASCII' => 'ASCII (no international unicode)', - 'USERNAME_LETTER_NUM' => 'Any letter and number', - 'USERNAME_LETTER_NUM_SPACERS' => 'Any letter, number, and spacer', - 'USERNAME_CHARS' => 'Limit username chars', - 'USERNAME_CHARS_ANY' => 'Any character', - 'USERNAME_CHARS_EXPLAIN' => 'Restrict type of characters that may be used in usernames, spacers are: space, -, +, _, [ and ].', - 'USERNAME_LENGTH' => 'Username length', - 'USERNAME_LENGTH_EXPLAIN' => 'Minimum and maximum number of characters in usernames.', -)); - -// Feeds -$lang = array_merge($lang, array( - 'ACP_FEED_MANAGEMENT' => 'General syndication feeds settings', - 'ACP_FEED_MANAGEMENT_EXPLAIN' => 'This module makes available various ATOM feeds, parsing any BBCode in posts to make them readable in external feeds.', - - 'ACP_FEED_GENERAL' => 'General feed settings', - 'ACP_FEED_POST_BASED' => 'Post-based feed settings', - 'ACP_FEED_TOPIC_BASED' => 'Topic-based feed settings', - '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.
Disabling this switches off all feeds, no matter how the options below are set.', - 'ACP_FEED_LIMIT' => 'Number of items', - 'ACP_FEED_LIMIT_EXPLAIN' => 'The maximum number of feed items to display.', - - 'ACP_FEED_OVERALL' => 'Enable board-wide feed', - 'ACP_FEED_OVERALL_EXPLAIN' => 'Board-wide new posts.', - 'ACP_FEED_FORUM' => 'Enable per-forum feeds', - 'ACP_FEED_FORUM_EXPLAIN' => 'Single forum and subforums new posts.', - 'ACP_FEED_TOPIC' => 'Enable per-topic feeds', - 'ACP_FEED_TOPIC_EXPLAIN' => 'Single topics new posts.', - - 'ACP_FEED_TOPICS_NEW' => 'Enable new topics feed', - 'ACP_FEED_TOPICS_NEW_EXPLAIN' => 'Enables the “New Topics” feed, which displays the last created topics including the first post.', - '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.
Select multiple forums by holding CTRL 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.', - - '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 auth=http 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
(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 not included in feeds. Select no forum to pull data from all forums.
Select/Deselect multiple forums by holding CTRL and clicking.', -)); - -// Visual Confirmation Settings -$lang = array_merge($lang, array( - 'ACP_VC_SETTINGS_EXPLAIN' => 'Here you can select and configure plugins, which are designed to block automated form submissions by spambots. These plugins typically work by challenging the user with a CAPTCHA, a test which is designed to be difficult for computers to solve.', - 'ACP_VC_EXT_GET_MORE' => 'For additional (and possibly better) anti-spam plugins, visit the phpBB.com Extensions Database. For more information on preventing spam on your board, visit the phpBB.com Knowledge Base.', - 'AVAILABLE_CAPTCHAS' => 'Available plugins', - 'CAPTCHA_UNAVAILABLE' => 'The plugin cannot be selected as its requirements are not met.', - 'CAPTCHA_GD' => 'GD image', - 'CAPTCHA_GD_3D' => 'GD 3D image', - 'CAPTCHA_GD_FOREGROUND_NOISE' => 'Foreground noise', - 'CAPTCHA_GD_EXPLAIN' => 'Uses GD to make a more advanced anti-spambot image.', - 'CAPTCHA_GD_FOREGROUND_NOISE_EXPLAIN' => 'Use foreground noise to make the image harder to read.', - 'CAPTCHA_GD_X_GRID' => 'Background noise x-axis', - 'CAPTCHA_GD_X_GRID_EXPLAIN' => 'Use lower settings of this to make the image harder to read. 0 will disable x-axis background noise.', - 'CAPTCHA_GD_Y_GRID' => 'Background noise y-axis', - 'CAPTCHA_GD_Y_GRID_EXPLAIN' => 'Use lower settings of this to make the image harder to read. 0 will disable y-axis background noise.', - 'CAPTCHA_GD_WAVE' => 'Wave distortion', - 'CAPTCHA_GD_WAVE_EXPLAIN' => 'This applies a wave distortion to the image.', - 'CAPTCHA_GD_3D_NOISE' => 'Add 3D-noise objects', - 'CAPTCHA_GD_3D_NOISE_EXPLAIN' => 'This adds additional objects to the image, over the letters.', - 'CAPTCHA_GD_FONTS' => 'Use different fonts', - 'CAPTCHA_GD_FONTS_EXPLAIN' => 'This setting controls how many different letter shapes are used. You can just use the default shapes or introduce altered letters. Adding lowercase letters is also possible.', - 'CAPTCHA_FONT_DEFAULT' => 'Default', - 'CAPTCHA_FONT_NEW' => 'New Shapes', - 'CAPTCHA_FONT_LOWER' => 'Also use lowercase', - 'CAPTCHA_NO_GD' => 'Simple image', - 'CAPTCHA_PREVIEW_MSG' => 'Your changes have not been saved, this is just a preview.', - 'CAPTCHA_PREVIEW_EXPLAIN' => 'The plugin as it would look like using the current selection.', - - 'CAPTCHA_SELECT' => 'Installed plugins', - 'CAPTCHA_SELECT_EXPLAIN' => 'The dropdown holds the plugins recognised by the board. Grey entries are not available right now and might need configuration prior to use.', - 'CAPTCHA_CONFIGURE' => 'Configure plugins', - 'CAPTCHA_CONFIGURE_EXPLAIN' => 'Change the settings for the selected plugin.', - 'CONFIGURE' => 'Configure', - 'CAPTCHA_NO_OPTIONS' => 'This plugin has no configuration options.', - - 'VISUAL_CONFIRM_POST' => 'Enable spambot countermeasures for guest postings', - 'VISUAL_CONFIRM_POST_EXPLAIN' => 'Requires guest users to pass the anti-spambot task to help prevent automated postings.', - 'VISUAL_CONFIRM_REG' => 'Enable spambot countermeasures for registrations', - 'VISUAL_CONFIRM_REG_EXPLAIN' => 'Requires new users to pass the anti-spambot task to help prevent automated registrations.', - 'VISUAL_CONFIRM_REFRESH' => 'Allow users to refresh the anti-spambot task', - 'VISUAL_CONFIRM_REFRESH_EXPLAIN' => 'Allows users to request a new anti-spambot task if they are unable to solve the current task during registration. Some plugins might not support this option.', -)); - -// 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 phpBB.com Knowledge Base - Fixing incorrect cookie settings.', - - 'COOKIE_DOMAIN' => 'Cookie domain', - 'COOKIE_DOMAIN_EXPLAIN' => 'In most cases the cookie domain is optional. Leave it blank if you are unsure.

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 example.com and forums.example.com, or perhaps forums.example.com and blog.example.com. Remove the subdomains until you find the common domain, example.com. 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' => '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', - 'ONLINE_LENGTH_EXPLAIN' => 'Number of minutes after which inactive users will not appear in “Who is online” listings. The higher this value the greater is the processing required to generate the listing.', - 'SESSION_LENGTH' => 'Session length', - 'SESSION_LENGTH_EXPLAIN' => 'Sessions will expire after this time, in seconds.', -)); - -// Contact Settings -$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. Please note that board-wide emails option must be enabled as well. You can find this option in General > Client Communication > Email settings.', - - 'CONTACT_US_INFO' => 'Contact information', - 'CONTACT_US_INFO_EXPLAIN' => 'The message is displayed on the contact page', - 'CONTACT_US_INFO_PREVIEW' => 'Contact page information - Preview', - 'CONTACT_US_INFO_UPDATED' => 'Contact page information has been updated.', -)); - -// Load Settings -$lang = array_merge($lang, array( - 'ACP_LOAD_SETTINGS_EXPLAIN' => 'Here you can enable and disable certain board functions to reduce the amount of processing required. On most servers there is no need to disable any functions. However on certain systems or in shared hosting environments it may be beneficial to disable capabilities you do not really need. You can also specify limits for system load and active sessions beyond which the board will go offline.', - - 'ALLOW_CDN' => 'Allow usage of third party content delivery networks', - 'ALLOW_CDN_EXPLAIN' => 'If this setting is enabled, some files will be served from external third party servers instead of your server. This reduces the network bandwidth required by your server, but may present a privacy issue for some board administrators. In a default phpBB installation, this includes loading “jQuery” and the font “Open Sans” from Google’s content delivery network.', - 'ALLOW_LIVE_SEARCHES' => 'Allow live searches', - 'ALLOW_LIVE_SEARCHES_EXPLAIN' => 'If this setting is enabled, users are provided with keyword suggestions as they type in certain fields throughout the board.', - 'CUSTOM_PROFILE_FIELDS' => 'Custom profile fields', - 'LIMIT_LOAD' => 'Limit system load', - 'LIMIT_LOAD_EXPLAIN' => 'If the system’s 1-minute load average exceeds this value the board will automatically go offline. A value of 1.0 equals ~100% utilisation of one processor. This only functions on UNIX based servers and where this information is accessible. The value here resets itself to 0 if phpBB was unable to get the load limit.', - 'LIMIT_SESSIONS' => 'Limit sessions', - 'LIMIT_SESSIONS_EXPLAIN' => 'If the number of sessions exceeds this value within a one minute period the board will go offline. Set to 0 for unlimited sessions.', - 'LOAD_CPF_MEMBERLIST' => 'Allow styles to display custom profile fields in memberlist', - 'LOAD_CPF_PM' => 'Display custom profile fields in private messages', - 'LOAD_CPF_VIEWPROFILE' => 'Display custom profile fields in user profiles', - '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', - 'YES_BIRTHDAYS_EXPLAIN' => 'If disabled the birthday listing is no longer displayed. To let this setting take effect the birthday feature needs to be enabled too.', - 'YES_JUMPBOX' => 'Enable display of jumpbox', - 'YES_MODERATORS' => 'Enable display of moderators', - 'YES_ONLINE' => 'Enable online user listings', - 'YES_ONLINE_EXPLAIN' => 'Display online user information on index, forum and topic pages.', - 'YES_ONLINE_GUESTS' => 'Enable online guest listings in viewonline', - 'YES_ONLINE_GUESTS_EXPLAIN' => 'Allow display of guest user information in viewonline.', - 'YES_ONLINE_TRACK' => 'Enable display of user online/offline information', - 'YES_ONLINE_TRACK_EXPLAIN' => 'Display online information for user in profiles and topic pages.', - 'YES_POST_MARKING' => 'Enable dotted topics', - 'YES_POST_MARKING_EXPLAIN' => 'Indicates whether user has posted to a topic.', - 'YES_READ_MARKING' => 'Enable server-side topic marking', - 'YES_READ_MARKING_EXPLAIN' => 'Stores read/unread status information in the database rather than a cookie.', - 'YES_UNREAD_SEARCH' => 'Enable search for unread posts', -)); - -// Auth settings -$lang = array_merge($lang, array( - 'ACP_AUTH_SETTINGS_EXPLAIN' => 'phpBB supports authentication plug-ins, or modules. These allow you determine how users are authenticated when they log into the board. By default four plug-ins are provided: DB, LDAP, Apache, and OAuth. Not all methods require additional information so only fill out fields if they are relevant to the selected method.', - - '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.
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', - - 'APACHE_SETUP_BEFORE_USE' => 'You have to setup apache authentication before you switch phpBB to this authentication method. Keep in mind that the username you use for apache authentication has to be the same as your phpBB username. Apache authentication can only be used with mod_php (not with a CGI version) and safe_mode disabled.', - - 'LDAP' => 'LDAP', - 'LDAP_DN' => 'LDAP base dn', - 'LDAP_DN_EXPLAIN' => 'This is the Distinguished Name, locating the user information, e.g. o=My Company,c=US.', - 'LDAP_EMAIL' => 'LDAP email attribute', - 'LDAP_EMAIL_EXPLAIN' => 'Set this to the name of your user entry email attribute (if one exists) in order to automatically set the email address for new users. Leaving this empty results in empty email address for users who log in for the first time.', - 'LDAP_INCORRECT_USER_PASSWORD' => 'Binding to LDAP server failed with specified user/password.', - '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.
Warning: 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.', - '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', - 'LDAP_SERVER_EXPLAIN' => 'If using LDAP this is the hostname or IP address of the LDAP server. Alternatively you can specify an URL like ldap://hostname:port/', - 'LDAP_UID' => 'LDAP uid', - 'LDAP_UID_EXPLAIN' => 'This is the key under which to search for a given login identity, e.g. uid, sn, etc.', - 'LDAP_USER' => 'LDAP user dn', - 'LDAP_USER_EXPLAIN' => 'Leave blank to use anonymous binding. If filled in phpBB uses the specified distinguished name on login attempts to find the correct user, e.g. uid=Username,ou=MyUnit,o=MyCompany,c=US. Required for Active Directory Servers.', - 'LDAP_USER_FILTER' => 'LDAP user filter', - 'LDAP_USER_FILTER_EXPLAIN' => 'Optionally you can further limit the searched objects with additional filters. For example objectClass=posixGroup would result in the use of (&(uid=$username)(objectClass=posixGroup))', -)); - -// Server Settings -$lang = array_merge($lang, array( - 'ACP_SERVER_SETTINGS_EXPLAIN' => 'Here you define server and domain dependent settings. Please ensure the data you enter is accurate, errors will result in emails containing incorrect information. When entering the domain name remember it does include http:// or other protocol term. Only alter the port number if you know your server uses a different value, port 80 is correct in most cases.', - - 'ENABLE_GZIP' => 'Enable GZip compression', - 'ENABLE_GZIP_EXPLAIN' => 'Generated content will be compressed prior to sending it to the user. This can reduce network traffic but will also increase CPU usage on both server and client side. Requires zlib PHP extension to be loaded.', - 'FORCE_SERVER_VARS' => 'Force server URL settings', - 'FORCE_SERVER_VARS_EXPLAIN' => 'If set to yes the server settings defined here will be used in favour of the automatically determined values.', - 'ICONS_PATH' => 'Post icons storage path', - 'ICONS_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/icons.', - 'MOD_REWRITE_ENABLE' => 'Enable URL Rewriting', - 'MOD_REWRITE_ENABLE_EXPLAIN' => 'When enabled, URLs containing ’app.php’ will be rewritten to remove the filename (i.e. app.php/foo will become /foo). Apache server’s mod_rewrite module is required for this functionality to work; if this option is enabled without mod_rewrite support, URLs on your board may be broken.', - 'MOD_REWRITE_DISABLED' => 'The mod_rewrite module on your Apache web server is disabled. Enable the module or contact your web hosting provider if you wish to enable this feature.', - 'MOD_REWRITE_INFORMATION_UNAVAILABLE' => 'We are unable to determine whether or not this server supports URL rewriting. This setting may be enabled but if URL rewriting is not available, paths generated by this board (such as for use in links) may be broken. Contact your web hosting provider if you are unsure whether or not you can safely enable this feature.', - 'PATH_SETTINGS' => 'Path settings', - 'RANKS_PATH' => 'Rank image storage path', - 'RANKS_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/ranks.', - 'SCRIPT_PATH' => 'Script path', - 'SCRIPT_PATH_EXPLAIN' => 'The path where phpBB is located relative to the domain name, e.g. /phpBB3.', - 'SERVER_NAME' => 'Domain name', - 'SERVER_NAME_EXPLAIN' => 'The domain name this board runs from (for example: www.example.com).', - 'SERVER_PORT' => 'Server port', - 'SERVER_PORT_EXPLAIN' => 'The port your server is running on, usually 80, only change if different.', - 'SERVER_PROTOCOL' => 'Server protocol', - 'SERVER_PROTOCOL_EXPLAIN' => 'This is used as the server protocol if these settings are forced. If empty or not forced the protocol is determined by the cookie secure settings (http:// or https://).', - 'SERVER_URL_SETTINGS' => 'Server URL settings', - 'SMILIES_PATH' => 'Smilies storage path', - 'SMILIES_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/smilies.', - 'UPLOAD_ICONS_PATH' => 'Extension group icons storage path', - 'UPLOAD_ICONS_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. images/upload_icons.', - 'USE_SYSTEM_CRON' => 'Run periodic tasks from system cron', - 'USE_SYSTEM_CRON_EXPLAIN' => 'When off, phpBB will arrange for periodic tasks to be run automatically. When on, phpBB will not schedule any periodic tasks by itself; a system administrator must arrange for bin/phpbbcli.php cron:run to be run by the system cron facility at regular intervals (e.g. every 5 minutes).', -)); - -// Security Settings -$lang = array_merge($lang, array( - 'ACP_SECURITY_SETTINGS_EXPLAIN' => 'Here you are able to define session and login related settings.', - - 'ALL' => 'All', - 'ALLOW_AUTOLOGIN' => 'Allow "Remember Me" logins', - 'ALLOW_AUTOLOGIN_EXPLAIN' => 'Determines whether users are given "Remember Me" option when they visit the board.', - 'ALLOW_PASSWORD_RESET' => 'Allow password reset ("Forgot Password")', - 'ALLOW_PASSWORD_RESET_EXPLAIN' => 'Determines whether or not users are able to use the "I forgot my password" link on the login page to recover their account. If you use an external authentication mechanism you may wish to disable this feature.', - 'AUTOLOGIN_LENGTH' => '"Remember Me" login key expiration length (in days)', - 'AUTOLOGIN_LENGTH_EXPLAIN' => 'Number of days after which "Remember Me" login keys are removed or zero to disable.', - 'BROWSER_VALID' => 'Validate browser', - 'BROWSER_VALID_EXPLAIN' => 'Enables browser validation for each session improving security.', - 'CHECK_DNSBL' => 'Check IP against DNS Blackhole List', - 'CHECK_DNSBL_EXPLAIN' => 'If enabled the user’s IP address is checked against the following DNSBL services on registration and posting: spamcop.net and www.spamhaus.org. This lookup may take a while, depending on the server’s configuration. If slowdowns are experienced or too many false positives reported it is recommended to disable this check.', - 'CLASS_B' => 'A.B', - 'CLASS_C' => 'A.B.C', - 'EMAIL_CHECK_MX' => 'Check email domain for valid MX record', - 'EMAIL_CHECK_MX_EXPLAIN' => 'If enabled, the email domain provided on registration and profile changes is checked for a valid MX record.', - 'FORCE_PASS_CHANGE' => 'Force password change', - 'FORCE_PASS_CHANGE_EXPLAIN' => 'Require user to change their password after a set number of days. Setting this value to 0 disables this behaviour.', - 'FORM_TIME_MAX' => 'Maximum time to submit forms', - 'FORM_TIME_MAX_EXPLAIN' => 'The time a user has to submit a form. Use -1 to disable. Note that a form might become invalid if the session expires, regardless of this setting.', - 'FORM_SID_GUESTS' => 'Tie forms to guest sessions', - 'FORM_SID_GUESTS_EXPLAIN' => 'If enabled, the form token issued to guests will be session-exclusive. This can cause problems with some ISPs.', - 'FORWARDED_FOR_VALID' => 'Validate X_FORWARDED_FOR header', - 'FORWARDED_FOR_VALID_EXPLAIN' => 'Sessions will only be continued if the sent X_FORWARDED_FOR header equals the one sent with the previous request. Bans will be checked against IPs in X_FORWARDED_FOR too.', - 'IP_VALID' => 'Session IP validation', - 'IP_VALID_EXPLAIN' => 'Determines how much of the users IP is used to validate a session; All compares the complete address, A.B.C the first x.x.x, A.B the first x.x, None disables checking. On IPv6 addresses A.B.C compares the first 4 blocks and A.B the first 3 blocks.', - 'IP_LOGIN_LIMIT_MAX' => 'Maximum number of login attempts per IP address', - 'IP_LOGIN_LIMIT_MAX_EXPLAIN' => 'The threshold of login attempts allowed from a single IP address before an anti-spambot task is triggered. Enter 0 to prevent the anti-spambot task from being triggered by IP addresses.', - '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 X_FORWARDED_FOR header', - 'IP_LOGIN_LIMIT_USE_FORWARDED_EXPLAIN' => 'Instead of limiting login attempts by IP address they are limited by X_FORWARDED_FOR values.
Warning: Only enable this if you are operating a proxy server that sets X_FORWARDED_FOR to trustworthy values.', - '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', - 'NO_REF_VALIDATION' => 'None', - 'PASSWORD_TYPE' => 'Password complexity', - 'PASSWORD_TYPE_EXPLAIN' => 'Determines how complex a password needs to be when set or altered, subsequent options include the previous ones.', - 'PASS_TYPE_ALPHA' => 'Must contain letters and numbers', - 'PASS_TYPE_ANY' => 'No requirements', - 'PASS_TYPE_CASE' => 'Must be mixed case', - 'PASS_TYPE_SYMBOL' => 'Must contain symbols', - 'REF_HOST' => 'Only validate host', - 'REF_PATH' => 'Also validate path', - 'REFERRER_VALID' => 'Validate Referrer', - '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, PHP and INCLUDEPHP 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 openssl.cafile or curl.cainfo 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' => '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 Sender 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', - 'BOARD_HIDE_EMAILS_EXPLAIN' => 'This function keeps email addresses completely private.', - 'CONTACT_EMAIL' => 'Contact email address', - '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 From and Reply-To 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_FORCE_SENDER' => 'Force from email address', - 'EMAIL_FORCE_SENDER_EXPLAIN' => 'This will set the Return-Path to the from email address instead of using the local user and hostname of the server. This setting does not apply when using SMTP.
Warning: Requires the user that the webserver runs as to be added as trusted user to the sendmail configuration.', - '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_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. 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.', - '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.
Warning: Allowing self-signed SSL certificates may cause security implications.', - '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.
Warning: 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.', - '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 and protocol', - '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_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.
Warning: Connecting peers with unverified SSL certificates may cause security implications.', - '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.
Warning: Connecting to unverified peers may cause security implications.', - 'TEST_EMAIL_SENT' => 'The test email has been sent.
If you don’t receive it, please check your emails configuration.

If you require assistance, please visit the phpBB support forums.', - - '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.', -)); - -// Jabber settings -$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.
Warning: Allowing self-signed SSL certificates may cause security implications.', - '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 dns_get_record 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.', - 'JAB_PACKAGE_SIZE' => 'Jabber package size', - 'JAB_PACKAGE_SIZE_EXPLAIN' => 'This is the number of messages sent in one package. If set to 0 the message is sent immediately and will not be queued for later sending.', - 'JAB_PASSWORD' => 'Jabber password', - 'JAB_PASSWORD_EXPLAIN' => 'Warning: 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.', - 'JAB_PORT' => 'Jabber port', - 'JAB_PORT_EXPLAIN' => 'Leave blank unless you know it is not port 5222.', - 'JAB_SERVER' => 'Jabber server', - 'JAB_SERVER_EXPLAIN' => 'See %sjabber.org%s for a list of servers.', - 'JAB_SETTINGS_CHANGED' => 'Jabber settings changed successfully.', - 'JAB_USE_SSL' => 'Use SSL to connect', - 'JAB_USE_SSL_EXPLAIN' => 'If enabled a secure connection is tried to be established. The Jabber port will be modified to 5223 if port 5222 is specified.', - '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.
Warning: Connecting peers with unverified SSL certificates may cause security implications.', - '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.
Warning: Connecting to unverified peers may cause security implications.', -)); diff --git a/install/update/old/language/en/acp/common.php b/install/update/old/language/en/acp/common.php deleted file mode 100644 index 1c22535..0000000 --- a/install/update/old/language/en/acp/common.php +++ /dev/null @@ -1,833 +0,0 @@ - -* @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(); -} - -// 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 - -// Common -$lang = array_merge($lang, array( - 'ACP_ADMINISTRATORS' => 'Administrators', - 'ACP_ADMIN_LOGS' => 'Admin log', - 'ACP_ADMIN_ROLES' => 'Admin roles', - 'ACP_ATTACHMENTS' => 'Attachments', - 'ACP_ATTACHMENT_SETTINGS' => 'Attachment settings', - 'ACP_AUTH_SETTINGS' => 'Authentication', - 'ACP_AUTOMATION' => 'Automation', - 'ACP_AVATAR_SETTINGS' => 'Avatar settings', - - 'ACP_BACKUP' => 'Backup', - 'ACP_BAN' => 'Banning', - 'ACP_BAN_EMAILS' => 'Ban emails', - 'ACP_BAN_IPS' => 'Ban IPs', - 'ACP_BAN_USERNAMES' => 'Ban users', - 'ACP_BBCODES' => 'BBCodes', - 'ACP_BOARD_CONFIGURATION' => 'Board configuration', - 'ACP_BOARD_FEATURES' => 'Board features', - 'ACP_BOARD_MANAGEMENT' => 'Board management', - 'ACP_BOARD_SETTINGS' => 'Board settings', - 'ACP_BOTS' => 'Spiders/Robots', - - 'ACP_CAPTCHA' => 'CAPTCHA', - - 'ACP_CAT_CUSTOMISE' => 'Customise', - 'ACP_CAT_DATABASE' => 'Database', - 'ACP_CAT_DOT_MODS' => 'Extensions', - 'ACP_CAT_FORUMS' => 'Forums', - 'ACP_CAT_GENERAL' => 'General', - 'ACP_CAT_MAINTENANCE' => 'Maintenance', - 'ACP_CAT_PERMISSIONS' => 'Permissions', - 'ACP_CAT_POSTING' => 'Posting', - 'ACP_CAT_STYLES' => 'Styles', - 'ACP_CAT_SYSTEM' => 'System', - 'ACP_CAT_USERGROUP' => 'Users and Groups', - 'ACP_CAT_USERS' => 'Users', - 'ACP_CLIENT_COMMUNICATION' => 'Client communication', - 'ACP_COOKIE_SETTINGS' => 'Cookie settings', - 'ACP_CONTACT' => 'Contact page', - 'ACP_CONTACT_SETTINGS' => 'Contact page settings', - 'ACP_CRITICAL_LOGS' => 'Error log', - 'ACP_CUSTOM_PROFILE_FIELDS' => 'Custom profile fields', - - 'ACP_DATABASE' => 'Database management', - 'ACP_DISALLOW' => 'Disallow', - 'ACP_DISALLOW_USERNAMES' => 'Disallow usernames', - - 'ACP_EMAIL_SETTINGS' => 'Email settings', - 'ACP_EXTENSION_GROUPS' => 'Manage attachment extension groups', - 'ACP_EXTENSION_MANAGEMENT' => 'Extension management', - 'ACP_EXTENSIONS' => 'Manage extensions', - - 'ACP_FORUM_BASED_PERMISSIONS' => 'Forum based permissions', - 'ACP_FORUM_LOGS' => 'Forum logs', - 'ACP_FORUM_MANAGEMENT' => 'Forum management', - 'ACP_FORUM_MODERATORS' => 'Forum moderators', - 'ACP_FORUM_PERMISSIONS' => 'Forum permissions', - 'ACP_FORUM_PERMISSIONS_COPY' => 'Copy forum permissions', - 'ACP_FORUM_ROLES' => 'Forum roles', - - 'ACP_GENERAL_CONFIGURATION' => 'General configuration', - 'ACP_GENERAL_TASKS' => 'General tasks', - 'ACP_GLOBAL_MODERATORS' => 'Global moderators', - 'ACP_GLOBAL_PERMISSIONS' => 'Global permissions', - 'ACP_GROUPS' => 'Groups', - 'ACP_GROUPS_FORUM_PERMISSIONS' => 'Group forum permissions', - 'ACP_GROUPS_MANAGE' => 'Manage groups', - 'ACP_GROUPS_MANAGEMENT' => 'Group management', - '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', - 'ACP_INDEX' => 'ACP index', - - 'ACP_JABBER_SETTINGS' => 'Jabber settings', - - 'ACP_LANGUAGE' => 'Language management', - 'ACP_LANGUAGE_PACKS' => 'Language packs', - 'ACP_LOAD_SETTINGS' => 'Load settings', - 'ACP_LOGGING' => 'Logging', - - 'ACP_MAIN' => 'ACP index', - - 'ACP_MANAGE_ATTACHMENTS' => 'Manage attachments', - 'ACP_MANAGE_ATTACHMENTS_EXPLAIN' => 'Here you can list and delete files attached to posts and private messages.', - - 'ACP_MANAGE_EXTENSIONS' => 'Manage attachment extensions', - 'ACP_MANAGE_FORUMS' => 'Manage forums', - 'ACP_MANAGE_RANKS' => 'Manage ranks', - 'ACP_MANAGE_REASONS' => 'Manage report/denial reasons', - 'ACP_MANAGE_USERS' => 'Manage users', - 'ACP_MASS_EMAIL' => 'Mass email', - 'ACP_MESSAGES' => 'Messages', - 'ACP_MESSAGE_SETTINGS' => 'Private message settings', - 'ACP_MODULE_MANAGEMENT' => 'Module management', - 'ACP_MOD_LOGS' => 'Moderator log', - 'ACP_MOD_ROLES' => 'Moderator roles', - - 'ACP_NO_ITEMS' => 'There are no items yet.', - - 'ACP_ORPHAN_ATTACHMENTS' => 'Orphaned attachments', - - 'ACP_PERMISSIONS' => 'Permissions', - 'ACP_PERMISSION_MASKS' => 'Permission masks', - 'ACP_PERMISSION_ROLES' => 'Permission roles', - 'ACP_PERMISSION_TRACE' => 'Permission trace', - 'ACP_PHP_INFO' => 'PHP information', - 'ACP_POST_SETTINGS' => 'Post settings', - 'ACP_PRUNE_FORUMS' => 'Prune forums', - 'ACP_PRUNE_USERS' => 'Prune users', - 'ACP_PRUNING' => 'Pruning', - - 'ACP_QUICK_ACCESS' => 'Quick access', - - 'ACP_RANKS' => 'Ranks', - 'ACP_REASONS' => 'Report/denial reasons', - 'ACP_REGISTER_SETTINGS' => 'User registration settings', - - 'ACP_RESTORE' => 'Restore', - - 'ACP_FEED' => 'Feed management', - 'ACP_FEED_SETTINGS' => 'Feed settings', - - 'ACP_SEARCH' => 'Search configuration', - 'ACP_SEARCH_INDEX' => 'Search index', - 'ACP_SEARCH_SETTINGS' => 'Search settings', - - 'ACP_SECURITY_SETTINGS' => 'Security settings', - 'ACP_SERVER_CONFIGURATION' => 'Server configuration', - 'ACP_SERVER_SETTINGS' => 'Server settings', - 'ACP_SIGNATURE_SETTINGS' => 'Signature settings', - 'ACP_SMILIES' => 'Smilies', - 'ACP_STYLE_MANAGEMENT' => 'Style management', - 'ACP_STYLES' => 'Styles', - 'ACP_STYLES_CACHE' => 'Purge Cache', - 'ACP_STYLES_INSTALL' => 'Install Styles', - - 'ACP_SUBMIT_CHANGES' => 'Submit changes', - - 'ACP_TEMPLATES' => 'Templates', - 'ACP_THEMES' => 'Themes', - - 'ACP_UPDATE' => 'Updating', - 'ACP_USERS_FORUM_PERMISSIONS' => 'User forum permissions', - 'ACP_USERS_LOGS' => 'User logs', - 'ACP_USERS_PERMISSIONS' => 'User permissions', - 'ACP_USER_ATTACH' => 'Attachments', - 'ACP_USER_AVATAR' => 'Avatar', - 'ACP_USER_FEEDBACK' => 'Feedback', - 'ACP_USER_GROUPS' => 'Groups', - 'ACP_USER_MANAGEMENT' => 'User management', - 'ACP_USER_OVERVIEW' => 'Overview', - 'ACP_USER_PERM' => 'Permissions', - 'ACP_USER_PREFS' => 'Preferences', - 'ACP_USER_PROFILE' => 'Profile', - 'ACP_USER_RANK' => 'Rank', - 'ACP_USER_ROLES' => 'User roles', - 'ACP_USER_SECURITY' => 'User security', - 'ACP_USER_SIG' => 'Signature', - 'ACP_USER_WARNINGS' => 'Warnings', - - 'ACP_VC_SETTINGS' => 'Spambot countermeasures', - 'ACP_VC_CAPTCHA_DISPLAY' => 'CAPTCHA image preview', - 'ACP_VERSION_CHECK' => 'Check for updates', - 'ACP_VIEW_ADMIN_PERMISSIONS' => 'View administrative permissions', - 'ACP_VIEW_FORUM_MOD_PERMISSIONS' => 'View forum moderation permissions', - 'ACP_VIEW_FORUM_PERMISSIONS' => 'View forum-based permissions', - 'ACP_VIEW_GLOBAL_MOD_PERMISSIONS' => 'View global moderation permissions', - 'ACP_VIEW_USER_PERMISSIONS' => 'View user-based permissions', - - 'ACP_WORDS' => 'Word censoring', - - 'ACTION' => 'Action', - 'ACTIONS' => 'Actions', - 'ACTIVATE' => 'Activate', - 'ADD' => 'Add', - 'ADMIN' => 'Administration', - 'ADMIN_INDEX' => 'Admin index', - 'ADMIN_PANEL' => 'Administration Control Panel', - - 'ADM_LOGOUT' => 'ACP Logout', - 'ADM_LOGGED_OUT' => 'Successfully logged out from Administration Control Panel', - - '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 phpBB.com 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.', - 'DIRECTORY_NOT_DIR' => 'The entered path “%s” is not a directory.', - 'DIRECTORY_NOT_WRITABLE' => 'The entered path “%s” is not writable.', - 'DISABLE' => 'Disable', - 'DOWNLOAD' => 'Download', - 'DOWNLOAD_AS' => 'Download as', - 'DOWNLOAD_STORE' => 'Download or store file', - 'DOWNLOAD_STORE_EXPLAIN' => 'You may directly download the file or save it in your store/ folder.', - 'DOWNLOADS' => 'Downloads', - - 'EDIT' => 'Edit', - 'ENABLE' => 'Enable', - 'EXPORT_DOWNLOAD' => 'Download', - 'EXPORT_STORE' => 'Store', - - 'GENERAL_OPTIONS' => 'General options', - 'GENERAL_SETTINGS' => 'General settings', - 'GLOBAL_MASK' => 'Global permission mask', - - 'INSTALL' => 'Install', - '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:', - 'LOGIN_ADMIN' => 'To administer the board you must be an authenticated user.', - 'LOGIN_ADMIN_CONFIRM' => 'To administer the board you must re-authenticate yourself.', - 'LOGIN_ADMIN_SUCCESS' => 'You have successfully authenticated and will now be redirected to the Administration Control Panel.', - 'LOOK_UP_FORUM' => 'Select a forum', - 'LOOK_UP_FORUMS_EXPLAIN'=> 'You are able to select more than one forum.', - - 'MANAGE' => 'Manage', - 'MENU_TOGGLE' => 'Hide or display the side menu', - 'MORE' => 'More', // Not used at the moment - 'MORE_INFORMATION' => 'More information »', - 'MOVE_DOWN' => 'Move down', - 'MOVE_UP' => 'Move up', - - 'NOTIFY' => 'Notification', - 'NO_ADMIN' => 'You are not authorised to administer this board.', - 'NO_EMAILS_DEFINED' => 'No valid email addresses found.', - 'NO_FILES_TO_DELETE' => 'Attachments you selected for deletion do not exist.', - 'NO_PASSWORD_SUPPLIED' => 'You need to enter your password to access the Administration Control Panel.', - - 'OFF' => 'Off', - 'ON' => 'On', - - 'PARSE_BBCODE' => 'Parse BBCode', - 'PARSE_SMILIES' => 'Parse smilies', - 'PARSE_URLS' => 'Parse links', - 'PERMISSIONS_TRANSFERRED' => 'Permissions transferred', - '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 revert to your permission set 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.', - 'SELECT_ANONYMOUS' => 'Select anonymous user', - 'SELECT_OPTION' => 'Select option', - - 'SETTING_TOO_LOW' => 'The provided value for the setting “%1$s” is too low. The minimum acceptable value is %2$d.', - 'SETTING_TOO_BIG' => 'The provided value for the setting “%1$s” is too high. The maximum acceptable value is %2$d.', - 'SETTING_TOO_LONG' => 'The provided value for the setting “%1$s” is too long. The maximum acceptable length is %2$d.', - 'SETTING_TOO_SHORT' => 'The provided value for the setting “%1$s” is too short. The minimum acceptable length is %2$d.', - - 'SHOW_ALL_OPERATIONS' => 'Show all operations', - - 'TASKS_NOT_READY' => 'Not ready tasks:', - 'TASKS_READY' => 'Ready tasks:', - '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', -)); - -// PHP info -$lang = array_merge($lang, array( - 'ACP_PHP_INFO_EXPLAIN' => 'This page lists information on the version of PHP installed on this server. It includes details of loaded modules, available variables and default settings. This information may be useful when diagnosing problems. Please be aware that some hosting companies will limit what information is displayed here for security reasons. You are advised to not give out any details on this page except when asked by official team members on the support forums.', - - 'NO_PHPINFO_AVAILABLE' => 'Information about your PHP configuration is unable to be determined. Phpinfo() has been disabled for security reasons.', -)); - -// Logs -$lang = array_merge($lang, array( - 'ACP_ADMIN_LOGS_EXPLAIN' => 'This lists all the actions carried out by board administrators. You can sort by username, date, IP or action. If you have appropriate permissions you can also clear individual operations or the log as a whole.', - 'ACP_CRITICAL_LOGS_EXPLAIN' => 'This lists the actions carried out by the board itself. This log provides you with information you are able to use for solving specific problems, for example non-delivery of emails. You can sort by username, date, IP or action. If you have appropriate permissions you can also clear individual operations or the log as a whole.', - 'ACP_MOD_LOGS_EXPLAIN' => 'This lists all actions done on forums, topics and posts as well as actions carried out on users by moderators, including banning. You can sort by username, date, IP or action. If you have appropriate permissions you can also clear individual operations or the log as a whole.', - 'ACP_USERS_LOGS_EXPLAIN' => 'This lists all actions carried out by users or on users (reports, warnings and user notes).', - 'ALL_ENTRIES' => 'All entries', - - 'DISPLAY_LOG' => 'Display entries from previous', - - 'NO_ENTRIES' => 'No log entries for this period.', - - 'SORT_IP' => 'IP address', - 'SORT_DATE' => 'Date', - 'SORT_ACTION' => 'Log action', -)); - -// Index page -$lang = array_merge($lang, array( - 'ADMIN_INTRO' => 'Thank you for choosing phpBB as your board solution. This screen will give you a quick overview of all the various statistics of your board. The links on the left hand side of this screen allow you to control every aspect of your board experience. Each page will have instructions on how to use the tools.', - 'ADMIN_LOG' => 'Logged administrator actions', - 'ADMIN_LOG_INDEX_EXPLAIN' => 'This gives an overview of the last five actions carried out by board administrators. A full copy of the log can be viewed from the appropriate menu item or following the link below.', - 'AVATAR_DIR_SIZE' => 'Avatar directory size', - - 'BOARD_STARTED' => 'Board started', - 'BOARD_VERSION' => 'Board version', - - 'DATABASE_SERVER_INFO' => 'Database server', - 'DATABASE_SIZE' => 'Database size', - - // Enviroment configuration checks, mbstring related - 'ERROR_MBSTRING_FUNC_OVERLOAD' => 'Function overloading is improperly configured', - 'ERROR_MBSTRING_FUNC_OVERLOAD_EXPLAIN' => 'mbstring.func_overload must be set to either 0 or 4. You can check the current value on the PHP information page.', - 'ERROR_MBSTRING_ENCODING_TRANSLATION' => 'Transparent character encoding is improperly configured', - 'ERROR_MBSTRING_ENCODING_TRANSLATION_EXPLAIN' => 'mbstring.encoding_translation must be set to 0. You can check the current value on the PHP information page.', - 'ERROR_MBSTRING_HTTP_INPUT' => 'HTTP input character conversion is improperly configured', - 'ERROR_MBSTRING_HTTP_INPUT_EXPLAIN' => 'mbstring.http_input must be set to pass. You can check the current value on the PHP information page.', - 'ERROR_MBSTRING_HTTP_OUTPUT' => 'HTTP output character conversion is improperly configured', - 'ERROR_MBSTRING_HTTP_OUTPUT_EXPLAIN' => 'mbstring.http_output must be set to pass. You can check the current value on the PHP information page.', - - 'FILES_PER_DAY' => 'Attachments per day', - 'FORUM_STATS' => 'Board statistics', - - 'GZIP_COMPRESSION' => 'GZip compression', - - 'NO_SEARCH_INDEX' => 'The selected search backend does not have a search index.
Please create the index for “%1$s” in the %2$ssearch index%3$s section.', - 'NOT_AVAILABLE' => 'Not available', - 'NUMBER_FILES' => 'Number of attachments', - 'NUMBER_POSTS' => 'Number of posts', - 'NUMBER_TOPICS' => 'Number of topics', - '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', - - 'PURGE_CACHE' => 'Purge the cache', - 'PURGE_CACHE_CONFIRM' => 'Are you sure you wish to purge the cache?', - 'PURGE_CACHE_EXPLAIN' => 'Purge all cache related items, this includes any cached template files or queries.', - 'PURGE_CACHE_SUCCESS' => 'Cache successfully purged.', - - 'PURGE_SESSIONS' => 'Purge all sessions', - 'PURGE_SESSIONS_CONFIRM' => 'Are you sure you wish to purge all sessions? This will log out all users.', - 'PURGE_SESSIONS_EXPLAIN' => 'Purge all sessions. This will log out all users by truncating the session table.', - 'PURGE_SESSIONS_SUCCESS' => 'Sessions successfully purged.', - - 'RESET_DATE' => 'Reset board’s start date', - 'RESET_DATE_CONFIRM' => 'Are you sure you wish to reset the board’s start date?', - 'RESET_DATE_SUCCESS' => 'Board’s start date reset', - 'RESET_ONLINE' => 'Reset most users ever online', - 'RESET_ONLINE_CONFIRM' => 'Are you sure you wish to reset the most users ever online counter?', - 'RESET_ONLINE_SUCCESS' => 'Most users ever online reset', - 'RESYNC_POSTCOUNTS' => 'Resynchronise post counts', - 'RESYNC_POSTCOUNTS_EXPLAIN' => 'Only existing posts will be taken into consideration. Pruned posts will not be counted.', - 'RESYNC_POSTCOUNTS_CONFIRM' => 'Are you sure you wish to resynchronise post counts?', - 'RESYNC_POSTCOUNTS_SUCCESS' => 'Resynchronised post counts', - 'RESYNC_POST_MARKING' => 'Resynchronise dotted topics', - 'RESYNC_POST_MARKING_CONFIRM' => 'Are you sure you wish to resynchronise dotted topics?', - 'RESYNC_POST_MARKING_EXPLAIN' => 'First unmarks all topics and then correctly marks topics that have seen any activity during the past six months.', - 'RESYNC_POST_MARKING_SUCCESS' => 'Resynchronised dotted topics', - 'RESYNC_STATS' => 'Resynchronise statistics', - 'RESYNC_STATS_CONFIRM' => 'Are you sure you wish to resynchronise statistics?', - 'RESYNC_STATS_EXPLAIN' => 'Recalculates the total number of posts, topics, users and files.', - 'RESYNC_STATS_SUCCESS' => 'Resynchronised statistics', - 'RUN' => 'Run now', - - 'STATISTIC' => 'Statistic', - 'STATISTIC_RESYNC_OPTIONS' => 'Resynchronise or reset statistics', - - 'TIMEZONE_INVALID' => 'The timezone you selected is invalid.', - 'TIMEZONE_SELECTED' => '(currently selected)', - 'TOPICS_PER_DAY' => 'Topics per day', - - 'UPLOAD_DIR_SIZE' => 'Size of posted attachments', - 'USERS_PER_DAY' => 'Users per day', - - '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.
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', - - 'WELCOME_PHPBB' => 'Welcome to phpBB', - 'WRITABLE_CONFIG' => 'Your config file (config.php) is currently world-writable. We strongly encourage you to change the permissions to 640 or at least to 644 (for example: chmod 640 config.php).', -)); - -// Inactive Users -$lang = array_merge($lang, array( - 'INACTIVE_DATE' => 'Inactive date', - 'INACTIVE_REASON' => 'Reason', - 'INACTIVE_REASON_MANUAL' => 'Account deactivated by administrator', - 'INACTIVE_REASON_PROFILE' => 'Profile details changed', - 'INACTIVE_REASON_REGISTER' => 'Newly registered account', - 'INACTIVE_REASON_REMIND' => 'Forced user account reactivation', - 'INACTIVE_REASON_UNKNOWN' => 'Unknown', - 'INACTIVE_USERS' => 'Inactive users', - 'INACTIVE_USERS_EXPLAIN' => 'This is a list of users who have registered but whose accounts are inactive. You can activate, delete or remind (by sending an email) these users if you wish.', - 'INACTIVE_USERS_EXPLAIN_INDEX' => 'This is a list of the last 10 registered users who have inactive accounts. Accounts are inactive either because account activation was enabled in user registration settings and these users’ accounts have not yet been activated, or because these accounts have been deactivated. A full list is available by following the link below from where you can activate, delete or remind (by sending an email) these users if you wish.', - - 'NO_INACTIVE_USERS' => 'No inactive users', - - 'SORT_INACTIVE' => 'Inactive date', - 'SORT_LAST_VISIT' => 'Last visit', - 'SORT_REASON' => 'Reason', - 'SORT_REG_DATE' => 'Registration date', - 'SORT_LAST_REMINDER'=> 'Last reminded', - 'SORT_REMINDER' => 'Reminder sent', - - 'USER_IS_INACTIVE' => 'User is inactive', -)); - -// 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 anonymous. We base decisions about future phpBB versions on this information. The statistics are made available publically. We also share this data with the PHP project, the programming language phpBB is made with.', - 'EXPLAIN_SHOW_STATISTICS' => 'Using the button below you can preview all variables that will be transmitted.', - 'DONT_SEND_STATISTICS' => 'Return to the ACP if you do not wish to send statistical information to phpBB.', - 'GO_ACP_MAIN' => 'Go to the ACP start page', - 'HIDE_STATISTICS' => 'Hide details', - 'SEND_STATISTICS' => 'Send 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 -$lang = array_merge($lang, array( - 'LOG_ACL_ADD_USER_GLOBAL_U_' => 'Added or edited users’ user permissions
» %s', - 'LOG_ACL_ADD_GROUP_GLOBAL_U_' => 'Added or edited groups’ user permissions
» %s', - 'LOG_ACL_ADD_USER_GLOBAL_M_' => 'Added or edited users’ global moderator permissions
» %s', - 'LOG_ACL_ADD_GROUP_GLOBAL_M_' => 'Added or edited groups’ global moderator permissions
» %s', - 'LOG_ACL_ADD_USER_GLOBAL_A_' => 'Added or edited users’ administrator permissions
» %s', - 'LOG_ACL_ADD_GROUP_GLOBAL_A_' => 'Added or edited groups’ administrator permissions
» %s', - - 'LOG_ACL_ADD_ADMIN_GLOBAL_A_' => 'Added or edited Administrators
» %s', - 'LOG_ACL_ADD_MOD_GLOBAL_M_' => 'Added or edited Global Moderators
» %s', - - 'LOG_ACL_ADD_USER_LOCAL_F_' => 'Added or edited users’ forum access from %1$s
» %2$s', - 'LOG_ACL_ADD_USER_LOCAL_M_' => 'Added or edited users’ forum moderator access from %1$s
» %2$s', - 'LOG_ACL_ADD_GROUP_LOCAL_F_' => 'Added or edited groups’ forum access from %1$s
» %2$s', - 'LOG_ACL_ADD_GROUP_LOCAL_M_' => 'Added or edited groups’ forum moderator access from %1$s
» %2$s', - - 'LOG_ACL_ADD_MOD_LOCAL_M_' => 'Added or edited Moderators from %1$s
» %2$s', - 'LOG_ACL_ADD_FORUM_LOCAL_F_' => 'Added or edited forum permissions from %1$s
» %2$s', - - 'LOG_ACL_DEL_ADMIN_GLOBAL_A_' => 'Removed Administrators
» %s', - 'LOG_ACL_DEL_MOD_GLOBAL_M_' => 'Removed Global Moderators
» %s', - 'LOG_ACL_DEL_MOD_LOCAL_M_' => 'Removed Moderators from %1$s
» %2$s', - 'LOG_ACL_DEL_FORUM_LOCAL_F_' => 'Removed User/Group forum permissions from %1$s
» %2$s', - - 'LOG_ACL_TRANSFER_PERMISSIONS' => 'Permissions transferred from
» %s', - 'LOG_ACL_RESTORE_PERMISSIONS' => 'Own permissions restored after using permissions from
» %s', - - 'LOG_ADMIN_AUTH_FAIL' => 'Failed administration login attempt', - 'LOG_ADMIN_AUTH_SUCCESS' => 'Successful administration login', - - 'LOG_ATTACHMENTS_DELETED' => 'Removed user attachments
» %s', - - 'LOG_ATTACH_EXT_ADD' => 'Added or edited attachment extension
» %s', - 'LOG_ATTACH_EXT_DEL' => 'Removed attachment extension
» %s', - 'LOG_ATTACH_EXT_UPDATE' => 'Updated attachment extension
» %s', - 'LOG_ATTACH_EXTGROUP_ADD' => 'Added extension group
» %s', - 'LOG_ATTACH_EXTGROUP_EDIT' => 'Edited extension group
» %s', - 'LOG_ATTACH_EXTGROUP_DEL' => 'Removed extension group
» %s', - 'LOG_ATTACH_FILEUPLOAD' => 'Orphan File uploaded to Post
» ID %1$d - %2$s', - 'LOG_ATTACH_ORPHAN_DEL' => 'Orphan Files deleted
» %s', - - 'LOG_BAN_EXCLUDE_USER' => 'Excluded user from ban for reason “%1$s
» %2$s', - 'LOG_BAN_EXCLUDE_IP' => 'Excluded IP from ban for reason “%1$s
» %2$s', - 'LOG_BAN_EXCLUDE_EMAIL' => 'Excluded email from ban for reason “%1$s
» %2$s', - 'LOG_BAN_USER' => 'Banned user for reason “%1$s
» %2$s', - 'LOG_BAN_IP' => 'Banned IP for reason “%1$s
» %2$s', - 'LOG_BAN_EMAIL' => 'Banned email for reason “%1$s
» %2$s', - 'LOG_UNBAN_USER' => 'Unbanned user
» %s', - 'LOG_UNBAN_IP' => 'Unbanned IP
» %s', - 'LOG_UNBAN_EMAIL' => 'Unbanned email
» %s', - - 'LOG_BBCODE_ADD' => 'Added new BBCode
» %s', - 'LOG_BBCODE_EDIT' => 'Edited BBCode
» %s', - 'LOG_BBCODE_DELETE' => 'Deleted BBCode
» %s', - 'LOG_BBCODE_CONFIGURATION_ERROR' => 'Error while configuring BBCode: %1$s
» %2$s', - - 'LOG_BOT_ADDED' => 'New bot added
» %s', - 'LOG_BOT_DELETE' => 'Deleted bot
» %s', - 'LOG_BOT_UPDATED' => 'Existing bot updated
» %s', - - 'LOG_CLEAR_ADMIN' => 'Cleared admin log', - 'LOG_CLEAR_CRITICAL' => 'Cleared error log', - 'LOG_CLEAR_MOD' => 'Cleared moderator log', - 'LOG_CLEAR_USER' => 'Cleared user log
» %s', - 'LOG_CLEAR_USERS' => 'Cleared user logs', - - 'LOG_CONFIG_ATTACH' => 'Altered attachment settings', - 'LOG_CONFIG_AUTH' => 'Altered authentication settings', - 'LOG_CONFIG_AVATAR' => 'Altered avatar settings', - 'LOG_CONFIG_COOKIE' => 'Altered cookie settings', - 'LOG_CONFIG_EMAIL' => 'Altered email settings', - 'LOG_CONFIG_FEATURES' => 'Altered board features', - 'LOG_CONFIG_LOAD' => 'Altered load settings', - 'LOG_CONFIG_MESSAGE' => 'Altered private message settings', - 'LOG_CONFIG_POST' => 'Altered post settings', - 'LOG_CONFIG_REGISTRATION' => 'Altered user registration settings', - 'LOG_CONFIG_FEED' => 'Altered syndication feeds settings', - 'LOG_CONFIG_SEARCH' => 'Altered search settings', - 'LOG_CONFIG_SECURITY' => 'Altered security settings', - 'LOG_CONFIG_SERVER' => 'Altered server settings', - 'LOG_CONFIG_SETTINGS' => 'Altered board settings', - 'LOG_CONFIG_SIGNATURE' => 'Altered signature settings', - 'LOG_CONFIG_VISUAL' => 'Altered anti-spambot settings', - - 'LOG_APPROVE_TOPIC' => 'Approved topic
» %s', - 'LOG_BUMP_TOPIC' => 'User bumped topic
» %s', - 'LOG_DELETE_POST' => 'Deleted post “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_DELETE_SHADOW_TOPIC' => 'Deleted shadow topic
» %s', - 'LOG_DELETE_TOPIC' => 'Deleted topic “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_FORK' => 'Copied topic
» from %s', - 'LOG_LOCK' => 'Locked topic
» %s', - 'LOG_LOCK_POST' => 'Locked post
» %s', - 'LOG_MERGE' => 'Merged posts into topic
» %s', - 'LOG_MOVE' => 'Moved topic
» from %1$s to %2$s', - 'LOG_MOVED_TOPIC' => 'Moved topic
» %s', - 'LOG_PM_REPORT_CLOSED' => 'Closed PM report
» %s', - 'LOG_PM_REPORT_DELETED' => 'Deleted PM report
» %s', - 'LOG_POST_APPROVED' => 'Approved post
» %s', - 'LOG_POST_DISAPPROVED' => 'Disapproved post “%1$s” written by “%3$s” for the following reason
» %2$s', - 'LOG_POST_EDITED' => 'Edited post “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_POST_RESTORED' => 'Restored post
» %s', - 'LOG_REPORT_CLOSED' => 'Closed report
» %s', - 'LOG_REPORT_DELETED' => 'Deleted report
» %s', - 'LOG_RESTORE_TOPIC' => 'Restored topic “%1$s” written by
» %2$s', - 'LOG_SOFTDELETE_POST' => 'Soft deleted post “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_SOFTDELETE_TOPIC' => 'Soft deleted topic “%1$s” written by “%2$s” for the following reason
» %3$s', - 'LOG_SPLIT_DESTINATION' => 'Moved split posts
» to %s', - 'LOG_SPLIT_SOURCE' => 'Split posts
» from %s', - - 'LOG_TOPIC_APPROVED' => 'Approved topic
» %s', - 'LOG_TOPIC_RESTORED' => 'Restored topic
» %s', - 'LOG_TOPIC_DISAPPROVED' => 'Disapproved topic “%1$s” written by “%3$s” for the following reason
» %2$s', - 'LOG_TOPIC_RESYNC' => 'Resynchronised topic counters
» %s', - 'LOG_TOPIC_TYPE_CHANGED' => 'Changed topic type
» %s', - 'LOG_UNLOCK' => 'Unlocked topic
» %s', - 'LOG_UNLOCK_POST' => 'Unlocked post
» %s', - - 'LOG_DISALLOW_ADD' => 'Added disallowed username
» %s', - 'LOG_DISALLOW_DELETE' => 'Deleted disallowed username', - - 'LOG_DB_BACKUP' => 'Database backup', - 'LOG_DB_DELETE' => 'Deleted database backup', - 'LOG_DB_RESTORE' => 'Restored database backup', - - 'LOG_DOWNLOAD_EXCLUDE_IP' => 'Excluded IP/hostname from download list
» %s', - 'LOG_DOWNLOAD_IP' => 'Added IP/hostname to download list
» %s', - 'LOG_DOWNLOAD_REMOVE_IP' => 'Removed IP/hostname from download list
» %s', - - 'LOG_ERROR_JABBER' => 'Jabber error
» %s', - 'LOG_ERROR_EMAIL' => 'Email error
» %s', - 'LOG_ERROR_CAPTCHA' => 'CAPTCHA error
» %s', - - 'LOG_FORUM_ADD' => 'Created new forum
» %s', - 'LOG_FORUM_COPIED_PERMISSIONS' => 'Copied forum permissions from %1$s
» %2$s', - 'LOG_FORUM_DEL_FORUM' => 'Deleted forum
» %s', - 'LOG_FORUM_DEL_FORUMS' => 'Deleted forum and its subforums
» %s', - 'LOG_FORUM_DEL_MOVE_FORUMS' => 'Deleted forum and moved subforums to %1$s
» %2$s', - 'LOG_FORUM_DEL_MOVE_POSTS' => 'Deleted forum and moved posts to %1$s
» %2$s', - 'LOG_FORUM_DEL_MOVE_POSTS_FORUMS' => 'Deleted forum and its subforums, moved posts to %1$s
» %2$s', - 'LOG_FORUM_DEL_MOVE_POSTS_MOVE_FORUMS' => 'Deleted forum, moved posts to %1$s and subforums to %2$s
» %3$s', - 'LOG_FORUM_DEL_POSTS' => 'Deleted forum and its posts
» %s', - 'LOG_FORUM_DEL_POSTS_FORUMS' => 'Deleted forum, its posts and subforums
» %s', - 'LOG_FORUM_DEL_POSTS_MOVE_FORUMS' => 'Deleted forum and its posts, moved subforums to %1$s
» %2$s', - 'LOG_FORUM_EDIT' => 'Edited forum details
» %s', - 'LOG_FORUM_MOVE_DOWN' => 'Moved forum %1$s below %2$s', - 'LOG_FORUM_MOVE_UP' => 'Moved forum %1$s above %2$s', - 'LOG_FORUM_SYNC' => 'Re-synchronised forum
» %s', - - 'LOG_GENERAL_ERROR' => 'A general error occurred: %1$s
» %2$s', - - 'LOG_GROUP_CREATED' => 'New usergroup created
» %s', - 'LOG_GROUP_DEFAULTS' => 'Group “%1$s” made default for members
» %2$s', - 'LOG_GROUP_DELETE' => 'Usergroup deleted
» %s', - 'LOG_GROUP_DEMOTED' => 'Leaders demoted in usergroup %1$s
» %2$s', - 'LOG_GROUP_PROMOTED' => 'Members promoted to leader in usergroup %1$s
» %2$s', - 'LOG_GROUP_REMOVE' => 'Members removed from usergroup %1$s
» %2$s', - 'LOG_GROUP_UPDATED' => 'Usergroup details updated
» %s', - 'LOG_MODS_ADDED' => 'Added new leaders to usergroup %1$s
» %2$s', - 'LOG_USERS_ADDED' => 'Added new members to usergroup %1$s
» %2$s', - 'LOG_USERS_APPROVED' => 'Users approved in usergroup %1$s
» %2$s', - 'LOG_USERS_PENDING' => 'Users requested to join group “%1$s” and need to be approved
» %2$s', - - 'LOG_IMAGE_GENERATION_ERROR' => 'Error while creating image
» Error in %1$s on line %2$s: %3$s', - - 'LOG_INACTIVE_ACTIVATE' => 'Activated inactive users
» %s', - 'LOG_INACTIVE_DELETE' => 'Deleted inactive users
» %s', - 'LOG_INACTIVE_REMIND' => 'Sent reminder emails to inactive users
» %s', - 'LOG_INSTALL_CONVERTED' => 'Converted from %1$s to phpBB %2$s', - 'LOG_INSTALL_INSTALLED' => 'Installed phpBB %s', - - 'LOG_IP_BROWSER_FORWARDED_CHECK' => 'Session IP/browser/X_FORWARDED_FOR check failed
»User IP “%1$s” checked against session IP “%2$s”, user browser string “%3$s” checked against session browser string “%4$s” and user X_FORWARDED_FOR string “%5$s” checked against session X_FORWARDED_FOR string “%6$s”.', - - 'LOG_JAB_CHANGED' => 'Jabber account changed', - 'LOG_JAB_PASSCHG' => 'Jabber password changed', - 'LOG_JAB_REGISTER' => 'Jabber account registered', - 'LOG_JAB_SETTINGS_CHANGED' => 'Jabber settings changed', - - 'LOG_LANGUAGE_PACK_DELETED' => 'Deleted language pack
» %s', - 'LOG_LANGUAGE_PACK_INSTALLED' => 'Installed language pack
» %s', - 'LOG_LANGUAGE_PACK_UPDATED' => 'Updated language pack details
» %s', - 'LOG_LANGUAGE_FILE_REPLACED' => 'Replaced language file
» %s', - 'LOG_LANGUAGE_FILE_SUBMITTED' => 'Submitted language file and placed in store folder
» %s', - - 'LOG_MASS_EMAIL' => 'Sent mass email
» %s', - - 'LOG_MCP_CHANGE_POSTER' => 'Changed poster in topic “%1$s”
» from %2$s to %3$s', - - 'LOG_MODULE_DISABLE' => 'Module disabled
» %s', - 'LOG_MODULE_ENABLE' => 'Module enabled
» %s', - 'LOG_MODULE_MOVE_DOWN' => 'Module moved down
» %1$s below %2$s', - 'LOG_MODULE_MOVE_UP' => 'Module moved up
» %1$s above %2$s', - 'LOG_MODULE_REMOVED' => 'Module removed
» %s', - 'LOG_MODULE_ADD' => 'Module added
» %s', - 'LOG_MODULE_EDIT' => 'Module edited
» %s', - - 'LOG_A_ROLE_ADD' => 'Admin role added
» %s', - 'LOG_A_ROLE_EDIT' => 'Admin role edited
» %s', - 'LOG_A_ROLE_REMOVED' => 'Admin role removed
» %s', - 'LOG_F_ROLE_ADD' => 'Forum role added
» %s', - 'LOG_F_ROLE_EDIT' => 'Forum role edited
» %s', - 'LOG_F_ROLE_REMOVED' => 'Forum role removed
» %s', - 'LOG_M_ROLE_ADD' => 'Moderator role added
» %s', - 'LOG_M_ROLE_EDIT' => 'Moderator role edited
» %s', - 'LOG_M_ROLE_REMOVED' => 'Moderator role removed
» %s', - 'LOG_U_ROLE_ADD' => 'User role added
» %s', - 'LOG_U_ROLE_EDIT' => 'User role edited
» %s', - 'LOG_U_ROLE_REMOVED' => 'User role removed
» %s', - - 'LOG_PLUPLOAD_TIDY_FAILED' => 'Unable to open %1$s for tidying, check permissions.
Exception: %2$s
Trace: %3$s', - - 'LOG_PROFILE_FIELD_ACTIVATE' => 'Profile field activated
» %s', - 'LOG_PROFILE_FIELD_CREATE' => 'Profile field added
» %s', - 'LOG_PROFILE_FIELD_DEACTIVATE' => 'Profile field deactivated
» %s', - 'LOG_PROFILE_FIELD_EDIT' => 'Profile field changed
» %s', - 'LOG_PROFILE_FIELD_REMOVED' => 'Profile field removed
» %s', - - 'LOG_PRUNE' => 'Pruned forums
» %s', - 'LOG_AUTO_PRUNE' => 'Auto-pruned forums
» %s', - 'LOG_PRUNE_SHADOW' => 'Auto-pruned shadow topics
» %s', - 'LOG_PRUNE_USER_DEAC' => 'Users deactivated
» %s', - 'LOG_PRUNE_USER_DEL_DEL' => 'Users pruned and posts deleted
» %s', - 'LOG_PRUNE_USER_DEL_ANON' => 'Users pruned and posts retained
» %s', - - 'LOG_PURGE_CACHE' => 'Purged cache', - 'LOG_PURGE_SESSIONS' => 'Purged sessions', - - 'LOG_RANK_ADDED' => 'Added new rank
» %s', - 'LOG_RANK_REMOVED' => 'Removed rank
» %s', - 'LOG_RANK_UPDATED' => 'Updated rank
» %s', - - 'LOG_REASON_ADDED' => 'Added report/denial reason
» %s', - 'LOG_REASON_REMOVED' => 'Removed report/denial reason
» %s', - 'LOG_REASON_UPDATED' => 'Updated report/denial reason
» %s', - - 'LOG_REFERER_INVALID' => 'Referrer validation failed
»Referrer was “%1$s”. The request was rejected and the session killed.', - 'LOG_RESET_DATE' => 'Board start date reset', - 'LOG_RESET_ONLINE' => 'Most users online reset', - 'LOG_RESYNC_FILES_STATS' => 'File statistics resynchronised', - 'LOG_RESYNC_POSTCOUNTS' => 'User post counts resynchronised', - 'LOG_RESYNC_POST_MARKING' => 'Dotted topics resynchronised', - 'LOG_RESYNC_STATS' => 'Post, topic and user statistics resynchronised', - - 'LOG_SEARCH_INDEX_CREATED' => 'Created search index for
» %s', - 'LOG_SEARCH_INDEX_REMOVED' => 'Removed search index for
» %s', - 'LOG_SPHINX_ERROR' => 'Sphinx Error
» %s', - 'LOG_STYLE_ADD' => 'Added new style
» %s', - 'LOG_STYLE_DELETE' => 'Deleted style
» %s', - 'LOG_STYLE_EDIT_DETAILS' => 'Edited style
» %s', - 'LOG_STYLE_EXPORT' => 'Exported style
» %s', - - // @deprecated 3.1 - 'LOG_TEMPLATE_ADD_DB' => 'Added new template set to database
» %s', - // @deprecated 3.1 - 'LOG_TEMPLATE_ADD_FS' => 'Add new template set on filesystem
» %s', - 'LOG_TEMPLATE_CACHE_CLEARED' => 'Deleted cached versions of template files in template set %1$s
» %2$s', - 'LOG_TEMPLATE_DELETE' => 'Deleted template set
» %s', - 'LOG_TEMPLATE_EDIT' => 'Edited template set %1$s
» %2$s', - 'LOG_TEMPLATE_EDIT_DETAILS' => 'Edited template details
» %s', - 'LOG_TEMPLATE_EXPORT' => 'Exported template set
» %s', - // @deprecated 3.1 - 'LOG_TEMPLATE_REFRESHED' => 'Refreshed template set
» %s', - - // @deprecated 3.1 - 'LOG_THEME_ADD_DB' => 'Added new theme to database
» %s', - // @deprecated 3.1 - 'LOG_THEME_ADD_FS' => 'Add new theme on filesystem
» %s', - 'LOG_THEME_DELETE' => 'Theme deleted
» %s', - 'LOG_THEME_EDIT_DETAILS' => 'Edited theme details
» %s', - 'LOG_THEME_EDIT' => 'Edited theme %1$s', - 'LOG_THEME_EDIT_FILE' => 'Edited theme %1$s
» Modified file %2$s', - 'LOG_THEME_EXPORT' => 'Exported theme
» %s', - // @deprecated 3.1 - 'LOG_THEME_REFRESHED' => 'Refreshed theme
» %s', - - 'LOG_UPDATE_DATABASE' => 'Updated Database from version %1$s to version %2$s', - 'LOG_UPDATE_PHPBB' => 'Updated phpBB from version %1$s to version %2$s', - - 'LOG_USER_ACTIVE' => 'User activated
» %s', - 'LOG_USER_BAN_USER' => 'Banned User via user management for reason “%1$s
» %2$s', - 'LOG_USER_BAN_IP' => 'Banned IP via user management for reason “%1$s
» %2$s', - 'LOG_USER_BAN_EMAIL' => 'Banned email via user management for reason “%1$s
» %2$s', - 'LOG_USER_DELETED' => 'Deleted user
» %s', - 'LOG_USER_DEL_ATTACH' => 'Removed all attachments made by the user
» %s', - 'LOG_USER_DEL_AVATAR' => 'Removed user avatar
» %s', - 'LOG_USER_DEL_OUTBOX' => 'Emptied user outbox
» %s', - 'LOG_USER_DEL_POSTS' => 'Removed all posts made by the user
» %s', - 'LOG_USER_DEL_SIG' => 'Removed user signature
» %s', - 'LOG_USER_INACTIVE' => 'User deactivated
» %s', - 'LOG_USER_MOVE_POSTS' => 'Moved user posts
» posts by “%1$s” to forum “%2$s”', - 'LOG_USER_NEW_PASSWORD' => 'Changed user password
» %s', - 'LOG_USER_REACTIVATE' => 'Forced user account reactivation
» %s', - 'LOG_USER_REMOVED_NR' => 'Removed newly registered flag from user
» %s', - - 'LOG_USER_UPDATE_EMAIL' => 'User “%1$s” changed email
» from “%2$s” to “%3$s”', - 'LOG_USER_UPDATE_NAME' => 'Changed username
» from “%1$s” to “%2$s”', - 'LOG_USER_USER_UPDATE' => 'Updated user details
» %s', - - 'LOG_USER_ACTIVE_USER' => 'User account activated', - 'LOG_USER_DEL_AVATAR_USER' => 'User avatar removed', - 'LOG_USER_DEL_SIG_USER' => 'User signature removed', - 'LOG_USER_FEEDBACK' => 'Added user feedback
» %s', - 'LOG_USER_GENERAL' => 'Entry added:
» %s', - 'LOG_USER_INACTIVE_USER' => 'User account de-activated', - 'LOG_USER_LOCK' => 'User locked own topic
» %s', - 'LOG_USER_MOVE_POSTS_USER' => 'Moved all posts to forum» %s', - 'LOG_USER_REACTIVATE_USER' => 'Forced user account reactivation', - 'LOG_USER_UNLOCK' => 'User unlocked own topic
» %s', - 'LOG_USER_WARNING' => 'Added user warning
» %s', - 'LOG_USER_WARNING_BODY' => 'The following warning was issued to this user
» %s', - - 'LOG_USER_GROUP_CHANGE' => 'User changed default group
» %s', - 'LOG_USER_GROUP_DEMOTE' => 'User demoted as leaders from usergroup
» %s', - 'LOG_USER_GROUP_JOIN' => 'User joined group
» %s', - 'LOG_USER_GROUP_JOIN_PENDING' => 'User joined group and needs to be approved
» %s', - 'LOG_USER_GROUP_RESIGN' => 'User resigned membership from group
» %s', - - 'LOG_WARNING_DELETED' => 'Deleted user warning
» %s', - 'LOG_WARNINGS_DELETED' => array( - 1 => 'Deleted user warning
» %1$s', - 2 => 'Deleted %2$d user warnings
» %1$s', // Example: 'Deleted 2 user warnings
» username' - ), - 'LOG_WARNINGS_DELETED_ALL' => 'Deleted all user warnings
» %s', - - 'LOG_WORD_ADD' => 'Added word censor
» %s', - 'LOG_WORD_DELETE' => 'Deleted word censor
» %s', - 'LOG_WORD_EDIT' => 'Edited word censor
» %s', - - 'LOG_EXT_ENABLE' => 'Extension enabled
» %s', - 'LOG_EXT_DISABLE' => 'Extension disabled
» %s', - 'LOG_EXT_PURGE' => 'Extension’s data deleted
» %s', - 'LOG_EXT_UPDATE' => 'Extension updated
» %s', -)); diff --git a/install/update/old/language/en/acp/forums.php b/install/update/old/language/en/acp/forums.php deleted file mode 100644 index 7a71763..0000000 --- a/install/update/old/language/en/acp/forums.php +++ /dev/null @@ -1,165 +0,0 @@ - -* @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(); -} - -// 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 - -// Forum Admin -$lang = array_merge($lang, array( - 'AUTO_PRUNE_DAYS' => 'Auto-prune post age', - 'AUTO_PRUNE_DAYS_EXPLAIN' => 'Number of days since last post after which topic is removed.', - 'AUTO_PRUNE_FREQ' => 'Auto-prune frequency', - 'AUTO_PRUNE_FREQ_EXPLAIN' => 'Time in days between pruning events.', - 'AUTO_PRUNE_VIEWED' => 'Auto-prune post viewed age', - 'AUTO_PRUNE_VIEWED_EXPLAIN' => 'Number of days since topic was viewed after which topic is removed.', - 'AUTO_PRUNE_SHADOW_FREQ' => 'Auto-prune shadow topics frequency', - 'AUTO_PRUNE_SHADOW_DAYS' => 'Auto-prune shadow topics age', - 'AUTO_PRUNE_SHADOW_DAYS_EXPLAIN' => 'Number of days after which shadow topic is removed.', - 'AUTO_PRUNE_SHADOW_FREQ_EXPLAIN' => 'Time in days between pruning events.', - - 'CONTINUE' => 'Continue', - 'COPY_PERMISSIONS' => 'Copy permissions from', - 'COPY_PERMISSIONS_EXPLAIN' => 'To ease up the permission setup for your new forum, you can copy the permissions of an existing forum.', - 'COPY_PERMISSIONS_ADD_EXPLAIN' => 'Once created, the forum will have the same permissions as the one you select here. If no forum is selected the newly created forum will not be visible until permissions had been set.', - 'COPY_PERMISSIONS_EDIT_EXPLAIN' => 'If you select to copy permissions, the forum will have the same permissions as the one you select here. This will overwrite any permissions you have previously set for this forum with the permissions of the forum you select here. If no forum is selected the current permissions will be kept.', - 'COPY_TO_ACL' => 'Alternatively, you are also able to %sset up new permissions%s for this forum.', - 'CREATE_FORUM' => 'Create new forum', - - 'DECIDE_MOVE_DELETE_CONTENT' => 'Delete content or move to forum', - 'DECIDE_MOVE_DELETE_SUBFORUMS' => 'Delete subforums or move to forum', - 'DEFAULT_STYLE' => 'Default style', - 'DELETE_ALL_POSTS' => 'Delete posts', - 'DELETE_SUBFORUMS' => 'Delete subforums and posts', - 'DISPLAY_ACTIVE_TOPICS' => 'Enable active topics', - 'DISPLAY_ACTIVE_TOPICS_EXPLAIN' => 'If set to yes active topics in selected subforums will be displayed under this category.', - - 'EDIT_FORUM' => 'Edit forum', - 'ENABLE_INDEXING' => 'Enable search indexing', - 'ENABLE_INDEXING_EXPLAIN' => 'If set to yes posts made to this forum will be indexed for searching.', - 'ENABLE_POST_REVIEW' => 'Enable post review', - 'ENABLE_POST_REVIEW_EXPLAIN' => 'If set to yes users are able to review their post if new posts were made to the topic while users wrote theirs. This should be disabled for chat forums.', - 'ENABLE_QUICK_REPLY' => 'Enable quick reply', - 'ENABLE_QUICK_REPLY_EXPLAIN' => 'Enables the quick reply in this forum. This setting is not considered if the quick reply is disabled board wide. The quick reply will only be displayed for users who have permission to post in this forum.', - 'ENABLE_RECENT' => 'Display active topics', - 'ENABLE_RECENT_EXPLAIN' => 'If set to yes topics made to this forum will be shown in the active topics list.', - 'ENABLE_TOPIC_ICONS' => 'Enable topic icons', - - 'FORUM_ADMIN' => 'Forum administration', - 'FORUM_ADMIN_EXPLAIN' => 'In phpBB3 everything is forum based. A category is just a special type of forum. Each forum can have an unlimited number of sub-forums and you can determine whether each may be posted to or not (i.e. whether it acts like an old category). Here you can add, edit, delete, lock, unlock individual forums as well as set certain additional controls. If your posts and topics have got out of sync you can also resynchronise a forum. You need to copy or set appropriate permissions for newly created forums to have them displayed.', - 'FORUM_AUTO_PRUNE' => 'Enable auto-pruning', - 'FORUM_AUTO_PRUNE_EXPLAIN' => 'Prunes the forum of topics, set the frequency/age parameters below.', - 'FORUM_CREATED' => 'Forum created successfully.', - 'FORUM_DATA_NEGATIVE' => 'Pruning parameters cannot be negative.', - 'FORUM_DESC_TOO_LONG' => 'The forum description is too long, it must be less than 4000 characters.', - 'FORUM_DELETE' => 'Delete forum', - '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. 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.', - 'FORUM_IMAGE_NO_EXIST' => 'The specified forum image does not exist', - 'FORUM_LINK_EXPLAIN' => 'Full URL (including the protocol, i.e.: http://) to the destination location that clicking this forum will take the user, e.g.: http://www.phpbb.com/.', - 'FORUM_LINK_TRACK' => 'Track link redirects', - '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_PARENT' => 'Parent forum', - 'FORUM_PASSWORD' => 'Forum password', - 'FORUM_PASSWORD_CONFIRM' => 'Confirm forum password', - 'FORUM_PASSWORD_CONFIRM_EXPLAIN' => 'Only needs to be set if a forum password is entered.', - 'FORUM_PASSWORD_EXPLAIN' => 'Defines a password for this forum, use the permission system in preference.', - 'FORUM_PASSWORD_UNSET' => 'Remove forum password', - 'FORUM_PASSWORD_UNSET_EXPLAIN' => 'Check here if you want to remove the forum password.', - 'FORUM_PASSWORD_OLD' => 'The forum password is using an old hashing method and should be changed.', - 'FORUM_PASSWORD_MISMATCH' => 'The passwords you entered did not match.', - 'FORUM_PRUNE_SETTINGS' => 'Forum prune settings', - 'FORUM_PRUNE_SHADOW' => 'Enable auto-pruning of shadow topics', - 'FORUM_PRUNE_SHADOW_EXPLAIN' => 'Prunes the forum of shadow topics, set the frequency/age parameters below.', - 'FORUM_RESYNCED' => 'Forum “%s” successfully resynced', - 'FORUM_RULES_EXPLAIN' => 'Forum rules are displayed at any page within the given forum.', - 'FORUM_RULES_LINK' => 'Link to forum rules', - 'FORUM_RULES_LINK_EXPLAIN' => 'You are able to enter the URL of the page/post containing your forum rules here. This setting will override the forum rules text you specified.', - 'FORUM_RULES_PREVIEW' => 'Forum rules preview', - 'FORUM_RULES_TOO_LONG' => 'The forum rules must be less than 4000 characters.', - 'FORUM_SETTINGS' => 'Forum settings', - 'FORUM_STATUS' => 'Forum status', - 'FORUM_STYLE' => 'Forum style', - 'FORUM_TOPICS_PAGE' => 'Topics per page', - 'FORUM_TOPICS_PAGE_EXPLAIN' => 'If non-zero this value will override the default topics per page setting.', - 'FORUM_TYPE' => 'Forum type', - 'FORUM_UPDATED' => 'Forum information updated successfully.', - - 'FORUM_WITH_SUBFORUMS_NOT_TO_LINK' => 'You want to change a postable forum having subforums to a link. Please move all subforums out of this forum before you proceed, because after changing to a link you are no longer able to see the subforums currently connected to this forum.', - - 'GENERAL_FORUM_SETTINGS' => 'General forum settings', - - 'LINK' => 'Link', - 'LIST_INDEX' => 'List subforum in parent-forum’s legend', - 'LIST_INDEX_EXPLAIN' => 'Displays this forum on the index and elsewhere as a link within the legend of its parent-forum if the parent-forum’s “List subforums in legend” option is enabled.', - 'LIST_SUBFORUMS' => 'List subforums in legend', - 'LIST_SUBFORUMS_EXPLAIN' => 'Displays this forum’s subforums on the index and elsewhere as a link within the legend if their “List subforum in parent-forum’s legend” option is enabled.', - 'LOCKED' => 'Locked', - - 'MOVE_POSTS_NO_POSTABLE_FORUM' => 'The forum you selected for moving the posts to is not postable. Please select a postable forum.', - 'MOVE_POSTS_TO' => 'Move posts to', - 'MOVE_SUBFORUMS_TO' => 'Move subforums to', - - 'NO_DESTINATION_FORUM' => 'You have not specified a forum to move content to.', - 'NO_FORUM_ACTION' => 'No action defined for what happens with the forum content.', - 'NO_PARENT' => 'No parent', - 'NO_PERMISSIONS' => 'Do not copy permissions', - 'NO_PERMISSION_FORUM_ADD' => 'You do not have the necessary permissions to add forums.', - 'NO_PERMISSION_FORUM_DELETE' => 'You do not have the necessary permissions to delete forums.', - - 'PARENT_IS_LINK_FORUM' => 'The parent you specified is a forum link. Link forums are not able to hold other forums, please specify a category or forum as the parent forum.', - 'PARENT_NOT_EXIST' => 'Parent does not exist.', - 'PRUNE_ANNOUNCEMENTS' => 'Prune announcements', - 'PRUNE_STICKY' => 'Prune stickies', - 'PRUNE_OLD_POLLS' => 'Prune old polls', - 'PRUNE_OLD_POLLS_EXPLAIN' => 'Removes topics with polls not voted in for post age days.', - - 'REDIRECT_ACL' => 'Now you are able to %sset permissions%s for this forum.', - - 'SYNC_IN_PROGRESS' => 'Synchronizing forum', - 'SYNC_IN_PROGRESS_EXPLAIN' => 'Currently resyncing topic range %1$d/%2$d.', - - 'TYPE_CAT' => 'Category', - 'TYPE_FORUM' => 'Forum', - 'TYPE_LINK' => 'Link', - - 'UNLOCKED' => 'Unlocked', -)); diff --git a/install/update/old/language/en/acp/permissions.php b/install/update/old/language/en/acp/permissions.php deleted file mode 100644 index 54d968c..0000000 --- a/install/update/old/language/en/acp/permissions.php +++ /dev/null @@ -1,287 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - 'ACP_PERMISSIONS_EXPLAIN' => ' -

Permissions are highly granular and grouped into four major sections, which are:

- -

Global Permissions

-

These are used to control access on a global level and apply to the entire bulletin board. They are further divided into User Permissions, Group Permissions, Administrators and Global Moderators.

- -

Forum Based Permissions

-

These are used to control access on a per forum basis. They are further divided into Forum Permissions, Forum Moderators, User Forum Permissions and Group Forum Permissions.

- -

Permission Roles

-

These are used to create different sets of permissions for the different permission types later being able to be assigned on a role-based basis. The default roles should cover the administration of bulletin boards large and small, though within each of the four divisions, you can add/edit/delete roles as you see fit.

- -

Permission Masks

-

These are used to view the effective permissions assigned to Users, Moderators (Local and Global), Administrators or Forums.

- -
- -

For further information on setting up and managing permissions on your phpBB3 board, please see the section on Setting permissions of our Quick Start Guide.

- ', - - 'ACL_NEVER' => 'Never', - 'ACL_SET' => 'Setting permissions', - 'ACL_SET_EXPLAIN' => 'Permissions are based on a simple YES/NO system. Setting an option to NEVER for a user or usergroup overrides any other value assigned to it. If you do not wish to assign a value for an option for this user or group select NO. If values are assigned for this option elsewhere they will be used in preference, else NEVER is assumed. All objects marked (with the checkbox in front of them) will copy the permission set you defined.', - 'ACL_SETTING' => 'Setting', - - 'ACL_TYPE_A_' => 'Administrative permissions', - 'ACL_TYPE_F_' => 'Forum permissions', - 'ACL_TYPE_M_' => 'Moderative permissions', - 'ACL_TYPE_U_' => 'User permissions', - - 'ACL_TYPE_GLOBAL_A_' => 'Administrative permissions', - 'ACL_TYPE_GLOBAL_U_' => 'User permissions', - 'ACL_TYPE_GLOBAL_M_' => 'Global Moderator permissions', - 'ACL_TYPE_LOCAL_M_' => 'Forum Moderator permissions', - 'ACL_TYPE_LOCAL_F_' => 'Forum permissions', - - 'ACL_NO' => 'No', - 'ACL_VIEW' => 'Viewing permissions', - 'ACL_VIEW_EXPLAIN' => 'Here you can see the effective permissions the user/group is having. A red square indicates that the user/group does not have the permission, a green square indicates that the user/group does have the permission.', - 'ACL_YES' => 'Yes', - - 'ACP_ADMINISTRATORS_EXPLAIN' => 'Here you can assign administrator permissions to users or groups. All users with administrator permissions can view the administration control panel.', - 'ACP_FORUM_MODERATORS_EXPLAIN' => 'Here you can assign users and groups as forum moderators. To assign users access to forums, to define global moderative permissions or administrators please use the appropriate page.', - 'ACP_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can alter which users and groups can access which forums. To assign moderators or define administrators please use the appropriate page.', - 'ACP_FORUM_PERMISSIONS_COPY_EXPLAIN' => 'Here you can copy forum permissions from one forum to one or more other forums.', - 'ACP_GLOBAL_MODERATORS_EXPLAIN' => 'Here you can assign global moderator permissions to users or groups. These moderators are like ordinary moderators except they have access to every forum on your board.', - 'ACP_GROUPS_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can assign forum permissions to groups.', - 'ACP_GROUPS_PERMISSIONS_EXPLAIN' => 'Here you can assign global permissions to groups - user permissions, global moderator permissions and administrator permissions. User permissions include capabilities such as the use of avatars, sending private messages, et cetera; global moderator permissions such as approving posts, manage topics, manage bans, et cetera and lastly administrator permissions such as altering permissions, define custom BBCodes, manage forums, et cetera. Individual user permissions should only be changed in rare occasions, the preferred method is putting users in groups and assigning the group permissions.', - 'ACP_ADMIN_ROLES_EXPLAIN' => 'Here you are able to manage the roles for administrative permissions. Roles are effective permissions, if you change a role the items having this role assigned will change its permissions too.', - 'ACP_FORUM_ROLES_EXPLAIN' => 'Here you are able to manage the roles for forum permissions. Roles are effective permissions, if you change a role the items having this role assigned will change its permissions too.', - 'ACP_MOD_ROLES_EXPLAIN' => 'Here you are able to manage the roles for moderative permissions. Roles are effective permissions, if you change a role the items having this role assigned will change its permissions too.', - 'ACP_USER_ROLES_EXPLAIN' => 'Here you are able to manage the roles for user permissions. Roles are effective permissions, if you change a role the items having this role assigned will change its permissions too.', - 'ACP_USERS_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can assign forum permissions to users.', - 'ACP_USERS_PERMISSIONS_EXPLAIN' => 'Here you can assign global permissions to users - user permissions, global moderator permissions and administrator permissions. User permissions include capabilities such as the use of avatars, sending private messages, et cetera; global moderator permissions such as approving posts, manage topics, manage bans, et cetera and lastly administrator permissions such as altering permissions, define custom BBCodes, manage forums, et cetera. To alter these settings for large numbers of users the Group permissions system is the preferred method. User permissions should only be changed in rare occasions, the preferred method is putting users in groups and assigning the group permissions.', - 'ACP_VIEW_ADMIN_PERMISSIONS_EXPLAIN' => 'Here you can view the effective administrative permissions assigned to the selected users/groups.', - 'ACP_VIEW_GLOBAL_MOD_PERMISSIONS_EXPLAIN' => 'Here you can view the global moderative permissions assigned to the selected users/groups.', - 'ACP_VIEW_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can view the forum permissions assigned to the selected users/groups and forums.', - 'ACP_VIEW_FORUM_MOD_PERMISSIONS_EXPLAIN' => 'Here you can view the forum moderator permissions assigned to the selected users/groups and forums.', - 'ACP_VIEW_USER_PERMISSIONS_EXPLAIN' => 'Here you can view the effective user permissions assigned to the selected users/groups.', - - 'ADD_GROUPS' => 'Add groups', - 'ADD_PERMISSIONS' => 'Add permissions', - 'ADD_USERS' => 'Add users', - 'ADVANCED_PERMISSIONS' => 'Advanced Permissions', - 'ALL_GROUPS' => 'Select all groups', - 'ALL_NEVER' => 'All NEVER', - 'ALL_NO' => 'All NO', - 'ALL_USERS' => 'Select all users', - 'ALL_YES' => 'All YES', - 'APPLY_ALL_PERMISSIONS' => 'Apply all permissions', - 'APPLY_PERMISSIONS' => 'Apply permissions', - 'APPLY_PERMISSIONS_EXPLAIN' => 'The permissions and role defined for this item will only be applied to this item and all checked items.', - 'AUTH_UPDATED' => 'Permissions have been updated.', - - 'COPY_PERMISSIONS_CONFIRM' => 'Are you sure you wish to carry out this operation? Please be aware that this will overwrite any existing permissions on the selected targets.', - 'COPY_PERMISSIONS_FORUM_FROM_EXPLAIN' => 'The source forum you want to copy permissions from.', - 'COPY_PERMISSIONS_FORUM_TO_EXPLAIN' => 'The destination forums you want the copied permissions applied to.', - 'COPY_PERMISSIONS_FROM' => 'Copy permissions from', - 'COPY_PERMISSIONS_TO' => 'Apply permissions to', - - 'CREATE_ROLE' => 'Create role', - 'CREATE_ROLE_FROM' => 'Use settings from…', - 'CUSTOM' => 'Custom…', - - 'DEFAULT' => 'Default', - 'DELETE_ROLE' => 'Delete role', - 'DELETE_ROLE_CONFIRM' => 'Are you sure you want to remove this role? Items having this role assigned will not lose their permission settings.', - 'DISPLAY_ROLE_ITEMS' => 'View items using this role', - - 'EDIT_PERMISSIONS' => 'Edit permissions', - 'EDIT_ROLE' => 'Edit role', - - 'GROUPS_NOT_ASSIGNED' => 'No group assigned to this role', - - 'LOOK_UP_GROUP' => 'Look up usergroup', - 'LOOK_UP_USER' => 'Look up user', - - 'MANAGE_GROUPS' => 'Manage groups', - 'MANAGE_USERS' => 'Manage users', - - 'NO_AUTH_SETTING_FOUND' => 'Permission settings not defined.', - 'NO_ROLE_ASSIGNED' => 'No role assigned…', - 'NO_ROLE_ASSIGNED_EXPLAIN' => 'Setting to this role does not change permissions on the right. If you want to unset/remove all permissions you should use the “All NO” link.', - 'NO_ROLE_AVAILABLE' => 'No role available', - 'NO_ROLE_NAME_SPECIFIED' => 'Please give the role a name.', - 'NO_ROLE_SELECTED' => 'Role could not be found.', - 'NO_USER_GROUP_SELECTED' => 'You haven’t selected any user or group.', - - 'ONLY_FORUM_DEFINED' => 'You only defined forums in your selection. Please also select at least one user or one group.', - - 'PERMISSION_APPLIED_TO_ALL' => 'Permissions and role will also be applied to all checked objects', - 'PLUS_SUBFORUMS' => '+Subforums', - - 'REMOVE_PERMISSIONS' => 'Remove permissions', - 'REMOVE_ROLE' => 'Remove role', - 'RESULTING_PERMISSION' => 'Resulting permission', - 'ROLE' => 'Role', - 'ROLE_ADD_SUCCESS' => 'Role successfully added.', - 'ROLE_ASSIGNED_TO' => 'Users/Groups assigned to %s', - 'ROLE_DELETED' => 'Role successfully removed.', - 'ROLE_DESCRIPTION' => 'Role description', - - 'ROLE_ADMIN_FORUM' => 'Forum Admin', - 'ROLE_ADMIN_FULL' => 'Full Admin', - 'ROLE_ADMIN_STANDARD' => 'Standard Admin', - 'ROLE_ADMIN_USERGROUP' => 'User and Groups Admin', - 'ROLE_FORUM_BOT' => 'Bot Access', - 'ROLE_FORUM_FULL' => 'Full Access', - 'ROLE_FORUM_LIMITED' => 'Limited Access', - 'ROLE_FORUM_LIMITED_POLLS' => 'Limited Access + Polls', - 'ROLE_FORUM_NOACCESS' => 'No Access', - 'ROLE_FORUM_ONQUEUE' => 'On Moderation Queue', - 'ROLE_FORUM_POLLS' => 'Standard Access + Polls', - 'ROLE_FORUM_READONLY' => 'Read Only Access', - 'ROLE_FORUM_STANDARD' => 'Standard Access', - 'ROLE_FORUM_NEW_MEMBER' => 'Newly Registered User Access', - 'ROLE_MOD_FULL' => 'Full Moderator', - 'ROLE_MOD_QUEUE' => 'Queue Moderator', - 'ROLE_MOD_SIMPLE' => 'Simple Moderator', - 'ROLE_MOD_STANDARD' => 'Standard Moderator', - 'ROLE_USER_FULL' => 'All Features', - 'ROLE_USER_LIMITED' => 'Limited Features', - 'ROLE_USER_NOAVATAR' => 'No Avatar', - 'ROLE_USER_NOPM' => 'No Private Messages', - 'ROLE_USER_STANDARD' => 'Standard Features', - 'ROLE_USER_NEW_MEMBER' => 'Newly Registered User Features', - - 'ROLE_DESCRIPTION_ADMIN_FORUM' => 'Can access the forum management and forum permission settings.', - 'ROLE_DESCRIPTION_ADMIN_FULL' => 'Has access to all administrative functions of this board.
Not recommended.', - 'ROLE_DESCRIPTION_ADMIN_STANDARD' => 'Has access to most administrative features but is not allowed to use server or system related tools.', - 'ROLE_DESCRIPTION_ADMIN_USERGROUP' => 'Can manage groups and users: Able to change permissions, settings, manage bans, and manage ranks.', - 'ROLE_DESCRIPTION_FORUM_BOT' => 'This role is recommended for bots and search spiders.', - 'ROLE_DESCRIPTION_FORUM_FULL' => 'Can use all forum features, including posting of announcements and stickies. Can also ignore the flood limit.
Not recommended for normal users.', - 'ROLE_DESCRIPTION_FORUM_LIMITED' => 'Can use some forum features, but cannot attach files or use post icons.', - 'ROLE_DESCRIPTION_FORUM_LIMITED_POLLS' => 'As per Limited Access but can also create polls.', - 'ROLE_DESCRIPTION_FORUM_NOACCESS' => 'Can neither see nor access the forum.', - 'ROLE_DESCRIPTION_FORUM_ONQUEUE' => 'Can use most forum features including attachments, but posts and topics need to be approved by a moderator.', - 'ROLE_DESCRIPTION_FORUM_POLLS' => 'Like Standard Access but can also create polls.', - 'ROLE_DESCRIPTION_FORUM_READONLY' => 'Can read the forum, but cannot create new topics or reply to posts.', - 'ROLE_DESCRIPTION_FORUM_STANDARD' => 'Can use most forum features including attachments and deleting own topics, but cannot lock own topics, and cannot create polls.', - 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER' => 'A role for members of the special newly registered users group; contains NEVER permissions to lock features for new users.', - 'ROLE_DESCRIPTION_MOD_FULL' => 'Can use all moderating features, including banning.', - 'ROLE_DESCRIPTION_MOD_QUEUE' => 'Can use the Moderation Queue to validate and edit posts, but nothing else.', - 'ROLE_DESCRIPTION_MOD_SIMPLE' => 'Can only use basic topic actions. Cannot send warnings or use moderation queue.', - 'ROLE_DESCRIPTION_MOD_STANDARD' => 'Can use most moderating tools, but cannot ban users or change the post author.', - 'ROLE_DESCRIPTION_USER_FULL' => 'Can use all available forum features for users, including changing the user name or ignoring the flood limit.
Not recommended.', - 'ROLE_DESCRIPTION_USER_LIMITED' => 'Can access some of the user features. Attachments, emails, or instant messages are not allowed.', - 'ROLE_DESCRIPTION_USER_NOAVATAR' => 'Has a limited feature set and is not allowed to use the Avatar feature.', - 'ROLE_DESCRIPTION_USER_NOPM' => 'Has a limited feature set, and is not allowed to use Private Messages.', - 'ROLE_DESCRIPTION_USER_STANDARD' => 'Can access most but not all user features. Cannot change user name or ignore the flood limit, for instance.', - 'ROLE_DESCRIPTION_USER_NEW_MEMBER' => 'A role for members of the special newly registered users group; contains NEVER permissions to lock features for new users.', - - 'ROLE_DESCRIPTION_EXPLAIN' => 'You are able to enter a short explanation of what the role is doing or for what it is meant for. The text you enter here will be displayed within the permissions screens too.', - 'ROLE_DESCRIPTION_LONG' => 'The role description is too long, please limit it to 4000 characters.', - 'ROLE_DETAILS' => 'Role details', - 'ROLE_EDIT_SUCCESS' => 'Role successfully edited.', - 'ROLE_NAME' => 'Role name', - 'ROLE_NAME_ALREADY_EXIST' => 'A role named %s already exist for the specified permission type.', - 'ROLE_NOT_ASSIGNED' => 'Role has not been assigned yet.', - - 'SELECTED_FORUM_NOT_EXIST' => 'The selected forum(s) do not exist.', - 'SELECTED_GROUP_NOT_EXIST' => 'The selected group(s) do not exist.', - 'SELECTED_USER_NOT_EXIST' => 'The selected user(s) do not exist.', - 'SELECT_FORUM_SUBFORUM_EXPLAIN' => 'The forum you select here will include all subforums into the selection.', - 'SELECT_ROLE' => 'Select role…', - 'SELECT_TYPE' => 'Select type', - 'SET_PERMISSIONS' => 'Set permissions', - 'SET_ROLE_PERMISSIONS' => 'Set role permissions', - 'SET_USERS_PERMISSIONS' => 'Set user permissions', - 'SET_USERS_FORUM_PERMISSIONS' => 'Set user forum permissions', - - 'TRACE_DEFAULT' => 'By default every permission is NO (unset). So the permission can be overwritten by other settings.', - 'TRACE_FOR' => 'Trace for', - 'TRACE_GLOBAL_SETTING' => '%s (global)', - 'TRACE_GROUP_NEVER_TOTAL_NEVER' => 'This group’s permission is set to NEVER like the total result so the old result is kept.', - 'TRACE_GROUP_NEVER_TOTAL_NEVER_LOCAL' => 'This group’s permission for this forum is set to NEVER like the total result so the old result is kept.', - 'TRACE_GROUP_NEVER_TOTAL_NO' => 'This group’s permission is set to NEVER which becomes the new total value because it wasn’t set yet (set to NO).', - 'TRACE_GROUP_NEVER_TOTAL_NO_LOCAL' => 'This group’s permission for this forum is set to NEVER which becomes the new total value because it wasn’t set yet (set to NO).', - 'TRACE_GROUP_NEVER_TOTAL_YES' => 'This group’s permission is set to NEVER which overwrites the total YES to a NEVER for this user.', - 'TRACE_GROUP_NEVER_TOTAL_YES_LOCAL' => 'This group’s permission for this forum is set to NEVER which overwrites the total YES to a NEVER for this user.', - 'TRACE_GROUP_NO' => 'The permission is NO for this group so the old total value is kept.', - 'TRACE_GROUP_NO_LOCAL' => 'The permission is NO for this group within this forum so the old total value is kept.', - 'TRACE_GROUP_YES_TOTAL_NEVER' => 'This group’s permission is set to YES but the total NEVER cannot be overwritten.', - 'TRACE_GROUP_YES_TOTAL_NEVER_LOCAL' => 'This group’s permission for this forum is set to YES but the total NEVER cannot be overwritten.', - 'TRACE_GROUP_YES_TOTAL_NO' => 'This group’s permission is set to YES which becomes the new total value because it wasn’t set yet (set to NO).', - 'TRACE_GROUP_YES_TOTAL_NO_LOCAL' => 'This group’s permission for this forum is set to YES which becomes the new total value because it wasn’t set yet (set to NO).', - 'TRACE_GROUP_YES_TOTAL_YES' => 'This group’s permission is set to YES and the total permission is already set to YES, so the total result is kept.', - 'TRACE_GROUP_YES_TOTAL_YES_LOCAL' => 'This group’s permission for this forum is set to YES and the total permission is already set to YES, so the total result is kept.', - 'TRACE_PERMISSION' => 'Trace permission - %s', - 'TRACE_RESULT' => 'Trace result', - 'TRACE_SETTING' => 'Trace setting', - - 'TRACE_USER_GLOBAL_YES_TOTAL_YES' => 'The forum independent user permission evaluates to YES but the total permission is already set to YES, so the total result is kept. %sTrace global permission%s', - 'TRACE_USER_GLOBAL_YES_TOTAL_NEVER' => 'The forum independent user permission evaluates to YES which overwrites the current local result NEVER. %sTrace global permission%s', - 'TRACE_USER_GLOBAL_NEVER_TOTAL_KEPT' => 'The forum independent user permission evaluates to NEVER which doesn’t influence the local permission. %sTrace global permission%s', - - 'TRACE_USER_FOUNDER' => 'The user is a founder, therefore admin permissions are always set to YES.', - 'TRACE_USER_KEPT' => 'The user’s permission is NO so the old total value is kept.', - 'TRACE_USER_KEPT_LOCAL' => 'The user’s permission for this forum is NO so the old total value is kept.', - 'TRACE_USER_NEVER_TOTAL_NEVER' => 'The user’s permission is set to NEVER and the total value is set to NEVER, so nothing is changed.', - 'TRACE_USER_NEVER_TOTAL_NEVER_LOCAL' => 'The user’s permission for this forum is set to NEVER and the total value is set to NEVER, so nothing is changed.', - 'TRACE_USER_NEVER_TOTAL_NO' => 'The user’s permission is set to NEVER which becomes the total value because it was set to NO.', - 'TRACE_USER_NEVER_TOTAL_NO_LOCAL' => 'The user’s permission for this forum is set to NEVER which becomes the total value because it was set to NO.', - 'TRACE_USER_NEVER_TOTAL_YES' => 'The user’s permission is set to NEVER and overwrites the previous YES.', - 'TRACE_USER_NEVER_TOTAL_YES_LOCAL' => 'The user’s permission for this forum is set to NEVER and overwrites the previous YES.', - 'TRACE_USER_NO_TOTAL_NO' => 'The user’s permission is NO and the total value was set to NO so it defaults to NEVER.', - 'TRACE_USER_NO_TOTAL_NO_LOCAL' => 'The user’s permission for this forum is NO and the total value was set to NO so it defaults to NEVER.', - 'TRACE_USER_YES_TOTAL_NEVER' => 'The user’s permission is set to YES but the total NEVER cannot be overwritten.', - 'TRACE_USER_YES_TOTAL_NEVER_LOCAL' => 'The user’s permission for this forum is set to YES but the total NEVER cannot be overwritten.', - 'TRACE_USER_YES_TOTAL_NO' => 'The user’s permission is set to YES which becomes the total value because it was set to NO.', - 'TRACE_USER_YES_TOTAL_NO_LOCAL' => 'The user’s permission for this forum is set to YES which becomes the total value because it was set to NO.', - 'TRACE_USER_YES_TOTAL_YES' => 'The user’s permission is set to YES and the total value is set to YES, so nothing is changed.', - 'TRACE_USER_YES_TOTAL_YES_LOCAL' => 'The user’s permission for this forum is set to YES and the total value is set to YES, so nothing is changed.', - 'TRACE_WHO' => 'Who', - 'TRACE_TOTAL' => 'Total', - - 'USERS_NOT_ASSIGNED' => 'No users are assigned to this role', - 'USER_IS_MEMBER_OF_DEFAULT' => 'is a member of the following pre-defined groups', - 'USER_IS_MEMBER_OF_CUSTOM' => 'is a member of the following user defined groups', - - 'VIEW_ASSIGNED_ITEMS' => 'View assigned items', - 'VIEW_LOCAL_PERMS' => 'Local permissions', - 'VIEW_GLOBAL_PERMS' => 'Global permissions', - 'VIEW_PERMISSIONS' => 'View permissions', - - 'WRONG_PERMISSION_TYPE' => 'Wrong permission type selected.', - 'WRONG_PERMISSION_SETTING_FORMAT' => 'The permission settings are in a wrong format, phpBB is not able to process them correctly.', -)); diff --git a/install/update/old/language/en/acp/permissions_phpbb.php b/install/update/old/language/en/acp/permissions_phpbb.php deleted file mode 100644 index 64740b3..0000000 --- a/install/update/old/language/en/acp/permissions_phpbb.php +++ /dev/null @@ -1,214 +0,0 @@ - -* @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(); -} - -// 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 - -/** -* EXTENSION-DEVELOPERS PLEASE NOTE -* -* You are able to put your permission sets into your extension. -* The permissions logic should be added via the 'core.permissions' event. -* You can easily add new permission categories, types and permissions, by -* simply merging them into the respective arrays. -* The respective language strings should be added into a language file, that -* start with 'permissions_', so they are automatically loaded within the ACP. -*/ - -$lang = array_merge($lang, array( - 'ACL_CAT_ACTIONS' => 'Actions', - 'ACL_CAT_CONTENT' => 'Content', - 'ACL_CAT_FORUMS' => 'Forums', - 'ACL_CAT_MISC' => 'Misc', - 'ACL_CAT_PERMISSIONS' => 'Permissions', - 'ACL_CAT_PM' => 'Private messages', - 'ACL_CAT_POLLS' => 'Polls', - 'ACL_CAT_POST' => 'Post', - 'ACL_CAT_POST_ACTIONS' => 'Post actions', - 'ACL_CAT_POSTING' => 'Posting', - 'ACL_CAT_PROFILE' => 'Profile', - 'ACL_CAT_SETTINGS' => 'Settings', - 'ACL_CAT_TOPIC_ACTIONS' => 'Topic actions', - 'ACL_CAT_USER_GROUP' => 'Users & Groups', -)); - -// User Permissions -$lang = array_merge($lang, array( - 'ACL_U_VIEWPROFILE' => 'Can view profiles, memberlist and online list', - 'ACL_U_CHGNAME' => 'Can change username', - 'ACL_U_CHGPASSWD' => 'Can change password', - 'ACL_U_CHGEMAIL' => 'Can change email address', - 'ACL_U_CHGAVATAR' => 'Can change avatar', - 'ACL_U_CHGGRP' => 'Can change default usergroup', - 'ACL_U_CHGPROFILEINFO' => 'Can change profile field information', - - 'ACL_U_ATTACH' => 'Can attach files', - 'ACL_U_DOWNLOAD' => 'Can download files', - 'ACL_U_SAVEDRAFTS' => 'Can save drafts', - 'ACL_U_CHGCENSORS' => 'Can disable word censors', - 'ACL_U_SIG' => 'Can use signature', - - '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_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', - 'ACL_U_PM_FORWARD' => 'Can forward private messages', - 'ACL_U_PM_EMAILPM' => 'Can email private messages', - 'ACL_U_PM_PRINTPM' => 'Can print private messages', - 'ACL_U_PM_ATTACH' => 'Can attach files in private messages', - 'ACL_U_PM_DOWNLOAD' => 'Can download files in private messages', - 'ACL_U_PM_BBCODE' => 'Can use BBCode in private messages', - 'ACL_U_PM_SMILIES' => 'Can use smilies in private messages', - 'ACL_U_PM_IMG' => 'Can use [img] BBCode tag in private messages', - 'ACL_U_PM_FLASH' => 'Can use [flash] BBCode tag in private messages', - - 'ACL_U_SENDEMAIL' => 'Can send emails', - 'ACL_U_SENDIM' => 'Can send instant messages', - 'ACL_U_IGNOREFLOOD' => 'Can ignore flood limit', - 'ACL_U_HIDEONLINE' => 'Can hide online status', - 'ACL_U_VIEWONLINE' => 'Can view hidden online users', - 'ACL_U_SEARCH' => 'Can search board', -)); - -// 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', - 'ACL_F_PRINT' => 'Can print topics', - 'ACL_F_EMAIL' => 'Can email topics', - 'ACL_F_BUMP' => 'Can bump topics', - 'ACL_F_USER_LOCK' => 'Can lock own topics', - 'ACL_F_DOWNLOAD' => 'Can download files', - 'ACL_F_REPORT' => 'Can report posts', - - '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', - 'ACL_F_SOFTDELETE' => 'Can soft delete own posts
Moderators, who have the approve posts permission, can restore soft deleted posts.', - 'ACL_F_IGNOREFLOOD' => 'Can ignore flood limit', - 'ACL_F_POSTCOUNT' => 'Increment post counter
Please note that this setting only affects new posts.', - 'ACL_F_NOAPPROVE' => 'Can post without approval', - - 'ACL_F_ATTACH' => 'Can attach files', - 'ACL_F_ICONS' => 'Can use topic/post icons', - 'ACL_F_BBCODE' => 'Can use BBCode', - 'ACL_F_FLASH' => 'Can use [flash] BBCode tag', - 'ACL_F_IMG' => 'Can use [img] BBCode tag', - 'ACL_F_SIGS' => 'Can use signatures', - 'ACL_F_SMILIES' => 'Can use smilies', - - 'ACL_F_POLL' => 'Can create polls', - 'ACL_F_VOTE' => 'Can vote in polls', - 'ACL_F_VOTECHG' => 'Can change existing vote', -)); - -// Moderator Permissions -$lang = array_merge($lang, array( - 'ACL_M_EDIT' => 'Can edit posts', - 'ACL_M_DELETE' => 'Can permanently delete posts', - 'ACL_M_SOFTDELETE' => 'Can soft delete posts
Moderators, who have the approve posts permission, can restore soft deleted posts.', - 'ACL_M_APPROVE' => 'Can approve and restore posts', - 'ACL_M_REPORT' => 'Can close and delete reports', - 'ACL_M_CHGPOSTER' => 'Can change post author', - - 'ACL_M_MOVE' => 'Can move topics', - 'ACL_M_LOCK' => 'Can lock topics', - 'ACL_M_SPLIT' => 'Can split topics', - 'ACL_M_MERGE' => 'Can merge topics', - - 'ACL_M_INFO' => 'Can view post details', - 'ACL_M_WARN' => 'Can issue warnings
This setting is only assigned globally. It is not forum based.', // This moderator setting is only global (and not local) - 'ACL_M_PM_REPORT' => 'Can close and delete reports of private messages
This setting is only assigned globally. It is not forum based.', // This moderator setting is only global (and not local) - 'ACL_M_BAN' => 'Can manage bans
This setting is only assigned globally. It is not forum based.', // This moderator setting is only global (and not local) -)); - -// Admin Permissions -$lang = array_merge($lang, array( - 'ACL_A_BOARD' => 'Can alter board settings/check for updates', - 'ACL_A_SERVER' => 'Can alter server/communication settings', - 'ACL_A_JABBER' => 'Can alter Jabber settings', - 'ACL_A_PHPINFO' => 'Can view php settings', - - 'ACL_A_FORUM' => 'Can manage forums', - 'ACL_A_FORUMADD' => 'Can add new forums', - 'ACL_A_FORUMDEL' => 'Can delete forums', - 'ACL_A_PRUNE' => 'Can prune forums', - - 'ACL_A_ICONS' => 'Can alter topic/post icons and smilies', - 'ACL_A_WORDS' => 'Can alter word censors', - 'ACL_A_BBCODE' => 'Can define BBCode tags', - 'ACL_A_ATTACH' => 'Can alter attachment related settings', - - 'ACL_A_USER' => 'Can manage users
This also includes seeing the users browser agent within the viewonline list.', - 'ACL_A_USERDEL' => 'Can delete/prune users', - 'ACL_A_GROUP' => 'Can manage groups', - 'ACL_A_GROUPADD' => 'Can add new groups', - 'ACL_A_GROUPDEL' => 'Can delete groups', - 'ACL_A_RANKS' => 'Can manage ranks', - 'ACL_A_PROFILE' => 'Can manage custom profile fields', - 'ACL_A_NAMES' => 'Can manage disallowed names', - 'ACL_A_BAN' => 'Can manage bans', - - 'ACL_A_VIEWAUTH' => 'Can view permission masks', - 'ACL_A_AUTHGROUPS' => 'Can alter permissions for individual groups', - 'ACL_A_AUTHUSERS' => 'Can alter permissions for individual users', - 'ACL_A_FAUTH' => 'Can alter forum permission class', - 'ACL_A_MAUTH' => 'Can alter moderator permission class', - 'ACL_A_AAUTH' => 'Can alter admin permission class', - 'ACL_A_UAUTH' => 'Can alter user permission class', - 'ACL_A_ROLES' => 'Can manage roles', - 'ACL_A_SWITCHPERM' => 'Can use others permissions', - - 'ACL_A_STYLES' => 'Can manage styles', - 'ACL_A_EXTENSIONS' => 'Can manage extensions', - 'ACL_A_VIEWLOGS' => 'Can view logs', - 'ACL_A_CLEARLOGS' => 'Can clear logs', - 'ACL_A_MODULES' => 'Can manage modules', - 'ACL_A_LANGUAGE' => 'Can manage language packs', - 'ACL_A_EMAIL' => 'Can send mass email', - 'ACL_A_BOTS' => 'Can manage bots', - 'ACL_A_REASONS' => 'Can manage report/denial reasons', - 'ACL_A_BACKUP' => 'Can backup/restore database', - 'ACL_A_SEARCH' => 'Can manage search backends and settings', -)); diff --git a/install/update/old/language/en/acp/posting.php b/install/update/old/language/en/acp/posting.php deleted file mode 100644 index 119ad2d..0000000 --- a/install/update/old/language/en/acp/posting.php +++ /dev/null @@ -1,291 +0,0 @@ - -* @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(); -} - -// 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 - -// BBCodes -// Note to translators: you can translate everything but what's between { and } -$lang = array_merge($lang, array( - 'ACP_BBCODES_EXPLAIN' => 'BBCode is a special implementation of HTML offering greater control over what and how something is displayed. From this page you can add, remove and edit custom BBCodes.', - 'ADD_BBCODE' => 'Add a new BBCode', - - 'BBCODE_DANGER' => 'The BBCode you are trying to add seems to use a {TEXT} token inside a HTML attribute. This is a possible XSS security issue. Try using the more restrictive {SIMPLETEXT} or {INTTEXT} types instead. Only proceed if you understand the risks involved and you consider the use of {TEXT} absolutely unavoidable.', - 'BBCODE_DANGER_PROCEED' => 'Proceed', //'I understand the risk', - - 'BBCODE_ADDED' => 'BBCode added successfully.', - 'BBCODE_EDITED' => 'BBCode edited successfully.', - 'BBCODE_DELETED' => 'The BBCode has been removed successfully.', - 'BBCODE_NOT_EXIST' => 'The BBCode you selected does not exist.', - 'BBCODE_HELPLINE' => 'Help line', - 'BBCODE_HELPLINE_EXPLAIN' => 'This field contains the mouse over text of the BBCode.', - 'BBCODE_HELPLINE_TEXT' => 'Help line text', - 'BBCODE_HELPLINE_TOO_LONG' => 'The help line you entered is too long.', - - '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.', - 'BBCODE_USAGE' => 'BBCode usage', - 'BBCODE_USAGE_EXAMPLE' => '[highlight={COLOR}]{TEXT}[/highlight]

[font={SIMPLETEXT1}]{SIMPLETEXT2}[/font]', - 'BBCODE_USAGE_EXPLAIN' => 'Here you define how to use the BBCode. Replace any variable input by the corresponding token (%ssee below%s).', - - 'EXAMPLE' => 'Example:', - 'EXAMPLES' => 'Examples:', - - 'HTML_REPLACEMENT' => 'HTML replacement', - 'HTML_REPLACEMENT_EXAMPLE' => '<span style="background-color: {COLOR};">{TEXT}</span>

<span style="font-family: {SIMPLETEXT1};">{SIMPLETEXT2}</span>', - 'HTML_REPLACEMENT_EXPLAIN' => 'Here you define the default HTML replacement. Do not forget to put back tokens you used above!', - - 'TOKEN' => 'Token', - 'TOKENS' => 'Tokens', - 'TOKENS_EXPLAIN' => 'Tokens are placeholders for user input. The input will be validated only if it matches the corresponding definition. If needed, you can number them by adding a number as the last character between the braces, e.g. {TEXT1}, {TEXT2}.

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

Please note that only tokens listed below are able to be used within custom BBCodes.', - 'TOKEN_DEFINITION' => 'What can it be?', - '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.', - '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.', - '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 #FF1234 or a CSS colour keyword such as fuchsia or InactiveBorder', - ), -)); - -// Smilies and topic icons -$lang = array_merge($lang, array( - 'ACP_ICONS_EXPLAIN' => 'From this page you can add, remove and edit the icons users may add to their topics or posts. These icons are generally displayed next to topic titles on the forum listing, or the post subjects in topic listings. You can also install and create new packages of icons.', - 'ACP_SMILIES_EXPLAIN' => 'Smilies or emoticons are typically small, sometimes animated images used to convey an emotion or feeling. From this page you can add, remove and edit the emoticons users can use in their posts and private messages. You can also install and create new packages of smilies.', - 'ADD_SMILIES' => 'Add multiple smilies', - 'ADD_SMILEY_CODE' => 'Add additional smiley code', - 'ADD_ICONS' => 'Add multiple icons', - 'AFTER_ICONS' => 'After %s', - 'AFTER_SMILIES' => 'After %s', - - 'CODE' => 'Code', - 'CURRENT_ICONS' => 'Current icons', - 'CURRENT_ICONS_EXPLAIN' => 'Choose what to do with the currently installed icons.', - 'CURRENT_SMILIES' => 'Current smilies', - 'CURRENT_SMILIES_EXPLAIN' => 'Choose what to do with the currently installed smilies.', - - 'DISPLAY_ON_POSTING' => 'Display on posting page', - 'DISPLAY_POSTING' => 'On posting page', - 'DISPLAY_POSTING_NO' => 'Not on posting page', - - 'EDIT_ICONS' => 'Edit icons', - 'EDIT_SMILIES' => 'Edit smilies', - 'EMOTION' => 'Emotion', - 'EXPORT_ICONS' => 'Export and download icons.pak', - 'EXPORT_ICONS_EXPLAIN' => '%sOn clicking this link, the configuration for your installed icons will be packaged into icons.pak which once downloaded can be used to create a .zip or .tgz file containing all of your icons plus this icons.pak configuration file%s.', - 'EXPORT_SMILIES' => 'Export and download smilies.pak', - 'EXPORT_SMILIES_EXPLAIN' => '%sOn clicking this link, the configuration for your installed smilies will be packaged into smilies.pak which once downloaded can be used to create a .zip or .tgz file containing all of your smilies plus this smilies.pak configuration file%s.', - - 'FIRST' => 'First', - - 'ICONS_ADD' => 'Add a new icon', - 'ICONS_ADDED' => array( - 0 => 'No icons were added.', - 1 => 'The icon has been added successfully.', - 2 => 'The icons have been added successfully.', - ), - 'ICONS_CONFIG' => 'Icon configuration', - 'ICONS_DELETED' => 'The icon has been removed successfully.', - 'ICONS_EDIT' => 'Edit icon', - 'ICONS_EDITED' => array( - 0 => 'No icons were updated.', - 1 => 'The icon has been updated successfully.', - 2 => 'The icons have been updated successfully.', - ), - 'ICONS_HEIGHT' => 'Icon height', - 'ICONS_IMAGE' => 'Icon image', - 'ICONS_IMPORTED' => 'The icons pack has been installed successfully.', - 'ICONS_IMPORT_SUCCESS' => 'The icons pack was imported successfully.', - 'ICONS_LOCATION' => 'Icon location', - 'ICONS_NOT_DISPLAYED' => 'The following icons are not displayed on the posting page', - 'ICONS_ORDER' => 'Icon order', - 'ICONS_URL' => 'Icon image file', - 'ICONS_WIDTH' => 'Icon width', - 'IMPORT_ICONS' => 'Install icons package', - 'IMPORT_SMILIES' => 'Install smilies package', - - 'KEEP_ALL' => 'Keep all', - - 'MASS_ADD_SMILIES' => 'Add multiple smilies', - - 'NO_ICONS_ADD' => 'There are no icons available for adding.', - 'NO_ICONS_EDIT' => 'There are no icons available for modifying.', - 'NO_ICONS_EXPORT' => 'You have no icons with which to create a package.', - 'NO_ICONS_PAK' => 'No icon packages found.', - 'NO_SMILIES_ADD' => 'There are no smilies available for adding.', - 'NO_SMILIES_EDIT' => 'There are no smilies available for modifying.', - 'NO_SMILIES_EXPORT' => 'You have no smilies with which to create a package.', - 'NO_SMILIES_PAK' => 'No smiley packages found.', - - 'PAK_FILE_NOT_READABLE' => 'Could not read .pak file.', - - 'REPLACE_MATCHES' => 'Replace matches', - - 'SELECT_PACKAGE' => 'Select a package file', - 'SMILIES_ADD' => 'Add a new smiley', - 'SMILIES_ADDED' => array( - 0 => 'No smilies were added.', - 1 => 'The smiley has been added successfully.', - 2 => 'The smilies have been added successfully.', - ), - 'SMILIES_CODE' => 'Smiley code', - 'SMILIES_CONFIG' => 'Smiley configuration', - 'SMILIES_DELETED' => 'The smiley has been removed successfully.', - 'SMILIES_EDIT' => 'Edit smiley', - 'SMILIE_NO_CODE' => 'The smiley “%s” was ignored, as there was no code entered.', - 'SMILIE_NO_EMOTION' => 'The smiley “%s” was ignored, as there was no emotion entered.', - 'SMILIE_NO_FILE' => 'The smiley “%s” was ignored, as the file is missing.', - 'SMILIES_EDITED' => array( - 0 => 'No smilies were updated.', - 1 => 'The smiley has been updated successfully.', - 2 => 'The smilies have been updated successfully.', - ), - 'SMILIES_EMOTION' => 'Emotion', - 'SMILIES_HEIGHT' => 'Smiley height', - 'SMILIES_IMAGE' => 'Smiley image', - 'SMILIES_IMPORTED' => 'The smilies pack has been installed successfully.', - 'SMILIES_IMPORT_SUCCESS' => 'The smilies pack was imported successfully.', - 'SMILIES_LOCATION' => 'Smiley location', - 'SMILIES_NOT_DISPLAYED' => 'The following smilies are not displayed on the posting page', - 'SMILIES_ORDER' => 'Smiley order', - 'SMILIES_URL' => 'Smiley image file', - 'SMILIES_WIDTH' => 'Smiley width', - - 'TOO_MANY_SMILIES' => array( - 1 => 'Limit of %d smiley reached.', - 2 => 'Limit of %d smilies reached.', - ), - - 'WRONG_PAK_TYPE' => 'The specified package does not contain the appropriate data.', -)); - -// Word censors -$lang = array_merge($lang, array( - 'ACP_WORDS_EXPLAIN' => 'From this control panel you can add, edit, and remove words that will be automatically censored on your forums. People are still allowed to register with usernames containing these words. Wildcards (*) are accepted in the word field, e.g. *test* will match detestable, test* would match testing, *test would match detest.', - 'ADD_WORD' => 'Add new word', - - 'EDIT_WORD' => 'Edit word censor', - 'ENTER_WORD' => 'You must enter a word and its replacement.', - - 'NO_WORD' => 'No word selected for editing.', - - 'REPLACEMENT' => 'Replacement', - - 'UPDATE_WORD' => 'Update word censor', - - 'WORD' => 'Word', - 'WORD_ADDED' => 'The word censor has been successfully added.', - 'WORD_REMOVED' => 'The selected word censor has been successfully removed.', - 'WORD_UPDATED' => 'The selected word censor has been successfully updated.', -)); - -// Ranks -$lang = array_merge($lang, array( - 'ACP_RANKS_EXPLAIN' => 'Using this form you can add, edit, view and delete ranks. You can also create special ranks which can be applied to a user via the user management facility.', - 'ADD_RANK' => 'Add new rank', - - 'MUST_SELECT_RANK' => 'You must select a rank.', - - 'NO_ASSIGNED_RANK' => 'No special rank assigned.', - 'NO_RANK_TITLE' => 'You haven’t specified a title for the rank.', - 'NO_UPDATE_RANKS' => 'The rank was successfully deleted. However user accounts using this rank were not updated. You will need to manually reset the rank on these accounts.', - - 'RANK_ADDED' => 'The rank was successfully added.', - 'RANK_IMAGE' => 'Rank image', - 'RANK_IMAGE_EXPLAIN' => 'Use this to define a small image associated with the rank. The path is relative to the root phpBB directory.', - 'RANK_IMAGE_IN_USE' => '(In use)', - 'RANK_MINIMUM' => 'Minimum posts', - 'RANK_REMOVED' => 'The rank was successfully deleted.', - 'RANK_SPECIAL' => 'Set as special rank', - 'RANK_TITLE' => 'Rank title', - 'RANK_UPDATED' => 'The rank was successfully updated.', -)); - -// Disallow Usernames -$lang = array_merge($lang, array( - 'ACP_DISALLOW_EXPLAIN' => 'Here you can control usernames which will not be allowed to be used. Disallowed usernames are allowed to contain a wildcard character of *.', - 'ADD_DISALLOW_EXPLAIN' => 'You can disallow a username using the wildcard character * to match any character.', - 'ADD_DISALLOW_TITLE' => 'Add a disallowed username', - - 'DELETE_DISALLOW_EXPLAIN' => 'You can remove a disallowed username by selecting the username from this list and clicking submit.', - 'DELETE_DISALLOW_TITLE' => 'Remove a disallowed username', - 'DISALLOWED_ALREADY' => 'The name you entered is already disallowed.', - 'DISALLOWED_DELETED' => 'The disallowed username has been successfully removed.', - 'DISALLOW_SUCCESSFUL' => 'The disallowed username has been successfully added.', - - 'NO_DISALLOWED' => 'No disallowed usernames', - 'NO_USERNAME_SPECIFIED' => 'You haven’t selected or entered a username to operate with.', -)); - -// Reasons -$lang = array_merge($lang, array( - 'ACP_REASONS_EXPLAIN' => 'Here you can manage the reasons used in reports and denial messages when disapproving posts. There is one default reason (marked with a *) you are not able to remove, this reason is normally used for custom messages if no reason fits.', - 'ADD_NEW_REASON' => 'Add new reason', - 'AVAILABLE_TITLES' => 'Available localised reason titles', - - 'IS_NOT_TRANSLATED' => 'Reason has not been localised.', - 'IS_NOT_TRANSLATED_EXPLAIN' => 'Reason has not been localised. If you want to provide the localised form, specify the correct key from the language files report reasons section.', - 'IS_TRANSLATED' => 'Reason has been localised.', - 'IS_TRANSLATED_EXPLAIN' => 'Reason has been localised. If the title you enter here is specified within the language files report reasons section, the localised form of the title and description will be used.', - - 'NO_REASON' => 'Reason could not be found.', - 'NO_REASON_INFO' => 'You have to specify a title and a description for this reason.', - 'NO_REMOVE_DEFAULT_REASON' => 'You are not able to remove the default reason “Other”.', - - 'REASON_ADD' => 'Add report/denial reason', - 'REASON_ADDED' => 'Report/denial reason successfully added.', - 'REASON_ALREADY_EXIST' => 'A reason with this title already exist, please enter another title for this reason.', - 'REASON_DESCRIPTION' => 'Reason description', - 'REASON_DESC_TRANSLATED' => 'Displayed reason description', - 'REASON_EDIT' => 'Edit report/denial reason', - 'REASON_EDIT_EXPLAIN' => 'Here you are able to add or edit a reason. If the reason is translated the localised version is used instead of the description entered here.', - 'REASON_REMOVED' => 'Report/denial reason successfully removed.', - 'REASON_TITLE' => 'Reason title', - 'REASON_TITLE_TRANSLATED' => 'Displayed reason title', - 'REASON_UPDATED' => 'Report/denial reason successfully updated.', - - 'USED_IN_REPORTS' => 'Used in reports', -)); diff --git a/install/update/old/language/en/acp/profile.php b/install/update/old/language/en/acp/profile.php deleted file mode 100644 index 41cbd9c..0000000 --- a/install/update/old/language/en/acp/profile.php +++ /dev/null @@ -1,176 +0,0 @@ - -* @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(); -} - -// 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 - -// Custom profile fields -$lang = array_merge($lang, array( - 'ADDED_PROFILE_FIELD' => 'Successfully added custom profile field.', - 'ALPHA_DOTS' => 'Alphanumeric and dots (periods)', - 'ALPHA_ONLY' => 'Alphanumeric only', - 'ALPHA_SPACERS' => 'Alphanumeric and spacers', - 'ALPHA_UNDERSCORE' => 'Alphanumeric and underscores', - 'ALPHA_PUNCTUATION' => 'Alphanumeric with comma, dots, underscore and dashes beginning with a letter', - 'ALWAYS_TODAY' => 'Always the current date', - - 'BOOL_ENTRIES_EXPLAIN' => 'Enter your options now', - 'BOOL_TYPE_EXPLAIN' => 'Define the type, either a checkbox or radio buttons. A checkbox will only be displayed if it is checked for a given user. In that case the second language option will be used. Radio buttons will display regardless of their value.', - - 'CHANGED_PROFILE_FIELD' => 'Successfully changed profile field.', - 'CHARS_ANY' => 'Any character', - 'CHECKBOX' => 'Checkbox', - 'COLUMNS' => 'Columns', - 'CP_LANG_DEFAULT_VALUE' => 'Default value', - 'CP_LANG_EXPLAIN' => 'Field description', - 'CP_LANG_EXPLAIN_EXPLAIN' => 'The explanation for this field presented to the user.', - 'CP_LANG_NAME' => 'Field name/title presented to the user', - 'CP_LANG_OPTIONS' => 'Options', - 'CREATE_NEW_FIELD' => 'Create new field', - 'CUSTOM_FIELDS_NOT_TRANSLATED' => 'At least one custom profile field has not yet been translated. Please enter the required information by clicking on the “Translate” link.', - - 'DEFAULT_ISO_LANGUAGE' => 'Default language [%s]', - 'DEFAULT_LANGUAGE_NOT_FILLED' => 'The language entries for the default language are not filled for this profile field.', - 'DEFAULT_VALUE' => 'Default value', - 'DELETE_PROFILE_FIELD' => 'Remove profile field', - 'DELETE_PROFILE_FIELD_CONFIRM' => 'Are you sure you want to delete this profile field?', - 'DISPLAY_AT_PROFILE' => 'Display in user control panel', - 'DISPLAY_AT_PROFILE_EXPLAIN' => 'The user is able to change this profile field within the user control panel.', - 'DISPLAY_AT_REGISTER' => 'Display on registration screen', - 'DISPLAY_AT_REGISTER_EXPLAIN' => 'If this option is enabled, the field will be displayed on registration.', - 'DISPLAY_ON_MEMBERLIST' => 'Display on memberlist screen', - 'DISPLAY_ON_MEMBERLIST_EXPLAIN' => 'If this option is enabled, the field will be displayed in the user rows on the memberlist screen.', - 'DISPLAY_ON_PM' => 'Display on view private message screen', - 'DISPLAY_ON_PM_EXPLAIN' => 'If this option is enabled, the field will be displayed in the mini-profile on the private message screen.', - 'DISPLAY_ON_VT' => 'Display on viewtopic screen', - 'DISPLAY_ON_VT_EXPLAIN' => 'If this option is enabled, the field will be displayed in the mini-profile on the topic screen.', - 'DISPLAY_PROFILE_FIELD' => 'Publicly display profile field', - 'DISPLAY_PROFILE_FIELD_EXPLAIN' => 'The profile field will be shown in all locations allowed within the load settings. Setting this to “no” will hide the field from topic pages, profiles and the memberlist.', - 'DROPDOWN_ENTRIES_EXPLAIN' => 'Enter your options now, every option in one line.', - - 'EDIT_DROPDOWN_LANG_EXPLAIN' => 'Please note that you are able to change your options text and also able to add new options to the end. It is not advised to add new options between existing options - this could result in wrong options assigned to your users. This can also happen if you remove options in-between. Removing options from the end result in users having assigned this item now reverting back to the default one.', - 'EMPTY_FIELD_IDENT' => 'Empty field identification', - 'EMPTY_USER_FIELD_NAME' => 'Please enter a field name/title', - 'ENTRIES' => 'Entries', - 'EVERYTHING_OK' => 'Everything OK', - - 'FIELD_BOOL' => 'Boolean (Yes/No)', - 'FIELD_CONTACT_DESC' => 'Contact description', - 'FIELD_CONTACT_URL' => 'Contact link', - 'FIELD_DATE' => 'Date', - 'FIELD_DESCRIPTION' => 'Field description', - 'FIELD_DESCRIPTION_EXPLAIN' => 'The explanation for this field presented to the user.', - 'FIELD_DROPDOWN' => 'Dropdown box', - 'FIELD_GOOGLEPLUS' => 'Google+', - 'FIELD_IDENT' => 'Field identification', - 'FIELD_IDENT_ALREADY_EXIST' => 'The chosen field identification already exist. Please choose another name.', - 'FIELD_IDENT_EXPLAIN' => 'The field identification is a name to identify the profile field within the database and the templates.', - 'FIELD_INT' => 'Numbers', - 'FIELD_IS_CONTACT' => 'Display field as a contact field', - 'FIELD_IS_CONTACT_EXPLAIN' => 'Contact fields are displayed within the contact section of the user profile and are displayed differently in the mini profile next to posts and private messages. You can use %s as a placeholder variable which will be replaced by a value provided by the user.', - 'FIELD_LENGTH' => 'Length of input box', - 'FIELD_NOT_FOUND' => 'Profile field not found.', - 'FIELD_STRING' => 'Single text field', - 'FIELD_TEXT' => 'Textarea', - 'FIELD_TYPE' => 'Field type', - 'FIELD_TYPE_EXPLAIN' => 'You are not able to change the field type later.', - 'FIELD_URL' => 'URL (Link)', - 'FIELD_VALIDATION' => 'Field validation', - '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.', - - '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', - 'ISO_LANGUAGE' => 'Language [%s]', - - 'LANG_SPECIFIC_OPTIONS' => 'Language specific options [%s]', - - 'LETTER_NUM_DOTS' => 'Any letters, numbers and dots (periods)', - 'LETTER_NUM_ONLY' => 'Any letters and numbers', - 'LETTER_NUM_PUNCTUATION' => 'Any letters, numbers, comma, dots, underscores and dashes beginning with any letter', - 'LETTER_NUM_SPACERS' => 'Any letters, numbers and spacers', - 'LETTER_NUM_UNDERSCORE' => 'Any letters, numbers and underscores', - - 'MAX_FIELD_CHARS' => 'Maximum number of characters', - 'MAX_FIELD_NUMBER' => 'Highest allowed number', - 'MIN_FIELD_CHARS' => 'Minimum number of characters', - 'MIN_FIELD_NUMBER' => 'Lowest allowed number', - - 'NO_FIELD_ENTRIES' => 'No entries defined', - 'NO_FIELD_ID' => 'No field id specified.', - 'NO_FIELD_TYPE' => 'No Field type specified.', - 'NO_VALUE_OPTION' => 'Option equal to non entered value', - 'NO_VALUE_OPTION_EXPLAIN' => 'Value for a non-entry. If the field is required, the user gets an error if he choose the option selected here.', - 'NUMBERS_ONLY' => 'Only numbers (0-9)', - - 'PROFILE_BASIC_OPTIONS' => 'Basic options', - 'PROFILE_FIELD_ACTIVATED' => 'Profile field successfully activated.', - 'PROFILE_FIELD_DEACTIVATED' => 'Profile field successfully deactivated.', - 'PROFILE_LANG_OPTIONS' => 'Language specific options', - 'PROFILE_TYPE_OPTIONS' => 'Profile type specific options', - - 'RADIO_BUTTONS' => 'Radio buttons', - 'REMOVED_PROFILE_FIELD' => 'Successfully removed profile field.', - 'REQUIRED_FIELD' => 'Required field', - 'REQUIRED_FIELD_EXPLAIN' => 'Force profile field to be filled out or specified by user or administrator. If display at registration screen option is disabled, the field will only be required when the user edits their profile.', - 'ROWS' => 'Rows', - - 'SAVE' => 'Save', - 'SECOND_OPTION' => 'Second option', - 'SHOW_NOVALUE_FIELD' => 'Show field if no value was selected', - 'SHOW_NOVALUE_FIELD_EXPLAIN' => 'Determines if the profile field should be displayed if no value was selected for optional fields or if no value has been selected yet for required fields.', - 'STEP_1_EXPLAIN_CREATE' => 'Here you can enter the first basic parameters of your new profile field. This information is needed for the second step where you’ll be able to set remaining options and tweak your profile field further.', - 'STEP_1_EXPLAIN_EDIT' => 'Here you can change the basic parameters of your profile field. The relevant options are re-calculated within the second step.', - 'STEP_1_TITLE_CREATE' => 'Add profile field', - 'STEP_1_TITLE_EDIT' => 'Edit profile field', - 'STEP_2_EXPLAIN_CREATE' => 'Here you are able to define some common options you may want to adjust.', - 'STEP_2_EXPLAIN_EDIT' => 'Here you are able to change some common options.
Please note that changes to profile fields will not affect existing profile fields entered by your users.', - '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. 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.', - - 'TEXT_DEFAULT_VALUE_EXPLAIN' => 'Enter a default text to be displayed, a default value. Leave empty if you want to show it empty at the first place.', - 'TRANSLATE' => 'Translate', - - 'USER_FIELD_NAME' => 'Field name/title presented to the user', - - 'VISIBILITY_OPTION' => 'Visibility options', -)); diff --git a/install/update/old/language/en/acp/styles.php b/install/update/old/language/en/acp/styles.php deleted file mode 100644 index ab85d9d..0000000 --- a/install/update/old/language/en/acp/styles.php +++ /dev/null @@ -1,90 +0,0 @@ - -* @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(); -} - -// 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 - -$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.', - - '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', - - 'INHERITING_FROM' => 'Inherits from', - 'INSTALL_STYLE' => 'Install style', - 'INSTALL_STYLES' => 'Install styles', - 'INSTALL_STYLES_EXPLAIN' => 'Here you can install new styles.
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.', - - 'PURGED_CACHE' => 'Cache was purged.', - - '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_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_PHPBB_VERSION' => 'phpBB Version', - 'STYLE_USED_BY' => 'Used by (including robots)', - 'STYLE_VERSION' => 'Style version', - - 'UNINSTALL_DEFAULT' => 'You cannot uninstall the default style.', - - 'BROWSE_STYLES_DATABASE' => 'Browse styles database', -)); diff --git a/install/update/old/language/en/captcha_recaptcha.php b/install/update/old/language/en/captcha_recaptcha.php deleted file mode 100644 index dde2a4b..0000000 --- a/install/update/old/language/en/captcha_recaptcha.php +++ /dev/null @@ -1,52 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - '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 www.google.com/recaptcha.', - 'CAPTCHA_RECAPTCHA' => 'reCaptcha', - '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 www.google.com/recaptcha.', - 'RECAPTCHA_PRIVATE' => 'Private reCaptcha key', - 'RECAPTCHA_PRIVATE_EXPLAIN' => 'Your private reCaptcha key. Keys can be obtained on www.google.com/recaptcha.', - - 'RECAPTCHA_EXPLAIN' => 'In an effort to prevent automatic submissions, we require that you complete the following challenge.', -)); diff --git a/install/update/old/language/en/cli.php b/install/update/old/language/en/cli.php deleted file mode 100644 index 505d12e..0000000 --- a/install/update/old/language/en/cli.php +++ /dev/null @@ -1,178 +0,0 @@ - -* @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; -} - -/** -* DO NOT CHANGE -*/ -if (empty($lang) || !is_array($lang)) -{ - $lang = array(); -} - -// DEVELOPERS PLEASE NOTE -// -// 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 - -$lang = array_merge($lang, array( - 'CLI_CONFIG_CANNOT_CACHED' => 'Set this option if the configuration option changes too frequently to be efficiently cached.', - 'CLI_CONFIG_CURRENT' => 'Current configuration value, use 0 and 1 to specify boolean values', - 'CLI_CONFIG_DELETE_SUCCESS' => 'Successfully deleted config %s.', - 'CLI_CONFIG_NEW' => 'New configuration value, use 0 and 1 to specify boolean values', - 'CLI_CONFIG_NOT_EXISTS' => 'Config %s does not exist', - 'CLI_CONFIG_OPTION_NAME' => 'The configuration option’s name', - 'CLI_CONFIG_PRINT_WITHOUT_NEWLINE' => 'Set this option if the value should be printed without a new line at the end.', - 'CLI_CONFIG_INCREMENT_BY' => 'Amount to increment by', - 'CLI_CONFIG_INCREMENT_SUCCESS' => 'Successfully incremented config %s', - 'CLI_CONFIG_SET_FAILURE' => 'Could not set config %s', - 'CLI_CONFIG_SET_SUCCESS' => 'Successfully set config %s', - - '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.', - 'CLI_DESCRIPTION_FIND_MIGRATIONS' => 'Finds migrations that are not depended upon.', - 'CLI_DESCRIPTION_FIX_LEFT_RIGHT_IDS' => 'Repairs the tree structure of the forums and modules.', - '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_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_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 --deactivate option. -To optionally send an activation email to the user, use the --send-email option.', - 'CLI_HELP_USER_ADD' => 'The %command.name% 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 --send-email 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/install/update/old/language/en/common.php b/install/update/old/language/en/common.php deleted file mode 100644 index 8350307..0000000 --- a/install/update/old/language/en/common.php +++ /dev/null @@ -1,1438 +0,0 @@ - -* @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(); -} - -// 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 -// -// Some characters you may want to copy&paste: -// ’ » “ ” … -// - -$lang = array_merge($lang, array( - 'TRANSLATION_INFO' => '', - 'DIRECTION' => 'ltr', - 'DATE_FORMAT' => '|d M Y|', // 01 Jan 2007 (with Relative days enabled) - 'DATETIME_FORMAT' => '|d M Y, H:i|', // 01 Jan 2007, 13:37 (with Relative days enabled) - 'USER_LANG' => 'en-gb', - - // You can define different rules for the determination of plural forms here. - // See https://area51.phpbb.com/docs/dev/32x/language/plurals.html for more information - // or ask the translation manager for help. - 'PLURAL_RULE' => 1, - - '1_DAY' => '1 day', - '1_MONTH' => '1 month', - '1_YEAR' => '1 year', - '2_WEEKS' => '2 weeks', - '3_MONTHS' => '3 months', - '6_MONTHS' => '6 months', - '7_DAYS' => '7 days', - - '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.', - 'ACP' => 'Administration Control Panel', - 'ACP_SHORT' => 'ACP', - 'ACTIVE' => 'active', - 'ACTIVE_ERROR' => 'The specified username is currently inactive. If you have problems activating your account, please contact a board administrator.', - 'ADMINISTRATOR' => 'Administrator', - 'ADMINISTRATORS' => 'Administrators', - 'AGE' => 'Age', - 'AIM' => 'AIM', - 'AJAX_ERROR_TITLE' => 'AJAX error', - 'AJAX_ERROR_TEXT' => 'Something went wrong when processing your request.', - 'AJAX_ERROR_TEXT_ABORT' => 'User aborted request.', - 'AJAX_ERROR_TEXT_TIMEOUT' => 'Your request timed out; please try again.', - 'AJAX_ERROR_TEXT_PARSERERROR' => 'Something went wrong with the request and the server returned an invalid reply.', - 'ALLOWED' => 'Allowed', - 'ALL_FILES' => 'All files', - 'ALL_FORUMS' => 'All forums', - 'ALL_MESSAGES' => 'All messages', - 'ALL_POSTS' => 'All posts', - 'ALL_TIMES' => 'All times are %1$s', - '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.', - 'ASCENDING' => 'Ascending', - 'ATTACHMENTS' => 'Attachments', - '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_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.', - 'AVATAR_DISALLOWED_EXTENSION' => 'This file cannot be displayed because the extension %s is not allowed.', - 'AVATAR_EMPTY_REMOTE_DATA' => 'The specified avatar could not be uploaded because the remote data appears to be invalid or corrupted.', - '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.
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.
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.', - 'AVATAR_WRONG_SIZE' => 'The submitted avatar is %5$s wide and %6$s high. Avatars must be at least %1$s wide and %2$s high, but no larger than %3$s wide and %4$s high.', - - 'BACK_TO_TOP' => 'Top', - 'BACK_TO_PREV' => 'Back to previous page', - 'BAN_TRIGGERED_BY_EMAIL'=> 'A ban has been issued on your email address.', - 'BAN_TRIGGERED_BY_IP' => 'A ban has been issued on your IP address.', - 'BAN_TRIGGERED_BY_USER' => 'A ban has been issued on your username.', - 'BBCODE_GUIDE' => 'BBCode guide', - 'BCC' => 'BCC', - 'BIRTHDAYS' => 'Birthdays', - 'BOARD_BAN_PERM' => 'You have been permanently banned from this board.

Please contact the %2$sBoard Administrator%3$s for more information.', - 'BOARD_BAN_REASON' => 'Reason given for ban: %s', - 'BOARD_BAN_TIME' => 'You have been banned from this board until %1$s.

Please contact the %2$sBoard Administrator%3$s for more information.', - 'BOARD_DISABLE' => 'Sorry but this board is currently unavailable.', - 'BOARD_DISABLED' => 'This board is currently disabled.', - 'BOARD_UNAVAILABLE' => 'Sorry but the board is temporarily unavailable, please try again in a few minutes.', - 'BROWSING_FORUM' => 'Users browsing this forum: %1$s', - 'BROWSING_FORUM_GUESTS' => 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', - 'BUTTON_PM_NEW' => 'New PM', - 'BUTTON_PM_REPLY' => 'Send Reply', - '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', - - 'CANCEL' => 'Cancel', - 'CHANGE' => 'Change', - 'CHANGE_FONT_SIZE' => 'Change font size', - 'CHANGING_PREFERENCES' => 'Changing board preferences', - 'CHANGING_PROFILE' => 'Changing profile settings', - 'CHARACTERS' => array( - 1 => '%d character', - 2 => '%d characters', - ), - 'COLLAPSE_VIEW' => 'Collapse view', - 'CLOSE_WINDOW' => 'Close window', - 'COLOUR_SWATCH' => 'Colour swatch', - 'COLON' => ':', - 'COMMA_SEPARATOR' => ', ', // Comma used to join lists into a single string, use localised comma if appropriate, eg: Ideographic or Arabic - 'CONFIRM' => 'Confirm', - 'CONFIRM_CODE' => 'Confirmation code', - 'CONFIRM_CODE_EXPLAIN' => 'Enter the code exactly as it appears. All letters are case insensitive.', - 'CONFIRM_CODE_WRONG' => 'The confirmation code you entered was incorrect.', - 'CONFIRM_OPERATION' => 'Are you sure you wish to carry out this operation?', - 'CONFIRM_AVATAR_DELETE' => 'Are you sure you wish to delete this avatar?', - 'CONGRATULATIONS' => 'Congratulations to', - 'CONNECTION_FAILED' => 'Connection failed.', - 'CONNECTION_SUCCESS' => 'Connection was successful!', - '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', - - 'DAY' => 'Day', - 'DAYS' => 'Days', - 'DELETE' => 'Delete', - 'DELETE_ALL' => 'Delete all', - 'DELETE_COOKIES' => 'Delete cookies', - 'DELETE_MARKED' => 'Delete marked', - 'DELETE_POST' => 'Delete post', - 'DELIMITER' => 'Delimiter', - 'DESCENDING' => 'Descending', - 'DISABLED' => 'Disabled', - 'DISPLAY' => 'Display', - 'DISPLAY_GUESTS' => 'Display guests', - 'DISPLAY_MESSAGES' => 'Display messages from previous', - 'DISPLAY_POSTS' => 'Display posts from previous', - 'DISPLAY_TOPICS' => 'Display topics from previous', - 'DOWNLOADED' => 'Downloaded', - 'DOWNLOADING_FILE' => 'Downloading file', - 'DOWNLOAD_COUNTS' => array( - 0 => 'Not downloaded yet', - 1 => 'Downloaded %d time', - 2 => 'Downloaded %d times', - ), - - 'EDIT_POST' => 'Edit post', - 'ELLIPSIS' => '…', - 'EMAIL' => 'Email', // Short form for EMAIL_ADDRESS - 'EMAIL_ADDRESS' => 'Email address', - 'EMAIL_INVALID_EMAIL' => 'The email address you entered is invalid.', - 'EMAIL_SMTP_ERROR_RESPONSE' => 'Ran into problems sending email at Line %1$s. Response: %2$s.', - 'EMPTY_SUBJECT' => 'You must specify a subject when posting a new topic.', - 'EMPTY_MESSAGE_SUBJECT' => 'You must specify a subject when composing a new message.', - 'ENABLED' => 'Enabled', - 'ENCLOSURE' => 'Enclosure', - 'ENTER_USERNAME' => 'Enter username', - 'ERR_CHANGING_DIRECTORY' => 'Unable to change directory.', - 'ERR_CONNECTING_SERVER' => 'Error connecting to the server.', - 'ERR_JAB_AUTH' => 'Could not authorise on Jabber server.', - 'ERR_JAB_CONNECT' => 'Could not connect to Jabber server.', - 'ERR_UNABLE_TO_LOGIN' => 'The specified username or password is incorrect.', - 'ERR_UNWATCHING' => 'An error occurred while trying to unsubscribe.', - 'ERR_WATCHING' => 'An error occurred while trying to subscribe.', - 'ERR_WRONG_PATH_TO_PHPBB' => 'The phpBB path specified appears to be invalid.', - 'ERROR' => 'Error', - 'EXPAND_VIEW' => 'Expand view', - 'EXTENSION' => 'Extension', - 'EXTENSION_DISABLED' => 'The extension %s is not enabled.', - 'EXTENSION_DISABLED_AFTER_POSTING' => 'The extension %s has been deactivated and can no longer be displayed.', - 'EXTENSION_DOES_NOT_EXIST' => 'The extension %s does not exist.', - - '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', - 'FILE_COMMENT' => 'File comment', - 'FILE_CONTENT_ERR' => 'Could not read the contents of file: %s', - 'FILE_JSON_DECODE_ERR' => 'Failed to decode json file: %s', - 'FILE_NOT_FOUND' => 'The requested file could not be found: %s', - 'FIND_USERNAME' => 'Find a member', - 'FOLDER' => 'Folder', - 'FORGOT_PASS' => 'I forgot my password', - 'FORM_INVALID' => 'The submitted form was invalid. Try submitting again.', - 'FORUM' => 'Forum', - 'FORUMS' => 'Forums', - 'FORUMS_MARKED' => 'Forums have been marked read.', - 'FORUM_CAT' => 'Forum category', - 'FORUM_INDEX' => 'Board index', - 'FORUM_LINK' => 'Forum link', - 'FORUM_LOCATION' => 'Forum location', - 'FORUM_LOCKED' => 'Forum locked', - 'FORUM_RULES' => 'Forum rules', - 'FORUM_RULES_LINK' => 'Please click here to view the forum rules', - 'FROM' => 'from', - 'FSOCK_DISABLED' => 'The operation could not be completed because the fsockopen function has been disabled or the server being queried could not be found.', - 'FSOCK_TIMEOUT' => 'A timeout occurred while reading from the network stream.', - - 'FTP_FSOCK_HOST' => 'FTP host', - 'FTP_FSOCK_HOST_EXPLAIN' => 'FTP server used to connect your site.', - 'FTP_FSOCK_PASSWORD' => 'FTP password', - 'FTP_FSOCK_PASSWORD_EXPLAIN' => 'Password for your FTP username.', - 'FTP_FSOCK_PORT' => 'FTP port', - 'FTP_FSOCK_PORT_EXPLAIN' => 'Port used to connect to your server.', - 'FTP_FSOCK_ROOT_PATH' => 'Path to phpBB', - 'FTP_FSOCK_ROOT_PATH_EXPLAIN' => 'Path from the root to your phpBB board.', - 'FTP_FSOCK_TIMEOUT' => 'FTP timeout', - 'FTP_FSOCK_TIMEOUT_EXPLAIN' => 'The amount of time, in seconds, that the system will wait for a reply from your server.', - 'FTP_FSOCK_USERNAME' => 'FTP username', - 'FTP_FSOCK_USERNAME_EXPLAIN' => 'Username used to connect to your server.', - - 'FTP_HOST' => 'FTP host', - 'FTP_HOST_EXPLAIN' => 'FTP server used to connect your site.', - 'FTP_PASSWORD' => 'FTP password', - 'FTP_PASSWORD_EXPLAIN' => 'Password for your FTP username.', - 'FTP_PORT' => 'FTP port', - 'FTP_PORT_EXPLAIN' => 'Port used to connect to your server.', - 'FTP_ROOT_PATH' => 'Path to phpBB', - 'FTP_ROOT_PATH_EXPLAIN' => 'Path from the root to your phpBB board.', - 'FTP_TIMEOUT' => 'FTP timeout', - 'FTP_TIMEOUT_EXPLAIN' => 'The amount of time, in seconds, that the system will wait for a reply from your server.', - 'FTP_USERNAME' => 'FTP username', - 'FTP_USERNAME_EXPLAIN' => 'Username used to connect to your server.', - - 'GENERAL_ERROR' => 'General Error', - 'GB' => 'GB', - 'GIB' => 'GiB', - 'GO' => 'Go', - 'GOOGLEPLUS' => 'Google+', - 'GOTO_FIRST_POST' => 'Go to first post', - 'GOTO_LAST_POST' => 'Go to last post', - 'GOTO_PAGE' => 'Go to page', - 'GROUP' => 'Group', - 'GROUPS' => 'Groups', - 'GROUP_ERR_TYPE' => 'Inappropriate group type specified.', - 'GROUP_ERR_USERNAME' => 'No group name specified.', - 'GROUP_ERR_USER_LONG' => 'Group names cannot exceed 60 characters. The specified group name is too long.', - 'GUEST' => 'Guest', - 'GUEST_USERS_ONLINE' => array( - 1 => 'There is %d guest user online', - 2 => 'There are %d guest users online', - ), - 'GUEST_USERS_TOTAL' => array( - 1 => '%d guest', - 2 => '%d guests', - ), - 'G_ADMINISTRATORS' => 'Administrators', - 'G_BOTS' => 'Bots', - 'G_GUESTS' => 'Guests', - 'G_REGISTERED' => 'Registered users', - 'G_REGISTERED_COPPA' => 'Registered COPPA users', - 'G_GLOBAL_MODERATORS' => 'Global moderators', - 'G_NEWLY_REGISTERED' => 'Newly registered users', - - 'HIDDEN_USERS_ONLINE' => array( - 1 => '%d hidden user', - 2 => '%d hidden users', - ), - 'HIDDEN_USERS_TOTAL' => array( - 1 => '%d hidden', - 2 => '%d hidden', - ), - 'HIDE_GUESTS' => 'Hide guests', - 'HIDE_ME' => 'Hide my online status this session', - 'HOURS' => 'Hours', - 'HOME' => 'Home', - - 'ICQ' => 'ICQ', - 'IF' => 'If', - 'IMAGE' => 'Image', - 'IMAGE_FILETYPE_INVALID' => 'Image file type %d for mimetype %s not supported.', - 'IMAGE_FILETYPE_MISMATCH' => 'Image file type mismatch: expected extension %1$s but extension %2$s given.', - 'IN' => 'in', - 'INACTIVE' => 'Inactive', - 'INDEX' => 'Index page', - 'INFORMATION' => 'Information', - 'INSECURE_REDIRECT' => 'Tried to redirect to potentially insecure url.', - 'INTERESTS' => 'Interests', - 'INVALID_DIGEST_CHALLENGE' => 'Invalid digest challenge.', - 'INVALID_EMAIL_LOG' => '%s possibly an invalid email address?', - 'INVALID_FEED_ATTACHMENTS' => 'The selected feed tried fetching attachments with invalid constraints.', - 'INVALID_PLURAL_RULE' => 'The chosen plural rule is invalid. Valid values are integers between 0 and 15.', - 'IP' => 'IP', - 'IP_BLACKLISTED' => 'Your IP %1$s has been blocked because it is blacklisted. For details please see %2$s.', - - 'JABBER' => 'Jabber', - 'JOINED' => 'Joined', - 'JUMP_PAGE' => 'Enter the page number you wish to go to', - 'JUMP_TO' => 'Jump to', - 'JUMP_TO_PAGE' => 'Jump to page', - 'JUMP_TO_PAGE_CLICK' => 'Click to jump to page…', - - 'KB' => 'KB', - 'KIB' => 'KiB', - - 'LAST_POST' => 'Last post', - 'LAST_UPDATED' => 'Last updated', - 'LAST_VISIT' => 'Last visit', - 'LDAP_NO_LDAP_EXTENSION' => 'LDAP extension not available.', - 'LDAP_NO_SERVER_CONNECTION' => 'Could not connect to LDAP server.', - 'LDAP_SEARCH_FAILED' => 'An error occurred while searching the LDAP directory.', - 'LEGEND' => 'Legend', - 'LIVE_SEARCHES_NOT_ALLOWED' => 'Live searches are not allowed.', - 'LOADING' => 'Loading', - 'LOCATION' => 'Location', - 'LOCK_POST' => 'Lock post', - 'LOCK_POST_EXPLAIN' => 'Prevent editing', - 'LOCK_TOPIC' => 'Lock topic', - 'LOGIN' => 'Login', - 'LOGIN_CHECK_PM' => 'Log in to check your private messages.', - 'LOGIN_CONFIRMATION' => 'Confirmation of login', - 'LOGIN_CONFIRM_EXPLAIN' => 'To prevent brute forcing accounts the board requires you to enter a confirmation code after a maximum amount of failed logins. The code is displayed in the image you should see below. If you are visually impaired or cannot otherwise read this code please contact the %sBoard Administrator%s.', // unused - 'LOGIN_ERROR_ATTEMPTS' => 'You exceeded the maximum allowed number of login attempts. In addition to your username and password you now also have to solve the CAPTCHA below.', - 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE' => 'You have not been authenticated by Apache.', - 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST' => 'A non-existant OAuth service has been requested.', - 'LOGIN_ERROR_PASSWORD' => 'You have specified an incorrect password. Please check your password and try again. If you continue to have problems please contact the %sBoard Administrator%s.', - 'LOGIN_ERROR_PASSWORD_CONVERT' => 'It was not possible to convert your password when updating this bulletin board’s software. Please %srequest a new password%s. If you continue to have problems please contact the %sBoard Administrator%s.', - 'LOGIN_ERROR_USERNAME' => 'You have specified an incorrect username. Please check your username and try again. If you continue to have problems please contact the %sBoard Administrator%s.', - 'LOGIN_FORUM' => 'To view or post in this forum you must enter its password.', - 'LOGIN_INFO' => 'In order to login you must be registered. Registering takes only a few moments but gives you increased capabilities. The board administrator may also grant additional permissions to registered users. Before you register please ensure you are familiar with our terms of use and related policies. Please ensure you read any forum rules as you navigate around the board.', - 'LOGIN_VIEWFORUM' => 'The board requires you to be registered and logged in to view this forum.', - 'LOGIN_EXPLAIN_EDIT' => 'In order to edit posts in this forum you have to be registered and logged in.', - 'LOGIN_EXPLAIN_VIEWONLINE' => 'In order to view the online list you have to be registered and logged in.', - 'LOGIN_REQUIRED' => 'You need to login to perform this action.', - 'LOGOUT' => 'Logout', - 'LOGOUT_USER' => 'Logout [ %s ]', - 'LOG_ME_IN' => 'Remember me', - - 'MAIN' => 'Main', - 'MARK' => 'Mark', - 'MARK_ALL' => 'Mark all', - 'MARK_ALL_READ' => 'Mark all read', - 'MARK_FORUMS_READ' => 'Mark forums read', - 'MARK_READ' => 'Mark read', - 'MARK_SUBFORUMS_READ' => 'Mark subforums read', - 'MB' => 'MB', - 'MIB' => 'MiB', - 'MCP' => 'Moderator Control Panel', - 'MCP_SHORT' => 'MCP', - 'MEMBERLIST' => 'Members', - 'MEMBERLIST_EXPLAIN' => 'View complete list of members', - 'MERGE' => 'Merge', - 'MERGE_POSTS' => 'Move posts', - 'MERGE_TOPIC' => 'Merge topic', - 'MESSAGE' => 'Message', - 'MESSAGES' => 'Messages', - 'MESSAGES_COUNT' => array( - 1 => '%d message', - 2 => '%d messages', - ), - 'MESSAGE_BODY' => 'Message body', - 'MINUTES' => 'Minutes', - 'MODERATE' => 'Moderate', - 'MODERATOR' => 'Moderator', - 'MODERATORS' => 'Moderators', - 'MODULE_NOT_ACCESS' => 'Module not accessible', - 'MODULE_NOT_FIND' => 'Cannot find module %s', - 'MODULE_FILE_INCORRECT_CLASS' => 'Module file %s does not contain correct class [%s]', - 'MONTH' => 'Month', - 'MOVE' => 'Move', - - 'NA' => 'N/A', - 'NEWEST_USER' => 'Our newest member %s', - 'NEW_MESSAGE' => 'New message', - 'NEW_MESSAGES' => 'New messages', - 'NEW_POST' => 'New post', // Not used anymore - 'NEW_POSTS' => 'New posts', // Not used anymore - 'NEXT' => 'Next', // Used in pagination - 'NEXT_STEP' => 'Next', - 'NEVER' => 'Never', - 'NO' => 'No', - 'NO_NOTIFICATIONS' => 'You have no notifications', - 'NOT_ALLOWED_MANAGE_GROUP' => 'You are not allowed to manage this group.', - 'NOT_AUTHORISED' => 'You are not authorised to access this area.', - 'NOT_WATCHING_FORUM' => 'You are no longer subscribed to updates on this forum.', - 'NOT_WATCHING_TOPIC' => 'You are no longer subscribed to this topic.', - 'NOTIFICATIONS' => 'Notifications', - // This applies for NOTIFICATION_BOOKMARK and NOTIFICATION_POST. - // %1$s will return a list of users that's concatenated using "," and "and" - see STRING_LIST - // Once the user count reaches 5 users or more, the list is trimmed using NOTIFICATION_X_OTHERS - // Once the user count reaches 20 users or more, the list is trimmed using NOTIFICATION_MANY_OTHERS - // Examples: - // A replied... - // A and B replied... - // A, B and C replied... - // A, B, C and 2 others replied... - // A, B, C and others replied... - 'NOTIFICATION_BOOKMARK' => array( - 1 => 'Reply from %1$s in bookmarked topic:', - ), - 'NOTIFICATION_FORUM' => 'Forum: %1$s', - 'NOTIFICATION_GROUP_REQUEST' => 'Group request from %1$s to join the group %2$s.', - 'NOTIFICATION_GROUP_REQUEST_APPROVED' => 'Group request approved to join the group %1$s.', - 'NOTIFICATION_METHOD_INVALID' => 'The method "%s" does not refer to a valid notification method.', - 'NOTIFICATION_PM' => 'Private Message from %1$s:', - 'NOTIFICATION_POST' => array( - 1 => 'Reply from %1$s in topic:', - ), - 'NOTIFICATION_POST_APPROVED' => 'Post approved:', - 'NOTIFICATION_POST_DISAPPROVED' => 'Post disapproved:', - 'NOTIFICATION_POST_IN_QUEUE' => 'Post approval request by %1$s:', - 'NOTIFICATION_QUOTE' => array( - 1 => 'Quoted by %1$s in:', - ), - 'NOTIFICATION_REFERENCE' => '"%1$s"', - 'NOTIFICATION_REASON' => 'Reason: %1$s.', - 'NOTIFICATION_REPORT_PM' => 'Private Message reported by %1$s:', - 'NOTIFICATION_REPORT_POST' => 'Post reported by %1$s:', - 'NOTIFICATION_REPORT_CLOSED' => 'Report closed by %1$s for:', - 'NOTIFICATION_TOPIC' => 'New topic by %1$s:', - 'NOTIFICATION_TOPIC_APPROVED' => 'Topic approved:', - 'NOTIFICATION_TOPIC_DISAPPROVED' => 'Topic disapproved:', - 'NOTIFICATION_TOPIC_IN_QUEUE' => 'Topic approval request by %1$s:', - 'NOTIFICATION_TYPE_NOT_EXIST' => 'The notification type "%s" is missing from the file system.', - 'NOTIFICATION_ADMIN_ACTIVATE_USER' => 'Activation required for deactivated or newly registered user: “%1$s”', - // Used in conjuction with NOTIFICATION_BOOKMARK and NOTIFICATION_POST. - 'NOTIFICATION_MANY_OTHERS' => 'others', - 'NOTIFICATION_X_OTHERS' => array( - 2 => '%d others', - ), - 'NOTIFY_ADMIN' => 'Please notify the board administrator or webmaster.', - 'NOTIFY_ADMIN_EMAIL' => 'Please notify the board administrator or webmaster: %1$s', - 'NO_ACCESS_ATTACHMENT' => 'You are not allowed to access this file.', - 'NO_ACTION' => 'No action specified.', - 'NO_ADMINISTRATORS' => 'There are no administrators.', - 'NO_AUTH_ADMIN' => 'Access to the Administration Control Panel is not allowed as you do not have administrative permissions.', - 'NO_AUTH_ADMIN_USER_DIFFER' => 'You are not able to re-authenticate as a different user.', - 'NO_AUTH_OPERATION' => 'You do not have the necessary permissions to complete this operation.', - 'NO_AVATARS' => 'No avatars currently available', - 'NO_CONNECT_TO_SMTP_HOST' => 'Could not connect to smtp host : %1$s : %2$s', - 'NO_BIRTHDAYS' => 'No birthdays today', - 'NO_EMAIL_MESSAGE' => 'Email message was blank.', - 'NO_EMAIL_RESPONSE_CODE' => 'Could not get mail server response codes.', - 'NO_EMAIL_SUBJECT' => 'No email subject specified.', - 'NO_FORUM' => 'The forum you selected does not exist.', - 'NO_FORUMS' => 'This board has no forums.', - 'NO_GROUP' => 'The requested usergroup does not exist.', - 'NO_GROUP_MEMBERS' => 'This group currently has no members.', - 'NO_IPS_DEFINED' => 'No IP addresses or hostnames defined', - 'NO_MEMBERS' => 'No members found for this search criterion.', - 'NO_MESSAGES' => 'No messages', - 'NO_MODE' => 'No mode specified.', - 'NO_MODERATORS' => 'There are no moderators.', - 'NO_NEW_MESSAGES' => 'No new messages', - 'NO_NEW_POSTS' => 'No new posts', // Not used anymore - 'NO_ONLINE_USERS' => 'No registered users', - 'NO_POSTS' => 'No posts', - 'NO_POSTS_TIME_FRAME' => 'No posts exist inside this topic for the selected time frame.', - 'NO_FEED_ENABLED' => 'Feeds are not available on this board.', - 'NO_FEED' => 'The requested feed is not available.', - 'NO_STYLE_DATA' => 'Could not get style data', - '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.', - 'NO_TOPIC' => 'The requested topic does not exist.', - 'NO_TOPIC_FORUM' => 'The topic or forum no longer exists.', - 'NO_TOPICS' => 'There are no topics or posts in this forum.', - 'NO_TOPICS_TIME_FRAME' => 'No topics exist inside this forum for the selected time frame.', - 'NO_UNREAD_POSTS' => 'No unread posts', - 'NO_UPLOAD_FORM_FOUND' => 'Upload initiated but no valid file upload form found.', - 'NO_USER' => 'The requested user does not exist.', - 'NO_USERS' => 'The requested users do not exist.', - 'NO_USER_SPECIFIED' => 'No username was specified.', - - // Nullar/Singular/Plural language entry. The key numbers define the number range in which a certain grammatical expression is valid. - 'NUM_ATTACHMENTS' => array( - 1 => '%d attachment', - 2 => '%d attachments', - ), - 'NUM_POSTS_IN_QUEUE' => array( - 0 => 'No posts in queue', // 0 - 1 => '1 post in queue', // 1 - 2 => '%d posts in queue', // 2+ - ), - - 'OCCUPATION' => 'Occupation', - 'OFFLINE' => 'Offline', - 'ONLINE' => 'Online', - 'ONLINE_BUDDIES' => 'Online friends', - // "... :: x registered and y hidden" - 'ONLINE_USERS_TOTAL' => array( - 1 => 'In total there is %1$d user online :: %2$s and %3$s', - 2 => 'In total there are %1$d users online :: %2$s and %3$s', - ), - // "... :: x registered, y hidden and z guests" - 'ONLINE_USERS_TOTAL_GUESTS' => array( - 1 => 'In total there is %1$d user online :: %2$s, %3$s and %4$s', - 2 => 'In total there are %1$d users online :: %2$s, %3$s and %4$s', - ), - 'OPTIONS' => 'Options', - - 'PAGE_NOT_FOUND' => 'The requested page could not be found.', - 'PAGE_OF' => 'Page %1$d of %2$d', - 'PAGE_TITLE_NUMBER' => 'Page %s', - 'PASSWORD' => 'Password', - 'PIXEL' => 'px', - 'PIXELS' => array( - 1 => '%d pixel', - 2 => '%d pixels', - ), - 'PLEASE_WAIT' => 'Please wait.', - 'PM' => 'PM', - 'PM_REPORTED' => 'Click to view report', - 'POSTING_MESSAGE' => 'Posting message in %s', - 'POSTING_PRIVATE_MESSAGE' => 'Composing private message', - 'POST' => 'Post', - 'POST_ANNOUNCEMENT' => 'Announce', - 'POST_STICKY' => 'Sticky', - 'POSTED' => 'Posted', - 'POSTED_IN_FORUM' => 'in', - 'POSTED_ON_DATE' => 'on', - 'POSTS' => 'Posts', - 'POSTS_UNAPPROVED' => 'At least one post in this topic has not been approved.', - 'POSTS_UNAPPROVED_FORUM'=> 'At least one post in this forum has not been approved.', - 'POST_BY_AUTHOR' => 'by', - 'POST_BY_FOE' => '%1$s, who is currently on your ignore list, made this post.', - 'POST_DISPLAY' => '%1$sDisplay this post%2$s.', - 'POST_DAY' => '%.2f posts per day', - 'POST_DELETED_ACTION' => 'Deleted post:', - 'POST_DELETED' => 'This post has been deleted.', - 'POST_DELETED_BY' => '%2$s deleted the post by %1$s on %3$s.', - 'POST_DELETED_BY_REASON'=> '%2$s deleted the post by %1$s on %3$s for the following reason: %4$s', - 'POST_DETAILS' => 'Post details', - 'POST_NEW_TOPIC' => 'Post new topic', - 'POST_PCT' => '%.2f%% of all posts', - 'POST_PCT_ACTIVE' => '%.2f%% of user’s posts', - 'POST_PCT_ACTIVE_OWN' => '%.2f%% of your posts', - 'POST_REPLY' => 'Post a reply', - 'POST_REPORTED' => 'Click to view report', - 'POST_SUBJECT' => 'Post subject', - 'POST_TIME' => 'Post time', - 'POST_TOPIC' => 'Post a new topic', - 'POST_UNAPPROVED_ACTION' => 'Post awaiting approval:', - 'POST_UNAPPROVED' => 'This post has not been approved.', - 'POWERED_BY' => 'Powered by %s', - 'PREVIEW' => 'Preview', - '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', - 'PROFILE' => 'User Control Panel', - - 'QUICK_LINKS' => 'Quick links', - - 'RANK' => 'Rank', - 'READING_FORUM' => 'Viewing topics in %s', - 'READING_GLOBAL_ANNOUNCE' => 'Reading global announcement', - 'READING_LINK' => 'Following forum link %s', - 'READING_TOPIC' => 'Reading topic in %s', - 'READ_PROFILE' => 'Profile', - 'REASON' => 'Reason', - 'RECORD_ONLINE_USERS' => 'Most users ever online was %1$s on %2$s', - 'REDIRECT' => 'Redirect', - 'REDIRECTS' => 'Total redirects', - 'REGISTER' => 'Register', - 'REGISTERED_USERS' => 'Registered users:', - // "... and 2 hidden users online" - 'REG_USERS_ONLINE' => array( - 1 => 'There is %1$d registered user and %2$s online', - 2 => 'There are %1$d registered users and %2$s online', - ), - 'REG_USERS_TOTAL' => array( - 1 => '%d registered', - 2 => '%d registered', - ), - 'REMOVE' => 'Remove', - 'REMOVE_INSTALL' => 'Please delete, move or rename the install directory before you use your board. If this directory is still present, only the Administration Control Panel (ACP) will be accessible.', - 'REPLIES' => 'Replies', - 'REPLY_WITH_QUOTE' => 'Reply with quote', - 'REPLYING_GLOBAL_ANNOUNCE' => 'Replying to global announcement', - 'REPLYING_MESSAGE' => 'Replying to message in %s', - 'REPORT_BY' => 'Report by', - 'REPORT_POST' => 'Report this post', - 'REPORTING_POST' => 'Reporting post', - 'RESEND_ACTIVATION' => 'Resend activation email', - 'RESET' => 'Reset', - 'RESTORE_PERMISSIONS' => 'Restore permissions', - 'RETURN_INDEX' => '%sReturn to the index page%s', - 'RETURN_FORUM' => '%sReturn to the forum last visited%s', - 'RETURN_PAGE' => '%sReturn to the previous page%s', - 'RETURN_TOPIC' => '%sReturn to the topic last visited%s', - 'RETURN_TO' => 'Return to “%s”', - 'RETURN_TO_INDEX' => 'Return to Board Index', - 'FEED' => 'Feed', - 'FEED_NEWS' => 'News', - 'FEED_TOPICS_ACTIVE' => 'Active Topics', - 'FEED_TOPICS_NEW' => 'New Topics', - 'RULES_ATTACH_CAN' => 'You can post attachments in this forum', - 'RULES_ATTACH_CANNOT' => 'You cannot post attachments in this forum', - 'RULES_DELETE_CAN' => 'You can delete your posts in this forum', - 'RULES_DELETE_CANNOT' => 'You cannot delete your posts in this forum', - 'RULES_DOWNLOAD_CAN' => 'You can download attachments in this forum', - 'RULES_DOWNLOAD_CANNOT' => 'You cannot download attachments in this forum', - 'RULES_EDIT_CAN' => 'You can edit your posts in this forum', - 'RULES_EDIT_CANNOT' => 'You cannot edit your posts in this forum', - 'RULES_LOCK_CAN' => 'You can lock your topics in this forum', - 'RULES_LOCK_CANNOT' => 'You cannot lock your topics in this forum', - 'RULES_POST_CAN' => 'You can post new topics in this forum', - 'RULES_POST_CANNOT' => 'You cannot post new topics in this forum', - 'RULES_REPLY_CAN' => 'You can reply to topics in this forum', - 'RULES_REPLY_CANNOT' => 'You cannot reply to topics in this forum', - 'RULES_VOTE_CAN' => 'You can vote in polls in this forum', - 'RULES_VOTE_CANNOT' => 'You cannot vote in polls in this forum', - - 'SEARCH' => 'Search', - 'SEARCH_MINI' => 'Search…', - 'SEARCH_ADV' => 'Advanced search', - 'SEARCH_ADV_EXPLAIN' => 'View the advanced search options', - 'SEARCH_KEYWORDS' => 'Search for keywords', - 'SEARCHING_FORUMS' => 'Searching forums', - 'SEARCH_ACTIVE_TOPICS' => 'Active topics', - 'SEARCH_FOR' => 'Search for', - 'SEARCH_FORUM' => 'Search this forum…', - 'SEARCH_NEW' => 'New posts', - 'SEARCH_POSTS_BY' => 'Search posts by', - 'SEARCH_SELF' => 'Your posts', - 'SEARCH_TOPIC' => 'Search this topic…', - 'SEARCH_UNANSWERED' => 'Unanswered topics', - 'SEARCH_UNREAD' => 'Unread posts', - 'SEARCH_USER_POSTS' => 'Search user’s posts', - 'SECONDS' => 'Seconds', - 'SEE_ALL' => 'See All', - 'SELECT' => 'Select', - 'SELECT_ALL_CODE' => 'Select all', - 'SELECT_DESTINATION_FORUM' => 'Please select a destination forum', - 'SELECT_FORUM' => 'Select a forum', - 'SEND_EMAIL' => 'Send email', // Used for submit buttons - 'SEND_EMAIL_USER' => 'Send email to %s', - 'SEND_PRIVATE_MESSAGE' => 'Send private message', - 'SETTINGS' => 'Settings', - 'SIGNATURE' => 'Signature', - 'SKIP' => 'Skip to content', - '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', - 'SORT_USERNAME' => 'Username', - 'SPLIT_TOPIC' => 'Split topic', - 'SQL_ERROR_OCCURRED' => 'An SQL error occurred while fetching this page. Please contact the %sBoard Administrator%s if this problem persists.', - 'STATISTICS' => 'Statistics', - 'START_WATCHING_FORUM' => 'Subscribe forum', - 'START_WATCHING_TOPIC' => 'Subscribe topic', - 'STOP_WATCHING_FORUM' => 'Unsubscribe forum', - 'STOP_WATCHING_TOPIC' => 'Unsubscribe topic', - 'STRING_LIST_MULTI' => '%1$s, and %2$s', - 'STRING_LIST_SIMPLE' => '%1$s and %2$s', - 'SUBFORUM' => 'Subforum', - 'SUBFORUMS' => 'Subforums', - 'SUBJECT' => 'Subject', - 'SUBMIT' => 'Submit', - - 'TB' => 'TB', - 'TERMS_LINK' => 'Terms', - 'TERMS_USE' => 'Terms of use', - 'TEST_CONNECTION' => 'Test connection', - 'THE_TEAM' => 'The team', - 'TIB' => 'TiB', - 'TIME' => 'Time', - 'TIMEOUT_PROCESSING_REQ' => 'Request timed out.', - - 'TOO_LARGE' => 'The value you entered is too large.', - 'TOO_LARGE_MAX_RECIPIENTS' => 'The value of Maximum number of allowed recipients per private message setting you entered is too large.', - - 'TOO_LONG' => 'The value you entered is too long.', - - 'TOO_LONG_CONFIRM_CODE' => 'The confirm code you entered is too long.', - 'TOO_LONG_DATEFORMAT' => 'The date format you entered is too long.', - 'TOO_LONG_JABBER' => 'The Jabber account name you entered is too long.', - 'TOO_LONG_NEW_PASSWORD' => 'The password you entered is too long.', - 'TOO_LONG_PASSWORD_CONFIRM' => 'The password confirmation you entered is too long.', - 'TOO_LONG_USER_PASSWORD' => 'The password you entered is too long.', - 'TOO_LONG_USERNAME' => 'The username you entered is too long.', - 'TOO_LONG_EMAIL' => 'The email address you entered is too long.', - - 'TOO_MANY_VOTE_OPTIONS' => 'You have tried to vote for too many options.', - - 'TOO_SHORT' => 'The value you entered is too short.', - - 'TOO_SHORT_CONFIRM_CODE' => 'The confirm code you entered is too short.', - 'TOO_SHORT_DATEFORMAT' => 'The date format you entered is too short.', - 'TOO_SHORT_JABBER' => 'The Jabber account name you entered is too short.', - 'TOO_SHORT_NEW_PASSWORD' => 'The password you entered is too short.', - 'TOO_SHORT_PASSWORD_CONFIRM' => 'The password confirmation you entered is too short.', - 'TOO_SHORT_USER_PASSWORD' => 'The password you entered is too short.', - 'TOO_SHORT_USERNAME' => 'The username you entered is too short.', - 'TOO_SHORT_EMAIL' => 'The email address you entered is too short.', - 'TOO_SHORT_EMAIL_CONFIRM' => 'The email address confirmation you entered is too short.', - 'TOO_SMALL' => 'The value you entered is too small.', - 'TOO_SMALL_MAX_RECIPIENTS' => 'The value of Maximum number of allowed recipients per private message setting you entered is too small.', - - 'TOPIC' => 'Topic', - 'TOPICS' => 'Topics', - 'TOPICS_UNAPPROVED' => 'At least one topic in this forum has not been approved.', - 'TOPIC_ICON' => 'Topic icon', - 'TOPIC_LOCKED' => 'This topic is locked, you cannot edit posts or make further replies.', - 'TOPIC_LOCKED_SHORT'=> 'Topic locked', - 'TOPIC_MOVED' => 'Moved topic', - '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( - 1 => '%d log', - 2 => '%d logs', - ), - 'TOTAL_PMS' => array( - 1 => '%d private message in total', - 2 => '%d private messages in total', - ), - 'TOPIC_POLL' => 'This topic has a poll.', - 'TOTAL_POSTS' => 'Total posts', - 'TOTAL_POSTS_COUNT' => array( - 2 => 'Total posts %d', - ), - 'TOPIC_REPORTED' => 'This topic has been reported', - 'TOTAL_TOPICS' => array( - 2 => 'Total topics %d', - ), - 'TOTAL_USERS' => array( - 2 => 'Total members %d', - ), - 'TRACKED_PHP_ERROR' => 'Tracked PHP errors: %s', - 'TWITTER' => 'Twitter', - - 'UNABLE_GET_IMAGE_SIZE' => 'It was not possible to determine the dimensions of the image. Please verify that the URL you entered is correct.', - 'UNABLE_TO_DELIVER_FILE'=> 'Unable to deliver file.', - 'UNKNOWN_BROWSER' => 'Unknown browser', - 'UNMARK_ALL' => 'Unmark all', - 'UNREAD_MESSAGES' => 'Unread messages', - 'UNREAD_POST' => 'Unread post', - 'UNREAD_POSTS' => 'Unread posts', - 'UNWATCH_FORUM_CONFIRM' => 'Are you sure you wish to unsubscribe from this forum?', - 'UNWATCH_FORUM_DETAILED' => 'Are you sure you wish to unsubscribe from the forum “%s”?', - 'UNWATCH_TOPIC_CONFIRM' => 'Are you sure you wish to unsubscribe from this topic?', - 'UNWATCH_TOPIC_DETAILED' => 'Are you sure you wish to unsubscribe from the topic “%s”?', - 'UNWATCHED_FORUMS' => 'You are no longer subscribed to the selected forums.', - 'UNWATCHED_TOPICS' => 'You are no longer subscribed to the selected topics.', - 'UNWATCHED_FORUMS_TOPICS' => 'You are no longer subscribed to the selected entries.', - 'UPDATE' => 'Update', - 'UPLOAD_IN_PROGRESS' => 'The upload is currently in progress.', - 'URL_REDIRECT' => 'If your browser does not support meta redirection %splease click HERE to be redirected%s.', - 'USERGROUPS' => 'Groups', - 'USERNAME' => 'Username', - 'USERNAMES' => 'Usernames', - 'USER_AVATAR' => 'User avatar', - 'USER_CANNOT_READ' => 'You cannot read posts in this forum.', - 'USER_POSTS' => array( - 1 => '%d Post', - 2 => '%d Posts', - ), - 'USERS' => 'Users', - 'USE_PERMISSIONS' => 'Test out user’s permissions', - - 'USER_NEW_PERMISSION_DISALLOWED' => 'We are sorry, but you are not authorised to use this feature. You may have just registered here and may need to participate more in discussions to be able to use this feature.', - - 'VARIANT_DATE_SEPARATOR' => ' / ', // Used in date format dropdown, eg: "Today, 13:37 / 01 Jan 2007, 13:37" ... to join a relative date with calendar date - 'VIEWED' => 'Viewed', - 'VIEWED_COUNTS' => array( - 0 => 'Not viewed yet', - 1 => 'Viewed %d time', - 2 => 'Viewed %d times', - ), - 'VIEWING_CONTACT_ADMIN' => 'Viewing contact page', - 'VIEWING_FAQ' => 'Viewing FAQ', - 'VIEWING_MEMBERS' => 'Viewing member details', - 'VIEWING_ONLINE' => 'Viewing who is online', - 'VIEWING_MCP' => 'Viewing moderator control panel', - 'VIEWING_MEMBER_PROFILE' => 'Viewing member profile', - 'VIEWING_PRIVATE_MESSAGES' => 'Viewing private messages', - 'VIEWING_REGISTER' => 'Registering account', - 'VIEWING_UCP' => 'Viewing user control panel', - 'VIEWS' => 'Views', - 'VIEW_BOOKMARKS' => 'View bookmarks', - 'VIEW_FORUM_LOGS' => 'View Logs', - 'VIEW_LATEST_POST' => 'View the latest post', - 'VIEW_NEWEST_POST' => 'View first unread post', - 'VIEW_NOTES' => 'View user notes', - 'VIEW_ONLINE_TIMES' => array( - 1 => 'based on users active over the past %d minute', - 2 => 'based on users active over the past %d minutes', - ), - 'VIEW_TOPIC' => 'View topic', - 'VIEW_TOPIC_ANNOUNCEMENT' => 'Announcement: ', - 'VIEW_TOPIC_GLOBAL' => 'Global Announcement: ', - 'VIEW_TOPIC_LOCKED' => 'Locked: ', - 'VIEW_TOPIC_LOGS' => 'View logs', - 'VIEW_TOPIC_MOVED' => 'Moved: ', - 'VIEW_TOPIC_POLL' => 'Poll: ', - 'VIEW_TOPIC_STICKY' => 'Sticky: ', - 'VISIT_WEBSITE' => 'Visit website', - - 'WARNINGS' => 'Warnings', - 'WARN_USER' => 'Warn user', - 'WATCH_FORUM_CONFIRM' => 'Are you sure you wish to subscribe to this forum?', - 'WATCH_FORUM_DETAILED' => 'Are you sure you wish to subscribe to the forum “%s”?', - 'WATCH_TOPIC_CONFIRM' => 'Are you sure you wish to subscribe to this topic?', - 'WATCH_TOPIC_DETAILED' => 'Are you sure you wish to subscribe to the topic “%s”?', - 'WELCOME_SUBJECT' => 'Welcome to %s forums', - 'WEBSITE' => 'Website', - 'WHOIS' => 'Whois', - 'WHO_IS_ONLINE' => 'Who is online', - 'WRONG_PASSWORD' => 'You entered an incorrect password.', - - 'WRONG_DATA_COLOUR' => 'The colour value you entered is invalid.', - 'WRONG_DATA_JABBER' => 'The name you entered is not a valid Jabber account name.', - 'WRONG_DATA_LANG' => 'The language you specified is not valid.', - 'WRONG_DATA_POST_SD' => 'The post sort direction you specified is not valid.', - 'WRONG_DATA_POST_SK' => 'The post sort option you specified is not valid.', - 'WRONG_DATA_TOPIC_SD' => 'The topic sort direction you specified is not valid.', - 'WRONG_DATA_TOPIC_SK' => 'The topic sort option you specified is not valid.', - 'WROTE' => 'wrote', - - 'YAHOO' => 'Yahoo Messenger', - 'YOUTUBE' => 'YouTube', - 'YEAR' => 'Year', - 'YEAR_MONTH_DAY' => '(YYYY-MM-DD)', - 'YES' => 'Yes', - 'YOU_LAST_VISIT' => 'Last visit was: %s', - - 'datetime' => array( - 'TODAY' => 'Today', - 'TOMORROW' => 'Tomorrow', - 'YESTERDAY' => 'Yesterday', - 'AGO' => array( - 0 => 'less than a minute ago', - 1 => '%d minute ago', - 2 => '%d minutes ago', - ), - - 'Sunday' => 'Sunday', - 'Monday' => 'Monday', - 'Tuesday' => 'Tuesday', - 'Wednesday' => 'Wednesday', - 'Thursday' => 'Thursday', - 'Friday' => 'Friday', - 'Saturday' => 'Saturday', - - 'Sun' => 'Sun', - 'Mon' => 'Mon', - 'Tue' => 'Tue', - 'Wed' => 'Wed', - 'Thu' => 'Thu', - 'Fri' => 'Fri', - 'Sat' => 'Sat', - - 'January' => 'January', - 'February' => 'February', - 'March' => 'March', - 'April' => 'April', - 'May' => 'May', - 'June' => 'June', - 'July' => 'July', - 'August' => 'August', - 'September' => 'September', - 'October' => 'October', - 'November' => 'November', - 'December' => 'December', - - 'Jan' => 'Jan', - 'Feb' => 'Feb', - 'Mar' => 'Mar', - 'Apr' => 'Apr', - 'May_short' => 'May', // Short representation of "May". May_short used because in English the short and long date are the same for May. - 'Jun' => 'Jun', - 'Jul' => 'Jul', - 'Aug' => 'Aug', - 'Sep' => 'Sep', - 'Oct' => 'Oct', - 'Nov' => 'Nov', - 'Dec' => 'Dec', - ), - - // Timezones can be translated. We use this for the Etc/GMT timezones here, - // because they are named invers to their offset. - 'timezones' => array( - 'UTC' => 'UTC', - 'UTC_OFFSET' => 'UTC%1$s', - 'UTC_OFFSET_CURRENT' => 'UTC%1$s - %2$s', - - 'Etc/GMT-12' => 'UTC+12', - 'Etc/GMT-11' => 'UTC+11', - 'Etc/GMT-10' => 'UTC+10', - 'Etc/GMT-9' => 'UTC+9', - 'Etc/GMT-8' => 'UTC+8', - 'Etc/GMT-7' => 'UTC+7', - 'Etc/GMT-6' => 'UTC+6', - 'Etc/GMT-5' => 'UTC+5', - 'Etc/GMT-4' => 'UTC+4', - 'Etc/GMT-3' => 'UTC+3', - 'Etc/GMT-2' => 'UTC+2', - 'Etc/GMT-1' => 'UTC+1', - 'Etc/GMT+1' => 'UTC-1', - 'Etc/GMT+2' => 'UTC-2', - 'Etc/GMT+3' => 'UTC-3', - 'Etc/GMT+4' => 'UTC-4', - 'Etc/GMT+5' => 'UTC-5', - 'Etc/GMT+6' => 'UTC-6', - 'Etc/GMT+7' => 'UTC-7', - 'Etc/GMT+8' => 'UTC-8', - 'Etc/GMT+9' => 'UTC-9', - 'Etc/GMT+10' => 'UTC-10', - 'Etc/GMT+11' => 'UTC-11', - 'Etc/GMT+12' => 'UTC-12', - - 'Africa/Abidjan' => 'Africa/Abidjan', - 'Africa/Accra' => 'Africa/Accra', - 'Africa/Addis_Ababa' => 'Africa/Addis Ababa', - 'Africa/Algiers' => 'Africa/Algiers', - 'Africa/Asmara' => 'Africa/Asmara', - 'Africa/Bamako' => 'Africa/Bamako', - 'Africa/Bangui' => 'Africa/Bangui', - 'Africa/Banjul' => 'Africa/Banjul', - 'Africa/Bissau' => 'Africa/Bissau', - 'Africa/Blantyre' => 'Africa/Blantyre', - 'Africa/Brazzaville' => 'Africa/Brazzaville', - 'Africa/Bujumbura' => 'Africa/Bujumbura', - 'Africa/Cairo' => 'Africa/Cairo', - 'Africa/Casablanca' => 'Africa/Casablanca', - 'Africa/Ceuta' => 'Africa/Ceuta', - 'Africa/Conakry' => 'Africa/Conakry', - 'Africa/Dakar' => 'Africa/Dakar', - 'Africa/Dar_es_Salaam' => 'Africa/Dar es Salaam', - 'Africa/Djibouti' => 'Africa/Djibouti', - 'Africa/Douala' => 'Africa/Douala', - 'Africa/El_Aaiun' => 'Africa/El Aaiun', - 'Africa/Freetown' => 'Africa/Freetown', - 'Africa/Gaborone' => 'Africa/Gaborone', - 'Africa/Harare' => 'Africa/Harare', - 'Africa/Johannesburg' => 'Africa/Johannesburg', - 'Africa/Juba' => 'Africa/Juba', - 'Africa/Kampala' => 'Africa/Kampala', - 'Africa/Khartoum' => 'Africa/Khartoum', - 'Africa/Kigali' => 'Africa/Kigali', - 'Africa/Kinshasa' => 'Africa/Kinshasa', - 'Africa/Lagos' => 'Africa/Lagos', - 'Africa/Libreville' => 'Africa/Libreville', - 'Africa/Lome' => 'Africa/Lome', - 'Africa/Luanda' => 'Africa/Luanda', - 'Africa/Lubumbashi' => 'Africa/Lubumbashi', - 'Africa/Lusaka' => 'Africa/Lusaka', - 'Africa/Malabo' => 'Africa/Malabo', - 'Africa/Maputo' => 'Africa/Maputo', - 'Africa/Maseru' => 'Africa/Maseru', - 'Africa/Mbabane' => 'Africa/Mbabane', - 'Africa/Mogadishu' => 'Africa/Mogadishu', - 'Africa/Monrovia' => 'Africa/Monrovia', - 'Africa/Nairobi' => 'Africa/Nairobi', - 'Africa/Ndjamena' => 'Africa/Ndjamena', - 'Africa/Niamey' => 'Africa/Niamey', - 'Africa/Nouakchott' => 'Africa/Nouakchott', - 'Africa/Ouagadougou' => 'Africa/Ouagadougou', - 'Africa/Porto-Novo' => 'Africa/Porto-Novo', - 'Africa/Sao_Tome' => 'Africa/Sao Tome', - 'Africa/Tripoli' => 'Africa/Tripoli', - 'Africa/Tunis' => 'Africa/Tunis', - 'Africa/Windhoek' => 'Africa/Windhoek', - - 'America/Adak' => 'America/Adak', - 'America/Anchorage' => 'America/Anchorage', - 'America/Anguilla' => 'America/Anguilla', - 'America/Antigua' => 'America/Antigua', - 'America/Araguaina' => 'America/Araguaina', - - 'America/Argentina/Buenos_Aires' => 'America/Argentina/Buenos Aires', - 'America/Argentina/Catamarca' => 'America/Argentina/Catamarca', - 'America/Argentina/Cordoba' => 'America/Argentina/Cordoba', - 'America/Argentina/Jujuy' => 'America/Argentina/Jujuy', - 'America/Argentina/La_Rioja' => 'America/Argentina/La Rioja', - 'America/Argentina/Mendoza' => 'America/Argentina/Mendoza', - 'America/Argentina/Rio_Gallegos' => 'America/Argentina/Rio Gallegos', - 'America/Argentina/Salta' => 'America/Argentina/Salta', - 'America/Argentina/San_Juan' => 'America/Argentina/San Juan', - 'America/Argentina/San_Luis' => 'America/Argentina/San Luis', - 'America/Argentina/Tucuman' => 'America/Argentina/Tucuman', - 'America/Argentina/Ushuaia' => 'America/Argentina/Ushuaia', - - 'America/Aruba' => 'America/Aruba', - 'America/Asuncion' => 'America/Asuncion', - 'America/Atikokan' => 'America/Atikokan', - 'America/Bahia' => 'America/Bahia', - 'America/Bahia_Banderas' => 'America/Bahia Banderas', - 'America/Barbados' => 'America/Barbados', - 'America/Belem' => 'America/Belem', - 'America/Belize' => 'America/Belize', - 'America/Blanc-Sablon' => 'America/Blanc-Sablon', - 'America/Boa_Vista' => 'America/Boa Vista', - 'America/Bogota' => 'America/Bogota', - 'America/Boise' => 'America/Boise', - 'America/Cambridge_Bay' => 'America/Cambridge Bay', - 'America/Campo_Grande' => 'America/Campo Grande', - 'America/Cancun' => 'America/Cancun', - 'America/Caracas' => 'America/Caracas', - 'America/Cayenne' => 'America/Cayenne', - 'America/Cayman' => 'America/Cayman', - 'America/Chicago' => 'America/Chicago', - 'America/Chihuahua' => 'America/Chihuahua', - 'America/Costa_Rica' => 'America/Costa Rica', - 'America/Creston' => 'America/Creston', - 'America/Cuiaba' => 'America/Cuiaba', - 'America/Curacao' => 'America/Curacao', - 'America/Danmarkshavn' => 'America/Danmarkshavn', - 'America/Dawson' => 'America/Dawson', - 'America/Dawson_Creek' => 'America/Dawson Creek', - 'America/Denver' => 'America/Denver', - 'America/Detroit' => 'America/Detroit', - 'America/Dominica' => 'America/Dominica', - 'America/Edmonton' => 'America/Edmonton', - 'America/Eirunepe' => 'America/Eirunepe', - 'America/El_Salvador' => 'America/El Salvador', - 'America/Fortaleza' => 'America/Fortaleza', - 'America/Glace_Bay' => 'America/Glace Bay', - 'America/Godthab' => 'America/Godthab', - 'America/Goose_Bay' => 'America/Goose Bay', - 'America/Grand_Turk' => 'America/Grand Turk', - 'America/Grenada' => 'America/Grenada', - 'America/Guadeloupe' => 'America/Guadeloupe', - 'America/Guatemala' => 'America/Guatemala', - 'America/Guayaquil' => 'America/Guayaquil', - 'America/Guyana' => 'America/Guyana', - 'America/Halifax' => 'America/Halifax', - 'America/Havana' => 'America/Havana', - 'America/Hermosillo' => 'America/Hermosillo', - 'America/Indiana/Indianapolis' => 'America/Indiana/Indianapolis', - 'America/Indiana/Knox' => 'America/Indiana/Knox', - 'America/Indiana/Marengo' => 'America/Indiana/Marengo', - 'America/Indiana/Petersburg' => 'America/Indiana/Petersburg', - 'America/Indiana/Tell_City' => 'America/Indiana/Tell City', - 'America/Indiana/Vevay' => 'America/Indiana/Vevay', - 'America/Indiana/Vincennes' => 'America/Indiana/Vincennes', - 'America/Indiana/Winamac' => 'America/Indiana/Winamac', - 'America/Inuvik' => 'America/Inuvik', - 'America/Iqaluit' => 'America/Iqaluit', - 'America/Jamaica' => 'America/Jamaica', - 'America/Juneau' => 'America/Juneau', - 'America/Kentucky/Louisville' => 'America/Kentucky/Louisville', - 'America/Kentucky/Monticello' => 'America/Kentucky/Monticello', - 'America/Kralendijk' => 'America/Kralendijk', - 'America/La_Paz' => 'America/La Paz', - 'America/Lima' => 'America/Lima', - 'America/Los_Angeles' => 'America/Los Angeles', - 'America/Lower_Princes' => 'America/Lower Princes', - 'America/Maceio' => 'America/Maceio', - 'America/Managua' => 'America/Managua', - 'America/Manaus' => 'America/Manaus', - 'America/Marigot' => 'America/Marigot', - 'America/Martinique' => 'America/Martinique', - 'America/Matamoros' => 'America/Matamoros', - 'America/Mazatlan' => 'America/Mazatlan', - 'America/Menominee' => 'America/Menominee', - 'America/Merida' => 'America/Merida', - 'America/Metlakatla' => 'America/Metlakatla', - 'America/Mexico_City' => 'America/Mexico City', - 'America/Miquelon' => 'America/Miquelon', - 'America/Moncton' => 'America/Moncton', - 'America/Monterrey' => 'America/Monterrey', - 'America/Montevideo' => 'America/Montevideo', - 'America/Montreal' => 'America/Montreal', - 'America/Montserrat' => 'America/Montserrat', - 'America/Nassau' => 'America/Nassau', - 'America/New_York' => 'America/New York', - 'America/Nipigon' => 'America/Nipigon', - 'America/Nome' => 'America/Nome', - 'America/Noronha' => 'America/Noronha', - 'America/North_Dakota/Beulah' => 'America/North Dakota/Beulah', - 'America/North_Dakota/Center' => 'America/North Dakota/Center', - 'America/North_Dakota/New_Salem' => 'America/North Dakota/New Salem', - 'America/Ojinaga' => 'America/Ojinaga', - 'America/Panama' => 'America/Panama', - 'America/Pangnirtung' => 'America/Pangnirtung', - 'America/Paramaribo' => 'America/Paramaribo', - 'America/Phoenix' => 'America/Phoenix', - 'America/Port-au-Prince' => 'America/Port-au-Prince', - 'America/Port_of_Spain' => 'America/Port of Spain', - 'America/Porto_Velho' => 'America/Porto Velho', - 'America/Puerto_Rico' => 'America/Puerto Rico', - 'America/Rainy_River' => 'America/Rainy River', - 'America/Rankin_Inlet' => 'America/Rankin Inlet', - 'America/Recife' => 'America/Recife', - 'America/Regina' => 'America/Regina', - 'America/Resolute' => 'America/Resolute', - 'America/Rio_Branco' => 'America/Rio Branco', - 'America/Santa_Isabel' => 'America/Santa Isabel', - 'America/Santarem' => 'America/Santarem', - 'America/Santiago' => 'America/Santiago', - 'America/Santo_Domingo' => 'America/Santo Domingo', - 'America/Sao_Paulo' => 'America/Sao Paulo', - 'America/Scoresbysund' => 'America/Scoresbysund', - 'America/Shiprock' => 'America/Shiprock', - 'America/Sitka' => 'America/Sitka', - 'America/St_Barthelemy' => 'America/St. Barthelemy', - 'America/St_Johns' => 'America/St. Johns', - 'America/St_Kitts' => 'America/St. Kitts', - 'America/St_Lucia' => 'America/St. Lucia', - 'America/St_Thomas' => 'America/St. Thomas', - 'America/St_Vincent' => 'America/St. Vincent', - 'America/Swift_Current' => 'America/Swift Current', - 'America/Tegucigalpa' => 'America/Tegucigalpa', - 'America/Thule' => 'America/Thule', - 'America/Thunder_Bay' => 'America/Thunder Bay', - 'America/Tijuana' => 'America/Tijuana', - 'America/Toronto' => 'America/Toronto', - 'America/Tortola' => 'America/Tortola', - 'America/Vancouver' => 'America/Vancouver', - 'America/Whitehorse' => 'America/Whitehorse', - 'America/Winnipeg' => 'America/Winnipeg', - 'America/Yakutat' => 'America/Yakutat', - 'America/Yellowknife' => 'America/Yellowknife', - - 'Antarctica/Casey' => 'Antarctica/Casey', - 'Antarctica/Davis' => 'Antarctica/Davis', - 'Antarctica/DumontDUrville' => 'Antarctica/DumontDUrville', - 'Antarctica/Macquarie' => 'Antarctica/Macquarie', - 'Antarctica/Mawson' => 'Antarctica/Mawson', - 'Antarctica/McMurdo' => 'Antarctica/McMurdo', - 'Antarctica/Palmer' => 'Antarctica/Palmer', - 'Antarctica/Rothera' => 'Antarctica/Rothera', - 'Antarctica/South_Pole' => 'Antarctica/South Pole', - 'Antarctica/Syowa' => 'Antarctica/Syowa', - 'Antarctica/Vostok' => 'Antarctica/Vostok', - - 'Arctic/Longyearbyen' => 'Arctic/Longyearbyen', - - 'Asia/Aden' => 'Asia/Aden', - 'Asia/Almaty' => 'Asia/Almaty', - 'Asia/Amman' => 'Asia/Amman', - 'Asia/Anadyr' => 'Asia/Anadyr', - 'Asia/Aqtau' => 'Asia/Aqtau', - 'Asia/Aqtobe' => 'Asia/Aqtobe', - 'Asia/Ashgabat' => 'Asia/Ashgabat', - 'Asia/Baghdad' => 'Asia/Baghdad', - 'Asia/Bahrain' => 'Asia/Bahrain', - 'Asia/Baku' => 'Asia/Baku', - 'Asia/Bangkok' => 'Asia/Bangkok', - 'Asia/Beirut' => 'Asia/Beirut', - 'Asia/Bishkek' => 'Asia/Bishkek', - 'Asia/Brunei' => 'Asia/Brunei', - 'Asia/Choibalsan' => 'Asia/Choibalsan', - 'Asia/Chongqing' => 'Asia/Chongqing', - 'Asia/Colombo' => 'Asia/Colombo', - 'Asia/Damascus' => 'Asia/Damascus', - 'Asia/Dhaka' => 'Asia/Dhaka', - 'Asia/Dili' => 'Asia/Dili', - 'Asia/Dubai' => 'Asia/Dubai', - 'Asia/Dushanbe' => 'Asia/Dushanbe', - 'Asia/Gaza' => 'Asia/Gaza', - 'Asia/Harbin' => 'Asia/Harbin', - 'Asia/Hebron' => 'Asia/Hebron', - 'Asia/Ho_Chi_Minh' => 'Asia/Ho Chi Minh', - 'Asia/Hong_Kong' => 'Asia/Hong Kong', - 'Asia/Hovd' => 'Asia/Hovd', - 'Asia/Irkutsk' => 'Asia/Irkutsk', - 'Asia/Jakarta' => 'Asia/Jakarta', - 'Asia/Jayapura' => 'Asia/Jayapura', - 'Asia/Jerusalem' => 'Asia/Jerusalem', - 'Asia/Kabul' => 'Asia/Kabul', - 'Asia/Kamchatka' => 'Asia/Kamchatka', - 'Asia/Karachi' => 'Asia/Karachi', - 'Asia/Kashgar' => 'Asia/Kashgar', - 'Asia/Kathmandu' => 'Asia/Kathmandu', - 'Asia/Khandyga' => 'Asia/Khandyga', - 'Asia/Kolkata' => 'Asia/Kolkata', - 'Asia/Krasnoyarsk' => 'Asia/Krasnoyarsk', - 'Asia/Kuala_Lumpur' => 'Asia/Kuala Lumpur', - 'Asia/Kuching' => 'Asia/Kuching', - 'Asia/Kuwait' => 'Asia/Kuwait', - 'Asia/Macau' => 'Asia/Macau', - 'Asia/Magadan' => 'Asia/Magadan', - 'Asia/Makassar' => 'Asia/Makassar', - 'Asia/Manila' => 'Asia/Manila', - 'Asia/Muscat' => 'Asia/Muscat', - 'Asia/Nicosia' => 'Asia/Nicosia', - 'Asia/Novokuznetsk' => 'Asia/Novokuznetsk', - 'Asia/Novosibirsk' => 'Asia/Novosibirsk', - 'Asia/Omsk' => 'Asia/Omsk', - 'Asia/Oral' => 'Asia/Oral', - 'Asia/Phnom_Penh' => 'Asia/Phnom Penh', - 'Asia/Pontianak' => 'Asia/Pontianak', - 'Asia/Pyongyang' => 'Asia/Pyongyang', - 'Asia/Qatar' => 'Asia/Qatar', - 'Asia/Qyzylorda' => 'Asia/Qyzylorda', - 'Asia/Rangoon' => 'Asia/Rangoon', - 'Asia/Riyadh' => 'Asia/Riyadh', - 'Asia/Sakhalin' => 'Asia/Sakhalin', - 'Asia/Samarkand' => 'Asia/Samarkand', - 'Asia/Seoul' => 'Asia/Seoul', - 'Asia/Shanghai' => 'Asia/Shanghai', - 'Asia/Singapore' => 'Asia/Singapore', - 'Asia/Taipei' => 'Asia/Taipei', - 'Asia/Tashkent' => 'Asia/Tashkent', - 'Asia/Tbilisi' => 'Asia/Tbilisi', - 'Asia/Tehran' => 'Asia/Tehran', - 'Asia/Thimphu' => 'Asia/Thimphu', - 'Asia/Tokyo' => 'Asia/Tokyo', - 'Asia/Ulaanbaatar' => 'Asia/Ulaanbaatar', - 'Asia/Urumqi' => 'Asia/Urumqi', - 'Asia/Ust-Nera' => 'Asia/Ust-Nera', - 'Asia/Vientiane' => 'Asia/Vientiane', - 'Asia/Vladivostok' => 'Asia/Vladivostok', - 'Asia/Yakutsk' => 'Asia/Yakutsk', - 'Asia/Yekaterinburg' => 'Asia/Yekaterinburg', - 'Asia/Yerevan' => 'Asia/Yerevan', - - 'Atlantic/Azores' => 'Atlantic/Azores', - 'Atlantic/Bermuda' => 'Atlantic/Bermuda', - 'Atlantic/Canary' => 'Atlantic/Canary', - 'Atlantic/Cape_Verde' => 'Atlantic/Cape Verde', - 'Atlantic/Faroe' => 'Atlantic/Faroe', - 'Atlantic/Madeira' => 'Atlantic/Madeira', - 'Atlantic/Reykjavik' => 'Atlantic/Reykjavik', - 'Atlantic/South_Georgia' => 'Atlantic/South Georgia', - 'Atlantic/St_Helena' => 'Atlantic/St. Helena', - 'Atlantic/Stanley' => 'Atlantic/Stanley', - - 'Australia/Adelaide' => 'Australia/Adelaide', - 'Australia/Brisbane' => 'Australia/Brisbane', - 'Australia/Broken_Hill' => 'Australia/Broken Hill', - 'Australia/Currie' => 'Australia/Currie', - 'Australia/Darwin' => 'Australia/Darwin', - 'Australia/Eucla' => 'Australia/Eucla', - 'Australia/Hobart' => 'Australia/Hobart', - 'Australia/Lindeman' => 'Australia/Lindeman', - 'Australia/Lord_Howe' => 'Australia/Lord Howe', - 'Australia/Melbourne' => 'Australia/Melbourne', - 'Australia/Perth' => 'Australia/Perth', - 'Australia/Sydney' => 'Australia/Sydney', - - 'Europe/Amsterdam' => 'Europe/Amsterdam', - 'Europe/Andorra' => 'Europe/Andorra', - 'Europe/Athens' => 'Europe/Athens', - 'Europe/Belgrade' => 'Europe/Belgrade', - 'Europe/Berlin' => 'Europe/Berlin', - 'Europe/Bratislava' => 'Europe/Bratislava', - 'Europe/Brussels' => 'Europe/Brussels', - 'Europe/Bucharest' => 'Europe/Bucharest', - 'Europe/Budapest' => 'Europe/Budapest', - 'Europe/Busingen' => 'Europe/Busingen', - 'Europe/Chisinau' => 'Europe/Chisinau', - 'Europe/Copenhagen' => 'Europe/Copenhagen', - 'Europe/Dublin' => 'Europe/Dublin', - 'Europe/Gibraltar' => 'Europe/Gibraltar', - 'Europe/Guernsey' => 'Europe/Guernsey', - 'Europe/Helsinki' => 'Europe/Helsinki', - 'Europe/Isle_of_Man' => 'Europe/Isle of Man', - 'Europe/Istanbul' => 'Europe/Istanbul', - 'Europe/Jersey' => 'Europe/Jersey', - 'Europe/Kaliningrad' => 'Europe/Kaliningrad', - 'Europe/Kiev' => 'Europe/Kiev', - 'Europe/Lisbon' => 'Europe/Lisbon', - 'Europe/Ljubljana' => 'Europe/Ljubljana', - 'Europe/London' => 'Europe/London', - 'Europe/Luxembourg' => 'Europe/Luxembourg', - 'Europe/Madrid' => 'Europe/Madrid', - 'Europe/Malta' => 'Europe/Malta', - 'Europe/Mariehamn' => 'Europe/Mariehamn', - 'Europe/Minsk' => 'Europe/Minsk', - 'Europe/Monaco' => 'Europe/Monaco', - 'Europe/Moscow' => 'Europe/Moscow', - 'Europe/Oslo' => 'Europe/Oslo', - 'Europe/Paris' => 'Europe/Paris', - 'Europe/Podgorica' => 'Europe/Podgorica', - 'Europe/Prague' => 'Europe/Prague', - 'Europe/Riga' => 'Europe/Riga', - 'Europe/Rome' => 'Europe/Rome', - 'Europe/Samara' => 'Europe/Samara', - 'Europe/San_Marino' => 'Europe/San Marino', - 'Europe/Sarajevo' => 'Europe/Sarajevo', - 'Europe/Simferopol' => 'Europe/Simferopol', - 'Europe/Skopje' => 'Europe/Skopje', - 'Europe/Sofia' => 'Europe/Sofia', - 'Europe/Stockholm' => 'Europe/Stockholm', - 'Europe/Tallinn' => 'Europe/Tallinn', - 'Europe/Tirane' => 'Europe/Tirane', - 'Europe/Uzhgorod' => 'Europe/Uzhgorod', - 'Europe/Vaduz' => 'Europe/Vaduz', - 'Europe/Vatican' => 'Europe/Vatican', - 'Europe/Vienna' => 'Europe/Vienna', - 'Europe/Vilnius' => 'Europe/Vilnius', - 'Europe/Volgograd' => 'Europe/Volgograd', - 'Europe/Warsaw' => 'Europe/Warsaw', - 'Europe/Zagreb' => 'Europe/Zagreb', - 'Europe/Zaporozhye' => 'Europe/Zaporozhye', - 'Europe/Zurich' => 'Europe/Zurich', - - 'Indian/Antananarivo' => 'Indian/Antananarivo', - 'Indian/Chagos' => 'Indian/Chagos', - 'Indian/Christmas' => 'Indian/Christmas', - 'Indian/Cocos' => 'Indian/Cocos', - 'Indian/Comoro' => 'Indian/Comoro', - 'Indian/Kerguelen' => 'Indian/Kerguelen', - 'Indian/Mahe' => 'Indian/Mahe', - 'Indian/Maldives' => 'Indian/Maldives', - 'Indian/Mauritius' => 'Indian/Mauritius', - 'Indian/Mayotte' => 'Indian/Mayotte', - 'Indian/Reunion' => 'Indian/Reunion', - - 'Pacific/Apia' => 'Pacific/Apia', - 'Pacific/Auckland' => 'Pacific/Auckland', - 'Pacific/Chatham' => 'Pacific/Chatham', - 'Pacific/Chuuk' => 'Pacific/Chuuk', - 'Pacific/Easter' => 'Pacific/Easter', - 'Pacific/Efate' => 'Pacific/Efate', - 'Pacific/Enderbury' => 'Pacific/Enderbury', - 'Pacific/Fakaofo' => 'Pacific/Fakaofo', - 'Pacific/Fiji' => 'Pacific/Fiji', - 'Pacific/Funafuti' => 'Pacific/Funafuti', - 'Pacific/Galapagos' => 'Pacific/Galapagos', - 'Pacific/Gambier' => 'Pacific/Gambier', - 'Pacific/Guadalcanal' => 'Pacific/Guadalcanal', - 'Pacific/Guam' => 'Pacific/Guam', - 'Pacific/Honolulu' => 'Pacific/Honolulu', - 'Pacific/Johnston' => 'Pacific/Johnston', - 'Pacific/Kiritimati' => 'Pacific/Kiritimati', - 'Pacific/Kosrae' => 'Pacific/Kosrae', - 'Pacific/Kwajalein' => 'Pacific/Kwajalein', - 'Pacific/Majuro' => 'Pacific/Majuro', - 'Pacific/Marquesas' => 'Pacific/Marquesas', - 'Pacific/Midway' => 'Pacific/Midway', - 'Pacific/Nauru' => 'Pacific/Nauru', - 'Pacific/Niue' => 'Pacific/Niue', - 'Pacific/Norfolk' => 'Pacific/Norfolk', - 'Pacific/Noumea' => 'Pacific/Noumea', - 'Pacific/Pago_Pago' => 'Pacific/Pago Pago', - 'Pacific/Palau' => 'Pacific/Palau', - 'Pacific/Pitcairn' => 'Pacific/Pitcairn', - 'Pacific/Pohnpei' => 'Pacific/Pohnpei', - 'Pacific/Port_Moresby' => 'Pacific/Port Moresby', - 'Pacific/Rarotonga' => 'Pacific/Rarotonga', - 'Pacific/Saipan' => 'Pacific/Saipan', - 'Pacific/Tahiti' => 'Pacific/Tahiti', - 'Pacific/Tarawa' => 'Pacific/Tarawa', - 'Pacific/Tongatapu' => 'Pacific/Tongatapu', - 'Pacific/Wake' => 'Pacific/Wake', - 'Pacific/Wallis' => 'Pacific/Wallis', - ), - - // The value is only an example and will get replaced by the current time on view - 'dateformats' => array( - 'd M Y, H:i' => '01 Jan 2007, 13:37', - 'd M Y H:i' => '01 Jan 2007 13:37', - 'M jS, \'y, H:i' => 'Jan 1st, \'07, 13:37', - 'D M d, Y g:i a' => 'Mon Jan 01, 2007 1:37 pm', - 'F jS, Y, g:i a' => 'January 1st, 2007, 1:37 pm', - '|d M Y|, H:i' => 'Today, 13:37 / 01 Jan 2007, 13:37', - '|F jS, Y|, g:i a' => 'Today, 1:37 pm / January 1st, 2007, 1:37 pm', - ), - - // The default dateformat which will be used on new installs in this language - // Translators should change this if a the usual date format is different - 'default_dateformat' => 'D M d, Y g:i a', // Mon Jan 01, 2007 1:37 pm - -)); diff --git a/install/update/old/language/en/email/admin_activate.txt b/install/update/old/language/en/email/admin_activate.txt deleted file mode 100644 index a53ab12..0000000 --- a/install/update/old/language/en/email/admin_activate.txt +++ /dev/null @@ -1,13 +0,0 @@ -Subject: Activate user account - -Hello, - -The account owned by "{USERNAME}" has been deactivated or newly created, you should check the details of this user (if required) and handle it appropriately. - -Use this link to view the user's profile: -{U_USER_DETAILS} - -Use this link to activate the account: -{U_ACTIVATE} - -{EMAIL_SIG} diff --git a/install/update/old/language/en/install.php b/install/update/old/language/en/install.php deleted file mode 100644 index 9bceecc..0000000 --- a/install/update/old/language/en/install.php +++ /dev/null @@ -1,599 +0,0 @@ - - * @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(); -} - -// 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 - -// Common installer pages -$lang = array_merge($lang, array( - 'INSTALL_PANEL' => 'Installation Panel', - 'SELECT_LANG' => 'Select language', - - 'STAGE_INSTALL' => 'Installing phpBB', - - // Introduction page - 'INTRODUCTION_TITLE' => 'Introduction', - 'INTRODUCTION_BODY' => 'Welcome to phpBB3!

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.

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 the installation guide.

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.', - - // Support page - 'SUPPORT_TITLE' => 'Support', - 'SUPPORT_BODY' => 'Full support will be provided for the current stable release of phpBB3, free of charge. This includes:

  • installation
  • configuration
  • technical questions
  • problems relating to potential bugs in the software
  • updating from Release Candidate (RC) versions to the latest stable version
  • converting from phpBB 2.0.x to phpBB3
  • converting from other discussion board software to phpBB3 (please see the Convertors Forum)

We encourage users still running beta versions of phpBB3 to replace their installation with a fresh copy of the latest version.

Extensions / Styles

For issues relating to Extensions, please post in the appropriate Extensions Forum.
For issues relating to styles, templates and themes, please post in the appropriate Styles Forum.

If your question relates to a specific package, please post directly in the topic dedicated to the package.

Obtaining Support

Support Section
Quick Start Guide

To ensure you stay up to date with the latest news and releases, follow us on Twitter and Facebook

', - - // License - 'LICENSE_TITLE' => 'General Public License', - - // Install page - 'INSTALL_INTRO' => 'Welcome to Installation', - 'INSTALL_INTRO_BODY' => 'With this option, it is possible to install phpBB3 onto your server.

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

- -
    -
  • The Database Type - the database you will be using.
  • -
  • The Database server hostname or DSN - the address of the database server.
  • -
  • The Database server port - the port of the database server (most of the time this is not needed).
  • -
  • The Database name - the name of the database on the server.
  • -
  • The Database username and Database password - the login data to access the database.
  • -
- -

Note: if you are installing using SQLite, you should enter the full path to your database file in the DSN field and leave the username and password fields blank. For security reasons, you should make sure that the database file is not stored in a location accessible from the web.

- -

phpBB3 supports the following databases:

-
    -
  • MySQL 3.23 or above (MySQLi supported)
  • -
  • PostgreSQL 8.3+
  • -
  • SQLite 3.6.15+
  • -
  • MS SQL Server 2000 or above (directly or via ODBC)
  • -
  • MS SQL Server 2005 or above (native)
  • -
  • Oracle
  • -
- -

Only those databases supported on your server will be displayed.', - - 'ACP_LINK' => 'Take me to the ACP', - - 'INSTALL_PHPBB_INSTALLED' => 'phpBB is already installed.', - 'INSTALL_PHPBB_NOT_INSTALLED' => 'phpBB is not installed yet.', -)); - -// 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', -)); - -// General error messages -$lang = array_merge($lang, array( - 'INST_ERR_MISSING_DATA' => 'You must fill out all fields in this block.', - - '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.', -)); - -// Data obtaining translations -$lang = array_merge($lang, array( - 'STAGE_OBTAIN_DATA' => 'Set installation data', - - // - // Admin data - // - 'STAGE_ADMINISTRATOR' => 'Administrator details', - - // 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.', - - // 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 NLS_CHARACTERSET parameter to UTF8. 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 UNICODE or UTF8 encoding. Try installing with a database in UNICODE or UTF8 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', - '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' => '

Incomplete update

- -

We noticed that the last update of your phpBB installation hasn’t been completed. Visit the database updater, ensure Update database only is selected and click on Submit. Don\'t forget to delete the "install"-directory after you have updated the database sucessfully.

', - - // - // Server data - // - // Form labels - 'UPGRADE_INSTRUCTIONS' => 'A new feature release %1$s is available. Please read the release announcement to learn about what it has to offer, and how to upgrade.', - 'SERVER_CONFIG' => 'Server configuration', - 'SCRIPT_PATH' => 'Script path', - 'SCRIPT_PATH_EXPLAIN' => 'The path where phpBB is located relative to the domain name, e.g. /phpBB3.', -)); - -// Default database schema entries... -$lang = array_merge($lang, array( - 'CONFIG_BOARD_EMAIL_SIG' => 'Thanks, The Management', - 'CONFIG_SITE_DESC' => 'A short text to describe your forum', - 'CONFIG_SITENAME' => 'yourdomain.com', - - 'DEFAULT_INSTALL_POST' => 'This is an example post in your phpBB3 installation. Everything seems to be working. You may delete this post if you like and continue to set up your board. During the installation process your first category and your first forum are assigned an appropriate set of permissions for the predefined usergroups administrators, bots, global moderators, guests, registered users and registered COPPA users. If you also choose to delete your first category and your first forum, do not forget to assign permissions for all these usergroups for all new categories and forums you create. It is recommended to rename your first category and your first forum and copy permissions from these while creating new categories and forums. Have fun!', - - 'FORUMS_FIRST_CATEGORY' => 'Your first category', - 'FORUMS_TEST_FORUM_DESC' => 'Description of your first forum.', - 'FORUMS_TEST_FORUM_TITLE' => 'Your first forum', - - 'RANKS_SITE_ADMIN_TITLE' => 'Site Admin', - 'REPORT_WAREZ' => 'The post contains links to illegal or pirated software.', - 'REPORT_SPAM' => 'The reported post has the only purpose to advertise for a website or another product.', - 'REPORT_OFF_TOPIC' => 'The reported post is off topic.', - 'REPORT_OTHER' => 'The reported post does not fit into any other category, please use the further information field.', - - 'SMILIES_ARROW' => 'Arrow', - 'SMILIES_CONFUSED' => 'Confused', - 'SMILIES_COOL' => 'Cool', - 'SMILIES_CRYING' => 'Crying or Very Sad', - 'SMILIES_EMARRASSED' => 'Embarrassed', - 'SMILIES_EVIL' => 'Evil or Very Mad', - 'SMILIES_EXCLAMATION' => 'Exclamation', - 'SMILIES_GEEK' => 'Geek', - 'SMILIES_IDEA' => 'Idea', - 'SMILIES_LAUGHING' => 'Laughing', - 'SMILIES_MAD' => 'Mad', - 'SMILIES_MR_GREEN' => 'Mr. Green', - 'SMILIES_NEUTRAL' => 'Neutral', - 'SMILIES_QUESTION' => 'Question', - 'SMILIES_RAZZ' => 'Razz', - 'SMILIES_ROLLING_EYES' => 'Rolling Eyes', - 'SMILIES_SAD' => 'Sad', - 'SMILIES_SHOCKED' => 'Shocked', - 'SMILIES_SMILE' => 'Smile', - 'SMILIES_SURPRISED' => 'Surprised', - 'SMILIES_TWISTED_EVIL' => 'Twisted Evil', - 'SMILIES_UBER_GEEK' => 'Uber Geek', - 'SMILIES_VERY_HAPPY' => 'Very Happy', - 'SMILIES_WINK' => 'Wink', - - '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.
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.

The file update itself can be done in two different ways.

Manual Update

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.

Automatic Update with FTP

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.

', - 'UPDATE_INSTRUCTIONS' => ' - -

Release announcement

- -

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.

- -
- -

How to update your installation with the Full Package

- -

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:

- -
    -
  1. Backup all board files and the database.
  2. -
  3. Go to the phpBB.com downloads page and download the latest "Full Package" archive.
  4. -
  5. Unpack the archive.
  6. -
  7. Remove (delete) the config.php file, and the /images, /store and /files folders from the package (not your site).
  8. -
  9. Go to the ACP, Board settings, and make sure prosilver is set as the default style. If not, set it to prosilver.
  10. -
  11. Delete the /vendor and /cache folders from the board’s root folder on the host.
  12. -
  13. 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 /ext folder when uploading the new phpBB3 contents.)
  14. -
  15. Now start the update process by pointing your browser to the install folder.
  16. -
  17. Follow the steps to update the database and let that run to completion.
  18. -
  19. Via FTP or SSH delete the /install folder from the root of your board installation.

  20. -
- -

You now have a new up to date board containing all your users and posts. Follow up tasks:

-
    -
  • Update your language pack
  • -
  • Update your style

  • -
- -

How to update your installation with the Automatic Update Package

- -

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:

- -
    -
  1. Go to the phpBB.com downloads page and download the "Automatic Update Package" archive.
  2. -
  3. Unpack the archive.
  4. -
  5. Upload the complete uncompressed "install" and "vendor" folders to your phpBB root directory (where your config.php file is).

  6. -
- -

Once uploaded your board will be offline for normal users due to the install directory you uploaded now being present.

- Now start the update process by pointing your browser to the install folder.
-
- You will then be guided through the update process. You will be notified once the update is complete. -

- ', -)); - -// 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 <<< 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.
» %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:
»%s.', - 'MAKE_FOLDERS_WRITABLE' => 'Please make sure that these folders exist and are writable by the webserver then try again:
»%s.', - - 'INSTALL_TEST' => 'Test again', - - 'NO_TABLES_FOUND' => 'No tables found.', - 'TABLES_MISSING' => 'Could not find these tables
» %s.', - '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.
» 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 %2$s.', - 'SPECIFY_OPTIONS' => 'Specify conversion options', - 'FORUM_PATH' => 'Board path', - 'FORUM_PATH_EXPLAIN' => 'This is the relative path on disk to your former board from the root of this phpBB3 installation.', - '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
» %s', - 'STARTING_CONVERT' => 'Starting conversion process', - 'CONFIG_CONVERT' => 'Converting the configuration', - 'DONE' => 'Done', - 'PREPROCESS_STEP' => 'Executing pre-processing functions/queries', - 'FILLING_TABLE' => 'Filling table %s', - 'FILLING_TABLES' => 'Filling tables', - 'DB_ERR_INSERT' => 'Error while processing INSERT query.', - 'DB_ERR_LAST' => 'Error while processing query_last.', - 'DB_ERR_QUERY_FIRST' => 'Error while executing query_first.', - 'DB_ERR_QUERY_FIRST_TABLE' => 'Error while executing query_first, %s (“%s”).', - 'DB_ERR_SELECT' => 'Error while running SELECT query.', - 'STEP_PERCENT_COMPLETED' => 'Step %d of %d', - '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 entry %1$s to %2$s.', - 'SYNC_TOPICS' => 'Starting to synchronise topics', - 'SYNC_TOPIC_ID' => 'Synchronising topics from topic_id %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

%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 access your board. 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 Documentation and the support forums.', - - '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/install/update/old/language/en/migrator.php b/install/update/old/language/en/migrator.php deleted file mode 100644 index 8a82d40..0000000 --- a/install/update/old/language/en/migrator.php +++ /dev/null @@ -1,81 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - 'CONFIG_NOT_EXIST' => 'The config setting "%s" unexpectedly does not exist.', - - 'GROUP_NOT_EXIST' => 'The group "%s" unexpectedly does not exist.', - - 'MIGRATION_APPLY_DEPENDENCIES' => 'Apply dependencies of %s.', - 'MIGRATION_DATA_DONE' => 'Installed Data: %1$s; Time: %2$.2f seconds', - 'MIGRATION_DATA_IN_PROGRESS' => 'Installing Data: %1$s; Time: %2$.2f seconds', - 'MIGRATION_DATA_RUNNING' => 'Installing Data: %s.', - '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.', - 'MIGRATION_INVALID_DATA_UNKNOWN_TYPE' => 'A migration is invalid. An unknown migration tool type was encountered.', - 'MIGRATION_INVALID_DATA_UNDEFINED_TOOL' => 'A migration is invalid. An undefined migration tool was encountered.', - 'MIGRATION_INVALID_DATA_UNDEFINED_METHOD' => 'A migration is invalid. An undefined migration tool method was encountered.', - - 'MODULE_ERROR' => 'An error occurred while creating a module: %s', - 'MODULE_EXISTS' => 'A module already exists: %s', - 'MODULE_EXIST_MULTIPLE' => 'Several modules with the given parent module langname already exist: %s. Try using before/after keys to clarify the module placement.', - 'MODULE_INFO_FILE_NOT_EXIST' => 'A required module info file is missing: %2$s', - 'MODULE_NOT_EXIST' => 'A required module does not exist: %s', - - 'PARENT_MODULE_FIND_ERROR' => 'Unable to determine the parent module identifier: %s', - 'PERMISSION_NOT_EXIST' => 'The permission setting "%s" unexpectedly does not exist.', - - 'ROLE_NOT_EXIST' => 'The permission role "%s" unexpectedly does not exist.', -)); diff --git a/install/update/old/language/en/posting.php b/install/update/old/language/en/posting.php deleted file mode 100644 index 11ea648..0000000 --- a/install/update/old/language/en/posting.php +++ /dev/null @@ -1,287 +0,0 @@ - -* @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(); -} - -// 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 - -$lang = array_merge($lang, array( - 'ADD_ATTACHMENT' => 'Upload attachment', - 'ADD_ATTACHMENT_EXPLAIN' => 'If you wish to attach one or more files enter the details below.', - 'ADD_FILE' => 'Add the file', - '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_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)', - - 'BBCODE_A_HELP' => 'Inline uploaded attachment: [attachment=]filename.ext[/attachment]', - 'BBCODE_B_HELP' => 'Bold text: [b]text[/b]', - 'BBCODE_C_HELP' => 'Code display: [code]code[/code]', - 'BBCODE_D_HELP' => 'Flash: [flash=width,height]http://url[/flash]', - 'BBCODE_F_HELP' => 'Font size: [size=85]small text[/size]', - 'BBCODE_IS_OFF' => '%sBBCode%s is OFF', - 'BBCODE_IS_ON' => '%sBBCode%s is ON', - 'BBCODE_I_HELP' => 'Italic text: [i]text[/i]', - 'BBCODE_L_HELP' => 'List: [list][*]text[/list]', - 'BBCODE_LISTITEM_HELP' => 'List item: [*]text', - 'BBCODE_O_HELP' => 'Ordered list: e.g. [list=1][*]First point[/list] or [list=a][*]Point a[/list]', - 'BBCODE_P_HELP' => 'Insert image: [img]http://image_url[/img]', - 'BBCODE_Q_HELP' => 'Quote text: [quote]text[/quote]', - 'BBCODE_S_HELP' => 'Font colour: [color=red]text[/color] or [color=#FF0000]text[/color]', - 'BBCODE_U_HELP' => 'Underline text: [u]text[/u]', - 'BBCODE_W_HELP' => 'Insert URL: [url]http://url[/url] or [url=http://url]URL text[/url]', - 'BBCODE_Y_HELP' => 'List: Add list element', - 'BUMP_ERROR' => 'You cannot bump this topic so soon after the last post.', - - 'CANNOT_DELETE_REPLIED' => 'Sorry but you may only delete posts which have not been replied to.', - 'CANNOT_EDIT_POST_LOCKED' => 'This post has been locked. You can no longer edit that post.', - 'CANNOT_EDIT_TIME' => 'You can no longer edit or delete that post.', - 'CANNOT_POST_ANNOUNCE' => 'Sorry but you cannot post announcements.', - 'CANNOT_POST_STICKY' => 'Sorry but you cannot post sticky topics.', - 'CHANGE_TOPIC_TO' => 'Change topic type to', - 'CHARS_POST_CONTAINS' => array( - 1 => 'Your message contains %1$d character.', - 2 => 'Your message contains %1$d characters.', - ), - 'CHARS_SIG_CONTAINS' => array( - 1 => 'Your signature contains %1$d character.', - 2 => 'Your signature contains %1$d characters.', - ), - 'CLOSE_TAGS' => 'Close tags', - 'CURRENT_TOPIC' => 'Current topic', - - 'DELETE_FILE' => 'Delete file', - 'DELETE_MESSAGE' => 'Delete message', - 'DELETE_MESSAGE_CONFIRM' => 'Are you sure you want to delete this message?', - 'DELETE_OWN_POSTS' => 'Sorry but you can only delete your own posts.', - 'DELETE_PERMANENTLY' => 'Delete permanently', - 'DELETE_POST_CONFIRM' => 'Are you sure you want to delete this post?', - 'DELETE_POST_PERMANENTLY_CONFIRM' => 'Are you sure you want to permanently delete this post?', - 'DELETE_POST_PERMANENTLY' => array( - 1 => 'Permanently delete this post so it can not be recovered', - 2 => 'Permanently delete %1$d posts so they can not be recovered', - ), - 'DELETE_POSTS_CONFIRM' => 'Are you sure you want to delete these posts?', - 'DELETE_POSTS_PERMANENTLY_CONFIRM' => 'Are you sure you want to permanently delete these posts?', - 'DELETE_REASON' => 'Reason for deletion', - 'DELETE_REASON_EXPLAIN' => 'The specified reason for deletion will be visible to moderators.', - 'DELETE_POST_WARN' => 'Delete this post', - 'DELETE_TOPIC_CONFIRM' => 'Are you sure you want to delete this topic?', - 'DELETE_TOPIC_PERMANENTLY' => array( - 1 => 'Permanently delete this topic so it can not be recovered', - 2 => 'Permanently delete %1$d topics so they can not be recovered', - ), - 'DELETE_TOPIC_PERMANENTLY_CONFIRM' => 'Are you sure you want to permanently delete this topic?', - 'DELETE_TOPICS_CONFIRM' => 'Are you sure you want to delete these topics?', - 'DELETE_TOPICS_PERMANENTLY_CONFIRM' => 'Are you sure you want to permanently delete these topics?', - 'DISABLE_BBCODE' => 'Disable BBCode', - 'DISABLE_MAGIC_URL' => 'Do not automatically parse URLs', - 'DISABLE_SMILIES' => 'Disable smilies', - 'DISALLOWED_CONTENT' => 'The upload was rejected because the uploaded file was identified as a possible attack vector.', - 'DISALLOWED_EXTENSION' => 'The extension %s is not allowed.', - 'DRAFT_LOADED' => 'Draft loaded into posting area, you may want to finish your post now.
Your draft will be deleted after submitting this post.', - 'DRAFT_LOADED_PM' => 'Draft loaded into message area, you may want to finish your private message now.
Your draft will be deleted after submitting this private message.', - 'DRAFT_SAVED' => 'Draft successfully saved.', - 'DRAFT_TITLE' => 'Draft title', - - 'EDIT_REASON' => 'Reason for editing this post', - 'EMPTY_FILEUPLOAD' => 'The uploaded file is empty.', - 'EMPTY_MESSAGE' => 'You must enter a message when posting.', - 'EMPTY_REMOTE_DATA' => 'File could not be uploaded, please try uploading the file manually.', - - 'FLASH_IS_OFF' => '[flash] is OFF', - 'FLASH_IS_ON' => '[flash] is ON', - 'FLOOD_ERROR' => 'You cannot make another post so soon after your last.', - 'FONT_COLOR' => 'Font colour', - 'FONT_COLOR_HIDE' => 'Hide font colour', - 'FONT_HUGE' => 'Huge', - 'FONT_LARGE' => 'Large', - 'FONT_NORMAL' => 'Normal', - 'FONT_SIZE' => 'Font size', - 'FONT_SMALL' => 'Small', - 'FONT_TINY' => 'Tiny', - - 'GENERAL_UPLOAD_ERROR' => 'Could not upload attachment to %s.', - - 'IMAGES_ARE_OFF' => '[img] is OFF', - 'IMAGES_ARE_ON' => '[img] is ON', - 'INVALID_FILENAME' => '%s is an invalid filename.', - - 'LOAD' => 'Load', - 'LOAD_DRAFT' => 'Load draft', - '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.', - - 'MAX_FONT_SIZE_EXCEEDED' => 'You may only use fonts up to size %d.', - 'MAX_FLASH_HEIGHT_EXCEEDED' => array( - 1 => 'Your flash files may only be up to %d pixel high.', - 2 => 'Your flash files may only be up to %d pixels high.', - ), - 'MAX_FLASH_WIDTH_EXCEEDED' => array( - 1 => 'Your flash files may only be up to %d pixel wide.', - 2 => 'Your flash files may only be up to %d pixels wide.', - ), - 'MAX_IMG_HEIGHT_EXCEEDED' => array( - 1 => 'Your images may only be up to %1$d pixel high.', - 2 => 'Your images may only be up to %1$d pixels high.', - ), - 'MAX_IMG_WIDTH_EXCEEDED' => array( - 1 => 'Your images may only be up to %d pixel wide.', - 2 => 'Your images may only be up to %d pixels wide.', - ), - - 'MESSAGE_BODY_EXPLAIN' => array( - 0 => '', // zero means no limit, so we don't view a message here. - 1 => 'Enter your message here, it may contain no more than %d character.', - 2 => 'Enter your message here, it may contain no more than %d characters.', - ), - 'MESSAGE_DELETED' => 'This message has been deleted successfully.', - 'MORE_SMILIES' => 'View more smilies', - - 'NOTIFY_REPLY' => 'Notify me when a reply is posted', - 'NOT_UPLOADED' => 'File could not be uploaded.', - 'NO_DELETE_POLL_OPTIONS' => 'You cannot delete existing poll options.', - 'NO_PM_ICON' => 'No PM icon', - '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.
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.
Please note this is set in php.ini and cannot be overridden.', - 'PLACE_INLINE' => 'Place inline', - 'POLL_DELETE' => 'Delete poll', - 'POLL_FOR' => 'Run poll for', - 'POLL_FOR_EXPLAIN' => 'Enter 0 for a never ending poll.', - 'POLL_MAX_OPTIONS' => 'Options per user', - 'POLL_MAX_OPTIONS_EXPLAIN' => 'This is the number of options each user may select when voting.', - 'POLL_OPTIONS' => 'Poll options', - 'POLL_OPTIONS_EXPLAIN' => array( - 1 => 'Place each option on a new line. You may enter %d option.', - 2 => 'Place each option on a new line. You may enter up to %d options.', - ), - 'POLL_OPTIONS_EDIT_EXPLAIN' => array( - 1 => 'Place each option on a new line. You may enter %d option. If you remove or add options all previous votes will be reset.', - 2 => 'Place each option on a new line. You may enter up to %d options. If you remove or add options all previous votes will be reset.', - ), - 'POLL_QUESTION' => 'Poll question', - '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.', - 'POLL_VOTE_CHANGE' => 'Allow re-voting', - 'POLL_VOTE_CHANGE_EXPLAIN' => 'If enabled users are able to change their vote.', - 'POSTED_ATTACHMENTS' => 'Posted attachments', - 'POST_APPROVAL_NOTIFY' => 'You will be notified when your post has been approved.', - 'POST_CONFIRMATION' => 'Confirmation of post', - 'POST_CONFIRM_EXPLAIN' => 'To prevent automated posts the board requires you to enter a confirmation code. The code is displayed in the image you should see below. If you are visually impaired or cannot otherwise read this code please contact the %sBoard Administrator%s.', - 'POST_DELETED' => 'This post has been deleted successfully.', - 'POST_EDITED' => 'This post has been edited successfully.', - 'POST_EDITED_MOD' => 'This post has been edited successfully, but it will need to be approved by a moderator before it is publicly viewable.', - 'POST_GLOBAL' => 'Global', - 'POST_ICON' => 'Post icon', - 'POST_NORMAL' => 'Normal', - 'POST_REVIEW' => 'Post review', - 'POST_REVIEW_EDIT' => 'Post review', - 'POST_REVIEW_EDIT_EXPLAIN' => 'This post has been altered by another user while you were editing it. You may wish to review the current version of this post and adjust your edits.', - 'POST_REVIEW_EXPLAIN' => 'At least one new post has been made to this topic. You may wish to review your post in light of this.', - 'POST_STORED' => 'This message has been posted successfully.', - 'POST_STORED_MOD' => 'This message has been submitted successfully, but it will need to be approved by a moderator before it is publicly viewable.', - 'POST_TOPIC_AS' => 'Post topic as', - 'PROGRESS_BAR' => 'Progress bar', - - 'QUOTE_DEPTH_EXCEEDED' => array( - 1 => 'You may embed only %d quote within each other.', - 2 => 'You may embed only %d quotes within each other.', - ), - 'QUOTE_NO_NESTING' => 'You may not embed quotes within each other.', - - 'REMOTE_UPLOAD_TIMEOUT' => 'The specified file could not be uploaded because the request timed out.', - 'SAVE' => 'Save', - 'SAVE_DATE' => 'Saved at', - 'SAVE_DRAFT' => 'Save draft', - 'SAVE_DRAFT_CONFIRM' => 'Please note that saved drafts only include the subject and the message, any other element will be removed. Do you want to save your draft now?', - 'SMILIES' => 'Smilies', - 'SMILIES_ARE_OFF' => 'Smilies are OFF', - 'SMILIES_ARE_ON' => 'Smilies are ON', - '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/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.', - 'TOO_FEW_CHARS_LIMIT' => array( - 1 => 'You need to enter at least %1$d character.', - 2 => 'You need to enter at least %1$d characters.', - ), - 'TOO_FEW_POLL_OPTIONS' => 'You must enter at least two poll options.', - 'TOO_MANY_ATTACHMENTS' => 'Cannot add another attachment, %d is the maximum.', - 'TOO_MANY_CHARS' => 'Your message contains too many characters.', - 'TOO_MANY_CHARS_LIMIT' => array( - 2 => 'The maximum number of allowed characters is %1$d.', - ), - 'TOO_MANY_POLL_OPTIONS' => 'You have tried to enter too many poll options.', - 'TOO_MANY_SMILIES' => 'Your message contains too many smilies. The maximum number of smilies allowed is %d.', - 'TOO_MANY_URLS' => 'Your message contains too many URLs. The maximum number of URLs allowed is %d.', - 'TOO_MANY_USER_OPTIONS' => 'You cannot specify more options per user than existing poll options.', - 'TOPIC_BUMPED' => 'Topic has been bumped successfully.', - - 'UNAUTHORISED_BBCODE' => 'You cannot use certain BBCodes: %s.', - 'UNGLOBALISE_EXPLAIN' => 'To switch this topic back from being global to a normal topic, you need to select the forum you wish this topic to be displayed.', - 'UNSUPPORTED_CHARACTERS_MESSAGE' => 'Your message contains the following unsupported characters:
%s', - 'UNSUPPORTED_CHARACTERS_SUBJECT' => 'Your subject contains the following unsupported characters:
%s', - 'UPDATE_COMMENT' => 'Update comment', - 'URL_INVALID' => 'The URL you specified is invalid.', - 'URL_NOT_FOUND' => 'The file specified could not be found.', - 'URL_IS_OFF' => '[url] is OFF', - 'URL_IS_ON' => '[url] is ON', - 'USER_CANNOT_BUMP' => 'You cannot bump topics in this forum.', - 'USER_CANNOT_DELETE' => 'You cannot delete posts in this forum.', - 'USER_CANNOT_EDIT' => 'You cannot edit posts in this forum.', - 'USER_CANNOT_REPLY' => 'You cannot reply in this forum.', - 'USER_CANNOT_FORUM_POST' => 'You are not able to do posting operations on this forum due to the forum type not supporting it.', - - 'VIEW_MESSAGE' => '%sView your submitted message%s', - 'VIEW_PRIVATE_MESSAGE' => '%sView your submitted private message%s', - - 'WRONG_FILESIZE' => 'The file is too big, maximum allowed size is %1$d %2$s.', - 'WRONG_SIZE' => 'The image must be at least %1$s wide, %2$s high and at most %3$s wide and %4$s high. The submitted image is %5$s wide and %6$s high.', -)); diff --git a/install/update/old/language/en/ucp.php b/install/update/old/language/en/ucp.php deleted file mode 100644 index 2622fb5..0000000 --- a/install/update/old/language/en/ucp.php +++ /dev/null @@ -1,662 +0,0 @@ - -* @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(); -} - -// 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 - -// Privacy policy and T&C -$lang = array_merge($lang, array( - 'TERMS_OF_USE_CONTENT' => 'By accessing “%1$s” (hereinafter “we”, “us”, “our”, “%1$s”, “%2$s”), you agree to be legally bound by the following terms. If you do not agree to be legally bound by all of the following terms then please do not access and/or use “%1$s”. We may change these at any time and we’ll do our utmost in informing you, though it would be prudent to review this regularly yourself as your continued usage of “%1$s” after changes mean you agree to be legally bound by these terms as they are updated and/or amended.
-
- Our forums are powered by phpBB (hereinafter “they”, “them”, “their”, “phpBB software”, “www.phpbb.com”, “phpBB Limited”, “phpBB Teams”) which is a bulletin board solution released under the “GNU General Public License v2” (hereinafter “GPL”) and can be downloaded from www.phpbb.com. The phpBB software only facilitates internet based discussions; phpBB Limited is not responsible for what we allow and/or disallow as permissible content and/or conduct. For further information about phpBB, please see: https://www.phpbb.com/.
-
- You agree not to post any abusive, obscene, vulgar, slanderous, hateful, threatening, sexually-orientated or any other material that may violate any laws be it of your country, the country where “%1$s” is hosted or International Law. Doing so may lead to you being immediately and permanently banned, with notification of your Internet Service Provider if deemed required by us. The IP address of all posts are recorded to aid in enforcing these conditions. You agree that “%1$s” have the right to remove, edit, move or close any topic at any time should we see fit. As a user you agree to any information you have entered to being stored in a database. While this information will not be disclosed to any third party without your consent, neither “%1$s” nor phpBB shall be held responsible for any hacking attempt that may lead to the data being compromised. - ', - - 'PRIVACY_POLICY' => 'This policy explains in detail how “%1$s” along with its affiliated companies (hereinafter “we”, “us”, “our”, “%1$s”, “%2$s”) and phpBB (hereinafter “they”, “them”, “their”, “phpBB software”, “www.phpbb.com”, “phpBB Limited”, “phpBB Teams”) use any information collected during any session of usage by you (hereinafter “your information”).
-
- Your information is collected via two ways. Firstly, by browsing “%1$s” will cause the phpBB software to create a number of cookies, which are small text files that are downloaded on to your computer’s web browser temporary files. The first two cookies just contain a user identifier (hereinafter “user-id”) and an anonymous session identifier (hereinafter “session-id”), automatically assigned to you by the phpBB software. A third cookie will be created once you have browsed topics within “%1$s” and is used to store which topics have been read, thereby improving your user experience.
-
- We may also create cookies external to the phpBB software whilst browsing “%1$s”, though these are outside the scope of this document which is intended to only cover the pages created by the phpBB software. The second way in which we collect your information is by what you submit to us. This can be, and is not limited to: posting as an anonymous user (hereinafter “anonymous posts”), registering on “%1$s” (hereinafter “your account”) and posts submitted by you after registration and whilst logged in (hereinafter “your posts”).
-
- Your account will at a bare minimum contain a uniquely identifiable name (hereinafter “your user name”), a personal password used for logging into your account (hereinafter “your password”) and a personal, valid email address (hereinafter “your email”). Your information for your account at “%1$s” is protected by data-protection laws applicable in the country that hosts us. Any information beyond your user name, your password, and your email address required by “%1$s” during the registration process is either mandatory or optional, at the discretion of “%1$s”. In all cases, you have the option of what information in your account is publicly displayed. Furthermore, within your account, you have the option to opt-in or opt-out of automatically generated emails from the phpBB software.
-
- Your password is ciphered (a one-way hash) so that it is secure. However, it is recommended that you do not reuse the same password across a number of different websites. Your password is the means of accessing your account at “%1$s”, so please guard it carefully and under no circumstance will anyone affiliated with “%1$s”, phpBB or another 3rd party, legitimately ask you for your password. Should you forget your password for your account, you can use the “I forgot my password” feature provided by the phpBB software. This process will ask you to submit your user name and your email, then the phpBB software will generate a new password to reclaim your account.
- ', -)); - -// Common language entries -$lang = array_merge($lang, array( - 'ACCOUNT_ACTIVE' => 'Your account has now been activated. Thank you for registering.', - 'ACCOUNT_ACTIVE_ADMIN' => 'The account has now been activated.', - 'ACCOUNT_ACTIVE_PROFILE' => 'Your account has now been successfully reactivated.', - 'ACCOUNT_ADDED' => 'Thank you for registering, your account has been created. You may now login with your username and password.', - 'ACCOUNT_COPPA' => 'Your account has been created but has to be approved, please check your email for details.', - 'ACCOUNT_EMAIL_CHANGED' => 'Your account has been updated. However, this board requires account reactivation on email changes. An activation key has been sent to the new email address you provided. Please check your email for further information.', - 'ACCOUNT_EMAIL_CHANGED_ADMIN' => 'Your account has been updated. However, this board requires account reactivation by the administrators on email changes. An email has been sent to them and you will be informed when your account has been reactivated.', - 'ACCOUNT_INACTIVE' => 'Your account has been created. However, this board requires account activation. An activation key has been sent to the email address you provided. Please check your email for further information and also be sure to check your junk mail box. It may take a while to get the email depending on your email provider.', - 'ACCOUNT_INACTIVE_ADMIN' => 'Your account has been created. However, this board requires account activation by the administrator group. An email has been sent to them and you will be informed when your account has been activated.', - 'ACTIVATION_EMAIL_SENT' => 'The activation email has been sent to your email address.', - 'ACTIVATION_EMAIL_SENT_ADMIN' => 'The activation email has been sent to the administrators email addresses.', - 'ADD' => 'Add', - 'ADD_BCC' => 'Add [BCC]', - 'ADD_FOES' => 'Add new foes', - 'ADD_FOES_EXPLAIN' => 'You may enter several usernames each on a different line.', - 'ADD_FOLDER' => 'Add folder', - 'ADD_FRIENDS' => 'Add new friends', - 'ADD_FRIENDS_EXPLAIN' => 'You may enter several usernames each on a different line.', - 'ADD_NEW_RULE' => 'Add new rule', - 'ADD_RULE' => 'Add rule', - 'ADD_TO' => 'Add [To]', - 'ADD_USERS_UCP_EXPLAIN' => 'Here you can add new users to the group. You may select whether this group becomes the new default for the selected users. Please enter each username on a separate line.', - 'ADMIN_EMAIL' => 'Administrators can email me information', - 'AGREE' => 'I agree to these terms', - 'ALLOW_PM' => 'Allow users to send you private messages', - 'ALLOW_PM_EXPLAIN' => 'Note that administrators and moderators will always be able to send you messages.', - 'ALREADY_ACTIVATED' => 'You have already activated your account.', - '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.', - 'AUTOLOGIN_SESSION_KEYS_DELETED'=> 'The selected "Remember Me" login keys were successfully deleted.', - 'AVATAR_CATEGORY' => 'Category', - 'AVATAR_DRIVER_GRAVATAR_TITLE' => 'Gravatar', - 'AVATAR_DRIVER_GRAVATAR_EXPLAIN'=> 'Gravatar is a service that allows you to maintain the same avatar across multiple websites. Visit Gravatar for more information.', - 'AVATAR_DRIVER_LOCAL_TITLE' => 'Gallery avatar', - 'AVATAR_DRIVER_LOCAL_EXPLAIN' => 'You can choose your avatar from a locally available set of avatars.', - 'AVATAR_DRIVER_REMOTE_TITLE' => 'Remote avatar', - 'AVATAR_DRIVER_REMOTE_EXPLAIN' => 'Link to avatar images from another website.', - 'AVATAR_DRIVER_UPLOAD_TITLE' => 'Upload avatar', - 'AVATAR_DRIVER_UPLOAD_EXPLAIN' => 'Upload your own custom avatar.', - 'AVATAR_EXPLAIN' => 'Maximum dimensions; width: %1$s, height: %2$s, file size: %3$.2f KiB.', - 'AVATAR_EXPLAIN_NO_FILESIZE' => 'Maximum dimensions; width: %1$s, height: %2$s.', - 'AVATAR_FEATURES_DISABLED' => 'The avatar functionality is currently disabled.', - 'AVATAR_GALLERY' => 'Local gallery', - 'AVATAR_GENERAL_UPLOAD_ERROR' => 'Could not upload avatar to %s.', - 'AVATAR_NOT_ALLOWED' => 'Your avatar cannot be displayed because avatars have been disallowed.', - 'AVATAR_PAGE' => 'Page', - 'AVATAR_SELECT' => 'Select your avatar', - 'AVATAR_TYPE' => 'Avatar type', - 'AVATAR_TYPE_NOT_ALLOWED' => 'Your current avatar cannot be displayed because its type has been disallowed.', - - 'BACK_TO_DRAFTS' => 'Back to saved drafts', - 'BACK_TO_LOGIN' => 'Back to login screen', - '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 date() function.', - 'BOARD_LANGUAGE' => 'My language', - 'BOARD_STYLE' => 'My board style', - 'BOARD_TIMEZONE' => 'My timezone', - 'BOOKMARKS' => 'Bookmarks', - 'BOOKMARKS_EXPLAIN' => 'You can bookmark topics for future reference. Select the checkbox for any bookmark you wish to delete, then press the Remove marked bookmarks button.', - 'BOOKMARKS_DISABLED' => 'Bookmarks are disabled on this board.', - 'BOOKMARKS_REMOVED' => 'Bookmarks removed successfully.', - - 'CANNOT_EDIT_MESSAGE_TIME' => 'You can no longer edit or delete that message.', - 'CANNOT_MOVE_TO_SAME_FOLDER'=> 'Messages cannot be moved to the folder you want to remove.', - 'CANNOT_MOVE_FROM_SPECIAL' => 'Messages cannot be moved from the outbox.', - 'CANNOT_RENAME_FOLDER' => 'This folder cannot be renamed.', - 'CANNOT_REMOVE_FOLDER' => 'This folder cannot be removed.', - 'CHANGE_DEFAULT_GROUP' => 'Change default group', - 'CHANGE_PASSWORD' => 'Change password', - 'CLICK_GOTO_FOLDER' => '%1$sGo to your “%3$s” folder%2$s', - 'CLICK_RETURN_FOLDER' => '%1$sReturn to your “%3$s” folder%2$s', - 'CONFIRMATION' => 'Confirmation of registration', - 'CONFIRM_CHANGES' => 'Confirm changes', - 'CONFIRM_EXPLAIN' => 'To prevent automated registrations the board requires you to enter a confirmation code. The code is displayed in the image you should see below. If you are visually impaired or cannot otherwise read this code please contact the %sBoard Administrator%s.', - 'VC_REFRESH' => 'Refresh confirmation code', - 'VC_REFRESH_EXPLAIN' => 'If you cannot read the code you can request a new one by clicking the button.', - - 'CONFIRM_PASSWORD' => 'Confirm password', - 'CONFIRM_PASSWORD_EXPLAIN' => 'You only need to confirm your password if you changed it above.', - 'COPPA_BIRTHDAY' => 'To continue with the registration procedure please tell us when you were born.', - 'COPPA_COMPLIANCE' => 'COPPA compliance', - 'COPPA_EXPLAIN' => 'Please note that clicking submit will create your account. However it cannot be activated until a parent or guardian approves your registration. You will be emailed a copy of the necessary form with details of where to send it.', - 'CREATE_FOLDER' => 'Add folder…', - 'CURRENT_IMAGE' => 'Current image', - 'CURRENT_PASSWORD' => 'Current password', - 'CURRENT_PASSWORD_EXPLAIN' => 'You must enter your current password if you wish to alter your email address or username.', - 'CURRENT_CHANGE_PASSWORD_EXPLAIN' => 'To change your password, your email address, or your username, you must enter your current password.', - 'CUR_PASSWORD_EMPTY' => 'You did not enter your current password.', - 'CUR_PASSWORD_ERROR' => 'The current password you entered is incorrect.', - 'CUSTOM_DATEFORMAT' => 'Custom…', - - 'DEFAULT_ACTION' => 'Default action', - 'DEFAULT_ACTION_EXPLAIN' => 'This action will be triggered if none of the above is applicable.', - 'DEFAULT_ADD_SIG' => 'Attach my signature by default', - 'DEFAULT_BBCODE' => 'Enable BBCode by default', - 'DEFAULT_NOTIFY' => 'Notify me upon replies by default', - 'DEFAULT_SMILIES' => 'Enable smilies by default', - 'DEFINED_RULES' => 'Defined rules', - 'DELETED_TOPIC' => 'Topic has been removed.', - 'DELETE_ATTACHMENT' => 'Delete attachment', - 'DELETE_ATTACHMENTS' => 'Delete attachments', - 'DELETE_ATTACHMENT_CONFIRM' => 'Are you sure you want to delete this attachment?', - 'DELETE_ATTACHMENTS_CONFIRM'=> 'Are you sure you want to delete these attachments?', - 'DELETE_AVATAR' => 'Delete image', - 'DELETE_COOKIES_CONFIRM' => 'Are you sure you want to delete all cookies set by this board?', - 'DELETE_MARKED_PM' => 'Delete marked messages', - 'DELETE_MARKED_PM_CONFIRM' => 'Are you sure you want to delete all marked messages?', - 'DELETE_OLDEST_MESSAGES' => 'Delete oldest messages', - 'DELETE_MESSAGE' => 'Delete message', - 'DELETE_MESSAGE_CONFIRM' => 'Are you sure you want to delete this private message?', - 'DELETE_MESSAGES_IN_FOLDER' => 'Delete all messages within removed folder', - 'DELETE_RULE' => 'Delete rule', - 'DELETE_RULE_CONFIRM' => 'Are you sure you want to delete this rule?', - 'DEMOTE_SELECTED' => 'Demote selected', - 'DISABLE_CENSORS' => 'Enable word censoring', - 'DISPLAY_GALLERY' => 'Display gallery', - 'DOMAIN_NO_MX_RECORD_EMAIL' => 'The entered email domain has no valid MX record.', - 'DOWNLOADS' => 'Downloads', - 'DRAFTS_DELETED' => 'All selected drafts were successfully deleted.', - 'DRAFTS_EXPLAIN' => 'Here you can view, edit and delete your saved drafts.', - 'DRAFT_UPDATED' => 'Draft successfully updated.', - - 'EDIT_DRAFT_EXPLAIN' => 'Here you are able to edit your draft. Drafts do not contain attachment and poll information.', - 'EMAIL_BANNED_EMAIL' => 'The email address you entered is not allowed to be used.', - 'EMAIL_REMIND' => 'This must be the email address associated with your account. If you have not changed this via your user control panel then it is the email address you registered your account with.', - 'EMAIL_TAKEN_EMAIL' => 'The entered email address is already in use.', - 'EMPTY_DRAFT' => 'You must enter a message to submit your changes.', - 'EMPTY_DRAFT_TITLE' => 'You must enter a draft title.', - 'EXPORT_AS_XML' => 'Export as XML', - 'EXPORT_AS_CSV' => 'Export as CSV', - 'EXPORT_AS_CSV_EXCEL' => 'Export as CSV (Excel)', - 'EXPORT_AS_TXT' => 'Export as TXT', - 'EXPORT_AS_MSG' => 'Export as MSG', - 'EXPORT_FOLDER' => 'Export this view', - - 'FIELD_REQUIRED' => 'The field “%s” must be completed.', - 'FIELD_TOO_SHORT' => array( - 1 => 'The field “%2$s” is too short, a minimum of %1$d character is required.', - 2 => 'The field “%2$s” is too short, a minimum of %1$d characters is required.', - ), - 'FIELD_TOO_LONG' => array( - 1 => 'The field “%2$s” is too long, a maximum of %1$d character is allowed.', - 2 => 'The field “%2$s” is too long, a maximum of %1$d characters is allowed.', - ), - 'FIELD_TOO_SMALL' => 'The value of “%2$s” is too small, a minimum value of %1$d is required.', - 'FIELD_TOO_LARGE' => 'The value of “%2$s” is too large, a maximum value of %1$d is allowed.', - 'FIELD_INVALID_CHARS_INVALID' => 'The field “%s” has invalid characters.', - 'FIELD_INVALID_CHARS_NUMBERS_ONLY' => 'The field “%s” has invalid characters, only numbers are allowed.', - 'FIELD_INVALID_CHARS_ALPHA_DOTS' => 'The field “%s” has invalid characters, only alphanumeric or . characters are allowed.', - 'FIELD_INVALID_CHARS_ALPHA_ONLY' => 'The field “%s” has invalid characters, only alphanumeric characters are allowed.', - 'FIELD_INVALID_CHARS_ALPHA_PUNCTUATION' => 'The field “%s” has invalid characters, only alphanumeric or _,-. characters are allowed and the first character must be alphabetic.', - 'FIELD_INVALID_CHARS_ALPHA_SPACERS' => 'The field “%s” has invalid characters, only alphanumeric, space or -+_[] characters are allowed.', - 'FIELD_INVALID_CHARS_ALPHA_UNDERSCORE' => 'The field “%s” has invalid characters, only alphanumeric or _ characters are allowed.', - 'FIELD_INVALID_CHARS_LETTER_NUM_DOTS' => 'The field “%s” has invalid characters, only letter, number or . characters are allowed.', - 'FIELD_INVALID_CHARS_LETTER_NUM_ONLY' => 'The field “%s” has invalid characters, only letter and number characters are allowed.', - 'FIELD_INVALID_CHARS_LETTER_NUM_PUNCTUATION' => 'The field “%s” has invalid characters, only letter, number or _,-. characters are allowed and the first character must be alphabetic.', - 'FIELD_INVALID_CHARS_LETTER_NUM_SPACERS' => 'The field “%s” has invalid characters, only letter, number, space or -+_[] characters are allowed.', - 'FIELD_INVALID_CHARS_LETTER_NUM_UNDERSCORE' => 'The field “%s” has invalid characters, only letter, number or _ characters are allowed.', - 'FIELD_INVALID_DATE' => 'The field “%s” has an invalid date.', - 'FIELD_INVALID_URL' => 'The field “%s” has an invalid url.', - 'FIELD_INVALID_VALUE' => 'The field “%s” has an invalid value.', - - 'FOE_MESSAGE' => 'Message from foe', - 'FOES_EXPLAIN' => 'Foes are users which will be ignored by default. Posts by these users will not be fully visible. Personal messages from foes are still permitted. Please note that you cannot ignore moderators or administrators.', - 'FOES_UPDATED' => 'Your foes list has been updated successfully.', - 'FOLDER_ADDED' => 'Folder successfully added.', - 'FOLDER_MESSAGE_STATUS' => array( - 1 => '%2$d out of %1$s stored', - 2 => '%2$d out of %1$s stored', - ), - 'FOLDER_NAME_EMPTY' => 'You must enter a name for this folder.', - 'FOLDER_NAME_EXIST' => 'Folder %s already exists.', - 'FOLDER_OPTIONS' => 'Folder options', - 'FOLDER_RENAMED' => 'Folder successfully renamed.', - 'FOLDER_REMOVED' => 'Folder successfully removed.', - 'FOLDER_STATUS_MSG' => array( - 1 => 'Folder is %3$d%% full (%2$d out of %1$s stored)', - 2 => 'Folder is %3$d%% full (%2$d out of %1$s stored)', - ), - 'FORWARD_PM' => 'Forward PM', - 'FORCE_PASSWORD_EXPLAIN' => 'Before you may continue browsing the board you are required to change your password.', - 'FRIEND_MESSAGE' => 'Message from friend', - 'FRIENDS' => 'Friends', - 'FRIENDS_EXPLAIN' => 'Friends enable you quick access to members you communicate with frequently. If the template has relevant support any posts made by a friend may be highlighted.', - 'FRIENDS_OFFLINE' => 'Offline', - 'FRIENDS_ONLINE' => 'Online', - 'FRIENDS_UPDATED' => 'Your friends list has been updated successfully.', - 'FULL_FOLDER_OPTION_CHANGED'=> 'The action to take when a folder is full has been changed successfully.', - 'FWD_ORIGINAL_MESSAGE' => '-------- Original Message --------', - 'FWD_SUBJECT' => 'Subject: %s', - 'FWD_DATE' => 'Date: %s', - 'FWD_FROM' => 'From: %s', - 'FWD_TO' => 'To: %s', - - 'GLOBAL_ANNOUNCEMENT' => 'Global announcement', - - 'GRAVATAR_AVATAR_EMAIL' => 'Gravatar email', - 'GRAVATAR_AVATAR_EMAIL_EXPLAIN' => 'Enter the email address you used for registering your account on Gravatar.', - 'GRAVATAR_AVATAR_SIZE' => 'Avatar dimensions', - 'GRAVATAR_AVATAR_SIZE_EXPLAIN' => 'Specify the width and height of the avatar, leave blank to attempt automatic verification.', - - 'HIDE_ONLINE' => 'Hide my online status', - 'HIDE_ONLINE_EXPLAIN' => 'Changing this setting won’t become effective until your next visit to the board.', - 'HOLD_NEW_MESSAGES' => 'Do not accept new messages (New messages will be held back until enough space is available)', - 'HOLD_NEW_MESSAGES_SHORT' => 'New messages will be held back', - - 'IF_FOLDER_FULL' => 'If folder is full', - '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.', - - 'JOIN_SELECTED' => 'Join selected', - - 'LANGUAGE' => 'Language', - 'LINK_REMOTE_AVATAR' => 'Link off-site', - 'LINK_REMOTE_AVATAR_EXPLAIN'=> 'Enter the URL of the location containing the avatar image you wish to link to.', - 'LINK_REMOTE_SIZE' => 'Avatar dimensions', - 'LINK_REMOTE_SIZE_EXPLAIN' => 'Specify the width and height of the avatar, leave blank to attempt automatic verification.', - 'LOGIN_EXPLAIN_UCP' => 'Please login in order to access the User Control Panel.', - 'LOGIN_LINK' => 'Link or register your account on an external service with your board account', - 'LOGIN_LINK_EXPLAIN' => 'You have attempted to login with an external service that is not yet connected to an account on this board. You must now either link this account to an existing account or create a new account.', - 'LOGIN_LINK_MISSING_DATA' => 'Data that is necessary to link your account with an external service is not available. Please restart the login process.', - 'LOGIN_LINK_NO_DATA_PROVIDED' => 'No data has been provided to this page to link an external account to a forum account. Please contact the board administrator if you continue to experience problems.', - 'LOGIN_KEY' => 'Login Key', - 'LOGIN_TIME' => 'Login Time', - 'LOGIN_REDIRECT' => 'You have been successfully logged in.', - 'LOGOUT_FAILED' => 'You were not logged out, as the request did not match your session. Please contact the board administrator if you continue to experience problems.', - 'LOGOUT_REDIRECT' => 'You have been successfully logged out.', - - 'MARK_IMPORTANT' => 'Mark/Unmark as important', - 'MARKED_MESSAGE' => 'Marked message', - 'MAX_FOLDER_REACHED' => 'Maximum number of allowed user defined folders reached.', - 'MESSAGE_BY_AUTHOR' => 'by', - 'MESSAGE_COLOURS' => 'Message colours', - 'MESSAGE_DELETED' => 'Message successfully deleted.', - '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', - 'MESSAGES_DELETED' => 'Messages successfully deleted', - 'MOVE_DELETED_MESSAGES_TO' => 'Move messages from removed folder to', - 'MOVE_DOWN' => 'Move down', - 'MOVE_MARKED_TO_FOLDER' => 'Move marked to %s', - 'MOVE_PM_ERROR' => array( - 1 => 'An error occurred while moving the messages to the new folder, only %2$d out of %1$s was moved.', - 2 => 'An error occurred while moving the messages to the new folder, only %2$d out of %1$s were moved.', - ), - 'MOVE_TO_FOLDER' => 'Move to folder', - 'MOVE_UP' => 'Move up', - - 'NEW_FOLDER_NAME' => 'New folder name', - 'NEW_PASSWORD' => 'New password', - 'NEW_PASSWORD_CONFIRM_EMPTY' => 'You did not enter a confirm password.', - 'NEW_PASSWORD_ERROR' => 'The passwords you entered do not match.', - - 'NOTIFICATIONS_MARK_ALL_READ' => 'Mark all notifications read', - 'NOTIFICATIONS_MARK_ALL_READ_CONFIRM' => 'Are you sure you want to mark all notifications read?', - 'NOTIFICATIONS_MARK_ALL_READ_SUCCESS' => 'All notifications have been marked read.', - 'NOTIFICATION_GROUP_MISCELLANEOUS' => 'Miscellaneous Notifications', - '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', - 'NOTIFICATION_TYPE_BOOKMARK' => 'Someone replies to a topic you have bookmarked', - 'NOTIFICATION_TYPE_GROUP_REQUEST' => 'Someone requests to join a group you lead', - 'NOTIFICATION_TYPE_IN_MODERATION_QUEUE' => 'A post or topic needs approval', - 'NOTIFICATION_TYPE_MODERATION_QUEUE' => 'Your topics/posts are approved or disapproved by a moderator', - 'NOTIFICATION_TYPE_PM' => 'Someone sends you a private message', - 'NOTIFICATION_TYPE_POST' => 'Someone replies to a topic to which you are subscribed', - 'NOTIFICATION_TYPE_QUOTE' => 'Someone quotes you in a post', - 'NOTIFICATION_TYPE_REPORT' => 'Someone reports a post', - 'NOTIFICATION_TYPE_TOPIC' => 'Someone creates a topic in a forum to which you are subscribed', - 'NOTIFICATION_TYPE_ADMIN_ACTIVATE_USER' => 'User requiring activation', - - 'NOTIFY_METHOD' => 'Notification method', - 'NOTIFY_METHOD_BOTH' => 'Both', - 'NOTIFY_METHOD_EMAIL' => 'Email only', - 'NOTIFY_METHOD_EXPLAIN' => 'Method for sending messages sent via this board.', - 'NOTIFY_METHOD_IM' => 'Jabber only', - 'NOTIFY_ON_PM' => 'Notify me on new private messages', - 'NOT_ADDED_FRIENDS_ANONYMOUS' => 'You cannot add the anonymous user to your friends list.', - 'NOT_ADDED_FRIENDS_BOTS' => 'You cannot add bots to your friends list.', - 'NOT_ADDED_FRIENDS_FOES' => 'You cannot add users to your friends list who are on your foes list.', - 'NOT_ADDED_FRIENDS_SELF' => 'You cannot add yourself to the friends list.', - 'NOT_ADDED_FOES_MOD_ADMIN' => 'You cannot add administrators and moderators to your foes list.', - 'NOT_ADDED_FOES_ANONYMOUS' => 'You cannot add the anonymous user to your foes list.', - 'NOT_ADDED_FOES_BOTS' => 'You cannot add bots to your foes list.', - 'NOT_ADDED_FOES_FRIENDS' => 'You cannot add users to your foes list who are on your friends list.', - 'NOT_ADDED_FOES_SELF' => 'You cannot add yourself to the foes list.', - 'NOT_AGREE' => 'I do not agree to these terms', - 'NOT_ENOUGH_SPACE_FOLDER' => 'The destination folder “%s” seems to be full. The requested action has not been taken.', - 'NOT_MOVED_MESSAGES' => array( - 1 => 'You have %d private message currently on hold because of full folder.', - 2 => 'You have %d private messages currently on hold because of full folder.', - ), - 'NO_ACTION_MODE' => 'No message action specified.', - 'NO_AUTHOR' => 'No author defined for this message', - 'NO_AVATAR' => 'No avatar selected', - 'NO_AVATAR_CATEGORY' => 'None', - - 'NO_AUTH_DELETE_MESSAGE' => 'You are not authorised to delete private messages.', - '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_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.', - - 'NO_BCC_RECIPIENT' => 'None', - 'NO_BOOKMARKS' => 'You have no bookmarks.', - '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', - 'NO_FRIENDS_ONLINE' => 'No friends online', - 'NO_GROUP_SELECTED' => 'No group specified.', - 'NO_IMPORTANT_NEWS' => 'No important announcements present.', - 'NO_MESSAGE' => 'Private message could not be found.', - 'NO_NEW_FOLDER_NAME' => 'You have to specify a new folder name.', - 'NO_NEWER_PM' => 'No newer messages.', - 'NO_OLDER_PM' => 'No older messages.', - 'NO_PASSWORD_SUPPLIED' => 'You cannot login without a password.', - 'NO_RECIPIENT' => 'No recipient defined.', - 'NO_RULES_DEFINED' => 'No rules defined.', - 'NO_SAVED_DRAFTS' => 'No drafts saved.', - 'NO_TO_RECIPIENT' => 'None', - 'NO_WATCHED_FORUMS' => 'You are not subscribed to any forums.', - 'NO_WATCHED_SELECTED' => 'You have not selected any subscribed topics or forums.', - 'NO_WATCHED_TOPICS' => 'You are not subscribed to any topics.', - - 'PASS_TYPE_ALPHA_EXPLAIN' => 'Password must be between %1$s and %2$s long, must contain letters in mixed case and must contain numbers.', - 'PASS_TYPE_ANY_EXPLAIN' => 'Must be between %1$s and %2$s.', - 'PASS_TYPE_CASE_EXPLAIN' => 'Password must be between %1$s and %2$s long and must contain letters in mixed case.', - '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_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 %s, you are now able to browse the board with this user’s permissions.
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.', - 'PM_FROM' => 'From', - 'PM_FROM_REMOVED_AUTHOR' => 'This message was sent by a user no longer registered.', - 'PM_ICON' => 'PM icon', - 'PM_INBOX' => 'Inbox', - 'PM_MARK_ALL_READ' => 'Mark all messages read', - 'PM_MARK_ALL_READ_SUCCESS' => 'All private messages in this folder have been marked read', - 'PM_NO_USERS' => 'The requested users to be added do not exist.', - 'PM_OUTBOX' => 'Outbox', - 'PM_SENTBOX' => 'Sent messages', - 'PM_SUBJECT' => 'Message subject', - 'PM_TO' => 'Send to', - 'PM_TOOLS' => 'Message tools', - 'PM_USERS_REMOVED_NO_PERMISSION' => 'Some users couldn’t be added as they do not have permission to read private messages.', - 'PM_USERS_REMOVED_NO_PM' => 'Some users couldn’t be added as they have disabled private message receipt.', - 'POST_EDIT_PM' => 'Edit message', - 'POST_FORWARD_PM' => 'Forward message', - 'POST_NEW_PM' => 'Compose message', - 'POST_PM_LOCKED' => 'Private messaging is locked.', - 'POST_PM_POST' => 'Quote post', - 'POST_QUOTE_PM' => 'Quote message', - 'POST_REPLY_PM' => 'Reply to message', - 'PRINT_PM' => 'Print view', - 'PREFERENCES_UPDATED' => 'Your preferences have been updated.', - 'PROFILE_INFO_NOTICE' => 'Please note that this information may be viewable to other members. Be careful when including any personal details. Any fields marked with a * must be completed.', - 'PROFILE_UPDATED' => 'Your profile has been updated.', - 'PROFILE_AUTOLOGIN_KEYS' => 'The "Remember Me" login keys automatically log you in when you visit the board. If you logout, the remember me login key is deleted only on the computer you are using to logout. Here you can see remember login keys created on other computers you used to access this site.', - 'PROFILE_NO_AUTOLOGIN_KEYS' => 'There are no saved "Remember Me" login keys.', - - 'RECIPIENT' => 'Recipient', - 'RECIPIENTS' => 'Recipients', - 'REGISTRATION' => 'Registration', - 'RELEASE_MESSAGES' => '%sRelease all on-hold messages%s… they will be re-sorted into the appropriate folder if enough space is made available.', - 'REMOVE_ADDRESS' => 'Remove address', - 'REMOVE_SELECTED_BOOKMARKS' => 'Remove selected bookmarks', - 'REMOVE_SELECTED_BOOKMARKS_CONFIRM' => 'Are you sure you want to delete all selected bookmarks?', - 'REMOVE_BOOKMARK_MARKED' => 'Remove marked bookmarks', - 'REMOVE_FOLDER' => 'Remove folder', - 'REMOVE_FOLDER_CONFIRM' => 'Are you sure you want to remove this folder?', - 'RENAME' => 'Rename', - 'RENAME_FOLDER' => 'Rename folder', - 'REPLIED_MESSAGE' => 'Replied to message', - 'REPLY_TO_ALL' => 'Reply to sender and all recipients.', - 'REPORT_PM' => 'Report private message', - 'RESIGN_SELECTED' => 'Resign selected', - 'RETURN_FOLDER' => '%1$sReturn to previous folder%2$s', - 'RETURN_UCP' => '%sReturn to the User Control Panel%s', - 'RULE_ADDED' => 'Rule successfully added.', - 'RULE_ALREADY_DEFINED' => 'This rule was defined previously.', - 'RULE_DELETED' => 'Rule successfully removed.', - 'RULE_LIMIT_REACHED' => 'You cannot add more PM rules. You have reached the maximum number of rules.', - 'RULE_NOT_DEFINED' => 'Rule not correctly specified.', - 'RULE_REMOVED_MESSAGES' => array( - 1 => '%d private message was removed due to private message filters.', - 2 => '%d private messages were removed due to private message filters.', - ), - - 'SAME_PASSWORD_ERROR' => 'The new password you entered is the same as your current password.', - 'SEARCH_YOUR_POSTS' => 'Show your posts', - 'SEND_PASSWORD' => 'Send password', - 'SENT_AT' => 'Sent', // Used before dates in private messages - 'SHOW_EMAIL' => 'Users can contact me by email', - 'SIGNATURE_EXPLAIN' => 'This is a block of text that can be added to posts you make. There is a %d character limit.', - 'SIGNATURE_PREVIEW' => 'Your signature will appear like this in posts', - 'SIGNATURE_TOO_LONG' => 'Your signature is too long.', - 'SELECT_CURRENT_TIME' => 'Select current time', - 'SELECT_TIMEZONE' => 'Select timezone', - 'SORT' => 'Sort', - 'SORT_COMMENT' => 'File comment', - 'SORT_DOWNLOADS' => 'Downloads', - 'SORT_EXTENSION' => 'Extension', - 'SORT_FILENAME' => 'Filename', - 'SORT_POST_TIME' => 'Post time', - 'SORT_SIZE' => 'File size', - - 'TIMEZONE' => 'Timezone', - 'TIMEZONE_DATE_SUGGESTION' => 'Suggestion: %s', - 'TIMEZONE_INVALID' => 'The timezone you selected is invalid.', - 'TO' => 'Recipient', - 'TO_MASS' => 'Recipients', - 'TO_ADD' => 'Add recipient', - 'TO_ADD_MASS' => 'Add recipients', - 'TO_ADD_GROUPS' => 'Add groups', - 'TOO_MANY_RECIPIENTS' => 'You tried to send a private message to too many recipients.', - 'TOO_MANY_REGISTERS' => 'You have exceeded the maximum number of registration attempts for this session. Please try again later.', - - 'UCP' => 'User Control Panel', - 'UCP_ACTIVATE' => 'Activate account', - 'UCP_ADMIN_ACTIVATE' => 'Please note that you will need to enter a valid email address before your account is activated. The administrator will review your account and if approved you will receive an email at the address you specified.', - 'UCP_ATTACHMENTS' => 'Attachments', - 'UCP_AUTH_LINK' => 'External accounts', - 'UCP_AUTH_LINK_ASK' => 'You currently have no account associated with this external service. Click the button below to link your board account to an account with this external service.', - 'UCP_AUTH_LINK_ID' => 'Unique identifier', - 'UCP_AUTH_LINK_LINK' => 'Link', - 'UCP_AUTH_LINK_MANAGE' => 'Manage external account associations', - 'UCP_AUTH_LINK_NOT_SUPPORTED' => 'Linking board accounts to external services is not supported by this board’s current authentication method.', - 'UCP_AUTH_LINK_TITLE' => 'Manage your external account associations', - 'UCP_AUTH_LINK_UNLINK' => 'Unlink', - 'UCP_COPPA_BEFORE' => 'Before %s', - 'UCP_COPPA_ON_AFTER' => 'On or after %s', - 'UCP_EMAIL_ACTIVATE' => 'Please note that you will need to enter a valid email address before your account is activated. You will receive an email at the address you provide that contains an account activation link.', - 'UCP_JABBER' => 'Jabber address', - 'UCP_LOGIN_LINK' => 'Set up an external account association', - - 'UCP_MAIN' => 'Overview', - 'UCP_MAIN_ATTACHMENTS' => 'Manage attachments', - 'UCP_MAIN_BOOKMARKS' => 'Manage bookmarks', - 'UCP_MAIN_DRAFTS' => 'Manage drafts', - 'UCP_MAIN_FRONT' => 'Front page', - 'UCP_MAIN_SUBSCRIBED' => 'Manage subscriptions', - - 'UCP_NO_ATTACHMENTS' => 'You have posted no files.', - - 'UCP_NOTIFICATION_LIST' => 'Manage notifications', - 'UCP_NOTIFICATION_LIST_EXPLAIN' => 'Here you may view all past notifications.', - 'UCP_NOTIFICATION_OPTIONS' => 'Edit notification options', - 'UCP_NOTIFICATION_OPTIONS_EXPLAIN' => 'Here you can set your preferred notification methods for the board.', - - 'UCP_PREFS' => 'Board preferences', - 'UCP_PREFS_PERSONAL' => 'Edit global settings', - 'UCP_PREFS_POST' => 'Edit posting defaults', - 'UCP_PREFS_VIEW' => 'Edit display options', - - 'UCP_PM' => 'Private messages', - 'UCP_PM_COMPOSE' => 'Compose message', - 'UCP_PM_DRAFTS' => 'Manage PM drafts', - 'UCP_PM_OPTIONS' => 'Rules, folders & settings', - 'UCP_PM_UNREAD' => 'Unread messages', - 'UCP_PM_VIEW' => 'View messages', - - 'UCP_PROFILE' => 'Profile', - 'UCP_PROFILE_AVATAR' => 'Edit avatar', - 'UCP_PROFILE_PROFILE_INFO' => 'Edit profile', - 'UCP_PROFILE_REG_DETAILS' => 'Edit account settings', - 'UCP_PROFILE_SIGNATURE' => 'Edit signature', - 'UCP_PROFILE_AUTOLOGIN_KEYS'=> 'Manage “Remember Me” login keys', - - 'UCP_USERGROUPS' => 'Usergroups', - 'UCP_USERGROUPS_MEMBER' => 'Edit memberships', - 'UCP_USERGROUPS_MANAGE' => 'Manage groups', - - 'UCP_PASSWORD_RESET_DISABLED' => 'The password reset functionality has been disabled. If you need help accessing your account, please contact the %sBoard Administrator%s', - 'UCP_REGISTER_DISABLE' => 'Creating a new account is currently not possible.', - 'UCP_REMIND' => 'Send password', - 'UCP_RESEND' => 'Send activation email', - 'UCP_WELCOME' => 'Welcome to the User Control Panel. From here you can monitor, view and update your profile, preferences, subscribed forums and topics. You can also send messages to other users (if permitted). Please ensure you read any announcements before continuing.', - 'UCP_ZEBRA' => 'Friends & Foes', - 'UCP_ZEBRA_FOES' => 'Manage foes', - 'UCP_ZEBRA_FRIENDS' => 'Manage friends', - 'UNDISCLOSED_RECIPIENT' => 'Undisclosed Recipient', - 'UNKNOWN_FOLDER' => 'Unknown folder', - 'UNWATCH_MARKED' => 'Unwatch marked', - 'UPLOAD_AVATAR_FILE' => 'Upload from your machine', - 'UPLOAD_AVATAR_URL' => 'Upload from a URL', - 'UPLOAD_AVATAR_URL_EXPLAIN' => 'Enter the URL of the location containing the image. The image will be copied to this site.', - 'USERNAME_ALPHA_ONLY_EXPLAIN' => 'Username must be between %1$s and %2$s long and use only alphanumeric characters.', - 'USERNAME_ALPHA_SPACERS_EXPLAIN'=> 'Username must be between %1$s and %2$s long and use alphanumeric, space or -+_[] characters.', - 'USERNAME_ASCII_EXPLAIN' => 'Username must be between %1$s and %2$s long and use only ASCII characters, so no special symbols.', - 'USERNAME_LETTER_NUM_EXPLAIN' => 'Username must be between %1$s and %2$s long and use only letter or number characters.', - 'USERNAME_LETTER_NUM_SPACERS_EXPLAIN'=> 'Username must be between %1$s and %2$s long and use letter, number, space or -+_[] characters.', - 'USERNAME_CHARS_ANY_EXPLAIN' => 'Length must be between %1$s and %2$s.', - 'USERNAME_TAKEN_USERNAME' => 'The username you entered is already in use, please select an alternative.', - 'USERNAME_DISALLOWED_USERNAME' => 'The username you entered has been disallowed or contains a disallowed word. Please choose a different name.', - 'USER_NOT_FOUND_OR_INACTIVE' => 'The usernames you specified could either not be found or are not activated users.', - - 'VIEW_AVATARS' => 'Display avatars', - 'VIEW_EDIT' => 'View/Edit', - 'VIEW_FLASH' => 'Display Flash animations', - 'VIEW_IMAGES' => 'Display images within posts', - 'VIEW_NEXT_HISTORY' => 'Next PM in history', - 'VIEW_NEXT_PM' => 'Next PM', - 'VIEW_PM' => 'View message', - 'VIEW_PM_INFO' => 'Message details', - 'VIEW_PM_MESSAGES' => array( - 1 => '%d message', - 2 => '%d messages', - ), - 'VIEW_PREVIOUS_HISTORY' => 'Previous PM in history', - 'VIEW_PREVIOUS_PM' => 'Previous PM', - 'VIEW_PROFILE' => 'View profile', - 'VIEW_SIGS' => 'Display signatures', - 'VIEW_SMILIES' => 'Display smilies as images', - 'VIEW_TOPICS_DAYS' => 'Display topics from previous days', - 'VIEW_TOPICS_DIR' => 'Display topic order direction', - 'VIEW_TOPICS_KEY' => 'Display topics ordering by', - 'VIEW_POSTS_DAYS' => 'Display posts from previous days', - 'VIEW_POSTS_DIR' => 'Display post order direction', - 'VIEW_POSTS_KEY' => 'Display posts ordering by', - - 'WATCHED_EXPLAIN' => 'Below is a list of forums and topics you are subscribed to. You will be notified of new posts in either. To unsubscribe mark the forum or topic and then press the Unwatch marked button.', - 'WATCHED_FORUMS' => 'Watched forums', - 'WATCHED_TOPICS' => 'Watched topics', - 'WRONG_ACTIVATION' => 'The activation key you supplied does not match any in the database.', - - 'YOUR_DETAILS' => 'Your activity', - 'YOUR_FOES' => 'Your foes', - 'YOUR_FOES_EXPLAIN' => 'To remove usernames select them and click submit.', - 'YOUR_FRIENDS' => 'Your friends', - 'YOUR_FRIENDS_EXPLAIN' => 'To remove usernames select them and click submit.', - 'YOUR_WARNINGS' => 'Your warning level', - - 'PM_ACTION' => array( - 'PLACE_INTO_FOLDER' => 'Place into folder', - 'MARK_AS_READ' => 'Mark as read', - 'MARK_AS_IMPORTANT' => 'Mark message', - 'DELETE_MESSAGE' => 'Delete message', - ), - 'PM_CHECK' => array( - 'SUBJECT' => 'Subject', - 'SENDER' => 'Sender', - 'MESSAGE' => 'Message', - 'STATUS' => 'Message status', - 'TO' => 'Sent To', - ), - 'PM_RULE' => array( - 'IS_LIKE' => 'is like', - 'IS_NOT_LIKE' => 'is not like', - 'IS' => 'is', - 'IS_NOT' => 'is not', - 'BEGINS_WITH' => 'begins with', - 'ENDS_WITH' => 'ends with', - 'IS_FRIEND' => 'is friend', - 'IS_FOE' => 'is foe', - 'IS_USER' => 'is user', - 'IS_GROUP' => 'is in usergroup', - 'ANSWERED' => 'answered', - 'FORWARDED' => 'forwarded', - 'TO_GROUP' => 'to my default usergroup', - 'TO_ME' => 'to me', - ), - - 'GROUPS_EXPLAIN' => 'Usergroups enable board admins to better administer users. By default you will be placed in a specific group, this is your default group. This group defines how you may appear to other users, for example your username colouration, avatar, rank, etc. Depending on whether the administrator allows it you may be allowed to change your default group. You may also be placed in or allowed to join other groups. Some groups may give you additional permissions to view content or increase your capabilities in other areas.', - 'GROUP_LEADER' => 'Leaderships', - 'GROUP_MEMBER' => 'Memberships', - 'GROUP_PENDING' => 'Pending memberships', - 'GROUP_NONMEMBER' => 'Non-memberships', - 'GROUP_DETAILS' => 'Group details', - - 'NO_LEADER' => 'No group leaderships', - 'NO_MEMBER' => 'No group memberships', - 'NO_PENDING' => 'No pending memberships', - 'NO_NONMEMBER' => 'No non-member groups', -)); diff --git a/install/update/old/mcp.php b/install/update/old/mcp.php deleted file mode 100644 index c4a8a66..0000000 --- a/install/update/old/mcp.php +++ /dev/null @@ -1,326 +0,0 @@ - -* @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); -$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_admin.' . $phpEx); -include($phpbb_root_path . 'includes/functions_mcp.' . $phpEx); -require($phpbb_root_path . 'includes/functions_module.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup('mcp'); - -$module = new p_master(); - -// Setting a variable to let the style designer know where he is... -$template->assign_var('S_IN_MCP', true); - -// Basic parameter data -$id = $request->variable('i', ''); - -$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']) -{ - if ($user->data['is_bot']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - login_box('', $user->lang['LOGIN_EXPLAIN_MCP']); -} - -$quickmod = (isset($_REQUEST['quickmod'])) ? true : false; -$action = $request->variable('action', ''); -$action_ary = $request->variable('action', array('' => 0)); - -$forum_action = $request->variable('forum_action', ''); -if ($forum_action !== '' && $request->variable('sort', false, false, \phpbb\request\request_interface::POST)) -{ - $action = $forum_action; -} - -if (count($action_ary)) -{ - list($action, ) = each($action_ary); -} -unset($action_ary); - -if ($mode == 'topic_logs') -{ - $id = 'logs'; - $quickmod = false; -} - -$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) -{ - // We determine the topic and forum id here, to make sure the moderator really has moderative rights on this post - $sql = 'SELECT topic_id, forum_id - FROM ' . POSTS_TABLE . " - WHERE post_id = $post_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $topic_id = (int) $row['topic_id']; - $forum_id = (int) $row['forum_id']; -} -else if ($topic_id) -{ - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . " - WHERE topic_id = $topic_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $forum_id = (int) $row['forum_id']; -} - -// If the user doesn't have any moderator powers (globally or locally) he can't access the mcp -if (!$auth->acl_getf_global('m_')) -{ - // Except he is using one of the quickmod tools for users - $user_quickmod_actions = array( - 'lock' => 'f_user_lock', - 'make_sticky' => 'f_sticky', - 'make_announce' => 'f_announce', - 'make_global' => 'f_announce_global', - 'make_normal' => array('f_announce', 'f_announce_global', 'f_sticky') - ); - - $allow_user = false; - if ($quickmod && isset($user_quickmod_actions[$action]) && $user->data['is_registered'] && $auth->acl_gets($user_quickmod_actions[$action], $forum_id)) - { - $topic_info = phpbb_get_topic_data(array($topic_id)); - if ($topic_info[$topic_id]['topic_poster'] == $user->data['user_id']) - { - $allow_user = true; - } - } - - if (!$allow_user) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } -} - -// 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'); -} - -/** -* Allow applying additional permissions to MCP access besides f_read -* -* @event core.mcp_global_f_read_auth_after -* @var string action The action the user tried to execute -* @var int forum_id The forum the user tried to access -* @var string mode The MCP module the user is trying to access -* @var p_master module Module system class -* @var bool quickmod True if the user is accessing using quickmod tools -* @var int topic_id The topic the user tried to access -* @since 3.1.3-RC1 -*/ -$vars = array( - 'action', - 'forum_id', - 'mode', - 'module', - 'quickmod', - 'topic_id', -); -extract($phpbb_dispatcher->trigger_event('core.mcp_global_f_read_auth_after', compact($vars))); - -if ($forum_id) -{ - $module->acl_forum_id = $forum_id; -} - -// Instantiate module system and generate list of available modules -$module->list_modules('mcp'); - -if ($quickmod) -{ - $mode = 'quickmod'; - - switch ($action) - { - case 'lock': - case 'unlock': - case 'lock_post': - case 'unlock_post': - case 'make_sticky': - case 'make_announce': - case 'make_global': - case 'make_normal': - case 'fork': - case 'move': - case 'delete_post': - case 'delete_topic': - case 'restore_topic': - $module->load('mcp', 'main', 'quickmod'); - return; - break; - - case 'topic_logs': - // Reset start parameter if we jumped from the quickmod dropdown - if ($request->variable('start', 0)) - { - $request->overwrite('start', 0); - } - - $module->set_active('logs', 'topic_logs'); - break; - - case 'merge_topic': - $module->set_active('main', 'forum_view'); - break; - - case 'split': - case 'merge': - $module->set_active('main', 'topic_view'); - break; - - default: - // If needed, the flag can be set to true within event listener - // to indicate that the action was handled properly - // and to pass by the trigger_error() call below - $is_valid_action = false; - - /** - * This event allows you to add custom quickmod options - * - * @event core.modify_quickmod_options - * @var object module Instance of module system class - * @var string action Quickmod option - * @var bool is_valid_action Flag indicating if the action was handled properly - * @since 3.1.0-a4 - */ - $vars = array('module', 'action', 'is_valid_action'); - extract($phpbb_dispatcher->trigger_event('core.modify_quickmod_options', compact($vars))); - - if (!$is_valid_action) - { - trigger_error($user->lang('QUICKMOD_ACTION_NOT_ALLOWED', $action), E_USER_ERROR); - } - break; - } -} -else -{ - // Select the active module - $module->set_active($id, $mode); -} - -// Hide some of the options if we don't have the relevant information to use them -if (!$post_id) -{ - $module->set_display('main', 'post_details', false); - $module->set_display('warn', 'warn_post', false); -} - -if ($mode == '' || $mode == 'unapproved_topics' || $mode == 'unapproved_posts' || $mode == 'deleted_topics' || $mode == 'deleted_posts') -{ - $module->set_display('queue', 'approve_details', false); -} - -if ($mode == '' || $mode == 'reports' || $mode == 'reports_closed' || $mode == 'pm_reports' || $mode == 'pm_reports_closed' || $mode == 'pm_report_details') -{ - $module->set_display('reports', 'report_details', false); -} - -if ($mode == '' || $mode == 'reports' || $mode == 'reports_closed' || $mode == 'pm_reports' || $mode == 'pm_reports_closed' || $mode == 'report_details') -{ - $module->set_display('pm_reports', 'pm_report_details', false); -} - -if (!$topic_id) -{ - $module->set_display('main', 'topic_view', false); - $module->set_display('logs', 'topic_logs', false); -} - -if (!$forum_id) -{ - $module->set_display('main', 'forum_view', false); - $module->set_display('logs', 'forum_logs', false); -} - -if (!$user_id && $username == '') -{ - $module->set_display('notes', 'user_notes', false); - $module->set_display('warn', 'warn_user', false); -} - -/** -* This event allows you to set display option for custom MCP modules -* -* @event core.modify_mcp_modules_display_option -* @var p_master module Module system class -* @var string mode MCP mode -* @var int user_id User id -* @var int forum_id Forum id -* @var int topic_id Topic id -* @var int post_id Post id -* @var string username User name -* @var int id Parent module id -* @since 3.1.0-b2 -*/ -$vars = array( - 'module', - 'mode', - 'user_id', - 'forum_id', - 'topic_id', - 'post_id', - 'username', - 'id', -); -extract($phpbb_dispatcher->trigger_event('core.modify_mcp_modules_display_option', compact($vars))); - -// Load and execute the relevant module -$module->load_active(); - -// Assign data to the template engine for the list of modules -$module->assign_tpl_vars(append_sid("{$phpbb_root_path}mcp.$phpEx")); - -// Generate urls for letting the moderation control panel being accessed in different modes -$template->assign_vars(array( - 'U_MCP' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main'), - 'U_MCP_FORUM' => ($forum_id) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=forum_view&f=$forum_id") : '', - 'U_MCP_TOPIC' => ($forum_id && $topic_id) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=topic_view&t=$topic_id") : '', - 'U_MCP_POST' => ($forum_id && $topic_id && $post_id) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=post_details&t=$topic_id&p=$post_id") : '', -)); - -// Generate the page, do not display/query online list -$module->display($module->get_page_title()); diff --git a/install/update/old/memberlist.php b/install/update/old/memberlist.php deleted file mode 100644 index b26d7c8..0000000 --- a/install/update/old/memberlist.php +++ /dev/null @@ -1,1776 +0,0 @@ - -* @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); -$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); - -$mode = $request->variable('mode', ''); - -if ($mode === 'contactadmin') -{ - define('SKIP_CHECK_BAN', true); - define('SKIP_CHECK_DISABLED', true); -} - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup(array('memberlist', 'groups')); - -// Setting a variable to let the style designer know where he is... -$template->assign_var('S_IN_MEMBERLIST', true); - -// Grab data -$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') -{ - send_status_line(301, 'Moved Permanently'); - redirect(append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=team')); -} - -// Check our mode... -if (!in_array($mode, array('', 'group', 'viewprofile', 'email', 'contact', 'contactadmin', 'searchuser', 'team', 'livesearch'))) -{ - trigger_error('NO_MODE'); -} - -switch ($mode) -{ - case 'email': - case 'contactadmin': - break; - - case 'livesearch': - if (!$config['allow_live_searches']) - { - trigger_error('LIVE_SEARCHES_NOT_ALLOWED'); - } - // No break - - default: - // 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('', ((isset($user->lang['LOGIN_EXPLAIN_' . strtoupper($mode)])) ? $user->lang['LOGIN_EXPLAIN_' . strtoupper($mode)] : $user->lang['LOGIN_EXPLAIN_MEMBERLIST'])); - } - break; -} - -/** @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->variable('sk', $default_key); -$sort_dir = $request->variable('sd', 'a'); - -$user_types = array(USER_NORMAL, USER_FOUNDER); -if ($auth->acl_get('a_user')) -{ - $user_types[] = USER_INACTIVE; -} - -// What do you want to do today? ... oops, I think that line is taken ... -switch ($mode) -{ - case 'team': - // Display a listing of board admins, moderators - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $page_title = $user->lang['THE_TEAM']; - $template_html = 'memberlist_team.html'; - - $sql = 'SELECT * - FROM ' . TEAMPAGE_TABLE . ' - ORDER BY teampage_position ASC'; - $result = $db->sql_query($sql, 3600); - $teampage_data = $db->sql_fetchrowset($result); - $db->sql_freeresult($result); - - $sql_ary = array( - 'SELECT' => 'g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id as ug_user_id, t.teampage_id', - - 'FROM' => array(GROUPS_TABLE => 'g'), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(TEAMPAGE_TABLE => 't'), - 'ON' => 't.group_id = g.group_id', - ), - array( - 'FROM' => array(USER_GROUP_TABLE => 'ug'), - 'ON' => 'ug.group_id = g.group_id AND ug.user_pending = 0 AND ug.user_id = ' . (int) $user->data['user_id'], - ), - ), - ); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - - $group_ids = $groups_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['group_type'] == GROUP_HIDDEN && !$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel') && $row['ug_user_id'] != $user->data['user_id']) - { - $row['group_name'] = $user->lang['GROUP_UNDISCLOSED']; - $row['u_group'] = ''; - } - else - { - $row['group_name'] = $group_helper->get_name($row['group_name']); - $row['u_group'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $row['group_id']); - } - - if ($row['teampage_id']) - { - // Only put groups into the array we want to display. - // We are fetching all groups, to ensure we got all data for default groups. - $group_ids[] = (int) $row['group_id']; - } - $groups_ary[(int) $row['group_id']] = $row; - } - $db->sql_freeresult($result); - - $sql_ary = array( - 'SELECT' => 'u.user_id, u.group_id as default_group, u.username, u.username_clean, u.user_colour, u.user_type, u.user_rank, u.user_posts, u.user_allow_pm, g.group_id', - - 'FROM' => array( - USER_GROUP_TABLE => 'ug', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(USERS_TABLE => 'u'), - 'ON' => 'ug.user_id = u.user_id', - ), - array( - 'FROM' => array(GROUPS_TABLE => 'g'), - 'ON' => 'ug.group_id = g.group_id', - ), - ), - - 'WHERE' => $db->sql_in_set('g.group_id', $group_ids, false, true) . ' AND ug.user_pending = 0', - - 'ORDER_BY' => 'u.username_clean ASC', - ); - - /** - * Modify the query used to get the users for the team page - * - * @event core.memberlist_team_modify_query - * @var array sql_ary Array containing the query - * @var array group_ids Array of group ids - * @var array teampage_data The teampage data - * @since 3.1.3-RC1 - */ - $vars = array( - 'sql_ary', - 'group_ids', - 'teampage_data', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_team_modify_query', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); - - $user_ary = $user_ids = $group_users = array(); - while ($row = $db->sql_fetchrow($result)) - { - $row['forums'] = ''; - $row['forums_ary'] = array(); - $user_ary[(int) $row['user_id']] = $row; - $user_ids[] = (int) $row['user_id']; - $group_users[(int) $row['group_id']][] = (int) $row['user_id']; - } - $db->sql_freeresult($result); - - $user_ids = array_unique($user_ids); - - if (!empty($user_ids) && $config['teampage_forums']) - { - $template->assign_var('S_DISPLAY_MODERATOR_FORUMS', true); - // Get all moderators - $perm_ary = $auth->acl_get_list($user_ids, array('m_'), false); - - foreach ($perm_ary as $forum_id => $forum_ary) - { - foreach ($forum_ary as $auth_option => $id_ary) - { - foreach ($id_ary as $id) - { - if (!$forum_id) - { - $user_ary[$id]['forums'] = $user->lang['ALL_FORUMS']; - } - else - { - $user_ary[$id]['forums_ary'][] = $forum_id; - } - } - } - } - - $sql = 'SELECT forum_id, forum_name - FROM ' . FORUMS_TABLE; - $result = $db->sql_query($sql); - - $forums = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forums[$row['forum_id']] = $row['forum_name']; - } - $db->sql_freeresult($result); - - foreach ($user_ary as $user_id => $user_data) - { - if (!$user_data['forums']) - { - foreach ($user_data['forums_ary'] as $forum_id) - { - $user_ary[$user_id]['forums_options'] = true; - if (isset($forums[$forum_id])) - { - if ($auth->acl_get('f_list', $forum_id)) - { - $user_ary[$user_id]['forums'] .= ''; - } - } - } - } - } - } - - $parent_team = 0; - foreach ($teampage_data as $team_data) - { - // If this team entry has no group, it's a category - if (!$team_data['group_id']) - { - $template->assign_block_vars('group', array( - 'GROUP_NAME' => $team_data['teampage_name'], - )); - - $parent_team = (int) $team_data['teampage_id']; - continue; - } - - $group_data = $groups_ary[(int) $team_data['group_id']]; - $group_id = (int) $team_data['group_id']; - - if (!$team_data['teampage_parent']) - { - // If the group does not have a parent category, we display the groupname as category - $template->assign_block_vars('group', array( - 'GROUP_NAME' => $group_data['group_name'], - 'GROUP_COLOR' => $group_data['group_colour'], - 'U_GROUP' => $group_data['u_group'], - )); - } - - // Display group members. - if (!empty($group_users[$group_id])) - { - foreach ($group_users[$group_id] as $user_id) - { - if (isset($user_ary[$user_id])) - { - $row = $user_ary[$user_id]; - if ($config['teampage_memberships'] == 1 && ($group_id != $groups_ary[$row['default_group']]['group_id']) && $groups_ary[$row['default_group']]['teampage_id']) - { - // Display users in their primary group, instead of the first group, when it is displayed on the teampage. - continue; - } - - $user_rank_data = phpbb_get_user_rank($row, (($row['user_id'] == ANONYMOUS) ? false : $row['user_posts'])); - - $template_vars = array( - 'USER_ID' => $row['user_id'], - 'FORUMS' => $row['forums'], - 'FORUM_OPTIONS' => (isset($row['forums_options'])) ? true : false, - 'RANK_TITLE' => $user_rank_data['title'], - - 'GROUP_NAME' => $groups_ary[$row['default_group']]['group_name'], - 'GROUP_COLOR' => $groups_ary[$row['default_group']]['group_colour'], - 'U_GROUP' => $groups_ary[$row['default_group']]['u_group'], - - 'RANK_IMG' => $user_rank_data['img'], - 'RANK_IMG_SRC' => $user_rank_data['img_src'], - - 'S_INACTIVE' => $row['user_type'] == USER_INACTIVE, - - 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($row['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $row['user_id']) : '', - - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), - 'USER_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), - 'U_VIEW_PROFILE' => get_username_string('profile', $row['user_id'], $row['username'], $row['user_colour']), - ); - - /** - * Modify the template vars for displaying the user in the groups on the teampage - * - * @event core.memberlist_team_modify_template_vars - * @var array template_vars Array containing the query - * @var array row Array containing the action user row - * @var array groups_ary Array of groups with all users that should be displayed - * @since 3.1.3-RC1 - */ - $vars = array( - 'template_vars', - 'row', - 'groups_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_team_modify_template_vars', compact($vars))); - - $template->assign_block_vars('group.user', $template_vars); - - if ($config['teampage_memberships'] != 2) - { - unset($user_ary[$user_id]); - } - } - } - } - } - - $template->assign_vars(array( - 'PM_IMG' => $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE'])) - ); - break; - - case 'contact': - - $page_title = $user->lang['IM_USER']; - $template_html = 'memberlist_im.html'; - - if (!$auth->acl_get('u_sendim')) - { - send_status_line(403, 'Forbidden'); - trigger_error('NOT_AUTHORISED'); - } - - $presence_img = ''; - switch ($action) - { - case 'jabber': - $lang = 'JABBER'; - $sql_field = 'user_jabber'; - $s_select = (@extension_loaded('xml') && $config['jab_enable']) ? 'S_SEND_JABBER' : 'S_NO_SEND_JABBER'; - $s_action = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=$action&u=$user_id"); - break; - - default: - trigger_error('NO_MODE', E_USER_ERROR); - break; - } - - // Grab relevant data - $sql = "SELECT user_id, username, user_email, user_lang, $sql_field - FROM " . USERS_TABLE . " - WHERE user_id = $user_id - AND user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_USER'); - } - else if (empty($row[$sql_field])) - { - trigger_error('IM_NO_DATA'); - } - - // Post data grab actions - switch ($action) - { - case 'jabber': - add_form_key('memberlist_messaging'); - - if ($submit && @extension_loaded('xml') && $config['jab_enable']) - { - if (check_form_key('memberlist_messaging')) - { - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $subject = sprintf($user->lang['IM_JABBER_SUBJECT'], $user->data['username'], $config['server_name']); - $message = $request->variable('message', '', true); - - if (empty($message)) - { - trigger_error('EMPTY_MESSAGE_IM'); - } - - $messenger = new messenger(false); - - $messenger->template('profile_send_im', $row['user_lang']); - $messenger->subject(htmlspecialchars_decode($subject)); - - $messenger->replyto($user->data['user_email']); - $messenger->set_addresses($row); - - $messenger->assign_vars(array( - 'BOARD_CONTACT' => phpbb_get_board_contact($config, $phpEx), - 'FROM_USERNAME' => htmlspecialchars_decode($user->data['username']), - 'TO_USERNAME' => htmlspecialchars_decode($row['username']), - 'MESSAGE' => htmlspecialchars_decode($message)) - ); - - $messenger->send(NOTIFY_IM); - - $s_select = 'S_SENT_JABBER'; - } - else - { - trigger_error('FORM_INVALID'); - } - } - break; - } - - // Send vars to the template - $template->assign_vars(array( - 'IM_CONTACT' => $row[$sql_field], - 'A_IM_CONTACT' => addslashes($row[$sql_field]), - - 'USERNAME' => $row['username'], - 'CONTACT_NAME' => $row[$sql_field], - 'SITENAME' => $config['sitename'], - - 'PRESENCE_IMG' => $presence_img, - - 'L_SEND_IM_EXPLAIN' => $user->lang['IM_' . $lang], - 'L_IM_SENT_JABBER' => sprintf($user->lang['IM_SENT_JABBER'], $row['username']), - - $s_select => true, - 'S_IM_ACTION' => $s_action) - ); - - break; - - case 'viewprofile': - // Display a profile - if ($user_id == ANONYMOUS && !$username) - { - trigger_error('NO_USER'); - } - - // Get user... - $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); - - if (!$member) - { - trigger_error('NO_USER'); - } - - // a_user admins and founder are able to view inactive users and bots to be able to manage them more easily - // Normal users are able to see at least users having only changed their profile settings but not yet reactivated. - if (!$auth->acl_get('a_user') && $user->data['user_type'] != USER_FOUNDER) - { - if ($member['user_type'] == USER_IGNORE) - { - trigger_error('NO_USER'); - } - else if ($member['user_type'] == USER_INACTIVE && $member['user_inactive_reason'] != INACTIVE_PROFILE) - { - trigger_error('NO_USER'); - } - } - - $user_id = (int) $member['user_id']; - - // Get group memberships - // Also get visiting user's groups to determine hidden group memberships if necessary. - $auth_hidden_groups = ($user_id === (int) $user->data['user_id'] || $auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? true : false; - $sql_uid_ary = ($auth_hidden_groups) ? array($user_id) : array($user_id, (int) $user->data['user_id']); - - // Do the SQL thang - $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(); - while ($row = $db->sql_fetchrow($result)) - { - $row['user_id'] = (int) $row['user_id']; - $row['group_id'] = (int) $row['group_id']; - - if ($row['user_id'] == $user_id) - { - $profile_groups[] = $row; - } - else - { - $user_groups[$row['group_id']] = $row['group_id']; - } - } - $db->sql_freeresult($result); - - // Filter out hidden groups and sort groups by name - $group_data = $group_sort = array(); - foreach ($profile_groups as $row) - { - 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; - } - unset($profile_groups); - 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) - { - $row = $group_data[$group_id]; - - $group_options .= ''; - } - unset($group_data); - unset($group_sort); - - // What colour is the zebra - $sql = 'SELECT friend, foe - FROM ' . ZEBRA_TABLE . " - WHERE zebra_id = $user_id - AND user_id = {$user->data['user_id']}"; - - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $foe = ($row['foe']) ? true : false; - $friend = ($row['friend']) ? true : false; - $db->sql_freeresult($result); - - if ($config['load_onlinetrack']) - { - $sql = 'SELECT MAX(session_time) AS session_time, MIN(session_viewonline) AS session_viewonline - FROM ' . SESSIONS_TABLE . " - WHERE session_user_id = $user_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $member['session_time'] = (isset($row['session_time'])) ? $row['session_time'] : 0; - $member['session_viewonline'] = (isset($row['session_viewonline'])) ? $row['session_viewonline'] : 0; - unset($row); - } - - if ($config['load_user_activity']) - { - display_user_activity($member); - } - - // Do the relevant calculations - $memberdays = max(1, round((time() - $member['user_regdate']) / 86400)); - $posts_per_day = $member['user_posts'] / $memberdays; - $percentage = ($config['num_posts']) ? min(100, ($member['user_posts'] / $config['num_posts']) * 100) : 0; - - - if ($member['user_sig']) - { - $parse_flags = ($member['user_sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - $member['user_sig'] = generate_text_for_display($member['user_sig'], $member['user_sig_bbcode_uid'], $member['user_sig_bbcode_bitfield'], $parse_flags, true); - } - - // We need to check if the modules 'zebra' ('friends' & 'foes' mode), 'notes' ('user_notes' mode) and 'warn' ('warn_user' mode) are accessible to decide if we can display appropriate links - $zebra_enabled = $friends_enabled = $foes_enabled = $user_notes_enabled = $warn_user_enabled = false; - - // Only check if the user is logged in - if ($user->data['is_registered']) - { - if (!class_exists('p_master')) - { - include($phpbb_root_path . 'includes/functions_module.' . $phpEx); - } - $module = new p_master(); - - $module->list_modules('ucp'); - $module->list_modules('mcp'); - - $user_notes_enabled = ($module->loaded('mcp_notes', 'user_notes')) ? true : false; - $warn_user_enabled = ($module->loaded('mcp_warn', 'warn_user')) ? true : false; - $zebra_enabled = ($module->loaded('ucp_zebra')) ? true : false; - $friends_enabled = ($module->loaded('ucp_zebra', 'friends')) ? true : false; - $foes_enabled = ($module->loaded('ucp_zebra', 'foes')) ? true : false; - - unset($module); - } - - // Custom Profile Fields - $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(); - } - - /** - * Modify user data before we display the profile - * - * @event core.memberlist_view_profile - * @var array member Array with user's data - * @var bool user_notes_enabled Is the mcp user notes module enabled? - * @var bool warn_user_enabled Is the mcp warnings module enabled? - * @var bool zebra_enabled Is the ucp zebra module enabled? - * @var bool friends_enabled Is the ucp friends module enabled? - * @var bool foes_enabled Is the ucp foes module enabled? - * @var bool friend Is the user friend? - * @var bool foe Is the user foe? - * @var array profile_fields Array with user's profile field data - * @since 3.1.0-a1 - * @changed 3.1.0-b2 Added friend and foe status - * @changed 3.1.0-b3 Added profile fields data - */ - $vars = array( - 'member', - 'user_notes_enabled', - 'warn_user_enabled', - 'zebra_enabled', - 'friends_enabled', - 'foes_enabled', - 'friend', - 'foe', - 'profile_fields', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_view_profile', compact($vars))); - - $template->assign_vars(phpbb_show_profile($member, $user_notes_enabled, $warn_user_enabled)); - - // If the user has m_approve permission or a_user permission, then list then display unapproved posts - if ($auth->acl_getf_global('m_approve') || $auth->acl_get('a_user')) - { - $sql = 'SELECT COUNT(post_id) as posts_in_queue - FROM ' . POSTS_TABLE . ' - WHERE poster_id = ' . $user_id . ' - AND ' . $db->sql_in_set('post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)); - $result = $db->sql_query($sql); - $member['posts_in_queue'] = (int) $db->sql_fetchfield('posts_in_queue'); - $db->sql_freeresult($result); - } - else - { - $member['posts_in_queue'] = 0; - } - - // 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), - - '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']), - - '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&mode=overview&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&mode=user&u=' . $user_id, true, $user->session_id) : '', - 'U_MCP_QUEUE' => ($auth->acl_getf_global('m_approve')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue', true, $user->session_id) : '', - - 'U_SWITCH_PERMISSIONS' => ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_id) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&u={$user_id}&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&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&add=' . urlencode(htmlspecialchars_decode($member['username']))) : '', - 'U_ADD_FOE' => (!$friend && !$foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&mode=foes&add=' . urlencode(htmlspecialchars_decode($member['username']))) : '', - 'U_REMOVE_FRIEND' => ($friend && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&remove=1&usernames[]=' . $user_id) : '', - 'U_REMOVE_FOE' => ($foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&remove=1&mode=foes&usernames[]=' . $user_id) : '', - - 'U_CANONICAL' => generate_board_url() . '/' . append_sid("memberlist.$phpEx", 'mode=viewprofile&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'])) - { - $template->assign_vars($profile_fields['row']); - } - - if (!empty($profile_fields['blockrow'])) - { - foreach ($profile_fields['blockrow'] as $field_data) - { - $template->assign_block_vars('custom_fields', $field_data); - } - } - - // Inactive reason/account? - if ($member['user_type'] == USER_INACTIVE) - { - $user->add_lang('acp/common'); - - $inactive_reason = $user->lang['INACTIVE_REASON_UNKNOWN']; - - switch ($member['user_inactive_reason']) - { - case INACTIVE_REGISTER: - $inactive_reason = $user->lang['INACTIVE_REASON_REGISTER']; - break; - - case INACTIVE_PROFILE: - $inactive_reason = $user->lang['INACTIVE_REASON_PROFILE']; - break; - - case INACTIVE_MANUAL: - $inactive_reason = $user->lang['INACTIVE_REASON_MANUAL']; - break; - - case INACTIVE_REMIND: - $inactive_reason = $user->lang['INACTIVE_REASON_REMIND']; - break; - } - - $template->assign_vars(array( - 'S_USER_INACTIVE' => true, - 'USER_INACTIVE_REASON' => $inactive_reason) - ); - } - - // Now generate page title - $page_title = sprintf($user->lang['VIEWING_PROFILE'], $member['username']); - $template_html = 'memberlist_view.html'; - - break; - - case 'contactadmin': - case 'email': - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $user_id = $request->variable('u', 0); - $topic_id = $request->variable('t', 0); - - if ($user_id) - { - $form_name = 'user'; - } - else if ($topic_id) - { - $form_name = 'topic'; - } - else if ($mode === 'contactadmin') - { - $form_name = 'admin'; - } - else - { - trigger_error('NO_EMAIL'); - } - - /** @var $form \phpbb\message\form */ - $form = $phpbb_container->get('message.form.' . $form_name); - - $form->bind($request); - $error = $form->check_allow(); - if ($error) - { - trigger_error($error); - } - - if ($request->is_set_post('submit')) - { - $messenger = new messenger(false); - $form->submit($messenger); - } - - $page_title = $form->get_page_title(); - $template_html = $form->get_template_file(); - $form->render($template); - - break; - - case 'livesearch': - - $username_chars = $request->variable('username', '', true); - - $sql = 'SELECT username, user_id, user_colour - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_type', $user_types) . ' - AND username_clean ' . $db->sql_like_expression(utf8_clean_string($username_chars) . $db->get_any_char()); - $result = $db->sql_query_limit($sql, 10); - $user_list = array(); - - while ($row = $db->sql_fetchrow($result)) - { - $user_list[] = array( - 'user_id' => (int) $row['user_id'], - 'result' => $row['username'], - 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'display' => get_username_string('no_profile', $row['user_id'], $row['username'], $row['user_colour']), - ); - } - $db->sql_freeresult($result); - $json_response = new \phpbb\json_response(); - $json_response->send(array( - 'keyword' => $username_chars, - 'results' => $user_list, - )); - - break; - - case 'group': - default: - // The basic memberlist - $page_title = $user->lang['MEMBERLIST']; - $template_html = 'memberlist_body.html'; - - /* @var $pagination \phpbb\pagination */ - $pagination = $phpbb_container->get('pagination'); - - // Sorting - $sort_key_text = array('a' => $user->lang['SORT_USERNAME'], 'c' => $user->lang['SORT_JOINED'], 'd' => $user->lang['SORT_POST_COUNT']); - $sort_key_sql = array('a' => 'u.username_clean', 'c' => 'u.user_regdate', 'd' => 'u.user_posts'); - - if ($config['jab_enable']) - { - $sort_key_text['k'] = $user->lang['JABBER']; - $sort_key_sql['k'] = 'u.user_jabber'; - } - - if ($auth->acl_get('a_user')) - { - $sort_key_text['e'] = $user->lang['SORT_EMAIL']; - $sort_key_sql['e'] = 'u.user_email'; - } - - if ($auth->acl_get('u_viewonline')) - { - $sort_key_text['l'] = $user->lang['SORT_LAST_ACTIVE']; - $sort_key_sql['l'] = 'u.user_lastvisit'; - } - - $sort_key_text['m'] = $user->lang['SORT_RANK']; - $sort_key_sql['m'] = 'u.user_rank'; - - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); - - $s_sort_key = ''; - foreach ($sort_key_text as $key => $value) - { - $selected = ($sort_key == $key) ? ' selected="selected"' : ''; - $s_sort_key .= ''; - } - - $s_sort_dir = ''; - foreach ($sort_dir_text as $key => $value) - { - $selected = ($sort_dir == $key) ? ' selected="selected"' : ''; - $s_sort_dir .= ''; - } - - // Additional sorting options for user search ... if search is enabled, if not - // then only admins can make use of this (for ACP functionality) - $sql_select = $sql_where_data = $sql_from = $sql_where = $order_by = ''; - - - $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'); - - // 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') || count(array_intersect($request->variable_names(\phpbb\request\request_interface::GET), $search_params)) > 0) && ($config['load_search'] || $auth->acl_get('a_'))) - { - $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->variable('joined_select', 'lt'); - $active_select = $request->variable('active_select', 'lt'); - $count_select = $request->variable('count_select', 'eq'); - - $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' => '='); - - $find_count = array('lt' => $user->lang['LESS_THAN'], 'eq' => $user->lang['EQUAL_TO'], 'gt' => $user->lang['MORE_THAN']); - $s_find_count = ''; - foreach ($find_count as $key => $value) - { - $selected = ($count_select == $key) ? ' selected="selected"' : ''; - $s_find_count .= ''; - } - - $find_time = array('lt' => $user->lang['BEFORE'], 'gt' => $user->lang['AFTER']); - $s_find_join_time = ''; - foreach ($find_time as $key => $value) - { - $selected = ($joined_select == $key) ? ' selected="selected"' : ''; - $s_find_join_time .= ''; - } - - $s_find_active_time = ''; - foreach ($find_time as $key => $value) - { - $selected = ($active_select == $key) ? ' selected="selected"' : ''; - $s_find_active_time .= ''; - } - - $sql_where .= ($username) ? ' AND u.username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($username))) : ''; - $sql_where .= ($auth->acl_get('a_user') && $email) ? ' AND u.user_email ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $email)) . ' ' : ''; - $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]) && count($joined) == 3) - { - $joined_time = gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]); - - if ($joined_time !== false) - { - $sql_where .= " AND u.user_regdate " . $find_key_match[$joined_select] . ' ' . $joined_time; - } - } - - 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; - } - } - - $sql_where .= ($search_group_id) ? " AND u.user_id = ug.user_id AND ug.group_id = $search_group_id AND ug.user_pending = 0 " : ''; - - if ($search_group_id) - { - $sql_from = ', ' . USER_GROUP_TABLE . ' ug '; - } - - if ($ipdomain && $auth->acl_getf_global('m_info')) - { - if (strspn($ipdomain, 'abcdefghijklmnopqrstuvwxyz')) - { - $hostnames = gethostbynamel($ipdomain); - - if ($hostnames !== false) - { - $ips = "'" . implode('\', \'', array_map(array($db, 'sql_escape'), preg_replace('#([0-9]{1,3}\.[0-9]{1,3}[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})#', "\\1", gethostbynamel($ipdomain)))) . "'"; - } - else - { - $ips = false; - } - } - else - { - $ips = "'" . str_replace('*', '%', $db->sql_escape($ipdomain)) . "'"; - } - - if ($ips === false) - { - // A minor fudge but it does the job :D - $sql_where .= " AND u.user_id = 0"; - } - else - { - $ip_forums = array_keys($auth->acl_getf('m_info', true)); - - $sql = 'SELECT DISTINCT poster_id - FROM ' . POSTS_TABLE . ' - WHERE poster_ip ' . ((strpos($ips, '%') !== false) ? 'LIKE' : 'IN') . " ($ips) - AND " . $db->sql_in_set('forum_id', $ip_forums); - - /** - * Modify sql query for members search by ip address / hostname - * - * @event core.memberlist_modify_ip_search_sql_query - * @var string ipdomain The host name - * @var string ips IP address list for the given host name - * @var string sql The SQL query for searching members by IP address - * @since 3.1.7-RC1 - */ - $vars = array( - 'ipdomain', - 'ips', - 'sql', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_ip_search_sql_query', compact($vars))); - - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $ip_sql = array(); - do - { - $ip_sql[] = $row['poster_id']; - } - while ($row = $db->sql_fetchrow($result)); - - $sql_where .= ' AND ' . $db->sql_in_set('u.user_id', $ip_sql); - } - else - { - // A minor fudge but it does the job :D - $sql_where .= " AND u.user_id = 0"; - } - unset($ip_forums); - - $db->sql_freeresult($result); - } - } - } - - $first_char = $request->variable('first_char', ''); - - if ($first_char == 'other') - { - for ($i = 97; $i < 123; $i++) - { - $sql_where .= ' AND u.username_clean NOT ' . $db->sql_like_expression(chr($i) . $db->get_any_char()); - } - } - else if ($first_char) - { - $sql_where .= ' AND u.username_clean ' . $db->sql_like_expression(substr($first_char, 0, 1) . $db->get_any_char()); - } - - // Are we looking at a usergroup? If so, fetch additional info - // and further restrict the user info query - if ($mode == 'group') - { - // We JOIN here to save a query for determining membership for hidden groups. ;) - $sql = 'SELECT g.*, ug.user_id, ug.group_leader - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug ON (ug.user_pending = 0 AND ug.user_id = ' . $user->data['user_id'] . " AND ug.group_id = $group_id) - WHERE g.group_id = $group_id"; - $result = $db->sql_query($sql); - $group_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$group_row) - { - trigger_error('NO_GROUP'); - } - - switch ($group_row['group_type']) - { - case GROUP_OPEN: - $group_row['l_group_type'] = 'OPEN'; - break; - - case GROUP_CLOSED: - $group_row['l_group_type'] = 'CLOSED'; - break; - - case GROUP_HIDDEN: - $group_row['l_group_type'] = 'HIDDEN'; - - // Check for membership or special permissions - if (!$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel') && $group_row['user_id'] != $user->data['user_id']) - { - trigger_error('NO_GROUP'); - } - break; - - case GROUP_SPECIAL: - $group_row['l_group_type'] = 'SPECIAL'; - break; - - case GROUP_FREE: - $group_row['l_group_type'] = 'FREE'; - break; - } - - $avatar_img = phpbb_get_group_avatar($group_row); - - // ... same for group rank - $user_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); - - if ($user_rank_data['img']) - { - $user_rank_data['img'] .= '
'; - } - } - // include modules for manage groups link display or not - // need to ensure the module is active - $can_manage_group = false; - if ($user->data['is_registered'] && $group_row['group_leader']) - { - if (!class_exists('p_master')) - { - include($phpbb_root_path . 'includes/functions_module.' . $phpEx); - } - $module = new p_master; - $module->list_modules('ucp'); - - if ($module->is_active('ucp_groups', 'manage')) - { - $can_manage_group = true; - } - unset($module); - } - - $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_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'], - - 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $user_rank_data['img'], - 'RANK_IMG_SRC' => $user_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&mode=compose&g=' . $group_id) : '', - 'U_MANAGE' => ($can_manage_group) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_groups&mode=manage') : false,) - ); - - $sql_select = ', ug.group_leader'; - $sql_from = ', ' . USER_GROUP_TABLE . ' ug '; - $order_by = 'ug.group_leader DESC, '; - - $sql_where .= " AND ug.user_pending = 0 AND u.user_id = ug.user_id AND ug.group_id = $group_id"; - $sql_where_data = " AND u.user_id = ug.user_id AND ug.group_id = $group_id"; - } - - // Sorting and order - if (!isset($sort_key_sql[$sort_key])) - { - $sort_key = $default_key; - } - - $order_by .= $sort_key_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); - - // Unfortunately we must do this here for sorting by rank, else the sort order is applied wrongly - if ($sort_key == 'm') - { - $order_by .= ', u.user_posts DESC'; - } - - /** - * Modify sql query data for members search - * - * @event core.memberlist_modify_sql_query_data - * @var string order_by SQL ORDER BY clause condition - * @var string sort_dir The sorting direction - * @var string sort_key The sorting key - * @var array sort_key_sql Arraty with the sorting conditions data - * @var string sql_from SQL FROM clause condition - * @var string sql_select SQL SELECT fields list - * @var string sql_where SQL WHERE clause condition - * @var string sql_where_data SQL WHERE clause additional conditions data - * @since 3.1.7-RC1 - */ - $vars = array( - 'order_by', - 'sort_dir', - 'sort_key', - 'sort_key_sql', - 'sql_from', - 'sql_select', - 'sql_where', - 'sql_where_data', - ); - extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_sql_query_data', compact($vars))); - - // Count the users ... - $sql = 'SELECT COUNT(u.user_id) AS total_users - FROM ' . USERS_TABLE . " u$sql_from - WHERE " . $db->sql_in_set('u.user_type', $user_types) . " - $sql_where"; - $result = $db->sql_query($sql); - $total_users = (int) $db->sql_fetchfield('total_users'); - $db->sql_freeresult($result); - - // Build a relevant pagination_url - $params = $sort_params = array(); - - // 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), - 'sd' => array('sd', 'a'), - 'form' => array('form', ''), - 'field' => array('field', ''), - 'select_single' => array('select_single', $select_single), - 'username' => array('username', '', true), - 'email' => array('email', ''), - 'jabber' => array('jabber', ''), - 'search_group_id' => array('search_group_id', 0), - 'joined_select' => array('joined_select', 'lt'), - 'active_select' => array('active_select', 'lt'), - 'count_select' => array('count_select', 'eq'), - 'joined' => array('joined', ''), - 'active' => array('active', ''), - 'count' => ($request->variable('count', '') !== '') ? array('count', 0) : array('count', ''), - 'ip' => array('ip', ''), - 'first_char' => array('first_char', ''), - ); - - $u_first_char_params = array(); - foreach ($check_params as $key => $call) - { - if (!isset($_REQUEST[$key])) - { - continue; - } - - $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; - - if ($key != 'first_char') - { - $u_first_char_params[] = $param; - } - if ($key != 'sk' && $key != 'sd') - { - $sort_params[] = $param; - } - } - - $u_hide_find_member = append_sid("{$phpbb_root_path}memberlist.$phpEx", "start=$start" . (!empty($params) ? '&' . implode('&', $params) : '')); - - if ($mode) - { - $params[] = "mode=$mode"; - $u_first_char_params[] = "mode=$mode"; - } - $sort_params[] = "mode=$mode"; - - $u_first_char_params = implode('&', $u_first_char_params); - $u_first_char_params .= ($u_first_char_params) ? '&' : ''; - - $first_characters = array(); - $first_characters[''] = $user->lang['ALL']; - for ($i = 97; $i < 123; $i++) - { - $first_characters[chr($i)] = chr($i - 32); - } - $first_characters['other'] = $user->lang['OTHER']; - - $first_char_block_vars = []; - - foreach ($first_characters as $char => $desc) - { - $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('&', $params)); - $sort_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", implode('&', $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->variable('search_group_id', 0); - $s_group_select = ''; - $group_ids = array(); - - /** - * @todo add this to a separate function (function is responsible for returning the groups the user is able to see based on the users group membership) - */ - - if ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) - { - $sql = 'SELECT group_id, group_name, group_type - FROM ' . GROUPS_TABLE; - - if (!$config['coppa_enable']) - { - $sql .= " WHERE group_name <> 'REGISTERED_COPPA'"; - } - - $sql .= ' ORDER BY group_name ASC'; - } - else - { - $sql = 'SELECT g.group_id, g.group_name, g.group_type - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ')'; - - if (!$config['coppa_enable']) - { - $sql .= " AND g.group_name <> 'REGISTERED_COPPA'"; - } - - $sql .= ' ORDER BY g.group_name ASC'; - } - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $group_ids[] = $row['group_id']; - $s_group_select .= ''; - } - $db->sql_freeresult($result); - - if ($group_selected !== 0 && !in_array($group_selected, $group_ids)) - { - trigger_error('NO_GROUP'); - } - - $template->assign_vars(array( - 'USERNAME' => $username, - 'EMAIL' => $email, - 'JABBER' => $jabber, - 'JOINED' => implode('-', $joined), - 'ACTIVE' => implode('-', $active), - 'COUNT' => $count, - 'IP' => $ipdomain, - - 'S_IP_SEARCH_ALLOWED' => ($auth->acl_getf_global('m_info')) ? true : false, - 'S_EMAIL_SEARCH_ALLOWED'=> ($auth->acl_get('a_user')) ? true : false, - 'S_JABBER_ENABLED' => $config['jab_enable'], - 'S_IN_SEARCH_POPUP' => ($form && $field) ? true : false, - 'S_SEARCH_USER' => ($mode == 'searchuser' || ($mode == '' && $submit)), - 'S_FORM_NAME' => $form, - 'S_FIELD_NAME' => $field, - 'S_SELECT_SINGLE' => $select_single, - 'S_COUNT_OPTIONS' => $s_find_count, - 'S_SORT_OPTIONS' => $s_sort_key, - 'S_JOINED_TIME_OPTIONS' => $s_find_join_time, - 'S_ACTIVE_TIME_OPTIONS' => $s_find_active_time, - 'S_GROUP_SELECT' => $s_group_select, - 'S_USER_SEARCH_ACTION' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=searchuser&form=$form&field=$field")) - ); - } - - $start = $pagination->validate_start($start, $config['topics_per_page'], $total_users); - - // Get us some users :D - $sql = "SELECT u.user_id - FROM " . USERS_TABLE . " u - $sql_from - WHERE " . $db->sql_in_set('u.user_type', $user_types) . " - $sql_where - ORDER BY $order_by"; - $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); - - $user_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_list[] = (int) $row['user_id']; - } - $db->sql_freeresult($result); - - // 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'); - foreach ($cp_row as $profile_field) - { - $template->assign_block_vars('custom_fields', $profile_field); - } - } - - $leaders_set = false; - // So, did we get any users? - if (count($user_list)) - { - // Session time?! Session time... - $sql = 'SELECT session_user_id, MAX(session_time) AS session_time - FROM ' . SESSIONS_TABLE . ' - WHERE session_time >= ' . (time() - $config['session_length']) . ' - AND ' . $db->sql_in_set('session_user_id', $user_list) . ' - GROUP BY session_user_id'; - $result = $db->sql_query($sql); - - $session_times = array(); - while ($row = $db->sql_fetchrow($result)) - { - $session_times[$row['session_user_id']] = $row['session_time']; - } - $db->sql_freeresult($result); - - // Do the SQL thang - if ($mode == 'group') - { - $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_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(); - while ($row = $db->sql_fetchrow($result)) - { - $row['session_time'] = (!empty($session_times[$row['user_id']])) ? $session_times[$row['user_id']] : 0; - $row['last_visit'] = (!empty($row['session_time'])) ? $row['session_time'] : $row['user_lastvisit']; - - $id_cache[$row['user_id']] = $row; - } - - $db->sql_freeresult($result); - - // 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 - $profile_fields_cache = $cp->grab_profile_fields_data($user_list); - - // Filter the fields we don't want to show - foreach ($profile_fields_cache as $user_id => $user_profile_fields) - { - foreach ($user_profile_fields as $field_ident => $profile_field) - { - if (!$profile_field['data']['field_show_on_ml']) - { - unset($profile_fields_cache[$user_id][$field_ident]); - } - } - } - } - - // If we sort by last active date we need to adjust the id cache due to user_lastvisit not being the last active date... - if ($sort_key == 'l') - { -// uasort($id_cache, create_function('$first, $second', "return (\$first['last_visit'] == \$second['last_visit']) ? 0 : ((\$first['last_visit'] < \$second['last_visit']) ? $lesser_than : ($lesser_than * -1));")); - usort($user_list, 'phpbb_sort_last_active'); - } - - // do we need to display contact fields as such - $use_contact_fields = false; - - /** - * Modify list of users before member row is created - * - * @event core.memberlist_memberrow_before - * @var array user_list Array containing list of users - * @var bool use_contact_fields Should we display contact fields as such? - * @since 3.1.7-RC1 - */ - $vars = array('user_list', 'use_contact_fields'); - extract($phpbb_dispatcher->trigger_event('core.memberlist_memberrow_before', compact($vars))); - - for ($i = 0, $end = count($user_list); $i < $end; ++$i) - { - $user_id = $user_list[$i]; - $row = $id_cache[$user_id]; - $is_leader = (isset($row['group_leader']) && $row['group_leader']) ? true : false; - $leaders_set = ($leaders_set || $is_leader); - - $cp_row = array(); - if ($config['load_cpf_memberlist']) - { - $cp_row = (isset($profile_fields_cache[$user_id])) ? $cp->generate_profile_fields_template_data($profile_fields_cache[$user_id], $use_contact_fields) : array(); - } - - $memberrow = array_merge(phpbb_show_profile($row, false, false, false), array( - 'ROW_NUMBER' => $i + ($start + 1), - - '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']) && count($cp_row['row'])) - { - $memberrow = array_merge($memberrow, $cp_row['row']); - } - - $template->assign_block_vars('memberrow', $memberrow); - - if (isset($cp_row['blockrow']) && count($cp_row['blockrow'])) - { - foreach ($cp_row['blockrow'] as $field_data) - { - $template->assign_block_vars('memberrow.custom_fields', $field_data); - } - } - - unset($id_cache[$user_id]); - } - } - - $pagination->generate_template_pagination($pagination_url, 'pagination', 'start', $total_users, $config['topics_per_page'], $start); - - // Generate page - $template_vars = array( - 'TOTAL_USERS' => $user->lang('LIST_USERS', (int) $total_users), - - 'PROFILE_IMG' => $user->img('icon_user_profile', $user->lang['PROFILE']), - 'PM_IMG' => $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE']), - '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']), - - 'U_FIND_MEMBER' => ($config['load_search'] || $auth->acl_get('a_')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser' . (($start) ? "&start=$start" : '') . (!empty($params) ? '&' . implode('&', $params) : '')) : '', - 'U_HIDE_FIND_MEMBER' => ($mode == 'searchuser' || ($mode == '' && $submit)) ? $u_hide_find_member : '', - 'U_LIVE_SEARCH' => ($config['allow_live_searches']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=livesearch') : false, - 'U_SORT_USERNAME' => $sort_url . '&sk=a&sd=' . (($sort_key == 'a' && $sort_dir == 'a') ? 'd' : 'a'), - 'U_SORT_JOINED' => $sort_url . '&sk=c&sd=' . (($sort_key == 'c' && $sort_dir == 'd') ? 'a' : 'd'), - 'U_SORT_POSTS' => $sort_url . '&sk=d&sd=' . (($sort_key == 'd' && $sort_dir == 'd') ? 'a' : 'd'), - 'U_SORT_EMAIL' => $sort_url . '&sk=e&sd=' . (($sort_key == 'e' && $sort_dir == 'd') ? 'a' : 'd'), - 'U_SORT_ACTIVE' => ($auth->acl_get('u_viewonline')) ? $sort_url . '&sk=l&sd=' . (($sort_key == 'l' && $sort_dir == 'd') ? 'a' : 'd') : '', - 'U_SORT_RANK' => $sort_url . '&sk=m&sd=' . (($sort_key == 'm' && $sort_dir == 'd') ? 'a' : 'd'), - 'U_LIST_CHAR' => $sort_url . '&sk=a&sd=' . (($sort_key == 'l' && $sort_dir == 'd') ? 'a' : 'd'), - - 'S_SHOW_GROUP' => ($mode == 'group') ? true : false, - 'S_VIEWONLINE' => $auth->acl_get('u_viewonline'), - 'S_LEADERS_SET' => $leaders_set, - 'S_MODE_SELECT' => $s_sort_key, - 'S_ORDER_SELECT' => $s_sort_dir, - '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 -page_header($page_title); - -$template->set_filenames(array( - 'body' => $template_html) -); -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - -page_footer(); diff --git a/install/update/old/phpbb/auth/provider/apache.php b/install/update/old/phpbb/auth/provider/apache.php deleted file mode 100644 index aa5bf64..0000000 --- a/install/update/old/phpbb/auth/provider/apache.php +++ /dev/null @@ -1,264 +0,0 @@ - -* @license 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; - -/** -* Apache authentication provider for phpBB3 -*/ -class apache extends \phpbb\auth\provider\base -{ - /** - * phpBB passwords manager - * - * @var \phpbb\passwords\manager - */ - protected $passwords_manager; - - /** - * Apache Authentication Constructor - * - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\config\config $config Config object - * @param \phpbb\passwords\manager $passwords_manager Passwords Manager object - * @param \phpbb\request\request $request Request object - * @param \phpbb\user $user User object - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $php_ext PHP file extension - */ - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request $request, \phpbb\user $user, $phpbb_root_path, $php_ext) - { - $this->db = $db; - $this->config = $config; - $this->passwords_manager = $passwords_manager; - $this->request = $request; - $this->user = $user; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - } - - /** - * {@inheritdoc} - */ - public function init() - { - if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER) || $this->user->data['username'] !== htmlspecialchars_decode($this->request->server('PHP_AUTH_USER'))) - { - return $this->user->lang['APACHE_SETUP_BEFORE_USE']; - } - return false; - } - - /** - * {@inheritdoc} - */ - public function login($username, $password) - { - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER)) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $php_auth_user = htmlspecialchars_decode($this->request->server('PHP_AUTH_USER')); - $php_auth_pw = htmlspecialchars_decode($this->request->server('PHP_AUTH_PW')); - - if (!empty($php_auth_user) && !empty($php_auth_pw)) - { - if ($php_auth_user !== $username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type - FROM ' . USERS_TABLE . " - WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - - // this is the user's first login so create an empty profile - return array( - 'status' => LOGIN_SUCCESS_CREATE_PROFILE, - 'error_msg' => false, - 'user_row' => $this->user_row($php_auth_user, $php_auth_pw), - ); - } - - // Not logged into apache - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - /** - * {@inheritdoc} - */ - public function autologin() - { - if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER)) - { - return array(); - } - - $php_auth_user = htmlspecialchars_decode($this->request->server('PHP_AUTH_USER')); - $php_auth_pw = htmlspecialchars_decode($this->request->server('PHP_AUTH_PW')); - - if (!empty($php_auth_user) && !empty($php_auth_pw)) - { - set_var($php_auth_user, $php_auth_user, 'string', true); - set_var($php_auth_pw, $php_auth_pw, 'string', true); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - return ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ? array() : $row; - } - - if (!function_exists('user_add')) - { - include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); - } - - // create the user if he does not exist yet - user_add($this->user_row($php_auth_user, $php_auth_pw)); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($php_auth_user)) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - return $row; - } - } - - return array(); - } - - /** - * This function generates an array which can be passed to the user_add - * function in order to create a user - * - * @param string $username The username of the new user. - * @param string $password The password of the new user. - * @return array Contains data that can be passed directly to - * the user_add function. - */ - private function user_row($username, $password) - { - // first retrieve default 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) - { - trigger_error('NO_GROUP'); - } - - // generate user account data - return array( - 'username' => $username, - 'user_password' => $this->passwords_manager->hash($password), - 'user_email' => '', - 'group_id' => (int) $row['group_id'], - 'user_type' => USER_NORMAL, - 'user_ip' => $this->user->ip, - 'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0, - ); - } - - /** - * {@inheritdoc} - */ - public function validate_session($user) - { - // Check if PHP_AUTH_USER is set and handle this case - if ($this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER)) - { - $php_auth_user = $this->request->server('PHP_AUTH_USER'); - - return ($php_auth_user === $user['username']) ? true : false; - } - - // PHP_AUTH_USER is not set. A valid session is now determined by the user type (anonymous/bot or not) - if ($user['user_type'] == USER_IGNORE) - { - return true; - } - - return false; - } -} diff --git a/install/update/old/phpbb/auth/provider/base.php b/install/update/old/phpbb/auth/provider/base.php deleted file mode 100644 index dea27cc..0000000 --- a/install/update/old/phpbb/auth/provider/base.php +++ /dev/null @@ -1,108 +0,0 @@ - -* @license 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; - -/** -* Base authentication provider class that all other providers should implement -*/ -abstract class base implements \phpbb\auth\provider\provider_interface -{ - /** - * {@inheritdoc} - */ - public function init() - { - return; - } - - /** - * {@inheritdoc} - */ - public function autologin() - { - return; - } - - /** - * {@inheritdoc} - */ - public function acp() - { - return; - } - - /** - * {@inheritdoc} - */ - public function get_acp_template($new_config) - { - return; - } - - /** - * {@inheritdoc} - */ - public function get_login_data() - { - return; - } - - /** - * {@inheritdoc} - */ - public function get_auth_link_data($user_id = 0) - { - return; - } - - /** - * {@inheritdoc} - */ - public function logout($data, $new_session) - { - return; - } - - /** - * {@inheritdoc} - */ - public function validate_session($user) - { - return; - } - - /** - * {@inheritdoc} - */ - public function login_link_has_necessary_data($login_link_data) - { - return; - } - - /** - * {@inheritdoc} - */ - public function link_account(array $link_data) - { - return; - } - - /** - * {@inheritdoc} - */ - public function unlink_account(array $link_data) - { - return; - } -} diff --git a/install/update/old/phpbb/auth/provider/db.php b/install/update/old/phpbb/auth/provider/db.php deleted file mode 100644 index 1adf85e..0000000 --- a/install/update/old/phpbb/auth/provider/db.php +++ /dev/null @@ -1,240 +0,0 @@ - -* @license 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; - -/** - * Database authentication provider for phpBB3 - * This is for authentication via the integrated user table - */ -class db extends \phpbb\auth\provider\base -{ - /** - * phpBB passwords manager - * - * @var \phpbb\passwords\manager - */ - protected $passwords_manager; - - /** - * DI container - * - * @var \Symfony\Component\DependencyInjection\ContainerInterface - */ - protected $phpbb_container; - - /** - * Database Authentication Constructor - * - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\config\config $config - * @param \phpbb\passwords\manager $passwords_manager - * @param \phpbb\request\request $request - * @param \phpbb\user $user - * @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container - * @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 $request, \phpbb\user $user, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, $phpbb_root_path, $php_ext) - { - $this->db = $db; - $this->config = $config; - $this->passwords_manager = $passwords_manager; - $this->request = $request; - $this->user = $user; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - $this->phpbb_container = $phpbb_container; - } - - /** - * {@inheritdoc} - */ - public function login($username, $password) - { - // Auth plugins get the password untrimmed. - // For compatibility we trim() here. - $password = trim($password); - - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $username_clean = utf8_clean_string($username); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if (($this->user->ip && !$this->config['ip_login_limit_use_forwarded']) || - ($this->user->forwarded_for && $this->config['ip_login_limit_use_forwarded'])) - { - $sql = 'SELECT COUNT(*) AS attempts - FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE attempt_time > ' . (time() - (int) $this->config['ip_login_limit_time']); - if ($this->config['ip_login_limit_use_forwarded']) - { - $sql .= " AND attempt_forwarded_for = '" . $this->db->sql_escape($this->user->forwarded_for) . "'"; - } - else - { - $sql .= " AND attempt_ip = '" . $this->db->sql_escape($this->user->ip) . "' "; - } - - $result = $this->db->sql_query($sql); - $attempts = (int) $this->db->sql_fetchfield('attempts'); - $this->db->sql_freeresult($result); - - $attempt_data = array( - 'attempt_ip' => $this->user->ip, - 'attempt_browser' => trim(substr($this->user->browser, 0, 149)), - 'attempt_forwarded_for' => $this->user->forwarded_for, - 'attempt_time' => time(), - 'user_id' => ($row) ? (int) $row['user_id'] : 0, - 'username' => $username, - 'username_clean' => $username_clean, - ); - $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $this->db->sql_build_array('INSERT', $attempt_data); - $this->db->sql_query($sql); - } - else - { - $attempts = 0; - } - - if (!$row) - { - if ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']) - { - return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $show_captcha = ($this->config['max_login_attempts'] && $row['user_login_attempts'] >= $this->config['max_login_attempts']) || - ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']); - - // If there are too many login attempts, we need to check for a confirm image - // 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); - $vc_response = $captcha->validate($row); - if ($vc_response) - { - return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', - 'user_row' => $row, - ); - } - else - { - $captcha->reset(); - } - - } - - // Check password ... - if ($this->passwords_manager->check($password, $row['user_password'], $row)) - { - // Check for old password hash... - if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32) - { - $hash = $this->passwords_manager->hash($password); - - // Update the password in the users table to the new format - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_password = '" . $this->db->sql_escape($hash) . "' - WHERE user_id = {$row['user_id']}"; - $this->db->sql_query($sql); - - $row['user_password'] = $hash; - } - - $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE user_id = ' . $row['user_id']; - $this->db->sql_query($sql); - - if ($row['user_login_attempts'] != 0) - { - // Successful, reset login attempts (the user passed all stages) - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_login_attempts = 0 - WHERE user_id = ' . $row['user_id']; - $this->db->sql_query($sql); - } - - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... set user_login_attempts to zero... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - - // Password incorrect - increase login attempts - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_login_attempts = user_login_attempts + 1 - WHERE user_id = ' . (int) $row['user_id'] . ' - AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX; - $this->db->sql_query($sql); - - // Give status about wrong password... - return array( - 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, - 'error_msg' => 'LOGIN_ERROR_PASSWORD', - 'user_row' => $row, - ); - } -} diff --git a/install/update/old/phpbb/auth/provider/ldap.php b/install/update/old/phpbb/auth/provider/ldap.php deleted file mode 100644 index 0789a62..0000000 --- a/install/update/old/phpbb/auth/provider/ldap.php +++ /dev/null @@ -1,348 +0,0 @@ - -* @license 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; - -/** - * Database authentication provider for phpBB3 - * This is for authentication via the integrated user table - */ -class ldap extends \phpbb\auth\provider\base -{ - /** - * phpBB passwords manager - * - * @var \phpbb\passwords\manager - */ - protected $passwords_manager; - - /** - * LDAP Authentication Constructor - * - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\config\config $config Config object - * @param \phpbb\passwords\manager $passwords_manager Passwords manager object - * @param \phpbb\user $user User object - */ - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\user $user) - { - $this->db = $db; - $this->config = $config; - $this->passwords_manager = $passwords_manager; - $this->user = $user; - } - - /** - * {@inheritdoc} - */ - public function init() - { - if (!@extension_loaded('ldap')) - { - return $this->user->lang['LDAP_NO_LDAP_EXTENSION']; - } - - $this->config['ldap_port'] = (int) $this->config['ldap_port']; - if ($this->config['ldap_port']) - { - $ldap = @ldap_connect($this->config['ldap_server'], $this->config['ldap_port']); - } - else - { - $ldap = @ldap_connect($this->config['ldap_server']); - } - - if (!$ldap) - { - return $this->user->lang['LDAP_NO_SERVER_CONNECTION']; - } - - @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); - @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); - - if ($this->config['ldap_user'] || $this->config['ldap_password']) - { - if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password']))) - { - return $this->user->lang['LDAP_INCORRECT_USER_PASSWORD']; - } - } - - // ldap_connect only checks whether the specified server is valid, so the connection might still fail - $search = @ldap_search( - $ldap, - htmlspecialchars_decode($this->config['ldap_base_dn']), - $this->ldap_user_filter($this->user->data['username']), - (empty($this->config['ldap_email'])) ? - array(htmlspecialchars_decode($this->config['ldap_uid'])) : - array(htmlspecialchars_decode($this->config['ldap_uid']), htmlspecialchars_decode($this->config['ldap_email'])), - 0, - 1 - ); - - if ($search === false) - { - return $this->user->lang['LDAP_SEARCH_FAILED']; - } - - $result = @ldap_get_entries($ldap, $search); - - @ldap_close($ldap); - - if (!is_array($result) || count($result) < 2) - { - return sprintf($this->user->lang['LDAP_NO_IDENTITY'], $this->user->data['username']); - } - - if (!empty($this->config['ldap_email']) && !isset($result[0][htmlspecialchars_decode($this->config['ldap_email'])])) - { - return $this->user->lang['LDAP_NO_EMAIL']; - } - - return false; - } - - /** - * {@inheritdoc} - */ - public function login($username, $password) - { - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!@extension_loaded('ldap')) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_LDAP_EXTENSION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $this->config['ldap_port'] = (int) $this->config['ldap_port']; - if ($this->config['ldap_port']) - { - $ldap = @ldap_connect($this->config['ldap_server'], $this->config['ldap_port']); - } - else - { - $ldap = @ldap_connect($this->config['ldap_server']); - } - - if (!$ldap) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); - @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); - - if ($this->config['ldap_user'] || $this->config['ldap_password']) - { - if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password']))) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - } - - $search = @ldap_search( - $ldap, - htmlspecialchars_decode($this->config['ldap_base_dn']), - $this->ldap_user_filter($username), - (empty($this->config['ldap_email'])) ? - array(htmlspecialchars_decode($this->config['ldap_uid'])) : - array(htmlspecialchars_decode($this->config['ldap_uid']), htmlspecialchars_decode($this->config['ldap_email'])), - 0, - 1 - ); - - $ldap_result = @ldap_get_entries($ldap, $search); - - if (is_array($ldap_result) && count($ldap_result) > 1) - { - if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password))) - { - @ldap_close($ldap); - - $sql ='SELECT user_id, username, user_password, user_passchg, user_email, user_type - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - unset($ldap_result); - - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... set user_login_attempts to zero... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - else - { - // retrieve default group id - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $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) - { - trigger_error('NO_GROUP'); - } - - // generate user account data - $ldap_user_row = array( - 'username' => $username, - 'user_password' => $this->passwords_manager->hash($password), - 'user_email' => (!empty($this->config['ldap_email'])) ? utf8_htmlspecialchars($ldap_result[0][htmlspecialchars_decode($this->config['ldap_email'])][0]) : '', - 'group_id' => (int) $row['group_id'], - 'user_type' => USER_NORMAL, - 'user_ip' => $this->user->ip, - 'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0, - ); - - unset($ldap_result); - - // this is the user's first login so create an empty profile - return array( - 'status' => LOGIN_SUCCESS_CREATE_PROFILE, - 'error_msg' => false, - 'user_row' => $ldap_user_row, - ); - } - } - else - { - unset($ldap_result); - @ldap_close($ldap); - - // Give status about wrong password... - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'LOGIN_ERROR_PASSWORD', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - } - - @ldap_close($ldap); - - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - /** - * {@inheritdoc} - */ - public function acp() - { - // These are fields required in the config table - return array( - 'ldap_server', 'ldap_port', 'ldap_base_dn', 'ldap_uid', 'ldap_user_filter', 'ldap_email', 'ldap_user', 'ldap_password', - ); - } - - /** - * {@inheritdoc} - */ - public function get_acp_template($new_config) - { - return array( - 'TEMPLATE_FILE' => 'auth_provider_ldap.html', - 'TEMPLATE_VARS' => array( - 'AUTH_LDAP_BASE_DN' => $new_config['ldap_base_dn'], - 'AUTH_LDAP_EMAIL' => $new_config['ldap_email'], - 'AUTH_LDAP_PASSORD' => $new_config['ldap_password'] !== '' ? '********' : '', - 'AUTH_LDAP_PORT' => $new_config['ldap_port'], - 'AUTH_LDAP_SERVER' => $new_config['ldap_server'], - 'AUTH_LDAP_UID' => $new_config['ldap_uid'], - 'AUTH_LDAP_USER' => $new_config['ldap_user'], - 'AUTH_LDAP_USER_FILTER' => $new_config['ldap_user_filter'], - ), - ); - } - - /** - * Generates a filter string for ldap_search to find a user - * - * @param $username string Username identifying the searched user - * - * @return string A filter string for ldap_search - */ - private function ldap_user_filter($username) - { - $filter = '(' . $this->config['ldap_uid'] . '=' . $this->ldap_escape(htmlspecialchars_decode($username)) . ')'; - if ($this->config['ldap_user_filter']) - { - $_filter = ($this->config['ldap_user_filter'][0] == '(' && substr($this->config['ldap_user_filter'], -1) == ')') ? $this->config['ldap_user_filter'] : "({$this->config['ldap_user_filter']})"; - $filter = "(&{$filter}{$_filter})"; - } - return $filter; - } - - /** - * Escapes an LDAP AttributeValue - * - * @param string $string The string to be escaped - * @return string The escaped string - */ - private function ldap_escape($string) - { - return str_replace(array('*', '\\', '(', ')'), array('\\*', '\\\\', '\\(', '\\)'), $string); - } -} diff --git a/install/update/old/phpbb/auth/provider/oauth/oauth.php b/install/update/old/phpbb/auth/provider/oauth/oauth.php deleted file mode 100644 index 93419d2..0000000 --- a/install/update/old/phpbb/auth/provider/oauth/oauth.php +++ /dev/null @@ -1,747 +0,0 @@ - -* @license 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; - -use OAuth\Common\Consumer\Credentials; - -/** -* OAuth authentication provider for phpBB3 -*/ -class oauth extends \phpbb\auth\provider\base -{ - /** - * Database driver - * - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB config - * - * @var \phpbb\config\config - */ - protected $config; - - /** - * phpBB passwords manager - * - * @var \phpbb\passwords\manager - */ - protected $passwords_manager; - - /** - * phpBB request object - * - * @var \phpbb\request\request_interface - */ - protected $request; - - /** - * phpBB user - * - * @var \phpbb\user - */ - protected $user; - - /** - * OAuth token table - * - * @var string - */ - protected $auth_provider_oauth_token_storage_table; - - /** - * OAuth state table - * - * @var string - */ - protected $auth_provider_oauth_state_table; - - /** - * OAuth account association table - * - * @var string - */ - protected $auth_provider_oauth_token_account_assoc; - - /** - * All OAuth service providers - * - * @var \phpbb\di\service_collection Contains \phpbb\auth\provider\oauth\service_interface - */ - protected $service_providers; - - /** - * Users table - * - * @var string - */ - protected $users_table; - - /** - * Cached current uri object - * - * @var \OAuth\Common\Http\Uri\UriInterface|null - */ - protected $current_uri; - - /** - * DI container - * - * @var \Symfony\Component\DependencyInjection\ContainerInterface - */ - protected $phpbb_container; - - /** - * phpBB event dispatcher - * - * @var \phpbb\event\dispatcher_interface - */ - protected $dispatcher; - - /** - * phpBB root path - * - * @var string - */ - protected $phpbb_root_path; - - /** - * PHP file extension - * - * @var string - */ - protected $php_ext; - - /** - * OAuth Authentication Constructor - * - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\config\config $config - * @param \phpbb\passwords\manager $passwords_manager - * @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 - * @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container - * @param \phpbb\event\dispatcher_interface $dispatcher phpBB event dispatcher - * @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_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; - $this->passwords_manager = $passwords_manager; - $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; - $this->phpbb_container = $phpbb_container; - $this->dispatcher = $dispatcher; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - } - - /** - * {@inheritdoc} - */ - public function init() - { - // This does not test whether or not the key and secret provided are valid. - foreach ($this->service_providers as $service_provider) - { - $credentials = $service_provider->get_service_credentials(); - - if (($credentials['key'] && !$credentials['secret']) || (!$credentials['key'] && $credentials['secret'])) - { - return $this->user->lang['AUTH_PROVIDER_OAUTH_ERROR_ELEMENT_MISSING']; - } - } - return false; - } - - /** - * {@inheritdoc} - */ - public function login($username, $password) - { - // Temporary workaround for only having one authentication provider available - if (!$this->request->is_set('oauth_service')) - { - $provider = new \phpbb\auth\provider\db($this->db, $this->config, $this->passwords_manager, $this->request, $this->user, $this->phpbb_container, $this->phpbb_root_path, $this->php_ext); - return $provider->login($username, $password); - } - - // 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)) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - // 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, $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 (($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 - $data = array( - 'provider' => $service_name_original, - 'oauth_provider_id' => $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 - return array( - 'status' => LOGIN_SUCCESS_LINK_PROFILE, - 'error_msg' => 'LOGIN_OAUTH_ACCOUNT_NOT_LINKED', - 'user_row' => array(), - '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 - FROM ' . $this->users_table . ' - WHERE user_id = ' . (int) $row['user_id']; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if (!$row) - { - 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, '', ''); - $message .= !empty($ban['ban_give_reason']) ? '

' . $this->user->lang('BOARD_BAN_REASON', $ban['ban_give_reason']) : ''; - $message .= !empty($ban['ban_triggered_by']) ? '

' . $this->user->lang('BAN_TRIGGERED_BY_' . strtoupper($ban['ban_triggered_by'])) . '' : ''; - - 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 successfully logged in via OAuth. - * - * @event core.auth_oauth_login_after - * @var array row User row - * @since 3.1.11-RC1 - */ - $vars = array( - 'row', - ); - extract($this->dispatcher->trigger_event('core.auth_oauth_login_after', compact($vars))); - - // The user is now authenticated and can be logged in - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - else - { - if ($service::OAUTH_VERSION === 1) - { - $token = $service->requestRequestToken(); - $url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken())); - } - else - { - $url = $service->getAuthorizationUri(); - } - header('Location: ' . $url); - } - } - - /** - * Returns the cached current_uri object or creates and caches it if it is - * not already created. In each case the query string is updated based on - * the $query parameter. - * - * @param string $service_name The name of the service - * @param string $query The query string of the current_uri - * used in redirects - * @return \OAuth\Common\Http\Uri\UriInterface - */ - protected function get_current_uri($service_name, $query) - { - if ($this->current_uri) - { - $this->current_uri->setQuery($query); - return $this->current_uri; - } - - $uri_factory = new \OAuth\Common\Http\Uri\UriFactory(); - $super_globals = $this->request->get_super_global(\phpbb\request\request_interface::SERVER); - if (!empty($super_globals['HTTP_X_FORWARDED_PROTO']) && $super_globals['HTTP_X_FORWARDED_PROTO'] === 'https') - { - $super_globals['HTTPS'] = 'on'; - $super_globals['SERVER_PORT'] = 443; - } - $current_uri = $uri_factory->createFromSuperGlobalArray($super_globals); - $current_uri->setQuery($query); - - $this->current_uri = $current_uri; - return $current_uri; - } - - /** - * Returns a new service object - * - * @param string $service_name The name of the service - * @param \phpbb\auth\provider\oauth\token_storage $storage - * @param array $service_credentials {@see \phpbb\auth\provider\oauth\oauth::get_service_credentials} - * @param string $query The query string of the - * current_uri used in redirection - * @param array $scopes The scope of the request against - * the api. - * @return \OAuth\Common\Service\ServiceInterface - * @throws \Exception - */ - protected function get_service($service_name, \phpbb\auth\provider\oauth\token_storage $storage, array $service_credentials, $query, array $scopes = array()) - { - $current_uri = $this->get_current_uri($service_name, $query); - - // Setup the credentials for the requests - $credentials = new Credentials( - $service_credentials['key'], - $service_credentials['secret'], - $current_uri->getAbsoluteUri() - ); - - $service_factory = new \OAuth\ServiceFactory(); - $service = $service_factory->createService($service_name, $credentials, $storage, $scopes); - - if (!$service) - { - throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_SERVICE_NOT_CREATED'); - } - - return $service; - } - - /** - * {@inheritdoc} - */ - public function get_login_data() - { - $login_data = array( - 'TEMPLATE_FILE' => 'login_body_oauth.html', - 'BLOCK_VAR_NAME' => 'oauth', - 'BLOCK_VARS' => array(), - ); - - foreach ($this->service_providers as $service_name => $service_provider) - { - // Only include data if the credentials are set - $credentials = $service_provider->get_service_credentials(); - 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; - $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)], - ); - } - } - - return $login_data; - } - - /** - * {@inheritdoc} - */ - public function acp() - { - $ret = array(); - - foreach ($this->service_providers as $service_name => $service_provider) - { - $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); - $ret[] = 'auth_oauth_' . $actual_name . '_key'; - $ret[] = 'auth_oauth_' . $actual_name . '_secret'; - } - - return $ret; - } - - /** - * {@inheritdoc} - */ - public function get_acp_template($new_config) - { - $ret = array( - 'BLOCK_VAR_NAME' => 'oauth_services', - 'BLOCK_VARS' => array(), - 'TEMPLATE_FILE' => 'auth_provider_oauth.html', - 'TEMPLATE_VARS' => array(), - ); - - foreach ($this->service_providers as $service_name => $service_provider) - { - $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); - $ret['BLOCK_VARS'][$actual_name] = array( - 'ACTUAL_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)], - 'KEY' => $new_config['auth_oauth_' . $actual_name . '_key'], - 'NAME' => $actual_name, - 'SECRET' => $new_config['auth_oauth_' . $actual_name . '_secret'], - ); - } - - return $ret; - } - - /** - * {@inheritdoc} - */ - public function login_link_has_necessary_data($login_link_data) - { - if (empty($login_link_data)) - { - return 'LOGIN_LINK_NO_DATA_PROVIDED'; - } - - if (!array_key_exists('oauth_service', $login_link_data) || !$login_link_data['oauth_service'] || - !array_key_exists('link_method', $login_link_data) || !$login_link_data['link_method']) - { - return 'LOGIN_LINK_MISSING_DATA'; - } - - return null; - } - - /** - * {@inheritdoc} - */ - public function link_account(array $link_data) - { - // Check for a valid link method (auth_link or login_link) - if (!array_key_exists('link_method', $link_data) || - !in_array($link_data['link_method'], array( - 'auth_link', - 'login_link', - ))) - { - return 'LOGIN_LINK_MISSING_DATA'; - } - - // We must have an oauth_service listed, check for it two ways - if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service']) - { - $link_data['oauth_service'] = $this->request->variable('oauth_service', ''); - - if (!$link_data['oauth_service']) - { - return 'LOGIN_LINK_MISSING_DATA'; - } - } - - $service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']); - if (!array_key_exists($service_name, $this->service_providers)) - { - return 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST'; - } - - switch ($link_data['link_method']) - { - case 'auth_link': - return $this->link_account_auth_link($link_data, $service_name); - case 'login_link': - return $this->link_account_login_link($link_data, $service_name); - } - } - - /** - * Performs the account linking for login_link - * - * @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account} - * @param string $service_name The name of the service being used in - * linking. - * @return string|null Returns a language constant (string) if an error is - * encountered, or null on success. - */ - 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, $this->auth_provider_oauth_state_table); - - // Check for an access token, they should have one - if (!$storage->has_access_token_by_session($service_name)) - { - return 'LOGIN_LINK_ERROR_OAUTH_NO_ACCESS_TOKEN'; - } - - // Prepare the query string - $query = 'mode=login_link&login_link_oauth_service=' . strtolower($link_data['oauth_service']); - - // Prepare for an authentication request - $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); - $this->service_providers[$service_name]->set_external_service_provider($service); - - // The user has already authenticated successfully, request to authenticate again - $unique_id = $this->service_providers[$service_name]->perform_token_auth(); - - // Insert into table, they will be able to log in after this - $data = array( - 'user_id' => $link_data['user_id'], - 'provider' => strtolower($link_data['oauth_service']), - 'oauth_provider_id' => $unique_id, - ); - - $this->link_account_perform_link($data); - // Update token storage to store the user_id - $storage->set_user_id($link_data['user_id']); - } - - /** - * Performs the account linking for auth_link - * - * @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account} - * @param string $service_name The name of the service being used in - * linking. - * @return string|null Returns a language constant (string) if an error is - * encountered, or null on success. - */ - 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, $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 (($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(); - - // Insert into table, they will be able to log in after this - $data = array( - 'user_id' => $this->user->data['user_id'], - 'provider' => strtolower($link_data['oauth_service']), - 'oauth_provider_id' => $unique_id, - ); - - $this->link_account_perform_link($data); - } - else - { - if ($service::OAUTH_VERSION === 1) - { - $token = $service->requestRequestToken(); - $url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken())); - } - else - { - $url = $service->getAuthorizationUri(); - } - header('Location: ' . $url); - } - } - - /** - * Performs the query that inserts an account link - * - * @param array $data This array is passed to db->sql_build_array - */ - protected function link_account_perform_link(array $data) - { - $sql = 'INSERT INTO ' . $this->auth_provider_oauth_token_account_assoc . ' - ' . $this->db->sql_build_array('INSERT', $data); - $this->db->sql_query($sql); - - /** - * Event is triggered after user links account. - * - * @event core.auth_oauth_link_after - * @var array data User row - * @since 3.1.11-RC1 - */ - $vars = array( - 'data', - ); - extract($this->dispatcher->trigger_event('core.auth_oauth_link_after', compact($vars))); - } - - /** - * {@inheritdoc} - */ - 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, $this->auth_provider_oauth_state_table); - $storage->clearAllTokens(); - - return; - } - - /** - * {@inheritdoc} - */ - public function get_auth_link_data($user_id = 0) - { - $block_vars = array(); - - // Get all external accounts tied to the current user - $data = array( - 'user_id' => ($user_id <= 0) ? (int) $this->user->data['user_id'] : (int) $user_id, - ); - $sql = 'SELECT oauth_provider_id, provider FROM ' . $this->auth_provider_oauth_token_account_assoc . ' - WHERE ' . $this->db->sql_build_array('SELECT', $data); - $result = $this->db->sql_query($sql); - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - $oauth_user_ids = array(); - - if ($rows !== false && count($rows)) - { - foreach ($rows as $row) - { - $oauth_user_ids[$row['provider']] = $row['oauth_provider_id']; - } - } - unset($rows); - - foreach ($this->service_providers as $service_name => $service_provider) - { - // Only include data if the credentials are set - $credentials = $service_provider->get_service_credentials(); - if ($credentials['key'] && $credentials['secret']) - { - $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); - - $block_vars[$service_name] = array( - 'HIDDEN_FIELDS' => array( - 'link' => (!isset($oauth_user_ids[$actual_name])), - '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, - ); - } - } - - return array( - 'BLOCK_VAR_NAME' => 'oauth', - 'BLOCK_VARS' => $block_vars, - - 'TEMPLATE_FILE' => 'ucp_auth_link_oauth.html', - ); - } - - /** - * {@inheritdoc} - */ - public function unlink_account(array $link_data) - { - if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service']) - { - return 'LOGIN_LINK_MISSING_DATA'; - } - - // Remove user specified in $link_data if possible - $user_id = isset($link_data['user_id']) ? $link_data['user_id'] : $this->user->data['user_id']; - - // Remove the link - $sql = 'DELETE FROM ' . $this->auth_provider_oauth_token_account_assoc . " - WHERE provider = '" . $this->db->sql_escape($link_data['oauth_service']) . "' - AND user_id = " . (int) $user_id; - $this->db->sql_query($sql); - - // 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, $this->auth_provider_oauth_state_table); - $storage->clearToken($service_name); - } -} diff --git a/install/update/old/phpbb/auth/provider/oauth/service/base.php b/install/update/old/phpbb/auth/provider/oauth/service/base.php deleted file mode 100644 index 6adf64a..0000000 --- a/install/update/old/phpbb/auth/provider/oauth/service/base.php +++ /dev/null @@ -1,51 +0,0 @@ - -* @license 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; - -/** -* Base OAuth abstract class that all OAuth services should implement -*/ -abstract class base implements \phpbb\auth\provider\oauth\service\service_interface -{ - /** - * External OAuth service provider - * - * @var \OAuth\Common\Service\ServiceInterface - */ - protected $service_provider; - - /** - * {@inheritdoc} - */ - public function get_external_service_provider() - { - return $this->service_provider; - } - - /** - * {@inheritdoc} - */ - public function get_auth_scope() - { - return array(); - } - - /** - * {@inheritdoc} - */ - public function set_external_service_provider(\OAuth\Common\Service\ServiceInterface $service_provider) - { - $this->service_provider = $service_provider; - } -} diff --git a/install/update/old/phpbb/auth/provider/oauth/service/bitly.php b/install/update/old/phpbb/auth/provider/oauth/service/bitly.php deleted file mode 100644 index 25e731a..0000000 --- a/install/update/old/phpbb/auth/provider/oauth/service/bitly.php +++ /dev/null @@ -1,94 +0,0 @@ - -* @license 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; - -/** -* Bitly OAuth service -*/ -class bitly 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_bitly_key'], - 'secret' => $this->config['auth_oauth_bitly_secret'], - ); - } - - /** - * {@inheritdoc} - */ - public function perform_auth_login() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Bitly)) - { - throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - // This was a callback request from bitly, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); - - // Send a request with it - $result = json_decode($this->service_provider->request('user/info'), true); - - // Return the unique identifier returned from bitly - return $result['data']['login']; - } - - /** - * {@inheritdoc} - */ - public function perform_token_auth() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Bitly)) - { - 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('user/info'), true); - - // Return the unique identifier returned from bitly - return $result['data']['login']; - } -} diff --git a/install/update/old/phpbb/auth/provider/oauth/service/facebook.php b/install/update/old/phpbb/auth/provider/oauth/service/facebook.php deleted file mode 100644 index bb98835..0000000 --- a/install/update/old/phpbb/auth/provider/oauth/service/facebook.php +++ /dev/null @@ -1,94 +0,0 @@ - -* @license 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; - -/** -* Facebook OAuth service -*/ -class facebook extends 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_facebook_key'], - 'secret' => $this->config['auth_oauth_facebook_secret'], - ); - } - - /** - * {@inheritdoc} - */ - public function perform_auth_login() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - // This was a callback request, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); - - // Send a request with it - $result = json_decode($this->service_provider->request('/me'), true); - - // Return the unique identifier - return $result['id']; - } - - /** - * {@inheritdoc} - */ - public function perform_token_auth() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - // Send a request with it - $result = json_decode($this->service_provider->request('/me'), true); - - // Return the unique identifier - return $result['id']; - } -} diff --git a/install/update/old/phpbb/auth/provider/oauth/service/google.php b/install/update/old/phpbb/auth/provider/oauth/service/google.php deleted file mode 100644 index cb9f83a..0000000 --- a/install/update/old/phpbb/auth/provider/oauth/service/google.php +++ /dev/null @@ -1,105 +0,0 @@ - -* @license 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; - -/** -* Google OAuth service -*/ -class google extends 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_auth_scope() - { - return array( - 'userinfo_email', - 'userinfo_profile', - ); - } - - /** - * {@inheritdoc} - */ - public function get_service_credentials() - { - return array( - 'key' => $this->config['auth_oauth_google_key'], - 'secret' => $this->config['auth_oauth_google_secret'], - ); - } - - /** - * {@inheritdoc} - */ - public function perform_auth_login() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Google)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - // This was a callback request, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); - - // Send a request with it - $result = json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true); - - // Return the unique identifier - return $result['id']; - } - - /** - * {@inheritdoc} - */ - public function perform_token_auth() - { - if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Google)) - { - throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); - } - - // Send a request with it - $result = json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true); - - // Return the unique identifier - return $result['id']; - } -} diff --git a/install/update/old/phpbb/auth/provider/oauth/service/service_interface.php b/install/update/old/phpbb/auth/provider/oauth/service/service_interface.php deleted file mode 100644 index e84eb24..0000000 --- a/install/update/old/phpbb/auth/provider/oauth/service/service_interface.php +++ /dev/null @@ -1,73 +0,0 @@ - -* @license 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; - -/** -* OAuth service interface -*/ -interface service_interface -{ - /** - * Returns an array of the scopes necessary for auth - * - * @return array An array of the required scopes - */ - public function get_auth_scope(); - - /** - * Returns the external library service provider once it has been set - * - * @param \OAuth\Common\Service\ServiceInterface|null - */ - public function get_external_service_provider(); - - /** - * Returns an array containing the service credentials belonging to requested - * service. - * - * @return array An array containing the 'key' and the 'secret' of the - * service in the form: - * array( - * 'key' => string - * 'secret' => string - * ) - */ - public function get_service_credentials(); - - /** - * Returns the results of the authentication in json format - * - * @throws \phpbb\auth\provider\oauth\service\exception - * @return string The unique identifier returned by the service provider - * that is used to authenticate the user with phpBB. - */ - public function perform_auth_login(); - - /** - * Returns the results of the authentication in json format - * Use this function when the user already has an access token - * - * @throws \phpbb\auth\provider\oauth\service\exception - * @return string The unique identifier returned by the service provider - * that is used to authenticate the user with phpBB. - */ - public function perform_token_auth(); - - /** - * Sets the external library service provider - * - * @param \OAuth\Common\Service\ServiceInterface $service_provider - */ - public function set_external_service_provider(\OAuth\Common\Service\ServiceInterface $service_provider); -} diff --git a/install/update/old/phpbb/auth/provider/oauth/service/twitter.php b/install/update/old/phpbb/auth/provider/oauth/service/twitter.php deleted file mode 100644 index 06beac5..0000000 --- a/install/update/old/phpbb/auth/provider/oauth/service/twitter.php +++ /dev/null @@ -1,102 +0,0 @@ - -* @license 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/install/update/old/phpbb/auth/provider/oauth/token_storage.php b/install/update/old/phpbb/auth/provider/oauth/token_storage.php deleted file mode 100644 index b0c2fd0..0000000 --- a/install/update/old/phpbb/auth/provider/oauth/token_storage.php +++ /dev/null @@ -1,592 +0,0 @@ - -* @license 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; - -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 -*/ -class token_storage implements TokenStorageInterface -{ - /** - * Cache driver. - * - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB user - * - * @var \phpbb\user - */ - protected $user; - - /** - * OAuth token table - * - * @var string - */ - protected $oauth_token_table; - - /** - * OAuth state table - * - * @var string - */ - protected $oauth_state_table; - - /** - * @var object|TokenInterface - */ - protected $cachedToken; - - /** - * @var string - */ - protected $cachedState; - - /** - * Creates token storage for phpBB. - * - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\user $user - * @param string $oauth_token_table - * @param string $oauth_state_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->oauth_token_table = $oauth_token_table; - $this->oauth_state_table = $oauth_state_table; - } - - /** - * {@inheritdoc} - */ - public function retrieveAccessToken($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedToken instanceof TokenInterface) - { - return $this->cachedToken; - } - - $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->_retrieve_access_token($data); - } - - /** - * {@inheritdoc} - */ - public function storeAccessToken($service, TokenInterface $token) - { - $service = $this->get_service_name_for_db($service); - - $this->cachedToken = $token; - - $data = array( - 'oauth_token' => $this->json_encode_token($token), - ); - - $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; - } - - /** - * {@inheritdoc} - */ - public function hasAccessToken($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedToken) - { - 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 $this->_has_acess_token($data); - } - - /** - * {@inheritdoc} - */ - public function clearToken($service) - { - $service = $this->get_service_name_for_db($service); - - $this->cachedToken = null; - - $sql = 'DELETE FROM ' . $this->oauth_token_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 clearAllTokens() - { - $this->cachedToken = null; - - $sql = 'DELETE FROM ' . $this->oauth_token_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; - } - - /** - * {@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; - } - - /** - * Updates the user_id field in the database assosciated with the token - * - * @param int $user_id - */ - public function set_user_id($user_id) - { - if (!$this->cachedToken) - { - return; - } - - $sql = 'UPDATE ' . $this->oauth_token_table . ' - SET ' . $this->db->sql_build_array('UPDATE', array( - 'user_id' => (int) $user_id - )) . ' - WHERE user_id = ' . (int) $this->user->data['user_id'] . " - AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'"; - $this->db->sql_query($sql); - } - - /** - * Checks to see if an access token exists solely by the session_id of the user - * - * @param string $service The name of the OAuth service - * @return bool true if they have token, false if they don't - */ - public function has_access_token_by_session($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedToken) - { - return true; - } - - $data = array( - 'session_id' => $this->user->data['session_id'], - 'provider' => $service, - ); - - return $this->_has_acess_token($data); - } - - /** - * 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 - * @return bool - */ - protected function _has_acess_token($data) - { - return (bool) $this->get_access_token_row($data); - } - - public function retrieve_access_token_by_session($service) - { - $service = $this->get_service_name_for_db($service); - - if ($this->cachedToken instanceof TokenInterface) - { - return $this->cachedToken; - } - - $data = array( - 'session_id' => $this->user->data['session_id'], - 'provider' => $service, - ); - - 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 - * - * @param array $data - * @return mixed - * @throws \OAuth\Common\Storage\Exception\TokenNotFoundException - */ - protected function _retrieve_access_token($data) - { - $row = $this->get_access_token_row($data); - - if (!$row) - { - throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_NOT_STORED'); - } - - $token = $this->json_decode_token($row['oauth_token']); - - // Ensure that the token was serialized/unserialized correctly - if (!($token instanceof TokenInterface)) - { - $this->clearToken($data['provider']); - throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED'); - } - - $this->cachedToken = $token; - return $token; - } - - /** - * 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 - * @return mixed - */ - protected function get_access_token_row($data) - { - $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); - $this->db->sql_freeresult($result); - - return $row; - } - - public function json_encode_token(TokenInterface $token) - { - $members = array( - 'accessToken' => $token->getAccessToken(), - 'endOfLife' => $token->getEndOfLife(), - 'extraParams' => $token->getExtraParams(), - 'refreshToken' => $token->getRefreshToken(), - - 'token_class' => get_class($token), - ); - - // Handle additional data needed for OAuth1 tokens - if ($token instanceof StdOAuth1Token) - { - $members['requestToken'] = $token->getRequestToken(); - $members['requestTokenSecret'] = $token->getRequestTokenSecret(); - $members['accessTokenSecret'] = $token->getAccessTokenSecret(); - } - - return json_encode($members); - } - - public function json_decode_token($json) - { - $token_data = json_decode($json, true); - - if ($token_data === null) - { - throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED'); - } - - $token_class = $token_data['token_class']; - $access_token = $token_data['accessToken']; - $refresh_token = $token_data['refreshToken']; - $endOfLife = $token_data['endOfLife']; - $extra_params = $token_data['extraParams']; - - // Create the token - $token = new $token_class($access_token, $refresh_token, TokenInterface::EOL_NEVER_EXPIRES, $extra_params); - $token->setEndOfLife($endOfLife); - - // Handle OAuth 1.0 specific elements - if ($token instanceof StdOAuth1Token) - { - $token->setRequestToken($token_data['requestToken']); - $token->setRequestTokenSecret($token_data['requestTokenSecret']); - $token->setAccessTokenSecret($token_data['accessTokenSecret']); - } - - return $token; - } - - /** - * Returns the name of the service as it must be stored in the database. - * - * @param string $service The name of the OAuth service - * @return string The name of the OAuth service as it needs to be stored - * in the database. - */ - protected function get_service_name_for_db($service) - { - // Enforce the naming convention for oauth services - if (strpos($service, 'auth.provider.oauth.service.') !== 0) - { - $service = 'auth.provider.oauth.service.' . strtolower($service); - } - - return $service; - } -} diff --git a/install/update/old/phpbb/auth/provider/provider_interface.php b/install/update/old/phpbb/auth/provider/provider_interface.php deleted file mode 100644 index 35e0f55..0000000 --- a/install/update/old/phpbb/auth/provider/provider_interface.php +++ /dev/null @@ -1,197 +0,0 @@ - -* @license 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; - -/** -* The interface authentication provider classes have to implement. -*/ -interface provider_interface -{ - /** - * Checks whether the user is currently identified to the authentication - * provider. - * Called in acp_board while setting authentication plugins. - * Changing to an authentication provider will not be permitted in acp_board - * if there is an error. - * - * @return boolean|string False if the user is identified, otherwise an - * error message, or null if not implemented. - */ - public function init(); - - /** - * Performs login. - * - * @param string $username The name of the user being authenticated. - * @param string $password The password of the user. - * @return array An associative array of the format: - * array( - * 'status' => status constant - * 'error_msg' => string - * 'user_row' => array - * ) - * A fourth key of the array may be present: - * 'redirect_data' This key is only used when 'status' is - * equal to LOGIN_SUCCESS_LINK_PROFILE and its value is an - * associative array that is turned into GET variables on - * the redirect url. - */ - public function login($username, $password); - - /** - * Autologin function - * - * @return array|null containing the user row, empty if no auto login - * should take place, or null if not impletmented. - */ - public function autologin(); - - /** - * This function is used to output any required fields in the authentication - * admin panel. It also defines any required configuration table fields. - * - * @return array|null Returns null if not implemented or an array of the - * configuration fields of the provider. - */ - public function acp(); - - /** - * This function updates the template with variables related to the acp - * 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 - * the template file name and an array of the vars - * that the template needs that must conform to the - * following example: - * array( - * 'TEMPLATE_FILE' => string, - * 'TEMPLATE_VARS' => array(...), - * ) - * An optional third element may be added to this - * array: 'BLOCK_VAR_NAME'. If this is present, - * then its value should be a string that is used - * to designate the name of the loop used in the - * ACP template file. When this is present, an - * additional key named 'BLOCK_VARS' is required. - * This must be an array containing at least one - * array of variables that will be assigned during - * the loop in the template. An example of this is - * presented below: - * array( - * 'BLOCK_VAR_NAME' => string, - * 'BLOCK_VARS' => array( - * 'KEY IS UNIMPORTANT' => array(...), - * ), - * 'TEMPLATE_FILE' => string, - * 'TEMPLATE_VARS' => array(...), - * ) - */ - public function get_acp_template($new_config); - - /** - * Returns an array of data necessary to build custom elements on the login - * form. - * - * @return array|null If this function is not implemented on an auth - * provider then it returns null. If it is implemented - * it will return an array of up to four elements of - * which only 'TEMPLATE_FILE'. If 'BLOCK_VAR_NAME' is - * present then 'BLOCK_VARS' must also be present in - * the array. The fourth element 'VARS' is also - * optional. The array, with all four elements present - * looks like the following: - * array( - * 'TEMPLATE_FILE' => string, - * 'BLOCK_VAR_NAME' => string, - * 'BLOCK_VARS' => array(...), - * 'VARS' => array(...), - * ) - */ - public function get_login_data(); - - /** - * Performs additional actions during logout. - * - * @param array $data An array corresponding to - * \phpbb\session::data - * @param boolean $new_session True for a new session, false for no new - * session. - */ - public function logout($data, $new_session); - - /** - * The session validation function checks whether the user is still logged - * into phpBB. - * - * @param array $user - * @return boolean true if the given user is authenticated, false if the - * session should be closed, or null if not implemented. - */ - public function validate_session($user); - - /** - * Checks to see if $login_link_data contains all information except for the - * user_id of an account needed to successfully link an external account to - * a forum account. - * - * @param array $login_link_data Any data needed to link a phpBB account to - * an external account. - * @return string|null Returns a string with a language constant if there - * is data missing or null if there is no error. - */ - public function login_link_has_necessary_data($login_link_data); - - /** - * Links an external account to a phpBB account. - * - * @param array $link_data Any data needed to link a phpBB account to - * an external account. - */ - public function link_account(array $link_data); - - /** - * Returns an array of data necessary to build the ucp_auth_link page - * - * @param int $user_id User ID for whom the data should be retrieved. - * defaults to 0, which is not a valid ID. The method - * should fall back to the current user's ID in this - * case. - * @return array|null If this function is not implemented on an auth - * provider then it returns null. If it is implemented - * it will return an array of up to four elements of - * which only 'TEMPLATE_FILE'. If 'BLOCK_VAR_NAME' is - * present then 'BLOCK_VARS' must also be present in - * the array. The fourth element 'VARS' is also - * optional. The array, with all four elements present - * looks like the following: - * array( - * 'TEMPLATE_FILE' => string, - * 'BLOCK_VAR_NAME' => string, - * 'BLOCK_VARS' => array(...), - * 'VARS' => array(...), - * ) - */ - public function get_auth_link_data($user_id = 0); - - /** - * Unlinks an external account from a phpBB account. - * - * @param array $link_data Any data needed to unlink a phpBB account - * from a phpbb account. - */ - public function unlink_account(array $link_data); -} diff --git a/install/update/old/phpbb/avatar/driver/remote.php b/install/update/old/phpbb/avatar/driver/remote.php deleted file mode 100644 index efc4f5e..0000000 --- a/install/update/old/phpbb/avatar/driver/remote.php +++ /dev/null @@ -1,216 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\avatar\driver; - -/** -* Handles avatars hosted remotely -*/ -class remote extends \phpbb\avatar\driver\driver -{ - /** - * {@inheritdoc} - */ - public function get_data($row) - { - return array( - 'src' => $row['avatar'], - 'width' => $row['avatar_width'], - 'height' => $row['avatar_height'], - ); - } - - /** - * {@inheritdoc} - */ - public function prepare_form($request, $template, $user, $row, &$error) - { - $template->assign_vars(array( - 'AVATAR_REMOTE_WIDTH' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_remote_width', ''), - 'AVATAR_REMOTE_HEIGHT' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_remote_width', ''), - 'AVATAR_REMOTE_URL' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar']) ? $row['avatar'] : '', - )); - - return true; - } - - /** - * {@inheritdoc} - */ - public function process_form($request, $template, $user, $row, &$error) - { - $url = $request->variable('avatar_remote_url', ''); - $width = $request->variable('avatar_remote_width', 0); - $height = $request->variable('avatar_remote_height', 0); - - if (empty($url)) - { - return false; - } - - if (!preg_match('#^(http|https|ftp)://#i', $url)) - { - $url = 'http://' . $url; - } - - if (!function_exists('validate_data')) - { - require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); - } - - $validate_array = validate_data( - array( - 'url' => $url, - ), - array( - 'url' => array('string', true, 5, 255), - ) - ); - - $error = array_merge($error, $validate_array); - - 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) || - 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)) - { - $error[] = 'AVATAR_URL_INVALID'; - return false; - } - - // Get image dimensions - if (($width <= 0 || $height <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false)) - { - $error[] = 'UNABLE_GET_IMAGE_SIZE'; - return false; - } - - if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['height'] <= 0)) - { - $error[] = 'AVATAR_NO_SIZE'; - return false; - } - - $width = ($width && $height) ? $width : $image_data['width']; - $height = ($width && $height) ? $height : $image_data['height']; - - if ($width <= 0 || $height <= 0) - { - $error[] = 'AVATAR_NO_SIZE'; - return false; - } - - $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')) - { - // Timeout after 1 second - stream_set_timeout($file_stream, 1); - // read some data to ensure headers are present - fread($file_stream, 1024); - $meta = stream_get_meta_data($file_stream); - - if (isset($meta['wrapper_data']['headers']) && is_array($meta['wrapper_data']['headers'])) - { - $headers = $meta['wrapper_data']['headers']; - } - else if (isset($meta['wrapper_data']) && is_array($meta['wrapper_data'])) - { - $headers = $meta['wrapper_data']; - } - else - { - $headers = array(); - } - - foreach ($headers as $header) - { - $header = preg_split('/ /', $header, 2); - if (strtr(strtolower(trim($header[0], ':')), '_', '-') === 'content-type') - { - if (strpos($header[1], 'image/') !== 0) - { - $error[] = 'AVATAR_URL_INVALID'; - fclose($file_stream); - return false; - } - else - { - fclose($file_stream); - break; - } - } - } - } - else - { - $error[] = 'AVATAR_URL_INVALID'; - return false; - } - - if (!empty($image_data) && (!isset($types[$image_data['type']]) || !in_array($extension, $types[$image_data['type']]))) - { - if (!isset($types[$image_data['type']])) - { - $error[] = 'UNABLE_GET_IMAGE_SIZE'; - } - else - { - $error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data['type']][0], $extension); - } - - return false; - } - - if ($this->config['avatar_max_width'] || $this->config['avatar_max_height']) - { - if ($width > $this->config['avatar_max_width'] || $height > $this->config['avatar_max_height']) - { - $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height); - return false; - } - } - - if ($this->config['avatar_min_width'] || $this->config['avatar_min_height']) - { - if ($width < $this->config['avatar_min_width'] || $height < $this->config['avatar_min_height']) - { - $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height); - return false; - } - } - - return array( - 'avatar' => $url, - 'avatar_width' => $width, - 'avatar_height' => $height, - ); - } - - /** - * {@inheritdoc} - */ - public function get_template_name() - { - return 'ucp_avatar_options_remote.html'; - } -} diff --git a/install/update/old/phpbb/avatar/driver/upload.php b/install/update/old/phpbb/avatar/driver/upload.php deleted file mode 100644 index a012bb1..0000000 --- a/install/update/old/phpbb/avatar/driver/upload.php +++ /dev/null @@ -1,331 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\avatar\driver; - -/** -* Handles avatars uploaded to the board -*/ -class upload extends \phpbb\avatar\driver\driver -{ - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * @var \phpbb\event\dispatcher_interface - */ - 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\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\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->dispatcher = $dispatcher; - $this->files_factory = $files_factory; - $this->cache = $cache; - } - - /** - * {@inheritdoc} - */ - public function get_data($row) - { - $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $this->path_helper->get_web_root_path(); - - return array( - 'src' => $root_path . 'download/file.' . $this->php_ext . '?avatar=' . $row['avatar'], - 'width' => $row['avatar_width'], - 'height' => $row['avatar_height'], - ); - } - - /** - * {@inheritdoc} - */ - public function prepare_form($request, $template, $user, $row, &$error) - { - if (!$this->can_upload()) - { - return false; - } - - $template->assign_vars(array( - 'S_UPLOAD_AVATAR_URL' => ($this->config['allow_avatar_remote_upload']) ? true : false, - 'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'], - )); - - return true; - } - - /** - * {@inheritdoc} - */ - public function process_form($request, $template, $user, $row, &$error) - { - if (!$this->can_upload()) - { - return 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->handle_upload('files.types.form', 'avatar_upload_file'); - } - else if (!empty($this->config['allow_avatar_remote_upload']) && !empty($url)) - { - if (!preg_match('#^(http|https|ftp)://#i', $url)) - { - $url = 'http://' . $url; - } - - if (!function_exists('validate_data')) - { - require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); - } - - $validate_array = validate_data( - array( - 'url' => $url, - ), - array( - 'url' => array('string', true, 5, 255), - ) - ); - - $error = array_merge($error, $validate_array); - - if (!empty($error)) - { - return false; - } - - // 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)://(?:(.*?\.)*?[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)) - { - $error[] = 'AVATAR_URL_INVALID'; - return false; - } - - $file = $upload->handle_upload('files.types.remote', $url); - } - else - { - return false; - } - - $prefix = $this->config['avatar_salt'] . '_'; - $file->clean_filename('avatar', $prefix, $row['id']); - - // If there was an error during upload, then abort operation - if (count($file->error)) - { - $file->remove(); - $error = $file->error; - return false; - } - - // Calculate new destination - $destination = $this->config['avatar_path']; - - // Adjust destination path (no trailing slash) - if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\') - { - $destination = substr($destination, 0, -1); - } - - $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination); - if ($destination && ($destination[0] == '/' || $destination[0] == "\\")) - { - $destination = ''; - } - - $filedata = array( - 'filename' => $file->get('filename'), - 'filesize' => $file->get('filesize'), - 'mimetype' => $file->get('mimetype'), - 'extension' => $file->get('extension'), - 'physical_filename' => $file->get('realname'), - 'real_filename' => $file->get('uploadname'), - ); - - /** - * Before moving new file in place (and eventually overwriting the existing avatar with the newly uploaded avatar) - * - * @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', - 'error', - ); - extract($this->dispatcher->trigger_event('core.avatar_driver_upload_move_file_before', compact($vars))); - - unset($filedata); - - if (!count($error)) - { - // Move file and overwrite any existing image - $file->move_file($destination, true); - } - - // If there was an error during move, then clean up leftovers - $error = array_merge($error, $file->error); - if (count($error)) - { - $file->remove(); - return false; - } - - // Delete current avatar if not overwritten - $ext = substr(strrchr($row['avatar'], '.'), 1); - if ($ext && $ext !== $file->get('extension')) - { - $this->delete($row); - } - - return array( - 'avatar' => $row['id'] . '_' . time() . '.' . $file->get('extension'), - 'avatar_width' => $file->get('width'), - 'avatar_height' => $file->get('height'), - ); - } - - /** - * {@inheritdoc} - */ - public function prepare_form_acp($user) - { - return array( - 'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), - 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - ); - } - - /** - * {@inheritdoc} - */ - public function delete($row) - { - - $error = array(); - $destination = $this->config['avatar_path']; - $prefix = $this->config['avatar_salt'] . '_'; - $ext = substr(strrchr($row['avatar'], '.'), 1); - $filename = $this->phpbb_root_path . $destination . '/' . $prefix . $row['id'] . '.' . $ext; - - /** - * Before deleting an existing avatar - * - * @event core.avatar_driver_upload_delete_before - * @var string destination Destination directory where the file is going to be deleted - * @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 deleted - * @since 3.1.6-RC1 - */ - $vars = array( - 'destination', - 'prefix', - 'row', - 'error', - ); - extract($this->dispatcher->trigger_event('core.avatar_driver_upload_delete_before', compact($vars))); - - if (!count($error) && $this->filesystem->exists($filename)) - { - try - { - $this->filesystem->remove($filename); - return true; - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Fail is covered by return statement below - } - } - - return false; - } - - /** - * {@inheritdoc} - */ - public function get_template_name() - { - return 'ucp_avatar_options_upload.html'; - } - - /** - * Check if user is able to upload an avatar - * - * @return bool True if user can upload, false if not - */ - protected function can_upload() - { - 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/install/update/old/phpbb/cache/driver/memcached.php b/install/update/old/phpbb/cache/driver/memcached.php deleted file mode 100644 index 7d66759..0000000 --- a/install/update/old/phpbb/cache/driver/memcached.php +++ /dev/null @@ -1,134 +0,0 @@ - -* @license 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; - -if (!defined('PHPBB_ACM_MEMCACHED_PORT')) -{ - define('PHPBB_ACM_MEMCACHED_PORT', 11211); -} - -if (!defined('PHPBB_ACM_MEMCACHED_COMPRESS')) -{ - define('PHPBB_ACM_MEMCACHED_COMPRESS', true); -} - -if (!defined('PHPBB_ACM_MEMCACHED_HOST')) -{ - define('PHPBB_ACM_MEMCACHED_HOST', 'localhost'); -} - -if (!defined('PHPBB_ACM_MEMCACHED')) -{ - //can define multiple servers with host1/port1,host2/port2 format - define('PHPBB_ACM_MEMCACHED', PHPBB_ACM_MEMCACHED_HOST . '/' . PHPBB_ACM_MEMCACHED_PORT); -} - -/** -* ACM for Memcached -*/ -class memcached extends \phpbb\cache\driver\memory -{ - /** @var string Extension to use */ - protected $extension = 'memcached'; - - /** @var \Memcached Memcached class */ - protected $memcached; - - /** @var int Flags */ - protected $flags = 0; - - /** - * Memcached constructor - */ - public function __construct() - { - // Call the parent constructor - parent::__construct(); - - $this->memcached = new \Memcached(); - $this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); - // Memcached defaults to using compression, disable if we don't want - // to use it - if (!PHPBB_ACM_MEMCACHED_COMPRESS) - { - $this->memcached->setOption(\Memcached::OPT_COMPRESSION, false); - } - - foreach (explode(',', PHPBB_ACM_MEMCACHED) as $u) - { - preg_match('#(.*)/(\d+)#', $u, $parts); - $this->memcached->addServer(trim($parts[1]), (int) trim($parts[2])); - } - } - - /** - * {@inheritDoc} - */ - public function unload() - { - parent::unload(); - - unset($this->memcached); - } - - /** - * {@inheritDoc} - */ - public function purge() - { - $this->memcached->flush(); - - parent::purge(); - } - - /** - * Fetch an item from the cache - * - * @param string $var Cache key - * - * @return mixed Cached data - */ - protected function _read($var) - { - return $this->memcached->get($this->key_prefix . $var); - } - - /** - * Store data in the cache - * - * @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 - */ - protected function _write($var, $data, $ttl = 2592000) - { - if (!$this->memcached->replace($this->key_prefix . $var, $data, $ttl)) - { - return $this->memcached->set($this->key_prefix . $var, $data, $ttl); - } - return true; - } - - /** - * Remove an item from the cache - * - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - protected function _delete($var) - { - return $this->memcached->delete($this->key_prefix . $var); - } -} diff --git a/install/update/old/phpbb/cache/driver/memory.php b/install/update/old/phpbb/cache/driver/memory.php deleted file mode 100644 index eba9549..0000000 --- a/install/update/old/phpbb/cache/driver/memory.php +++ /dev/null @@ -1,282 +0,0 @@ - -* @license 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 Abstract Memory Class -*/ -abstract class memory extends \phpbb\cache\driver\base -{ - var $key_prefix; - - /** - * Set cache path - */ - function __construct() - { - global $phpbb_root_path, $dbname, $table_prefix, $phpbb_container; - - $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)) - { - global $acm_type; - - trigger_error("Could not find required extension [{$this->extension}] for the ACM module $acm_type.", E_USER_ERROR); - } - - if (isset($this->function) && !function_exists($this->function)) - { - global $acm_type; - - trigger_error("The required function [{$this->function}] is not available for the ACM module $acm_type.", E_USER_ERROR); - } - } - - /** - * {@inheritDoc} - */ - function load() - { - // grab the global cache - $data = $this->_read('global'); - - if ($data !== false) - { - $this->vars = $data; - return true; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function save() - { - if (!$this->is_modified) - { - return; - } - - $this->_write('global', $this->vars, 2592000); - - $this->is_modified = false; - } - - /** - * {@inheritDoc} - */ - function tidy() - { - global $config; - - // cache has auto GC, no need to have any code here :) - $config->set('cache_last_gc', time(), false); - } - - /** - * {@inheritDoc} - */ - function get($var_name) - { - if ($var_name[0] == '_') - { - if (!$this->_exists($var_name)) - { - return false; - } - - return $this->_read($var_name); - } - else - { - return ($this->_exists($var_name)) ? $this->vars[$var_name] : false; - } - } - - /** - * {@inheritDoc} - */ - function put($var_name, $var, $ttl = 2592000) - { - if ($var_name[0] == '_') - { - $this->_write($var_name, $var, $ttl); - } - else - { - $this->vars[$var_name] = $var; - $this->is_modified = true; - } - } - - /** - * {@inheritDoc} - */ - function destroy($var_name, $table = '') - { - if ($var_name == 'sql' && !empty($table)) - { - if (!is_array($table)) - { - $table = array($table); - } - - foreach ($table as $table_name) - { - // gives us the md5s that we want - $temp = $this->_read('sql_' . $table_name); - - if ($temp === false) - { - continue; - } - - // delete each query ref - foreach ($temp as $md5_id => $void) - { - $this->_delete('sql_' . $md5_id); - } - - // delete the table ref - $this->_delete('sql_' . $table_name); - } - - return; - } - - if (!$this->_exists($var_name)) - { - return; - } - - if ($var_name[0] == '_') - { - $this->_delete($var_name); - } - else if (isset($this->vars[$var_name])) - { - $this->is_modified = true; - unset($this->vars[$var_name]); - - // We save here to let the following cache hits succeed - $this->save(); - } - } - - /** - * {@inheritDoc} - */ - function _exists($var_name) - { - if ($var_name[0] == '_') - { - return $this->_isset($var_name); - } - else - { - if (!count($this->vars)) - { - $this->load(); - } - - return isset($this->vars[$var_name]); - } - } - - /** - * {@inheritDoc} - */ - function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl) - { - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - $query_id = md5($query); - - // determine which tables this query belongs to - // Some queries use backticks, namely the get_database_size() query - // don't check for conformity, the SQL would error and not reach here. - if (!preg_match_all('/(?:FROM \\(?(`?\\w+`?(?: \\w+)?(?:, ?`?\\w+`?(?: \\w+)?)*)\\)?)|(?:JOIN (`?\\w+`?(?: \\w+)?))/', $query, $regs, PREG_SET_ORDER)) - { - // Bail out if the match fails. - return $query_result; - } - - $tables = array(); - foreach ($regs as $match) - { - if ($match[0][0] == 'F') - { - $tables = array_merge($tables, array_map('trim', explode(',', $match[1]))); - } - else - { - $tables[] = $match[2]; - } - } - - foreach ($tables as $table_name) - { - // Remove backticks - $table_name = ($table_name[0] == '`') ? substr($table_name, 1, -1) : $table_name; - - if (($pos = strpos($table_name, ' ')) !== false) - { - $table_name = substr($table_name, 0, $pos); - } - - $temp = $this->_read('sql_' . $table_name); - - if ($temp === false) - { - $temp = array(); - } - - $temp[$query_id] = true; - - // This must never expire - $this->_write('sql_' . $table_name, $temp, 0); - } - - // store them in the right place - $this->sql_rowset[$query_id] = array(); - $this->sql_row_pointer[$query_id] = 0; - - while ($row = $db->sql_fetchrow($query_result)) - { - $this->sql_rowset[$query_id][] = $row; - } - $db->sql_freeresult($query_result); - - $this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl); - - return $query_id; - } - - /** - * Check if a cache var exists - * - * @access protected - * @param string $var Cache key - * @return bool True if it exists, otherwise false - */ - function _isset($var) - { - // Most caches don't need to check - return true; - } -} diff --git a/install/update/old/phpbb/captcha/non_gd.php b/install/update/old/phpbb/captcha/non_gd.php deleted file mode 100644 index 3818672..0000000 --- a/install/update/old/phpbb/captcha/non_gd.php +++ /dev/null @@ -1,386 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\captcha; - -/** -* Main non-gd captcha class -* @ignore -*/ -class non_gd -{ - var $filtered_pngs; - var $width = 320; - var $height = 50; - - /** - * Define filtered pngs on init - */ - function __construct() - { - // If we can we will generate a single filtered png, we avoid nastiness via emulation of some Zlib stuff - $this->define_filtered_pngs(); - } - - /** - * Create the image containing $code with a seed of $seed - */ - function execute($code, $seed) - { - $img_height = $this->height - 10; - $img_width = 0; - - mt_srand($seed); - - $char_widths = $hold_chars = array(); - $code_len = strlen($code); - - for ($i = 0; $i < $code_len; $i++) - { - $char = $code[$i]; - - $width = mt_rand(0, 4); - $raw_width = $this->filtered_pngs[$char]['width']; - $char_widths[$i] = $width; - $img_width += $raw_width - $width; - - // Split the char into chunks of $raw_width + 1 length - if (empty($hold_chars[$char])) - { - $hold_chars[$char] = str_split(base64_decode($this->filtered_pngs[$char]['data']), $raw_width + 1); - } - } - - $offset_x = mt_rand(0, $this->width - $img_width); - $offset_y = mt_rand(0, $this->height - $img_height); - - $image = ''; - for ($i = 0; $i < $this->height; $i++) - { - $image .= chr(0); - - if ($i > $offset_y && $i < $offset_y + $img_height) - { - for ($j = 0; $j < $offset_x; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - - for ($j = 0; $j < $code_len; $j++) - { - $image .= $this->randomise(substr($hold_chars[$code{$j}][$i - $offset_y - 1], 1), $char_widths[$j]); - } - - for ($j = $offset_x + $img_width; $j < $this->width; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - } - else - { - for ($j = 0; $j < $this->width; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - } - } - unset($hold_chars); - - $image = $this->create_png($image, $this->width, $this->height); - - // Output image - header('Content-Type: image/png'); - header('Cache-control: no-cache, no-store'); - echo $image; - exit; - } - - /** - * This is designed to randomise the pixels of the image data within - * certain limits so as to keep it readable. It also varies the image - * width a little - */ - function randomise($scanline, $width) - { - $new_line = ''; - - $end = strlen($scanline) - ceil($width/2); - for ($i = (int) floor($width / 2); $i < $end; $i++) - { - $pixel = ord($scanline{$i}); - - if ($pixel < 190) - { - $new_line .= chr(mt_rand(0, 205)); - } - else if ($pixel > 190) - { - $new_line .= chr(mt_rand(145, 255)); - } - else - { - $new_line .= $scanline{$i}; - } - } - - return $new_line; - } - - /** - * This creates a chunk of the given type, with the given data - * of the given length adding the relevant crc - */ - function png_chunk($length, $type, $data) - { - $raw = $type . $data; - - return pack('N', $length) . $raw . pack('N', crc32($raw)); - } - - /** - * Creates greyscale 8bit png - The PNG spec can be found at - * http://www.libpng.org/pub/png/spec/PNG-Contents.html we use - * png because it's a fully recognised open standard and supported - * by practically all modern browsers and OSs - */ - function create_png($raw_image, $width, $height) - { - // SIG - $image = pack('C8', 137, 80, 78, 71, 13, 10, 26, 10); - - // IHDR - $raw = pack('N2', $width, $height); - $raw .= pack('C5', 8, 0, 0, 0, 0); - $image .= $this->png_chunk(13, 'IHDR', $raw); - - // IDAT - if (@extension_loaded('zlib')) - { - $raw_image = gzcompress($raw_image); - $length = strlen($raw_image); - } - else - { - // The total length of this image, uncompressed, is just a calculation of pixels - $length = ($width + 1) * $height; - - // Adler-32 hash generation - // Note: The hash is _backwards_ so we must reverse it - - if (@extension_loaded('hash')) - { - $adler_hash = strrev(hash('adler32', $raw_image, true)); - } - else if (@extension_loaded('mhash')) - { - $adler_hash = strrev(mhash(MHASH_ADLER32, $raw_image)); - } - else - { - // Optimized Adler-32 loop ported from the GNU Classpath project - $temp_length = $length; - $s1 = 1; - $s2 = $index = 0; - - while ($temp_length > 0) - { - // We can defer the modulo operation: - // s1 maximally grows from 65521 to 65521 + 255 * 3800 - // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 - $substract_value = ($temp_length < 3800) ? $temp_length : 3800; - $temp_length -= $substract_value; - - while (--$substract_value >= 0) - { - $s1 += ord($raw_image[$index]); - $s2 += $s1; - - $index++; - } - - $s1 %= 65521; - $s2 %= 65521; - } - $adler_hash = pack('N', ($s2 << 16) | $s1); - } - - // This is the same thing as gzcompress($raw_image, 0) but does not need zlib - $raw_image = pack('C3v2', 0x78, 0x01, 0x01, $length, ~$length) . $raw_image . $adler_hash; - - // The Zlib header + Adler hash make us add on 11 - $length += 11; - } - - // IDAT - $image .= $this->png_chunk($length, 'IDAT', $raw_image); - - // IEND - $image .= $this->png_chunk(0, 'IEND', ''); - - return $image; - } - - /** - * png image data - * Each 'data' element is base64_encoded uncompressed IDAT - */ - function define_filtered_pngs() - { - $this->filtered_pngs = array( - '0' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////olFAkBAAAGDyA4P///M31/////////////wD////////////////0dAgAAAAAAAAAAAAEcPipFGHn////////////AP//////////////6DAAAAAAAAAAAAAAAAAALSEAN+T///////////8A//////////////xAAAAAAAAAAAAAAAAAAAAAACPA/////////////wD/////////////oAAAAAAAAAAAAAAAAAAAAAAAev//////////////AP////////////8oAAAAAAAAPNj/zDAAAAAAAABD//////////////8A////////////1AAAAAAAABjw////5BAAAAAAAADo/////////////wD///////////+QAAAAAAAAbP//////QgAAAAAAAKj/////////////AP///////////1wAAAAAAACs/////8AXAAAAAAAAcP////////////8A////////////OAAAAAAAAND////dNwAAAAAAAABI/////////////wD///////////8gAAAAAAAA4P//7koACwAAAAAAACT/////////////AP///////////wgAAAAAAAD///VqAwaPAAAAAAAAEP////////////8A////////////AAAAAAAAAP/8kQYDavUAAAAAAAAA/////////////wD///////////8AAAAAAAAA/6kNAEru/wAAAAAAAAD/////////////AP///////////wAAAAAAAADAIwA33f//AAAAAAAAAP////////////8A////////////FAAAAAAAADYAI8D///8AAAAAAAAQ/////////////wD///////////8kAAAAAAAAAA2p////5AAAAAAAACD/////////////AP///////////0gAAAAAAAAFkfz////UAAAAAAAAQP////////////8A////////////cAAAAAAAAET1/////7AAAAAAAABo/////////////wD///////////+oAAAAAAAAXfX/////sAAAAAAAAGj/////////////AAAAALgAAAAAAAAwAAAAAAAAAAAAAAD////////////oAAAAAAAACOT////oEAAAAAAAAOD/////////////AP////////////8+AAAAAAAAKMz/zDQAAAAAAAA0//////////////8A////////////7jgAAAAAAAAAAAAAAAAAAAAAAKT//////////////wD///////////VqAwIAAAAAAAAAAAAAAAAAAAA8////////////////AP//////////rQcDaVEAAAAAAAAAAAAAAAAAKOj///////////////8A///////////nblnu/IAIAAAAAAAAAAAAAFzw/////////////////wD////////////79////+iITCAAAAAgSITg////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////w==', - 'width' => 40 - ), - '1' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////8BAAAAAAAP//////////////////AP////////////////////////9sAAAAAAAA//////////////////8A////////////////////////pAAAAAAAAAD//////////////////wD//////////////////////6wEAAAAAAAAAP//////////////////AP////////////////////h4AAAAAAAAAAAA//////////////////8A//////////////////ygJAAAAAAAAAAAAAD//////////////////wD//////////////9x8HAAAAAAAAAAAAAAAAP//////////////////AP//////////////AAAAAAAAAAAAAAAAAAAA//////////////////8A//////////////8AAAAAAAAAAAAAAAAAAAD//////////////////wD//////////////wAAAAAAAAR4AAAAAAAAAP//////////////////AP//////////////AAAAAAA4zP8AAAAAAAAA//////////////////8A//////////////8AAAA4sP///wAAAAAAAAD//////////////////wD//////////////yR80P//////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '2' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////okFAkCAAABCBIfNT///////////////////8A///////////////8hAgAAAAAAAAAAAAAAFTo/////////////////wD//////////////1QAAAAAAAAAAAAAAAAAACjo////////////////AP////////////+MAAAAAAAAAAAAAAAAAAAAADj///////////////8A////////////9BAAAAAAAAAAAAAAAAAAAAAAALD//////////////wD///////////+gAAAAAAAAAHjs+KwMAAAAAAAAVP//////////////AP///////////1gAAAAAAABM/////6QAAAAAAAAU//////////////8A////////////KAAAAAAAALj/////+AAAAAAAAAD//////////////wD///////////+MfGBMOCAI8P/////wAAAAAAAACP//////////////AP///////////////////////////5wAAAAAAAAw//////////////8A///////////////////////////oFAAAAAAAAHz//////////////wD/////////////////////////6CgAAAAAAAAE3P//////////////AP///////////////////////9ggAAAAAAAAAHT///////////////8A//////////////////////+0DAAAAAAAAAA8+P///////////////wD/////////////////////gAAAAAAAAAAAKOj/////////////////AP//////////////////9FAAAAAAAAAAADzw//////////////////8A/////////////////+g4AAAAAAAAAABk/P///////////////////wD////////////////oKAAAAAAAAAAMqP//////////////////////AP//////////////6CgAAAAAAAAAMNz///////////////////////8A//////////////g4AAAAAAAAAFT0/////////////////////////wD/////////////bAAAAAAAAABU/P//////////////////////////AP///////////8wAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A////////////SAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////9AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////xAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '3' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////8sGg0FAAAACA4cLz8////////////////////AP//////////////rBgAAAAAAAAAAAAAACTA//////////////////8A/////////////3QAAAAAAAAAAAAAAAAAAASs/////////////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAjc////////////////AP//////////6AwAAAAAAAAAAAAAAAAAAAAAAGT///////////////8A//////////94AAAAAAAABJDw/8g4AAAAAAAAHP///////////////wD//////////yAAAAAAAACE/////9gAAAAAAAAA////////////////AP///////////NSwiGQ4FOT//////AAAAAAAABD///////////////8A//////////////////////////+YAAAAAAAAVP///////////////wD//////////////////////P/ggAQAAAAAAATM////////////////AP////////////////////9gAAAAAAAAAAAElP////////////////8A/////////////////////0AAAAAAAAAAHLj//////////////////wD/////////////////////OAAAAAAAAAAwkPj/////////////////AP////////////////////8gAAAAAAAAAAAAINj///////////////8A/////////////////////xAAAAAAAAAAAAAAIPD//////////////wD/////////////////////uOz/4HgEAAAAAAAAhP//////////////AP///////////////////////////3wAAAAAAAAw//////////////8A////////////////////////////6AAAAAAAAAj//////////////wD/////////////////////////////AAAAAAAAAP//////////////AP//////////tJh8YEQoDNz//////+AAAAAAAAAY//////////////8A//////////88AAAAAAAAaP//////dAAAAAAAAEz//////////////wD//////////6QAAAAAAAAAdOD/5HQAAAAAAAAApP//////////////AP///////////CgAAAAAAAAAAAAAAAAAAAAAACD4//////////////8A////////////yAQAAAAAAAAAAAAAAAAAAAAEuP///////////////wD/////////////rAQAAAAAAAAAAAAAAAAABJD/////////////////AP//////////////zDQAAAAAAAAAAAAAACTA//////////////////8A/////////////////8BwOCAAAAAUNGi0/P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '4' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////////////nAAAAAAAAAD///////////////8A/////////////////////////8AEAAAAAAAAAP///////////////wD////////////////////////gGAAAAAAAAAAA////////////////AP//////////////////////9DAAAAAAAAAAAAD///////////////8A//////////////////////9UAAAAAAAAAAAAAP///////////////wD/////////////////////hAAAAAAAAAAAAAAA////////////////AP///////////////////7QAAAAAAAAAAAAAAAD///////////////8A///////////////////UDAAAAAAUAAAAAAAAAP///////////////wD/////////////////7CQAAAAABMAAAAAAAAAA////////////////AP////////////////xEAAAAAACU/wAAAAAAAAD///////////////8A////////////////cAAAAAAAZP//AAAAAAAAAP///////////////wD//////////////6AAAAAAADz8//8AAAAAAAAA////////////////AP/////////////IBAAAAAAc6P///wAAAAAAAAD///////////////8A////////////5BgAAAAADMz/////AAAAAAAAAP///////////////wD///////////g0AAAAAACk//////8AAAAAAAAA////////////////AP//////////XAAAAAAAfP///////wAAAAAAAAD///////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP///////////////////////////wAAAAAAAAD///////////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '5' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////8AAAAAAAAAAAAAAAAAAAAAAA//////////////8A///////////////MAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////6wAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////iAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////////9kAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////0QAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////IAAAAAAAYP////////////////////////////8A//////////////wAAAAAAAB8/////////////////////////////wD/////////////3AAAAAAAAIj/////////////////////////////AP////////////+4AAAAAAAAoLRYHAAEKGTE//////////////////8A/////////////5QAAAAAAAAQAAAAAAAAAABY9P///////////////wD/////////////dAAAAAAAAAAAAAAAAAAAAAA89P//////////////AP////////////9QAAAAAAAAAAAAAAAAAAAAAABg//////////////8A/////////////zAAAAAAAAAAAAAAAAAAAAAAAADQ/////////////wD/////////////IAAAAAAAAGjY/+h4BAAAAAAAAGz/////////////AP//////////////9NS0lHSc//////90AAAAAAAALP////////////8A/////////////////////////////9QAAAAAAAAE/////////////wD//////////////////////////////wAAAAAAAAD/////////////AP/////////////////////////////8AAAAAAAAEP////////////8A////////////pIRwWEAgDOD//////8wAAAAAAAA8/////////////wD///////////9EAAAAAAAAaP//////ZAAAAAAAAHz/////////////AP///////////6QAAAAAAAAAaOD/4GQAAAAAAAAE4P////////////8A/////////////CQAAAAAAAAAAAAAAAAAAAAAAGD//////////////wD/////////////yAQAAAAAAAAAAAAAAAAAAAAc7P//////////////AP//////////////rAwAAAAAAAAAAAAAAAAAGNj///////////////8A////////////////0EAAAAAAAAAAAAAAAFTo/////////////////wD//////////////////8h4QCAAAAAcQHzU////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '6' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////+0ZCwMAAAUNGjI////////////////////AP/////////////////EMAAAAAAAAAAAAABM6P////////////////8A////////////////lAQAAAAAAAAAAAAAAAAo6P///////////////wD//////////////6wAAAAAAAAAAAAAAAAAAABI////////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAACw//////////////8A/////////////3AAAAAAAAAoxP/YPAAAAAAAAEj//////////////wD////////////4EAAAAAAACOD////YDCBAVGiAoP//////////////AP///////////7gAAAAAAABY//////////////////////////////8A////////////eAAAAAAAAJT//////////////////////////////wD///////////9MAAAAAAAAvP/IXBgABCx03P//////////////////AP///////////ygAAAAAAADcdAAAAAAAAAAEiP////////////////8A////////////FAAAAAAAAFAAAAAAAAAAAAAAcP///////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAlP//////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAQ8P////////////8A////////////AAAAAAAAAABAyP/kZAAAAAAAAACQ/////////////wD///////////8MAAAAAAAALPj/////WAAAAAAAAET/////////////AP///////////yQAAAAAAACY///////MAAAAAAAAFP////////////8A////////////SAAAAAAAAMD///////wAAAAAAAAA/////////////wD///////////9wAAAAAAAAvP///////wAAAAAAAAD/////////////AP///////////7QAAAAAAACI///////UAAAAAAAAJP////////////8A////////////+AwAAAAAACDw/////2wAAAAAAABY/////////////wD/////////////cAAAAAAAADC8/Ox4AAAAAAAAAKj/////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAAAk/P////////////8A//////////////+oAAAAAAAAAAAAAAAAAAAABLj//////////////wD///////////////+QAAAAAAAAAAAAAAAAAACQ////////////////AP////////////////+0JAAAAAAAAAAAAAAkuP////////////////8A///////////////////8sGg0FAAADCxgqPz//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '7' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAABP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAy4/////////////wD//////////////////////////+QUAAAAAAAEuP//////////////AP/////////////////////////8QAAAAAAAAKT///////////////8A/////////////////////////4wAAAAAAAB0/////////////////wD////////////////////////cCAAAAAAANPz/////////////////AP///////////////////////0QAAAAAAATY//////////////////8A//////////////////////+0AAAAAAAAeP///////////////////wD//////////////////////CQAAAAAABTw////////////////////AP////////////////////+gAAAAAAAAkP////////////////////8A/////////////////////ywAAAAAABDw/////////////////////wD///////////////////+4AAAAAAAAbP//////////////////////AP///////////////////1wAAAAAAADQ//////////////////////8A///////////////////4DAAAAAAAMP///////////////////////wD//////////////////7QAAAAAAAB8////////////////////////AP//////////////////aAAAAAAAAMj///////////////////////8A//////////////////8oAAAAAAAM/P///////////////////////wD/////////////////8AAAAAAAAET/////////////////////////AP////////////////+0AAAAAAAAcP////////////////////////8A/////////////////4wAAAAAAACY/////////////////////////wD/////////////////WAAAAAAAAMD/////////////////////////AP////////////////80AAAAAAAA4P////////////////////////8A/////////////////xAAAAAAAAD4/////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '8' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////////IdDQUAAAEIEiA1P//////////////////AP/////////////////gRAAAAAAAAAAAAAAAROD///////////////8A////////////////0BgAAAAAAAAAAAAAAAAAEMj//////////////wD///////////////AcAAAAAAAAAAAAAAAAAAAAHPD/////////////AP//////////////hAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A//////////////8sAAAAAAAAKMz/zCgAAAAAAAAs/////////////wD//////////////wAAAAAAAADM////zAAAAAAAAAD/////////////AP//////////////BAAAAAAAAP//////AAAAAAAABP////////////8A//////////////8sAAAAAAAAzP///9QAAAAAAAAw/////////////wD//////////////3wAAAAAAAAoyP/YNAAAAAAAAIT/////////////AP//////////////7BgAAAAAAAAAAAAAAAAAAAAc8P////////////8A////////////////xBgAAAAAAAAAAAAAAAAAGNj//////////////wD/////////////////tAQAAAAAAAAAAAAAAACo////////////////AP///////////////HAAAAAAAAAAAAAAAAAAAAB8//////////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB8/////////////wD/////////////wAAAAAAAAABk4P/UWAAAAAAAAATQ////////////AP////////////9UAAAAAAAAaP//////XAAAAAAAAGT///////////8A/////////////xgAAAAAAADg///////cAAAAAAAAJP///////////wD/////////////AAAAAAAAAP////////8AAAAAAAAA////////////AP////////////8AAAAAAAAA4P//////3AAAAAAAAAT///////////8A/////////////ygAAAAAAABg//////9cAAAAAAAALP///////////wD/////////////ZAAAAAAAAABY1P/cXAAAAAAAAABw////////////AP/////////////QAAAAAAAAAAAAAAAAAAAAAAAABNz///////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB0/////////////wD///////////////Q8AAAAAAAAAAAAAAAAAAAAUPz/////////////AP////////////////x4CAAAAAAAAAAAAAAAEIT8//////////////8A///////////////////smFQwGAAAABg0ZKT0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '9' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////ysYCwMAAAUNGiw/P//////////////////AP////////////////+4JAAAAAAAAAAAAAAkuP////////////////8A////////////////lAQAAAAAAAAAAAAAAAAAkP///////////////wD//////////////8AEAAAAAAAAAAAAAAAAAAAAqP//////////////AP/////////////8JAAAAAAAAAAAAAAAAAAAAAAQ7P////////////8A/////////////6wAAAAAAAAAfOz8vCwAAAAAAABw/////////////wD/////////////WAAAAAAAAHD/////7BgAAAAAAAz4////////////AP////////////8kAAAAAAAA1P//////hAAAAAAAALT///////////8A/////////////wAAAAAAAAD///////+4AAAAAAAAcP///////////wD/////////////AAAAAAAAAPz//////8AAAAAAAABI////////////AP////////////8UAAAAAAAAzP//////lAAAAAAAACT///////////8A/////////////0QAAAAAAABY//////gsAAAAAAAADP///////////wD/////////////kAAAAAAAAABw5P/IPAAAAAAAAAAA////////////AP/////////////wEAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////////+UAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////9wAAAAAAAAAAAAAFAAAAAAAAAU////////////AP////////////////+IBAAAAAAAAABw3AAAAAAAACj///////////8A///////////////////cdCwEABhcxP+8AAAAAAAATP///////////wD//////////////////////////////5AAAAAAAAB4////////////AP//////////////////////////////UAAAAAAAALj///////////8A//////////////+kgGxUQCAM2P///+AIAAAAAAAQ+P///////////wD//////////////0gAAAAAAAA42P/EKAAAAAAAAHD/////////////AP//////////////sAAAAAAAAAAAAAAAAAAAAAAQ6P////////////8A////////////////TAAAAAAAAAAAAAAAAAAAAKz//////////////wD////////////////oKAAAAAAAAAAAAAAAAASU////////////////AP/////////////////sUAAAAAAAAAAAAAAwxP////////////////8A////////////////////yHA0FAAADCxktP///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'A' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////+QAAAAAAAAAAAAAAOT/////////////////AP//////////////////kAAAAAAAAAAAAAAAkP////////////////8A//////////////////88AAAAAAAAAAAAAAA8/////////////////wD/////////////////5AAAAAAAAAAAAAAAAADk////////////////AP////////////////+QAAAAAAAAAAAAAAAAAJD///////////////8A/////////////////zwAAAAAAAAAAAAAAAAAPP///////////////wD////////////////kAAAAAAAAAAgAAAAAAAAA5P//////////////AP///////////////5AAAAAAAAAAgAAAAAAAAACQ//////////////8A////////////////PAAAAAAAAAz8HAAAAAAAADz//////////////wD//////////////+QAAAAAAAAAWP9kAAAAAAAAANz/////////////AP//////////////kAAAAAAAAACk/7wAAAAAAAAAhP////////////8A//////////////88AAAAAAAABOz//BQAAAAAAAAw/////////////wD/////////////4AAAAAAAAAA8////ZAAAAAAAAADc////////////AP////////////+EAAAAAAAAAIj///+8AAAAAAAAAIT///////////8A/////////////zAAAAAAAAAA2P////wQAAAAAAAAMP///////////wD////////////cAAAAAAAAACT//////1wAAAAAAAAA3P//////////AP///////////4QAAAAAAAAAAAAAAAAAAAAAAAAAAACE//////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAAAAAADD//////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANz/////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhP////////8A//////////8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/////////wD/////////3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc////////AP////////+EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIT///////8A/////////zAAAAAAAAAAhP///////////2QAAAAAAAAAMP///////wD////////cAAAAAAAAAADM////////////vAAAAAAAAAAA3P//////AP///////4QAAAAAAAAAHP/////////////4DAAAAAAAAACE//////8A////////MAAAAAAAAABk//////////////9cAAAAAAAAADD//////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'B' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAEDh83P///////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAEhP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAeP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAABY////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAABT///////////8A//////////8AAAAAAAAAAP/////4zEwAAAAAAAAAAP///////////wD//////////wAAAAAAAAAA////////7AAAAAAAAAAQ////////////AP//////////AAAAAAAAAAD////////sAAAAAAAAAEj///////////8A//////////8AAAAAAAAAAP/////4zEQAAAAAAAAAtP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAFz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAiA/P////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAIjPj//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAGKz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJT///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAABNz//////////wD//////////wAAAAAAAAAA///////sqCAAAAAAAAAAbP//////////AP//////////AAAAAAAAAAD/////////yAAAAAAAAAAs//////////8A//////////8AAAAAAAAAAP//////////AAAAAAAAAAT//////////wD//////////wAAAAAAAAAA/////////7wAAAAAAAAAAP//////////AP//////////AAAAAAAAAAD//////+ikGAAAAAAAAAAY//////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFT//////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsP//////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAADj///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAc6P///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAATOj/////////////AP//////////AAAAAAAAAAAAAAAAAAAEIEBkkNj///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'C' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////5JRULBAAAAgkTIDQ//////////////////8A////////////////1FAAAAAAAAAAAAAAAABAyP///////////////wD//////////////4gEAAAAAAAAAAAAAAAAAAAElP//////////////AP////////////9wAAAAAAAAAAAAAAAAAAAAAAAAlP////////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAEyP///////////wD//////////9wIAAAAAAAAAAAAAAAAAAAAAAAAAAAw////////////AP//////////WAAAAAAAAAAAWMz/8JwQAAAAAAAAAACw//////////8A/////////+wEAAAAAAAAAID//////9QMAAAAAAAAAET//////////wD/////////nAAAAAAAAAAo/P///////3wAAAAABDBspP//////////AP////////9gAAAAAAAAAIz/////////3BxQjMT0//////////////8A/////////zQAAAAAAAAAzP///////////////////////////////wD/////////GAAAAAAAAADo////////////////////////////////AP////////8AAAAAAAAAAP////////////////////////////////8A/////////wAAAAAAAAAA/////////////////////////////////wD/////////AAAAAAAAAAD/////////////////////////////////AP////////8cAAAAAAAAAOj///////////////////////////////8A/////////zgAAAAAAAAA0P/////////kIGio7P///////////////wD/////////bAAAAAAAAACg/////////5wAAAAAMHS49P//////////AP////////+oAAAAAAAAAEz/////////PAAAAAAAAAAc//////////8A//////////QIAAAAAAAAALz//////6QAAAAAAAAAAGT//////////wD//////////3AAAAAAAAAADIzo/+SEBAAAAAAAAAAAyP//////////AP//////////7BAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////rAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD/////////////fAAAAAAAAAAAAAAAAAAAAAAAAJz/////////////AP//////////////iAQAAAAAAAAAAAAAAAAAAASY//////////////8A////////////////yEAAAAAAAAAAAAAAAAA8yP///////////////wD//////////////////9yIUCwQAAAAIEB4yP//////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'D' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAADChQkOT/////////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAABGjw//////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAACDY/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAABjk////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKj//////////wD///////////8AAAAAAAAAAP///+isSAAAAAAAAAAANP//////////AP///////////wAAAAAAAAAA////////hAAAAAAAAAAA2P////////8A////////////AAAAAAAAAAD/////////MAAAAAAAAACQ/////////wD///////////8AAAAAAAAAAP////////+MAAAAAAAAAFj/////////AP///////////wAAAAAAAAAA/////////8gAAAAAAAAAMP////////8A////////////AAAAAAAAAAD/////////5AAAAAAAAAAY/////////wD///////////8AAAAAAAAAAP//////////AAAAAAAAAAD/////////AP///////////wAAAAAAAAAA//////////8AAAAAAAAAAP////////8A////////////AAAAAAAAAAD//////////wAAAAAAAAAA/////////wD///////////8AAAAAAAAAAP/////////wAAAAAAAAABD/////////AP///////////wAAAAAAAAAA/////////9QAAAAAAAAAJP////////8A////////////AAAAAAAAAAD/////////qAAAAAAAAABI/////////wD///////////8AAAAAAAAAAP////////9QAAAAAAAAAHj/////////AP///////////wAAAAAAAAAA////////uAAAAAAAAAAAvP////////8A////////////AAAAAAAAAAD////w0HwEAAAAAAAAACT8/////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAADz8//////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAY6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAKNz/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAACHT0//////////////8A////////////AAAAAAAAAAAAAAAAABg4bKj0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'E' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'F' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'G' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////MB8TCgQAAAACCA4YJzs////////////////AP///////////////JQcAAAAAAAAAAAAAAAAAAhw8P////////////8A/////////////9gwAAAAAAAAAAAAAAAAAAAAAAAk2P///////////wD////////////EDAAAAAAAAAAAAAAAAAAAAAAAAAAc7P//////////AP//////////2AwAAAAAAAAAAAAAAAAAAAAAAAAAAABY//////////8A//////////wwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQ/////////wD/////////kAAAAAAAAAAAEHzQ/P/gmCAAAAAAAAAAAFz/////////AP////////wcAAAAAAAAACjg////////8CwAAAAAAAAgWP////////8A////////vAAAAAAAAAAI2P//////////yBRAcJjI8P///////////wD///////94AAAAAAAAAGD/////////////////////////////////AP///////0AAAAAAAAAAsP////////////////////////////////8A////////IAAAAAAAAADc/////////////////////////////////wD///////8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAD/////////AP///////wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAP////////8A////////AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAA/////////wD///////8gAAAAAAAAAOD//////wAAAAAAAAAAAAAAAAD/////////AP///////0AAAAAAAAAAtP//////AAAAAAAAAAAAAAAAAP////////8A////////cAAAAAAAAABw//////8AAAAAAAAAAAAAAAAA/////////wD///////+8AAAAAAAAABDs////////////AAAAAAAAAAD/////////AP////////wYAAAAAAAAADz0//////////AAAAAAAAAAAP////////8A/////////5AAAAAAAAAAACCY4P//3KhcCAAAAAAAAAAA/////////wD/////////+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////AP//////////xAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIP////////8A////////////rAQAAAAAAAAAAAAAAAAAAAAAAAAAAGTw/////////wD/////////////vBQAAAAAAAAAAAAAAAAAAAAAADjI////////////AP//////////////8HAQAAAAAAAAAAAAAAAAAEiw//////////////8A//////////////////iwcEAgBAAABCA4aKDk/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'H' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'I' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'J' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAj//////////////wD//////////+zMrIxwUDAQ//////wAAAAAAAAAIP//////////////AP//////////DAAAAAAAAADo////2AAAAAAAAAA0//////////////8A//////////8wAAAAAAAAAKj///+YAAAAAAAAAFj//////////////wD//////////2gAAAAAAAAAIND/yBgAAAAAAAAAkP//////////////AP//////////vAAAAAAAAAAAAAAAAAAAAAAAAADc//////////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAUP///////////////wD////////////EBAAAAAAAAAAAAAAAAAAAABjk////////////////AP////////////+sBAAAAAAAAAAAAAAAAAAY2P////////////////8A///////////////EMAAAAAAAAAAAAAAAVOj//////////////////wD/////////////////vHBAIAAAABg8fNT/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'K' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////8AAAAAAAAAAP//////////wAQAAAAAAAAAAABw////////AP///////wAAAAAAAAAA/////////9AMAAAAAAAAAAAAcP////////8A////////AAAAAAAAAAD////////cGAAAAAAAAAAAAHD//////////wD///////8AAAAAAAAAAP//////6CgAAAAAAAAAAABs////////////AP///////wAAAAAAAAAA//////Q0AAAAAAAAAAAAVPz///////////8A////////AAAAAAAAAAD////8RAAAAAAAAAAAAFT8/////////////wD///////8AAAAAAAAAAP///1gAAAAAAAAAAABU/P//////////////AP///////wAAAAAAAAAA//9wAAAAAAAAAAAASPz///////////////8A////////AAAAAAAAAAD/jAAAAAAAAAAAADz0/////////////////wD///////8AAAAAAAAAAKQAAAAAAAAAAAA89P//////////////////AP///////wAAAAAAAAAABAAAAAAAAAAAFPT///////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAApP///////////////////wD///////8AAAAAAAAAAAAAAAAAAAAAAAAU8P//////////////////AP///////wAAAAAAAAAAAAAAAAAAAAAAAABk//////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAAAADE/////////////////wD///////8AAAAAAAAAAAAAAAAoEAAAAAAAACz8////////////////AP///////wAAAAAAAAAAAAAAGNiAAAAAAAAAAIj///////////////8A////////AAAAAAAAAAAAABjY//gYAAAAAAAACOD//////////////wD///////8AAAAAAAAAAAAY2P///5wAAAAAAAAASP//////////////AP///////wAAAAAAAAAAGNj//////CgAAAAAAAAAqP////////////8A////////AAAAAAAAAADI////////sAAAAAAAAAAc8P///////////wD///////8AAAAAAAAAAP//////////QAAAAAAAAABs////////////AP///////wAAAAAAAAAA///////////IAAAAAAAAAATI//////////8A////////AAAAAAAAAAD///////////9YAAAAAAAAADD8/////////wD///////8AAAAAAAAAAP///////////9wEAAAAAAAAAJD/////////AP///////wAAAAAAAAAA/////////////3AAAAAAAAAADOT///////8A////////AAAAAAAAAAD/////////////7BAAAAAAAAAAUP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'L' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'M' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////8AAAAAAAAAAAAAAHz//////3wAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAATP//////UAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAc//////8cAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAADw////8AAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAAALz////AAAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAAkP///5AAAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAABc////ZAAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAoAAAAADD///8wAAAAACQAAAAAAAAA////////AP//////AAAAAAAAAFwAAAAABPz//AgAAAAAXAAAAAAAAAD///////8A//////8AAAAAAAAAkAAAAAAA0P/UAAAAAACQAAAAAAAAAP///////wD//////wAAAAAAAADMAAAAAACg/6gAAAAAAMQAAAAAAAAA////////AP//////AAAAAAAAAPgEAAAAAHD/dAAAAAAE+AAAAAAAAAD///////8A//////8AAAAAAAAA/zQAAAAAQP9IAAAAADD/AAAAAAAAAP///////wD//////wAAAAAAAAD/bAAAAAAQ/xQAAAAAaP8AAAAAAAAA////////AP//////AAAAAAAAAP+gAAAAAADQAAAAAACc/wAAAAAAAAD///////8A//////8AAAAAAAAA/9QAAAAAAGgAAAAAAND/AAAAAAAAAP///////wD//////wAAAAAAAAD//wwAAAAAFAAAAAAM/P8AAAAAAAAA////////AP//////AAAAAAAAAP//RAAAAAAAAAAAADz//wAAAAAAAAD///////8A//////8AAAAAAAAA//94AAAAAAAAAAAAcP//AAAAAAAAAP///////wD//////wAAAAAAAAD//7AAAAAAAAAAAACo//8AAAAAAAAA////////AP//////AAAAAAAAAP//5AAAAAAAAAAAANz//wAAAAAAAAD///////8A//////8AAAAAAAAA////HAAAAAAAAAAQ////AAAAAAAAAP///////wD//////wAAAAAAAAD///9QAAAAAAAAAEz///8AAAAAAAAA////////AP//////AAAAAAAAAP///4gAAAAAAAAAfP///wAAAAAAAAD///////8A//////8AAAAAAAAA////vAAAAAAAAACw////AAAAAAAAAP///////wD//////wAAAAAAAAD////wAAAAAAAAAOz///8AAAAAAAAA////////AP//////AAAAAAAAAP////8sAAAAAAAc/////wAAAAAAAAD///////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'N' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAALD/////////////AAAAAAAAAP//////////AP////////8AAAAAAAAAFOj///////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAASP///////////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAkP//////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAI1P////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAw+P///////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAABw////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAC8//////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAABzs/////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAFD/////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAJz///8AAAAAAAAA//////////8A/////////wAAAAAAAAAUAAAAAAAADNz//wAAAAAAAAD//////////wD/////////AAAAAAAAALQAAAAAAAAANPz/AAAAAAAAAP//////////AP////////8AAAAAAAAA/2wAAAAAAAAAfP8AAAAAAAAA//////////8A/////////wAAAAAAAAD/+CwAAAAAAAAExAAAAAAAAAD//////////wD/////////AAAAAAAAAP//0AQAAAAAAAAgAAAAAAAAAP//////////AP////////8AAAAAAAAA////jAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////RAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP/////kFAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA//////+sAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD///////9kAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP////////QkAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA/////////8wEAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD//////////4QAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP///////////DwAAAAAAAAAAP//////////AP////////8AAAAAAAAA////////////4BAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////////////qAAAAAAAAAD//////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'O' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////0qGw4HAAAABw4aKT0/////////////////wD////////////////wcAwAAAAAAAAAAAAAAAho6P//////////////AP//////////////uBQAAAAAAAAAAAAAAAAAAAAMoP////////////8A/////////////6AEAAAAAAAAAAAAAAAAAAAAAAAAkP///////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP//////////8BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAM5P////////8A//////////9wAAAAAAAAAAAsrPD/7KQsAAAAAAAAAABg/////////wD/////////+BAAAAAAAAAAUPj///////hQAAAAAAAAAAjs////////AP////////+sAAAAAAAAABDw//////////AYAAAAAAAAAKD///////8A/////////2wAAAAAAAAAdP///////////3wAAAAAAAAAYP///////wD/////////OAAAAAAAAAC4////////////xAAAAAAAAAAw////////AP////////8cAAAAAAAAAOD////////////oAAAAAAAAABT///////8A/////////wAAAAAAAAAA//////////////8AAAAAAAAAAP///////wD/////////AAAAAAAAAAD//////////////wAAAAAAAAAA////////AP////////8AAAAAAAAAAP/////////////8AAAAAAAAAAD///////8A/////////xwAAAAAAAAA5P///////////+AAAAAAAAAAHP///////wD/////////NAAAAAAAAAC8////////////uAAAAAAAAAA4////////AP////////9oAAAAAAAAAHj///////////98AAAAAAAAAGT///////8A/////////6gAAAAAAAAAGPD/////////+BgAAAAAAAAApP///////wD/////////9AwAAAAAAAAAUPz///////xcAAAAAAAAAAjs////////AP//////////cAAAAAAAAAAALKjs//CwOAAAAAAAAAAAYP////////8A///////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzk/////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP////////////+QAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A//////////////+sEAAAAAAAAAAAAAAAAAAAAAyg/////////////wD////////////////oZAgAAAAAAAAAAAAAAARg4P//////////////AP//////////////////9KhsOCAAAAAUMFyc7P////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'P' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////wAAAAAAAAAAAAAAAAAACCxguP////////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAOOD//////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAGOD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAARP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAABo////////////AP///////////wAAAAAAAAAA////6JwMAAAAAAAAADD///////////8A////////////AAAAAAAAAAD//////6AAAAAAAAAADP///////////wD///////////8AAAAAAAAAAP//////9AAAAAAAAAAA////////////AP///////////wAAAAAAAAAA///////0AAAAAAAAAAD///////////8A////////////AAAAAAAAAAD//////5gAAAAAAAAAHP///////////wD///////////8AAAAAAAAAAP///9iICAAAAAAAAABI////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAIT/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAABU/P////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAIhPz//////////////wD///////////8AAAAAAAAAAAAAAAAABCRMkOz/////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Q' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////SoaDQcAAAAHDhoqPT///////////////////8A//////////////BwDAAAAAAAAAAAAAAACHDo/////////////////wD///////////+4FAAAAAAAAAAAAAAAAAAAABCo////////////////AP//////////nAQAAAAAAAAAAAAAAAAAAAAAAACQ//////////////8A/////////7gEAAAAAAAAAAAAAAAAAAAAAAAAAACg/////////////wD////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzo////////////AP///////3AAAAAAAAAAACyo8P/sqCwAAAAAAAAAAGT///////////8A///////4EAAAAAAAAABM+P///////FQAAAAAAAAACPT//////////wD//////7AAAAAAAAAAFPD/////////9BgAAAAAAAAApP//////////AP//////bAAAAAAAAAB4////////////fAAAAAAAAABk//////////8A//////84AAAAAAAAALz///////////+8AAAAAAAAADT//////////wD//////xwAAAAAAAAA6P///////////+QAAAAAAAAAHP//////////AP//////AAAAAAAAAAD//////////////wAAAAAAAAAA//////////8A//////8AAAAAAAAAAP//////////////AAAAAAAAAAD//////////wD//////wAAAAAAAAAA/P////////////8AAAAAAAAAAP//////////AP//////GAAAAAAAAADg////////////4AAAAAAAAAAc//////////8A//////84AAAAAAAAALT////MJHTo//+8AAAAAAAAADT//////////wD//////2wAAAAAAAAAdP///2AAABCg/3wAAAAAAAAAZP//////////AP//////rAAAAAAAAAAY9P/sCAAAAABMGAAAAAAAAACk//////////8A///////4EAAAAAAAAABU/P+0OAAAAAAAAAAAAAAACPT//////////wD///////94AAAAAAAAAAA4sPD/gAAAAAAAAAAAAABk////////////AP////////AcAAAAAAAAAAAAAAAAAAAAAAAAAAAADOT///////////8A/////////7wEAAAAAAAAAAAAAAAAAAAAAAAAAACQ/////////////wD//////////6wEAAAAAAAAAAAAAAAAAAAAAAAAABSs////////////AP///////////7gUAAAAAAAAAAAAAAAAAAAAAAAAAABAwP////////8A//////////////BwDAAAAAAAAAAAAAAABAgAAAAAAAA8/////////wD////////////////0qGg0GAAAABgwXJjkxBgAAAAAALD/////////AP//////////////////////////////////5DQAAAAk/P////////8A////////////////////////////////////+GwAAJD//////////wD//////////////////////////////////////8A49P//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'R' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////wAAAAAAAAAAAAAAAAAAAAQgOGSk+P///////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAcuP//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAEsP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ6P///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADD///////////8A/////////wAAAAAAAAAA///////svDgAAAAAAAAACP///////////wD/////////AAAAAAAAAAD/////////7AAAAAAAAAAA////////////AP////////8AAAAAAAAAAP/////////cAAAAAAAAABD///////////8A/////////wAAAAAAAAAA//////DQoCQAAAAAAAAAQP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACU////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIPj///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAzU/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAA02P//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAxctPz///////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAEDY/////////////////wD/////////AAAAAAAAAAD/9LAsAAAAAAAAAAzc////////////////AP////////8AAAAAAAAAAP///+wkAAAAAAAAADD8//////////////8A/////////wAAAAAAAAAA/////8QAAAAAAAAAAJD//////////////wD/////////AAAAAAAAAAD//////1QAAAAAAAAAFPD/////////////AP////////8AAAAAAAAAAP//////3AQAAAAAAAAAgP////////////8A/////////wAAAAAAAAAA////////aAAAAAAAAAAM6P///////////wD/////////AAAAAAAAAAD////////oCAAAAAAAAABs////////////AP////////8AAAAAAAAAAP////////+AAAAAAAAAAATc//////////8A/////////wAAAAAAAAAA//////////AUAAAAAAAAAFj//////////wD/////////AAAAAAAAAAD//////////5AAAAAAAAAAAND/////////AP////////8AAAAAAAAAAP//////////+CQAAAAAAAAAQP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'S' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////8vHBEIAgAAAQgQHC8/P////////////////8A////////////////pCQAAAAAAAAAAAAAAAAcoP///////////////wD//////////////FwAAAAAAAAAAAAAAAAAAAAAXP//////////////AP////////////9oAAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A////////////zAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////9cAAAAAAAAAAAAAAAAAAAAAAAAAACA////////////AP///////////xgAAAAAAAAAUOD/8KwkAAAAAAAAADj///////////8A////////////AAAAAAAAAAD0/////8wABCAgICxASP///////////wD///////////8MAAAAAAAAAMz/////////////////////////////AP///////////0AAAAAAAAAACFiQxPT///////////////////////8A////////////oAAAAAAAAAAAAAAAADBwtPT//////////////////wD////////////8QAAAAAAAAAAAAAAAAAAACFTA////////////////AP/////////////oOAAAAAAAAAAAAAAAAAAAAABM6P////////////8A///////////////4fAgAAAAAAAAAAAAAAAAAAAAY2P///////////wD/////////////////7IwwAAAAAAAAAAAAAAAAAAAo+P//////////AP/////////////////////koGw0BAAAAAAAAAAAAACU//////////8A///////////////////////////4uFgAAAAAAAAAADz//////////wD//////////2BgSEA0IBwA6P///////5QAAAAAAAAADP//////////AP//////////JAAAAAAAAACc/////////AAAAAAAAAAA//////////8A//////////9YAAAAAAAAACDo///////AAAAAAAAAABT//////////wD//////////6QAAAAAAAAAACCk7P/snBQAAAAAAAAAUP//////////AP//////////+BAAAAAAAAAAAAAAAAAAAAAAAAAAAACs//////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAAOP///////////wD////////////8RAAAAAAAAAAAAAAAAAAAAAAAABjc////////////AP/////////////0PAAAAAAAAAAAAAAAAAAAAAAg2P////////////8A///////////////8hBQAAAAAAAAAAAAAAAAMdPT//////////////wD/////////////////+LRwSCAMAAAAHDhoqPT/////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'T' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'U' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////JAAAAAAAAADk/////////+gAAAAAAAAAHP//////////AP////////9MAAAAAAAAAJz/////////nAAAAAAAAABE//////////8A/////////4gAAAAAAAAAHOj//////+ggAAAAAAAAAHz//////////wD/////////0AAAAAAAAAAAIJzs/+ykIAAAAAAAAAAA0P//////////AP//////////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A///////////IBAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAAAAJj/////////////AP////////////+UBAAAAAAAAAAAAAAAAAAAAASU//////////////8A///////////////IPAAAAAAAAAAAAAAAAAAwyP///////////////wD/////////////////0IxYOCAIAAAEIEiAyP//////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'V' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////zAAAAAAAAAAYP//////////////ZAAAAAAAAAAw////////AP//////kAAAAAAAAAAU/P////////////8UAAAAAAAAAJD///////8A///////oBAAAAAAAAADE////////////xAAAAAAAAAAE7P///////wD///////9MAAAAAAAAAHD///////////94AAAAAAAAAEz/////////AP///////6gAAAAAAAAAJP///////////yQAAAAAAAAArP////////8A////////+BAAAAAAAAAA1P/////////YAAAAAAAAABT4/////////wD/////////aAAAAAAAAACE/////////4QAAAAAAAAAbP//////////AP/////////EAAAAAAAAADT/////////OAAAAAAAAADM//////////8A//////////8kAAAAAAAAAOT//////+QAAAAAAAAAKP///////////wD//////////4QAAAAAAAAAmP//////nAAAAAAAAACI////////////AP//////////5AAAAAAAAABE//////9EAAAAAAAABOT///////////8A////////////QAAAAAAAAAT0////9AgAAAAAAABI/////////////wD///////////+gAAAAAAAAAKT///+kAAAAAAAAAKj/////////////AP////////////QIAAAAAAAAXP///1wAAAAAAAAM+P////////////8A/////////////1wAAAAAAAAM+P/8DAAAAAAAAGT//////////////wD/////////////vAAAAAAAAAC8/7wAAAAAAAAAxP//////////////AP//////////////HAAAAAAAAGj/aAAAAAAAACT///////////////8A//////////////94AAAAAAAAHP8cAAAAAAAAhP///////////////wD//////////////9gAAAAAAAAAkAAAAAAAAADk////////////////AP///////////////zgAAAAAAAAQAAAAAAAAQP////////////////8A////////////////lAAAAAAAAAAAAAAAAACg/////////////////wD////////////////sCAAAAAAAAAAAAAAADPT/////////////////AP////////////////9QAAAAAAAAAAAAAABg//////////////////8A/////////////////7AAAAAAAAAAAAAAAMD//////////////////wD//////////////////BQAAAAAAAAAAAAc////////////////////AP//////////////////cAAAAAAAAAAAAHz///////////////////8A///////////////////MAAAAAAAAAAAA3P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'W' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//8cAAAAAAAAALz/////4AAAAAAAAAAA6P////+8AAAAAAAAABz//wD//1QAAAAAAAAAjP////+gAAAAAAAAAACo/////4wAAAAAAAAAUP//AP//jAAAAAAAAABU/////2AAAAAAAAAAAGj/////VAAAAAAAAACM//8A///EAAAAAAAAACT/////IAAAAAAAAAAAKP////8kAAAAAAAAAMT//wD///gEAAAAAAAAAPD//+AAAAAAAAAAAAAA6P//8AAAAAAAAAAE9P//AP///zAAAAAAAAAAvP//oAAAAAAAAAAAAACo//+8AAAAAAAAADD///8A////bAAAAAAAAACM//9gAAAAAAAAAAAAAGT//4wAAAAAAAAAaP///wD///+kAAAAAAAAAFT//yAAAAAAAAAAAAAAIP//VAAAAAAAAACc////AP///9gAAAAAAAAAJP/gAAAAAAAAAAAAAAAA4P8kAAAAAAAAANT///8A/////xAAAAAAAAAA8KAAAAAAAAAAAAAAAACg8AAAAAAAAAAQ/////wD/////TAAAAAAAAAC8YAAAAAAAAAAAAAAAAGC8AAAAAAAAAET/////AP////+AAAAAAAAAAIwgAAAAAAAAAAAAAAAAIIwAAAAAAAAAfP////8A/////7gAAAAAAAAANAAAAAAAACwwAAAAAAAANAAAAAAAAACw/////wD/////8AAAAAAAAAAAAAAAAAAAdHgAAAAAAAAAAAAAAAAAAOz/////AP//////KAAAAAAAAAAAAAAAAAC4vAAAAAAAAAAAAAAAAAAg//////8A//////9gAAAAAAAAAAAAAAAACPj4CAAAAAAAAAAAAAAAAFj//////wD//////5QAAAAAAAAAAAAAAABE//9IAAAAAAAAAAAAAAAAkP//////AP//////0AAAAAAAAAAAAAAAAIj//4wAAAAAAAAAAAAAAADI//////8A///////8DAAAAAAAAAAAAAAAzP//1AAAAAAAAAAAAAAABPj//////wD///////88AAAAAAAAAAAAABT/////GAAAAAAAAAAAAAA0////////AP///////3QAAAAAAAAAAAAAWP////9gAAAAAAAAAAAAAHD///////8A////////sAAAAAAAAAAAAACg/////6QAAAAAAAAAAAAApP///////wD////////kAAAAAAAAAAAAAOT/////6AAAAAAAAAAAAADc////////AP////////8cAAAAAAAAAAAo////////MAAAAAAAAAAAEP////////8A/////////1QAAAAAAAAAAHD///////94AAAAAAAAAABM/////////wD/////////jAAAAAAAAAAAtP///////7wAAAAAAAAAAID/////////AP/////////EAAAAAAAAAAT0////////+AgAAAAAAAAAuP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'X' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////9UAAAAAAAAAKz///////////+sAAAAAAAAAFD/////////AP///////+QQAAAAAAAAFOT/////////8BwAAAAAAAAM5P////////8A/////////5gAAAAAAAAATP////////9kAAAAAAAAAJD//////////wD//////////0AAAAAAAAAAoP//////wAAAAAAAAAA0/P//////////AP//////////2AgAAAAAAAAQ4P////gkAAAAAAAABMz///////////8A////////////iAAAAAAAAABA////dAAAAAAAAABw/////////////wD////////////8MAAAAAAAAACU/9AEAAAAAAAAHPD/////////////AP/////////////IBAAAAAAAAAzYMAAAAAAAAACs//////////////8A//////////////90AAAAAAAAABAAAAAAAAAATP///////////////wD///////////////QgAAAAAAAAAAAAAAAAAAzg////////////////AP///////////////7wAAAAAAAAAAAAAAAAAjP////////////////8A/////////////////2AAAAAAAAAAAAAAADD8/////////////////wD/////////////////7BQAAAAAAAAAAAAEyP//////////////////AP/////////////////gDAAAAAAAAAAAAAjY//////////////////8A/////////////////0AAAAAAAAAAAAAAADj8/////////////////wD///////////////+UAAAAAAAAAAAAAAAAAJD/////////////////AP//////////////4AwAAAAAAAAAAAAAAAAADOD///////////////8A//////////////9AAAAAAAAAAAAAAAAAAAAAQP///////////////wD/////////////nAAAAAAAAAAAWAAAAAAAAAAAlP//////////////AP///////////+QQAAAAAAAAAGD/YAAAAAAAAAAM4P////////////8A////////////TAAAAAAAAAAs9P/0LAAAAAAAAABM/////////////wD//////////6AAAAAAAAAADNT////UDAAAAAAAAACg////////////AP/////////kEAAAAAAAAACg//////+gAAAAAAAAABDk//////////8A/////////0wAAAAAAAAAYP////////9gAAAAAAAAAEz//////////wD///////+oAAAAAAAAACz0//////////QsAAAAAAAAAKT/////////AP//////7BQAAAAAAAAM1P///////////9QMAAAAAAAAFOz///////8A//////9UAAAAAAAAAKD//////////////6AAAAAAAAAAVP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Y' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////1QAAAAAAAAAAGj//////////2gAAAAAAAAAAFT///////8A////////5BAAAAAAAAAAAMT////////EAAAAAAAAAAAQ5P///////wD/////////mAAAAAAAAAAAKPj/////+CgAAAAAAAAAAJj/////////AP//////////PAAAAAAAAAAAgP////+AAAAAAAAAAAA8//////////8A///////////YCAAAAAAAAAAE2P//2AQAAAAAAAAACNj//////////wD///////////+AAAAAAAAAAAA4//84AAAAAAAAAACA////////////AP////////////woAAAAAAAAAACUlAAAAAAAAAAAKPz///////////8A/////////////8gAAAAAAAAAABAQAAAAAAAAAADI/////////////wD//////////////2wAAAAAAAAAAAAAAAAAAAAAbP//////////////AP//////////////8BwAAAAAAAAAAAAAAAAAABzw//////////////8A////////////////tAAAAAAAAAAAAAAAAAAAtP///////////////wD/////////////////VAAAAAAAAAAAAAAAAFT/////////////////AP/////////////////oEAAAAAAAAAAAAAAQ6P////////////////8A//////////////////+cAAAAAAAAAAAAAJz//////////////////wD///////////////////9AAAAAAAAAAABA////////////////////AP///////////////////9gAAAAAAAAAANj///////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Z' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAQ//////////////8A/////////////////////////1AAAAAAAAAABLz//////////////wD///////////////////////98AAAAAAAAAACY////////////////AP//////////////////////pAAAAAAAAAAAaP////////////////8A/////////////////////8QIAAAAAAAAAET8/////////////////wD////////////////////gGAAAAAAAAAAo9P//////////////////AP//////////////////9CwAAAAAAAAAFNz///////////////////8A//////////////////xMAAAAAAAAAATA/////////////////////wD/////////////////eAAAAAAAAAAAnP//////////////////////AP///////////////5wAAAAAAAAAAHT///////////////////////8A///////////////ABAAAAAAAAABM/P///////////////////////wD/////////////3BQAAAAAAAAALPT/////////////////////////AP////////////QoAAAAAAAAABjg//////////////////////////8A///////////8SAAAAAAAAAAExP///////////////////////////wD//////////2wAAAAAAAAAAKD/////////////////////////////AP////////+YAAAAAAAAAAB8//////////////////////////////8A/////////wQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - ); - } -} diff --git a/install/update/old/phpbb/captcha/plugins/qa.php b/install/update/old/phpbb/captcha/plugins/qa.php deleted file mode 100644 index 70b3f72..0000000 --- a/install/update/old/phpbb/captcha/plugins/qa.php +++ /dev/null @@ -1,1040 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\captcha\plugins; - -/** -* And now to something completely different. Let's make a captcha without extending the abstract class. -* QA CAPTCHA sample implementation -*/ -class qa -{ - var $confirm_id; - var $answer; - var $question_ids; - var $question_text; - var $question_lang; - var $question_strict; - var $attempts = 0; - var $type; - // dirty trick: 0 is false, but can still encode that the captcha is not yet validated - var $solved = 0; - - protected $table_captcha_questions; - protected $table_captcha_answers; - protected $table_qa_confirm; - - /** - * @var string name of the service. - */ - protected $service_name; - - /** - * Constructor - * - * @param string $table_captcha_questions - * @param string $table_captcha_answers - * @param string $table_qa_confirm - */ - function __construct($table_captcha_questions, $table_captcha_answers, $table_qa_confirm) - { - $this->table_captcha_questions = $table_captcha_questions; - $this->table_captcha_answers = $table_captcha_answers; - $this->table_qa_confirm = $table_qa_confirm; - } - - /** - * @param int $type as per the CAPTCHA API docs, the type - */ - function init($type) - { - global $config, $db, $user, $request; - - // load our language file - $user->add_lang('captcha_qa'); - - // read input - $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; - - // we need all defined questions - shouldn't be too many, so we can just grab them - // try the user's lang first - $sql = 'SELECT question_id - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'"; - $result = $db->sql_query($sql, 3600); - - while ($row = $db->sql_fetchrow($result)) - { - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - - // fallback to the board default lang - if (!count($this->question_ids)) - { - $this->question_lang = $config['default_lang']; - - $sql = 'SELECT question_id - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query($sql, 7200); - - while ($row = $db->sql_fetchrow($result)) - { - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - } - - // final fallback to any language - 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'; - $result = $db->sql_query($sql, 7200); - - while ($row = $db->sql_fetchrow($result)) - { - if (empty($this->question_lang)) - { - $this->question_lang = $row['lang_iso']; - } - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - } - - // okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one - if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer())) - { - // we have no valid confirm ID, better get ready to ask something - $this->select_question(); - } - } - - /** - * See if the captcha has created its tables. - */ - public function is_installed() - { - global $phpbb_container; - - $db_tool = $phpbb_container->get('dbal.tools'); - - return $db_tool->sql_table_exists($this->table_captcha_questions); - } - - /** - * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang - */ - public function is_available() - { - global $config, $db, $user; - - // load language file for pretty display in the ACP dropdown - $user->add_lang('captcha_qa'); - - if (!$this->is_installed()) - { - return false; - } - - $sql = 'SELECT COUNT(question_id) AS question_count - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - return ((bool) $row['question_count']); - } - - /** - * API function - */ - function has_config() - { - return true; - } - - /** - * API function - */ - static public function get_name() - { - return 'CAPTCHA_QA'; - } - - /** - * @return string the name of the service corresponding to the plugin - */ - function get_service_name() - { - return $this->service_name; - } - - /** - * Set the name of the plugin - * - * @param string $name - */ - public function set_name($name) - { - $this->service_name = $name; - } - - /** - * API function - not needed as we don't display an image - */ - function execute_demo() - { - } - - /** - * API function - not needed as we don't display an image - */ - function execute() - { - } - - /** - * API function - send the question to the template - */ - function get_template() - { - global $phpbb_log, $template, $user; - - if ($this->is_solved()) - { - return false; - } - else if (empty($this->question_text) || !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'))); - return false; - } - else - { - $template->assign_vars(array( - 'QA_CONFIRM_QUESTION' => $this->question_text, - 'QA_CONFIRM_ID' => $this->confirm_id, - 'S_CONFIRM_CODE' => true, - 'S_TYPE' => $this->type, - )); - - return 'captcha_qa.html'; - } - } - - /** - * API function - we just display a mockup so that the captcha doesn't need to be installed - */ - function get_demo_template() - { - global $config, $db, $template; - - if ($this->is_available()) - { - $sql = 'SELECT question_text - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) - { - $template->assign_vars(array( - 'QA_CONFIRM_QUESTION' => $row['question_text'], - )); - } - $db->sql_freeresult($result); - } - return 'captcha_qa_acp_demo.html'; - } - - /** - * API function - */ - function get_hidden_fields() - { - $hidden_fields = array(); - - // this is required - otherwise we would forget about the captcha being already solved - if ($this->solved) - { - $hidden_fields['qa_answer'] = $this->answer; - } - $hidden_fields['qa_confirm_id'] = $this->confirm_id; - - return $hidden_fields; - } - - /** - * API function - */ - function garbage_collect($type = 0) - { - global $db; - - $sql = 'SELECT c.confirm_id - FROM ' . $this->table_qa_confirm . ' c - LEFT JOIN ' . SESSIONS_TABLE . ' s - ON (c.session_id = s.session_id) - WHERE s.session_id IS NULL' . - ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - - do - { - $sql_in[] = (string) $row['confirm_id']; - } - while ($row = $db->sql_fetchrow($result)); - - if (count($sql_in)) - { - $sql = 'DELETE FROM ' . $this->table_qa_confirm . ' - WHERE ' . $db->sql_in_set('confirm_id', $sql_in); - $db->sql_query($sql); - } - } - $db->sql_freeresult($result); - } - - /** - * API function - we don't drop the tables here, as that would cause the loss of all entered questions. - */ - function uninstall() - { - $this->garbage_collect(0); - } - - /** - * API function - set up shop - */ - function install() - { - global $phpbb_container; - - $db_tool = $phpbb_container->get('dbal.tools'); - $schemas = array( - $this->table_captcha_questions => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', null, 'auto_increment'), - 'strict' => array('BOOL', 0), - 'lang_id' => array('UINT', 0), - 'lang_iso' => array('VCHAR:30', ''), - 'question_text' => array('TEXT_UNI', ''), - ), - 'PRIMARY_KEY' => 'question_id', - 'KEYS' => array( - 'lang' => array('INDEX', 'lang_iso'), - ), - ), - $this->table_captcha_answers => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', 0), - 'answer_text' => array('STEXT_UNI', ''), - ), - 'KEYS' => array( - 'qid' => array('INDEX', 'question_id'), - ), - ), - $this->table_qa_confirm => array ( - 'COLUMNS' => array( - 'session_id' => array('CHAR:32', ''), - 'confirm_id' => array('CHAR:32', ''), - 'lang_iso' => array('VCHAR:30', ''), - 'question_id' => array('UINT', 0), - 'attempts' => array('UINT', 0), - 'confirm_type' => array('USINT', 0), - ), - 'KEYS' => array( - 'session_id' => array('INDEX', 'session_id'), - 'lookup' => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')), - ), - 'PRIMARY_KEY' => 'confirm_id', - ), - ); - - foreach ($schemas as $table => $schema) - { - if (!$db_tool->sql_table_exists($table)) - { - $db_tool->sql_create_table($table, $schema); - } - } - } - - /** - * API function - see what has to be done to validate - */ - function validate() - { - global $phpbb_log, $user; - - $error = ''; - - 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'))); - return $user->lang('CONFIRM_QUESTION_MISSING'); - } - - if (!$this->confirm_id) - { - $error = $user->lang['CONFIRM_QUESTION_WRONG']; - } - else - { - if ($this->check_answer()) - { - $this->solved = true; - } - else - { - $error = $user->lang['CONFIRM_QUESTION_WRONG']; - } - } - - if (strlen($error)) - { - // okay, incorrect answer. Let's ask a new question. - $this->new_attempt(); - $this->solved = false; - - return $error; - } - else - { - return false; - } - } - - /** - * Select a question - */ - function select_question() - { - global $db, $user; - - if (!count($this->question_ids)) - { - return; - } - $this->confirm_id = md5(unique_id($user->ip)); - $this->question = (int) array_rand($this->question_ids); - - $sql = 'INSERT INTO ' . $this->table_qa_confirm . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $this->confirm_id, - 'session_id' => (string) $user->session_id, - 'lang_iso' => (string) $this->question_lang, - 'confirm_type' => (int) $this->type, - 'question_id' => (int) $this->question, - )); - $db->sql_query($sql); - - $this->load_answer(); - } - - /** - * New Question, if desired. - */ - function reselect_question() - { - global $db, $user; - - if (!count($this->question_ids)) - { - return; - } - - $this->question = (int) array_rand($this->question_ids); - $this->solved = 0; - - $sql = 'UPDATE ' . $this->table_qa_confirm . ' - SET question_id = ' . (int) $this->question . " - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $db->sql_query($sql); - - $this->load_answer(); - } - - /** - * Wrong answer, so we increase the attempts and use a different question. - */ - function new_attempt() - { - global $db, $user; - - // yah, I would prefer a stronger rand, but this should work - $this->question = (int) array_rand($this->question_ids); - $this->solved = 0; - - $sql = 'UPDATE ' . $this->table_qa_confirm . ' - SET question_id = ' . (int) $this->question . ", - attempts = attempts + 1 - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $db->sql_query($sql); - - $this->load_answer(); - } - - - /** - * See if there is already an entry for the current session. - */ - function load_confirm_id() - { - global $db, $user; - - $sql = 'SELECT confirm_id - FROM ' . $this->table_qa_confirm . " - WHERE - session_id = '" . $db->sql_escape($user->session_id) . "' - AND lang_iso = '" . $db->sql_escape($this->question_lang) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->confirm_id = $row['confirm_id']; - return true; - } - return false; - } - - /** - * Look up everything we need and populate the instance variables. - */ - function load_answer() - { - global $db, $user; - - if (!strlen($this->confirm_id) || !count($this->question_ids)) - { - return false; - } - - $sql = 'SELECT con.question_id, attempts, question_text, strict - FROM ' . $this->table_qa_confirm . ' con, ' . $this->table_captcha_questions . " qes - WHERE con.question_id = qes.question_id - AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->question = $row['question_id']; - - $this->attempts = $row['attempts']; - $this->question_strict = $row['strict']; - $this->question_text = $row['question_text']; - - return true; - } - - return false; - } - - /** - * The actual validation - */ - function check_answer() - { - global $db, $request; - - $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 . ' - WHERE question_id = ' . (int) $this->question; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']); - - if ($solution === $answer) - { - $this->solved = true; - - break; - } - } - $db->sql_freeresult($result); - - return $this->solved; - } - - /** - * API function - */ - function get_attempt_count() - { - return $this->attempts; - } - - /** - * API function - */ - function reset() - { - global $db, $user; - - $sql = 'DELETE FROM ' . $this->table_qa_confirm . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . (int) $this->type; - $db->sql_query($sql); - - // we leave the class usable by generating a new question - $this->select_question(); - } - - /** - * API function - */ - function is_solved() - { - global $request; - - if ($request->variable('qa_answer', false) && $this->solved === 0) - { - $this->validate(); - } - - return (bool) $this->solved; - } - - /** - * API function - The ACP backend, this marks the end of the easy methods - */ - function acp_page($id, $module) - { - global $config, $request, $phpbb_log, $template, $user; - - $user->add_lang('acp/board'); - $user->add_lang('captcha_qa'); - - if (!self::is_installed()) - { - $this->install(); - } - - $module->tpl_name = 'captcha_qa_acp'; - $module->page_title = 'ACP_VC_SETTINGS'; - $form_key = 'acp_captcha'; - add_form_key($form_key); - - $submit = $request->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 . "&configure=1&select_captcha=" . $this->get_service_name(); - - $template->assign_vars(array( - 'U_ACTION' => $module->u_action, - 'QUESTION_ID' => $question_id , - 'CLASS' => $this->get_service_name(), - )); - - // show the list? - if (!$question_id && $action != 'add') - { - $this->acp_question_list($module); - } - else if ($question_id && $action == 'delete') - { - if ($this->get_service_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id)) - { - if (confirm_box(true)) - { - $this->acp_delete_question($question_id); - - trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'question_id' => $question_id, - 'action' => $action, - 'configure' => 1, - 'select_captcha' => $this->get_service_name(), - )) - ); - } - } - else - { - trigger_error($user->lang['QA_LAST_QUESTION'] . adm_back_link($list_url), E_USER_WARNING); - } - } - else - { - // okay, show the editor - $question_input = $this->acp_get_question_input(); - $langs = $this->get_languages(); - - foreach ($langs as $lang => $entry) - { - $template->assign_block_vars('langs', array( - 'ISO' => $lang, - 'NAME' => $entry['name'], - )); - } - - $template->assign_vars(array( - 'U_LIST' => $list_url, - )); - - if ($question_id) - { - if ($question = $this->acp_get_question_data($question_id)) - { - $template->assign_vars(array( - 'QUESTION_TEXT' => ($question_input['question_text']) ? $question_input['question_text'] : $question['question_text'], - 'LANG_ISO' => ($question_input['lang_iso']) ? $question_input['lang_iso'] : $question['lang_iso'], - 'STRICT' => (isset($_REQUEST['strict'])) ? $question_input['strict'] : $question['strict'], - 'ANSWERS' => implode("\n", $question['answers']), - )); - } - else - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); - } - } - else - { - $template->assign_vars(array( - 'QUESTION_TEXT' => $question_input['question_text'], - 'LANG_ISO' => $question_input['lang_iso'], - 'STRICT' => $question_input['strict'], - 'ANSWERS' => (is_array($question_input['answers'])) ? implode("\n", $question_input['answers']) : '', - )); - } - - if ($submit && check_form_key($form_key)) - { - if (!$this->validate_input($question_input)) - { - $template->assign_vars(array( - 'S_ERROR' => true, - )); - } - else - { - if ($question_id) - { - $this->acp_update_question($question_input, $question_id); - } - else - { - $this->acp_add_question($question_input); - } - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL'); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url)); - } - } - else if ($submit) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url), E_USER_WARNING); - } - } - } - - /** - * This handles the list overview - */ - function acp_question_list($module) - { - global $db, $template; - - $sql = 'SELECT * - FROM ' . $this->table_captcha_questions; - $result = $db->sql_query($sql); - - $template->assign_vars(array( - 'S_LIST' => true, - )); - - while ($row = $db->sql_fetchrow($result)) - { - $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_service_name() . '&'; - - $template->assign_block_vars('questions', array( - 'QUESTION_TEXT' => $row['question_text'], - 'QUESTION_ID' => $row['question_id'], - 'QUESTION_LANG' => $row['lang_iso'], - 'U_DELETE' => "{$url}action=delete", - 'U_EDIT' => "{$url}action=edit", - )); - } - $db->sql_freeresult($result); - } - - /** - * Grab a question and bring it into a format the editor understands - */ - function acp_get_question_data($question_id) - { - global $db; - - if ($question_id) - { - $sql = 'SELECT * - FROM ' . $this->table_captcha_questions . ' - WHERE question_id = ' . $question_id; - $result = $db->sql_query($sql); - $question = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$question) - { - return false; - } - - $question['answers'] = array(); - - $sql = 'SELECT * - FROM ' . $this->table_captcha_answers . ' - WHERE question_id = ' . $question_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $question['answers'][] = $row['answer_text']; - } - $db->sql_freeresult($result); - - return $question; - } - - return false; - } - - /** - * Grab a question from input and bring it into a format the editor understands - */ - function acp_get_question_input() - { - global $request; - - $answers = $request->variable('answers', '', true); - - // Convert answers into array and filter if answers are set - if (strlen($answers)) - { - $answers = array_filter(array_map('trim', explode("\n", $answers)), function ($value) { - return $value !== ''; - }); - } - - $question = array( - 'question_text' => $request->variable('question_text', '', true), - 'strict' => $request->variable('strict', false), - 'lang_iso' => $request->variable('lang_iso', ''), - 'answers' => $answers, - ); - return $question; - } - - /** - * Update a question. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_update_question($data, $question_id) - { - global $db, $cache; - - // easier to delete all answers than to figure out which to update - $sql = 'DELETE FROM ' . $this->table_captcha_answers . " WHERE question_id = $question_id"; - $db->sql_query($sql); - - $langs = $this->get_languages(); - $question_ary = $data; - $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id']; - unset($question_ary['answers']); - - $sql = 'UPDATE ' . $this->table_captcha_questions . ' - SET ' . $db->sql_build_array('UPDATE', $question_ary) . " - WHERE question_id = $question_id"; - $db->sql_query($sql); - - $this->acp_insert_answers($data, $question_id); - - $cache->destroy('sql', $this->table_captcha_questions); - } - - /** - * Insert a question. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_add_question($data) - { - global $db, $cache; - - $langs = $this->get_languages(); - $question_ary = $data; - - $question_ary['lang_id'] = $langs[$data['lang_iso']]['id']; - unset($question_ary['answers']); - - $sql = 'INSERT INTO ' . $this->table_captcha_questions . ' ' . $db->sql_build_array('INSERT', $question_ary); - $db->sql_query($sql); - - $question_id = $db->sql_nextid(); - - $this->acp_insert_answers($data, $question_id); - - $cache->destroy('sql', $this->table_captcha_questions); - } - - /** - * Insert the answers. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_insert_answers($data, $question_id) - { - global $db, $cache; - - foreach ($data['answers'] as $answer) - { - $answer_ary = array( - 'question_id' => $question_id, - 'answer_text' => $answer, - ); - - $sql = 'INSERT INTO ' . $this->table_captcha_answers . ' ' . $db->sql_build_array('INSERT', $answer_ary); - $db->sql_query($sql); - } - - $cache->destroy('sql', $this->table_captcha_answers); - } - - /** - * Delete a question. - */ - function acp_delete_question($question_id) - { - global $db, $cache; - - $tables = array($this->table_captcha_questions, $this->table_captcha_answers); - - foreach ($tables as $table) - { - $sql = "DELETE FROM $table - WHERE question_id = $question_id"; - $db->sql_query($sql); - } - - $cache->destroy('sql', $tables); - } - - /** - * Check if the entered data can be inserted/used - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function validate_input($question_data) - { - $langs = $this->get_languages(); - - if (!isset($question_data['lang_iso']) || - !isset($question_data['question_text']) || - !isset($question_data['strict']) || - !isset($question_data['answers'])) - { - return false; - } - - if (!isset($langs[$question_data['lang_iso']]) || - !strlen($question_data['question_text']) || - !count($question_data['answers']) || - !is_array($question_data['answers'])) - { - return false; - } - - return true; - } - - /** - * List the installed language packs - */ - function get_languages() - { - global $db; - - $sql = 'SELECT * - FROM ' . LANG_TABLE; - $result = $db->sql_query($sql); - - $langs = array(); - while ($row = $db->sql_fetchrow($result)) - { - $langs[$row['lang_iso']] = array( - 'name' => $row['lang_local_name'], - 'id' => (int) $row['lang_id'], - ); - } - $db->sql_freeresult($result); - - return $langs; - } - - - - /** - * See if there is a question other than the one we have - */ - function acp_is_last($question_id) - { - global $config, $db; - - if ($question_id) - { - $sql = 'SELECT question_id - FROM ' . $this->table_captcha_questions . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "' - AND question_id <> " . (int) $question_id; - $result = $db->sql_query_limit($sql, 1); - $question = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$question) - { - return true; - } - return false; - } - } -} diff --git a/install/update/old/phpbb/class_loader.php b/install/update/old/phpbb/class_loader.php deleted file mode 100644 index cfdcc2a..0000000 --- a/install/update/old/phpbb/class_loader.php +++ /dev/null @@ -1,164 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* The class loader resolves class names to file system paths and loads them if -* necessary. -* -* Classes have to be of the form phpbb_(dir_)*(classpart_)*, so directory names -* must never contain underscores. Example: phpbb_dir_subdir_class_name is a -* valid class name, while phpbb_dir_sub_dir_class_name is not. -* -* If every part of the class name is a directory, the last directory name is -* also used as the filename, e.g. phpbb_dir would resolve to dir/dir.php. -*/ -class class_loader -{ - private $namespace; - private $path; - private $php_ext; - private $cache; - - /** - * A map of looked up class names to paths relative to $this->path. - * This map is stored in cache and looked up if the cache is available. - * - * @var array - */ - private $cached_paths = array(); - - /** - * Creates a new \phpbb\class_loader, which loads files with the given - * file extension from the given path. - * - * @param string $namespace Required namespace for files to be loaded - * @param string $path Directory to load files from - * @param string $php_ext The file extension for PHP files - * @param \phpbb\cache\driver\driver_interface $cache An implementation of the phpBB cache interface. - */ - public function __construct($namespace, $path, $php_ext = 'php', \phpbb\cache\driver\driver_interface $cache = null) - { - if ($namespace[0] !== '\\') - { - $namespace = '\\' . $namespace; - } - - $this->namespace = $namespace; - $this->path = $path; - $this->php_ext = $php_ext; - - $this->set_cache($cache); - } - - /** - * Provide the class loader with a cache to store paths. If set to null, the - * the class loader will resolve paths by checking for the existance of every - * directory in the class name every time. - * - * @param \phpbb\cache\driver\driver_interface $cache An implementation of the phpBB cache interface. - */ - public function set_cache(\phpbb\cache\driver\driver_interface $cache = null) - { - if ($cache) - { - $this->cached_paths = $cache->get('class_loader_' . str_replace('\\', '__', $this->namespace)); - - if ($this->cached_paths === false) - { - $this->cached_paths = array(); - } - } - - $this->cache = $cache; - } - - /** - * Registers the class loader as an autoloader using SPL. - */ - public function register() - { - spl_autoload_register(array($this, 'load_class')); - } - - /** - * Removes the class loader from the SPL autoloader stack. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'load_class')); - } - - /** - * Resolves a phpBB class name to a relative path which can be included. - * - * @param string $class The class name to resolve, must be in the - * namespace the loader was constructed with. - * Has to begin with \ - * @return string|bool A relative path to the file containing the - * class or false if looking it up failed. - */ - public function resolve_path($class) - { - if (isset($this->cached_paths[$class])) - { - return $this->path . $this->cached_paths[$class] . '.' . $this->php_ext; - } - - if (!preg_match('/^' . preg_quote($this->namespace, '/') . '[a-zA-Z0-9_\\\\]+$/', $class)) - { - return false; - } - - $relative_path = str_replace('\\', '/', substr($class, strlen($this->namespace))); - - if (!file_exists($this->path . $relative_path . '.' . $this->php_ext)) - { - return false; - } - - if ($this->cache) - { - $this->cached_paths[$class] = $relative_path; - $this->cache->put('class_loader_' . str_replace('\\', '__', $this->namespace), $this->cached_paths); - } - - return $this->path . $relative_path . '.' . $this->php_ext; - } - - /** - * Resolves a class name to a path and then includes it. - * - * @param string $class The class name which is being loaded. - */ - public function load_class($class) - { - // In general $class is not supposed to contain a leading backslash, - // but sometimes it does. See tickets PHP-50731 and HHVM-1840. - if ($class[0] !== '\\') - { - $class = '\\' . $class; - } - - if (substr($class, 0, strlen($this->namespace)) === $this->namespace) - { - $path = $this->resolve_path($class); - - if ($path) - { - require $path; - } - } - } -} diff --git a/install/update/old/phpbb/config/config.php b/install/update/old/phpbb/config/config.php deleted file mode 100644 index aaad333..0000000 --- a/install/update/old/phpbb/config/config.php +++ /dev/null @@ -1,167 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\config; - -/** -* Configuration container class -*/ -class config implements \ArrayAccess, \IteratorAggregate, \Countable -{ - /** - * The configuration data - * @var array(string => string) - */ - protected $config; - - /** - * Creates a configuration container with a default set of values - * - * @param array(string => string) $config The configuration data. - */ - public function __construct(array $config) - { - $this->config = $config; - } - - /** - * Retrieves an ArrayIterator over the configuration values. - * - * @return \ArrayIterator An iterator over all config data - */ - public function getIterator() - { - return new \ArrayIterator($this->config); - } - - /** - * Checks if the specified config value exists. - * - * @param string $key The configuration option's name. - * @return bool Whether the configuration option exists. - */ - public function offsetExists($key) - { - return isset($this->config[$key]); - } - - /** - * Retrieves a configuration value. - * - * @param string $key The configuration option's name. - * @return string The configuration value - */ - public function offsetGet($key) - { - return (isset($this->config[$key])) ? $this->config[$key] : ''; - } - - /** - * Temporarily overwrites the value of a configuration variable. - * - * The configuration change will not persist. It will be lost - * after the request. - * - * @param string $key The configuration option's name. - * @param string $value The temporary value. - */ - public function offsetSet($key, $value) - { - $this->config[$key] = $value; - } - - /** - * Called when deleting a configuration value directly, triggers an error. - * - * @param string $key The configuration option's name. - */ - public function offsetUnset($key) - { - trigger_error('Config values have to be deleted explicitly with the \phpbb\config\config::delete($key) method.', E_USER_ERROR); - } - - /** - * Retrieves the number of configuration options currently set. - * - * @return int Number of config options - */ - public function count() - { - return count($this->config); - } - - /** - * Removes a configuration option - * - * @param String $key The configuration option's name - * @param bool $use_cache Whether this variable should be cached or if it - * changes too frequently to be efficiently cached - * @return null - */ - public function delete($key, $use_cache = true) - { - unset($this->config[$key]); - } - - /** - * Sets a configuration option's value - * - * @param string $key The configuration option's name - * @param string $value New configuration value - * @param bool $use_cache Whether this variable should be cached or if it - * changes too frequently to be efficiently cached. - */ - public function set($key, $value, $use_cache = true) - { - $this->config[$key] = $value; - } - - /** - * Sets a configuration option's value only if the old_value matches the - * current configuration value or the configuration value does not exist yet. - * - * @param string $key The configuration option's name - * @param string $old_value Current configuration value - * @param string $new_value New configuration value - * @param bool $use_cache Whether this variable should be cached or if it - * changes too frequently to be efficiently cached. - * @return bool True if the value was changed, false otherwise. - */ - public function set_atomic($key, $old_value, $new_value, $use_cache = true) - { - if (!isset($this->config[$key]) || $this->config[$key] == $old_value) - { - $this->config[$key] = $new_value; - return true; - } - return false; - } - - /** - * Increments an integer configuration value. - * - * @param string $key The configuration option's name - * @param int $increment Amount to increment by - * @param bool $use_cache Whether this variable should be cached or if it - * changes too frequently to be efficiently cached. - */ - function increment($key, $increment, $use_cache = true) - { - if (!isset($this->config[$key])) - { - $this->config[$key] = 0; - } - - $this->config[$key] += $increment; - } -} diff --git a/install/update/old/phpbb/config_php_file.php b/install/update/old/phpbb/config_php_file.php deleted file mode 100644 index 7445e7d..0000000 --- a/install/update/old/phpbb/config_php_file.php +++ /dev/null @@ -1,160 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -class config_php_file -{ - /** @var string phpBB Root Path */ - protected $phpbb_root_path; - - /** @var string php file extension */ - protected $php_ext; - - /** - * Indicates whether the php config file has been loaded. - * - * @var bool - */ - protected $config_loaded = false; - - /** - * The content of the php config file - * - * @var array - */ - protected $config_data = array(); - - /** - * The path to the config file. (Default: $phpbb_root_path . 'config.' . $php_ext) - * - * @var string - */ - protected $config_file; - - private $defined_vars; - - /** - * Constructor - * - * @param string $phpbb_root_path phpBB Root Path - * @param string $php_ext php file extension - */ - function __construct($phpbb_root_path, $php_ext) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - $this->config_file = $this->phpbb_root_path . 'config.' . $this->php_ext; - } - - /** - * Set the path to the config file. - * - * @param string $config_file - */ - public function set_config_file($config_file) - { - $this->config_file = $config_file; - $this->config_loaded = false; - } - - /** - * Returns an associative array containing the variables defined by the config file. - * - * @return array Return the content of the config file or an empty array if the file does not exists. - */ - public function get_all() - { - $this->load_config_file(); - - return $this->config_data; - } - - /** - * Return the value of a variable defined into the config.php file or null if the variable does not exist. - * - * @param string $variable The name of the variable - * @return mixed Value of the variable or null if the variable is not defined. - */ - public function get($variable) - { - $this->load_config_file(); - - return isset($this->config_data[$variable]) ? $this->config_data[$variable] : null; - } - - /** - * Load the config file and store the information. - * - * @return null - */ - protected function load_config_file() - { - if (!$this->config_loaded && file_exists($this->config_file)) - { - $this->defined_vars = get_defined_vars(); - - require($this->config_file); - $this->config_data = array_diff_key(get_defined_vars(), $this->defined_vars); - - $this->config_loaded = true; - } - } - - /** - * Convert either 3.0 dbms or 3.1 db driver class name to 3.1 db driver class name. - * - * If $dbms is a valid 3.1 db driver class name, returns it unchanged. - * Otherwise prepends phpbb\db\driver\ to the dbms to convert a 3.0 dbms - * to 3.1 db driver class name. - * - * @param string $dbms dbms parameter - * @return string driver class - * @throws \RuntimeException - */ - public function convert_30_dbms_to_31($dbms) - { - // Note: this check is done first because mysqli extension - // supplies a mysqli class, and class_exists($dbms) would return - // true for mysqli class. - // However, per the docblock any valid 3.1 driver name should be - // recognized by this function, and have priority over 3.0 dbms. - if (strpos($dbms, 'phpbb\db\driver') === false && class_exists('phpbb\db\driver\\' . $dbms)) - { - return 'phpbb\db\driver\\' . $dbms; - } - - if (class_exists($dbms)) - { - // Additionally we could check that $dbms extends phpbb\db\driver\driver. - // http://php.net/manual/en/class.reflectionclass.php - // Beware of possible performance issues: - // http://stackoverflow.com/questions/294582/php-5-reflection-api-performance - // We could check for interface implementation in all paths or - // only when we do not prepend phpbb\db\driver\. - - /* - $reflection = new \ReflectionClass($dbms); - - if ($reflection->isSubclassOf('phpbb\db\driver\driver')) - { - return $dbms; - } - */ - - return $dbms; - } - - throw new \RuntimeException("You have specified an invalid dbms driver: $dbms"); - } -} diff --git a/install/update/old/phpbb/console/command/cron/run.php b/install/update/old/phpbb/console/command/cron/run.php deleted file mode 100644 index dea6493..0000000 --- a/install/update/old/phpbb/console/command/cron/run.php +++ /dev/null @@ -1,171 +0,0 @@ - -* @license 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\cron; - -use phpbb\exception\runtime_exception; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Output\OutputInterface; - -class run extends \phpbb\console\command\command -{ - /** @var \phpbb\cron\manager */ - protected $cron_manager; - - /** @var \phpbb\lock\db */ - protected $lock_db; - - /** - * Construct method - * - * @param \phpbb\user $user The user object (used to get language information) - * @param \phpbb\cron\manager $cron_manager The cron manager containing - * the cron tasks to be executed. - * @param \phpbb\lock\db $lock_db The lock for accessing database. - */ - public function __construct(\phpbb\user $user, \phpbb\cron\manager $cron_manager, \phpbb\lock\db $lock_db) - { - $this->cron_manager = $cron_manager; - $this->lock_db = $lock_db; - parent::__construct($user); - } - - /** - * Sets the command name and description - * - * @return null - */ - protected function configure() - { - $this - ->setName('cron:run') - ->setDescription($this->user->lang('CLI_DESCRIPTION_CRON_RUN')) - ->setHelp($this->user->lang('CLI_HELP_CRON_RUN')) - ->addArgument('name', InputArgument::OPTIONAL, $this->user->lang('CLI_DESCRIPTION_CRON_RUN_ARGUMENT_1')) - ; - } - - /** - * Executes the command cron:run. - * - * Tries to acquire the cron lock, then if no argument has been given runs all ready cron tasks. - * If the cron lock can not be obtained, an error message is printed - * and the exit status is set to 1. - * If the verbose option is specified, each start of a task is printed. - * Otherwise there is no output. - * If an argument is given to the command, only the task whose name matches the - * argument will be started. If verbose option is specified, - * an info message containing the name of the task is printed. - * If no task matches the argument given, an error message is printed - * and the exit status is set to 2. - * - * @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 lock error occured and 2 if no task matching the argument was found. - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - if ($this->lock_db->acquire()) - { - $task_name = $input->getArgument('name'); - if ($task_name) - { - $exit_status = $this->run_one($input, $output, $task_name); - } - else - { - $exit_status = $this->run_all($input, $output); - } - - $this->lock_db->release(); - return $exit_status; - } - else - { - throw new runtime_exception('CRON_LOCK_ERROR', array(), null, 1); - } - } - - /** - * Executes all ready cron tasks. - * - * If verbose mode is set, an info message will be printed if there is no task to - * be run, or else for each starting task. - * - * @see execute - * @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 - */ - protected function run_all(InputInterface $input, OutputInterface $output) - { - $run_tasks = $this->cron_manager->find_all_ready_tasks(); - - if ($run_tasks) - { - foreach ($run_tasks as $task) - { - if ($input->getOption('verbose')) - { - $output->writeln('' . $this->user->lang('RUNNING_TASK', $task->get_name()) . ''); - } - - $task->run(); - } - } - else - { - if ($input->getOption('verbose')) - { - $output->writeln('' . $this->user->lang('CRON_NO_TASK') . ''); - } - } - - return 0; - } - - /** - * Executes a given cron task, if it is ready. - * - * If there is a task whose name matches $task_name, it is run and 0 is returned. - * and if verbose mode is set, print an info message with the name of the task. - * If there is no task matching $task_name, the function prints an error message - * and returns with status 2. - * - * @see execute - * @param string $task_name The name of the task that should be run. - * @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 well, 2 if no task matches $task_name. - */ - protected function run_one(InputInterface $input, OutputInterface $output, $task_name) - { - $task = $this->cron_manager->find_task($task_name); - if ($task) - { - if ($input->getOption('verbose')) - { - $output->writeln('' . $this->user->lang('RUNNING_TASK', $task_name) . ''); - } - - $task->run(); - return 0; - } - else - { - throw new runtime_exception('CRON_NO_SUCH_TASK', array( $task_name), null, 2); - } - } -} diff --git a/install/update/old/phpbb/console/command/extension/enable.php b/install/update/old/phpbb/console/command/extension/enable.php deleted file mode 100644 index a6f5b10..0000000 --- a/install/update/old/phpbb/console/command/extension/enable.php +++ /dev/null @@ -1,76 +0,0 @@ - -* @license 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\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 -{ - protected function configure() - { - $this - ->setName('extension:enable') - ->setDescription($this->user->lang('CLI_DESCRIPTION_ENABLE_EXTENSION')) - ->addArgument( - 'extension-name', - InputArgument::REQUIRED, - $this->user->lang('CLI_EXTENSION_NAME') - ) - ; - } - - 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)); - $io->success($this->user->lang('CLI_EXTENSION_ENABLE_SUCCESS', $name)); - return 0; - } - else - { - $io->error($this->user->lang('CLI_EXTENSION_ENABLE_FAILURE', $name)); - return 1; - } - } -} diff --git a/install/update/old/phpbb/console/command/update/check.php b/install/update/old/phpbb/console/command/update/check.php deleted file mode 100644 index 9ced651..0000000 --- a/install/update/old/phpbb/console/command/update/check.php +++ /dev/null @@ -1,331 +0,0 @@ - -* @license 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("%s", $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("%s", $metadata['version']); - $row[] = implode(', ', $versions); - } - else - { - $row[] = sprintf("%s", $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[] = '' . $exception_message . ''; - } - catch (\RuntimeException $e) - { - $row[] = '' . $e->getMessage() . ''; - } - - $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/install/update/old/phpbb/console/command/user/add.php b/install/update/old/phpbb/console/command/user/add.php deleted file mode 100644 index c60a059..0000000 --- a/install/update/old/phpbb/console/command/user/add.php +++ /dev/null @@ -1,334 +0,0 @@ - - * @license 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/install/update/old/phpbb/content_visibility.php b/install/update/old/phpbb/content_visibility.php deleted file mode 100644 index f023e07..0000000 --- a/install/update/old/phpbb/content_visibility.php +++ /dev/null @@ -1,885 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* phpbb_visibility -* Handle fetching and setting the visibility for topics and posts -*/ -class content_visibility -{ - /** - * Database object - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Auth object - * @var \phpbb\auth\auth - */ - protected $auth; - - /** - * config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * phpBB root path - * @var string - */ - protected $phpbb_root_path; - - /** - * PHP Extension - * @var string - */ - protected $php_ext; - - /** - * Constructor - * - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\user $user User object - * @param string $phpbb_root_path Root path - * @param string $php_ext PHP Extension - * @param string $forums_table Forums table name - * @param string $posts_table Posts table name - * @param string $topics_table Topics table name - * @param string $users_table Users table name - */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table) - { - $this->auth = $auth; - $this->config = $config; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->db = $db; - $this->user = $user; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - $this->forums_table = $forums_table; - $this->posts_table = $posts_table; - $this->topics_table = $topics_table; - $this->users_table = $users_table; - } - - /** - * Can the current logged-in user soft-delete posts? - * - * @param $forum_id int Forum ID whose permissions to check - * @param $poster_id int Poster ID of the post in question - * @param $post_locked bool Is the post locked? - * @return bool - */ - public function can_soft_delete($forum_id, $poster_id, $post_locked) - { - if ($this->auth->acl_get('m_softdelete', $forum_id)) - { - return true; - } - else if ($this->auth->acl_get('f_softdelete', $forum_id) && $poster_id == $this->user->data['user_id'] && !$post_locked) - { - return true; - } - - return false; - } - - /** - * Get the topics post count or the forums post/topic count based on permissions - * - * @param $mode string One of topic_posts, forum_posts or forum_topics - * @param $data array Array with the topic/forum data to calculate from - * @param $forum_id int The forum id is used for permission checks - * @return int Number of posts/topics the user can see in the topic/forum - */ - public function get_count($mode, $data, $forum_id) - { - if (!$this->auth->acl_get('m_approve', $forum_id)) - { - return (int) $data[$mode . '_approved']; - } - - 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 - * - * 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 $table_alias string Table alias to prefix in SQL queries - * @return string The appropriate combination SQL logic for topic/post_visibility - */ - public function get_visibility_sql($mode, $forum_id, $table_alias = '') - { - $where_sql = ''; - - $get_visibility_sql_overwrite = false; - - /** - * Allow changing the result of calling get_visibility_sql - * - * @event core.phpbb_content_visibility_get_visibility_sql_before - * @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_id The forum id in which the search is made. - * @var string table_alias Table alias to prefix in SQL queries - * @var mixed get_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event - * If false, get_visibility_sql continues normally - * It must be either boolean or string - * @since 3.1.4-RC1 - */ - $vars = array( - 'where_sql', - 'mode', - 'forum_id', - 'table_alias', - 'get_visibility_sql_overwrite', - ); - extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_visibility_sql_before', compact($vars))); - - if ($get_visibility_sql_overwrite !== false) - { - return $get_visibility_sql_overwrite; - } - - if ($this->auth->acl_get('m_approve', $forum_id)) - { - $where_sql .= '1 = 1'; - } - else - { - $where_sql .= $table_alias . $mode . '_visibility = ' . ITEM_APPROVED; - } - - return '(' . $where_sql . ')'; - } - - /** - * Create topic/post visibility SQL for a set of forums - * - * Note: Read permissions are not checked. Forums without read permissions - * should not be in $forum_ids - * - * @param $mode string Either "topic" or "post" - * @param $forum_ids array Array of forum ids which the posts/topics are limited to - * @param $table_alias string Table alias to prefix in SQL queries - * @return string The appropriate combination SQL logic for topic/post_visibility - */ - public function get_forums_visibility_sql($mode, $forum_ids = array(), $table_alias = '') - { - $where_sql = ''; - - $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 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 - * @var array approve_forums Array of forums where the user has m_approve permissions - * @var mixed get_forums_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event - * If false, get_forums_visibility_sql continues normally - * It must be either boolean or string - * @since 3.1.3-RC1 - */ - $vars = array( - 'where_sql', - 'mode', - 'forum_ids', - 'table_alias', - 'approve_forums', - 'get_forums_visibility_sql_overwrite', - ); - extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_forums_visibility_before', compact($vars))); - - if ($get_forums_visibility_sql_overwrite !== false) - { - return $get_forums_visibility_sql_overwrite; - } - - // 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, false, true) . '))'; - - return '(' . $where_sql . ')'; - } - - /** - * Create topic/post visibility SQL for all forums on the board - * - * Note: Read permissions are not checked. Forums without read permissions - * should be in $exclude_forum_ids - * - * @param $mode string Either "topic" or "post" - * @param $exclude_forum_ids array Array of forum ids which are excluded - * @param $table_alias string Table alias to prefix in SQL queries - * @return string The appropriate combination SQL logic for topic/post_visibility - */ - public function get_global_visibility_sql($mode, $exclude_forum_ids = array(), $table_alias = '') - { - $where_sqls = array(); - - $approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids); - - $visibility_sql_overwrite = null; - - /** - * Allow changing the result of calling get_global_visibility_sql - * - * @event core.phpbb_content_visibility_get_global_visibility_before - * @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 If not empty, forces the function to return visibility_sql_overwrite after executing the event - * @since 3.1.3-RC1 - */ - $vars = array( - 'where_sqls', - 'mode', - 'exclude_forum_ids', - 'table_alias', - 'approve_forums', - 'visibility_sql_overwrite', - ); - extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_global_visibility_before', compact($vars))); - - if ($visibility_sql_overwrite) - { - return $visibility_sql_overwrite; - } - - // 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 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) . ')'; - } - - /** - * Change visibility status of one post or all posts of a topic - * - * @param $visibility int Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @param $post_id mixed Post ID or array of post IDs to act on, - * if it is empty, all posts of topic_id will be modified - * @param $topic_id int Topic where $post_id is found - * @param $forum_id int Forum where $topic_id is found - * @param $user_id int User performing the action - * @param $time int Timestamp when the action is performed - * @param $reason string Reason why the visibility was changed. - * @param $is_starter bool Is this the first post of the topic changed? - * @param $is_latest bool Is this the last post of the topic changed? - * @param $limit_visibility mixed Limit updating per topic_id to a certain visibility - * @param $limit_delete_time mixed Limit updating per topic_id to a certain deletion time - * @return array Changed post data, empty array if an error occurred. - */ - public function set_post_visibility($visibility, $post_id, $topic_id, $forum_id, $user_id, $time, $reason, $is_starter, $is_latest, $limit_visibility = false, $limit_delete_time = false) - { - if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE))) - { - return array(); - } - - if ($post_id) - { - if (is_array($post_id)) - { - $where_sql = $this->db->sql_in_set('post_id', array_map('intval', $post_id)); - } - else - { - $where_sql = 'post_id = ' . (int) $post_id; - } - $where_sql .= ' AND topic_id = ' . (int) $topic_id; - } - else - { - $where_sql = 'topic_id = ' . (int) $topic_id; - - // Limit the posts to a certain visibility and deletion time - // This allows us to only restore posts, that were approved - // when the topic got soft deleted. So previous soft deleted - // and unapproved posts are still soft deleted/unapproved - if ($limit_visibility !== false) - { - $where_sql .= ' AND post_visibility = ' . (int) $limit_visibility; - } - - if ($limit_delete_time !== false) - { - $where_sql .= ' AND post_delete_time = ' . (int) $limit_delete_time; - } - } - - $sql = 'SELECT poster_id, post_id, post_postcount, post_visibility - FROM ' . $this->posts_table . ' - WHERE ' . $where_sql; - $result = $this->db->sql_query($sql); - - $post_ids = $poster_postcounts = $postcounts = $postcount_visibility = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $post_ids[] = (int) $row['post_id']; - - if ($row['post_visibility'] != $visibility) - { - if ($row['post_postcount'] && !isset($poster_postcounts[(int) $row['poster_id']])) - { - $poster_postcounts[(int) $row['poster_id']] = 1; - } - else if ($row['post_postcount']) - { - $poster_postcounts[(int) $row['poster_id']]++; - } - - if (!isset($postcount_visibility[$row['post_visibility']])) - { - $postcount_visibility[$row['post_visibility']] = 1; - } - else - { - $postcount_visibility[$row['post_visibility']]++; - } - } - } - $this->db->sql_freeresult($result); - - if (empty($post_ids)) - { - return array(); - } - - if (!function_exists('truncate_string')) - { - include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext); - } - - $data = array( - 'post_visibility' => (int) $visibility, - 'post_delete_user' => (int) $user_id, - 'post_delete_time' => ((int) $time) ?: time(), - 'post_delete_reason' => truncate_string($reason, 255, 255, false), - ); - /** - * Perform actions right before the query to change post visibility - * - * @event core.set_post_visibility_before_sql - * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @var array post_id Array containing all post IDs to be modified. If blank, all posts within the topic are modified. - * @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 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', - 'post_id', - 'topic_id', - 'forum_id', - 'user_id', - 'time', - 'reason', - 'is_starter', - 'is_latest', - 'data', - ); - extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_before_sql', compact($vars))); - $sql = 'UPDATE ' . $this->posts_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $data) . ' - WHERE ' . $this->db->sql_in_set('post_id', $post_ids); - $this->db->sql_query($sql); - - // Group the authors by post count, to reduce the number of queries - foreach ($poster_postcounts as $poster_id => $num_posts) - { - $postcounts[$num_posts][] = $poster_id; - } - - // Update users postcounts - foreach ($postcounts as $num_posts => $poster_ids) - { - if (in_array($visibility, array(ITEM_REAPPROVE, ITEM_DELETED))) - { - $sql = 'UPDATE ' . $this->users_table . ' - SET user_posts = 0 - WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . ' - AND user_posts < ' . $num_posts; - $this->db->sql_query($sql); - - $sql = 'UPDATE ' . $this->users_table . ' - SET user_posts = user_posts - ' . $num_posts . ' - WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . ' - AND user_posts >= ' . $num_posts; - $this->db->sql_query($sql); - } - else - { - $sql = 'UPDATE ' . $this->users_table . ' - SET user_posts = user_posts + ' . $num_posts . ' - WHERE ' . $this->db->sql_in_set('user_id', $poster_ids); - $this->db->sql_query($sql); - } - } - - $update_topic_postcount = true; - - // Sync the first/last topic information if needed - if (!$is_starter && $is_latest) - { - if (!function_exists('update_post_information')) - { - include($this->phpbb_root_path . 'includes/functions_posting.' . $this->php_ext); - } - - // update_post_information can only update the last post info ... - if ($topic_id) - { - update_post_information('topic', $topic_id, false); - } - if ($forum_id) - { - update_post_information('forum', $forum_id, false); - } - } - else if ($is_starter && $topic_id) - { - if (!function_exists('sync')) - { - include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext); - } - - // ... so we need to use sync, if the first post is changed. - // The forum is resynced recursive by sync() itself. - sync('topic', 'topic_id', $topic_id, true); - - // sync recalculates the topic replies and forum posts by itself, so we don't do that. - $update_topic_postcount = false; - } - - $topic_update_array = array(); - // Update the topic's reply count and the forum's post count - if ($update_topic_postcount) - { - $field_alias = array( - ITEM_APPROVED => 'posts_approved', - ITEM_UNAPPROVED => 'posts_unapproved', - ITEM_DELETED => 'posts_softdeleted', - ITEM_REAPPROVE => 'posts_unapproved', - ); - $cur_posts = array_fill_keys($field_alias, 0); - - foreach ($postcount_visibility as $post_visibility => $visibility_posts) - { - $cur_posts[$field_alias[(int) $post_visibility]] += $visibility_posts; - } - - $sql_ary = array(); - $recipient_field = $field_alias[$visibility]; - - foreach ($cur_posts as $field => $count) - { - // Decrease the count for the old statuses. - if ($count && $field != $recipient_field) - { - $sql_ary[$field] = " - $count"; - } - } - // Add up the count from all statuses excluding the recipient status. - $count_increase = array_sum(array_diff($cur_posts, array($recipient_field))); - - if ($count_increase) - { - $sql_ary[$recipient_field] = " + $count_increase"; - } - - if (count($sql_ary)) - { - $forum_sql = array(); - - foreach ($sql_ary as $field => $value_change) - { - $topic_update_array[] = 'topic_' . $field . ' = topic_' . $field . $value_change; - $forum_sql[] = 'forum_' . $field . ' = forum_' . $field . $value_change; - } - - $sql = 'UPDATE ' . $this->forums_table . ' - SET ' . implode(', ', $forum_sql) . ' - WHERE forum_id = ' . (int) $forum_id; - $this->db->sql_query($sql); - } - } - - if ($post_id) - { - $sql = 'SELECT 1 AS has_attachments - FROM ' . POSTS_TABLE . ' - WHERE topic_id = ' . (int) $topic_id . ' - AND post_attachment = 1 - AND post_visibility = ' . ITEM_APPROVED . ' - AND ' . $this->db->sql_in_set('post_id', $post_id, true); - $result = $this->db->sql_query_limit($sql, 1); - - $has_attachment = (bool) $this->db->sql_fetchfield('has_attachments'); - $this->db->sql_freeresult($result); - - if ($has_attachment && $visibility == ITEM_APPROVED) - { - $topic_update_array[] = 'topic_attachment = 1'; - } - else if (!$has_attachment && $visibility != ITEM_APPROVED) - { - $topic_update_array[] = 'topic_attachment = 0'; - } - } - - if (!empty($topic_update_array)) - { - // Update the number for replies and posts, and update the attachments flag - $sql = 'UPDATE ' . $this->topics_table . ' - SET ' . implode(', ', $topic_update_array) . ' - WHERE topic_id = ' . (int) $topic_id; - $this->db->sql_query($sql); - } - /** - * Perform actions after all steps to changing post visibility - * - * @event core.set_post_visibility_after - * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @var array post_id Array containing all post IDs to be modified. If blank, all posts within the topic are modified. - * @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 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', - 'post_id', - 'topic_id', - 'forum_id', - 'user_id', - 'time', - 'reason', - 'is_starter', - 'is_latest', - 'data', - ); - extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_after', compact($vars))); - return $data; - } - - /** - * Set topic visibility - * - * Allows approving (which is akin to undeleting/restore) or soft deleting an entire topic. - * Calls set_post_visibility as needed. - * - * Note: By default, when a soft deleted topic is restored. Only posts that - * were approved at the time of soft deleting, are being restored. - * Same applies to soft deleting. Only approved posts will be marked - * as soft deleted. - * If you want to update all posts, use the force option. - * - * @param $visibility int Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @param $topic_id mixed Topic ID to act on - * @param $forum_id int Forum where $topic_id is found - * @param $user_id int User performing the action - * @param $time int Timestamp when the action is performed - * @param $reason string Reason why the visibilty was changed. - * @param $force_update_all bool Force to update all posts within the topic - * @return array Changed topic data, empty array if an error occured. - */ - public function set_topic_visibility($visibility, $topic_id, $forum_id, $user_id, $time, $reason, $force_update_all = false) - { - if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE))) - { - return array(); - } - - if (!$force_update_all) - { - $sql = 'SELECT topic_visibility, topic_delete_time - FROM ' . $this->topics_table . ' - WHERE topic_id = ' . (int) $topic_id; - $result = $this->db->sql_query($sql); - $original_topic_data = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if (!$original_topic_data) - { - // The topic does not exist... - return array(); - } - } - - if (!function_exists('truncate_string')) - { - include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext); - } - - // Note, we do not set a reason for the posts, just for the topic - $data = array( - 'topic_visibility' => (int) $visibility, - 'topic_delete_user' => (int) $user_id, - 'topic_delete_time' => ((int) $time) ?: time(), - 'topic_delete_reason' => truncate_string($reason, 255, 255, false), - ); - /** - * Perform actions right before the query to change topic visibility - * - * @event core.set_topic_visibility_before_sql - * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @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 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', - 'time', - 'reason', - 'force_update_all', - 'data', - ); - extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_before_sql', compact($vars))); - $sql = 'UPDATE ' . $this->topics_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $data) . ' - WHERE topic_id = ' . (int) $topic_id; - $this->db->sql_query($sql); - - if (!$this->db->sql_affectedrows()) - { - return array(); - } - - if (!$force_update_all && $original_topic_data['topic_delete_time'] && $original_topic_data['topic_visibility'] == ITEM_DELETED && $visibility == ITEM_APPROVED) - { - // If we're restoring a topic we only restore posts, that were soft deleted through the topic soft deletion. - $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility'], $original_topic_data['topic_delete_time']); - } - else if (!$force_update_all && $original_topic_data['topic_visibility'] == ITEM_APPROVED && $visibility == ITEM_DELETED) - { - // If we're soft deleting a topic we only mark approved posts as soft deleted. - $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility']); - } - else - { - $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true); - } - /** - * Perform actions after all steps to changing topic visibility - * - * @event core.set_topic_visibility_after - * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE} - * @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 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', - 'time', - 'reason', - 'force_update_all', - 'data', - ); - extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_after', compact($vars))); - return $data; - } - - /** - * Add post to topic and forum statistics - * - * @param $data array Contains information from the topics table about given topic - * @param &$sql_data array Populated with the SQL changes, may be empty at call time - * @return null - */ - public function add_post_to_statistic($data, &$sql_data) - { - $sql_data[$this->topics_table] = (($sql_data[$this->topics_table]) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved + 1'; - - $sql_data[$this->forums_table] = (($sql_data[$this->forums_table]) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved + 1'; - - if ($data['post_postcount']) - { - $sql_data[$this->users_table] = (($sql_data[$this->users_table]) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts + 1'; - } - - $this->config->increment('num_posts', 1, false); - } - - /** - * Remove post from topic and forum statistics - * - * @param $data array Contains information from the topics table about given topic - * @param &$sql_data array Populated with the SQL changes, may be empty at call time - * @return null - */ - public function remove_post_from_statistic($data, &$sql_data) - { - if ($data['post_visibility'] == ITEM_APPROVED) - { - $sql_data[$this->topics_table] = ((!empty($sql_data[$this->topics_table])) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved - 1'; - $sql_data[$this->forums_table] = ((!empty($sql_data[$this->forums_table])) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved - 1'; - - if ($data['post_postcount']) - { - $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1'; - } - - $this->config->increment('num_posts', -1, false); - } - else if ($data['post_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE) - { - $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_unapproved = forum_posts_unapproved - 1'; - $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_unapproved = topic_posts_unapproved - 1'; - } - else if ($data['post_visibility'] == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_softdeleted = forum_posts_softdeleted - 1'; - $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_softdeleted = topic_posts_softdeleted - 1'; - } - } - - /** - * Remove topic from forum statistics - * - * @param $data array Post and topic data - * @param &$sql_data array Populated with the SQL changes, may be empty at call time - * @return null - */ - public function remove_topic_from_statistic($data, &$sql_data) - { - if ($data['topic_visibility'] == ITEM_APPROVED) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_approved = forum_posts_approved - 1, forum_topics_approved = forum_topics_approved - 1'; - - if ($data['post_postcount']) - { - $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1'; - } - } - else if ($data['topic_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_unapproved = forum_posts_unapproved - 1, forum_topics_unapproved = forum_topics_unapproved - 1'; - } - else if ($data['topic_visibility'] == ITEM_DELETED) - { - $sql_data[FORUMS_TABLE] .= 'forum_posts_softdeleted = forum_posts_softdeleted - 1, forum_topics_softdeleted = forum_topics_softdeleted - 1'; - } - - } -} diff --git a/install/update/old/phpbb/controller/helper.php b/install/update/old/phpbb/controller/helper.php deleted file mode 100644 index 664b4f4..0000000 --- a/install/update/old/phpbb/controller/helper.php +++ /dev/null @@ -1,195 +0,0 @@ - -* @license 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\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; - -/** -* Controller helper class, contains methods that do things for controllers -*/ -class helper -{ - /** - * Template object - * @var \phpbb\template\template - */ - protected $template; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * config object - * @var \phpbb\config\config - */ - protected $config; - - /* @var \phpbb\symfony_request */ - protected $symfony_request; - - /* @var \phpbb\request\request_interface */ - protected $request; - - /** - * @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 - * @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->routing_helper = $routing_helper; - } - - /** - * 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 int $status_code The status code to be sent to the page header - * @param bool $display_online_list Do we display online users list - * @param int $item_id Restrict online users to item id - * @param string $item Restrict online users to a certain session item, e.g. forum for session_forum_id - * @param bool $send_headers Whether headers should be sent by page_header(). Defaults to false for controllers. - * - * @return Response object containing rendered page - */ - public function render($template_file, $page_title = '', $status_code = 200, $display_online_list = false, $item_id = 0, $item = 'forum', $send_headers = false) - { - page_header($page_title, $display_online_list, $item_id, $item, $send_headers); - - $this->template->set_filenames(array( - 'body' => $template_file, - )); - - page_footer(true, false, false); - - $headers = !empty($this->user->data['is_bot']) ? array('X-PHPBB-IS-BOT' => 'yes') : array(); - - return new Response($this->template->assign_display('body'), $status_code, $headers); - } - - /** - * 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 & (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) - { - return $this->routing_helper->route($route, $params, $is_amp, $session_id, $reference_type); - } - - /** - * Output an error, effectively the same thing as trigger_error - * - * @param string $message The error message - * @param int $code The error code (e.g. 404, 500, 503, etc.) - * @return Response A Response instance - * - * @deprecated 3.1.3 (To be removed: 3.3.0) Use exceptions instead. - */ - public function error($message, $code = 500) - { - return $this->message($message, array(), 'INFORMATION', $code); - } - - /** - * Output a message - * - * In case of an error, please throw an exception instead - * - * @param string $message The message to display (must be a language variable) - * @param array $parameters The parameters to use with the language var - * @param string $title Title for the message (must be a language variable) - * @param int $code The HTTP status code (e.g. 404, 500, 503, etc.) - * @return Response A Response instance - */ - public function message($message, array $parameters = array(), $title = 'INFORMATION', $code = 200) - { - array_unshift($parameters, $message); - $message_text = call_user_func_array(array($this->user, 'lang'), $parameters); - $message_title = $this->user->lang($title); - - if ($this->request->is_ajax()) - { - global $refresh_data; - - return new JsonResponse( - array( - 'MESSAGE_TITLE' => $message_title, - 'MESSAGE_TEXT' => $message_text, - 'S_USER_WARNING' => false, - 'S_USER_NOTICE' => false, - 'REFRESH_DATA' => (!empty($refresh_data)) ? $refresh_data : null - ), - $code - ); - } - - $this->template->assign_vars(array( - 'MESSAGE_TEXT' => $message_text, - 'MESSAGE_TITLE' => $message_title, - )); - - return $this->render('message_body.html', $message_title, $code); - } - - /** - * 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' => '', - )); - } - - /** - * Return the current url - * - * @return string - */ - public function get_current_url() - { - return generate_board_url(true) . $this->request->escape($this->symfony_request->getRequestUri(), true); - } -} diff --git a/install/update/old/phpbb/cron/manager.php b/install/update/old/phpbb/cron/manager.php deleted file mode 100644 index 9bd30a0..0000000 --- a/install/update/old/phpbb/cron/manager.php +++ /dev/null @@ -1,147 +0,0 @@ - -* @license 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; - -/** -* Cron manager class. -* -* Finds installed cron tasks, stores task objects, provides task selection. -*/ -class manager -{ - /** - * Set of \phpbb\cron\task\wrapper objects. - * Array holding all tasks that have been found. - * - * @var array - */ - protected $tasks = array(); - - protected $phpbb_root_path; - protected $php_ext; - - /** - * Constructor. Loads all available tasks. - * - * @param array|\Traversable $tasks Provides an iterable set of task names - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $php_ext PHP file extension - */ - public function __construct($tasks, $phpbb_root_path, $php_ext) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->load_tasks($tasks); - } - - /** - * Loads tasks given by name, wraps them - * and puts them into $this->tasks. - * - * @param array|\Traversable $tasks Array of instances of \phpbb\cron\task\task - * - * @return null - */ - public function load_tasks($tasks) - { - foreach ($tasks as $task) - { - $this->tasks[] = $this->wrap_task($task); - } - } - - /** - * Finds a task that is ready to run. - * - * If several tasks are ready, any one of them could be returned. - * - * If no tasks are ready, null is returned. - * - * @return \phpbb\cron\task\wrapper|null - */ - public function find_one_ready_task() - { - shuffle($this->tasks); - foreach ($this->tasks as $task) - { - if ($task->is_ready()) - { - return $task; - } - } - return null; - } - - /** - * Finds all tasks that are ready to run. - * - * @return array List of tasks which are ready to run (wrapped in \phpbb\cron\task\wrapper). - */ - public function find_all_ready_tasks() - { - $tasks = array(); - foreach ($this->tasks as $task) - { - if ($task->is_ready()) - { - $tasks[] = $task; - } - } - return $tasks; - } - - /** - * Finds a task by name. - * - * If there is no task with the specified name, null is returned. - * - * Web runner uses this method to resolve names to tasks. - * - * @param string $name Name of the task to look up. - * @return \phpbb\cron\task\wrapper A wrapped task corresponding to the given name, or null. - */ - public function find_task($name) - { - foreach ($this->tasks as $task) - { - if ($task->get_name() == $name) - { - return $task; - } - } - return null; - } - - /** - * Find all tasks and return them. - * - * @return array List of all tasks. - */ - public function get_tasks() - { - return $this->tasks; - } - - /** - * Wraps a task inside an instance of \phpbb\cron\task\wrapper. - * - * @param \phpbb\cron\task\task $task The task. - * @return \phpbb\cron\task\wrapper The wrapped task. - */ - public function wrap_task(\phpbb\cron\task\task $task) - { - return new \phpbb\cron\task\wrapper($task, $this->phpbb_root_path, $this->php_ext); - } -} diff --git a/install/update/old/phpbb/cron/task/core/update_hashes.php b/install/update/old/phpbb/cron/task/core/update_hashes.php deleted file mode 100644 index ba095ab..0000000 --- a/install/update/old/phpbb/cron/task/core/update_hashes.php +++ /dev/null @@ -1,130 +0,0 @@ - - * @license 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\core; - -/** - * Update old hashes to the current default hashing algorithm - * - * It is intended to gradually update all "old" style hashes to the - * current default hashing algorithm. - */ -class update_hashes extends \phpbb\cron\task\base -{ - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\lock\db */ - protected $update_lock; - - /** @var \phpbb\passwords\manager */ - protected $passwords_manager; - - /** @var string Default hashing type */ - protected $default_type; - - /** - * Constructor. - * - * @param \phpbb\config\config $config - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\lock\db $update_lock - * @param \phpbb\passwords\manager $passwords_manager - * @param array $hashing_algorithms Hashing driver - * service collection - * @param array $defaults Default password types - */ - public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\lock\db $update_lock, \phpbb\passwords\manager $passwords_manager, $hashing_algorithms, $defaults) - { - $this->config = $config; - $this->db = $db; - $this->passwords_manager = $passwords_manager; - $this->update_lock = $update_lock; - - foreach ($defaults as $type) - { - if ($hashing_algorithms[$type]->is_supported()) - { - $this->default_type = $type; - break; - } - } - } - - /** - * {@inheritdoc} - */ - public function is_runnable() - { - return !$this->config['use_system_cron']; - } - - /** - * {@inheritdoc} - */ - public function should_run() - { - if (!empty($this->config['update_hashes_lock'])) - { - $last_run = explode(' ', $this->config['update_hashes_lock']); - if ($last_run[0] + 60 >= time()) - { - return false; - } - } - - return $this->config['enable_update_hashes'] && $this->config['update_hashes_last_cron'] < (time() - 60); - } - - /** - * {@inheritdoc} - */ - public function run() - { - if ($this->update_lock->acquire()) - { - $sql = 'SELECT user_id, user_password - FROM ' . USERS_TABLE . ' - WHERE user_password ' . $this->db->sql_like_expression('$H$' . $this->db->get_any_char()) . ' - OR user_password ' . $this->db->sql_like_expression('$CP$' . $this->db->get_any_char()); - $result = $this->db->sql_query_limit($sql, 20); - - $affected_rows = 0; - - while ($row = $this->db->sql_fetchrow($result)) - { - $new_hash = $this->passwords_manager->hash($row['user_password'], array($this->default_type)); - - // 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']; - $this->db->sql_query($sql); - } - - $this->config->set('update_hashes_last_cron', time()); - $this->update_lock->release(); - - // Stop cron for good once all hashes are converted - if ($affected_rows === 0) - { - $this->config->set('enable_update_hashes', '0'); - } - } - } -} diff --git a/install/update/old/phpbb/cron/task/wrapper.php b/install/update/old/phpbb/cron/task/wrapper.php deleted file mode 100644 index 8a4a8b1..0000000 --- a/install/update/old/phpbb/cron/task/wrapper.php +++ /dev/null @@ -1,106 +0,0 @@ - -* @license 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; - -/** -* Cron task wrapper class. -* Enhances cron tasks with convenience methods that work identically for all tasks. -*/ -class wrapper -{ - protected $task; - protected $phpbb_root_path; - protected $php_ext; - - /** - * Constructor. - * - * Wraps a task $task, which must implement cron_task interface. - * - * @param \phpbb\cron\task\task $task The cron task to wrap. - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $php_ext PHP file extension - */ - public function __construct(\phpbb\cron\task\task $task, $phpbb_root_path, $php_ext) - { - $this->task = $task; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - } - - /** - * Returns whether the wrapped task is parametrised. - * - * Parametrized tasks accept parameters during initialization and must - * normally be scheduled with parameters. - * - * @return bool Whether or not this task is parametrized. - */ - public function is_parametrized() - { - return $this->task instanceof \phpbb\cron\task\parametrized; - } - - /** - * Returns whether the wrapped task is ready to run. - * - * A task is ready to run when it is runnable according to current configuration - * and enough time has passed since it was last run. - * - * @return bool Whether the wrapped task is ready to run. - */ - public function is_ready() - { - return $this->task->is_runnable() && $this->task->should_run(); - } - - /** - * Returns a url through which this task may be invoked via web. - * - * When system cron is not in use, running a cron task is accomplished - * by outputting an image with the url returned by this function as - * source. - * - * @return string URL through which this task may be invoked. - */ - public function get_url() - { - $name = $this->get_name(); - if ($this->is_parametrized()) - { - $params = $this->task->get_parameters(); - $extra = ''; - foreach ($params as $key => $value) - { - $extra .= '&' . $key . '=' . urlencode($value); - } - } - else - { - $extra = ''; - } - $url = append_sid($this->phpbb_root_path . 'cron.' . $this->php_ext, 'cron_type=' . $name . $extra); - return $url; - } - - /** - * Forwards all other method calls to the wrapped task implementation. - * - * @return mixed - */ - public function __call($name, $args) - { - return call_user_func_array(array($this->task, $name), $args); - } -} diff --git a/install/update/old/phpbb/db/driver/driver.php b/install/update/old/phpbb/db/driver/driver.php deleted file mode 100644 index a36ce8c..0000000 --- a/install/update/old/phpbb/db/driver/driver.php +++ /dev/null @@ -1,1220 +0,0 @@ - -* @license 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; - -/** -* Database Abstraction Layer -*/ -abstract class driver implements driver_interface -{ - var $db_connect_id; - var $query_result; - var $return_on_error = false; - var $transaction = false; - var $sql_time = 0; - var $num_queries = array(); - var $open_queries = array(); - - var $curtime = 0; - var $query_hold = ''; - var $html_hold = ''; - var $sql_report = ''; - - var $persistency = false; - var $user = ''; - var $server = ''; - var $dbname = ''; - - // Set to true if error triggered - var $sql_error_triggered = false; - - // Holding the last sql query on sql error - var $sql_error_sql = ''; - // Holding the error information - only populated if sql_error_triggered is set - var $sql_error_returned = array(); - - // Holding transaction count - var $transactions = 0; - - // Supports multi inserts? - var $multi_insert = false; - - /** - * Current sql layer - */ - var $sql_layer = ''; - - /** - * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions - */ - var $any_char; - var $one_char; - - /** - * Exact version of the DBAL, directly queried - */ - var $sql_server_version = false; - - 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 - */ - function __construct() - { - $this->num_queries = array( - 'cached' => 0, - 'normal' => 0, - 'total' => 0, - ); - - // Fill default sql layer based on the class being called. - // This can be changed by the specified layer itself later if needed. - $this->sql_layer = substr(get_class($this), strlen('phpbb\db\driver\\')); - - // Do not change this please! This variable is used to easy the use of it - and is hardcoded. - $this->any_char = chr(0) . '%'; - $this->one_char = chr(0) . '_'; - } - - /** - * {@inheritdoc} - */ - public function get_sql_layer() - { - return $this->sql_layer; - } - - /** - * {@inheritdoc} - */ - public function get_db_name() - { - return $this->dbname; - } - - /** - * {@inheritdoc} - */ - public function get_any_char() - { - return $this->any_char; - } - - /** - * {@inheritdoc} - */ - public function get_one_char() - { - return $this->one_char; - } - - /** - * {@inheritdoc} - */ - public function get_db_connect_id() - { - return $this->db_connect_id; - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_triggered() - { - return $this->sql_error_triggered; - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_sql() - { - return $this->sql_error_sql; - } - - /** - * {@inheritdoc} - */ - public function get_transaction() - { - return $this->transaction; - } - - /** - * {@inheritdoc} - */ - public function get_sql_time() - { - return $this->sql_time; - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_returned() - { - return $this->sql_error_returned; - } - - /** - * {@inheritdoc} - */ - public function get_multi_insert() - { - return $this->multi_insert; - } - - /** - * {@inheritdoc} - */ - public function set_multi_insert($multi_insert) - { - $this->multi_insert = $multi_insert; - } - - /** - * {@inheritDoc} - */ - function sql_return_on_error($fail = false) - { - $this->sql_error_triggered = false; - $this->sql_error_sql = ''; - - $this->return_on_error = $fail; - } - - /** - * {@inheritDoc} - */ - function sql_num_queries($cached = false) - { - return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; - } - - /** - * {@inheritDoc} - */ - function sql_add_num_queries($cached = false) - { - $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; - $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; - $this->num_queries['total'] += 1; - } - - /** - * {@inheritDoc} - */ - function sql_close() - { - if (!$this->db_connect_id) - { - return false; - } - - if ($this->transaction) - { - do - { - $this->sql_transaction('commit'); - } - while ($this->transaction); - } - - foreach ($this->open_queries as $query_id) - { - $this->sql_freeresult($query_id); - } - - // Connection closed correctly. Set db_connect_id to false to prevent errors - if ($result = $this->_sql_close()) - { - $this->db_connect_id = false; - } - - return $result; - } - - /** - * {@inheritDoc} - */ - function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - if (empty($query)) - { - return false; - } - - // Never use a negative total or offset - $total = ($total < 0) ? 0 : $total; - $offset = ($offset < 0) ? 0 : $offset; - - return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); - } - - /** - * {@inheritDoc} - */ - function sql_fetchrowset($query_id = false) - { - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - $result = array(); - while ($row = $this->sql_fetchrow($query_id)) - { - $result[] = $row; - } - - return $result; - } - - return 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); - } - - if (!$query_id) - { - return false; - } - - $this->sql_freeresult($query_id); - $query_id = $this->sql_query($this->last_query_text); - - if (!$query_id) - { - return false; - } - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * {@inheritDoc} - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return (isset($row[$field])) ? $row[$field] : false; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_like_expression($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) . '\''); - } - - /** - * {@inheritDoc} - */ - function sql_not_like_expression($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) . '\''); - } - - /** - * {@inheritDoc} - */ - public function sql_case($condition, $action_true, $action_false = false) - { - $sql_case = 'CASE WHEN ' . $condition; - $sql_case .= ' THEN ' . $action_true; - $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; - $sql_case .= ' END'; - return $sql_case; - } - - /** - * {@inheritDoc} - */ - public function sql_concatenate($expr1, $expr2) - { - return $expr1 . ' || ' . $expr2; - } - - /** - * {@inheritDoc} - */ - function sql_buffer_nested_transactions() - { - return false; - } - - /** - * {@inheritDoc} - */ - function sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - // If we are within a transaction we will not open another one, but enclose the current one to not loose data (preventing auto commit) - if ($this->transaction) - { - $this->transactions++; - return true; - } - - $result = $this->_sql_transaction('begin'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = true; - break; - - case 'commit': - // If there was a previously opened transaction we do not commit yet... - // but count back the number of inner transactions - if ($this->transaction && $this->transactions) - { - $this->transactions--; - return true; - } - - // Check if there is a transaction (no transaction can happen if - // there was an error, with a combined rollback and error returning enabled) - // This implies we have transaction always set for autocommit db's - if (!$this->transaction) - { - return false; - } - - $result = $this->_sql_transaction('commit'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = false; - $this->transactions = 0; - break; - - case 'rollback': - $result = $this->_sql_transaction('rollback'); - $this->transaction = false; - $this->transactions = 0; - break; - - default: - $result = $this->_sql_transaction($status); - break; - } - - return $result; - } - - /** - * {@inheritDoc} - */ - function sql_build_array($query, $assoc_ary = false) - { - if (!is_array($assoc_ary)) - { - return false; - } - - $fields = $values = array(); - - if ($query == 'INSERT' || $query == 'INSERT_SELECT') - { - foreach ($assoc_ary as $key => $var) - { - $fields[] = $key; - - if (is_array($var) && is_string($var[0])) - { - // This is used for INSERT_SELECT(s) - $values[] = $var[0]; - } - else - { - $values[] = $this->_sql_validate_value($var); - } - } - - $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; - } - else if ($query == 'MULTI_INSERT') - { - trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); - } - else if ($query == 'UPDATE' || $query == 'SELECT' || $query == 'DELETE') - { - $values = array(); - foreach ($assoc_ary as $key => $var) - { - $values[] = "$key = " . $this->_sql_validate_value($var); - } - $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); - } - - return $query; - } - - /** - * {@inheritDoc} - */ - function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) - { - $array = (array) $array; - - if (!count($array)) - { - if (!$allow_empty_set) - { - // Print the backtrace to help identifying the location of the problematic code - $this->sql_error('No values specified for SQL IN comparison'); - } - else - { - // NOT IN () actually means everything so use a tautology - if ($negate) - { - return '1=1'; - } - // IN () actually means nothing so use a contradiction - else - { - return '1=0'; - } - } - } - - if (count($array) == 1) - { - @reset($array); - $var = current($array); - - return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); - } - else - { - return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; - } - } - - /** - * {@inheritDoc} - */ - function sql_bit_and($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_and')) - { - return $this->_sql_bit_and($column_name, $bit, $compare); - } - - return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * {@inheritDoc} - */ - function sql_bit_or($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_or')) - { - return $this->_sql_bit_or($column_name, $bit, $compare); - } - - return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * {@inheritDoc} - */ - function cast_expr_to_bigint($expression) - { - return $expression; - } - - /** - * {@inheritDoc} - */ - function cast_expr_to_string($expression) - { - return $expression; - } - - /** - * {@inheritDoc} - */ - function sql_lower_text($column_name) - { - return "LOWER($column_name)"; - } - - /** - * {@inheritDoc} - */ - function sql_multi_insert($table, $sql_ary) - { - if (!count($sql_ary)) - { - return false; - } - - if ($this->multi_insert) - { - $ary = array(); - foreach ($sql_ary as $id => $_sql_ary) - { - // If by accident the sql array is only one-dimensional we build a normal insert statement - if (!is_array($_sql_ary)) - { - return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); - } - - $values = array(); - foreach ($_sql_ary as $key => $var) - { - $values[] = $this->_sql_validate_value($var); - } - $ary[] = '(' . implode(', ', $values) . ')'; - } - - return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); - } - else - { - foreach ($sql_ary as $ary) - { - if (!is_array($ary)) - { - return false; - } - - $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); - - if (!$result) - { - return false; - } - } - } - - return true; - } - - /** - * Function for validating values - * @access private - */ - function _sql_validate_value($var) - { - if (is_null($var)) - { - return 'NULL'; - } - else if (is_string($var)) - { - return "'" . $this->sql_escape($var) . "'"; - } - else - { - return (is_bool($var)) ? intval($var) : $var; - } - } - - /** - * {@inheritDoc} - */ - function sql_build_query($query, $array) - { - $sql = ''; - switch ($query) - { - case 'SELECT': - case 'SELECT_DISTINCT'; - - $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; - - // Build table array. We also build an alias array for later checks. - $table_array = $aliases = array(); - $used_multi_alias = false; - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - $used_multi_alias = true; - - foreach ($alias as $multi_alias) - { - $table_array[] = $table_name . ' ' . $multi_alias; - $aliases[] = $multi_alias; - } - } - else - { - $table_array[] = $table_name . ' ' . $alias; - $aliases[] = $alias; - } - } - - // We run the following code to determine if we need to re-order the table array. ;) - // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. - // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. - if (!empty($array['LEFT_JOIN']) && count($array['FROM']) > 1 && $used_multi_alias !== false) - { - // Take first LEFT JOIN - $join = current($array['LEFT_JOIN']); - - // Determine the table used there (even if there are more than one used, we only want to have one - preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); - - // If there is a first join match, we need to make sure the table order is correct - if (!empty($matches[1])) - { - $first_join_match = trim($matches[1]); - $table_array = $last = array(); - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - foreach ($alias as $multi_alias) - { - ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; - } - } - else - { - ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; - } - } - - $table_array = array_merge($table_array, $last); - } - } - - $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); - - if (!empty($array['LEFT_JOIN'])) - { - foreach ($array['LEFT_JOIN'] as $join) - { - $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; - } - } - - if (!empty($array['WHERE'])) - { - $sql .= ' WHERE '; - - 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'])) - { - $sql .= ' GROUP BY ' . $array['GROUP_BY']; - } - - if (!empty($array['ORDER_BY'])) - { - $sql .= ' ORDER BY ' . $array['ORDER_BY']; - } - - break; - } - - 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} - */ - function sql_error($sql = '') - { - global $auth, $user, $config; - - // Set var to retrieve errored status - $this->sql_error_triggered = true; - $this->sql_error_sql = $sql; - - $this->sql_error_returned = $this->_sql_error(); - - if (!$this->return_on_error) - { - $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]

' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; - - // Show complete SQL error and path to administrators only - // Additionally show complete error on installation or if extended debug mode is enabled - // The DEBUG constant is for development only! - if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG')) - { - $message .= ($sql) ? '

SQL

' . htmlspecialchars($sql) : ''; - } - else - { - // If error occurs in initiating the session we need to use a pre-defined language string - // This could happen if the connection could not be established for example (then we are not able to grab the default language) - if (!isset($user->lang['SQL_ERROR_OCCURRED'])) - { - $message .= '

An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; - } - else - { - if (!empty($config['board_contact'])) - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - else - { - $message .= '

' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - } - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - if (strlen($message) > 1024) - { - // We need to define $msg_long_text here to circumvent text stripping. - global $msg_long_text; - $msg_long_text = $message; - - trigger_error(false, E_USER_ERROR); - } - - trigger_error($message, E_USER_ERROR); - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - return $this->sql_error_returned; - } - - /** - * {@inheritDoc} - */ - function sql_report($mode, $query = '') - { - global $cache, $starttime, $phpbb_root_path, $phpbb_path_helper; - global $request; - - if (is_object($request) && !$request->variable('explain', false)) - { - return false; - } - - if (!$query && $this->query_hold != '') - { - $query = $this->query_hold; - } - - switch ($mode) - { - case 'display': - if (!empty($cache)) - { - $cache->unload(); - } - $this->sql_close(); - - $mtime = explode(' ', microtime()); - $totaltime = $mtime[0] + $mtime[1] - $starttime; - - echo ' - - - - - SQL Report - - - -
- -
-
-
- -
-

SQL Report

-
-

Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '

- -

Time spent on ' . $this->sql_layer . ' queries: ' . round($this->sql_time, 5) . 's | Time spent on PHP: ' . round($totaltime - $this->sql_time, 5) . 's

- -

- ' . $this->sql_report . ' -
- -
-
-
- -
- - '; - - exit_handler(); - - break; - - case 'stop': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $this->sql_report .= ' - - - - - - - - - - - - -
Query #' . $this->num_queries['total'] . '
- - ' . $this->html_hold . ' - -

- '; - - if ($this->query_result) - { - if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) - { - $this->sql_report .= 'Affected rows: ' . $this->sql_affectedrows() . ' | '; - } - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: ' . sprintf('%.5f', $endtime - $this->curtime) . 's'; - } - else - { - $error = $this->sql_error(); - $this->sql_report .= 'FAILED - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); - } - - $this->sql_report .= '



'; - - $this->sql_time += $endtime - $this->curtime; - break; - - case 'start': - $this->query_hold = $query; - $this->html_hold = ''; - - $this->_sql_report($mode, $query); - - $this->curtime = explode(' ', microtime()); - $this->curtime = $this->curtime[0] + $this->curtime[1]; - - break; - - case 'add_select_row': - - $html_table = func_get_arg(2); - $row = func_get_arg(3); - - if (!$html_table && count($row)) - { - $html_table = true; - $this->html_hold .= ''; - - foreach (array_keys($row) as $val) - { - $this->html_hold .= ''; - } - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - $class = 'row1'; - foreach (array_values($row) as $val) - { - $class = ($class == 'row1') ? 'row2' : 'row1'; - $this->html_hold .= ''; - } - $this->html_hold .= ''; - - return $html_table; - - break; - - case 'fromcache': - - $this->_sql_report($mode, $query); - - break; - - case 'record_fromcache': - - $endtime = func_get_arg(2); - $splittime = func_get_arg(3); - - $time_cache = $endtime - $this->curtime; - $time_db = $splittime - $endtime; - $color = ($time_db > $time_cache) ? 'green' : 'red'; - - $this->sql_report .= '
' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '
' . (($val) ? $val : ' ') . '
'; - $this->sql_report .= '
Query results obtained from the cache
'; - $this->sql_report .= '

'; - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: ' . sprintf('%.5f', ($time_cache)) . 's | Elapsed [db]: ' . sprintf('%.5f', $time_db) . 's



'; - - // Pad the start time to not interfere with page timing - $starttime += $time_db; - - break; - - default: - - $this->_sql_report($mode, $query); - - break; - } - - return true; - } - - /** - * {@inheritDoc} - */ - function get_estimated_row_count($table_name) - { - return $this->get_row_count($table_name); - } - - /** - * {@inheritDoc} - */ - function get_row_count($table_name) - { - $sql = 'SELECT COUNT(*) AS rows_total - FROM ' . $this->sql_escape($table_name); - $result = $this->sql_query($sql); - $rows_total = $this->sql_fetchfield('rows_total'); - $this->sql_freeresult($result); - - return $rows_total; - } -} diff --git a/install/update/old/phpbb/db/driver/driver_interface.php b/install/update/old/phpbb/db/driver/driver_interface.php deleted file mode 100644 index 8b487c5..0000000 --- a/install/update/old/phpbb/db/driver/driver_interface.php +++ /dev/null @@ -1,453 +0,0 @@ - -* @license 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; - -interface driver_interface -{ - /** - * Gets the name of the sql layer. - * - * @return string - */ - public function get_sql_layer(); - - /** - * Gets the name of the database. - * - * @return string - */ - public function get_db_name(); - - /** - * Wildcards for matching any (%) character within LIKE expressions - * - * @return string - */ - public function get_any_char(); - - /** - * Wildcards for matching exactly one (_) character within LIKE expressions - * - * @return string - */ - public function get_one_char(); - - /** - * Gets the time spent into the queries - * - * @return int - */ - public function get_sql_time(); - - /** - * Gets the connect ID. - * - * @return mixed - */ - public function get_db_connect_id(); - - /** - * Indicates if an error was triggered. - * - * @return bool - */ - public function get_sql_error_triggered(); - - /** - * Gets the last faulty query - * - * @return string - */ - public function get_sql_error_sql(); - - /** - * Indicates if we are in a transaction. - * - * @return bool - */ - public function get_transaction(); - - /** - * Gets the returned error. - * - * @return array - */ - public function get_sql_error_returned(); - - /** - * Indicates if multiple insertion can be used - * - * @return bool - */ - public function get_multi_insert(); - - /** - * Set if multiple insertion can be used - * - * @param bool $multi_insert - */ - public function set_multi_insert($multi_insert); - - /** - * Gets the exact number of rows in a specified table. - * - * @param string $table_name Table name - * @return string Exact number of rows in $table_name. - */ - public function get_row_count($table_name); - - /** - * Gets the estimated number of rows in a specified table. - * - * @param string $table_name Table name - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). - */ - public function get_estimated_row_count($table_name); - - /** - * Run LOWER() on DB column of type text (i.e. neither varchar nor char). - * - * @param string $column_name The column name to use - * @return string A SQL statement like "LOWER($column_name)" - */ - public function sql_lower_text($column_name); - - /** - * Display sql error page - * - * @param string $sql The SQL query causing the error - * @return mixed Returns the full error message, if $this->return_on_error - * is set, null otherwise - */ - public function sql_error($sql = ''); - - /** - * Returns whether results of a query need to be buffered to run a - * transaction while iterating over them. - * - * @return bool Whether buffering is required. - */ - public function sql_buffer_nested_transactions(); - - /** - * Run binary OR operator on DB column. - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the OR operator, - * will be converted to (1 << $bit). Is used by options, - * using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (e.g. "= 0") - * @return string A SQL statement like "$column | (1 << $bit) {$compare}" - */ - public function sql_bit_or($column_name, $bit, $compare = ''); - - /** - * Version information about used database - * - * @param bool $raw Only return the fetched sql_server_version - * @param bool $use_cache Is it safe to retrieve the value from the cache - * @return string sql server version - */ - public function sql_server_info($raw = false, $use_cache = true); - - /** - * Return on error or display error message - * - * @param bool $fail Should we return on errors, or stop - * @return null - */ - public function sql_return_on_error($fail = false); - - /** - * Build sql statement from an array - * - * @param string $query Should be on of the following strings: - * INSERT, INSERT_SELECT, UPDATE, SELECT, DELETE - * @param array $assoc_ary Array with "column => value" pairs - * @return string A SQL statement like "c1 = 'a' AND c2 = 'b'" - */ - public function sql_build_array($query, $assoc_ary = array()); - - /** - * Fetch all rows - * - * @param mixed $query_id Already executed query to get the rows from, - * if false, the last query will be used. - * @return mixed Nested array if the query had rows, false otherwise - */ - public function sql_fetchrowset($query_id = false); - - /** - * SQL Transaction - * - * @param string $status Should be one of the following strings: - * begin, commit, rollback - * @return mixed Buffered, seekable result handle, false on error - */ - public function sql_transaction($status = 'begin'); - - /** - * Build a concatenated expression - * - * @param string $expr1 Base SQL expression where we append the second one - * @param string $expr2 SQL expression that is appended to the first expression - * @return string Concatenated string - */ - public function sql_concatenate($expr1, $expr2); - - /** - * Build a case expression - * - * Note: The two statements action_true and action_false must have the same - * data type (int, vchar, ...) in the database! - * - * @param string $condition The condition which must be true, - * to use action_true rather then action_else - * @param string $action_true SQL expression that is used, if the condition is true - * @param mixed $action_false SQL expression that is used, if the condition is false - * @return string CASE expression including the condition and statements - */ - public function sql_case($condition, $action_true, $action_false = false); - - /** - * Build sql statement from array for select and select distinct statements - * - * Possible query values: SELECT, SELECT_DISTINCT - * - * @param string $query Should be one of: SELECT, SELECT_DISTINCT - * @param array $array Array with the query data: - * SELECT A comma imploded list of columns to select - * FROM Array with "table => alias" pairs, - * (alias can also be an array) - * Optional: LEFT_JOIN Array of join entries: - * FROM Table that should be joined - * ON Condition for the join - * Optional: WHERE Where SQL statement - * Optional: GROUP_BY Group by SQL statement - * Optional: ORDER_BY Order by SQL statement - * @return string A SQL statement ready for execution - */ - public function sql_build_query($query, $array); - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - * - * @param string $field Name of the column - * @param mixed $rownum Row number, if false the current row will be used - * and the row curser will point to the next row - * Note: $rownum is 0 based - * @param mixed $query_id Already executed query to get the rows from, - * if false, the last query will be used. - * @return mixed String value of the field in the selected row, - * false, if the row does not exist - */ - public function sql_fetchfield($field, $rownum = false, $query_id = false); - - /** - * Fetch current row - * - * @param mixed $query_id Already executed query to get the rows from, - * if false, the last query will be used. - * @return mixed Array with the current row, - * false, if the row does not exist - */ - public function sql_fetchrow($query_id = false); - - /** - * Returns SQL string to cast a string expression to an int. - * - * @param string $expression An expression evaluating to string - * @return string Expression returning an int - */ - public function cast_expr_to_bigint($expression); - - /** - * Get last inserted id after insert statement - * - * @return string Autoincrement value of the last inserted row - */ - public function sql_nextid(); - - /** - * Add to query count - * - * @param bool $cached Is this query cached? - * @return null - */ - public function sql_add_num_queries($cached = false); - - /** - * Build LIMIT query - * - * @param string $query The SQL query to execute - * @param int $total The number of rows to select - * @param int $offset - * @param int $cache_ttl Either 0 to avoid caching or - * the time in seconds which the result shall be kept in cache - * @return mixed Buffered, seekable result handle, false on error - */ - public function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0); - - /** - * Base query method - * - * @param string $query The SQL query to execute - * @param int $cache_ttl Either 0 to avoid caching or - * the time in seconds which the result shall be kept in cache - * @return mixed Buffered, seekable result handle, false on error - */ - public function sql_query($query = '', $cache_ttl = 0); - - /** - * Returns SQL string to cast an integer expression to a string. - * - * @param string $expression An expression evaluating to int - * @return string Expression returning a string - */ - public function cast_expr_to_string($expression); - - /** - * Connect to server - * - * @param string $sqlserver Address of the database server - * @param string $sqluser User name of the SQL user - * @param string $sqlpassword Password of the SQL user - * @param string $database Name of the database - * @param mixed $port Port of the database server - * @param bool $persistency - * @param bool $new_link Should a new connection be established - * @return mixed Connection ID on success, string error message otherwise - */ - public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false); - - /** - * Run binary AND operator on DB column. - * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the AND operator, - * will be converted to (1 << $bit). Is used by - * options, using the number schema: 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - * @return string A SQL statement like: "{$column} & (1 << {$bit}) {$compare}" - */ - public function sql_bit_and($column_name, $bit, $compare = ''); - - /** - * Free sql result - * - * @param mixed $query_id Already executed query result, - * if false, the last query will be used. - * @return null - */ - public function sql_freeresult($query_id = false); - - /** - * Return number of sql queries and cached sql queries used - * - * @param bool $cached Should we return the number of cached or normal queries? - * @return int Number of queries that have been executed - */ - public function sql_num_queries($cached = false); - - /** - * Run more than one insert statement. - * - * @param string $table Table name to run the statements on - * @param array $sql_ary Multi-dimensional array holding the statement data - * @return bool false if no statements were executed. - */ - public function sql_multi_insert($table, $sql_ary); - - /** - * Return number of affected rows - * - * @return mixed Number of the affected rows by the last query - * false if no query has been run before - */ - public function sql_affectedrows(); - - /** - * DBAL garbage collection, close SQL connection - * - * @return mixed False if no connection was opened before, - * Server response otherwise - */ - public function sql_close(); - - /** - * Seek to given row number - * - * @param mixed $rownum Row number the curser should point to - * Note: $rownum is 0 based - * @param mixed $query_id ID of the query to set the row cursor on - * if false, the last query will be used. - * $query_id will then be set correctly - * @return bool False if something went wrong - */ - public function sql_rowseek($rownum, &$query_id); - - /** - * Escape string used in sql query - * - * @param string $msg String to be escaped - * @return string Escaped version of $msg - */ - public function sql_escape($msg); - - /** - * Correctly adjust LIKE expression for special characters - * Some DBMS are handling them in a different way - * - * @param string $expression The expression to use. Every wildcard is - * escaped, except $this->any_char and $this->one_char - * @return string A SQL statement like: "LIKE 'bertie_%'" - */ - public function sql_like_expression($expression); - - /** - * Correctly adjust NOT LIKE expression for special characters - * Some DBMS are handling them in a different way - * - * @param string $expression The expression to use. Every wildcard is - * escaped, except $this->any_char and $this->one_char - * @return string A SQL statement like: "NOT LIKE 'bertie_%'" - */ - public function sql_not_like_expression($expression); - - /** - * Explain queries - * - * @param string $mode Available modes: display, start, stop, - * add_select_row, fromcache, record_fromcache - * @param string $query The Query that should be explained - * @return mixed Either a full HTML page, boolean or null - */ - public function sql_report($mode, $query = ''); - - /** - * Build IN or NOT IN sql comparison string, uses <> or = on single element - * arrays to improve comparison speed - * - * @param string $field Name of the sql column that shall be compared - * @param array $array Array of values that are (not) allowed - * @param bool $negate true for NOT IN (), false for IN () - * @param bool $allow_empty_set If true, allow $array to be empty, - * this function will return 1=1 or 1=0 then. - * @return string A SQL statement like: "IN (1, 2, 3, 4)" or "= 1" - */ - public function sql_in_set($field, $array, $negate = false, $allow_empty_set = false); -} diff --git a/install/update/old/phpbb/db/driver/factory.php b/install/update/old/phpbb/db/driver/factory.php deleted file mode 100644 index fb3a826..0000000 --- a/install/update/old/phpbb/db/driver/factory.php +++ /dev/null @@ -1,443 +0,0 @@ - -* @license 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; - -use \Symfony\Component\DependencyInjection\ContainerInterface; - -/** -* Database Abstraction Layer -*/ -class factory implements driver_interface -{ - /** - * @var driver_interface - */ - protected $driver = null; - - /** - * @var ContainerInterface - */ - protected $container; - - /** - * Constructor. - * - * @param ContainerInterface $container A ContainerInterface instance - */ - public function __construct(ContainerInterface $container) - { - $this->container = $container; - } - - /** - * Return the current driver (and retrieved it from the container if necessary) - * - * @return driver_interface - */ - protected function get_driver() - { - if ($this->driver === null) - { - $this->driver = $this->container->get('dbal.conn.driver'); - } - - return $this->driver; - } - - /** - * Set the current driver - * - * @param driver_interface $driver - */ - public function set_driver(driver_interface $driver) - { - $this->driver = $driver; - } - - /** - * {@inheritdoc} - */ - public function get_sql_layer() - { - return $this->get_driver()->get_sql_layer(); - } - - /** - * {@inheritdoc} - */ - public function get_db_name() - { - return $this->get_driver()->get_db_name(); - } - - /** - * {@inheritdoc} - */ - public function get_any_char() - { - return $this->get_driver()->get_any_char(); - } - - /** - * {@inheritdoc} - */ - public function get_one_char() - { - return $this->get_driver()->get_one_char(); - } - - /** - * {@inheritdoc} - */ - public function get_db_connect_id() - { - return $this->get_driver()->get_db_connect_id(); - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_triggered() - { - return $this->get_driver()->get_sql_error_triggered(); - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_sql() - { - return $this->get_driver()->get_sql_error_sql(); - } - - /** - * {@inheritdoc} - */ - public function get_transaction() - { - return $this->get_driver()->get_transaction(); - } - - /** - * {@inheritdoc} - */ - public function get_sql_time() - { - return $this->get_driver()->get_sql_time(); - } - - /** - * {@inheritdoc} - */ - public function get_sql_error_returned() - { - return $this->get_driver()->get_sql_error_returned(); - } - - /** - * {@inheritdoc} - */ - public function get_multi_insert() - { - return $this->get_driver()->get_multi_insert(); - } - - /** - * {@inheritdoc} - */ - public function set_multi_insert($multi_insert) - { - $this->get_driver()->set_multi_insert($multi_insert); - } - - /** - * {@inheritdoc} - */ - public function get_row_count($table_name) - { - return $this->get_driver()->get_row_count($table_name); - } - - /** - * {@inheritdoc} - */ - public function get_estimated_row_count($table_name) - { - return $this->get_driver()->get_estimated_row_count($table_name); - } - - /** - * {@inheritdoc} - */ - public function sql_lower_text($column_name) - { - return $this->get_driver()->sql_lower_text($column_name); - } - - /** - * {@inheritdoc} - */ - public function sql_error($sql = '') - { - return $this->get_driver()->sql_error($sql); - } - - /** - * {@inheritdoc} - */ - public function sql_buffer_nested_transactions() - { - return $this->get_driver()->sql_buffer_nested_transactions(); - } - - /** - * {@inheritdoc} - */ - public function sql_bit_or($column_name, $bit, $compare = '') - { - return $this->get_driver()->sql_bit_or($column_name, $bit, $compare); - } - - /** - * {@inheritdoc} - */ - public function sql_server_info($raw = false, $use_cache = true) - { - return $this->get_driver()->sql_server_info($raw, $use_cache); - } - - /** - * {@inheritdoc} - */ - public function sql_return_on_error($fail = false) - { - return $this->get_driver()->sql_return_on_error($fail); - } - - /** - * {@inheritdoc} - */ - public function sql_build_array($query, $assoc_ary = array()) - { - return $this->get_driver()->sql_build_array($query, $assoc_ary); - } - - /** - * {@inheritdoc} - */ - public function sql_fetchrowset($query_id = false) - { - return $this->get_driver()->sql_fetchrowset($query_id); - } - - /** - * {@inheritdoc} - */ - public function sql_transaction($status = 'begin') - { - return $this->get_driver()->sql_transaction($status); - } - - /** - * {@inheritdoc} - */ - public function sql_concatenate($expr1, $expr2) - { - return $this->get_driver()->sql_concatenate($expr1, $expr2); - } - - /** - * {@inheritdoc} - */ - public function sql_case($condition, $action_true, $action_false = false) - { - return $this->get_driver()->sql_case($condition, $action_true, $action_false); - } - - /** - * {@inheritdoc} - */ - public function sql_build_query($query, $array) - { - return $this->get_driver()->sql_build_query($query, $array); - } - - /** - * {@inheritdoc} - */ - public function sql_fetchfield($field, $rownum = false, $query_id = false) - { - return $this->get_driver()->sql_fetchfield($field, $rownum, $query_id); - } - - /** - * {@inheritdoc} - */ - public function sql_fetchrow($query_id = false) - { - return $this->get_driver()->sql_fetchrow($query_id); - } - - /** - * {@inheritdoc} - */ - public function cast_expr_to_bigint($expression) - { - return $this->get_driver()->cast_expr_to_bigint($expression); - } - - /** - * {@inheritdoc} - */ - public function sql_nextid() - { - return $this->get_driver()->sql_nextid(); - } - - /** - * {@inheritdoc} - */ - public function sql_add_num_queries($cached = false) - { - return $this->get_driver()->sql_add_num_queries($cached); - } - - /** - * {@inheritdoc} - */ - public function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - return $this->get_driver()->sql_query_limit($query, $total, $offset, $cache_ttl); - } - - /** - * {@inheritdoc} - */ - public function sql_query($query = '', $cache_ttl = 0) - { - return $this->get_driver()->sql_query($query, $cache_ttl); - } - - /** - * {@inheritdoc} - */ - public function cast_expr_to_string($expression) - { - return $this->get_driver()->cast_expr_to_string($expression); - } - - /** - * {@inheritdoc} - */ - public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - throw new \Exception('Disabled method.'); - } - - /** - * {@inheritdoc} - */ - public function sql_bit_and($column_name, $bit, $compare = '') - { - return $this->get_driver()->sql_bit_and($column_name, $bit, $compare); - } - - /** - * {@inheritdoc} - */ - public function sql_freeresult($query_id = false) - { - return $this->get_driver()->sql_freeresult($query_id); - } - - /** - * {@inheritdoc} - */ - public function sql_num_queries($cached = false) - { - return $this->get_driver()->sql_num_queries($cached); - } - - /** - * {@inheritdoc} - */ - public function sql_multi_insert($table, $sql_ary) - { - return $this->get_driver()->sql_multi_insert($table, $sql_ary); - } - - /** - * {@inheritdoc} - */ - public function sql_affectedrows() - { - return $this->get_driver()->sql_affectedrows(); - } - - /** - * {@inheritdoc} - */ - public function sql_close() - { - return $this->get_driver()->sql_close(); - } - - /** - * {@inheritdoc} - */ - public function sql_rowseek($rownum, &$query_id) - { - return $this->get_driver()->sql_rowseek($rownum, $query_id); - } - - /** - * {@inheritdoc} - */ - public function sql_escape($msg) - { - return $this->get_driver()->sql_escape($msg); - } - - /** - * {@inheritdoc} - */ - public function sql_like_expression($expression) - { - return $this->get_driver()->sql_like_expression($expression); - } - - /** - * {@inheritdoc} - */ - public function sql_not_like_expression($expression) - { - return $this->get_driver()->sql_not_like_expression($expression); - } - - /** - * {@inheritdoc} - */ - public function sql_report($mode, $query = '') - { - return $this->get_driver()->sql_report($mode, $query); - } - - /** - * {@inheritdoc} - */ - public function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) - { - return $this->get_driver()->sql_in_set($field, $array, $negate, $allow_empty_set); - } -} diff --git a/install/update/old/phpbb/db/driver/mssql_odbc.php b/install/update/old/phpbb/db/driver/mssql_odbc.php deleted file mode 100644 index 9d9ad60..0000000 --- a/install/update/old/phpbb/db/driver/mssql_odbc.php +++ /dev/null @@ -1,385 +0,0 @@ - -* @license 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; - -/** -* Unified ODBC functions -* Unified ODBC functions support any database having ODBC driver, for example Adabas D, IBM DB2, iODBC, Solid, Sybase SQL Anywhere... -* Here we only support MSSQL Server 2000+ because of the provided schema -* -* @note number of bytes returned for returning data depends on odbc.defaultlrl php.ini setting. -* If it is limited to 4K for example only 4K of data is returned max, resulting in incomplete theme data for example. -* @note odbc.defaultbinmode may affect UTF8 characters -*/ -class mssql_odbc extends \phpbb\db\driver\mssql_base -{ - var $last_query_text = ''; - 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->dbname = $database; - - $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; - $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); - - $max_size = @ini_get('odbc.defaultlrl'); - if (!empty($max_size)) - { - $unit = strtolower(substr($max_size, -1, 1)); - $max_size = (int) $max_size; - - if ($unit == 'k') - { - $max_size = floor($max_size / 1024); - } - else if ($unit == 'g') - { - $max_size *= 1024; - } - else if (is_numeric($unit)) - { - $max_size = floor((int) ($max_size . $unit) / 1048576); - } - $max_size = max(8, $max_size) . 'M'; - - @ini_set('odbc.defaultlrl', $max_size); - } - - if ($this->persistency) - { - if (!function_exists('odbc_pconnect')) - { - $this->connect_error = 'odbc_pconnect function does not exist, is odbc extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @odbc_pconnect($this->server, $this->user, $sqlpassword); - } - else - { - if (!function_exists('odbc_connect')) - { - $this->connect_error = 'odbc_connect function does not exist, is odbc extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @odbc_connect($this->server, $this->user, $sqlpassword); - } - - 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('mssqlodbc_version')) === false) - { - $result_id = @odbc_exec($this->db_connect_id, "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')"); - - $row = false; - if ($result_id) - { - $row = odbc_fetch_array($result_id); - odbc_free_result($result_id); - } - - $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0; - - if (!empty($cache) && $use_cache) - { - $cache->put('mssqlodbc_version', $this->sql_server_version); - } - } - - if ($raw) - { - return $this->sql_server_version; - } - - return ($this->sql_server_version) ? 'MSSQL (ODBC)
' . $this->sql_server_version : 'MSSQL (ODBC)'; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @odbc_exec($this->db_connect_id, 'BEGIN TRANSACTION'); - break; - - case 'commit': - return @odbc_exec($this->db_connect_id, 'COMMIT TRANSACTION'); - break; - - case 'rollback': - return @odbc_exec($this->db_connect_id, 'ROLLBACK TRANSACTION'); - break; - } - - return true; - } - - /** - * {@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->last_query_text = $query; - $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 = @odbc_exec($this->db_connect_id, $query)) === 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 (!$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->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) ? @odbc_num_rows($this->query_result) : 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) ? odbc_fetch_array($query_id) : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - $result_id = @odbc_exec($this->db_connect_id, 'SELECT @@IDENTITY'); - - if ($result_id) - { - if (odbc_fetch_array($result_id)) - { - $id = odbc_result($result_id, 1); - odbc_free_result($result_id); - return $id; - } - odbc_free_result($result_id); - } - - return false; - } - - /** - * {@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 odbc_free_result($query_id); - } - - return false; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('odbc_errormsg')) - { - $error = array( - 'message' => @odbc_errormsg(), - 'code' => @odbc_error(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @odbc_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @odbc_exec($this->db_connect_id, $query); - if ($result) - { - while ($void = odbc_fetch_array($result)) - { - // Take the time spent on parsing rows into account - } - odbc_free_result($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/install/update/old/phpbb/db/driver/mssqlnative.php b/install/update/old/phpbb/db/driver/mssqlnative.php deleted file mode 100644 index a4dcac5..0000000 --- a/install/update/old/phpbb/db/driver/mssqlnative.php +++ /dev/null @@ -1,451 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* This is the MS SQL Server Native database abstraction layer. -* PHP mssql native driver required. -* @author Chris Pucci -* -*/ - -namespace phpbb\db\driver; - -class mssqlnative extends \phpbb\db\driver\mssql_base -{ - var $m_insert_id = null; - var $last_query_text = ''; - var $query_options = array(); - var $connect_error = ''; - - /** - * {@inheritDoc} - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - // Test for driver support, to avoid suppressed fatal error - if (!function_exists('sqlsrv_connect')) - { - $this->connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx'; - return $this->sql_error(''); - } - - //set up connection variables - $this->persistency = $persistency; - $this->user = $sqluser; - $this->dbname = $database; - $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; - $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); - - //connect to database - $this->db_connect_id = sqlsrv_connect($this->server, array( - 'Database' => $this->dbname, - 'UID' => $this->user, - 'PWD' => $sqlpassword, - 'CharacterSet' => 'UTF-8' - )); - - 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) - { - $arr_server_info = sqlsrv_server_info($this->db_connect_id); - $this->sql_server_version = $arr_server_info['SQLServerVersion']; - - if (!empty($cache) && $use_cache) - { - $cache->put('mssql_version', $this->sql_server_version); - } - } - - if ($raw) - { - return $this->sql_server_version; - } - - return ($this->sql_server_version) ? 'MSSQL
' . $this->sql_server_version : 'MSSQL'; - } - - /** - * {@inheritDoc} - */ - function sql_buffer_nested_transactions() - { - return true; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return sqlsrv_begin_transaction($this->db_connect_id); - break; - - case 'commit': - return sqlsrv_commit($this->db_connect_id); - break; - - case 'rollback': - return sqlsrv_rollback($this->db_connect_id); - break; - } - return true; - } - - /** - * {@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->last_query_text = $query; - $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 = @sqlsrv_query($this->db_connect_id, $query, array(), $this->query_options)) === false) - { - $this->sql_error($query); - } - // reset options for next query - $this->query_options = array(); - - if (defined('DEBUG')) - { - $this->sql_report('stop', $query); - } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) - { - $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->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // total == 0 means all results - not zero results - if ($offset == 0 && $total !== 0) - { - if (strpos($query, "SELECT") === false) - { - $query = "TOP {$total} " . $query; - } - else - { - $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query); - } - } - else if ($offset > 0) - { - $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query); - $query = 'SELECT * - FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3 - FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3'; - - if ($total > 0) - { - $query .= ' WHERE line3 BETWEEN ' . ($offset+1) . ' AND ' . ($offset + $total); - } - else - { - $query .= ' WHERE line3 > ' . $offset; - } - } - - $result = $this->sql_query($query, $cache_ttl); - - return $result; - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @sqlsrv_rows_affected($this->query_result) : 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) - { - return false; - } - - $row = sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC); - - if ($row) - { - foreach ($row as $key => $value) - { - $row[$key] = ($value === ' ' || $value === null) ? '' : $value; - } - - // remove helper values from LIMIT queries - if (isset($row['line2'])) - { - unset($row['line2'], $row['line3']); - } - } - return ($row !== null) ? $row : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - $result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY'); - - if ($result_id) - { - $row = sqlsrv_fetch_array($result_id); - $id = $row[0]; - sqlsrv_free_stmt($result_id); - return $id; - } - else - { - 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 sqlsrv_free_stmt($query_id); - } - - return false; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('sqlsrv_errors')) - { - $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); - $error_message = ''; - $code = 0; - - if ($errors != null) - { - foreach ($errors as $error) - { - $error_message .= "SQLSTATE: " . $error['SQLSTATE'] . "\n"; - $error_message .= "code: " . $error['code'] . "\n"; - $code = $error['code']; - $error_message .= "message: " . $error['message'] . "\n"; - } - $this->last_error_result = $error_message; - $error = $this->last_error_result; - } - else - { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); - } - - $error = array( - 'message' => $error, - 'code' => $code, - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @sqlsrv_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - $html_table = false; - @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;'); - if ($result = @sqlsrv_query($this->db_connect_id, $query)) - { - sqlsrv_next_result($result); - while ($row = sqlsrv_fetch_array($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - sqlsrv_free_stmt($result); - } - @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;'); - - if ($html_table) - { - $this->html_hold .= ''; - } - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @sqlsrv_query($this->db_connect_id, $query); - if ($result) - { - while ($void = sqlsrv_fetch_array($result)) - { - // Take the time spent on parsing rows into account - } - sqlsrv_free_stmt($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } - - /** - * Utility method used to retrieve number of rows - * Emulates mysql_num_rows - * Used in acp_database.php -> write_data_mssqlnative() - * Requires a static or keyset cursor to be definde via - * mssqlnative_set_query_options() - */ - function mssqlnative_num_rows($res) - { - if ($res !== false) - { - return sqlsrv_num_rows($res); - } - else - { - return false; - } - } - - /** - * Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter. - */ - function mssqlnative_set_query_options($options) - { - $this->query_options = $options; - } -} diff --git a/install/update/old/phpbb/db/driver/mysqli.php b/install/update/old/phpbb/db/driver/mysqli.php deleted file mode 100644 index d43e201..0000000 --- a/install/update/old/phpbb/db/driver/mysqli.php +++ /dev/null @@ -1,490 +0,0 @@ - -* @license 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; - -/** -* MySQLi Database Abstraction Layer -* mysqli-extension has to be compiled with: -* MySQL 4.1+ or MySQL 5.0+ -*/ -class mysqli extends \phpbb\db\driver\mysql_base -{ - var $multi_insert = true; - var $connect_error = ''; - - /** - * {@inheritDoc} - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - if (!function_exists('mysqli_connect')) - { - $this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?'; - return $this->sql_error(''); - } - - $this->persistency = $persistency; - $this->user = $sqluser; - - // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix - $this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver; - - $this->dbname = $database; - $port = (!$port) ? null : $port; - - // If port is set and it is not numeric, most likely mysqli socket is set. - // Try to map it to the $socket parameter. - $socket = null; - if ($port) - { - if (is_numeric($port)) - { - $port = (int) $port; - } - else - { - $socket = $port; - $port = null; - } - } - - $this->db_connect_id = mysqli_init(); - - if (!@mysqli_real_connect($this->db_connect_id, $this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket, MYSQLI_CLIENT_FOUND_ROWS)) - { - $this->db_connect_id = ''; - } - - if ($this->db_connect_id && $this->dbname != '') - { - @mysqli_query($this->db_connect_id, "SET NAMES 'utf8'"); - - // enforce strict mode on databases that support it - if (version_compare($this->sql_server_info(true), '5.0.2', '>=')) - { - $result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode'); - if ($result) - { - $row = mysqli_fetch_assoc($result); - mysqli_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)) - { - if (!in_array('STRICT_ALL_TABLES', $modes)) - { - $modes[] = 'STRICT_ALL_TABLES'; - } - - if (!in_array('STRICT_TRANS_TABLES', $modes)) - { - $modes[] = 'STRICT_TRANS_TABLES'; - } - } - - $mode = implode(',', $modes); - @mysqli_query($this->db_connect_id, "SET SESSION sql_mode='{$mode}'"); - } - return $this->db_connect_id; - } - - return $this->sql_error(''); - } - - /** - * {@inheritDoc} - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false) - { - $result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version'); - if ($result) - { - $row = mysqli_fetch_assoc($result); - mysqli_free_result($result); - - $this->sql_server_version = $row['version']; - - if (!empty($cache) && $use_cache) - { - $cache->put('mysqli_version', $this->sql_server_version); - } - } - } - - return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @mysqli_autocommit($this->db_connect_id, false); - break; - - case 'commit': - $result = @mysqli_commit($this->db_connect_id); - @mysqli_autocommit($this->db_connect_id, true); - return $result; - break; - - case 'rollback': - $result = @mysqli_rollback($this->db_connect_id); - @mysqli_autocommit($this->db_connect_id, true); - return $result; - break; - } - - return true; - } - - /** - * {@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 = @mysqli_query($this->db_connect_id, $query)) === 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 (!$this->query_result) - { - return false; - } - - if ($cache && $cache_ttl) - { - $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); - } - } - else if (defined('DEBUG')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @mysqli_affected_rows($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 && !is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchrow($query_id); - } - - if ($query_id) - { - $result = mysqli_fetch_assoc($query_id); - return $result !== null ? $result : false; - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_rowseek($rownum, &$query_id) - { - 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_rowseek($rownum, $query_id); - } - - return ($query_id) ? @mysqli_data_seek($query_id, $rownum) : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - return ($this->db_connect_id) ? @mysqli_insert_id($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); - } - - if (!$query_id) - { - return false; - } - - if ($query_id === true) - { - return true; - } - - return mysqli_free_result($query_id); - } - - /** - * {@inheritDoc} - */ - function sql_escape($msg) - { - return @mysqli_real_escape_string($this->db_connect_id, $msg); - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if ($this->db_connect_id) - { - $error = array( - 'message' => @mysqli_error($this->db_connect_id), - 'code' => @mysqli_errno($this->db_connect_id) - ); - } - else if (function_exists('mysqli_connect_error')) - { - $error = array( - 'message' => @mysqli_connect_error(), - 'code' => @mysqli_connect_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @mysqli_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - static $test_prof; - - // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING - if ($test_prof === null) - { - $test_prof = false; - if (strpos(mysqli_get_server_info($this->db_connect_id), 'community') !== false) - { - $ver = mysqli_get_server_version($this->db_connect_id); - if ($ver >= 50037 && $ver < 50100) - { - $test_prof = true; - } - } - } - - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - // begin profiling - if ($test_prof) - { - @mysqli_query($this->db_connect_id, 'SET profiling = 1;'); - } - - if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query")) - { - while ($row = mysqli_fetch_assoc($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - mysqli_free_result($result); - } - - if ($html_table) - { - $this->html_hold .= ''; - } - - if ($test_prof) - { - $html_table = false; - - // get the last profile - if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;')) - { - $this->html_hold .= '
'; - while ($row = mysqli_fetch_assoc($result)) - { - // make HTML safe - if (!empty($row['Source_function'])) - { - $row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']); - } - - // remove unsupported features - foreach ($row as $key => $val) - { - if ($val === null) - { - unset($row[$key]); - } - } - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - mysqli_free_result($result); - } - - if ($html_table) - { - $this->html_hold .= ''; - } - - @mysqli_query($this->db_connect_id, 'SET profiling = 0;'); - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @mysqli_query($this->db_connect_id, $query); - if ($result) - { - while ($void = mysqli_fetch_assoc($result)) - { - // Take the time spent on parsing rows into account - } - mysqli_free_result($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/install/update/old/phpbb/db/driver/oracle.php b/install/update/old/phpbb/db/driver/oracle.php deleted file mode 100644 index 5fd1470..0000000 --- a/install/update/old/phpbb/db/driver/oracle.php +++ /dev/null @@ -1,822 +0,0 @@ - -* @license 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; - -/** -* Oracle Database Abstraction Layer -*/ -class oracle extends \phpbb\db\driver\driver -{ - var $last_query_text = ''; - 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; - - $connect = $database; - - // support for "easy connect naming" - if ($sqlserver !== '' && $sqlserver !== '/') - { - if (substr($sqlserver, -1, 1) == '/') - { - $sqlserver == substr($sqlserver, 0, -1); - } - $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database; - } - - if ($new_link) - { - if (!function_exists('ocinlogon')) - { - $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - else if ($this->persistency) - { - if (!function_exists('ociplogon')) - { - $this->connect_error = 'ociplogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - else - { - if (!function_exists('ocilogon')) - { - $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - - return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); - } - - /** - * {@inheritDoc} - */ - function sql_server_info($raw = false, $use_cache = true) - { - /** - * force $use_cache false. I didn't research why the caching code below is commented out - * but I assume its because the Oracle extension provides a direct method to access it - * without a query. - */ -/* - global $cache; - - if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false) - { - $result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\''); - @ociexecute($result, OCI_DEFAULT); - @ocicommit($this->db_connect_id); - - $row = array(); - @ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS); - @ocifreestatement($result); - $this->sql_server_version = trim($row['BANNER']); - - $cache->put('oracle_version', $this->sql_server_version); - } -*/ - $this->sql_server_version = @ociserverversion($this->db_connect_id); - - return $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return true; - break; - - case 'commit': - return @ocicommit($this->db_connect_id); - break; - - case 'rollback': - return @ocirollback($this->db_connect_id); - break; - } - - return true; - } - - /** - * Oracle specific code to handle the fact that it does not compare columns properly - * @access private - */ - function _rewrite_col_compare($args) - { - if (count($args) == 4) - { - if ($args[2] == '=') - { - return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))'; - } - else if ($args[2] == '<>') - { - // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P - return '(' . $args[0] . ' OR ((' . $args[1] . ' is NULL AND ' . $args[3] . ' is NOT NULL) OR (' . $args[1] . ' is NOT NULL AND ' . $args[3] . ' is NULL)))'; - } - } - else - { - return $this->_rewrite_where($args[0]); - } - } - - /** - * Oracle specific code to handle it's lack of sanity - * @access private - */ - function _rewrite_where($where_clause) - { - preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER); - $out = ''; - foreach ($result as $val) - { - if (!isset($val[5])) - { - if ($val[4] !== "''") - { - $out .= $val[0]; - } - else - { - $out .= ' ' . $val[1] . ' ' . $val[2]; - if ($val[3] == '=') - { - $out .= ' is NULL'; - } - else if ($val[3] == '<>') - { - $out .= ' is NOT NULL'; - } - } - } - else - { - $in_clause = array(); - $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1); - $extra = false; - preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER); - $i = 0; - foreach ($sub_vals[0] as $sub_val) - { - // two things: - // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison - // 2) This fixes the 1000 list limit that Oracle has (ORA-01795) - if ($sub_val !== "''") - { - $in_clause[(int) $i++/1000][] = $sub_val; - } - else - { - $extra = true; - } - } - if (!$extra && $i < 1000) - { - $out .= $val[0]; - } - else - { - $out .= ' ' . $val[1] . '('; - $in_array = array(); - - // constuct each IN() clause - foreach ($in_clause as $in_values) - { - $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')'; - } - - // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway) - $out .= implode(' OR ', $in_array); - - // handle the empty string case - if ($extra) - { - $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL'; - } - $out .= ')'; - - unset($in_array, $in_clause); - } - } - } - - return $out; - } - - /** - * {@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->last_query_text = $query; - $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - $in_transaction = false; - if (!$this->transaction) - { - $this->sql_transaction('begin'); - } - else - { - $in_transaction = true; - } - - $array = array(); - - // We overcome Oracle's 4000 char limit by binding vars - if (strlen($query) > 4000) - { - if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs)) - { - if (strlen($regs[3]) > 4000) - { - $cols = explode(', ', $regs[2]); - - preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); - -/* The code inside this comment block breaks clob handling, but does allow the - database restore script to work. If you want to allow no posts longer than 4KB - and/or need the db restore script, uncomment this. - - - if (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]); - $_vals = explode(', ', $regs[3]); - - $vals = array(); - $is_in_val = false; - $i = 0; - $string = ''; - - foreach ($_vals as $value) - { - if (strpos($value, "'") === false && !$is_in_val) - { - $vals[$i++] = $value; - continue; - } - - if (substr($value, -1) === "'") - { - $vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value; - $string = ''; - $is_in_val = false; - - if ($vals[$i][0] !== "'") - { - $vals[$i] = "''" . $vals[$i]; - } - $i++; - continue; - } - else - { - $string .= (($is_in_val) ? ', ' : '') . $value; - $is_in_val = true; - } - } - - if ($string) - { - // New value if cols != value - $vals[(count($cols) !== count($vals)) ? $i : $i - 1] .= $string; - } - - $vals = array(0 => $vals); - } -*/ - - $inserts = $vals[0]; - unset($vals); - - foreach ($inserts as $key => $value) - { - if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2 - { - $inserts[$key] = ':' . strtoupper($cols[$key]); - $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1)); - } - } - - $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')'; - } - } - else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER)) - { - if (strlen($data[0][2]) > 4000) - { - $update = $data[0][1]; - $where = $data[0][3]; - preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER); - unset($data); - - $cols = array(); - foreach ($temp as $value) - { - if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2 - { - $cols[] = $value[1] . '=:' . strtoupper($value[1]); - $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1)); - } - else - { - $cols[] = $value[1] . '=' . $value[2]; - } - } - - $query = $update . implode(', ', $cols) . ' ' . $where; - unset($cols); - } - } - } - - switch (substr($query, 0, 6)) - { - case 'DELETE': - if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs)) - { - $query = $regs[1] . $this->_rewrite_where($regs[2]); - unset($regs); - } - break; - - case 'UPDATE': - if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs)) - { - $query = $regs[1] . $this->_rewrite_where($regs[2]); - unset($regs); - } - break; - - case 'SELECT': - $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query); - break; - } - - $this->query_result = @ociparse($this->db_connect_id, $query); - - foreach ($array as $key => $value) - { - @ocibindbyname($this->query_result, $key, $array[$key], -1); - } - - $success = @ociexecute($this->query_result, OCI_DEFAULT); - - if (!$success) - { - $this->sql_error($query); - $this->query_result = false; - } - else - { - if (!$in_transaction) - { - $this->sql_transaction('commit'); - } - } - - if (defined('DEBUG')) - { - $this->sql_report('stop', $query); - } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) - { - $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->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset; - - return $this->sql_query($query, $cache_ttl); - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - return ($this->query_result) ? @ocirowcount($this->query_result) : 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) - { - $row = array(); - $result = ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS); - - if (!$result || !$row) - { - return false; - } - - $result_row = array(); - foreach ($row as $key => $value) - { - // Oracle treats empty strings as null - if (is_null($value)) - { - $value = ''; - } - - // OCI->CLOB? - if (is_object($value)) - { - $value = $value->load(); - } - - $result_row[strtolower($key)] = $value; - } - - return $result_row; - } - - return false; - } - - /** - * {@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); - } - - if (!$query_id) - { - return false; - } - - // Reset internal pointer - @ociexecute($query_id, OCI_DEFAULT); - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - $query_id = $this->query_result; - - if ($query_id !== false && $this->last_query_text != '') - { - if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename)) - { - $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL'; - $stmt = @ociparse($this->db_connect_id, $query); - if ($stmt) - { - $success = @ociexecute($stmt, OCI_DEFAULT); - - 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; - } - } - } - } - } - - 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 ocifreestatement($query_id); - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_escape($msg) - { - return str_replace(array("'", "\0"), array("''", ''), $msg); - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - /** - * Build NOT LIKE expression - * @access private - */ - function _sql_not_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - function _sql_custom_build($stage, $data) - { - return $data; - } - - function _sql_bit_and($column_name, $bit, $compare = '') - { - return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); - } - - function _sql_bit_or($column_name, $bit, $compare = '') - { - return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('ocierror')) - { - $error = @ocierror(); - $error = (!$error) ? @ocierror($this->query_result) : $error; - $error = (!$error) ? @ocierror($this->db_connect_id) : $error; - - if ($error) - { - $this->last_error_result = $error; - } - else - { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); - } - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @ocilogoff($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $html_table = false; - - // Grab a plan table, any will do - $sql = "SELECT table_name - FROM USER_TABLES - WHERE table_name LIKE '%PLAN_TABLE%'"; - $stmt = ociparse($this->db_connect_id, $sql); - ociexecute($stmt); - $result = array(); - - if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS)) - { - $table = $result['TABLE_NAME']; - - // This is the statement_id that will allow us to track the plan - $statement_id = substr(md5($query), 0, 30); - - // Remove any stale plans - $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); - ociexecute($stmt2); - ocifreestatement($stmt2); - - // Explain the plan - $sql = "EXPLAIN PLAN - SET STATEMENT_ID = '$statement_id' - FOR $query"; - $stmt2 = ociparse($this->db_connect_id, $sql); - ociexecute($stmt2); - ocifreestatement($stmt2); - - // Get the data from the plan - $sql = "SELECT operation, options, object_name, object_type, cardinality, cost - FROM plan_table - START WITH id = 0 AND statement_id = '$statement_id' - CONNECT BY PRIOR id = parent_id - AND statement_id = '$statement_id'"; - $stmt2 = ociparse($this->db_connect_id, $sql); - ociexecute($stmt2); - - $row = array(); - while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - - ocifreestatement($stmt2); - - // Remove the plan we just made, we delete them on request anyway - $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); - ociexecute($stmt2); - ocifreestatement($stmt2); - } - - ocifreestatement($stmt); - - if ($html_table) - { - $this->html_hold .= ''; - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @ociparse($this->db_connect_id, $query); - if ($result) - { - $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); - } - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/install/update/old/phpbb/db/driver/postgres.php b/install/update/old/phpbb/db/driver/postgres.php deleted file mode 100644 index 4447661..0000000 --- a/install/update/old/phpbb/db/driver/postgres.php +++ /dev/null @@ -1,501 +0,0 @@ - -* @license 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; - -/** -* PostgreSQL Database Abstraction Layer -* Minimum Requirement is Version 8.3+ -*/ -class postgres extends \phpbb\db\driver\driver -{ - var $multi_insert = true; - var $last_query_text = ''; - var $connect_error = ''; - - /** - * {@inheritDoc} - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $connect_string = ''; - - if ($sqluser) - { - $connect_string .= "user=$sqluser "; - } - - if ($sqlpassword) - { - $connect_string .= "password=$sqlpassword "; - } - - if ($sqlserver) - { - // $sqlserver can carry a port separated by : for compatibility reasons - // If $sqlserver has more than one : it's probably an IPv6 address. - // In this case we only allow passing a port via the $port variable. - if (substr_count($sqlserver, ':') === 1) - { - list($sqlserver, $port) = explode(':', $sqlserver); - } - - if ($sqlserver !== 'localhost') - { - $connect_string .= "host=$sqlserver "; - } - - if ($port) - { - $connect_string .= "port=$port "; - } - } - - $schema = ''; - - if ($database) - { - $this->dbname = $database; - if (strpos($database, '.') !== false) - { - list($database, $schema) = explode('.', $database); - } - $connect_string .= "dbname=$database"; - } - - $this->persistency = $persistency; - - if ($this->persistency) - { - if (!function_exists('pg_pconnect')) - { - $this->connect_error = 'pg_pconnect function does not exist, is pgsql extension installed?'; - return $this->sql_error(''); - } - $collector = new \phpbb\error_collector; - $collector->install(); - $this->db_connect_id = (!$new_link) ? @pg_pconnect($connect_string) : @pg_pconnect($connect_string, PGSQL_CONNECT_FORCE_NEW); - } - else - { - if (!function_exists('pg_connect')) - { - $this->connect_error = 'pg_connect function does not exist, is pgsql extension installed?'; - return $this->sql_error(''); - } - $collector = new \phpbb\error_collector; - $collector->install(); - $this->db_connect_id = (!$new_link) ? @pg_connect($connect_string) : @pg_connect($connect_string, PGSQL_CONNECT_FORCE_NEW); - } - - $collector->uninstall(); - - if ($this->db_connect_id) - { - if ($schema !== '') - { - @pg_query($this->db_connect_id, 'SET search_path TO ' . $schema); - } - return $this->db_connect_id; - } - - $this->connect_error = $collector->format_errors(); - return $this->sql_error(''); - } - - /** - * {@inheritDoc} - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('pgsql_version')) === false) - { - $query_id = @pg_query($this->db_connect_id, 'SELECT VERSION() AS version'); - 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; - - if (!empty($cache) && $use_cache) - { - $cache->put('pgsql_version', $this->sql_server_version); - } - } - } - - return ($raw) ? $this->sql_server_version : 'PostgreSQL ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @pg_query($this->db_connect_id, 'BEGIN'); - break; - - case 'commit': - return @pg_query($this->db_connect_id, 'COMMIT'); - break; - - case 'rollback': - return @pg_query($this->db_connect_id, 'ROLLBACK'); - break; - } - - return true; - } - - /** - * {@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->last_query_text = $query; - $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 = @pg_query($this->db_connect_id, $query)) === 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 (!$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->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) - { - $total = 'ALL'; - } - - $query .= "\n LIMIT $total OFFSET $offset"; - - return $this->sql_query($query, $cache_ttl); - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - return ($this->query_result) ? @pg_affected_rows($this->query_result) : 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) ? pg_fetch_assoc($query_id, null) : 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) ? @pg_result_seek($query_id, $rownum) : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - $query_id = $this->query_result; - - if ($query_id !== false && $this->last_query_text != '') - { - if (preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $this->last_query_text, $tablename)) - { - $query = "SELECT currval('" . $tablename[1] . "_seq') AS last_value"; - $temp_q_id = @pg_query($this->db_connect_id, $query); - - if (!$temp_q_id) - { - return false; - } - - $temp_result = pg_fetch_assoc($temp_q_id, null); - pg_free_result($query_id); - - return ($temp_result) ? $temp_result['last_value'] : false; - } - } - - return false; - } - - /** - * {@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 pg_free_result($query_id); - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_escape($msg) - { - return @pg_escape_string($msg); - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression; - } - - /** - * Build NOT LIKE expression - * @access private - */ - function _sql_not_like_expression($expression) - { - return $expression; - } - - /** - * {@inheritDoc} - */ - function cast_expr_to_bigint($expression) - { - return 'CAST(' . $expression . ' as DECIMAL(255, 0))'; - } - - /** - * {@inheritDoc} - */ - function cast_expr_to_string($expression) - { - return 'CAST(' . $expression . ' as VARCHAR(255))'; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - // pg_last_error only works when there is an established connection. - // Connection errors have to be tracked by us manually. - if ($this->db_connect_id) - { - $message = @pg_last_error($this->db_connect_id); - } - else - { - $message = $this->connect_error; - } - - return array( - 'message' => $message, - 'code' => '' - ); - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @pg_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - if ($result = @pg_query($this->db_connect_id, "EXPLAIN $explain_query")) - { - while ($row = pg_fetch_assoc($result, null)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - pg_free_result($result); - } - - if ($html_table) - { - $this->html_hold .= ''; - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @pg_query($this->db_connect_id, $query); - if ($result) - { - while ($void = pg_fetch_assoc($result, null)) - { - // Take the time spent on parsing rows into account - } - pg_free_result($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/install/update/old/phpbb/db/driver/sqlite3.php b/install/update/old/phpbb/db/driver/sqlite3.php deleted file mode 100644 index 0508500..0000000 --- a/install/update/old/phpbb/db/driver/sqlite3.php +++ /dev/null @@ -1,431 +0,0 @@ - -* @license 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; - -/** -* SQLite3 Database Abstraction Layer -* Minimum Requirement: 3.6.15+ -*/ -class sqlite3 extends \phpbb\db\driver\driver -{ - /** - * @var string Stores errors during connection setup in case the driver is not available - */ - protected $connect_error = ''; - - /** - * @var \SQLite3 The SQLite3 database object to operate against - */ - protected $dbo = null; - - /** - * {@inheritDoc} - */ - public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $this->persistency = false; - $this->user = $sqluser; - $this->server = $sqlserver . (($port) ? ':' . $port : ''); - $this->dbname = $database; - - if (!class_exists('SQLite3', false)) - { - $this->connect_error = 'SQLite3 not found, is the extension installed?'; - return $this->sql_error(''); - } - - try - { - $this->dbo = new \SQLite3($this->server, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE); - $this->dbo->busyTimeout(60000); - $this->db_connect_id = true; - } - catch (\Exception $e) - { - $this->connect_error = $e->getMessage(); - return array('message' => $this->connect_error); - } - - return true; - } - - /** - * {@inheritDoc} - */ - public 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) - { - $version = \SQLite3::version(); - - $this->sql_server_version = $version['versionString']; - - 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 - * - * @param string $status Should be one of the following strings: - * begin, commit, rollback - * @return bool Success/failure of the transaction query - */ - protected function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return $this->dbo->exec('BEGIN IMMEDIATE'); - break; - - case 'commit': - return $this->dbo->exec('COMMIT'); - break; - - case 'rollback': - return @$this->dbo->exec('ROLLBACK'); - break; - } - - return true; - } - - /** - * {@inheritDoc} - */ - public function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG')) - { - $this->sql_report('start', $query); - } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) - { - $this->curtime = microtime(true); - } - - $this->last_query_text = $query; - $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->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) - { - // 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')) - { - $this->sql_report('stop', $query); - } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) - { - $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); - } - } - else if (defined('DEBUG')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - * - * @param string $query The SQL query to execute - * @param int $total The number of rows to select - * @param int $offset - * @param int $cache_ttl Either 0 to avoid caching or - * the time in seconds which the result shall be kept in cache - * @return mixed Buffered, seekable result handle, false on error - */ - protected 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} - */ - public function sql_affectedrows() - { - return ($this->db_connect_id) ? $this->dbo->changes() : false; - } - - /** - * {@inheritDoc} - */ - public function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - /** @var \SQLite3Result $query_id */ - $query_id = $this->query_result; - } - - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchrow($query_id); - } - - return is_object($query_id) ? @$query_id->fetchArray(SQLITE3_ASSOC) : false; - } - - /** - * {@inheritDoc} - */ - public function sql_nextid() - { - return ($this->db_connect_id) ? $this->dbo->lastInsertRowID() : false; - } - - /** - * {@inheritDoc} - */ - public 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 ($query_id) - { - return @$query_id->finalize(); - } - } - - /** - * {@inheritDoc} - */ - public function sql_escape($msg) - { - return \SQLite3::escapeString($msg); - } - - /** - * {@inheritDoc} - * - * For SQLite an underscore is an unknown character. - */ - public 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 an unknown character. - */ - public 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 - * - * @return array - */ - protected function _sql_error() - { - if (class_exists('SQLite3', false) && isset($this->dbo)) - { - $error = array( - 'message' => $this->dbo->lastErrorMsg(), - 'code' => $this->dbo->lastErrorCode(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Build db-specific query data - * - * @param string $stage Available stages: FROM, WHERE - * @param mixed $data A string containing the CROSS JOIN query or an array of WHERE clauses - * - * @return string The db-specific query fragment - */ - protected function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * Close sql connection - * - * @return bool False if failure - */ - protected function _sql_close() - { - return $this->dbo->close(); - } - - /** - * Build db-specific report - * - * @param string $mode Available modes: display, start, stop, - * add_select_row, fromcache, record_fromcache - * @param string $query The Query that should be explained - * @return mixed Either a full HTML page, boolean or null - */ - protected function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - if ($result = $this->dbo->query("EXPLAIN QUERY PLAN $explain_query")) - { - while ($row = $result->fetchArray(SQLITE3_ASSOC)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - - if ($html_table) - { - $this->html_hold .= ''; - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = $this->dbo->query($query); - if ($result) - { - while ($void = $result->fetchArray(SQLITE3_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/install/update/old/phpbb/db/extractor/mysql_extractor.php b/install/update/old/phpbb/db/extractor/mysql_extractor.php deleted file mode 100644 index 34e309c..0000000 --- a/install/update/old/phpbb/db/extractor/mysql_extractor.php +++ /dev/null @@ -1,403 +0,0 @@ - -* @license 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/install/update/old/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php b/install/update/old/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php deleted file mode 100644 index 1034343..0000000 --- a/install/update/old/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php +++ /dev/null @@ -1,129 +0,0 @@ - -* @license 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\v30x; - -class release_3_0_4_rc1 extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return phpbb_version_compare($this->config['version'], '3.0.4-RC1', '>='); - } - - static public function depends_on() - { - return array('\phpbb\db\migration\data\v30x\release_3_0_3'); - } - - public function update_schema() - { - return array( - 'add_columns' => array( - $this->table_prefix . 'profile_fields' => array( - 'field_show_profile' => array('BOOL', 0), - ), - ), - 'change_columns' => array( - $this->table_prefix . 'styles' => array( - 'style_id' => array('UINT', NULL, 'auto_increment'), - 'template_id' => array('UINT', 0), - 'theme_id' => array('UINT', 0), - 'imageset_id' => array('UINT', 0), - ), - $this->table_prefix . 'styles_imageset' => array( - 'imageset_id' => array('UINT', NULL, 'auto_increment'), - ), - $this->table_prefix . 'styles_imageset_data' => array( - 'image_id' => array('UINT', NULL, 'auto_increment'), - 'imageset_id' => array('UINT', 0), - ), - $this->table_prefix . 'styles_theme' => array( - 'theme_id' => array('UINT', NULL, 'auto_increment'), - ), - $this->table_prefix . 'styles_template' => array( - 'template_id' => array('UINT', NULL, 'auto_increment'), - ), - $this->table_prefix . 'styles_template_data' => array( - 'template_id' => array('UINT', 0), - ), - $this->table_prefix . 'forums' => array( - 'forum_style' => array('UINT', 0), - ), - $this->table_prefix . 'users' => array( - 'user_style' => array('UINT', 0), - ), - ), - ); - } - - public function revert_schema() - { - return array( - 'drop_columns' => array( - $this->table_prefix . 'profile_fields' => array( - 'field_show_profile', - ), - ), - ); - } - - public function update_data() - { - return array( - array('custom', array(array(&$this, 'update_custom_profile_fields'))), - - array('config.update', array('version', '3.0.4-RC1')), - ); - } - - public function update_custom_profile_fields() - { - // Update the Custom Profile Fields based on previous settings to the new \format - $sql = 'SELECT field_id, field_required, field_show_on_reg, field_hide - FROM ' . PROFILE_FIELDS_TABLE; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - $sql_ary = array( - 'field_required' => 0, - 'field_show_on_reg' => 0, - 'field_hide' => 0, - 'field_show_profile'=> 0, - ); - - if ($row['field_required']) - { - $sql_ary['field_required'] = $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1; - } - else if ($row['field_show_on_reg']) - { - $sql_ary['field_show_on_reg'] = $sql_ary['field_show_profile'] = 1; - } - else if ($row['field_hide']) - { - // Only administrators and moderators can see this CPF, if the view is enabled, they can see it, otherwise just admins in the acp_users module - $sql_ary['field_hide'] = 1; - } - else - { - // equivelant to "none", which is the "Display in user control panel" option - $sql_ary['field_show_profile'] = 1; - } - - $this->sql_query('UPDATE ' . $this->table_prefix . 'profile_fields SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE field_id = ' . $row['field_id'], $errored, $error_ary); - } - - $this->db->sql_freeresult($result); - } -} diff --git a/install/update/old/phpbb/db/migration/data/v310/softdelete_p1.php b/install/update/old/phpbb/db/migration/data/v310/softdelete_p1.php deleted file mode 100644 index b1e7486..0000000 --- a/install/update/old/phpbb/db/migration/data/v310/softdelete_p1.php +++ /dev/null @@ -1,211 +0,0 @@ - -* @license 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\v310; - -class softdelete_p1 extends \phpbb\db\migration\migration -{ - public function effectively_installed() - { - return $this->db_tools->sql_column_exists($this->table_prefix . 'posts', 'post_visibility'); - } - - static public function depends_on() - { - return array('\phpbb\db\migration\data\v310\dev'); - } - - public function update_schema() - { - return array( - 'add_columns' => array( - $this->table_prefix . 'forums' => array( - 'forum_posts_approved' => array('UINT', 0), - 'forum_posts_unapproved' => array('UINT', 0), - 'forum_posts_softdeleted' => array('UINT', 0), - 'forum_topics_approved' => array('UINT', 0), - 'forum_topics_unapproved' => array('UINT', 0), - 'forum_topics_softdeleted' => array('UINT', 0), - ), - $this->table_prefix . 'posts' => array( - 'post_visibility' => array('TINT:3', 0), - 'post_delete_time' => array('TIMESTAMP', 0), - 'post_delete_reason' => array('STEXT_UNI', ''), - 'post_delete_user' => array('UINT', 0), - ), - $this->table_prefix . 'topics' => array( - 'topic_visibility' => array('TINT:3', 0), - 'topic_delete_time' => array('TIMESTAMP', 0), - 'topic_delete_reason' => array('STEXT_UNI', ''), - 'topic_delete_user' => array('UINT', 0), - 'topic_posts_approved' => array('UINT', 0), - 'topic_posts_unapproved' => array('UINT', 0), - 'topic_posts_softdeleted' => array('UINT', 0), - ), - ), - 'add_index' => array( - $this->table_prefix . 'posts' => array( - 'post_visibility' => array('post_visibility'), - ), - $this->table_prefix . 'topics' => array( - 'topic_visibility' => array('topic_visibility'), - 'forum_vis_last' => array('forum_id', 'topic_visibility', 'topic_last_post_id'), - ), - ), - ); - } - - public function revert_schema() - { - return array( - 'drop_columns' => array( - $this->table_prefix . 'forums' => array( - 'forum_posts_approved', - 'forum_posts_unapproved', - 'forum_posts_softdeleted', - 'forum_topics_approved', - 'forum_topics_unapproved', - 'forum_topics_softdeleted', - ), - $this->table_prefix . 'posts' => array( - 'post_visibility', - 'post_delete_time', - 'post_delete_reason', - 'post_delete_user', - ), - $this->table_prefix . 'topics' => array( - 'topic_visibility', - 'topic_delete_time', - 'topic_delete_reason', - 'topic_delete_user', - 'topic_posts_approved', - 'topic_posts_unapproved', - 'topic_posts_softdeleted', - ), - ), - 'drop_keys' => array( - $this->table_prefix . 'posts' => array('post_visibility'), - $this->table_prefix . 'topics' => array('topic_visibility', 'forum_vis_last'), - ), - ); - } - - public function update_data() - { - return array( - array('custom', array(array($this, 'update_post_visibility'))), - array('custom', array(array($this, 'update_topic_visibility'))), - array('custom', array(array($this, 'update_topics_post_counts'))), - array('custom', array(array($this, 'update_forums_topic_and_post_counts'))), - - array('permission.add', array('f_softdelete', false)), - array('permission.add', array('m_softdelete', false)), - ); - } - - public function update_post_visibility() - { - $sql = 'UPDATE ' . $this->table_prefix . 'posts - SET post_visibility = post_approved'; - $this->sql_query($sql); - } - - public function update_topic_visibility() - { - $sql = 'UPDATE ' . $this->table_prefix . 'topics - SET topic_visibility = topic_approved'; - $this->sql_query($sql); - } - - public function update_topics_post_counts() - { - /* - * Using sql_case here to avoid "BIGINT UNSIGNED value is out of range" errors. - * As we update all topics in 2 queries, one broken topic would stop the conversion - * for all topics and the surpressed error will cause the admin to not even notice it. - */ - $sql = 'UPDATE ' . $this->table_prefix . 'topics - SET topic_posts_approved = topic_replies + 1, - topic_posts_unapproved = ' . $this->db->sql_case('topic_replies_real > topic_replies', 'topic_replies_real - topic_replies', '0') . ' - WHERE topic_visibility = ' . ITEM_APPROVED; - $this->sql_query($sql); - - $sql = 'UPDATE ' . $this->table_prefix . 'topics - SET topic_posts_approved = 0, - topic_posts_unapproved = (' . $this->db->sql_case('topic_replies_real > topic_replies', 'topic_replies_real - topic_replies', '0') . ') + 1 - WHERE topic_visibility = ' . ITEM_UNAPPROVED; - $this->sql_query($sql); - } - - public function update_forums_topic_and_post_counts($start) - { - $start = (int) $start; - $limit = 10; - $converted_forums = 0; - - if (!$start) - { - // Preserve the forum_posts value for link forums as it represents redirects. - $sql = 'UPDATE ' . $this->table_prefix . 'forums - SET forum_posts_approved = forum_posts - WHERE forum_type = ' . FORUM_LINK; - $this->db->sql_query($sql); - } - - $sql = 'SELECT forum_id, topic_visibility, COUNT(topic_id) AS sum_topics, SUM(topic_posts_approved) AS sum_posts_approved, SUM(topic_posts_unapproved) AS sum_posts_unapproved - FROM ' . $this->table_prefix . 'topics - GROUP BY forum_id, topic_visibility - ORDER BY forum_id, topic_visibility'; - $result = $this->db->sql_query_limit($sql, $limit, $start); - - $update_forums = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $converted_forums++; - - $forum_id = (int) $row['forum_id']; - if (!isset($update_forums[$forum_id])) - { - $update_forums[$forum_id] = array( - 'forum_posts_approved' => 0, - 'forum_posts_unapproved' => 0, - 'forum_topics_approved' => 0, - 'forum_topics_unapproved' => 0, - ); - } - - $update_forums[$forum_id]['forum_posts_approved'] += (int) $row['sum_posts_approved']; - $update_forums[$forum_id]['forum_posts_unapproved'] += (int) $row['sum_posts_unapproved']; - - $update_forums[$forum_id][(($row['topic_visibility'] == ITEM_APPROVED) ? 'forum_topics_approved' : 'forum_topics_unapproved')] += (int) $row['sum_topics']; - } - $this->db->sql_freeresult($result); - - foreach ($update_forums as $forum_id => $forum_data) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . $this->db->sql_build_array('UPDATE', $forum_data) . ' - WHERE forum_id = ' . $forum_id; - $this->sql_query($sql); - } - - if ($converted_forums < $limit) - { - // There are no more topics, we are done - return; - } - - // There are still more topics to query, return the next start value - return $start + $limit; - } -} diff --git a/install/update/old/phpbb/db/migration/tool/module.php b/install/update/old/phpbb/db/migration/tool/module.php deleted file mode 100644 index e5133c8..0000000 --- a/install/update/old/phpbb/db/migration/tool/module.php +++ /dev/null @@ -1,556 +0,0 @@ - -* @license 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\tool; - -use phpbb\module\exception\module_exception; - -/** -* Migration module management tool -*/ -class module implements \phpbb\db\migration\tool\tool_interface -{ - /** @var \phpbb\cache\service */ - protected $cache; - - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\user */ - protected $user; - - /** @var \phpbb\module\module_manager */ - protected $module_manager; - - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - - /** @var string */ - protected $modules_table; - - /** @var array */ - protected $module_categories = array(); - - /** - * Constructor - * - * @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\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; - } - - /** - * {@inheritdoc} - */ - public function get_name() - { - return 'module'; - } - - /** - * Module Exists - * - * Check if a module exists - * - * @param string $class The module class(acp|mcp|ucp) - * @param int|string|bool $parent The parent module_id|module_langname (0 for no parent). - * 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 - * @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, $lazy = false) - { - // the main root directory should return true - if (!$module) - { - return true; - } - - $parent_sqls = []; - if ($parent !== false) - { - $parents = $this->get_parent_module_id($parent, $module, false); - if ($parents === false) - { - return false; - } - - foreach ((array) $parents as $parent_id) - { - $parent_sqls[] = 'AND parent_id = ' . (int) $parent_id; - } - } - else - { - $parent_sqls[] = ''; - } - - foreach ($parent_sqls as $parent_sql) - { - $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; - } - } - - // Returns true, if modules exist in all parents and false otherwise - return !$lazy; - } - - /** - * Module Add - * - * Add a new module - * - * @param string $class The module class(acp|mcp|ucp) - * @param int|string $parent The parent module_id|module_langname (0 for no parent) - * @param array $data an array of the data on the new \module. - * This can be setup in two different ways. - * 1. The "manual" way. For inserting a category or one at a time. - * It will be merged with the base array shown a bit below, - * but at the least requires 'module_langname' to be sent, and, - * if you want to create a module (instead of just a category) you must - * send module_basename and module_mode. - * array( - * 'module_enabled' => 1, - * 'module_display' => 1, - * 'module_basename' => '', - * 'module_class' => $class, - * 'parent_id' => (int) $parent, - * 'module_langname' => '', - * 'module_mode' => '', - * 'module_auth' => '', - * ) - * 2. The "automatic" way. For inserting multiple at a time based on the - * specs in the info file for the module(s). For this to work the - * modules must be correctly setup in the info file. - * An example follows (this would insert the settings, log, and flag - * modes from the includes/acp/info/acp_asacp.php file): - * array( - * 'module_basename' => 'asacp', - * 'modes' => array('settings', 'log', 'flag'), - * ) - * Optionally you may not send 'modes' and it will insert all of the - * modules in that info file. - * path, specify that here - * @return null - * @throws \phpbb\db\migration\exception - */ - 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); - } - - $parents = (array) $this->get_parent_module_id($parent, $data); - - if (!isset($data['module_langname'])) - { - // The "automatic" way - $basename = (isset($data['module_basename'])) ? $data['module_basename'] : ''; - $module = $this->get_module_info($class, $basename); - - foreach ($module['modes'] as $mode => $module_info) - { - if (!isset($data['modes']) || in_array($mode, $data['modes'])) - { - $new_module = array( - 'module_basename' => $basename, - 'module_langname' => $module_info['title'], - 'module_mode' => $mode, - 'module_auth' => $module_info['auth'], - 'module_display' => (isset($module_info['display'])) ? $module_info['display'] : true, - 'before' => (isset($module_info['before'])) ? $module_info['before'] : false, - 'after' => (isset($module_info['after'])) ? $module_info['after'] : false, - ); - - // Run the "manual" way with the data we've collected. - foreach ($parents as $parent) - { - $this->add($class, $parent, $new_module); - } - } - } - - return; - } - - foreach ($parents as $parent) - { - $data['parent_id'] = $parent; - - // The "manual" way - if (!$this->exists($class, false, $parent)) - { - throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent); - } - - if ($this->exists($class, $parent, $data['module_langname'])) - { - throw new \phpbb\db\migration\exception('MODULE_EXISTS', $data['module_langname']); - } - - $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 - { - $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($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 . " - 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); - - $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']) - { - $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($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 . " - 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); - - $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); - } - } - catch (module_exception $e) - { - // Error - throw new \phpbb\db\migration\exception('MODULE_ERROR', $e->getMessage()); - } - } - - // Clear the Modules Cache - $this->module_manager->remove_cache_file($class); - } - - /** - * Module Remove - * - * Remove a module - * - * @param string $class The module class(acp|mcp|ucp) - * @param int|string|bool $parent The parent module_id|module_langname(0 for no parent). - * Use false to ignore the parent check and check class wide. - * @param int|string $module The module id|module_langname - * specify that here - * @return null - * @throws \phpbb\db\migration\exception - */ - public function remove($class, $parent = 0, $module = '') - { - // Imitation of module_add's "automatic" and "manual" method so the uninstaller works from the same set of instructions for umil_auto - if (is_array($module)) - { - if (isset($module['module_langname'])) - { - // Manual Method - return $this->remove($class, $parent, $module['module_langname']); - } - - // Failed. - if (!isset($module['module_basename'])) - { - throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST'); - } - - // Automatic method - $basename = $module['module_basename']; - $module_info = $this->get_module_info($class, $basename); - - foreach ($module_info['modes'] as $mode => $info) - { - if (!isset($module['modes']) || in_array($mode, $module['modes'])) - { - $this->remove($class, $parent, $info['title']); - } - } - } - else - { - if (!$this->exists($class, $parent, $module, true)) - { - return; - } - - $parent_sql = ''; - if ($parent !== false) - { - $parents = (array) $this->get_parent_module_id($parent, $module); - $parent_sql = 'AND ' . $this->db->sql_in_set('parent_id', $parents); - } - - $module_ids = array(); - if (!is_numeric($module)) - { - $sql = 'SELECT module_id - FROM ' . $this->modules_table . " - WHERE module_langname = '" . $this->db->sql_escape($module) . "' - AND module_class = '" . $this->db->sql_escape($class) . "' - $parent_sql"; - $result = $this->db->sql_query($sql); - while ($module_id = $this->db->sql_fetchfield('module_id')) - { - $module_ids[] = (int) $module_id; - } - $this->db->sql_freeresult($result); - } - else - { - $module_ids[] = (int) $module; - } - - foreach ($module_ids as $module_id) - { - $this->module_manager->delete_module($module_id, $class); - } - - $this->module_manager->remove_cache_file($class); - } - } - - /** - * {@inheritdoc} - */ - public function reverse() - { - $arguments = func_get_args(); - $original_call = array_shift($arguments); - - $call = false; - switch ($original_call) - { - case 'add': - $call = 'remove'; - break; - - case 'remove': - $call = 'add'; - break; - - case 'reverse': - // Reversing a reverse is just the call itself - $call = array_shift($arguments); - break; - } - - if ($call) - { - return call_user_func_array(array(&$this, $call), $arguments); - } - } - - /** - * Wrapper for \acp_modules::get_module_infos() - * - * @param string $class Module Class - * @param string $basename Module Basename - * @return array Module Information - * @throws \phpbb\db\migration\exception - */ - protected function get_module_info($class, $basename) - { - $module = $this->module_manager->get_module_infos($class, $basename, true); - - if (empty($module)) - { - throw new \phpbb\db\migration\exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename); - } - - return array_pop($module); - } - - /** - * Get the list of installed module categories - * key - module_id - * value - module_langname - * - * @return null - */ - protected function get_categories_list() - { - // Select the top level categories - // and 2nd level [sub]categories - $sql = 'SELECT m2.module_id, m2.module_langname - FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2 - WHERE m1.parent_id = 0 - AND (m1.module_id = m2.module_id OR m2.parent_id = m1.module_id) - ORDER BY m1.module_id, m2.module_id ASC"; - - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $this->module_categories[(int) $row['module_id']] = $row['module_langname']; - } - $this->db->sql_freeresult($result); - } - - /** - * Get parent module id - * - * @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, 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) - { - // Allow '' to be sent as 0 - $parent_id = $parent_id ?: 0; - - if (!is_numeric($parent_id)) - { - // Refresh the $module_categories array - $this->get_categories_list(); - - // Search for the parent module_langname - $ids = array_keys($this->module_categories, $parent_id); - - switch (count($ids)) - { - // No parent with the given module_langname exist - case 0: - if ($throw_exception) - { - throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id); - } - - return false; - break; - - // Return the module id - case 1: - return (int) $ids[0]; - break; - - default: - // This represents the old behaviour of phpBB 3.0 - return $ids; - break; - } - } - - return $parent_id; - } -} diff --git a/install/update/old/phpbb/db/migrator.php b/install/update/old/phpbb/db/migrator.php deleted file mode 100644 index 2b0c66f..0000000 --- a/install/update/old/phpbb/db/migrator.php +++ /dev/null @@ -1,1037 +0,0 @@ - -* @license 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\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; - -/** -* The migrator is responsible for applying new migrations in the correct order. -*/ -class migrator -{ - /** - * @var ContainerInterface - */ - protected $container; - - /** @var \phpbb\config\config */ - protected $config; - - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\db\tools\tools_interface */ - protected $db_tools; - - /** @var \phpbb\db\migration\helper */ - protected $helper; - - /** @var string */ - protected $table_prefix; - - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - - /** @var string */ - protected $migrations_table; - - /** - * State of all migrations - * - * (SELECT * FROM migrations table) - * - * @var array - */ - protected $migration_state = array(); - - /** - * Array of all migrations available to be run - * - * @var array - */ - protected $migrations = array(); - - /** - * Array of migrations that have been determined to be fulfillable - * - * @var array - */ - protected $fulfillable_migrations = array(); - - /** - * 'name,' 'class,' and 'state' of the last migration run - * - * 'effectively_installed' set and set to true if the migration was effectively_installed - * - * @var array - */ - protected $last_run_migration = false; - - /** - * The output handler. A null handler is configured by default. - * - * @var migrator_output_handler_interface - */ - protected $output_handler; - - /** - * Constructor of the database migrator - */ - 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; - $this->db = $db; - $this->db_tools = $db_tools; - $this->helper = $helper; - - $this->migrations_table = $migrations_table; - - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->table_prefix = $table_prefix; - - $this->output_handler = new null_migrator_output_handler(); - - foreach ($tools as $tool) - { - $this->tools[$tool->get_name()] = $tool; - } - - $this->tools['dbtools'] = $this->db_tools; - - $this->load_migration_state(); - } - - /** - * Set the output handler. - * - * @param migrator_output_handler_interface $handler The output handler - */ - public function set_output_handler(migrator_output_handler_interface $handler) - { - $this->output_handler = $handler; - } - - /** - * Loads all migrations and their application state from the database. - * - * @return null - */ - public function load_migration_state() - { - $this->migration_state = array(); - - // prevent errors in case the table does not exist yet - $this->db->sql_return_on_error(true); - - $sql = "SELECT * - FROM " . $this->migrations_table; - $result = $this->db->sql_query($sql); - - if (!$this->db->get_sql_error_triggered()) - { - while ($migration = $this->db->sql_fetchrow($result)) - { - $this->migration_state[$migration['migration_name']] = $migration; - - $this->migration_state[$migration['migration_name']]['migration_depends_on'] = unserialize($migration['migration_depends_on']); - $this->migration_state[$migration['migration_name']]['migration_data_state'] = !empty($migration['migration_data_state']) ? unserialize($migration['migration_data_state']) : ''; - } - } - - $this->db->sql_freeresult($result); - - $this->db->sql_return_on_error(false); - } - - /** - * Get an array with information about the last migration run. - * - * The array contains 'name', 'class' and 'state'. 'effectively_installed' is set - * and set to true if the last migration was effectively_installed. - * - * @return array - */ - public function get_last_run_migration() - { - return $this->last_run_migration; - } - - /** - * Sets the list of available migration class names to the given array. - * - * @param array $class_names An array of migration class names - * @return null - */ - 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 - * check if update() needs to be called again use the finished() method. - * - * @return null - */ - public function update() - { - $this->container->get('dispatcher')->disable(); - $this->update_do(); - $this->container->get('dispatcher')->enable(); - } - - /** - * Get a valid migration name from the migration state array in case the - * supplied name is not in the migration state list. - * - * @param string $name Migration name - * @return string Migration name - */ - protected function get_valid_name($name) - { - // Try falling back to a valid migration name with or without leading backslash - if (!isset($this->migration_state[$name])) - { - $prepended_name = ($name[0] == '\\' ? '' : '\\') . $name; - $prefixless_name = $name[0] == '\\' ? substr($name, 1) : $name; - - if (isset($this->migration_state[$prepended_name])) - { - $name = $prepended_name; - } - else if (isset($this->migration_state[$prefixless_name])) - { - $name = $prefixless_name; - } - } - - return $name; - } - - /** - * Effectively runs a single update step from the next migration to be applied. - * - * @return null - */ - protected function update_do() - { - foreach ($this->migrations as $name) - { - $name = $this->get_valid_name($name); - - if (!isset($this->migration_state[$name]) || - !$this->migration_state[$name]['migration_schema_done'] || - !$this->migration_state[$name]['migration_data_done']) - { - if (!$this->try_apply($name)) - { - continue; - } - else - { - return; - } - } - else - { - $this->output_handler->write(array('MIGRATION_EFFECTIVELY_INSTALLED', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); - } - } - } - - /** - * Attempts to apply a step of the given migration or one of its dependencies - * - * @param string $name The class name of the migration - * @return bool Whether any update step was successfully run - * @throws \phpbb\db\migration\exception - */ - protected function try_apply($name) - { - if (!class_exists($name)) - { - $this->output_handler->write(array('MIGRATION_NOT_VALID', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); - return false; - } - - $migration = $this->get_migration($name); - - $state = (isset($this->migration_state[$name])) ? - $this->migration_state[$name] : - array( - 'migration_depends_on' => $migration->depends_on(), - 'migration_schema_done' => false, - 'migration_data_done' => false, - 'migration_data_state' => '', - 'migration_start_time' => 0, - 'migration_end_time' => 0, - ); - - if (!empty($state['migration_depends_on'])) - { - $this->output_handler->write(array('MIGRATION_APPLY_DEPENDENCIES', $name), migrator_output_handler_interface::VERBOSITY_DEBUG); - } - - foreach ($state['migration_depends_on'] as $depend) - { - $depend = $this->get_valid_name($depend); - - // Test all possible namings before throwing exception - if ($this->unfulfillable($depend) !== false) - { - throw new \phpbb\db\migration\exception('MIGRATION_NOT_FULFILLABLE', $name, $depend); - } - - if (!isset($this->migration_state[$depend]) || - !$this->migration_state[$depend]['migration_schema_done'] || - !$this->migration_state[$depend]['migration_data_done']) - { - return $this->try_apply($depend); - } - } - - $this->last_run_migration = array( - 'name' => $name, - 'class' => $migration, - 'state' => $state, - 'task' => '', - ); - - if (!isset($this->migration_state[$name])) - { - if ($state['migration_start_time'] == 0 && $migration->effectively_installed()) - { - $state = array( - 'migration_depends_on' => $migration->depends_on(), - 'migration_schema_done' => true, - 'migration_data_done' => true, - 'migration_data_state' => '', - 'migration_start_time' => 0, - 'migration_end_time' => 0, - ); - - $this->last_run_migration['effectively_installed'] = true; - - $this->output_handler->write(array('MIGRATION_EFFECTIVELY_INSTALLED', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); - } - else - { - $state['migration_start_time'] = time(); - } - } - - $this->set_migration_state($name, $state); - - 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_SCHEMA_RUNNING', $name), $verbosity); - - $this->last_run_migration['task'] = 'process_schema_step'; - - $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->update_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); - - if ($state['migration_schema_done']) - { - $this->output_handler->write(array('MIGRATION_SCHEMA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL); - } - else - { - $this->output_handler->write(array('MIGRATION_SCHEMA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE); - } - } - else if (!$state['migration_data_done']) - { - try - { - $verbosity = empty($state['migration_data_state']) ? - migrator_output_handler_interface::VERBOSITY_VERBOSE : migrator_output_handler_interface::VERBOSITY_DEBUG; - $this->output_handler->write(array('MIGRATION_DATA_RUNNING', $name), $verbosity); - - $this->last_run_migration['task'] = 'process_data_step'; - - $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); - - $result = $this->process_data_step($migration->update_data(), $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); - $state['migration_end_time'] = ($result === true) ? time() : 0; - - if ($state['migration_data_done']) - { - $this->output_handler->write(array('MIGRATION_DATA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL); - } - else - { - $this->output_handler->write(array('MIGRATION_DATA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE); - } - } - catch (\phpbb\db\migration\exception $e) - { - // Reset data state and revert the schema changes - $state['migration_data_state'] = ''; - $this->set_migration_state($name, $state); - - $this->revert_do($name); - - throw $e; - } - } - - $this->set_migration_state($name, $state); - - return true; - } - - /** - * Runs a single revert step from the last migration installed - * - * YOU MUST ADD/SET ALL MIGRATIONS THAT COULD BE DEPENDENT ON THE MIGRATION TO REVERT TO BEFORE CALLING THIS METHOD! - * The revert step can either be a schema or a (partial) data revert. To - * check if revert() needs to be called again use the migration_state() method. - * - * @param string $migration String migration name to revert (including any that depend on this migration) - */ - public function revert($migration) - { - $this->container->get('dispatcher')->disable(); - $this->revert_do($migration); - $this->container->get('dispatcher')->enable(); - } - - /** - * Effectively runs a single revert step from the last migration installed - * - * @param string $migration String migration name to revert (including any that depend on this migration) - * @return null - */ - protected function revert_do($migration) - { - if (!isset($this->migration_state[$migration])) - { - // Not installed - return; - } - - foreach ($this->migrations as $name) - { - $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; - } - } - - $this->try_revert($migration); - } - - /** - * Attempts to revert a step of the given migration or one of its dependencies - * - * @param string $name The class name of the migration - * @return bool Whether any update step was successfully run - */ - protected function try_revert($name) - { - if (!class_exists($name)) - { - return false; - } - - $migration = $this->get_migration($name); - - $state = $this->migration_state[$name]; - - $this->last_run_migration = array( - 'name' => $name, - 'class' => $migration, - 'task' => '', - ); - - 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; - - if (!$state['migration_schema_done']) - { - $sql = 'DELETE FROM ' . $this->migrations_table . " - WHERE migration_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - $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); - } - } - - return true; - } - - /** - * Process the data step of the migration - * - * @param array $steps The steps to run - * @param bool|string $state Current state of the migration - * @param bool $revert true to revert a data step - * @return bool|string migration state. True if completed, serialized array if not finished - * @throws \phpbb\db\migration\exception - */ - protected function process_data_step($steps, $state, $revert = false) - { - if (count($steps) === 0) - { - return true; - } - - $state = is_array($state) ? $state : false; - - // reverse order of steps if reverting - if ($revert === true) - { - $steps = array_reverse($steps); - } - - $step = $last_result = 0; - if ($state) - { - $step = $state['step']; - - // We send the result from last time to the callable function - $last_result = $state['result']; - } - - try - { - // 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 < count($steps)) - { - return array( - 'result' => $result, - // Move on if the last call finished - 'step' => ($result !== null && $result !== true) ? $step : $step + 1, - ); - } - } - catch (\phpbb\db\migration\exception $e) - { - // We should try rolling back here - foreach ($steps as $reverse_step_identifier => $reverse_step) - { - // If we've reached the current step we can break because we reversed everything that was run - if ($reverse_step_identifier == $step) - { - break; - } - - // Reverse the step that was run - $result = $this->run_step($reverse_step, false, !$revert); - } - - throw $e; - } - - return true; - } - - /** - * Run a single step - * - * An exception should be thrown if an error occurs - * - * @param mixed $step Data step from migration - * @param mixed $last_result Result to pass to the callable (only for 'custom' method) - * @param bool $reverse False to install, True to attempt uninstallation by reversing the call - * @return null - */ - protected function run_step($step, $last_result = 0, $reverse = false) - { - $callable_and_parameters = $this->get_callable_from_step($step, $last_result, $reverse); - - if ($callable_and_parameters === false) - { - return; - } - - $callable = $callable_and_parameters[0]; - $parameters = $callable_and_parameters[1]; - - return call_user_func_array($callable, $parameters); - } - - /** - * Get a callable statement from a data step - * - * @param array $step Data step from migration - * @param mixed $last_result Result to pass to the callable (only for 'custom' method) - * @param bool $reverse False to install, True to attempt uninstallation by reversing the call - * @return array Array with parameters for call_user_func_array(), 0 is the callable, 1 is parameters - * @throws \phpbb\db\migration\exception - */ - protected function get_callable_from_step(array $step, $last_result = 0, $reverse = false) - { - $type = $step[0]; - $parameters = $step[1]; - - $parts = explode('.', $type); - - $class = $parts[0]; - $method = false; - - if (isset($parts[1])) - { - $method = $parts[1]; - } - - switch ($class) - { - case 'if': - if (!isset($parameters[0])) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_MISSING_CONDITION', $step); - } - - if (!isset($parameters[1])) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_MISSING_STEP', $step); - } - - if ($reverse) - { - // We might get unexpected results when trying - // to revert this, so just avoid it - return false; - } - - $condition = $parameters[0]; - - if (!$condition || (is_array($condition) && !$this->run_step($condition, $last_result, $reverse))) - { - return false; - } - - $step = $parameters[1]; - - return $this->get_callable_from_step($step); - break; - - case 'custom': - if (!is_callable($parameters[0])) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_CUSTOM_NOT_CALLABLE', $step); - } - - if ($reverse) - { - return false; - } - else - { - return array( - $parameters[0], - array($last_result), - ); - } - break; - - default: - if (!$method) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNKNOWN_TYPE', $step); - } - - if (!isset($this->tools[$class])) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNDEFINED_TOOL', $step); - } - - if (!method_exists(get_class($this->tools[$class]), $method)) - { - throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_UNDEFINED_METHOD', $step); - } - - // Attempt to reverse operations - if ($reverse) - { - array_unshift($parameters, $method); - - return array( - array($this->tools[$class], 'reverse'), - $parameters, - ); - } - - return array( - array($this->tools[$class], $method), - $parameters, - ); - break; - } - } - - /** - * Insert/Update migration row into the database - * - * @param string $name Name of the migration - * @param array $state - * @return null - */ - protected function set_migration_state($name, $state) - { - $migration_row = $state; - $migration_row['migration_depends_on'] = serialize($state['migration_depends_on']); - $migration_row['migration_data_state'] = !empty($state['migration_data_state']) ? serialize($state['migration_data_state']) : ''; - - if (isset($this->migration_state[$name])) - { - $sql = 'UPDATE ' . $this->migrations_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $migration_row) . " - WHERE migration_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - } - else - { - $migration_row['migration_name'] = $name; - $sql = 'INSERT INTO ' . $this->migrations_table . ' - ' . $this->db->sql_build_array('INSERT', $migration_row); - $this->db->sql_query($sql); - } - - $this->migration_state[$name] = $state; - - $this->last_run_migration['state'] = $state; - } - - /** - * Checks if a migration's dependencies can even theoretically be satisfied. - * - * @param string $name The class name of the migration - * @return bool|string False if fulfillable, string of missing migration name if unfulfillable - */ - public function unfulfillable($name) - { - $name = $this->get_valid_name($name); - - if (isset($this->migration_state[$name]) || isset($this->fulfillable_migrations[$name])) - { - return false; - } - - if (!class_exists($name)) - { - return $name; - } - - $migration = $this->get_migration($name); - $depends = $migration->depends_on(); - - foreach ($depends as $depend) - { - $depend = $this->get_valid_name($depend); - $unfulfillable = $this->unfulfillable($depend); - if ($unfulfillable !== false) - { - return $unfulfillable; - } - } - $this->fulfillable_migrations[$name] = true; - - return false; - } - - /** - * Checks whether all available, fulfillable migrations have been applied. - * - * @return bool Whether the migrations have been applied - */ - public function finished() - { - foreach ($this->migrations as $name) - { - if (!isset($this->migration_state[$name])) - { - // skip unfulfillable migrations, but fulfillables mean we - // are not finished yet - if ($this->unfulfillable($name) !== false) - { - continue; - } - - return false; - } - - $migration = $this->migration_state[$name]; - - if (!$migration['migration_schema_done'] || !$migration['migration_data_done']) - { - return false; - } - } - - return true; - } - - /** - * Gets a migration state (whether it is installed and to what extent) - * - * @param string $migration String migration name to check if it is installed - * @return bool|array False if the migration has not at all been installed, array - */ - public function migration_state($migration) - { - if (!isset($this->migration_state[$migration])) - { - return false; - } - - return $this->migration_state[$migration]; - } - - /** - * Helper to get a migration - * - * @param string $name Name of the migration - * @return \phpbb\db\migration\migration - */ - protected function get_migration($name) - { - $migration = new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix); - - if ($migration instanceof ContainerAwareInterface) - { - $migration->setContainer($this->container); - } - - return $migration; - } - - /** - * This function adds all migrations sent to it to the migrations table - * - * THIS SHOULD NOT GENERALLY BE USED! THIS IS FOR THE PHPBB INSTALLER. - * THIS WILL THROW ERRORS IF MIGRATIONS ALREADY EXIST IN THE TABLE, DO NOT CALL MORE THAN ONCE! - * - * @param array $migrations Array of migrations (names) to add to the migrations table - * @return null - */ - public function populate_migrations($migrations) - { - foreach ($migrations as $name) - { - if ($this->migration_state($name) === false) - { - $state = array( - 'migration_depends_on' => $name::depends_on(), - 'migration_schema_done' => true, - 'migration_data_done' => true, - 'migration_data_state' => '', - 'migration_start_time' => time(), - 'migration_end_time' => time(), - ); - $this->set_migration_state($name, $state); - } - } - } - - /** - * Creates the migrations table if it does not exist. - * @return null - */ - public function create_migrations_table() - { - // Make sure migrations have been installed. - if (!$this->db_tools->sql_table_exists($this->table_prefix . 'migrations')) - { - $this->db_tools->sql_create_table($this->table_prefix . 'migrations', array( - 'COLUMNS' => array( - 'migration_name' => array('VCHAR', ''), - 'migration_depends_on' => array('TEXT', ''), - 'migration_schema_done' => array('BOOL', 0), - 'migration_data_done' => array('BOOL', 0), - 'migration_data_state' => array('TEXT', ''), - 'migration_start_time' => array('TIMESTAMP', 0), - 'migration_end_time' => array('TIMESTAMP', 0), - ), - 'PRIMARY_KEY' => 'migration_name', - )); - } - } - - /** - * 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/install/update/old/phpbb/db/tools/mssql.php b/install/update/old/phpbb/db/tools/mssql.php deleted file mode 100644 index cbedf9a..0000000 --- a/install/update/old/phpbb/db/tools/mssql.php +++ /dev/null @@ -1,880 +0,0 @@ - - * @license 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/install/update/old/phpbb/db/tools/postgres.php b/install/update/old/phpbb/db/tools/postgres.php deleted file mode 100644 index 077d6e0..0000000 --- a/install/update/old/phpbb/db/tools/postgres.php +++ /dev/null @@ -1,614 +0,0 @@ - - * @license 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/install/update/old/phpbb/db/tools/tools.php b/install/update/old/phpbb/db/tools/tools.php deleted file mode 100644 index d21d34b..0000000 --- a/install/update/old/phpbb/db/tools/tools.php +++ /dev/null @@ -1,1956 +0,0 @@ - -* @license 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)) - { - 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/install/update/old/phpbb/di/container_builder.php b/install/update/old/phpbb/di/container_builder.php deleted file mode 100644 index 8c1ce8b..0000000 --- a/install/update/old/phpbb/di/container_builder.php +++ /dev/null @@ -1,673 +0,0 @@ - -* @license 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 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\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 The environment to use. - */ - protected $environment; - - /** - * @var string phpBB Root Path - */ - protected $phpbb_root_path; - - /** - * @var string php file extension - */ - protected $php_ext; - - /** - * The container under construction - * - * @var ContainerBuilder - */ - protected $container; - - /** - * @var \phpbb\db\driver\driver_interface - */ - protected $dbal_connection = null; - - /** - * 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 - */ - protected $config_path = null; - - /** - * 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 if the container should be compiled automatically (default to true). - * - * @var bool - */ - protected $compile_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 = []; - - /** - * @var \phpbb\config_php_file - */ - protected $config_php_file; - - /** - * @var string - */ - protected $cache_dir; - - /** - * @var array - */ - private $container_extensions; - - /** @var \Exception */ - private $build_exception; - - /** - * 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->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 - */ - public function get_container() - { - try - { - $container_filename = $this->get_container_filename(); - $config_cache = new ConfigCache($container_filename, defined('DEBUG')); - if ($this->use_cache && $config_cache->isFresh()) - { - 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()); - } - - require($config_cache->getPath()); - $this->container = new \phpbb_cache_container(); - } - else - { - $this->container_extensions = array(new extension\core($this->get_config_path())); - - if ($this->use_extensions) - { - $this->load_extensions(); - } - - // 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')); - - // Event listeners "Symfony style" - $this->container->addCompilerPass(new RegisterListenersPass('dispatcher')); - - if ($this->use_extensions) - { - $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_dbal_driver(); - - return $this->container; - } - catch (\Exception $e) - { - // Don't try to recover if we are in the development environment - if ($this->get_environment() === 'development') - { - throw $e; - } - - 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 - { - // Rethrow the original exception if it's still failing - throw $this->build_exception; - } - } - } - - /** - * Enable the extensions. - * - * @param string $environment The environment to use - * @return $this - */ - public function with_environment($environment) - { - $this->environment = $environment; - - return $this; - } - - /** - * Enable the extensions. - * - * @return $this - */ - public function with_extensions() - { - $this->use_extensions = true; - - return $this; - } - - /** - * Disable the extensions. - * - * @return $this - */ - public function without_extensions() - { - $this->use_extensions = false; - - return $this; - } - - /** - * 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_cache = true; - - return $this; - } - - /** - * Disable the caching of the container. - * - * @return $this - */ - public function without_cache() - { - $this->use_cache = false; - - return $this; - } - - /** - * Set the cache directory. - * - * @param string $cache_dir The cache directory. - * @return $this - */ - public function with_cache_dir($cache_dir) - { - $this->cache_dir = $cache_dir; - - return $this; - } - - /** - * Enable the compilation of the container. - * - * @return $this - */ - public function with_compiled_container() - { - $this->compile_container = true; - - return $this; - } - - /** - * Disable the compilation of the container. - * - * @return $this - */ - public function without_compiled_container() - { - $this->compile_container = false; - - return $this; - } - - /** - * 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 - * @return $this - */ - public function with_custom_parameters($custom_parameters) - { - $this->custom_parameters = $custom_parameters; - - return $this; - } - - /** - * 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) - { - $this->config_php_file = $config_php_file; - - return $this; - } - - /** - * Returns the path to the container configuration (default: root_path/config) - * - * @return string - */ - protected function get_config_path() - { - return $this->config_path ?: $this->phpbb_root_path . 'config'; - } - - /** - * Returns the path to the cache directory (default: root_path/cache/environment). - * - * @return string Path to the cache directory. - */ - protected function get_cache_dir() - { - return $this->cache_dir ?: $this->phpbb_root_path . 'cache/' . $this->get_environment() . '/'; - } - - /** - * Load the enabled extensions. - */ - protected function load_extensions() - { - if ($this->config_php_file !== null) - { - // 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 = ' $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); - - 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; - } - } - - /** - * Dump the container to the disk. - * - * @param ConfigCache $cache The config cache - */ - protected function dump_container($cache) - { - try - { - $dumper = new PhpDumper($this->container); - $proxy_dumper = new ProxyDumper(); - $dumper->setProxyDumper($proxy_dumper); - - $cached_container_dump = $dumper->dump(array( - 'class' => 'phpbb_cache_container', - 'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder', - )); - - $cache->write($cached_container_dump, $this->container->getResources()); - } - catch (IOException $e) - { - // Don't fail if the cache isn't writeable - } - } - - /** - * Create the ContainerBuilder object - * - * @param array $extensions Array of Container extension objects - * @return ContainerBuilder object - */ - protected function create_container(array $extensions) - { - $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); - $extensions_alias[] = $extension->getAlias(); - } - - $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions_alias)); - - return $container; - } - - /** - * Inject the customs parameters into the container - */ - protected function inject_custom_parameters() - { - foreach ($this->custom_parameters as $key => $value) - { - $this->container->setParameter($key, $value); - } - } - - /** - * Inject the dbal connection driver into container - */ - protected function inject_dbal_driver() - { - if (empty($this->config_php_file)) - { - 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 - */ - protected function get_container_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() . '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/install/update/old/phpbb/di/extension/container_configuration.php b/install/update/old/phpbb/di/extension/container_configuration.php deleted file mode 100644 index 4585d65..0000000 --- a/install/update/old/phpbb/di/extension/container_configuration.php +++ /dev/null @@ -1,52 +0,0 @@ - -* @license 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/install/update/old/phpbb/di/extension/core.php b/install/update/old/phpbb/di/extension/core.php deleted file mode 100644 index 67150f0..0000000 --- a/install/update/old/phpbb/di/extension/core.php +++ /dev/null @@ -1,124 +0,0 @@ - -* @license 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\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 core extends Extension -{ - const TWIG_OPTIONS_POSITION = 7; - - /** - * Config path - * @var string - */ - protected $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 $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) - { - $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 - */ - public function getAlias() - { - return 'core'; - } -} diff --git a/install/update/old/phpbb/di/service_collection.php b/install/update/old/phpbb/di/service_collection.php deleted file mode 100644 index 8e9175e..0000000 --- a/install/update/old/phpbb/di/service_collection.php +++ /dev/null @@ -1,106 +0,0 @@ - -* @license 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 to be configured at container compile time. -*/ -class service_collection extends \ArrayObject -{ - /** - * @var \Symfony\Component\DependencyInjection\ContainerInterface - */ - protected $container; - - /** - * @var array - */ - protected $service_classes; - - /** - * Constructor - * - * @param ContainerInterface $container Container object - */ - public function __construct(ContainerInterface $container) - { - $this->container = $container; - $this->service_classes = array(); - } - - /** - * {@inheritdoc} - */ - public function getIterator() - { - return new service_collection_iterator($this); - } - - // Because of a PHP issue we have to redefine offsetExists - // (even with a call to the parent): - // https://bugs.php.net/bug.php?id=66834 - // https://bugs.php.net/bug.php?id=67067 - // But it triggers a sniffer issue that we have to skip - // @codingStandardsIgnoreStart - /** - * {@inheritdoc} - */ - public function offsetExists($index) - { - return parent::offsetExists($index); - } - // @codingStandardsIgnoreEnd - - /** - * {@inheritdoc} - */ - public function offsetGet($index) - { - return $this->container->get($index); - } - - /** - * Add a service to the collection - * - * @param string $name The service name - * @return null - */ - public function add($name) - { - $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/install/update/old/phpbb/event/md_exporter.php b/install/update/old/phpbb/event/md_exporter.php deleted file mode 100644 index c3942bd..0000000 --- a/install/update/old/phpbb/event/md_exporter.php +++ /dev/null @@ -1,561 +0,0 @@ - -* @license 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; - -/** -* Crawls through a markdown file and grabs all events -*/ -class md_exporter -{ - /** @var string Path where we look for files*/ - protected $path; - - /** @var string phpBB Root Path */ - protected $root_path; - - /** @var string The minimum version for the events to return */ - protected $min_version; - - /** @var string The maximum version for the events to return */ - protected $max_version; - - /** @var string */ - protected $filter; - - /** @var string */ - protected $current_event; - - /** @var array */ - protected $events; - - /** - * @param string $phpbb_root_path - * @param mixed $extension String 'vendor/ext' to filter, null for phpBB core - * @param string $min_version - * @param string $max_version - */ - public function __construct($phpbb_root_path, $extension = null, $min_version = null, $max_version = null) - { - $this->root_path = $phpbb_root_path; - $this->path = $this->root_path; - if ($extension) - { - $this->path .= 'ext/' . $extension . '/'; - } - - $this->events = array(); - $this->events_by_file = array(); - $this->filter = $this->current_event = ''; - $this->min_version = $min_version; - $this->max_version = $max_version; - } - - /** - * Get the list of all events - * - * @return array Array with events: name => details - */ - public function get_events() - { - return $this->events; - } - - /** - * @param string $md_file Relative from phpBB root - * @return int Number of events found - * @throws \LogicException - */ - public function crawl_phpbb_directory_adm($md_file) - { - $this->crawl_eventsmd($md_file, 'adm'); - - $file_list = $this->get_recursive_file_list($this->path . 'adm/style/'); - foreach ($file_list as $file) - { - $file_name = 'adm/style/' . $file; - $this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name)); - } - - return count($this->events); - } - - /** - * @param string $md_file Relative from phpBB root - * @return int Number of events found - * @throws \LogicException - */ - public function crawl_phpbb_directory_styles($md_file) - { - $this->crawl_eventsmd($md_file, 'styles'); - - $styles = array('prosilver'); - foreach ($styles as $style) - { - $file_list = $this->get_recursive_file_list( - $this->path . 'styles/' . $style . '/template/' - ); - - foreach ($file_list as $file) - { - $file_name = 'styles/' . $style . '/template/' . $file; - $this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name)); - } - } - - return count($this->events); - } - - /** - * @param string $md_file Relative from phpBB root - * @param string $filter Should be 'styles' or 'adm' - * @return int Number of events found - * @throws \LogicException - */ - public function crawl_eventsmd($md_file, $filter) - { - if (!file_exists($this->path . $md_file)) - { - throw new \LogicException("The event docs file '{$md_file}' could not be found"); - } - - $file_content = file_get_contents($this->path . $md_file); - $this->filter = $filter; - - $events = explode("\n\n", $file_content); - foreach ($events as $event) - { - // Last row of the file - if (strpos($event, "\n===\n") === false) - { - continue; - } - - 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])) - { - 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)) - { - continue; - } - - list($file_details, $details) = explode("\n* Since: ", $details, 2); - - $changed_versions = array(); - if (strpos($details, "\n* Changed: ") !== false) - { - list($since, $details) = explode("\n* Changed: ", $details, 2); - while (strpos($details, "\n* Changed: ") !== false) - { - list($changed, $details) = explode("\n* Changed: ", $details, 2); - $changed_versions[] = $changed; - } - list($changed, $description) = explode("\n* Purpose: ", $details, 2); - $changed_versions[] = $changed; - } - else - { - list($since, $description) = explode("\n* Purpose: ", $details, 2); - $changed_versions = array(); - } - - $files = $this->validate_file_list($file_details); - $since = $this->validate_since($since); - $changes = array(); - foreach ($changed_versions as $changed) - { - list($changed_version, $changed_description) = $this->validate_changed($changed); - - if (isset($changes[$changed_version])) - { - throw new \LogicException("Duplicate change information found for event '{$this->current_event}'"); - } - - $changes[$changed_version] = $changed_description; - } - $description = trim($description, "\n") . "\n"; - - if (!$this->version_is_filtered($since)) - { - $is_filtered = false; - foreach ($changes as $version => $null) - { - if ($this->version_is_filtered($version)) - { - $is_filtered = true; - break; - } - } - - if (!$is_filtered) - { - continue; - } - } - - $this->events[$event_name] = array( - 'event' => $this->current_event, - 'files' => $files, - 'since' => $since, - 'changed' => $changes, - 'description' => $description, - ); - } - - return count($this->events); - } - - /** - * The version to check - * - * @param string $version - * @return bool - */ - protected function version_is_filtered($version) - { - return (!$this->min_version || phpbb_version_compare($this->min_version, $version, '<=')) - && (!$this->max_version || phpbb_version_compare($this->max_version, $version, '>=')); - } - - /** - * Format the php events as a wiki table - * - * @param string $action - * @return string Number of events found - */ - public function export_events_for_wiki($action = '') - { - if ($this->filter === 'adm') - { - if ($action === 'diff') - { - $wiki_page = '=== ACP Template Events ===' . "\n"; - } - else - { - $wiki_page = '= ACP Template Events =' . "\n"; - } - $wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n"; - $wiki_page .= '! Identifier !! Placement !! Added in Release !! Explanation' . "\n"; - } - else - { - if ($action === 'diff') - { - $wiki_page = '=== Template Events ===' . "\n"; - } - else - { - $wiki_page = '= Template Events =' . "\n"; - } - $wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n"; - $wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Added in Release !! Explanation' . "\n"; - } - - foreach ($this->events as $event_name => $event) - { - $wiki_page .= "|- id=\"{$event_name}\"\n"; - $wiki_page .= "| [[#{$event_name}|{$event_name}]] || "; - - if ($this->filter === 'adm') - { - $wiki_page .= implode(', ', $event['files']['adm']); - } - else - { - $wiki_page .= implode(', ', $event['files']['prosilver']); - } - - $wiki_page .= " || {$event['since']} || " . str_replace("\n", ' ', $event['description']) . "\n"; - } - $wiki_page .= '|}' . "\n"; - - return $wiki_page; - } - - /** - * Validates a template event name - * - * @param $event_name - * @return null - * @throws \LogicException - */ - public function validate_event_name($event_name) - { - if (!preg_match('#^([a-z][a-z0-9]*(?:_[a-z][a-z0-9]*)+)$#', $event_name)) - { - throw new \LogicException("Invalid event name '{$event_name}'"); - } - } - - /** - * Validate "Since" Information - * - * @param string $since - * @return string - * @throws \LogicException - */ - public function validate_since($since) - { - if (!$this->validate_version($since)) - { - throw new \LogicException("Invalid since information found for event '{$this->current_event}'"); - } - - return $since; - } - - /** - * Validate "Changed" Information - * - * @param string $changed - * @return string - * @throws \LogicException - */ - public function validate_changed($changed) - { - if (strpos($changed, ' ') !== false) - { - list($version, $description) = explode(' ', $changed, 2); - } - else - { - $version = $changed; - $description = ''; - } - - if (!$this->validate_version($version)) - { - throw new \LogicException("Invalid changed information found for event '{$this->current_event}'"); - } - - return array($version, $description); - } - - /** - * Validate "version" Information - * - * @param string $version - * @return bool True if valid, false otherwise - */ - public function validate_version($version) - { - return preg_match('#^\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?$#', $version); - } - - /** - * Validate the files list - * - * @param string $file_details - * @return array - * @throws \LogicException - */ - public function validate_file_list($file_details) - { - $files_list = array( - 'prosilver' => array(), - 'adm' => array(), - ); - - // Multi file list - if (strpos($file_details, "* Locations:\n + ") === 0) - { - $file_details = substr($file_details, strlen("* Locations:\n + ")); - $files = explode("\n + ", $file_details); - foreach ($files as $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); - } - - 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, '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); - } - - $this->events_by_file[$file][] = $this->current_event; - } - } - else if ($this->filter == 'adm') - { - $file = substr($file_details, strlen('* Location: ')); - if (!file_exists($this->path . $file) || substr($file, -5) !== '.html') - { - throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 1); - } - - $files_list['adm'][] = substr($file, strlen('adm/style/')); - - $this->events_by_file[$file][] = $this->current_event; - } - else - { - throw new \LogicException("Invalid file list found for event '{$this->current_event}'", 2); - } - - return $files_list; - } - - /** - * Get all template events in a template file - * - * @param string $file - * @return array - * @throws \LogicException - */ - public function crawl_file_for_events($file) - { - if (!file_exists($this->path . $file)) - { - throw new \LogicException("File '{$file}' does not exist", 1); - } - - $event_list = array(); - $file_content = file_get_contents($this->path . $file); - - preg_match_all('/(?:{%|)/U', $file_content, $event_list); - - return $event_list[1]; - } - - /** - * Validates whether all events from $file are in the md file and vice-versa - * - * @param string $file - * @param array $events - * @return true - * @throws \LogicException - */ - public function validate_events_from_file($file, array $events) - { - if (empty($this->events_by_file[$file]) && empty($events)) - { - return true; - } - else if (empty($this->events_by_file[$file])) - { - $event_list = implode("', '", $events); - throw new \LogicException("File '{$file}' should not contain events, but contains: " - . "'{$event_list}'", 1); - } - else if (empty($events)) - { - $event_list = implode("', '", $this->events_by_file[$file]); - throw new \LogicException("File '{$file}' contains no events, but should contain: " - . "'{$event_list}'", 1); - } - - $missing_events_from_file = array(); - foreach ($this->events_by_file[$file] as $event) - { - if (!in_array($event, $events)) - { - $missing_events_from_file[] = $event; - } - } - - if (!empty($missing_events_from_file)) - { - $event_list = implode("', '", $missing_events_from_file); - throw new \LogicException("File '{$file}' does not contain events: '{$event_list}'", 2); - } - - $missing_events_from_md = array(); - foreach ($events as $event) - { - if (!in_array($event, $this->events_by_file[$file])) - { - $missing_events_from_md[] = $event; - } - } - - if (!empty($missing_events_from_md)) - { - $event_list = implode("', '", $missing_events_from_md); - throw new \LogicException("File '{$file}' contains additional events: '{$event_list}'", 3); - } - - return true; - } - - /** - * Returns a list of files in $dir - * - * Works recursive with any depth - * - * @param string $dir Directory to go through - * @return array List of files (including directories) - */ - public function get_recursive_file_list($dir) - { - try - { - $iterator = new \RecursiveIteratorIterator( - new \phpbb\recursive_dot_prefix_filter_iterator( - new \RecursiveDirectoryIterator( - $dir, - \FilesystemIterator::SKIP_DOTS - ) - ), - \RecursiveIteratorIterator::SELF_FIRST - ); - } - catch (\Exception $e) - { - return array(); - } - - $files = array(); - foreach ($iterator as $file_info) - { - /** @var \RecursiveDirectoryIterator $file_info */ - if ($file_info->isDir()) - { - continue; - } - - $relative_path = $iterator->getInnerIterator()->getSubPathname(); - - if (substr($relative_path, -5) == '.html') - { - $files[] = str_replace(DIRECTORY_SEPARATOR, '/', $relative_path); - } - } - - return $files; - } -} diff --git a/install/update/old/phpbb/extension/extension_interface.php b/install/update/old/phpbb/extension/extension_interface.php deleted file mode 100644 index 6a6b6ad..0000000 --- a/install/update/old/phpbb/extension/extension_interface.php +++ /dev/null @@ -1,70 +0,0 @@ - -* @license 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; - -/** -* The interface extension meta classes have to implement to run custom code -* on enable/disable/purge. -*/ -interface extension_interface -{ - /** - * Indicate whether or not the extension can be enabled. - * - * @return bool - */ - public function is_enableable(); - - /** - * enable_step is executed on enabling an extension until it returns false. - * - * Calls to this function can be made in subsequent requests, when the - * function is invoked through a webserver with a too low max_execution_time. - * - * @param mixed $old_state The return value of the previous call - * of this method, or false on the first call - * @return mixed Returns false after last step, otherwise - * temporary state which is passed as an - * argument to the next step - */ - public function enable_step($old_state); - - /** - * Disables the extension. - * - * Calls to this function can be made in subsequent requests, when the - * function is invoked through a webserver with a too low max_execution_time. - * - * @param mixed $old_state The return value of the previous call - * of this method, or false on the first call - * @return mixed Returns false after last step, otherwise - * temporary state which is passed as an - * argument to the next step - */ - public function disable_step($old_state); - - /** - * purge_step is executed on purging an extension until it returns false. - * - * Calls to this function can be made in subsequent requests, when the - * function is invoked through a webserver with a too low max_execution_time. - * - * @param mixed $old_state The return value of the previous call - * of this method, or false on the first call - * @return mixed Returns false after last step, otherwise - * temporary state which is passed as an - * argument to the next step - */ - public function purge_step($old_state); -} diff --git a/install/update/old/phpbb/extension/manager.php b/install/update/old/phpbb/extension/manager.php deleted file mode 100644 index 4b4109b..0000000 --- a/install/update/old/phpbb/extension/manager.php +++ /dev/null @@ -1,633 +0,0 @@ - -* @license 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; - -use phpbb\exception\runtime_exception; -use phpbb\file_downloader; -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** -* The extension manager provides means to activate/deactivate extensions. -*/ -class manager -{ - /** @var ContainerInterface */ - protected $container; - - protected $db; - protected $config; - protected $cache; - protected $php_ext; - protected $extensions; - protected $extension_table; - protected $phpbb_root_path; - protected $cache_name; - - /** - * Creates a manager and loads information from database - * - * @param 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_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\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_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; - $this->config = $config; - $this->container = $container; - $this->db = $db; - $this->extension_table = $extension_table; - $this->filesystem = $filesystem; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false; - - if ($this->extensions === false) - { - $this->load_extensions(); - } - } - - /** - * Loads all extension information from the database - * - * @return null - */ - public function load_extensions() - { - $this->extensions = array(); - - // Do not try to load any extensions if the extension table - // does not exist or when installing or updating. - // Note: database updater invokes this code, and in 3.0 - // there is no extension table therefore the rest of this function - // fails - if (defined('IN_INSTALL') || version_compare($this->config['version'], '3.1.0-dev', '<')) - { - return; - } - - $sql = 'SELECT * - FROM ' . $this->extension_table; - - $result = $this->db->sql_query($sql); - $extensions = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - foreach ($extensions as $extension) - { - $extension['ext_path'] = $this->get_extension_path($extension['ext_name']); - $this->extensions[$extension['ext_name']] = $extension; - } - - ksort($this->extensions); - - if ($this->cache) - { - $this->cache->put($this->cache_name, $this->extensions); - } - } - - /** - * Generates the path to an extension - * - * @param string $name The name of the extension - * @param bool $phpbb_relative Whether the path should be relative to phpbb root - * @return string Path to an extension - */ - public function get_extension_path($name, $phpbb_relative = false) - { - $name = str_replace('.', '', $name); - - return (($phpbb_relative) ? $this->phpbb_root_path : '') . 'ext/' . $name . '/'; - } - - /** - * Instantiates the extension meta class for the extension with the given name - * - * @param string $name The extension name - * @return \phpbb\extension\extension_interface Instance of the extension meta class or - * \phpbb\extension\base if the class does not exist - */ - public function get_extension($name) - { - $extension_class_name = str_replace('/', '\\', $name) . '\\ext'; - - $migrator = $this->container->get('migrator'); - - if (class_exists($extension_class_name)) - { - return new $extension_class_name($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true)); - } - else - { - return new \phpbb\extension\base($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true)); - } - } - - /** - * Instantiates the metadata manager for the extension with the given name - * - * @param string $name The extension name - * @return \phpbb\extension\metadata_manager Instance of the metadata manager - */ - public function create_extension_metadata_manager($name) - { - 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']; - } - - /** - * Runs a step of the extension enabling process. - * - * Allows the exentension to enable in a long running script that works - * in multiple steps across requests. State is kept for the extension - * in the extensions table. - * - * @param string $name The extension's name - * @return bool False if enabling is finished, true otherwise - */ - public function enable_step($name) - { - // ignore extensions that are already enabled - if ($this->is_enabled($name)) - { - return false; - } - - $old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false; - - $extension = $this->get_extension($name); - - if (!$extension->is_enableable()) - { - return false; - } - - $state = $extension->enable_step($old_state); - - $active = ($state === false); - - $extension_data = array( - 'ext_name' => $name, - 'ext_active' => $active, - 'ext_state' => serialize($state), - ); - - $this->extensions[$name] = $extension_data; - $this->extensions[$name]['ext_path'] = $this->get_extension_path($extension_data['ext_name']); - ksort($this->extensions); - - $sql = 'SELECT COUNT(ext_name) as row_count - FROM ' . $this->extension_table . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $result = $this->db->sql_query($sql); - $count = $this->db->sql_fetchfield('row_count'); - $this->db->sql_freeresult($result); - - if ($count) - { - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - } - else - { - $sql = 'INSERT INTO ' . $this->extension_table . ' - ' . $this->db->sql_build_array('INSERT', $extension_data); - $this->db->sql_query($sql); - } - - if ($this->cache) - { - $this->cache->purge(); - } - - if ($active) - { - $this->config->increment('assets_version', 1); - } - - return !$active; - } - - /** - * Enables an extension - * - * This method completely enables an extension. But it could be long running - * so never call this in a script that has a max_execution time. - * - * @param string $name The extension's name - * @return null - */ - public function enable($name) - { - // @codingStandardsIgnoreStart - while ($this->enable_step($name)); - // @codingStandardsIgnoreEnd - } - - /** - * Disables an extension - * - * Calls the disable method on the extension's meta class to allow it to - * process the event. - * - * @param string $name The extension's name - * @return bool False if disabling is finished, true otherwise - */ - public function disable_step($name) - { - // ignore extensions that are not enabled - if (!$this->is_enabled($name)) - { - return false; - } - - $old_state = unserialize($this->extensions[$name]['ext_state']); - - $extension = $this->get_extension($name); - $state = $extension->disable_step($old_state); - - // continue until the state is false - if ($state !== false) - { - $extension_data = array( - 'ext_state' => serialize($state), - ); - $this->extensions[$name]['ext_state'] = serialize($state); - - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - if ($this->cache) - { - $this->cache->purge(); - } - - return true; - } - - $extension_data = array( - 'ext_active' => false, - 'ext_state' => serialize(false), - ); - $this->extensions[$name]['ext_active'] = false; - $this->extensions[$name]['ext_state'] = serialize(false); - - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - if ($this->cache) - { - $this->cache->purge(); - } - - return false; - } - - /** - * Disables an extension - * - * Disables an extension completely at once. This process could run for a - * while so never call this in a script that has a max_execution time. - * - * @param string $name The extension's name - * @return null - */ - public function disable($name) - { - // @codingStandardsIgnoreStart - while ($this->disable_step($name)); - // @codingStandardsIgnoreEnd - } - - /** - * Purge an extension - * - * Disables the extension first if active, and then calls purge on the - * extension's meta class to delete the extension's database content. - * - * @param string $name The extension's name - * @return bool False if purging is finished, true otherwise - */ - public function purge_step($name) - { - // ignore extensions that are not configured - if (!$this->is_configured($name)) - { - return false; - } - - // disable first if necessary - if ($this->extensions[$name]['ext_active']) - { - $this->disable($name); - } - - $old_state = unserialize($this->extensions[$name]['ext_state']); - - $extension = $this->get_extension($name); - $state = $extension->purge_step($old_state); - - // continue until the state is false - if ($state !== false) - { - $extension_data = array( - 'ext_state' => serialize($state), - ); - $this->extensions[$name]['ext_state'] = serialize($state); - - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - if ($this->cache) - { - $this->cache->purge(); - } - - return true; - } - - unset($this->extensions[$name]); - - $sql = 'DELETE FROM ' . $this->extension_table . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - if ($this->cache) - { - $this->cache->purge(); - } - - return false; - } - - /** - * Purge an extension - * - * Purges an extension completely at once. This process could run for a while - * so never call this in a script that has a max_execution time. - * - * @param string $name The extension's name - * @return null - */ - public function purge($name) - { - // @codingStandardsIgnoreStart - while ($this->purge_step($name)); - // @codingStandardsIgnoreEnd - } - - /** - * Retrieves a list of all available extensions on the filesystem - * - * @return array An array with extension names as keys and paths to the - * extension as values - */ - public function all_available() - { - $available = array(); - if (!is_dir($this->phpbb_root_path . 'ext/')) - { - return $available; - } - - $iterator = new \RecursiveIteratorIterator( - new \phpbb\recursive_dot_prefix_filter_iterator( - new \RecursiveDirectoryIterator($this->phpbb_root_path . 'ext/', \FilesystemIterator::NEW_CURRENT_AND_KEY | \FilesystemIterator::FOLLOW_SYMLINKS) - ), - \RecursiveIteratorIterator::SELF_FIRST - ); - $iterator->setMaxDepth(2); - - foreach ($iterator as $file_info) - { - if ($file_info->isFile() && $file_info->getFilename() == 'composer.json') - { - $ext_name = $iterator->getInnerIterator()->getSubPath(); - $ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name); - if ($this->is_available($ext_name)) - { - $available[$ext_name] = $this->get_extension_path($ext_name, true); - } - } - } - ksort($available); - return $available; - } - - /** - * Retrieves all configured extensions. - * - * All enabled and disabled extensions are considered configured. A purged - * extension that is no longer in the database is not configured. - * - * @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($phpbb_relative = true) - { - $configured = array(); - foreach ($this->extensions as $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($phpbb_relative = true) - { - $enabled = array(); - foreach ($this->extensions as $name => $data) - { - if ($this->is_enabled($name)) - { - $enabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path']; - } - } - return $enabled; - } - - /** - * 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($phpbb_relative = true) - { - $disabled = array(); - foreach ($this->extensions as $name => $data) - { - if ($this->is_disabled($name)) - { - $disabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path']; - } - } - return $disabled; - } - - /** - * Check to see if a given extension is available on the filesystem - * - * @param string $name Extension name to check NOTE: Can be user input - * @return bool Depending on whether or not the extension is available - */ - public function is_available($name) - { - $md_manager = $this->create_extension_metadata_manager($name); - try - { - return $md_manager->get_metadata('all') && $md_manager->validate_enable(); - } - catch (\phpbb\extension\exception $e) - { - return false; - } - } - - /** - * Check to see if a given extension is enabled - * - * @param string $name Extension name to check - * @return bool Depending on whether or not the extension is enabled - */ - public function is_enabled($name) - { - return isset($this->extensions[$name]['ext_active']) && $this->extensions[$name]['ext_active']; - } - - /** - * Check to see if a given extension is disabled - * - * @param string $name Extension name to check - * @return bool Depending on whether or not the extension is disabled - */ - public function is_disabled($name) - { - return isset($this->extensions[$name]['ext_active']) && !$this->extensions[$name]['ext_active']; - } - - /** - * Check to see if a given extension is configured - * - * All enabled and disabled extensions are considered configured. A purged - * extension that is no longer in the database is not configured. - * - * @param string $name Extension name to check - * @return bool Depending on whether or not the extension is configured - */ - public function is_configured($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); - } - - /** - * Check to see if a given extension is purged - * - * An extension is purged if it is available, not enabled and not disabled. - * - * @param string $name Extension name to check - * @return bool Depending on whether or not the extension is purged - */ - public function is_purged($name) - { - return $this->is_available($name) && !$this->is_configured($name); - } - - /** - * Instantiates a \phpbb\finder. - * - * @param bool $use_all_available Should we load all extensions, or just enabled ones - * @return \phpbb\finder An extension finder instance - */ - public function get_finder($use_all_available = false) - { - $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder'); - if ($use_all_available) - { - $finder->set_extensions(array_keys($this->all_available())); - } - else - { - $finder->set_extensions(array_keys($this->all_enabled())); - } - return $finder; - } -} diff --git a/install/update/old/phpbb/feed/controller/feed.php b/install/update/old/phpbb/feed/controller/feed.php deleted file mode 100644 index c0d7bc7..0000000 --- a/install/update/old/phpbb/feed/controller/feed.php +++ /dev/null @@ -1,411 +0,0 @@ - -* @license 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/install/update/old/phpbb/feed/topics_active.php b/install/update/old/phpbb/feed/topics_active.php deleted file mode 100644 index ea9ee97..0000000 --- a/install/update/old/phpbb/feed/topics_active.php +++ /dev/null @@ -1,147 +0,0 @@ - - * @license 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 topic_base -{ - protected $sort_days = 7; - - /** - * {@inheritdoc} - */ - public function set_keys() - { - parent::set_keys(); - - $this->set('author_id', 'topic_last_poster_id'); - $this->set('creator', 'topic_last_poster_name'); - } - - /** - * {@inheritdoc} - */ - protected function get_sql() - { - $forum_ids_read = $this->get_readable_forums(); - if (empty($forum_ids_read)) - { - return false; - } - - $in_fid_ary = array_intersect($forum_ids_read, $this->get_forum_ids()); - $in_fid_ary = array_diff($in_fid_ary, $this->get_passworded_forums()); - if (empty($in_fid_ary)) - { - return false; - } - - // Search for topics in last X days - $last_post_time_sql = ($this->sort_days) ? ' AND topic_last_post_time > ' . (time() - ($this->sort_days * 24 * 3600)) : ''; - - // We really have to get the post ids first! - $sql = 'SELECT topic_last_post_id, topic_last_post_time - FROM ' . TOPICS_TABLE . ' - WHERE topic_moved_id = 0 - AND ' . $this->content_visibility->get_forums_visibility_sql('topic', $in_fid_ary) . ' - ' . $last_post_time_sql . ' - ORDER BY topic_last_post_time DESC, topic_last_post_id DESC'; - $result = $this->db->sql_query_limit($sql, $this->num_items); - - $post_ids = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $post_ids[] = (int) $row['topic_last_post_id']; - } - $this->db->sql_freeresult($result); - - if (empty($post_ids)) - { - return false; - } - - parent::fetch_attachments($post_ids); - - $this->sql = array( - 'SELECT' => 'f.forum_id, f.forum_name, - t.topic_id, t.topic_title, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_views, - t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_post_time, - p.post_id, p.post_time, p.post_edit_time, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, t.topic_visibility', - 'FROM' => array( - TOPICS_TABLE => 't', - POSTS_TABLE => 'p', - ), - 'LEFT_JOIN' => array( - array( - 'FROM' => array(FORUMS_TABLE => 'f'), - 'ON' => 'p.forum_id = f.forum_id', - ), - ), - 'WHERE' => 'p.topic_id = t.topic_id - AND ' . $this->db->sql_in_set('p.post_id', $post_ids), - 'ORDER_BY' => 'p.post_time DESC, p.post_id DESC', - ); - - return true; - } - - /** - * Returns the ids of the forums not excluded from the active list - * - * @return int[] - */ - private function get_forum_ids() - { - static $forum_ids; - - $cache_name = 'feed_topic_active_forum_ids'; - - if (!isset($forum_ids) && ($forum_ids = $this->cache->get('_' . $cache_name)) === false) - { - $sql = 'SELECT forum_id - 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', round(log(FORUM_FLAG_ACTIVE_TOPICS, 2)), '<> 0'); - $result = $this->db->sql_query($sql); - - $forum_ids = array(); - while ($forum_id = (int) $this->db->sql_fetchfield('forum_id')) - { - $forum_ids[$forum_id] = $forum_id; - } - $this->db->sql_freeresult($result); - - $this->cache->put('_' . $cache_name, $forum_ids, 180); - } - - return $forum_ids; - } - - /** - * {@inheritdoc} - */ - public function adjust_item(&$item_row, &$row) - { - parent::adjust_item($item_row, $row); - - $item_row['title'] = (isset($row['forum_name']) && $row['forum_name'] !== '') ? $row['forum_name'] . ' ' . $this->separator . ' ' . $item_row['title'] : $item_row['title']; - } -} diff --git a/install/update/old/phpbb/files/filespec.php b/install/update/old/phpbb/files/filespec.php deleted file mode 100644 index 6847bca..0000000 --- a/install/update/old/phpbb/files/filespec.php +++ /dev/null @@ -1,584 +0,0 @@ - - * @license 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/install/update/old/phpbb/filesystem.php b/install/update/old/phpbb/filesystem.php deleted file mode 100644 index af56d78..0000000 --- a/install/update/old/phpbb/filesystem.php +++ /dev/null @@ -1,21 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** - * @deprecated 3.2.0-dev (To be removed 3.3.0) use \phpbb\filesystem\filesystem instead - */ -class filesystem extends \phpbb\filesystem\filesystem -{ -} diff --git a/install/update/old/phpbb/filesystem/filesystem.php b/install/update/old/phpbb/filesystem/filesystem.php deleted file mode 100644 index bfafdf5..0000000 --- a/install/update/old/phpbb/filesystem/filesystem.php +++ /dev/null @@ -1,916 +0,0 @@ - - * @license 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/install/update/old/phpbb/filesystem/filesystem_interface.php b/install/update/old/phpbb/filesystem/filesystem_interface.php deleted file mode 100644 index 1093be2..0000000 --- a/install/update/old/phpbb/filesystem/filesystem_interface.php +++ /dev/null @@ -1,284 +0,0 @@ - - * @license 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/install/update/old/phpbb/finder.php b/install/update/old/phpbb/finder.php deleted file mode 100644 index 1f1d931..0000000 --- a/install/update/old/phpbb/finder.php +++ /dev/null @@ -1,547 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* The finder provides a simple way to locate files in the core and a set of extensions -*/ -class finder -{ - protected $extensions; - protected $filesystem; - protected $phpbb_root_path; - protected $cache; - protected $php_ext; - - /** - * The cache variable name used to store $this->cached_queries in $this->cache. - * - * Allows the use of multiple differently configured finders with the same cache. - * @var string - */ - protected $cache_name; - - /** - * An associative array, containing all search parameters set in methods. - * @var array - */ - protected $query; - - /** - * A map from md5 hashes of serialized queries to their previously retrieved - * results. - * @var array - */ - protected $cached_queries; - - /** - * Creates a new finder instance with its dependencies - * - * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem instance - * @param string $phpbb_root_path Path to the phpbb root directory - * @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_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; - $this->cache = $cache; - $this->php_ext = $php_ext; - $this->cache_name = $cache_name; - - $this->query = array( - 'core_path' => false, - 'core_suffix' => false, - 'core_prefix' => false, - 'core_directory' => false, - 'extension_suffix' => false, - 'extension_prefix' => false, - 'extension_directory' => false, - ); - $this->extensions = array(); - - $this->cached_queries = ($this->cache) ? $this->cache->get($this->cache_name) : false; - } - - /** - * Set the array of extensions - * - * @param array $extensions A list of extensions that should be searched aswell - * @param bool $replace_list Should the list be emptied before adding the extensions - * @return \phpbb\finder This object for chaining calls - */ - public function set_extensions(array $extensions, $replace_list = true) - { - if ($replace_list) - { - $this->extensions = array(); - } - - foreach ($extensions as $ext_name) - { - $this->extensions[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; - } - return $this; - } - - /** - * Sets a core path to be searched in addition to extensions - * - * @param string $core_path The path relative to phpbb_root_path - * @return \phpbb\finder This object for chaining calls - */ - public function core_path($core_path) - { - $this->query['core_path'] = $core_path; - return $this; - } - - /** - * Sets the suffix all files found in extensions and core must match. - * - * There is no default file extension, so to find PHP files only, you will - * have to specify .php as a suffix. However when using get_classes, the .php - * file extension is automatically added to suffixes. - * - * @param string $suffix A filename suffix - * @return \phpbb\finder This object for chaining calls - */ - public function suffix($suffix) - { - $this->core_suffix($suffix); - $this->extension_suffix($suffix); - return $this; - } - - /** - * Sets a suffix all files found in extensions must match - * - * There is no default file extension, so to find PHP files only, you will - * have to specify .php as a suffix. However when using get_classes, the .php - * file extension is automatically added to suffixes. - * - * @param string $extension_suffix A filename suffix - * @return \phpbb\finder This object for chaining calls - */ - public function extension_suffix($extension_suffix) - { - $this->query['extension_suffix'] = $extension_suffix; - return $this; - } - - /** - * Sets a suffix all files found in the core path must match - * - * There is no default file extension, so to find PHP files only, you will - * have to specify .php as a suffix. However when using get_classes, the .php - * file extension is automatically added to suffixes. - * - * @param string $core_suffix A filename suffix - * @return \phpbb\finder This object for chaining calls - */ - public function core_suffix($core_suffix) - { - $this->query['core_suffix'] = $core_suffix; - return $this; - } - - /** - * Sets the prefix all files found in extensions and core must match - * - * @param string $prefix A filename prefix - * @return \phpbb\finder This object for chaining calls - */ - public function prefix($prefix) - { - $this->core_prefix($prefix); - $this->extension_prefix($prefix); - return $this; - } - - /** - * Sets a prefix all files found in extensions must match - * - * @param string $extension_prefix A filename prefix - * @return \phpbb\finder This object for chaining calls - */ - public function extension_prefix($extension_prefix) - { - $this->query['extension_prefix'] = $extension_prefix; - return $this; - } - - /** - * Sets a prefix all files found in the core path must match - * - * @param string $core_prefix A filename prefix - * @return \phpbb\finder This object for chaining calls - */ - public function core_prefix($core_prefix) - { - $this->query['core_prefix'] = $core_prefix; - return $this; - } - - /** - * Sets a directory all files found in extensions and core must be contained in - * - * Automatically sets the core_directory if its value does not differ from - * the current directory. - * - * @param string $directory - * @return \phpbb\finder This object for chaining calls - */ - public function directory($directory) - { - $this->core_directory($directory); - $this->extension_directory($directory); - return $this; - } - - /** - * Sets a directory all files found in extensions must be contained in - * - * @param string $extension_directory - * @return \phpbb\finder This object for chaining calls - */ - public function extension_directory($extension_directory) - { - $this->query['extension_directory'] = $this->sanitise_directory($extension_directory); - return $this; - } - - /** - * Sets a directory all files found in the core path must be contained in - * - * @param string $core_directory - * @return \phpbb\finder This object for chaining calls - */ - public function core_directory($core_directory) - { - $this->query['core_directory'] = $this->sanitise_directory($core_directory); - return $this; - } - - /** - * Removes occurances of /./ and makes sure path ends without trailing slash - * - * @param string $directory A directory pattern - * @return string A cleaned up directory pattern - */ - protected function sanitise_directory($directory) - { - $directory = $this->filesystem->clean_path($directory); - $dir_len = strlen($directory); - - if ($dir_len > 1 && $directory[$dir_len - 1] === '/') - { - $directory = substr($directory, 0, -1); - } - - return $directory; - } - - /** - * Finds classes matching the configured options if they follow phpBB naming rules. - * - * The php file extension is automatically added to suffixes. - * - * Note: If a file is matched but contains a class name not following the - * phpBB naming rules an incorrect class name will be returned. - * - * @param bool $cache Whether the result should be cached - * @return array An array of found class names - */ - public function get_classes($cache = true) - { - $this->query['extension_suffix'] .= '.' . $this->php_ext; - $this->query['core_suffix'] .= '.' . $this->php_ext; - - $files = $this->find($cache, false); - - return $this->get_classes_from_files($files); - } - - /** - * Get class names from a list of files - * - * @param array $files Array of files (from find()) - * @return array Array of class names - */ - public function get_classes_from_files($files) - { - $classes = array(); - foreach ($files as $file => $ext_name) - { - $class = substr($file, 0, -strlen('.' . $this->php_ext)); - if ($ext_name === '/' && preg_match('#^includes/#', $file)) - { - $class = preg_replace('#^includes/#', '', $class); - $classes[] = 'phpbb_' . str_replace('/', '_', $class); - } - else - { - $class = preg_replace('#^ext/#', '', $class); - $classes[] = '\\' . str_replace('/', '\\', $class); - } - } - return $classes; - } - - /** - * Finds all directories matching the configured options - * - * @param bool $cache Whether the result should be cached - * @param bool $extension_keys Whether the result should have extension name as array key - * @return array An array of paths to found directories - */ - public function get_directories($cache = true, $extension_keys = false) - { - return $this->find_with_root_path($cache, true, $extension_keys); - } - - /** - * Finds all files matching the configured options. - * - * @param bool $cache Whether the result should be cached - * @return array An array of paths to found files - */ - public function get_files($cache = true) - { - return $this->find_with_root_path($cache, false); - } - - /** - * A wrapper around the general find which prepends a root path to results - * - * @param bool $cache Whether the result should be cached - * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @param bool $extension_keys If true, result will be associative array - * with extension name as key - * @return array An array of paths to found items - */ - protected function find_with_root_path($cache = true, $is_dir = false, $extension_keys = false) - { - $items = $this->find($cache, $is_dir); - - $result = array(); - foreach ($items as $item => $ext_name) - { - if ($extension_keys) - { - $result[$ext_name] = $this->phpbb_root_path . $item; - } - else - { - $result[] = $this->phpbb_root_path . $item; - } - } - - return $result; - } - - /** - * Finds all file system entries matching the configured options - * - * @param bool $cache Whether the result should be cached - * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @return array An array of paths to found items - */ - public function find($cache = true, $is_dir = false) - { - $extensions = $this->extensions; - if ($this->query['core_path']) - { - $extensions['/'] = $this->phpbb_root_path . $this->query['core_path']; - } - - $files = array(); - $file_list = $this->find_from_paths($extensions, $cache, $is_dir); - - foreach ($file_list as $file) - { - $files[$file['named_path']] = $file['ext_name']; - } - - return $files; - } - - /** - * Finds all file system entries matching the configured options for one - * specific extension - * - * @param string $extension_name Name of the extension - * @param string $extension_path Relative path to the extension root directory - * @param bool $cache Whether the result should be cached - * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @return array An array of paths to found items - */ - public function find_from_extension($extension_name, $extension_path, $cache = true, $is_dir = false) - { - $extensions = array( - $extension_name => $extension_path, - ); - - $files = array(); - $file_list = $this->find_from_paths($extensions, $cache, $is_dir); - - foreach ($file_list as $file) - { - $files[$file['named_path']] = $file['ext_name']; - } - - return $files; - } - - /** - * Finds all file system entries matching the configured options from - * an array of paths - * - * @param array $extensions Array of extensions (name => full relative path) - * @param bool $cache Whether the result should be cached - * @param bool $is_dir Directories will be returned when true, only files - * otherwise - * @return array An array of paths to found items - */ - public function find_from_paths($extensions, $cache = true, $is_dir = false) - { - $this->query['is_dir'] = $is_dir; - $query = md5(serialize($this->query) . serialize($extensions)); - - if (!defined('DEBUG') && $cache && isset($this->cached_queries[$query])) - { - return $this->cached_queries[$query]; - } - - $files = array(); - - foreach ($extensions as $name => $path) - { - $ext_name = $name; - - if (!file_exists($path)) - { - continue; - } - - if ($name === '/') - { - $location = $this->query['core_path']; - $name = ''; - $suffix = $this->query['core_suffix']; - $prefix = $this->query['core_prefix']; - $directory = $this->query['core_directory']; - } - else - { - $location = 'ext/'; - $name .= '/'; - $suffix = $this->query['extension_suffix']; - $prefix = $this->query['extension_prefix']; - $directory = $this->query['extension_directory']; - } - - // match only first directory if leading slash is given - if ($directory === '/') - { - $directory_pattern = '^' . preg_quote(DIRECTORY_SEPARATOR, '#'); - } - else if ($directory && $directory[0] === '/') - { - if (!$is_dir) - { - $path .= substr($directory, 1); - } - $directory_pattern = '^' . preg_quote(str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#'); - } - else - { - $directory_pattern = preg_quote(DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#'); - } - if ($is_dir) - { - $directory_pattern .= '$'; - } - $directory_pattern = '#' . $directory_pattern . '#'; - - if (is_dir($path)) - { - $iterator = new \RecursiveIteratorIterator( - new \phpbb\recursive_dot_prefix_filter_iterator( - new \RecursiveDirectoryIterator( - $path, - \FilesystemIterator::SKIP_DOTS - ) - ), - \RecursiveIteratorIterator::SELF_FIRST - ); - - foreach ($iterator as $file_info) - { - $filename = $file_info->getFilename(); - - if ($file_info->isDir() == $is_dir) - { - if ($is_dir) - { - $relative_path = $iterator->getInnerIterator()->getSubPath() . DIRECTORY_SEPARATOR . basename($filename) . DIRECTORY_SEPARATOR; - if ($relative_path[0] !== DIRECTORY_SEPARATOR) - { - $relative_path = DIRECTORY_SEPARATOR . $relative_path; - } - } - else - { - $relative_path = $iterator->getInnerIterator()->getSubPathname(); - if ($directory && $directory[0] === '/') - { - $relative_path = str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR . $relative_path; - } - else - { - $relative_path = DIRECTORY_SEPARATOR . $relative_path; - } - } - - if ((!$suffix || substr($relative_path, -strlen($suffix)) === $suffix) && - (!$prefix || substr($filename, 0, strlen($prefix)) === $prefix) && - (!$directory || preg_match($directory_pattern, $relative_path))) - { - $files[] = array( - 'named_path' => str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1)), - 'ext_name' => $ext_name, - 'path' => str_replace(array(DIRECTORY_SEPARATOR, $this->phpbb_root_path), array('/', ''), $file_info->getPath()) . '/', - 'filename' => $filename, - ); - } - } - } - } - } - - if ($cache && $this->cache) - { - $this->cached_queries[$query] = $files; - $this->cache->put($this->cache_name, $this->cached_queries); - } - - return $files; - } -} diff --git a/install/update/old/phpbb/group/helper.php b/install/update/old/phpbb/group/helper.php deleted file mode 100644 index 5befddf..0000000 --- a/install/update/old/phpbb/group/helper.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @license 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; - -class helper -{ - /** @var \phpbb\language\language */ - protected $language; - - /** - * Constructor - * - * @param \phpbb\language\language $language Language object - */ - public function __construct(\phpbb\language\language $language) - { - $this->language = $language; - } - - /** - * @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; - } -} diff --git a/install/update/old/phpbb/help/controller/bbcode.php b/install/update/old/phpbb/help/controller/bbcode.php deleted file mode 100644 index e16f990..0000000 --- a/install/update/old/phpbb/help/controller/bbcode.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @license 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/install/update/old/phpbb/help/controller/faq.php b/install/update/old/phpbb/help/controller/faq.php deleted file mode 100644 index 5e45cfe..0000000 --- a/install/update/old/phpbb/help/controller/faq.php +++ /dev/null @@ -1,165 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/controller/helper.php b/install/update/old/phpbb/install/controller/helper.php deleted file mode 100644 index ff7e691..0000000 --- a/install/update/old/phpbb/install/controller/helper.php +++ /dev/null @@ -1,413 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/helper/container_factory.php b/install/update/old/phpbb/install/helper/container_factory.php deleted file mode 100644 index 9e372fe..0000000 --- a/install/update/old/phpbb/install/helper/container_factory.php +++ /dev/null @@ -1,191 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/helper/database.php b/install/update/old/phpbb/install/helper/database.php deleted file mode 100644 index fa5a10c..0000000 --- a/install/update/old/phpbb/install/helper/database.php +++ /dev/null @@ -1,439 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/helper/iohandler/iohandler_interface.php b/install/update/old/phpbb/install/helper/iohandler/iohandler_interface.php deleted file mode 100644 index 4407489..0000000 --- a/install/update/old/phpbb/install/helper/iohandler/iohandler_interface.php +++ /dev/null @@ -1,222 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/installer_configuration.php b/install/update/old/phpbb/install/installer_configuration.php deleted file mode 100644 index 8051403..0000000 --- a/install/update/old/phpbb/install/installer_configuration.php +++ /dev/null @@ -1,147 +0,0 @@ - -* @license 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/install/update/old/phpbb/install/module/install_database/task/add_config_settings.php b/install/update/old/phpbb/install/module/install_database/task/add_config_settings.php deleted file mode 100644 index ba43960..0000000 --- a/install/update/old/phpbb/install/module/install_database/task/add_config_settings.php +++ /dev/null @@ -1,368 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/module/install_database/task/create_schema.php b/install/update/old/phpbb/install/module/install_database/task/create_schema.php deleted file mode 100644 index a5635d5..0000000 --- a/install/update/old/phpbb/install/module/install_database/task/create_schema.php +++ /dev/null @@ -1,234 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/module/install_database/task/set_up_database.php b/install/update/old/phpbb/install/module/install_database/task/set_up_database.php deleted file mode 100644 index 49c8ea2..0000000 --- a/install/update/old/phpbb/install/module/install_database/task/set_up_database.php +++ /dev/null @@ -1,164 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/module/install_filesystem/task/create_config_file.php b/install/update/old/phpbb/install/module/install_filesystem/task/create_config_file.php deleted file mode 100644 index 5bc425b..0000000 --- a/install/update/old/phpbb/install/module/install_filesystem/task/create_config_file.php +++ /dev/null @@ -1,244 +0,0 @@ - - * @license 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 = "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/install/update/old/phpbb/install/module/requirements/task/check_server_environment.php b/install/update/old/phpbb/install/module/requirements/task/check_server_environment.php deleted file mode 100644 index 29f9777..0000000 --- a/install/update/old/phpbb/install/module/requirements/task/check_server_environment.php +++ /dev/null @@ -1,209 +0,0 @@ - - * @license 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/install/update/old/phpbb/install/module_base.php b/install/update/old/phpbb/install/module_base.php deleted file mode 100644 index 93c10bd..0000000 --- a/install/update/old/phpbb/install/module_base.php +++ /dev/null @@ -1,213 +0,0 @@ - - * @license 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/install/update/old/phpbb/language/language_file_loader.php b/install/update/old/phpbb/language/language_file_loader.php deleted file mode 100644 index b6816af..0000000 --- a/install/update/old/phpbb/language/language_file_loader.php +++ /dev/null @@ -1,206 +0,0 @@ - - * @license 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/install/update/old/phpbb/lock/db.php b/install/update/old/phpbb/lock/db.php deleted file mode 100644 index 85ba9a7..0000000 --- a/install/update/old/phpbb/lock/db.php +++ /dev/null @@ -1,146 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\lock; - -/** -* Database locking class -*/ -class db -{ - /** - * Name of the config variable this lock uses - * @var string - */ - private $config_name; - - /** - * Unique identifier for this lock. - * - * @var string - */ - private $unique_id; - - /** - * Stores the state of this lock - * @var bool - */ - private $locked; - - /** - * The phpBB configuration - * @var \phpbb\config\config - */ - private $config; - - /** - * A database connection - * @var \phpbb\db\driver\driver_interface - */ - private $db; - - /** - * Creates a named released instance of the lock. - * - * You have to call acquire() to actually create the lock. - * - * @param string $config_name A config variable to be used for locking - * @param \phpbb\config\config $config The phpBB configuration - * @param \phpbb\db\driver\driver_interface $db A database connection - */ - public function __construct($config_name, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db) - { - $this->config_name = $config_name; - $this->config = $config; - $this->db = $db; - } - - /** - * Tries to acquire the lock by updating - * the configuration variable in the database. - * - * As a lock may only be held by one process at a time, lock - * acquisition may fail if another process is holding the lock - * or if another process obtained the lock but never released it. - * Locks are forcibly released after a timeout of 1 hour. - * - * @return bool true if lock was acquired - * false otherwise - */ - public function acquire() - { - if ($this->locked) - { - return false; - } - - if (!isset($this->config[$this->config_name])) - { - $this->config->set($this->config_name, '0', false); - } - $lock_value = $this->config[$this->config_name]; - - // make sure lock cannot be acquired by multiple processes - if ($lock_value) - { - // if the other process is running more than an hour already we have to assume it - // aborted without cleaning the lock - $time = explode(' ', $lock_value); - $time = $time[0]; - - if ($time + 3600 >= time()) - { - return false; - } - } - - $this->unique_id = time() . ' ' . unique_id(); - - // try to update the config value, if it was already modified by another - // process we failed to acquire the lock. - $this->locked = $this->config->set_atomic($this->config_name, $lock_value, $this->unique_id, false); - - return $this->locked; - } - - /** - * Does this process own the lock? - * - * @return bool true if lock is owned - * false otherwise - */ - public function owns_lock() - { - return (bool) $this->locked; - } - - /** - * Releases the lock. - * - * The lock must have been previously obtained, that is, acquire() call - * was issued and returned true. - * - * Note: Attempting to release a lock that is already released, - * that is, calling release() multiple times, is harmless. - * - * @return null - */ - public function release() - { - if ($this->locked) - { - $this->config->set_atomic($this->config_name, $this->unique_id, '0', false); - $this->locked = false; - } - } -} diff --git a/install/update/old/phpbb/lock/flock.php b/install/update/old/phpbb/lock/flock.php deleted file mode 100644 index df88e14..0000000 --- a/install/update/old/phpbb/lock/flock.php +++ /dev/null @@ -1,141 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\lock; - -/** -* File locking class -*/ -class flock -{ - /** - * Path to the file to which access is controlled - * - * @var string - */ - private $path; - - /** - * File pointer for the lock file - * @var string - */ - private $lock_fp; - - /** - * Constructor. - * - * You have to call acquire() to actually acquire the lock. - * - * @param string $path Path to the file to which access is controlled - */ - public function __construct($path) - { - $this->path = $path; - $this->lock_fp = null; - } - - /** - * Tries to acquire the lock. - * - * If the lock is already held by another process, this call will block - * until the other process releases the lock. If a lock is acquired and - * is not released before script finishes but the process continues to - * live (apache/fastcgi) then subsequent processes trying to acquire - * the same lock will be blocked forever. - * - * If the lock is already held by the same process via another instance - * of this class, this call will block forever. - * - * If flock function is disabled in php or fails to work, lock - * acquisition will fail and false will be returned. - * - * @return bool true if lock was acquired - * false otherwise - */ - public function acquire() - { - if ($this->lock_fp) - { - return false; - } - - // For systems that can't have two processes opening - // one file for writing simultaneously - if (file_exists($this->path . '.lock')) - { - $mode = 'rb'; - } - else - { - $mode = 'wb'; - } - - $this->lock_fp = @fopen($this->path . '.lock', $mode); - - if ($mode == 'wb') - { - if (!$this->lock_fp) - { - // Two processes may attempt to create lock file at the same time. - // Have the losing process try opening the lock file again for reading - // on the assumption that the winning process created it - $mode = 'rb'; - $this->lock_fp = @fopen($this->path . '.lock', $mode); - } - else - { - // Only need to set mode when the lock file is written - @chmod($this->path . '.lock', 0666); - } - } - - if ($this->lock_fp) - { - @flock($this->lock_fp, LOCK_EX); - } - - return (bool) $this->lock_fp; - } - - /** - * Does this process own the lock? - * - * @return bool true if lock is owned - * false otherwise - */ - public function owns_lock() - { - return (bool) $this->lock_fp; - } - - /** - * Releases the lock. - * - * The lock must have been previously obtained, that is, acquire() call - * was issued and returned true. - * - * Note: Attempting to release a lock that is already released, - * that is, calling release() multiple times, is harmless. - * - * @return null - */ - public function release() - { - if ($this->lock_fp) - { - @flock($this->lock_fp, LOCK_UN); - fclose($this->lock_fp); - $this->lock_fp = null; - } - } -} diff --git a/install/update/old/phpbb/message/form.php b/install/update/old/phpbb/message/form.php deleted file mode 100644 index 63bada9..0000000 --- a/install/update/old/phpbb/message/form.php +++ /dev/null @@ -1,175 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\message; - -/** -* Abstract class form -*/ -abstract class form -{ - /** @var \phpbb\auth\auth */ - protected $auth; - /** @var \phpbb\config\config */ - protected $config; - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - /** @var \phpbb\message\message */ - protected $message; - /** @var \phpbb\user */ - protected $user; - - /** @var string */ - protected $phpbb_root_path; - /** @var string */ - protected $phpEx; - - /** @var array */ - protected $errors = array(); - /** @var bool */ - protected $cc_sender; - /** @var string */ - protected $body; - - /** - * Construct - * - * @param \phpbb\auth\auth $auth - * @param \phpbb\config\config $config - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\user $user - * @param string $phpbb_root_path - * @param string $phpEx - */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $phpEx) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->phpEx = $phpEx; - $this->user = $user; - $this->auth = $auth; - $this->config = $config; - $this->db = $db; - - $this->message = new message($config['server_name']); - $this->message->set_sender_from_user($this->user); - } - - /** - * Returns the title for the email form page - * - * @return string - */ - public function get_page_title() - { - return $this->user->lang['SEND_EMAIL']; - } - - /** - * Returns the file name of the form template - * - * @return string - */ - public function get_template_file() - { - return 'memberlist_email.html'; - } - - /** - * Checks whether the user is allowed to use the form - * - * @return false|string Error string if not allowed, false otherwise - */ - public function check_allow() - { - if (!$this->config['email_enable']) - { - return 'EMAIL_DISABLED'; - } - - if (time() - $this->user->data['user_emailtime'] < $this->config['flood_interval']) - { - return 'FLOOD_EMAIL_LIMIT'; - } - - return false; - } - - /** - * Get the return link after the message has been sent - * - * @return string - */ - public function get_return_message() - { - return sprintf($this->user->lang['RETURN_INDEX'], '', ''); - } - - /** - * Bind the values of the request to the form - * - * @param \phpbb\request\request_interface $request - * @return null - */ - public function bind(\phpbb\request\request_interface $request) - { - $this->cc_sender = $request->is_set_post('cc_sender'); - $this->body = $request->variable('message', '', true); - } - - /** - * Submit form, generate the email and send it - * - * @param \messenger $messenger - * @return null - */ - public function submit(\messenger $messenger) - { - if (!check_form_key('memberlist_email')) - { - $this->errors[] = 'FORM_INVALID'; - } - - if (!count($this->errors)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_emailtime = ' . time() . ' - WHERE user_id = ' . $this->user->data['user_id']; - $this->db->sql_query($sql); - - if ($this->cc_sender && $this->user->data['is_registered']) - { - $this->message->cc_sender(); - } - - $this->message->send($messenger, phpbb_get_board_contact($this->config, $this->phpEx)); - - meta_refresh(3, append_sid($this->phpbb_root_path . 'index.' . $this->phpEx)); - trigger_error($this->user->lang['EMAIL_SENT'] . '

' . $this->get_return_message()); - } - } - - /** - * Render the template of the form - * - * @param \phpbb\template\template $template - * @return null - */ - public function render(\phpbb\template\template $template) - { - add_form_key('memberlist_email'); - - $template->assign_vars(array( - 'ERROR_MESSAGE' => (count($this->errors)) ? implode('
', $this->errors) : '', - )); - } -} diff --git a/install/update/old/phpbb/mimetype/guesser.php b/install/update/old/phpbb/mimetype/guesser.php deleted file mode 100644 index 8baa770..0000000 --- a/install/update/old/phpbb/mimetype/guesser.php +++ /dev/null @@ -1,156 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\mimetype; - -class guesser -{ - /** - * @const Default priority for mimetype guessers - */ - const PRIORITY_DEFAULT = 0; - - /** - * @var array guessers - */ - protected $guessers; - - /** - * Construct a mimetype guesser object - * - * @param array $mimetype_guessers Mimetype guesser service collection - */ - public function __construct($mimetype_guessers) - { - $this->register_guessers($mimetype_guessers); - } - - /** - * Register MimeTypeGuessers and sort them by priority - * - * @param array $mimetype_guessers Mimetype guesser service collection - * - * @throws \LogicException If incorrect or not mimetype guessers have - * been supplied to class - */ - protected function register_guessers($mimetype_guessers) - { - foreach ($mimetype_guessers as $guesser) - { - $is_supported = (method_exists($guesser, 'is_supported')) ? 'is_supported' : ''; - $is_supported = (method_exists($guesser, 'isSupported')) ? 'isSupported' : $is_supported; - - if (empty($is_supported)) - { - throw new \LogicException('Incorrect mimetype guesser supplied.'); - } - - if ($guesser->$is_supported()) - { - $this->guessers[] = $guesser; - } - } - - if (empty($this->guessers)) - { - throw new \LogicException('No mimetype guesser supplied.'); - } - - // Sort guessers by priority - usort($this->guessers, array($this, 'sort_priority')); - } - - /** - * Sort the priority of supplied guessers - * This is a compare function for usort. A guesser with higher priority - * should be used first and vice versa. usort() orders the array values - * from low to high depending on what the comparison function returns - * to it. Return value should be smaller than 0 if value a is smaller - * than value b. This has been reversed in the comparision function in - * order to sort the guessers from high to low. - * Method has been set to public in order to allow proper testing. - * - * @param object $guesser_a Mimetype guesser a - * @param object $guesser_b Mimetype guesser b - * - * @return int If both guessers have the same priority 0, bigger - * than 0 if first guesser has lower priority, and lower - * than 0 if first guesser has higher priority - */ - public function sort_priority($guesser_a, $guesser_b) - { - $priority_a = (int) (method_exists($guesser_a, 'get_priority')) ? $guesser_a->get_priority() : self::PRIORITY_DEFAULT; - $priority_b = (int) (method_exists($guesser_b, 'get_priority')) ? $guesser_b->get_priority() : self::PRIORITY_DEFAULT; - - return $priority_b - $priority_a; - } - - /** - * Guess mimetype of supplied file - * - * @param string $file Path to file - * @param string $file_name The real file name - * - * @return string Guess for mimetype of file - */ - public function guess($file, $file_name = '') - { - if (!is_file($file)) - { - return false; - } - - if (!is_readable($file)) - { - return false; - } - - $mimetype = 'application/octet-stream'; - - foreach ($this->guessers as $guesser) - { - $mimetype_guess = $guesser->guess($file, $file_name); - - $mimetype = $this->choose_mime_type($mimetype, $mimetype_guess); - } - // Return any mimetype if we got a result or the fallback value - return $mimetype; - } - - /** - * Choose the best mime type based on the current mime type and the guess - * If a guesser returns nulls or application/octet-stream, we will keep - * the current guess. Guesses with a slash inside them will be favored over - * already existing ones. However, any guess that will pass the first check - * will always overwrite the default application/octet-stream. - * - * @param string $mime_type The current mime type - * @param string $guess The current mime type guess - * - * @return string The best mime type based on current mime type and guess - */ - public function choose_mime_type($mime_type, $guess) - { - if ($guess === null || $guess == 'application/octet-stream') - { - return $mime_type; - } - - if ($mime_type == 'application/octet-stream' || strpos($guess, '/') !== false) - { - $mime_type = $guess; - } - - return $mime_type; - } -} diff --git a/install/update/old/phpbb/notification/type/approve_post.php b/install/update/old/phpbb/notification/type/approve_post.php deleted file mode 100644 index e4b111e..0000000 --- a/install/update/old/phpbb/notification/type/approve_post.php +++ /dev/null @@ -1,149 +0,0 @@ - -* @license 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\type; - -/** -* Post approved notifications class -* This class handles notifications for posts when they are approved (to their authors) -*/ - -class approve_post extends \phpbb\notification\type\post -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type() - { - return 'notification.type.approve_post'; - } - - /** - * Language key used to output the text - * - * @var string - */ - protected $language_key = 'NOTIFICATION_POST_APPROVED'; - - /** - * Inherit notification read status from post. - * - * @var bool - */ - protected $inherit_read_status = false; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use it's default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - static public $notification_option = array( - 'id' => 'moderation_queue', - 'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE', - 'group' => 'NOTIFICATION_GROUP_POSTING', - ); - - /** - * Is available - */ - public function is_available() - { - return !$this->auth->acl_get('m_approve'); - } - - /** - * Find the users who want to receive notifications - * - * @param array $post Data from submit_post - * @param array $options Options for finding users for notification - * - * @return array - */ - public function find_users_for_notification($post, $options = array()) - { - $options = array_merge(array( - 'ignore_users' => array(), - ), $options); - - $users = 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'], - ))); - } - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $post Post data from submit_post - * @param array $notify_users Notify users list - * Formated from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($post, $notify_users) - { - // In the parent class, this is used to check if the post is already - // read by a user and marks the notification read if it was marked read. - // Returning an empty array in effect, forces it to be marked as unread - // (and also saves a query) - return array(); - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($post, $pre_create_data = array()) - { - $this->set_data('post_subject', $post['post_subject']); - - 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; - } - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template() - { - return 'post_approved'; - } - - /** - * {inheritDoc} - */ - public function get_redirect_url() - { - return $this->get_url(); - } -} diff --git a/install/update/old/phpbb/notification/type/approve_topic.php b/install/update/old/phpbb/notification/type/approve_topic.php deleted file mode 100644 index f8a3fde..0000000 --- a/install/update/old/phpbb/notification/type/approve_topic.php +++ /dev/null @@ -1,140 +0,0 @@ - -* @license 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\type; - -/** -* Topic approved notifications class -* This class handles notifications for topics when they are approved (for authors) -*/ - -class approve_topic extends \phpbb\notification\type\topic -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type() - { - return 'notification.type.approve_topic'; - } - - /** - * Language key used to output the text - * - * @var string - */ - protected $language_key = 'NOTIFICATION_TOPIC_APPROVED'; - - /** - * Inherit notification read status from topic. - * - * @var bool - */ - protected $inherit_read_status = false; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use it's default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - static public $notification_option = array( - 'id' => 'moderation_queue', - 'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE', - 'group' => 'NOTIFICATION_GROUP_POSTING', - ); - - /** - * Is available - */ - public function is_available() - { - return !$this->auth->acl_get('m_approve'); - } - - /** - * Find the users who want to receive notifications - * - * @param array $post Data from submit_post - * @param array $options Options for finding users for notification - * - * @return array - */ - public function find_users_for_notification($post, $options = array()) - { - $options = array_merge(array( - 'ignore_users' => array(), - ), $options); - - $users = 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'], - ))); - } - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $post Post data from submit_post - * @param array $notify_users Notify users list - * Formated from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($post, $notify_users) - { - // In the parent class, this is used to check if the post is already - // read by a user and marks the notification read if it was marked read. - // Returning an empty array in effect, forces it to be marked as unread - // (and also saves a query) - return array(); - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($post, $pre_create_data = array()) - { - - 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; - } - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template() - { - return 'topic_approved'; - } -} diff --git a/install/update/old/phpbb/notification/type/base.php b/install/update/old/phpbb/notification/type/base.php deleted file mode 100644 index 77ed7f2..0000000 --- a/install/update/old/phpbb/notification/type/base.php +++ /dev/null @@ -1,577 +0,0 @@ - -* @license 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\type; - -/** -* Base notifications class -*/ -abstract class base implements \phpbb\notification\type\type_interface -{ - /** @var \phpbb\notification\manager */ - protected $notification_manager; - - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - /** @var \phpbb\language\language */ - protected $language; - - /** @var \phpbb\user */ - protected $user; - - /** @var \phpbb\auth\auth */ - protected $auth; - - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - - /** @var string */ - protected $user_notifications_table; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use its default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - static public $notification_option = false; - - /** - * The notification_type_id, set upon creation of the class - * This is the notification_type_id from the notification_types table - * - * @var int - */ - protected $notification_type_id; - - /** - * 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) - * user_id - * notification_read - * notification_time - * notification_data (special serialized field that each notification type can use to store stuff) - * - * @var array $data Notification row from the database - * This must be private, all interaction should use __get(), __set(), get_data(), set_data() - */ - private $data = array(); - - /** - * 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->db = $db; - $this->language = $language; - $this->user = $user; - $this->auth = $auth; - - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->user_notifications_table = $user_notifications_table; - } - - /** - * Set notification manager (required) - * - * @param \phpbb\notification\manager $notification_manager - */ - public function set_notification_manager(\phpbb\notification\manager $notification_manager) - { - $this->notification_manager = $notification_manager; - - $this->notification_type_id = $this->notification_manager->get_notification_type_id($this->get_type()); - } - - /** - * Set initial data from the database - * - * @param array $data Row directly from the database - */ - public function set_initial_data($data = array()) - { - // The row from the database (unless this is a new notification we're going to add) - $this->data = $data; - $this->data['notification_data'] = (isset($this->data['notification_data'])) ? unserialize($this->data['notification_data']) : array(); - } - - /** - * Magic method to get data from this notification - * - * @param mixed $name - * @return mixed - */ - public function __get($name) - { - return (!isset($this->data[$name])) ? null : $this->data[$name]; - } - - - /** - * Magic method to set data on this notification - * - * @param mixed $name - * @param mixed $value - * - * @return null - */ - public function __set($name, $value) - { - $this->data[$name] = $value; - } - - - /** - * Magic method to get a string of this notification - * - * Primarily for testing - * - * @return mixed - */ - public function __toString() - { - return (!empty($this->data)) ? var_export($this->data, true) : $this->get_type(); - } - - /** - * Get special data (only important for the classes that extend this) - * - * @param string $name Name of the variable to get - * @return mixed - */ - protected function get_data($name) - { - return ($name === false) ? $this->data['notification_data'] : ((isset($this->data['notification_data'][$name])) ? $this->data['notification_data'][$name] : null); - } - - /** - * Set special data (only important for the classes that extend this) - * - * @param string $name Name of the variable to set - * @param mixed $value Value to set to the variable - * @return mixed - */ - protected function set_data($name, $value) - { - $this->data['notification_data'][$name] = $value; - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($type_data, $pre_create_data = array()) - { - // Defaults - $this->data = array_merge(array( - 'item_id' => static::get_item_id($type_data), - 'notification_type_id' => $this->notification_type_id, - 'item_parent_id' => static::get_item_parent_id($type_data), - - 'notification_time' => time(), - 'notification_read' => false, - - 'notification_data' => array(), - ), $this->data); - } - - /** - * {@inheritdoc} - */ - public function get_insert_array() - { - $data = $this->data; - - $data['notification_data'] = serialize($data['notification_data']); - - return $data; - } - - /** - * Function for preparing the data for update in an SQL query - * (The service handles insertion) - * - * @param array $type_data Data unique to this notification type - * @return array Array of data ready to be updated in the database - */ - public function create_update_array($type_data) - { - $this->create_insert_array($type_data); - $data = $this->get_insert_array(); - - // Unset data unique to each row - unset( - $data['notification_time'], // Also unsetting time, since it always tries to change the time to current (if you actually need to change the time, over-ride this function) - $data['notification_id'], - $data['notification_read'], - $data['user_id'] - ); - - return $data; - } - - /** - * Mark this item read - * - * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False) - * @return string|null If $return is False, nothing will be returned, else the sql code to update this item - */ - public function mark_read($return = false) - { - return $this->mark(false, $return); - } - - /** - * Mark this item unread - * - * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False) - * @return string|null If $return is False, nothing will be returned, else the sql code to update this item - */ - public function mark_unread($return = false) - { - return $this->mark(true, $return); - } - - /** - * {inheritDoc} - */ - public function get_redirect_url() - { - return $this->get_url(); - } - - /** - * Prepare to output the notification to the template - * - * @return array Template variables - */ - public function prepare_for_display() - { - $mark_hash = generate_link_hash('mark_notification_read'); - - if ($this->get_url()) - { - $u_mark_read = append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'mark_notification=' . $this->notification_id . '&hash=' . $mark_hash); - } - else - { - $redirect = (($this->user->page['page_dir']) ? $this->user->page['page_dir'] . '/' : '') . $this->user->page['page_name'] . (($this->user->page['query_string']) ? '?' . $this->user->page['query_string'] : ''); - - $u_mark_read = append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'mark_notification=' . $this->notification_id . '&hash=' . $mark_hash . '&redirect=' . urlencode($redirect)); - } - - return array( - 'NOTIFICATION_ID' => $this->notification_id, - 'STYLING' => $this->get_style_class(), - 'AVATAR' => $this->get_avatar(), - 'FORMATTED_TITLE' => $this->get_title(), - 'REFERENCE' => $this->get_reference(), - 'FORUM' => $this->get_forum(), - 'REASON' => $this->get_reason(), - 'URL' => $this->get_url(), - 'TIME' => $this->user->format_date($this->notification_time), - 'UNREAD' => !$this->notification_read, - 'U_MARK_READ' => (!$this->notification_read) ? $u_mark_read : '', - ); - } - - /** - * -------------- Fall back functions ------------------- - */ - - /** - * 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) - { - return false; - } - - /** - * Get the CSS style class of the notification (fall back) - * - * @return string - */ - public function get_style_class() - { - return ''; - } - - /** - * Get the user's avatar (fall back) - * - * @return string - */ - public function get_avatar() - { - return ''; - } - - /** - * Get the reference of the notifcation (fall back) - * - * @return string - */ - public function get_reference() - { - return ''; - } - - /** - * Get the forum of the notification reference (fall back) - * - * @return string - */ - public function get_forum() - { - return ''; - } - - /** - * Get the reason for the notifcation (fall back) - * - * @return string - */ - public function get_reason() - { - return ''; - } - - /** - * Get the special items to load (fall back) - * - * @return array - */ - public function get_load_special() - { - return array(); - } - - /** - * Load the special items (fall back) - * - * @param array $data - * @param array $notifications - */ - public function load_special($data, $notifications) - { - return; - } - - /** - * Is available (fall back) - * - * @return bool - */ - public function is_available() - { - return true; - } - - /** - * 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(); - } - - /** - * -------------- Helper functions ------------------- - */ - - /** - * 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( - 'ignore_users' => array(), - 'item_type' => $this->get_type(), - 'item_id' => 0, // Global by default - ), $options); - - if ($user_ids === false) - { - $user_ids = array(); - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE user_id <> ' . ANONYMOUS . ' - AND user_type <> ' . USER_IGNORE; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $user_ids[] = $row['user_id']; - } - $this->db->sql_freeresult($result); - } - - if (empty($user_ids)) - { - return array(); - } - - $rowset = $output = array(); - - $sql = 'SELECT user_id, method, notify - FROM ' . $this->user_notifications_table . ' - WHERE ' . $this->db->sql_in_set('user_id', $user_ids) . " - AND item_type = '" . $this->db->sql_escape($options['item_type']) . "' - AND item_id = " . (int) $options['item_id']; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - if (isset($options['ignore_users'][$row['user_id']]) && in_array($row['method'], $options['ignore_users'][$row['user_id']])) - { - continue; - } - - if (!isset($rowset[$row['user_id']])) - { - $rowset[$row['user_id']] = array(); - } - $rowset[$row['user_id']][$row['method']] = $row['notify']; - - 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 (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 - { - 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 $output; - } - - /** - * Mark this item read/unread helper - * - * @param bool $unread Unread (True/False) (Default: False) - * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False) - * @return string|null If $return is False, nothing will be returned, else the sql code to update this item - */ - protected function mark($unread = true, $return = false) - { - $this->notification_read = (bool) !$unread; - - 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); - } - - return null; - } - - /** - * Get a list of users that are authorised to receive notifications - * - * @param array $users Array of users that have subscribed to a notification - * @param int $forum_id Forum ID of the forum - * @param array $options Array of notification options - * @param bool $sort Whether the users array should be sorted. Default: false - * @return array Array of users that are authorised recipients - */ - protected function get_authorised_recipients($users, $forum_id, $options, $sort = false) - { - if (empty($users)) - { - return array(); - } - - $users = array_unique($users); - - if ($sort) - { - sort($users); - } - - $auth_read = $this->auth->acl_get_list($users, 'f_read', $forum_id); - - if (empty($auth_read)) - { - return array(); - } - - return $this->check_user_notification_options($auth_read[$forum_id]['f_read'], $options); - } -} diff --git a/install/update/old/phpbb/notification/type/post.php b/install/update/old/phpbb/notification/type/post.php deleted file mode 100644 index 254f4c0..0000000 --- a/install/update/old/phpbb/notification/type/post.php +++ /dev/null @@ -1,467 +0,0 @@ - -* @license 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\type; - -/** -* Post notifications class -* This class handles notifications for replies to a topic -*/ - -class post extends \phpbb\notification\type\base -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type() - { - return 'notification.type.post'; - } - - /** - * Language key used to output the text - * - * @var string - */ - protected $language_key = 'NOTIFICATION_POST'; - - /** - * Inherit notification read status from post. - * - * @var bool - */ - protected $inherit_read_status = true; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use it's default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - 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 - */ - public function is_available() - { - return $this->config['allow_topic_notify']; - } - - /** - * Get the id of the item - * - * @param array $post The data from the post - * @return int The post id - */ - static public function get_item_id($post) - { - return (int) $post['post_id']; - } - - /** - * Get the id of the parent - * - * @param array $post The data from the post - * @return int The topic id - */ - static public function get_item_parent_id($post) - { - return (int) $post['topic_id']; - } - - /** - * Find the users who want to receive notifications - * - * @param array $post Data from submit_post - * @param array $options Options for finding users for notification - * - * @return array - */ - public function find_users_for_notification($post, $options = array()) - { - $options = array_merge(array( - 'ignore_users' => array(), - ), $options); - - $users = array(); - - $sql = 'SELECT user_id - FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . (int) $post['topic_id'] . ' - AND notify_status = ' . NOTIFY_YES . ' - AND user_id <> ' . (int) $post['poster_id']; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $users[] = (int) $row['user_id']; - } - $this->db->sql_freeresult($result); - - $sql = 'SELECT user_id - FROM ' . FORUMS_WATCH_TABLE . ' - WHERE forum_id = ' . (int) $post['forum_id'] . ' - AND notify_status = ' . NOTIFY_YES . ' - AND user_id <> ' . (int) $post['poster_id']; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $users[] = (int) $row['user_id']; - } - $this->db->sql_freeresult($result); - - $notify_users = $this->get_authorised_recipients($users, $post['forum_id'], $options, true); - - if (empty($notify_users)) - { - return array(); - } - - // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications - $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) - { - unset($notify_users[$user]); - - /** @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)) - { - $this->notification_manager->update_notification($notification, $update_responders, array( - 'item_parent_id' => self::get_item_parent_id($post), - 'read' => 0, - 'user_id' => $user, - )); - } - } - - return $notify_users; - } - - /** - * Get the user's avatar - */ - public function get_avatar() - { - return $this->user_loader->get_avatar($this->get_data('poster_id'), false, true); - } - - /** - * Get the HTML formatted title of this notification - * - * @return string - */ - public function get_title() - { - $responders = $this->get_data('responders'); - $usernames = array(); - - if (!is_array($responders)) - { - $responders = array(); - } - - $responders = array_merge(array(array( - 'poster_id' => $this->get_data('poster_id'), - 'username' => $this->get_data('post_username'), - )), $responders); - - $responders_cnt = count($responders); - $responders = $this->trim_user_ary($responders); - $trimmed_responders_cnt = $responders_cnt - count($responders); - - foreach ($responders as $responder) - { - if ($responder['username']) - { - $usernames[] = $responder['username']; - } - else - { - $usernames[] = $this->user_loader->get_username($responder['poster_id'], 'no_profile'); - } - } - - if ($trimmed_responders_cnt > 20) - { - $usernames[] = $this->language->lang('NOTIFICATION_MANY_OTHERS'); - } - else if ($trimmed_responders_cnt) - { - $usernames[] = $this->language->lang('NOTIFICATION_X_OTHERS', $trimmed_responders_cnt); - } - - return $this->language->lang( - $this->language_key, - phpbb_generate_string_list($usernames, $this->user), - $responders_cnt - ); - } - - /** - * Get the HTML formatted reference of the notification - * - * @return string - */ - public function get_reference() - { - return $this->language->lang( - 'NOTIFICATION_REFERENCE', - censor_text($this->get_data('topic_title')) - ); - } - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template() - { - return 'topic_notify'; - } - - /** - * Get email template variables - * - * @return array - */ - public function get_email_template_variables() - { - if ($this->get_data('post_username')) - { - $username = $this->get_data('post_username'); - } - else - { - $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username'); - } - - return array( - 'AUTHOR_NAME' => htmlspecialchars_decode($username), - 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('post_subject'))), - 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('topic_title'))), - - 'U_VIEW_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?p={$this->item_id}#p{$this->item_id}", - 'U_NEWEST_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}&e=1&view=unread#unread", - 'U_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}", - 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}", - 'U_FORUM' => generate_board_url() . "/viewforum.{$this->php_ext}?f={$this->get_data('forum_id')}", - 'U_STOP_WATCHING_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?uid={$this->user_id}&f={$this->get_data('forum_id')}&t={$this->item_parent_id}&unwatch=topic", - ); - } - - /** - * Get the url to this item - * - * @return string URL - */ - public function get_url() - { - return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "p={$this->item_id}#p{$this->item_id}"); - } - - /** - * {inheritDoc} - */ - public function get_redirect_url() - { - return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "t={$this->item_parent_id}&view=unread#unread"); - } - - /** - * Users needed to query before this notification can be displayed - * - * @return array Array of user_ids - */ - public function users_to_query() - { - $responders = $this->get_data('responders'); - $users = array( - $this->get_data('poster_id'), - ); - - if (is_array($responders)) - { - foreach ($responders as $responder) - { - $users[] = $responder['poster_id']; - } - } - - return $this->trim_user_ary($users); - } - - /** - * Trim the user array passed down to 3 users if the array contains - * more than 4 users. - * - * @param array $users Array of users - * @return array Trimmed array of user_ids - */ - public function trim_user_ary($users) - { - if (count($users) > 4) - { - array_splice($users, 3); - } - return $users; - } - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $post Post data from submit_post - * @param array $notify_users Notify users list - * Formated from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($post, $notify_users) - { - if (!count($notify_users) || !$this->inherit_read_status) - { - return array(); - } - - $tracking_data = array(); - $sql = 'SELECT user_id, mark_time FROM ' . TOPICS_TRACK_TABLE . ' - WHERE topic_id = ' . (int) $post['topic_id'] . ' - AND ' . $this->db->sql_in_set('user_id', array_keys($notify_users)); - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $tracking_data[$row['user_id']] = $row['mark_time']; - } - $this->db->sql_freeresult($result); - - return $tracking_data; - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($post, $pre_create_data = array()) - { - $this->set_data('poster_id', $post['poster_id']); - - $this->set_data('topic_title', $post['topic_title']); - - $this->set_data('post_subject', $post['post_subject']); - - $this->set_data('post_username', (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : '')); - - $this->set_data('forum_id', $post['forum_id']); - - $this->set_data('forum_name', $post['forum_name']); - - $this->notification_time = $post['post_time']; - - // Topics can be "read" before they are public (while awaiting approval). - // Make sure that if the user has read the topic, it's marked as read in the notification - if ($this->inherit_read_status && isset($pre_create_data[$this->user_id]) && $pre_create_data[$this->user_id] >= $this->notification_time) - { - $this->notification_read = true; - } - - 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) - { - // Do not add them as a responder if they were the original poster that created the notification - if ($this->get_data('poster_id') == $post['poster_id']) - { - return array(); - } - - $responders = $this->get_data('responders'); - - $responders = ($responders === null) ? array() : $responders; - - // 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 (count($responders) > 25) - { - return array(); - } - - foreach ($responders as $responder) - { - // Do not add them as a responder multiple times - if ($responder['poster_id'] == $post['poster_id']) - { - return array(); - } - } - - $responders[] = array( - 'poster_id' => $post['poster_id'], - 'username' => (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : ''), - ); - - $this->set_data('responders', $responders); - - $serialized_data = serialize($this->get_data(false)); - - // If the data is longer then 4000 characters, it would cause a SQL error. - // We don't add the username to the list if this is the case. - if (utf8_strlen($serialized_data) >= 4000) - { - return array(); - } - - $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/install/update/old/phpbb/notification/type/topic.php b/install/update/old/phpbb/notification/type/topic.php deleted file mode 100644 index 5c42afa..0000000 --- a/install/update/old/phpbb/notification/type/topic.php +++ /dev/null @@ -1,307 +0,0 @@ - -* @license 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\type; - -/** -* Topic notifications class -* This class handles notifications for new topics -*/ - -class topic extends \phpbb\notification\type\base -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type() - { - return 'notification.type.topic'; - } - - /** - * Language key used to output the text - * - * @var string - */ - protected $language_key = 'NOTIFICATION_TOPIC'; - - /** - * Inherit notification read status from topic. - * - * @var bool - */ - protected $inherit_read_status = true; - - /** - * Notification option data (for outputting to the user) - * - * @var bool|array False if the service should use it's default data - * Array of data (including keys 'id', 'lang', and 'group') - */ - 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 - */ - public function is_available() - { - return $this->config['allow_forum_notify']; - } - - /** - * Get the id of the item - * - * @param array $post The data from the post - * @return int The topic id - */ - static public function get_item_id($post) - { - return (int) $post['topic_id']; - } - - /** - * Get the id of the parent - * - * @param array $post The data from the post - * @return int The forum id - */ - static public function get_item_parent_id($post) - { - return (int) $post['forum_id']; - } - - /** - * Find the users who want to receive notifications - * - * @param array $topic Data from the topic - * @param array $options Options for finding users for notification - * - * @return array - */ - public function find_users_for_notification($topic, $options = array()) - { - $options = array_merge(array( - 'ignore_users' => array(), - ), $options); - - $users = array(); - - $sql = 'SELECT user_id - FROM ' . FORUMS_WATCH_TABLE . ' - WHERE forum_id = ' . (int) $topic['forum_id'] . ' - AND notify_status = ' . NOTIFY_YES . ' - AND user_id <> ' . (int) $topic['poster_id']; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $users[] = (int) $row['user_id']; - } - $this->db->sql_freeresult($result); - - return $this->get_authorised_recipients($users, $topic['forum_id'], $options); - } - - /** - * Get the user's avatar - */ - public function get_avatar() - { - return $this->user_loader->get_avatar($this->get_data('poster_id'), false, true); - } - - /** - * Get the HTML formatted title of this notification - * - * @return string - */ - public function get_title() - { - if ($this->get_data('post_username')) - { - $username = $this->get_data('post_username'); - } - else - { - $username = $this->user_loader->get_username($this->get_data('poster_id'), 'no_profile'); - } - - return $this->language->lang( - $this->language_key, - $username - ); - } - - /** - * Get the HTML formatted reference of the notification - * - * @return string - */ - public function get_reference() - { - return $this->language->lang( - 'NOTIFICATION_REFERENCE', - censor_text($this->get_data('topic_title')) - ); - } - - /** - * Get the forum of the notification reference - * - * @return string - */ - public function get_forum() - { - return $this->language->lang( - 'NOTIFICATION_FORUM', - $this->get_data('forum_name') - ); - } - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template() - { - return 'newtopic_notify'; - } - - /** - * Get email template variables - * - * @return array - */ - public function get_email_template_variables() - { - $board_url = generate_board_url(); - - if ($this->get_data('post_username')) - { - $username = $this->get_data('post_username'); - } - else - { - $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username'); - } - - return array( - 'AUTHOR_NAME' => htmlspecialchars_decode($username), - 'FORUM_NAME' => htmlspecialchars_decode($this->get_data('forum_name')), - 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('topic_title'))), - - 'U_TOPIC' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->item_parent_id}&t={$this->item_id}", - 'U_VIEW_TOPIC' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->item_parent_id}&t={$this->item_id}", - 'U_FORUM' => "{$board_url}/viewforum.{$this->php_ext}?f={$this->item_parent_id}", - 'U_STOP_WATCHING_FORUM' => "{$board_url}/viewforum.{$this->php_ext}?uid={$this->user_id}&f={$this->item_parent_id}&unwatch=forum", - ); - } - - /** - * Get the url to this item - * - * @return string URL - */ - public function get_url() - { - return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "f={$this->item_parent_id}&t={$this->item_id}"); - } - - /** - * Users needed to query before this notification can be displayed - * - * @return array Array of user_ids - */ - public function users_to_query() - { - return array($this->get_data('poster_id')); - } - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $post Post data from submit_post - * @param array $notify_users Notify users list - * Formated from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($post, $notify_users) - { - if (!count($notify_users) || !$this->inherit_read_status) - { - return array(); - } - - $tracking_data = array(); - $sql = 'SELECT user_id, mark_time FROM ' . TOPICS_TRACK_TABLE . ' - WHERE topic_id = ' . (int) $post['topic_id'] . ' - AND ' . $this->db->sql_in_set('user_id', array_keys($notify_users)); - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - $tracking_data[$row['user_id']] = $row['mark_time']; - } - $this->db->sql_freeresult($result); - - return $tracking_data; - } - - /** - * {@inheritdoc} - */ - public function create_insert_array($post, $pre_create_data = array()) - { - $this->set_data('poster_id', $post['poster_id']); - - $this->set_data('topic_title', $post['topic_title']); - - $this->set_data('post_username', (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : '')); - - $this->set_data('forum_name', $post['forum_name']); - - $this->notification_time = $post['post_time']; - - // Topics can be "read" before they are public (while awaiting approval). - // Make sure that if the user has read the topic, it's marked as read in the notification - if ($this->inherit_read_status && isset($pre_create_data[$this->user_id]) && $pre_create_data[$this->user_id] >= $this->notification_time) - { - $this->notification_read = true; - } - - parent::create_insert_array($post, $pre_create_data); - } -} diff --git a/install/update/old/phpbb/notification/type/type_interface.php b/install/update/old/phpbb/notification/type/type_interface.php deleted file mode 100644 index f9f832b..0000000 --- a/install/update/old/phpbb/notification/type/type_interface.php +++ /dev/null @@ -1,218 +0,0 @@ - -* @license 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\type; - -/** -* Base notifications interface -*/ -interface type_interface -{ - /** - * Get notification type name - * - * @return string - */ - public function get_type(); - - /** - * Set initial data from the database - * - * @param array $data Row directly from the database - */ - public function set_initial_data($data); - - /** - * Get the id of the item - * - * @param array $type_data The type specific data - */ - static public function get_item_id($type_data); - - /** - * Get the id of the parent - * - * @param array $type_data The type specific 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) - * - * @return bool True/False whether or not this is available to the user - */ - public function is_available(); - - /** - * Find the users who want to receive notifications - * - * @param array $type_data The type specific data - * @param array $options Options for finding users for notification - * ignore_users => array of users and user types that should not receive notifications from this type because they've already been notified - * e.g.: array(2 => array(''), 3 => array('', 'email'), ...) - * - * @return array - */ - public function find_users_for_notification($type_data, $options); - - /** - * Users needed to query before this notification can be displayed - * - * @return array Array of user_ids - */ - public function users_to_query(); - - /** - * Get the special items to load - * - * @return array Data will be combined sent to load_special() so you can run a single query and get data required for this notification type - */ - public function get_load_special(); - - /** - * Load the special items - * - * @param array $data Data from get_load_special() - * @param array $notifications Array of notifications (key is notification_id, value is the notification objects) - */ - public function load_special($data, $notifications); - - /** - * Get the CSS style class of the notification - * - * @return string - */ - public function get_style_class(); - - /** - * Get the HTML formatted title of this notification - * - * @return string - */ - public function get_title(); - - /** - * Get the HTML formatted reference of the notification - * - * @return string - */ - public function get_reference(); - - /** - * Get the forum of the notification reference - * - * @return string - */ - public function get_forum(); - - /** - * Get the url to this item - * - * @return string URL - */ - public function get_url(); - - /** - * Get the url to redirect after the item has been marked as read - * - * @return string URL - */ - public function get_redirect_url(); - - /** - * URL to unsubscribe to this notification - * - * @param string|bool $method Method name to unsubscribe from (email|jabber|etc), False to unsubscribe from all notifications for this item - */ - public function get_unsubscribe_url($method); - - /** - * Get the user's avatar (the user who caused the notification typically) - * - * @return string - */ - public function get_avatar(); - - /** - * Prepare to output the notification to the template - */ - public function prepare_for_display(); - - /** - * Get email template - * - * @return string|bool - */ - public function get_email_template(); - - /** - * Get email template variables - * - * @return array - */ - public function get_email_template_variables(); - - /** - * Pre create insert array function - * This allows you to perform certain actions, like run a query - * and load data, before create_insert_array() is run. The data - * returned from this function will be sent to create_insert_array(). - * - * @param array $type_data The type specific data - * @param array $notify_users Notify users list - * Formated from find_users_for_notification() - * @return array Whatever you want to send to create_insert_array(). - */ - public function pre_create_insert_array($type_data, $notify_users); - - /** - * Function for preparing the data for insertion in an SQL query - * - * @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 get_insert_array(); - - /** - * Function for preparing the data for update in an SQL query - * (The service handles insertion) - * - * @param array $type_data Data unique to this notification type - * - * @return array Array of data ready to be updated in the database - */ - public function create_update_array($type_data); - - /** - * Mark this item read - * - * @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 = false); - - /** - * Mark this item unread - * - * @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 = false); -} diff --git a/install/update/old/phpbb/passwords/manager.php b/install/update/old/phpbb/passwords/manager.php deleted file mode 100644 index fad76a9..0000000 --- a/install/update/old/phpbb/passwords/manager.php +++ /dev/null @@ -1,407 +0,0 @@ - -* @license 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; - -class manager -{ - /** - * Default hashing method - */ - protected $type = false; - - /** - * Hashing algorithm type map - * Will be used to map hash prefix to type - */ - protected $type_map = false; - - /** - * Service collection of hashing algorithms - * Needs to be public for passwords helper - */ - public $algorithms = false; - - /** - * Password convert flag. Signals that password should be converted - */ - public $convert_flag = false; - - /** - * Passwords helper - * @var \phpbb\passwords\helper - */ - protected $helper; - - /** - * phpBB configuration - * @var \phpbb\config\config - */ - 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 - */ - 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; - } - - /** - * 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); - } - } - - /** - * Register default type - * Will register the first supported type from the list of default types - * - * @param array $defaults List of default types in order from first to - * use to last to use - */ - protected function register_default_type($defaults) - { - foreach ($defaults as $type) - { - if ($this->algorithms[$type]->is_supported()) - { - $this->type = $this->algorithms[$type]->get_prefix(); - break; - } - } - } - - /** - * Fill algorithm type map - * - * @param \phpbb\di\service_collection $hashing_algorithms - */ - protected function fill_type_map($hashing_algorithms) - { - foreach ($hashing_algorithms as $algorithm) - { - if (!isset($this->type_map[$algorithm->get_prefix()])) - { - $this->type_map[$algorithm->get_prefix()] = $algorithm; - } - } - $this->algorithms = $hashing_algorithms; - } - - /** - * Get the algorithm specified by a specific prefix - * - * @param string $prefix Password hash prefix - * - * @return object|bool The hash type object or false if prefix is not - * supported - */ - protected function get_algorithm($prefix) - { - if (isset($this->type_map[$prefix])) - { - return $this->type_map[$prefix]; - } - else - { - return false; - } - } - - /** - * Detect the hash type of the supplied hash - * - * @param string $hash Password hash that should be checked - * - * @return object|bool The hash type object or false if the specified - * type is not supported - */ - public function detect_algorithm($hash) - { - /* - * preg_match() will also show hashing algos like $2a\H$, which - * is a combination of bcrypt and phpass. Legacy algorithms - * like md5 will not be matched by this and need to be treated - * differently. - */ - if (!preg_match('#^\$([a-zA-Z0-9\\\]*?)\$#', $hash, $match)) - { - 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 && strpos($match[1], '\\') !== false) - { - $hash_types = explode('\\', $match[1]); - $return_ary = array(); - foreach ($hash_types as $type) - { - // we do not support the same hashing - // algorithm more than once - if (isset($return_ary[$type])) - { - return false; - } - - $return_ary[$type] = $this->get_algorithm('$' . $type . '$'); - - if (empty($return_ary[$type])) - { - return false; - } - } - return $return_ary; - } - - // get_algorithm() will automatically return false if prefix - // is not supported - return $this->get_algorithm($match[0]); - } - - /** - * Hash supplied password - * - * @param string $password Password that should be hashed - * @param string $type Hash type. Will default to standard hash type if - * none is supplied - * @return string|bool Password hash of supplied password or false if - * if something went wrong during hashing - */ - public function hash($password, $type = '') - { - if (strlen($password) > 4096) - { - // If the password is too huge, we will simply reject it - // and not let the server try to hash it. - 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])) - { - $type = $this->algorithms[$type]->get_prefix(); - } - - $type = ($type === '') ? $this->type : $type; - - if (is_array($type)) - { - return $this->combined_hash_password($password, $type); - } - - if (isset($this->type_map[$type])) - { - $hashing_algorithm = $this->type_map[$type]; - } - else - { - return false; - } - - return $hashing_algorithm->hash($password); - } - - /** - * Check supplied password against hash and set convert_flag if password - * needs to be converted to different format (preferrably newer one) - * - * @param string $password Password that should be checked - * @param string $hash Stored hash - * @param array $user_row User's row in users table - * @return string|bool True if password is correct, false if not - */ - public function check($password, $hash, $user_row = array()) - { - if (strlen($password) > 4096) - { - // If the password is too huge, we will simply reject it - // and not let the server try to hash it. - return false; - } - - // Empty hashes can't be checked - if (empty($hash)) - { - 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) - { - // Still check MD5 hashes as that is what the installer - // will default to for the admin user - return $this->get_algorithm('$H$')->check($password, $hash); - } - - // Multiple hash passes needed - if (is_array($stored_hash_type)) - { - $correct = $this->check_combined_hash($password, $stored_hash_type, $hash); - $this->convert_flag = ($correct === true) ? true : false; - return $correct; - } - - if ($stored_hash_type->get_prefix() !== $this->type) - { - $this->convert_flag = true; - } - else - { - 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$ - if ($stored_hash_type->get_prefix() === '$CP$') - { - // Remove $CP$ prefix for proper checking - $hash = substr($hash, 4); - - foreach ($this->type_map as $algorithm) - { - if ($algorithm->is_legacy() && $algorithm->check($password, $hash, $user_row) === true) - { - return true; - } - } - } - - return $stored_hash_type->check($password, $hash); - } - - /** - * Create combined hash from already hashed password - * - * @param string $password_hash Complete current password hash - * @param string $type Type of the hashing algorithm the password hash - * should be combined with - * @return string|bool Combined password hash if combined hashing was - * successful, else false - */ - public function combined_hash_password($password_hash, $type) - { - $this->initialize(); - - $data = array( - 'prefix' => '$', - 'settings' => '$', - ); - $hash_settings = $this->helper->get_combined_hash_settings($password_hash); - $hash = $hash_settings[0]; - - // Put settings of current hash into data array - $stored_hash_type = $this->detect_algorithm($password_hash); - $this->helper->combine_hash_output($data, 'prefix', $stored_hash_type->get_prefix()); - $this->helper->combine_hash_output($data, 'settings', $stored_hash_type->get_settings_only($password_hash)); - - // Hash current hash with the defined types - foreach ($type as $cur_type) - { - if (isset($this->algorithms[$cur_type])) - { - $new_hash_type = $this->algorithms[$cur_type]; - } - else - { - $new_hash_type = $this->get_algorithm($cur_type); - } - - if (!$new_hash_type) - { - return false; - } - - $new_hash = $new_hash_type->hash(str_replace($stored_hash_type->get_settings_only($password_hash), '', $hash)); - $this->helper->combine_hash_output($data, 'prefix', $new_hash_type->get_prefix()); - $this->helper->combine_hash_output($data, 'settings', substr(str_replace('$', '\\', $new_hash_type->get_settings_only($new_hash, true)), 0)); - $hash = str_replace($new_hash_type->get_settings_only($new_hash), '', $this->helper->obtain_hash_only($new_hash)); - } - return $this->helper->combine_hash_output($data, 'hash', $hash); - } - - /** - * Check combined password hash against the supplied password - * - * @param string $password Password entered by user - * @param array $stored_hash_type An array containing the hash types - * as described by stored password hash - * @param string $hash Stored password hash - * - * @return bool True if password is correct, false if not - */ - public function check_combined_hash($password, $stored_hash_type, $hash) - { - $i = 0; - $data = array( - 'prefix' => '$', - 'settings' => '$', - ); - $hash_settings = $this->helper->get_combined_hash_settings($hash); - foreach ($stored_hash_type as $key => $hash_type) - { - $rebuilt_hash = $this->helper->rebuild_hash($hash_type->get_prefix(), $hash_settings[$i]); - $this->helper->combine_hash_output($data, 'prefix', $key); - $this->helper->combine_hash_output($data, 'settings', $hash_settings[$i]); - $cur_hash = $hash_type->hash($password, $rebuilt_hash); - $password = str_replace($rebuilt_hash, '', $cur_hash); - $i++; - } - return ($hash === $this->helper->combine_hash_output($data, 'hash', $password)); - } -} diff --git a/install/update/old/phpbb/permissions.php b/install/update/old/phpbb/permissions.php deleted file mode 100644 index 7697884..0000000 --- a/install/update/old/phpbb/permissions.php +++ /dev/null @@ -1,364 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -class permissions -{ - /** - * Event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Constructor - * - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher - * @param \phpbb\user $user User Object - */ - public function __construct(\phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\user $user) - { - $this->dispatcher = $phpbb_dispatcher; - $this->user = $user; - - $categories = $this->categories; - $types = $this->types; - $permissions = $this->permissions; - - /** - * Allows to specify additional permission categories, types and permissions - * - * @event core.permissions - * @var array types Array with permission types (a_, u_, m_, etc.) - * @var array categories Array with permission categories (pm, post, settings, misc, etc.) - * @var array permissions Array with permissions. Each Permission has the following layout: - * '' => array( - * 'lang' => 'Language Key with a Short description', // Optional, if not set, - * // the permissions identifier '' is used with - * // all uppercase. - * 'cat' => 'Identifier of the category, the permission should be displayed in', - * ), - * Example: - * 'u_viewprofile' => array( - * 'lang' => 'ACL_U_VIEWPROFILE', - * 'cat' => 'profile', - * ), - * @since 3.1.0-a1 - */ - $vars = array('types', 'categories', 'permissions'); - extract($phpbb_dispatcher->trigger_event('core.permissions', compact($vars))); - - $this->categories = $categories; - $this->types = $types; - $this->permissions = $permissions; - } - - /** - * Returns an array with all the permission categories (pm, post, settings, misc, etc.) - * - * @return array Layout: cat-identifier => Language key - */ - public function get_categories() - { - return $this->categories; - } - - /** - * Returns the language string of a permission category - * - * @param string $category Identifier of the category - * @return string Language string - */ - public function get_category_lang($category) - { - return $this->user->lang($this->categories[$category]); - } - - /** - * Returns an array with all the permission types (a_, u_, m_, etc.) - * - * @return array Layout: type-identifier => Language key - */ - public function get_types() - { - return $this->types; - } - - /** - * Returns the language string of a permission type - * - * @param string $type Identifier of the type - * @param mixed $scope Scope of the type (should be 'global', 'local' or false) - * @return string Language string - */ - public function get_type_lang($type, $scope = false) - { - if ($scope && isset($this->types[$scope][$type])) - { - $lang_key = $this->types[$scope][$type]; - } - else if (isset($this->types[$type])) - { - $lang_key = $this->types[$type]; - } - else - { - $lang_key = 'ACL_TYPE_' . strtoupper(($scope) ? $scope . '_' . $type : $type); - } - - return $this->user->lang($lang_key); - } - - /** - * Returns an array with all the permissions. - * Each Permission has the following layout: - * '' => array( - * 'lang' => 'Language Key with a Short description', // Optional, if not set, - * // the permissions identifier '' is used with - * // all uppercase. - * 'cat' => 'Identifier of the category, the permission should be displayed in', - * ), - * Example: - * 'u_viewprofile' => array( - * 'lang' => 'ACL_U_VIEWPROFILE', - * 'cat' => 'profile', - * ), - * - * @return array - */ - public function get_permissions() - { - return $this->permissions; - } - - /** - * Returns the category of a permission - * - * @param string $permission Identifier of the permission - * @return string Returns the category identifier of the permission - */ - public function get_permission_category($permission) - { - return (isset($this->permissions[$permission]['cat'])) ? $this->permissions[$permission]['cat'] : 'misc'; - } - - /** - * Checks if a category has been defined - * - * @param string $category Identifier of the category - * @return bool True if the category is defined, false otherwise - */ - public function category_defined($category) - { - return isset($this->categories[$category]); - } - - /** - * Checks if a permission has been defined - * - * @param string $permission Identifier of the permission - * @return bool True if the permission is defined, false otherwise - */ - public function permission_defined($permission) - { - return isset($this->permissions[$permission]); - } - - /** - * Returns the language string of a permission - * - * @param string $permission Identifier of the permission - * @return string Language string - */ - public function get_permission_lang($permission) - { - return (isset($this->permissions[$permission]['lang'])) ? $this->user->lang($this->permissions[$permission]['lang']) : $this->user->lang('ACL_' . strtoupper($permission)); - } - - protected $types = array( - 'u_' => 'ACL_TYPE_U_', - 'a_' => 'ACL_TYPE_A_', - 'm_' => 'ACL_TYPE_M_', - 'f_' => 'ACL_TYPE_F_', - 'global' => array( - 'm_' => 'ACL_TYPE_GLOBAL_M_', - ), - ); - - protected $categories = array( - 'actions' => 'ACL_CAT_ACTIONS', - 'content' => 'ACL_CAT_CONTENT', - 'forums' => 'ACL_CAT_FORUMS', - 'misc' => 'ACL_CAT_MISC', - 'permissions' => 'ACL_CAT_PERMISSIONS', - 'pm' => 'ACL_CAT_PM', - 'polls' => 'ACL_CAT_POLLS', - 'post' => 'ACL_CAT_POST', - 'post_actions' => 'ACL_CAT_POST_ACTIONS', - 'posting' => 'ACL_CAT_POSTING', - 'profile' => 'ACL_CAT_PROFILE', - 'settings' => 'ACL_CAT_SETTINGS', - 'topic_actions' => 'ACL_CAT_TOPIC_ACTIONS', - 'user_group' => 'ACL_CAT_USER_GROUP', - ); - - protected $permissions = array( - // User Permissions - 'u_viewprofile' => array('lang' => 'ACL_U_VIEWPROFILE', 'cat' => 'profile'), - 'u_chgname' => array('lang' => 'ACL_U_CHGNAME', 'cat' => 'profile'), - 'u_chgpasswd' => array('lang' => 'ACL_U_CHGPASSWD', 'cat' => 'profile'), - 'u_chgemail' => array('lang' => 'ACL_U_CHGEMAIL', 'cat' => 'profile'), - 'u_chgavatar' => array('lang' => 'ACL_U_CHGAVATAR', 'cat' => 'profile'), - 'u_chggrp' => array('lang' => 'ACL_U_CHGGRP', 'cat' => 'profile'), - 'u_chgprofileinfo' => array('lang' => 'ACL_U_CHGPROFILEINFO', 'cat' => 'profile'), - - 'u_attach' => array('lang' => 'ACL_U_ATTACH', 'cat' => 'post'), - 'u_download' => array('lang' => 'ACL_U_DOWNLOAD', 'cat' => 'post'), - '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_sendpm' => array('lang' => 'ACL_U_SENDPM', 'cat' => 'pm'), - 'u_masspm' => array('lang' => 'ACL_U_MASSPM', 'cat' => 'pm'), - 'u_masspm_group'=> array('lang' => 'ACL_U_MASSPM_GROUP', 'cat' => 'pm'), - 'u_readpm' => array('lang' => 'ACL_U_READPM', 'cat' => 'pm'), - 'u_pm_edit' => array('lang' => 'ACL_U_PM_EDIT', 'cat' => 'pm'), - 'u_pm_delete' => array('lang' => 'ACL_U_PM_DELETE', 'cat' => 'pm'), - 'u_pm_forward' => array('lang' => 'ACL_U_PM_FORWARD', 'cat' => 'pm'), - 'u_pm_emailpm' => array('lang' => 'ACL_U_PM_EMAILPM', 'cat' => 'pm'), - 'u_pm_printpm' => array('lang' => 'ACL_U_PM_PRINTPM', 'cat' => 'pm'), - 'u_pm_attach' => array('lang' => 'ACL_U_PM_ATTACH', 'cat' => 'pm'), - 'u_pm_download' => array('lang' => 'ACL_U_PM_DOWNLOAD', 'cat' => 'pm'), - 'u_pm_bbcode' => array('lang' => 'ACL_U_PM_BBCODE', 'cat' => 'pm'), - 'u_pm_smilies' => array('lang' => 'ACL_U_PM_SMILIES', 'cat' => 'pm'), - 'u_pm_img' => array('lang' => 'ACL_U_PM_IMG', 'cat' => 'pm'), - 'u_pm_flash' => array('lang' => 'ACL_U_PM_FLASH', 'cat' => 'pm'), - - 'u_sendemail' => array('lang' => 'ACL_U_SENDEMAIL', 'cat' => 'misc'), - 'u_sendim' => array('lang' => 'ACL_U_SENDIM', 'cat' => 'misc'), - 'u_ignoreflood' => array('lang' => 'ACL_U_IGNOREFLOOD', 'cat' => 'misc'), - 'u_hideonline' => array('lang' => 'ACL_U_HIDEONLINE', 'cat' => 'misc'), - 'u_viewonline' => array('lang' => 'ACL_U_VIEWONLINE', 'cat' => 'misc'), - 'u_search' => array('lang' => 'ACL_U_SEARCH', 'cat' => 'misc'), - - // 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'), - 'f_print' => array('lang' => 'ACL_F_PRINT', 'cat' => 'actions'), - 'f_email' => array('lang' => 'ACL_F_EMAIL', 'cat' => 'actions'), - 'f_bump' => array('lang' => 'ACL_F_BUMP', 'cat' => 'actions'), - 'f_user_lock' => array('lang' => 'ACL_F_USER_LOCK', 'cat' => 'actions'), - 'f_download' => array('lang' => 'ACL_F_DOWNLOAD', 'cat' => 'actions'), - 'f_report' => array('lang' => 'ACL_F_REPORT', 'cat' => 'actions'), - - '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'), - 'f_softdelete' => array('lang' => 'ACL_F_SOFTDELETE', 'cat' => 'post'), - 'f_ignoreflood' => array('lang' => 'ACL_F_IGNOREFLOOD', 'cat' => 'post'), - 'f_postcount' => array('lang' => 'ACL_F_POSTCOUNT', 'cat' => 'post'), - 'f_noapprove' => array('lang' => 'ACL_F_NOAPPROVE', 'cat' => 'post'), - - 'f_attach' => array('lang' => 'ACL_F_ATTACH', 'cat' => 'content'), - 'f_icons' => array('lang' => 'ACL_F_ICONS', 'cat' => 'content'), - 'f_bbcode' => array('lang' => 'ACL_F_BBCODE', 'cat' => 'content'), - 'f_flash' => array('lang' => 'ACL_F_FLASH', 'cat' => 'content'), - 'f_img' => array('lang' => 'ACL_F_IMG', 'cat' => 'content'), - 'f_sigs' => array('lang' => 'ACL_F_SIGS', 'cat' => 'content'), - 'f_smilies' => array('lang' => 'ACL_F_SMILIES', 'cat' => 'content'), - - 'f_poll' => array('lang' => 'ACL_F_POLL', 'cat' => 'polls'), - 'f_vote' => array('lang' => 'ACL_F_VOTE', 'cat' => 'polls'), - 'f_votechg' => array('lang' => 'ACL_F_VOTECHG', 'cat' => 'polls'), - - // Moderator Permissions - 'm_edit' => array('lang' => 'ACL_M_EDIT', 'cat' => 'post_actions'), - 'm_delete' => array('lang' => 'ACL_M_DELETE', 'cat' => 'post_actions'), - 'm_approve' => array('lang' => 'ACL_M_APPROVE', 'cat' => 'post_actions'), - 'm_report' => array('lang' => 'ACL_M_REPORT', 'cat' => 'post_actions'), - 'm_chgposter' => array('lang' => 'ACL_M_CHGPOSTER', 'cat' => 'post_actions'), - 'm_info' => array('lang' => 'ACL_M_INFO', 'cat' => 'post_actions'), - 'm_softdelete' => array('lang' => 'ACL_M_SOFTDELETE', 'cat' => 'post_actions'), - - 'm_move' => array('lang' => 'ACL_M_MOVE', 'cat' => 'topic_actions'), - 'm_lock' => array('lang' => 'ACL_M_LOCK', 'cat' => 'topic_actions'), - 'm_split' => array('lang' => 'ACL_M_SPLIT', 'cat' => 'topic_actions'), - 'm_merge' => array('lang' => 'ACL_M_MERGE', 'cat' => 'topic_actions'), - - 'm_warn' => array('lang' => 'ACL_M_WARN', 'cat' => 'misc'), - 'm_pm_report' => array('lang' => 'ACL_M_PM_REPORT', 'cat' => 'misc'), - 'm_ban' => array('lang' => 'ACL_M_BAN', 'cat' => 'misc'), - - // Admin Permissions - 'a_board' => array('lang' => 'ACL_A_BOARD', 'cat' => 'settings'), - 'a_server' => array('lang' => 'ACL_A_SERVER', 'cat' => 'settings'), - 'a_jabber' => array('lang' => 'ACL_A_JABBER', 'cat' => 'settings'), - 'a_phpinfo' => array('lang' => 'ACL_A_PHPINFO', 'cat' => 'settings'), - - 'a_forum' => array('lang' => 'ACL_A_FORUM', 'cat' => 'forums'), - 'a_forumadd' => array('lang' => 'ACL_A_FORUMADD', 'cat' => 'forums'), - 'a_forumdel' => array('lang' => 'ACL_A_FORUMDEL', 'cat' => 'forums'), - 'a_prune' => array('lang' => 'ACL_A_PRUNE', 'cat' => 'forums'), - - 'a_icons' => array('lang' => 'ACL_A_ICONS', 'cat' => 'posting'), - 'a_words' => array('lang' => 'ACL_A_WORDS', 'cat' => 'posting'), - 'a_bbcode' => array('lang' => 'ACL_A_BBCODE', 'cat' => 'posting'), - 'a_attach' => array('lang' => 'ACL_A_ATTACH', 'cat' => 'posting'), - - 'a_user' => array('lang' => 'ACL_A_USER', 'cat' => 'user_group'), - 'a_userdel' => array('lang' => 'ACL_A_USERDEL', 'cat' => 'user_group'), - 'a_group' => array('lang' => 'ACL_A_GROUP', 'cat' => 'user_group'), - 'a_groupadd' => array('lang' => 'ACL_A_GROUPADD', 'cat' => 'user_group'), - 'a_groupdel' => array('lang' => 'ACL_A_GROUPDEL', 'cat' => 'user_group'), - 'a_ranks' => array('lang' => 'ACL_A_RANKS', 'cat' => 'user_group'), - 'a_profile' => array('lang' => 'ACL_A_PROFILE', 'cat' => 'user_group'), - 'a_names' => array('lang' => 'ACL_A_NAMES', 'cat' => 'user_group'), - 'a_ban' => array('lang' => 'ACL_A_BAN', 'cat' => 'user_group'), - - 'a_viewauth' => array('lang' => 'ACL_A_VIEWAUTH', 'cat' => 'permissions'), - 'a_authgroups' => array('lang' => 'ACL_A_AUTHGROUPS', 'cat' => 'permissions'), - 'a_authusers' => array('lang' => 'ACL_A_AUTHUSERS', 'cat' => 'permissions'), - 'a_fauth' => array('lang' => 'ACL_A_FAUTH', 'cat' => 'permissions'), - 'a_mauth' => array('lang' => 'ACL_A_MAUTH', 'cat' => 'permissions'), - 'a_aauth' => array('lang' => 'ACL_A_AAUTH', 'cat' => 'permissions'), - 'a_uauth' => array('lang' => 'ACL_A_UAUTH', 'cat' => 'permissions'), - 'a_roles' => array('lang' => 'ACL_A_ROLES', 'cat' => 'permissions'), - 'a_switchperm' => array('lang' => 'ACL_A_SWITCHPERM', 'cat' => 'permissions'), - - 'a_styles' => array('lang' => 'ACL_A_STYLES', 'cat' => 'misc'), - 'a_extensions' => array('lang' => 'ACL_A_EXTENSIONS', 'cat' => 'misc'), - 'a_viewlogs' => array('lang' => 'ACL_A_VIEWLOGS', 'cat' => 'misc'), - 'a_clearlogs' => array('lang' => 'ACL_A_CLEARLOGS', 'cat' => 'misc'), - 'a_modules' => array('lang' => 'ACL_A_MODULES', 'cat' => 'misc'), - 'a_language' => array('lang' => 'ACL_A_LANGUAGE', 'cat' => 'misc'), - 'a_email' => array('lang' => 'ACL_A_EMAIL', 'cat' => 'misc'), - 'a_bots' => array('lang' => 'ACL_A_BOTS', 'cat' => 'misc'), - 'a_reasons' => array('lang' => 'ACL_A_REASONS', 'cat' => 'misc'), - 'a_backup' => array('lang' => 'ACL_A_BACKUP', 'cat' => 'misc'), - 'a_search' => array('lang' => 'ACL_A_SEARCH', 'cat' => 'misc'), - ); -} diff --git a/install/update/old/phpbb/plupload/plupload.php b/install/update/old/phpbb/plupload/plupload.php deleted file mode 100644 index eb698fb..0000000 --- a/install/update/old/phpbb/plupload/plupload.php +++ /dev/null @@ -1,402 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\plupload; - -/** -* This class handles all server-side plupload functions -*/ -class plupload -{ - /** - * @var string - */ - protected $phpbb_root_path; - - /** - * @var \phpbb\config\config - */ - protected $config; - - /** - * @var \phpbb\request\request_interface - */ - protected $request; - - /** - * @var \phpbb\user - */ - protected $user; - - /** - * @var \bantu\IniGetWrapper\IniGetWrapper - */ - protected $php_ini; - - /** - * @var \phpbb\mimetype\guesser - */ - protected $mimetype_guesser; - - /** - * Final destination for uploaded files, i.e. the "files" directory. - * @var string - */ - protected $upload_directory; - - /** - * Temporary upload directory for plupload uploads. - * @var string - */ - protected $temporary_directory; - - /** - * Constructor. - * - * @param string $phpbb_root_path - * @param \phpbb\config\config $config - * @param \phpbb\request\request_interface $request - * @param \phpbb\user $user - * @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, \bantu\IniGetWrapper\IniGetWrapper $php_ini, \phpbb\mimetype\guesser $mimetype_guesser) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->config = $config; - $this->request = $request; - $this->user = $user; - $this->php_ini = $php_ini; - $this->mimetype_guesser = $mimetype_guesser; - - $this->set_default_directories(); - } - - /** - * Plupload allows for chunking so we must check for that and assemble - * the whole file first before performing any checks on it. - * - * @param string $form_name The name of the file element in the upload form - * - * @return array|null null if there are no chunks to piece together - * otherwise array containing the path to the - * pieced-together file and its size - */ - public function handle_upload($form_name) - { - $chunks_expected = $this->request->variable('chunks', 0); - - // If chunking is disabled or we are not using plupload, just return - // and handle the file as usual - if ($chunks_expected < 2) - { - return; - } - - $file_name = $this->request->variable('name', ''); - $chunk = $this->request->variable('chunk', 0); - - $this->user->add_lang('plupload'); - $this->prepare_temporary_directory(); - - $file_path = $this->temporary_filepath($file_name); - $this->integrate_uploaded_file($form_name, $chunk, $file_path); - - // If we are done with all the chunks, strip the .part suffix and then - // handle the resulting file as normal, otherwise die and await the - // next chunk. - if ($chunk == $chunks_expected - 1) - { - rename("{$file_path}.part", $file_path); - - // Reset upload directories to defaults once completed - $this->set_default_directories(); - - // Need to modify some of the $_FILES values to reflect the new file - return array( - 'tmp_name' => $file_path, - 'name' => $this->request->variable('real_filename', '', true), - 'size' => filesize($file_path), - 'type' => $this->mimetype_guesser->guess($file_path, $file_name), - ); - } - else - { - $json_response = new \phpbb\json_response(); - $json_response->send(array( - 'jsonrpc' => '2.0', - 'id' => 'id', - 'result' => null, - )); - } - } - - /** - * Fill in the plupload configuration options in the template - * - * @param \phpbb\cache\service $cache - * @param \phpbb\template\template $template - * @param string $s_action The URL to submit the POST data to - * @param int $forum_id The ID of the forum - * @param int $max_files Maximum number of files allowed. 0 for unlimited. - * - * @return null - */ - public function configure(\phpbb\cache\service $cache, \phpbb\template\template $template, $s_action, $forum_id, $max_files) - { - $filters = $this->generate_filter_string($cache, $forum_id); - $chunk_size = $this->get_chunk_size(); - $resize = $this->generate_resize_string(); - - $template->assign_vars(array( - 'S_RESIZE' => $resize, - 'S_PLUPLOAD' => true, - 'FILTERS' => $filters, - 'CHUNK_SIZE' => $chunk_size, - 'S_PLUPLOAD_URL' => htmlspecialchars_decode($s_action), - 'MAX_ATTACHMENTS' => $max_files, - 'ATTACH_ORDER' => ($this->config['display_order']) ? 'asc' : 'desc', - 'L_TOO_MANY_ATTACHMENTS' => $this->user->lang('TOO_MANY_ATTACHMENTS', $max_files), - )); - - $this->user->add_lang('plupload'); - } - - /** - * Checks whether the page request was sent by plupload or not - * - * @return bool - */ - public function is_active() - { - return $this->request->header('X-PHPBB-USING-PLUPLOAD', false); - } - - /** - * Returns whether the current HTTP request is a multipart request. - * - * @return bool - */ - public function is_multipart() - { - $content_type = $this->request->server('CONTENT_TYPE'); - - return strpos($content_type, 'multipart') === 0; - } - - /** - * Sends an error message back to the client via JSON response - * - * @param int $code The error code - * @param string $msg The translation string of the message to be sent - * - * @return null - */ - public function emit_error($code, $msg) - { - $json_response = new \phpbb\json_response(); - $json_response->send(array( - 'jsonrpc' => '2.0', - 'id' => 'id', - 'error' => array( - 'code' => $code, - 'message' => $this->user->lang($msg), - ), - )); - } - - /** - * 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 - */ - public function generate_filter_string(\phpbb\cache\service $cache, $forum_id) - { - $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; - } - - $filters = array(); - foreach ($groups as $group => $extensions) - { - $filters[] = sprintf( - "{title: '%s', extensions: '%s'}", - addslashes(ucfirst(strtolower($group))), - addslashes(implode(',', $extensions)) - ); - } - - return implode(',', $filters); - } - - /** - * Generates a string that is used to tell plupload to automatically resize - * files before uploading them. - * - * @return string - */ - public function generate_resize_string() - { - $resize = ''; - if ($this->config['img_max_height'] > 0 && $this->config['img_max_width'] > 0) - { - $resize = sprintf( - 'resize: {width: %d, height: %d, quality: 85},', - (int) $this->config['img_max_width'], - (int) $this->config['img_max_height'] - ); - } - - return $resize; - } - - /** - * 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 - */ - public function get_chunk_size() - { - $max = min( - $this->php_ini->getBytes('upload_max_filesize'), - $this->php_ini->getBytes('post_max_size'), - max(1, $this->php_ini->getBytes('memory_limit')), - $this->config['max_filesize'] - ); - - // Use half of the maximum possible to leave plenty of room for other - // POST data. - return floor($max / 2); - } - - protected function temporary_filepath($file_name) - { - // Must preserve the extension for plupload to work. - return sprintf( - '%s/%s_%s%s', - $this->temporary_directory, - $this->config['plupload_salt'], - md5($file_name), - \phpbb\files\filespec::get_extension($file_name) - ); - } - - /** - * Checks whether the chunk we are about to deal with was actually uploaded - * by PHP and actually exists, if not, it generates an error - * - * @param string $form_name The name of the file in the form data - * - * @return null - */ - protected function integrate_uploaded_file($form_name, $chunk, $file_path) - { - $is_multipart = $this->is_multipart(); - $upload = $this->request->file($form_name); - if ($is_multipart && (!isset($upload['tmp_name']) || !is_uploaded_file($upload['tmp_name']))) - { - $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED'); - } - - $tmp_file = $this->temporary_filepath($upload['tmp_name']); - - if (!phpbb_is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file)) - { - $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED'); - } - - $out = fopen("{$file_path}.part", $chunk == 0 ? 'wb' : 'ab'); - if (!$out) - { - $this->emit_error(102, 'PLUPLOAD_ERR_OUTPUT'); - } - - $in = fopen(($is_multipart) ? $tmp_file : 'php://input', 'rb'); - if (!$in) - { - $this->emit_error(101, 'PLUPLOAD_ERR_INPUT'); - } - - while ($buf = fread($in, 4096)) - { - fwrite($out, $buf); - } - - fclose($in); - fclose($out); - - if ($is_multipart) - { - unlink($tmp_file); - } - } - - /** - * Creates the temporary directory if it does not already exist. - * - * @return null - */ - protected function prepare_temporary_directory() - { - if (!file_exists($this->temporary_directory)) - { - mkdir($this->temporary_directory); - - copy( - $this->upload_directory . '/index.htm', - $this->temporary_directory . '/index.htm' - ); - } - } - - /** - * Sets the default directories for uploads - * - * @return null - */ - protected function set_default_directories() - { - $this->upload_directory = $this->phpbb_root_path . $this->config['upload_path']; - $this->temporary_directory = $this->upload_directory . '/plupload'; - } - - /** - * Sets the upload directories to the specified paths - * - * @param string $upload_directory Upload directory - * @param string $temporary_directory Temporary directory - * - * @return null - */ - public function set_upload_directories($upload_directory, $temporary_directory) - { - $this->upload_directory = $upload_directory; - $this->temporary_directory = $temporary_directory; - } -} diff --git a/install/update/old/phpbb/report/report_handler.php b/install/update/old/phpbb/report/report_handler.php deleted file mode 100644 index 854318c..0000000 --- a/install/update/old/phpbb/report/report_handler.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @license 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/install/update/old/phpbb/request/request.php b/install/update/old/phpbb/request/request.php deleted file mode 100644 index a0267d1..0000000 --- a/install/update/old/phpbb/request/request.php +++ /dev/null @@ -1,454 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\request; - -/** -* All application input is accessed through this class. -* -* It provides a method to disable access to input data through super globals. -* This should force MOD authors to read about data validation. -*/ -class request implements \phpbb\request\request_interface -{ - /** - * @var array The names of super global variables that this class should protect if super globals are disabled. - */ - protected $super_globals = array( - \phpbb\request\request_interface::POST => '_POST', - \phpbb\request\request_interface::GET => '_GET', - \phpbb\request\request_interface::REQUEST => '_REQUEST', - \phpbb\request\request_interface::COOKIE => '_COOKIE', - \phpbb\request\request_interface::SERVER => '_SERVER', - \phpbb\request\request_interface::FILES => '_FILES', - ); - - /** - * @var array Stores original contents of $_REQUEST array. - */ - protected $original_request = null; - - /** - * @var - */ - protected $super_globals_disabled = false; - - /** - * @var array An associative array that has the value of super global constants as keys and holds their data as values. - */ - protected $input; - - /** - * @var \phpbb\request\type_cast_helper_interface An instance of a type cast helper providing convenience methods for type conversions. - */ - protected $type_cast_helper; - - /** - * Initialises the request class, that means it stores all input data in {@link $input input} - * and then calls {@link \phpbb\request\deactivated_super_global \phpbb\request\deactivated_super_global} - */ - public function __construct(\phpbb\request\type_cast_helper_interface $type_cast_helper = null, $disable_super_globals = true) - { - if ($type_cast_helper) - { - $this->type_cast_helper = $type_cast_helper; - } - else - { - $this->type_cast_helper = new \phpbb\request\type_cast_helper(); - } - - foreach ($this->super_globals as $const => $super_global) - { - $this->input[$const] = isset($GLOBALS[$super_global]) ? $GLOBALS[$super_global] : array(); - } - - // simulate request_order = GP - $this->original_request = $this->input[\phpbb\request\request_interface::REQUEST]; - $this->input[\phpbb\request\request_interface::REQUEST] = $this->input[\phpbb\request\request_interface::POST] + $this->input[\phpbb\request\request_interface::GET]; - - if ($disable_super_globals) - { - $this->disable_super_globals(); - } - } - - /** - * Getter for $super_globals_disabled - * - * @return bool Whether super globals are disabled or not. - */ - public function super_globals_disabled() - { - return $this->super_globals_disabled; - } - - /** - * Disables access of super globals specified in $super_globals. - * This is achieved by overwriting the super globals with instances of {@link \phpbb\request\deactivated_super_global \phpbb\request\deactivated_super_global} - */ - public function disable_super_globals() - { - if (!$this->super_globals_disabled) - { - foreach ($this->super_globals as $const => $super_global) - { - unset($GLOBALS[$super_global]); - $GLOBALS[$super_global] = new \phpbb\request\deactivated_super_global($this, $super_global, $const); - } - - $this->super_globals_disabled = true; - } - } - - /** - * Enables access of super globals specified in $super_globals if they were disabled by {@link disable_super_globals disable_super_globals}. - * This is achieved by making the super globals point to the data stored within this class in {@link $input input}. - */ - public function enable_super_globals() - { - if ($this->super_globals_disabled) - { - foreach ($this->super_globals as $const => $super_global) - { - $GLOBALS[$super_global] = $this->input[$const]; - } - - $GLOBALS['_REQUEST'] = $this->original_request; - - $this->super_globals_disabled = false; - } - } - - /** - * This function allows overwriting or setting a value in one of the super global arrays. - * - * Changes which are performed on the super globals directly will not have any effect on the results of - * other methods this class provides. Using this function should be avoided if possible! It will - * consume twice the the amount of memory of the value - * - * @param string $var_name The name of the variable that shall be overwritten - * @param mixed $value The value which the variable shall contain. - * If this is null the variable will be unset. - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global shall be changed - */ - public function overwrite($var_name, $value, $super_global = \phpbb\request\request_interface::REQUEST) - { - if (!isset($this->super_globals[$super_global])) - { - return; - } - - // setting to null means unsetting - if ($value === null) - { - unset($this->input[$super_global][$var_name]); - if (!$this->super_globals_disabled()) - { - unset($GLOBALS[$this->super_globals[$super_global]][$var_name]); - } - } - else - { - $this->input[$super_global][$var_name] = $value; - if (!$this->super_globals_disabled()) - { - $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value; - } - } - } - - /** - * Central type safe input handling function. - * All variables in GET or POST requests should be retrieved through this function to maximise security. - * - * @param string|array $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global should be used - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ - public function variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST) - { - return $this->_variable($var_name, $default, $multibyte, $super_global, true); - } - - /** - * Get a variable, but without trimming strings. - * Same functionality as variable(), except does not run trim() on strings. - * This method should be used when handling passwords. - * - * @param string|array $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global should be used - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ - public function untrimmed_variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST) - { - return $this->_variable($var_name, $default, $multibyte, $super_global, false); - } - - /** - * {@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 - * whatever). - * - * @param string|array $var_name See \phpbb\request\request_interface::variable - * @param mixed $Default See \phpbb\request\request_interface::variable - * - * @return mixed The server variable value. - */ - public function server($var_name, $default = '') - { - $multibyte = true; - - if ($this->is_set($var_name, \phpbb\request\request_interface::SERVER)) - { - return $this->variable($var_name, $default, $multibyte, \phpbb\request\request_interface::SERVER); - } - else - { - $var = getenv($var_name); - $this->type_cast_helper->recursive_set_var($var, $default, $multibyte); - return $var; - } - } - - /** - * Shortcut method to retrieve the value of client HTTP headers. - * - * @param string|array $header_name The name of the header to retrieve. - * @param mixed $default See \phpbb\request\request_interface::variable - * - * @return mixed The header value. - */ - public function header($header_name, $default = '') - { - $var_name = 'HTTP_' . str_replace('-', '_', strtoupper($header_name)); - return $this->server($var_name, $default); - } - - /** - * Shortcut method to retrieve $_FILES variables - * - * @param string $form_name The name of the file input form element - * - * @return array The uploaded file's information or an empty array if the - * variable does not exist in _FILES. - */ - public function file($form_name) - { - return $this->variable($form_name, array('name' => 'none'), true, \phpbb\request\request_interface::FILES); - } - - /** - * Checks whether a certain variable was sent via POST. - * To make sure that a request was sent using POST you should call this function - * on at least one variable. - * - * @param string $name The name of the form variable which should have a - * _p suffix to indicate the check in the code that creates the form too. - * - * @return bool True if the variable was set in a POST request, false otherwise. - */ - public function is_set_post($name) - { - return $this->is_set($name, \phpbb\request\request_interface::POST); - } - - /** - * Checks whether a certain variable is set in one of the super global - * arrays. - * - * @param string $var Name of the variable - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies the super global which shall be checked - * - * @return bool True if the variable was sent as input - */ - public function is_set($var, $super_global = \phpbb\request\request_interface::REQUEST) - { - return isset($this->input[$super_global][$var]); - } - - /** - * Checks whether the current request is an AJAX request (XMLHttpRequest) - * - * @return bool True if the current request is an ajax request - */ - public function is_ajax() - { - return $this->header('X-Requested-With') == 'XMLHttpRequest'; - } - - /** - * Checks if the current request is happening over HTTPS. - * - * @return bool True if the request is secure. - */ - public function is_secure() - { - $https = $this->server('HTTPS'); - $https = $this->server('HTTP_X_FORWARDED_PROTO') === 'https' ? 'on' : $https; - return !empty($https) && $https !== 'off'; - } - - /** - * Returns all variable names for a given super global - * - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * The super global from which names shall be taken - * - * @return array All variable names that are set for the super global. - * Pay attention when using these, they are unsanitised! - */ - public function variable_names($super_global = \phpbb\request\request_interface::REQUEST) - { - if (!isset($this->input[$super_global])) - { - return array(); - } - - return array_keys($this->input[$super_global]); - } - - /** - * Helper function used by variable() and untrimmed_variable(). - * - * @param string|array $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global should be used - * @param bool $trim Indicates whether trim() should be applied to string values. - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ - protected function _variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST, $trim = true) - { - $var = $this->raw_variable($var_name, $default, $super_global); - - // 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 $var; - } - - $this->type_cast_helper->recursive_set_var($var, $default, $multibyte, $trim); - - return $var; - } - - /** - * {@inheritdoc} - */ - public function get_super_global($super_global = \phpbb\request\request_interface::REQUEST) - { - return $this->input[$super_global]; - } - - /** - * {@inheritdoc} - */ - public function escape($var, $multibyte) - { - if (is_array($var)) - { - $result = array(); - foreach ($var as $key => $value) - { - $this->type_cast_helper->set_var($key, $key, gettype($key), $multibyte); - $result[$key] = $this->escape($value, $multibyte); - } - $var = $result; - } - else - { - $this->type_cast_helper->set_var($var, $var, 'string', $multibyte); - } - - return $var; - } -} diff --git a/install/update/old/phpbb/request/request_interface.php b/install/update/old/phpbb/request/request_interface.php deleted file mode 100644 index 3bfa8bb..0000000 --- a/install/update/old/phpbb/request/request_interface.php +++ /dev/null @@ -1,177 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\request; - -/** -* An interface through which all application input can be accessed. -*/ -interface request_interface -{ - /**#@+ - * Constant identifying the super global with the same name. - */ - const POST = 0; - const GET = 1; - const REQUEST = 2; - const COOKIE = 3; - const SERVER = 4; - const FILES = 5; - /**#@-*/ - - /** - * This function allows overwriting or setting a value in one of the super global arrays. - * - * Changes which are performed on the super globals directly will not have any effect on the results of - * other methods this class provides. Using this function should be avoided if possible! It will - * consume twice the the amount of memory of the value - * - * @param string $var_name The name of the variable that shall be overwritten - * @param mixed $value The value which the variable shall contain. - * If this is null the variable will be unset. - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global shall be changed - */ - public function overwrite($var_name, $value, $super_global = \phpbb\request\request_interface::REQUEST); - - /** - * Central type safe input handling function. - * All variables in GET or POST requests should be retrieved through this function to maximise security. - * - * @param string|array $var_name The form variable's name from which data shall be retrieved. - * If the value is an array this may be an array of indizes which will give - * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") - * then specifying array("var", 1) as the name will return "a". - * @param mixed $default A default value that is returned if the variable was not set. - * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies which super global should be used - * - * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the - * the same as that of $default. If the variable is not set $default is returned. - */ - public function variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\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 - * @param mixed $default See \phpbb\request\request_interface::variable - * - * @return mixed The server variable value. - */ - public function server($var_name, $default = ''); - - /** - * Shortcut method to retrieve the value of client HTTP headers. - * - * @param string|array $header_name The name of the header to retrieve. - * @param mixed $default See \phpbb\request\request_interface::variable - * - * @return mixed The header value. - */ - public function header($var_name, $default = ''); - - /** - * Checks whether a certain variable was sent via POST. - * To make sure that a request was sent using POST you should call this function - * on at least one variable. - * - * @param string $name The name of the form variable which should have a - * _p suffix to indicate the check in the code that creates the form too. - * - * @return bool True if the variable was set in a POST request, false otherwise. - */ - public function is_set_post($name); - - /** - * Checks whether a certain variable is set in one of the super global - * arrays. - * - * @param string $var Name of the variable - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * Specifies the super global which shall be checked - * - * @return bool True if the variable was sent as input - */ - public function is_set($var, $super_global = \phpbb\request\request_interface::REQUEST); - - /** - * Checks whether the current request is an AJAX request (XMLHttpRequest) - * - * @return bool True if the current request is an ajax request - */ - public function is_ajax(); - - /** - * Checks if the current request is happening over HTTPS. - * - * @return bool True if the request is secure. - */ - public function is_secure(); - - /** - * Returns all variable names for a given super global - * - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * The super global from which names shall be taken - * - * @return array All variable names that are set for the super global. - * Pay attention when using these, they are unsanitised! - */ - public function variable_names($super_global = \phpbb\request\request_interface::REQUEST); - - /** - * Returns the original array of the requested super global - * - * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global - * The super global which will be returned - * - * @return array The original array of the requested super global. - */ - public function get_super_global($super_global = \phpbb\request\request_interface::REQUEST); - - /** - * Escape a string variable. - * - * @param mixed $value The contents to fill with - * @param bool $multibyte Indicates whether string values may contain UTF-8 characters. - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks. - * @return string|array - */ - public function escape($value, $multibyte); -} diff --git a/install/update/old/phpbb/request/type_cast_helper.php b/install/update/old/phpbb/request/type_cast_helper.php deleted file mode 100644 index 9124949..0000000 --- a/install/update/old/phpbb/request/type_cast_helper.php +++ /dev/null @@ -1,124 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\request; - -/** -* A helper class that provides convenience methods for type casting. -*/ -class type_cast_helper implements \phpbb\request\type_cast_helper_interface -{ - /** - * Set variable $result to a particular type. - * - * @param mixed &$result The variable to fill - * @param mixed $var The contents to fill with - * @param mixed $type The variable type. Will be used with {@link settype()} - * @param bool $multibyte Indicates whether string values may contain UTF-8 characters. - * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks. - * @param bool $trim Indicates whether trim() should be applied to string values. - * Default is true. - */ - public function set_var(&$result, $var, $type, $multibyte = false, $trim = true) - { - settype($var, $type); - $result = $var; - - if ($type == 'string') - { - $result = str_replace(array("\r\n", "\r", "\0"), array("\n", "\n", ''), $result); - - if ($trim) - { - $result = trim($result); - } - - $result = htmlspecialchars($result, ENT_COMPAT, 'UTF-8'); - - if ($multibyte) - { - $result = utf8_normalize_nfc($result); - } - - if (!empty($result)) - { - // Make sure multibyte characters are wellformed - if ($multibyte) - { - if (!preg_match('/^./u', $result)) - { - $result = ''; - } - } - else - { - // no multibyte, allow only ASCII (0-127) - $result = preg_replace('/[\x80-\xFF]/', '?', $result); - } - } - } - } - - /** - * Recursively sets a variable to a given type using {@link set_var set_var} - * - * @param string $var The value which shall be sanitised (passed by reference). - * @param mixed $default Specifies the type $var shall have. - * If it is an array and $var is not one, then an empty array is returned. - * Otherwise var is cast to the same type, and if $default is an array all - * keys and values are cast recursively using this function too. - * @param bool $multibyte Indicates whether string keys and values may contain UTF-8 characters. - * Default is false, causing all bytes outside the ASCII range (0-127) to - * be replaced with question marks. - * @param bool $trim Indicates whether trim() should be applied to string values. - * Default is true. - */ - public function recursive_set_var(&$var, $default, $multibyte, $trim = true) - { - if (is_array($var) !== is_array($default)) - { - $var = (is_array($default)) ? array() : $default; - return; - } - - if (!is_array($default)) - { - $type = gettype($default); - $this->set_var($var, $var, $type, $multibyte, $trim); - } - else - { - // make sure there is at least one key/value pair to use get the - // types from - if (empty($default)) - { - $var = array(); - return; - } - - list($default_key, $default_value) = each($default); - $key_type = gettype($default_key); - - $_var = $var; - $var = array(); - - foreach ($_var as $k => $v) - { - $this->set_var($k, $k, $key_type, $multibyte); - - $this->recursive_set_var($v, $default_value, $multibyte, $trim); - $var[$k] = $v; - } - } - } -} diff --git a/install/update/old/phpbb/search/fulltext_mysql.php b/install/update/old/phpbb/search/fulltext_mysql.php deleted file mode 100644 index 137ed74..0000000 --- a/install/update/old/phpbb/search/fulltext_mysql.php +++ /dev/null @@ -1,1227 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\search; - -/** -* Fulltext search for MySQL -*/ -class fulltext_mysql extends \phpbb\search\base -{ - /** - * Associative array holding index stats - * @var array - */ - protected $stats = array(); - - /** - * Holds the words entered by user, obtained by splitting the entered query on whitespace - * @var array - */ - protected $split_words = array(); - - /** - * Config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Database connection - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Associative array stores the min and max word length to be searched - * @var array - */ - protected $word_length = array(); - - /** - * Contains tidied search query. - * Operators are prefixed in search query and common words excluded - * @var string - */ - protected $search_query; - - /** - * Contains common words. - * Common words are words with length less/more than min/max length - * @var array - */ - protected $common_words = array(); - - /** - * Constructor - * Creates a new \phpbb\search\fulltext_mysql, which is used as a search backend - * - * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $phpEx PHP file extension - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\db\driver\driver_interface Database object - * @param \phpbb\user $user User object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - */ - public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) - { - $this->config = $config; - $this->db = $db; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->user = $user; - - $this->word_length = array('min' => $this->config['fulltext_mysql_min_word_len'], 'max' => $this->config['fulltext_mysql_max_word_len']); - - /** - * Load the UTF tools - */ - if (!function_exists('utf8_strlen')) - { - include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - } - - $error = false; - } - - /** - * Returns the name of this search backend to be displayed to administrators - * - * @return string Name - */ - public function get_name() - { - return 'MySQL Fulltext'; - } - - /** - * Returns the search_query - * - * @return string search query - */ - public function get_search_query() - { - return $this->search_query; - } - - /** - * Returns the common_words array - * - * @return array common words that are ignored by search backend - */ - public function get_common_words() - { - return $this->common_words; - } - - /** - * Returns the word_length array - * - * @return array min and max word length for searching - */ - public function get_word_length() - { - return $this->word_length; - } - - /** - * Checks for correct MySQL version and stores min/max word length in the config - * - * @return string|bool Language key of the error/incompatiblity occurred - */ - public function init() - { - if ($this->db->get_sql_layer() != 'mysql4' && $this->db->get_sql_layer() != 'mysqli') - { - return $this->user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE']; - } - - $result = $this->db->sql_query('SHOW TABLE STATUS LIKE \'' . POSTS_TABLE . '\''); - $info = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - $engine = ''; - if (isset($info['Engine'])) - { - $engine = $info['Engine']; - } - else if (isset($info['Type'])) - { - $engine = $info['Type']; - } - - $fulltext_supported = - $engine === 'MyISAM' || - // FULLTEXT is supported on InnoDB since MySQL 5.6.4 according to - // http://dev.mysql.com/doc/refman/5.6/en/innodb-storage-engine.html - // We also require https://bugs.mysql.com/bug.php?id=67004 to be - // fixed for proper overall operation. Hence we require 5.6.8. - $engine === 'InnoDB' && - phpbb_version_compare($this->db->sql_server_info(true), '5.6.8', '>='); - - if (!$fulltext_supported) - { - return $this->user->lang['FULLTEXT_MYSQL_NOT_SUPPORTED']; - } - - $sql = 'SHOW VARIABLES - LIKE \'ft\_%\''; - $result = $this->db->sql_query($sql); - - $mysql_info = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $mysql_info[$row['Variable_name']] = $row['Value']; - } - $this->db->sql_freeresult($result); - - $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']); - - return false; - } - - /** - * Splits keywords entered by a user into an array of words stored in $this->split_words - * Stores the tidied search query in $this->search_query - * - * @param string &$keywords Contains the keyword as entered by the user - * @param string $terms is either 'all' or 'any' - * @return bool false if no valid keywords were found and otherwise true - */ - public function split_keywords(&$keywords, $terms) - { - if ($terms == 'all') - { - $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#(^|\s)\+#', '#(^|\s)-#', '#(^|\s)\|#'); - $replace = array(' +', ' |', ' -', ' +', ' -', ' |'); - - $keywords = preg_replace($match, $replace, $keywords); - } - - // Filter out as above - $split_keywords = preg_replace("#[\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords))); - - // Split words - $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches); - $this->split_words = $matches[1]; - - // We limit the number of allowed keywords to minimize load on the database - if ($this->config['max_num_search_keywords'] && 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'], count($this->split_words))); - } - - // to allow phrase search, we need to concatenate quoted words - $tmp_split_words = array(); - $phrase = ''; - foreach ($this->split_words as $word) - { - if ($phrase) - { - $phrase .= ' ' . $word; - if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1) - { - $tmp_split_words[] = $phrase; - $phrase = ''; - } - } - else if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1) - { - $phrase = $word; - } - else - { - $tmp_split_words[] = $word; - } - } - if ($phrase) - { - $tmp_split_words[] = $phrase; - } - - $this->split_words = $tmp_split_words; - - unset($tmp_split_words); - unset($phrase); - - foreach ($this->split_words as $i => $word) - { - // Check for not allowed search queries for InnoDB. - // We assume similar restrictions for MyISAM, which is usually even - // slower but not as restrictive as InnoDB. - // InnoDB full-text search does not support the use of a leading - // plus sign with wildcard ('+*'), a plus and minus sign - // combination ('+-'), or leading a plus and minus sign combination. - // InnoDB full-text search only supports leading plus or minus signs. - // For example, InnoDB supports '+apple' but does not support 'apple+'. - // Specifying a trailing plus or minus sign causes InnoDB to report - // a syntax error. InnoDB full-text search does not support the use - // of multiple operators on a single search word, as in this example: - // '++apple'. Use of multiple operators on a single search word - // returns a syntax error to standard out. - // Also, ensure that the wildcard character is only used at the - // end of the line as it's intended by MySQL. - if (preg_match('#^(\+[+-]|\+\*|.+[+-]$|.+\*(?!$))#', $word)) - { - unset($this->split_words[$i]); - continue; - } - - $clean_word = preg_replace('#^[+\-|"]#', '', $word); - - // check word length - $clean_len = utf8_strlen(str_replace('*', '', $clean_word)); - if (($clean_len < $this->config['fulltext_mysql_min_word_len']) || ($clean_len > $this->config['fulltext_mysql_max_word_len'])) - { - $this->common_words[] = $word; - unset($this->split_words[$i]); - } - } - - if ($terms == 'any') - { - $this->search_query = ''; - foreach ($this->split_words as $word) - { - if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0)) - { - $word = substr($word, 1); - } - $this->search_query .= $word . ' '; - } - } - else - { - $this->search_query = ''; - foreach ($this->split_words as $word) - { - if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0)) - { - $this->search_query .= $word . ' '; - } - else if (strpos($word, '|') === 0) - { - $this->search_query .= substr($word, 1) . ' '; - } - else - { - $this->search_query .= '+' . $word . ' '; - } - } - } - - $this->search_query = utf8_htmlspecialchars($this->search_query); - - if ($this->search_query) - { - $this->split_words = array_values($this->split_words); - sort($this->split_words); - return true; - } - return false; - } - - /** - * Turns text into an array of words - * @param string $text contains post text/subject - */ - public function split_message($text) - { - // Split words - $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches); - $text = $matches[1]; - - // remove too short or too long words - $text = array_values($text); - for ($i = 0, $n = 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']) - { - unset($text[$i]); - } - } - - return array_values($text); - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No keywords? No posts - if (!$this->search_query) - { - return false; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - implode(', ', $this->split_words), - $type, - $fields, - $terms, - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary) - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_mysql_by_keyword_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var string fields Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') - * @var string terms Searching terms ('all', 'any') - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'fields', - 'terms', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_by_keyword_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - if ($start < 0) - { - $start = 0; - } - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - $join_topic = ($type == 'posts') ? false : true; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $join_topic = true; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - // Build some display specific sql strings - switch ($fields) - { - case 'titleonly': - $sql_match = 'p.post_subject'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - case 'msgonly': - $sql_match = 'p.post_text'; - $sql_match_where = ''; - break; - - case 'firstpost': - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - default: - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ''; - break; - } - - $search_query = $this->search_query; - - /** - * Allow changing the query used to search for posts using fulltext_mysql - * - * @event core.search_mysql_keywords_main_query_before - * @var string search_query The parsed keywords used for this search - * @var int result_count The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var bool join_topic Weather or not TOPICS_TABLE should be CROSS JOIN'ED - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on (!empty(author_ary) must be true, to be relevant) - * @var array ex_fid_ary Which forums not to search on - * @var int topic_id Limit the search to this topic_id only - * @var string sql_sort_table Extra tables to include in the SQL query. - * Used in conjunction with sql_sort_join - * @var string sql_sort_join SQL conditions to join all the tables used together. - * Used in conjunction with sql_sort_table - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sql_match Which columns to do the search on. - * @var string sql_match_where Extra conditions to use to properly filter the matching process - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'search_query', - 'result_count', - 'join_topic', - 'author_ary', - 'author_name', - 'ex_fid_ary', - 'topic_id', - 'sql_sort_table', - 'sql_sort_join', - 'sort_days', - 'sql_match', - 'sql_match_where', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_keywords_main_query_before', compact($vars))); - - $sql_select = (!$result_count) ? 'SQL_CALC_FOUND_ROWS ' : ''; - $sql_select = ($type == 'posts') ? $sql_select . 'p.post_id' : 'DISTINCT ' . $sql_select . 't.topic_id'; - $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; - $field = ($type == 'posts') ? 'post_id' : 'topic_id'; - if (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 (count($author_ary)) - { - $sql_author = ' AND ' . $this->db->sql_in_set('p.poster_id', $author_ary); - } - else - { - $sql_author = ''; - } - - $sql_where_options = $sql_sort_join; - $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; - $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; - $sql_where_options .= (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; - - $sql = "SELECT $sql_select - FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p - WHERE MATCH ($sql_match) AGAINST ('" . $this->db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE) - $sql_where_options - ORDER BY $sql_sort"; - $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)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - - // if the total result count is not cached yet, retrieve it from the db - if (!$result_count && count($id_ary)) - { - $sql_found_rows = 'SELECT FOUND_ROWS() as result_count'; - $result = $this->db->sql_query($sql_found_rows); - $result_count = (int) $this->db->sql_fetchfield('result_count'); - $this->db->sql_freeresult($result); - - if (!$result_count) - { - return false; - } - } - - if ($start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - } - - // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page - $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $result_count; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No author? No posts - if (!count($author_ary)) - { - return 0; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - '', - $type, - ($firstpost_only) ? 'firstpost' : '', - '', - '', - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary), - $author_name, - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_mysql_by_author_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var boolean firstpost_only Flag indicating if only topic starting posts are considered - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name The username to search on - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'firstpost_only', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - 'author_name', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_by_author_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - if ($start < 0) - { - $start = 0; - } - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - // Create some display specific sql strings - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); - } - $sql_fora = (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' : ''; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; - $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - $m_approve_fid_sql = ' AND ' . $post_visibility; - - /** - * Allow changing the query used to search for posts by author in fulltext_mysql - * - * @event core.search_mysql_author_query_before - * @var int result_count The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var string sql_sort_table CROSS JOIN'ed table to allow doing the sort chosen - * @var string sql_sort_join Condition to define how to join the CROSS JOIN'ed table specifyed in sql_sort_table - * @var string type Either "posts" or "topics" specifying the type of search being made - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on - * @var string sql_author SQL WHERE condition for the post author ids - * @var int topic_id Limit the search to this topic_id only - * @var string sql_topic_id SQL of topic_id - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var string sort_days Time, in days, that the oldest post showing can have - * @var string sql_time The SQL to search on the time specifyed by sort_days - * @var bool firstpost_only Wether or not to search only on the first post of the topics - * @var string sql_firstpost The SQL with the conditions to join the tables when using firstpost_only - * @var array ex_fid_ary Forum ids that must not be searched on - * @var array sql_fora SQL query for ex_fid_ary - * @var string m_approve_fid_sql WHERE clause condition on post_visibility restrictions - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'result_count', - 'sql_sort_table', - 'sql_sort_join', - 'type', - 'author_ary', - 'author_name', - 'sql_author', - 'topic_id', - 'sql_topic_id', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'sort_days', - 'sql_time', - 'firstpost_only', - 'sql_firstpost', - 'ex_fid_ary', - 'sql_fora', - 'm_approve_fid_sql', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_author_query_before', compact($vars))); - - // If the cache was completely empty count the results - $calc_results = ($result_count) ? '' : 'SQL_CALC_FOUND_ROWS '; - - // Build the query for really selecting the post_ids - if ($type == 'posts') - { - $sql = "SELECT {$calc_results}p.post_id - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_sort_join - $sql_time - ORDER BY $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = "SELECT {$calc_results}t.topic_id - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id - ORDER BY $sql_sort"; - $field = 'topic_id'; - } - - // Only read one block of posts from the db and then cache it - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - // retrieve the total result count if needed - if (!$result_count) - { - $sql_found_rows = 'SELECT FOUND_ROWS() as result_count'; - $result = $this->db->sql_query($sql_found_rows); - $result_count = (int) $this->db->sql_fetchfield('result_count'); - $this->db->sql_freeresult($result); - - if (!$result_count) - { - return false; - } - } - - if ($start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - } - - if (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); - - return $result_count; - } - return false; - } - - /** - * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated - * - * @param string $mode contains the post mode: edit, post, reply, quote ... - * @param int $post_id contains the post id of the post to index - * @param string $message contains the post text of the post - * @param string $subject contains the subject of the post to index - * @param int $poster_id contains the user id of the poster - * @param int $forum_id contains the forum id of parent forum of the post - */ - public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - // Split old and new post/subject to obtain array of words - $split_text = $this->split_message($message); - $split_title = ($subject) ? $this->split_message($subject) : array(); - - $words = array_unique(array_merge($split_text, $split_title)); - - /** - * 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); - - // destroy cached search results containing any of the words removed or added - $this->destroy_cache($words, array($poster_id)); - - unset($words); - } - - /** - * Destroy cached results, that might be outdated after deleting a post - */ - public function index_remove($post_ids, $author_ids, $forum_ids) - { - $this->destroy_cache(array(), array_unique($author_ids)); - } - - /** - * Destroy old cache entries - */ - public function tidy() - { - // destroy too old cached search results - $this->destroy_cache(array()); - - $this->config->set('search_last_gc', time(), false); - } - - /** - * Create fulltext index - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function create_index($acp_module, $u_action) - { - // Make sure we can actually use MySQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $alter_list = array(); - - if (!isset($this->stats['post_subject'])) - { - $alter_entry = array(); - if ($this->db->get_sql_layer() == 'mysqli' || version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) - { - $alter_entry[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; - } - else - { - $alter_entry[] = 'MODIFY post_subject text NOT NULL'; - } - $alter_entry[] = 'ADD FULLTEXT (post_subject)'; - $alter_list[] = $alter_entry; - } - - if (!isset($this->stats['post_content'])) - { - $alter_entry = array(); - if ($this->db->get_sql_layer() == 'mysqli' || version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) - { - $alter_entry[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL'; - } - else - { - $alter_entry[] = 'MODIFY post_text mediumtext NOT NULL'; - } - - $alter_entry[] = 'ADD FULLTEXT post_content (post_text, post_subject)'; - $alter_list[] = $alter_entry; - } - - $sql_queries = []; - - foreach ($alter_list as $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); - - return false; - } - - /** - * Drop fulltext index - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function delete_index($acp_module, $u_action) - { - // Make sure we can actually use MySQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $alter = array(); - - if (isset($this->stats['post_subject'])) - { - $alter[] = 'DROP INDEX post_subject'; - } - - if (isset($this->stats['post_content'])) - { - $alter[] = 'DROP INDEX post_content'; - } - - if (isset($this->stats['post_text'])) - { - $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); - - return false; - } - - /** - * Returns true if both FULLTEXT indexes exist - */ - public function index_created() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return isset($this->stats['post_subject']) && isset($this->stats['post_content']) && isset($this->stats['post_text']); - } - - /** - * Returns an associative array containing information about the indexes - */ - public function index_stats() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return array( - $this->user->lang['FULLTEXT_MYSQL_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0, - ); - } - - /** - * Computes the stats and store them in the $this->stats associative array - */ - protected function get_stats() - { - if (strpos($this->db->get_sql_layer(), 'mysql') === false) - { - $this->stats = array(); - return; - } - - $sql = 'SHOW INDEX - FROM ' . POSTS_TABLE; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - // deal with older MySQL versions which didn't use Index_type - $index_type = (isset($row['Index_type'])) ? $row['Index_type'] : $row['Comment']; - - if ($index_type == 'FULLTEXT') - { - if ($row['Key_name'] == 'post_subject') - { - $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; - } - } - } - $this->db->sql_freeresult($result); - - $this->stats['total_posts'] = empty($this->stats) ? 0 : $this->db->get_estimated_row_count(POSTS_TABLE); - } - - /** - * Display a note, that UTF-8 support is not available with certain versions of PHP - * - * @return associative array containing template and config variables - */ - public function acp() - { - $tpl = ' -
-

' . $this->user->lang['FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN'] . '
-
' . $this->config['fulltext_mysql_min_word_len'] . '
-
-
-

' . $this->user->lang['FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN'] . '
-
' . $this->config['fulltext_mysql_max_word_len'] . '
-
- '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array() - ); - } -} diff --git a/install/update/old/phpbb/search/fulltext_native.php b/install/update/old/phpbb/search/fulltext_native.php deleted file mode 100644 index c83de75..0000000 --- a/install/update/old/phpbb/search/fulltext_native.php +++ /dev/null @@ -1,2062 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\search; - -/** -* phpBB's own db driven fulltext search, version 2 -*/ -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 - */ - protected $stats = array(); - - /** - * Associative array stores the min and max word length to be searched - * @var array - */ - protected $word_length = array(); - - /** - * Contains tidied search query. - * Operators are prefixed in search query and common words excluded - * @var string - */ - protected $search_query; - - /** - * Contains common words. - * Common words are words with length less/more than min/max length - * @var array - */ - protected $common_words = array(); - - /** - * Post ids of posts containing words that are to be included - * @var array - */ - protected $must_contain_ids = array(); - - /** - * Post ids of posts containing words that should not be included - * @var array - */ - protected $must_not_contain_ids = array(); - - /** - * Post ids of posts containing at least one word that needs to be excluded - * @var array - */ - protected $must_exclude_one_ids = array(); - - /** - * Relative path to board root - * @var string - */ - protected $phpbb_root_path; - - /** - * PHP Extension - * @var string - */ - protected $php_ext; - - /** - * Config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Database connection - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * 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 - */ - public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $phpEx; - $this->config = $config; - $this->db = $db; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->user = $user; - - $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 (!function_exists('utf8_decode_ncr')) - { - include($this->phpbb_root_path . 'includes/utf/utf_tools.' . $this->php_ext); - } - - $error = false; - } - - /** - * Returns the name of this search backend to be displayed to administrators - * - * @return string Name - */ - public function get_name() - { - return 'phpBB Native Fulltext'; - } - - /** - * Returns the search_query - * - * @return string search query - */ - public function get_search_query() - { - return $this->search_query; - } - - /** - * Returns the common_words array - * - * @return array common words that are ignored by search backend - */ - public function get_common_words() - { - return $this->common_words; - } - - /** - * Returns the word_length array - * - * @return array min and max word length for searching - */ - public function get_word_length() - { - return $this->word_length; - } - - /** - * This function fills $this->search_query with the cleaned user search query - * - * If $terms is 'any' then the words will be extracted from the search query - * and combined with | inside brackets. They will afterwards be treated like - * an standard search query. - * - * Then it analyses the query and fills the internal arrays $must_not_contain_ids, - * $must_contain_ids and $must_exclude_one_ids which are later used by keyword_search() - * - * @param string $keywords contains the search query string as entered by the user - * @param string $terms is either 'all' (use search query as entered, default words to 'must be contained in post') - * or 'any' (find all posts containing at least one of the given words) - * @return boolean false if no valid keywords were found and otherwise true - */ - public function split_keywords($keywords, $terms) - { - $tokens = '+-|()* '; - - $keywords = trim($this->cleanup($keywords, $tokens)); - - // allow word|word|word without brackets - if ((strpos($keywords, ' ') === false) && (strpos($keywords, '|') !== false) && (strpos($keywords, '(') === false)) - { - $keywords = '(' . $keywords . ')'; - } - - $open_bracket = $space = false; - for ($i = 0, $n = strlen($keywords); $i < $n; $i++) - { - if ($open_bracket !== false) - { - switch ($keywords[$i]) - { - case ')': - if ($open_bracket + 1 == $i) - { - $keywords[$i - 1] = '|'; - $keywords[$i] = '|'; - } - $open_bracket = false; - break; - case '(': - $keywords[$i] = '|'; - break; - case '+': - case '-': - case ' ': - $keywords[$i] = '|'; - break; - case '*': - // $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)) - { - $keywords[$i] = '|'; - } - break; - } - } - else - { - switch ($keywords[$i]) - { - case ')': - $keywords[$i] = ' '; - break; - case '(': - $open_bracket = $i; - $space = false; - break; - case '|': - $keywords[$i] = ' '; - break; - case '-': - case '+': - $space = $keywords[$i]; - break; - case ' ': - if ($space !== false) - { - $keywords[$i] = $space; - } - break; - default: - $space = false; - } - } - } - - if ($open_bracket !== false) - { - $keywords .= ')'; - } - - $match = array( - '# +#', - '#\|\|+#', - '#(\+|\-)(?:\+|\-)+#', - '#\(\|#', - '#\|\)#', - ); - $replace = array( - ' ', - '|', - '$1', - '(', - ')', - ); - - $keywords = preg_replace($match, $replace, $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']) - { - trigger_error($this->user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', (int) $this->config['max_num_search_keywords'], $num_keywords)); - } - - // $keywords input format: each word separated by a space, words in a bracket are not separated - - // the user wants to search for any word, convert the search query - if ($terms == 'any') - { - $words = array(); - - preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $words); - if (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; - - $exact_words = array(); - preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words); - $exact_words = $exact_words[1]; - - $common_ids = $words = array(); - - if (count($exact_words)) - { - $sql = 'SELECT word_id, word_text, word_common - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_text', $exact_words) . ' - ORDER BY word_count ASC'; - $result = $this->db->sql_query($sql); - - // store an array of words and ids, remove common words - while ($row = $this->db->sql_fetchrow($result)) - { - if ($row['word_common']) - { - $this->common_words[] = $row['word_text']; - $common_ids[$row['word_text']] = (int) $row['word_id']; - continue; - } - - $words[$row['word_text']] = (int) $row['word_id']; - } - $this->db->sql_freeresult($result); - } - - // Handle +, - without preceeding whitespace character - $match = array('#(\S)\+#', '#(\S)-#'); - $replace = array('$1 +', '$1 +'); - - $keywords = preg_replace($match, $replace, $keywords); - - // now analyse the search query, first split it using the spaces - $query = explode(' ', $keywords); - - $this->must_contain_ids = array(); - $this->must_not_contain_ids = array(); - $this->must_exclude_one_ids = array(); - - foreach ($query as $word) - { - if (empty($word)) - { - continue; - } - - // words which should not be included - if ($word[0] == '-') - { - $word = substr($word, 1); - - // a group of which at least one may not be in the resulting posts - if ($word[0] == '(') - { - $word = array_unique(explode('|', substr($word, 1, -1))); - $mode = 'must_exclude_one'; - } - // one word which should not be in the resulting posts - else - { - $mode = 'must_not_contain'; - } - $ignore_no_id = true; - } - // words which have to be included - else - { - // no prefix is the same as a +prefix - if ($word[0] == '+') - { - $word = substr($word, 1); - } - - // a group of words of which at least one word should be in every resulting post - if ($word[0] == '(') - { - $word = array_unique(explode('|', substr($word, 1, -1))); - } - $ignore_no_id = false; - $mode = 'must_contain'; - } - - if (empty($word)) - { - continue; - } - - // if this is an array of words then retrieve an id for each - if (is_array($word)) - { - $non_common_words = array(); - $id_words = array(); - foreach ($word as $i => $word_part) - { - if (strpos($word_part, '*') !== false) - { - $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])) - { - $id_words[] = $words[$word_part]; - $non_common_words[] = $word_part; - } - else - { - $len = utf8_strlen($word_part); - if ($len < $this->word_length['min'] || $len > $this->word_length['max']) - { - $this->common_words[] = $word_part; - } - } - } - if (count($id_words)) - { - sort($id_words); - if (count($id_words) > 1) - { - $this->{$mode . '_ids'}[] = $id_words; - } - else - { - $mode = ($mode == 'must_exclude_one') ? 'must_not_contain' : $mode; - $this->{$mode . '_ids'}[] = $id_words[0]; - } - } - // throw an error if we shall not ignore unexistant words - else if (!$ignore_no_id && count($non_common_words)) - { - trigger_error(sprintf($this->user->lang['WORDS_IN_NO_POST'], implode($this->user->lang['COMMA_SEPARATOR'], $non_common_words))); - } - unset($non_common_words); - } - // else we only need one id - else if (($wildcard = strpos($word, '*') !== false) || isset($words[$word])) - { - if ($wildcard) - { - $len = utf8_strlen(str_replace('*', '', $word)); - if ($len >= $this->word_length['min'] && $len <= $this->word_length['max']) - { - $this->{$mode . '_ids'}[] = '\'' . $this->db->sql_escape(str_replace('*', '%', $word)) . '\''; - } - else - { - $this->common_words[] = $word; - } - } - else - { - $this->{$mode . '_ids'}[] = $words[$word]; - } - } - else - { - if (!isset($common_ids[$word])) - { - $len = utf8_strlen($word); - if ($len < $this->word_length['min'] || $len > $this->word_length['max']) - { - $this->common_words[] = $word; - } - } - } - } - - // Return true if all words are not common words - if (count($exact_words) - count($this->common_words) > 0) - { - return true; - } - return false; - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No keywords? No posts. - if (empty($this->search_query)) - { - return false; - } - - // we can't search for negatives only - if (empty($this->must_contain_ids)) - { - return false; - } - - $must_contain_ids = $this->must_contain_ids; - $must_not_contain_ids = $this->must_not_contain_ids; - $must_exclude_one_ids = $this->must_exclude_one_ids; - - sort($must_contain_ids); - sort($must_not_contain_ids); - sort($must_exclude_one_ids); - - // generate a search_key from all the options to identify the results - $search_key_array = array( - serialize($must_contain_ids), - serialize($must_not_contain_ids), - serialize($must_exclude_one_ids), - $type, - $fields, - $terms, - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary), - $author_name, - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_native_by_keyword_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var array must_contain_ids Array with post ids of posts containing words that are to be included - * @var array must_not_contain_ids Array with post ids of posts containing words that should not be included - * @var array must_exclude_one_ids Array with post ids of posts containing at least one word that needs to be excluded - * @var string type Searching type ('posts', 'topics') - * @var string fields Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') - * @var string terms Searching terms ('all', 'any') - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'must_contain_ids', - 'must_not_contain_ids', - 'must_exclude_one_ids', - 'type', - 'fields', - 'terms', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_native_by_keyword_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - // try reading the results from cache - $total_results = 0; - if ($this->obtain_ids($search_key, $total_results, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $total_results; - } - - $id_ary = array(); - - $sql_where = array(); - $m_num = 0; - $w_num = 0; - - $sql_array = array( - 'SELECT' => ($type == 'posts') ? 'p.post_id' : 'p.topic_id', - 'FROM' => array( - SEARCH_WORDMATCH_TABLE => array(), - SEARCH_WORDLIST_TABLE => array(), - ), - 'LEFT_JOIN' => array(array( - 'FROM' => array(POSTS_TABLE => 'p'), - 'ON' => 'm0.post_id = p.post_id', - )), - ); - - $title_match = ''; - $left_join_topics = false; - $group_by = true; - // Build some display specific sql strings - switch ($fields) - { - case 'titleonly': - $title_match = 'title_match = 1'; - $group_by = false; - // no break - case 'firstpost': - $left_join_topics = true; - $sql_where[] = 'p.post_id = t.topic_first_post_id'; - break; - - case 'msgonly': - $title_match = 'title_match = 0'; - $group_by = false; - break; - } - - if ($type == 'topics') - { - $left_join_topics = true; - $group_by = true; - } - - /** - * @todo Add a query optimizer (handle stuff like "+(4|3) +4") - */ - - foreach ($this->must_contain_ids as $subquery) - { - if (is_array($subquery)) - { - $group_by = true; - - $word_id_sql = array(); - $word_ids = array(); - foreach ($subquery as $id) - { - if (is_string($id)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $id" - ); - $word_ids[] = "w$w_num.word_id"; - - $w_num++; - } - else - { - $word_ids[] = $id; - } - } - - $sql_where[] = $this->db->sql_in_set("m$m_num.word_id", $word_ids); - - unset($word_id_sql); - unset($word_ids); - } - else if (is_string($subquery)) - { - $sql_array['FROM'][SEARCH_WORDLIST_TABLE][] = 'w' . $w_num; - - $sql_where[] = "w$w_num.word_text LIKE $subquery"; - $sql_where[] = "m$m_num.word_id = w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - else - { - $sql_where[] = "m$m_num.word_id = $subquery"; - } - - $sql_array['FROM'][SEARCH_WORDMATCH_TABLE][] = 'm' . $m_num; - - if ($title_match) - { - $sql_where[] = "m$m_num.$title_match"; - } - - if ($m_num != 0) - { - $sql_where[] = "m$m_num.post_id = m0.post_id"; - } - $m_num++; - } - - foreach ($this->must_not_contain_ids as $key => $subquery) - { - if (is_string($subquery)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $subquery" - ); - - $this->must_not_contain_ids[$key] = "w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - } - - if (count($this->must_not_contain_ids)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num), - 'ON' => $this->db->sql_in_set("m$m_num.word_id", $this->must_not_contain_ids) . (($title_match) ? " AND m$m_num.$title_match" : '') . " AND m$m_num.post_id = m0.post_id" - ); - - $sql_where[] = "m$m_num.word_id IS NULL"; - $m_num++; - } - - foreach ($this->must_exclude_one_ids as $ids) - { - $is_null_joins = array(); - foreach ($ids as $id) - { - if (is_string($id)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $id" - ); - $id = "w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num), - 'ON' => "m$m_num.word_id = $id AND m$m_num.post_id = m0.post_id" . (($title_match) ? " AND m$m_num.$title_match" : '') - ); - $is_null_joins[] = "m$m_num.word_id IS NULL"; - - $m_num++; - } - $sql_where[] = '(' . implode(' OR ', $is_null_joins) . ')'; - } - - $sql_where[] = $post_visibility; - - $search_query = $this->search_query; - $must_exclude_one_ids = $this->must_exclude_one_ids; - $must_not_contain_ids = $this->must_not_contain_ids; - $must_contain_ids = $this->must_contain_ids; - - /** - * Allow changing the query used for counting for posts using fulltext_native - * - * @event core.search_native_keywords_count_query_before - * @var string search_query The parsed keywords used for this search - * @var array must_not_contain_ids Ids that cannot be taken into account for the results - * @var array must_exclude_one_ids Ids that cannot be on the results - * @var array must_contain_ids Ids that must be on the results - * @var int total_results The previous result count for the format of the query - * Set to 0 to force a re-count - * @var array sql_array The data on how to search in the DB at this point - * @var bool left_join_topics Whether or not TOPICS_TABLE should be CROSS JOIN'ED - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on (!empty(author_ary) must be true, to be relevant) - * @var array ex_fid_ary Which forums not to search on - * @var int topic_id Limit the search to this topic_id only - * @var string sql_sort_table Extra tables to include in the SQL query. - * Used in conjunction with sql_sort_join - * @var string sql_sort_join SQL conditions to join all the tables used together. - * Used in conjunction with sql_sort_table - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sql_where An array of the current WHERE clause conditions - * @var string sql_match Which columns to do the search on - * @var string sql_match_where Extra conditions to use to properly filter the matching process - * @var bool group_by Whether or not the SQL query requires a GROUP BY for the elements in the SELECT clause - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'search_query', - 'must_not_contain_ids', - 'must_exclude_one_ids', - 'must_contain_ids', - 'total_results', - 'sql_array', - 'left_join_topics', - 'author_ary', - 'author_name', - 'ex_fid_ary', - 'topic_id', - 'sql_sort_table', - 'sql_sort_join', - 'sort_days', - 'sql_where', - 'sql_match', - 'sql_match_where', - 'group_by', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_native_keywords_count_query_before', compact($vars))); - - if ($topic_id) - { - $sql_where[] = 'p.topic_id = ' . $topic_id; - } - - if (count($author_ary)) - { - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); - } - $sql_where[] = $sql_author; - } - - if (count($ex_fid_ary)) - { - $sql_where[] = $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true); - } - - if ($sort_days) - { - $sql_where[] = 'p.post_time >= ' . (time() - ($sort_days * 86400)); - } - - $sql_array['WHERE'] = implode(' AND ', $sql_where); - - $is_mysql = false; - // if the total result count is not cached yet, retrieve it from the db - if (!$total_results) - { - $sql = ''; - $sql_array_count = $sql_array; - - if ($left_join_topics) - { - $sql_array_count['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_TABLE => 't'), - 'ON' => 'p.topic_id = t.topic_id' - ); - } - - switch ($this->db->get_sql_layer()) - { - case 'mysql4': - case 'mysqli': - - // 3.x does not support SQL_CALC_FOUND_ROWS - // $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT']; - $is_mysql = true; - - break; - - case '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 - FROM (' . $this->db->sql_build_query('SELECT', $sql_array_count) . ')'; - - // no break - - default: - $sql_array_count['SELECT'] = ($type == 'posts') ? 'COUNT(DISTINCT p.post_id) AS total_results' : 'COUNT(DISTINCT p.topic_id) AS total_results'; - $sql = (!$sql) ? $this->db->sql_build_query('SELECT', $sql_array_count) : $sql; - - $result = $this->db->sql_query($sql); - $total_results = (int) $this->db->sql_fetchfield('total_results'); - $this->db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - break; - } - - unset($sql_array_count, $sql); - } - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - switch ($sql_sort[0]) - { - case 'u': - $sql_array['FROM'][USERS_TABLE] = 'u'; - $sql_where[] = 'u.user_id = p.poster_id '; - break; - - case 't': - $left_join_topics = true; - break; - - case 'f': - $sql_array['FROM'][FORUMS_TABLE] = 'f'; - $sql_where[] = 'f.forum_id = p.forum_id'; - break; - } - - if ($left_join_topics) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_TABLE => 't'), - 'ON' => 'p.topic_id = t.topic_id' - ); - } - - // if using mysql and the total result count is not calculated yet, get it from the db - if (!$total_results && $is_mysql) - { - // Also count rows for the query as if there was not LIMIT. Add SQL_CALC_FOUND_ROWS to SQL - $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT']; - } - - $sql_array['WHERE'] = implode(' AND ', $sql_where); - $sql_array['GROUP_BY'] = ($group_by) ? (($type == 'posts') ? 'p.post_id' : 'p.topic_id') . ', ' . $sort_by_sql[$sort_key] : ''; - $sql_array['ORDER_BY'] = $sql_sort; - - unset($sql_where, $sql_sort, $group_by); - - $sql = $this->db->sql_build_query('SELECT', $sql_array); - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[(($type == 'posts') ? 'post_id' : 'topic_id')]; - } - $this->db->sql_freeresult($result); - - if (!$total_results && $is_mysql) - { - // Get the number of results as calculated by MySQL - $sql_count = 'SELECT FOUND_ROWS() as total_results'; - $result = $this->db->sql_query($sql_count); - $total_results = (int) $this->db->sql_fetchfield('total_results'); - $this->db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - } - - if ($start >= $total_results) - { - $start = floor(($total_results - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[(($type == 'posts') ? 'post_id' : 'topic_id')]; - } - $this->db->sql_freeresult($result); - - } - - // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page - $this->save_ids($search_key, $this->search_query, $author_ary, $total_results, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $total_results; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No author? No posts - if (!count($author_ary)) - { - return 0; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - '', - $type, - ($firstpost_only) ? 'firstpost' : '', - '', - '', - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary), - $author_name, - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_native_by_author_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var boolean firstpost_only Flag indicating if only topic starting posts are considered - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name The username to search on - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'firstpost_only', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - 'author_name', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_native_by_author_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - // try reading the results from cache - $total_results = 0; - if ($this->obtain_ids($search_key, $total_results, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $total_results; - } - - $id_ary = array(); - - // Create some display specific sql strings - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); - } - $sql_fora = (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' : ''; - $post_visibility = ($post_visibility) ? ' AND ' . $post_visibility : ''; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ' AND u.user_id = p.poster_id '; - break; - - case 't': - $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; - $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - $select = ($type == 'posts') ? 'p.post_id' : 't.topic_id'; - $is_mysql = false; - - /** - * Allow changing the query used to search for posts by author in fulltext_native - * - * @event core.search_native_author_count_query_before - * @var int total_results The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var string type The type of search being made - * @var string select SQL SELECT clause for what to get - * @var string sql_sort_table CROSS JOIN'ed table to allow doing the sort chosen - * @var string sql_sort_join Condition to define how to join the CROSS JOIN'ed table specifyed in sql_sort_table - * @var array sql_author SQL WHERE condition for the post author ids - * @var int topic_id Limit the search to this topic_id only - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var string sort_days Time, in days, that the oldest post showing can have - * @var string sql_time The SQL to search on the time specifyed by sort_days - * @var bool firstpost_only Wether or not to search only on the first post of the topics - * @var string sql_firstpost The SQL used in the WHERE claused to filter by firstpost. - * @var array ex_fid_ary Forum ids that must not be searched on - * @var array sql_fora SQL query for ex_fid_ary - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'total_results', - 'type', - 'select', - 'sql_sort_table', - 'sql_sort_join', - 'sql_author', - 'topic_id', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'sort_days', - 'sql_time', - 'firstpost_only', - 'sql_firstpost', - 'ex_fid_ary', - 'sql_fora', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_native_author_count_query_before', compact($vars))); - - // If the cache was completely empty count the results - if (!$total_results) - { - switch ($this->db->get_sql_layer()) - { - case 'mysql4': - case 'mysqli': -// $select = 'SQL_CALC_FOUND_ROWS ' . $select; - $is_mysql = true; - break; - - default: - if ($type == 'posts') - { - $sql = 'SELECT COUNT(p.post_id) as total_results - FROM ' . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $post_visibility - $sql_fora - $sql_time"; - } - else - { - if ($this->db->get_sql_layer() == 'sqlite3') - { - $sql = 'SELECT COUNT(topic_id) as total_results - FROM (SELECT DISTINCT t.topic_id'; - } - else - { - $sql = 'SELECT COUNT(DISTINCT t.topic_id) as total_results'; - } - - $sql .= ' FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $post_visibility - $sql_fora - AND t.topic_id = p.topic_id - $sql_time" . ($this->db->get_sql_layer() == 'sqlite3' ? ')' : ''); - } - $result = $this->db->sql_query($sql); - - $total_results = (int) $this->db->sql_fetchfield('total_results'); - $this->db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - break; - } - } - - // Build the query for really selecting the post_ids - if ($type == 'posts') - { - $sql = "SELECT $select - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t' : '') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $post_visibility - $sql_fora - $sql_sort_join - $sql_time - ORDER BY $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = "SELECT $select - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $post_visibility - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id, " . $sort_by_sql[$sort_key] . ' - ORDER BY ' . $sql_sort; - $field = 'topic_id'; - } - - // Only read one block of posts from the db and then cache it - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - if (!$total_results && $is_mysql) - { - // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it. - $sql_calc = str_replace('SELECT ' . $select, 'SELECT SQL_CALC_FOUND_ROWS ' . $select, $sql); - - $result = $this->db->sql_query($sql_calc); - $this->db->sql_freeresult($result); - - $sql_count = 'SELECT FOUND_ROWS() as total_results'; - $result = $this->db->sql_query($sql_count); - $total_results = (int) $this->db->sql_fetchfield('total_results'); - $this->db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - } - - if ($start >= $total_results) - { - $start = floor(($total_results - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - } - - if (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); - - return $total_results; - } - return false; - } - - /** - * Split a text into words of a given length - * - * The text is converted to UTF-8, cleaned up, and split. Then, words that - * conform to the defined length range are returned in an array. - * - * NOTE: duplicates are NOT removed from the return array - * - * @param string $text Text to split, encoded in UTF-8 - * @return array Array of UTF-8 words - */ - public function split_message($text) - { - $match = $words = array(); - - /** - * Taken from the original code - */ - // Do not index code - $match[] = '#\[code(?:=.*?)?(\:?[0-9a-z]{5,})\].*?\[\/code(\:?[0-9a-z]{5,})\]#is'; - // BBcode - $match[] = '#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?[0-9a-z]{5,})\]#'; - - $min = $this->word_length['min']; - - $isset_min = $min - 1; - - /** - * Clean up the string, remove HTML tags, remove BBCodes - */ - $word = strtok($this->cleanup(preg_replace($match, ' ', strip_tags($text)), -1), ' '); - - while (strlen($word)) - { - if (strlen($word) > 255 || strlen($word) <= $isset_min) - { - /** - * Words longer than 255 bytes are ignored. This will have to be - * changed whenever we change the length of search_wordlist.word_text - * - * Words shorter than $isset_min bytes are ignored, too - */ - $word = strtok(' '); - continue; - } - - $len = utf8_strlen($word); - - /** - * Test whether the word is too short to be indexed. - * - * Note that this limit does NOT apply to CJK and Hangul - */ - if ($len < $min) - { - /** - * Note: this could be optimized. If the codepoint is lower than Hangul's range - * we know that it will also be lower than CJK ranges - */ - if ((strncmp($word, 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; - } - } - - $words[] = $word; - $word = strtok(' '); - } - - return $words; - } - - /** - * Updates wordlist and wordmatch tables when a message is posted or changed - * - * @param string $mode Contains the post mode: edit, post, reply, quote - * @param int $post_id The id of the post which is modified/created - * @param string &$message New or updated post content - * @param string &$subject New or updated post subject - * @param int $poster_id Post author's user id - * @param int $forum_id The id of the forum in which the post is located - */ - public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - if (!$this->config['fulltext_native_load_upd']) - { - /** - * The search indexer is disabled, return - */ - return; - } - - // Split old and new post/subject to obtain array of 'words' - $split_text = $this->split_message($message); - $split_title = $this->split_message($subject); - - $cur_words = array('post' => array(), 'title' => array()); - - $words = array(); - if ($mode == 'edit') - { - $words['add']['post'] = array(); - $words['add']['title'] = array(); - $words['del']['post'] = array(); - $words['del']['title'] = array(); - - $sql = 'SELECT w.word_id, w.word_text, m.title_match - FROM ' . SEARCH_WORDLIST_TABLE . ' w, ' . SEARCH_WORDMATCH_TABLE . " m - WHERE m.post_id = $post_id - AND w.word_id = m.word_id"; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - $which = ($row['title_match']) ? 'title' : 'post'; - $cur_words[$which][$row['word_text']] = $row['word_id']; - } - $this->db->sql_freeresult($result); - - $words['add']['post'] = array_diff($split_text, array_keys($cur_words['post'])); - $words['add']['title'] = array_diff($split_title, array_keys($cur_words['title'])); - $words['del']['post'] = array_diff(array_keys($cur_words['post']), $split_text); - $words['del']['title'] = array_diff(array_keys($cur_words['title']), $split_title); - } - else - { - $words['add']['post'] = $split_text; - $words['add']['title'] = $split_title; - $words['del']['post'] = array(); - $words['del']['title'] = array(); - } - - /** - * 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); - - // Get unique words from the above arrays - $unique_add_words = array_unique(array_merge($words['add']['post'], $words['add']['title'])); - - // We now have unique arrays of all words to be added and removed and - // individual arrays of added and removed words for text and title. What - // we need to do now is add the new words (if they don't already exist) - // and then add (or remove) matches between the words and this post - if (count($unique_add_words)) - { - $sql = 'SELECT word_id, word_text - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_text', $unique_add_words); - $result = $this->db->sql_query($sql); - - $word_ids = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $word_ids[$row['word_text']] = $row['word_id']; - } - $this->db->sql_freeresult($result); - $new_words = array_diff($unique_add_words, array_keys($word_ids)); - - $this->db->sql_transaction('begin'); - if (count($new_words)) - { - $sql_ary = array(); - - foreach ($new_words as $word) - { - $sql_ary[] = array('word_text' => (string) $word, 'word_count' => 0); - } - $this->db->sql_return_on_error(true); - $this->db->sql_multi_insert(SEARCH_WORDLIST_TABLE, $sql_ary); - $this->db->sql_return_on_error(false); - } - unset($new_words, $sql_ary); - } - else - { - $this->db->sql_transaction('begin'); - } - - // now update the search match table, remove links to removed words and add links to new words - foreach ($words['del'] as $word_in => $word_ary) - { - $title_match = ($word_in == 'title') ? 1 : 0; - - if (count($word_ary)) - { - $sql_in = array(); - foreach ($word_ary as $word) - { - $sql_in[] = $cur_words[$word_in][$word]; - } - - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_id', $sql_in) . ' - AND post_id = ' . intval($post_id) . " - AND title_match = $title_match"; - $this->db->sql_query($sql); - - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $this->db->sql_in_set('word_id', $sql_in) . ' - AND word_count > 0'; - $this->db->sql_query($sql); - - unset($sql_in); - } - } - - $this->db->sql_return_on_error(true); - foreach ($words['add'] as $word_in => $word_ary) - { - $title_match = ($word_in == 'title') ? 1 : 0; - - if (count($word_ary)) - { - $sql = 'INSERT INTO ' . SEARCH_WORDMATCH_TABLE . ' (post_id, word_id, title_match) - SELECT ' . (int) $post_id . ', word_id, ' . (int) $title_match . ' - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_text', $word_ary); - $this->db->sql_query($sql); - - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count + 1 - WHERE ' . $this->db->sql_in_set('word_text', $word_ary); - $this->db->sql_query($sql); - } - } - $this->db->sql_return_on_error(false); - - $this->db->sql_transaction('commit'); - - // destroy cached search results containing any of the words removed or added - $this->destroy_cache(array_unique(array_merge($words['add']['post'], $words['add']['title'], $words['del']['post'], $words['del']['title'])), array($poster_id)); - - unset($unique_add_words); - unset($words); - unset($cur_words); - } - - /** - * Removes entries from the wordmatch table for the specified post_ids - */ - public function index_remove($post_ids, $author_ids, $forum_ids) - { - if (count($post_ids)) - { - $sql = 'SELECT w.word_id, w.word_text, m.title_match - FROM ' . SEARCH_WORDMATCH_TABLE . ' m, ' . SEARCH_WORDLIST_TABLE . ' w - WHERE ' . $this->db->sql_in_set('m.post_id', $post_ids) . ' - AND w.word_id = m.word_id'; - $result = $this->db->sql_query($sql); - - $message_word_ids = $title_word_ids = $word_texts = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - if ($row['title_match']) - { - $title_word_ids[] = $row['word_id']; - } - else - { - $message_word_ids[] = $row['word_id']; - } - $word_texts[] = $row['word_text']; - } - $this->db->sql_freeresult($result); - - if (count($title_word_ids)) - { - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $this->db->sql_in_set('word_id', $title_word_ids) . ' - AND word_count > 0'; - $this->db->sql_query($sql); - } - - if (count($message_word_ids)) - { - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $this->db->sql_in_set('word_id', $message_word_ids) . ' - AND word_count > 0'; - $this->db->sql_query($sql); - } - - unset($title_word_ids); - unset($message_word_ids); - - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $this->db->sql_in_set('post_id', $post_ids); - $this->db->sql_query($sql); - } - - $this->destroy_cache(array_unique($word_texts), array_unique($author_ids)); - } - - /** - * Tidy up indexes: Tag 'common words' and remove - * words no longer referenced in the match table - */ - public function tidy() - { - // Is the fulltext indexer disabled? If yes then we need not - // carry on ... it's okay ... I know when I'm not wanted boo hoo - if (!$this->config['fulltext_native_load_upd']) - { - $this->config->set('search_last_gc', time(), false); - return; - } - - $destroy_cache_words = array(); - - // Remove common words - if ($this->config['num_posts'] >= 100 && $this->config['fulltext_native_common_thres']) - { - $common_threshold = ((double) $this->config['fulltext_native_common_thres']) / 100.0; - // First, get the IDs of common words - $sql = 'SELECT word_id, word_text - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE word_count > ' . floor($this->config['num_posts'] * $common_threshold) . ' - OR word_common = 1'; - $result = $this->db->sql_query($sql); - - $sql_in = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $sql_in[] = $row['word_id']; - $destroy_cache_words[] = $row['word_text']; - } - $this->db->sql_freeresult($result); - - if (count($sql_in)) - { - // Flag the words - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_common = 1 - WHERE ' . $this->db->sql_in_set('word_id', $sql_in); - $this->db->sql_query($sql); - - // by setting search_last_gc to the new time here we make sure that if a user reloads because the - // following query takes too long, he won't run into it again - $this->config->set('search_last_gc', time(), false); - - // Delete the matches - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $this->db->sql_in_set('word_id', $sql_in); - $this->db->sql_query($sql); - } - unset($sql_in); - } - - if (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)); - } - - $this->config->set('search_last_gc', time(), false); - } - - /** - * Deletes all words from the index - */ - public function delete_index($acp_module, $u_action) - { - $sql_queries = []; - - switch ($this->db->get_sql_layer()) - { - case 'sqlite3': - $sql_queries[] = 'DELETE FROM ' . SEARCH_WORDLIST_TABLE; - $sql_queries[] = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE; - $sql_queries[] = 'DELETE FROM ' . SEARCH_RESULTS_TABLE; - break; - - default: - $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); - } - } - - /** - * Returns true if both FULLTEXT indexes exist - */ - public function index_created() - { - if (!count($this->stats)) - { - $this->get_stats(); - } - - return ($this->stats['total_words'] && $this->stats['total_matches']) ? true : false; - } - - /** - * Returns an associative array containing information about the indexes - */ - public function index_stats() - { - if (!count($this->stats)) - { - $this->get_stats(); - } - - return array( - $this->user->lang['TOTAL_WORDS'] => $this->stats['total_words'], - $this->user->lang['TOTAL_MATCHES'] => $this->stats['total_matches']); - } - - protected function get_stats() - { - $this->stats['total_words'] = $this->db->get_estimated_row_count(SEARCH_WORDLIST_TABLE); - $this->stats['total_matches'] = $this->db->get_estimated_row_count(SEARCH_WORDMATCH_TABLE); - } - - /** - * Clean up a text to remove non-alphanumeric characters - * - * This method receives a UTF-8 string, normalizes and validates it, replaces all - * non-alphanumeric characters with strings then returns the result. - * - * Any number of "allowed chars" can be passed as a UTF-8 string in NFC. - * - * @param string $text Text to split, in UTF-8 (not normalized or sanitized) - * @param string $allowed_chars String of special chars to allow - * @param string $encoding Text encoding - * @return string Cleaned up text, only alphanumeric chars are left - */ - protected function cleanup($text, $allowed_chars = null, $encoding = 'utf-8') - { - static $conv = array(), $conv_loaded = array(); - $allow = array(); - - // Convert the text to UTF-8 - $encoding = strtolower($encoding); - if ($encoding != 'utf-8') - { - $text = utf8_recode($text, $encoding); - } - - $utf_len_mask = array( - "\xC0" => 2, - "\xD0" => 2, - "\xE0" => 3, - "\xF0" => 4 - ); - - /** - * Replace HTML entities and NCRs - */ - $text = htmlspecialchars_decode(utf8_decode_ncr($text), ENT_QUOTES); - - /** - * Normalize to NFC - */ - $text = \Normalizer::normalize($text); - - /** - * The first thing we do is: - * - * - convert ASCII-7 letters to lowercase - * - remove the ASCII-7 non-alpha characters - * - remove the bytes that should not appear in a valid UTF-8 string: 0xC0, - * 0xC1 and 0xF5-0xFF - * - * @todo in theory, the third one is already taken care of during normalization and those chars should have been replaced by Unicode replacement chars - */ - $sb_match = "ISTCPAMELRDOJBNHFGVWUQKYXZ\r\n\t!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\xC0\xC1\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"; - $sb_replace = 'istcpamelrdojbnhfgvwuqkyxz '; - - /** - * This is the list of legal ASCII chars, it is automatically extended - * with ASCII chars from $allowed_chars - */ - $legal_ascii = ' eaisntroludcpmghbfvq10xy2j9kw354867z'; - - /** - * Prepare an array containing the extra chars to allow - */ - if (isset($allowed_chars[0])) - { - $pos = 0; - $len = strlen($allowed_chars); - do - { - $c = $allowed_chars[$pos]; - - if ($c < "\x80") - { - /** - * ASCII char - */ - $sb_pos = strpos($sb_match, $c); - if (is_int($sb_pos)) - { - /** - * Remove the char from $sb_match and its corresponding - * replacement in $sb_replace - */ - $sb_match = substr($sb_match, 0, $sb_pos) . substr($sb_match, $sb_pos + 1); - $sb_replace = substr($sb_replace, 0, $sb_pos) . substr($sb_replace, $sb_pos + 1); - $legal_ascii .= $c; - } - - ++$pos; - } - else - { - /** - * UTF-8 char - */ - $utf_len = $utf_len_mask[$c & "\xF0"]; - $allow[substr($allowed_chars, $pos, $utf_len)] = 1; - $pos += $utf_len; - } - } - while ($pos < $len); - } - - $text = strtr($text, $sb_match, $sb_replace); - $ret = ''; - - $pos = 0; - $len = strlen($text); - - do - { - /** - * Do all consecutive ASCII chars at once - */ - if ($spn = strspn($text, $legal_ascii, $pos)) - { - $ret .= substr($text, $pos, $spn); - $pos += $spn; - } - - if ($pos >= $len) - { - return $ret; - } - - /** - * Capture the UTF char - */ - $utf_len = $utf_len_mask[$text[$pos] & "\xF0"]; - $utf_char = substr($text, $pos, $utf_len); - $pos += $utf_len; - - if (($utf_char >= 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 - * - * We separate them with a space in order to index each character - * individually - */ - $ret .= ' ' . $utf_char . ' '; - continue; - } - - if (isset($allow[$utf_char])) - { - /** - * The char is explicitly allowed - */ - $ret .= $utf_char; - continue; - } - - if (isset($conv[$utf_char])) - { - /** - * The char is mapped to something, maybe to itself actually - */ - $ret .= $conv[$utf_char]; - continue; - } - - /** - * The char isn't mapped, but did we load its conversion table? - * - * The search indexer table is split into blocks. The block number of - * each char is equal to its codepoint right-shifted for 11 bits. It - * means that out of the 11, 16 or 21 meaningful bits of a 2-, 3- or - * 4- byte sequence we only keep the leftmost 0, 5 or 10 bits. Thus, - * all UTF chars encoded in 2 bytes are in the same first block. - */ - if (isset($utf_char[2])) - { - if (isset($utf_char[3])) - { - /** - * 1111 0nnn 10nn nnnn 10nx xxxx 10xx xxxx - * 0000 0111 0011 1111 0010 0000 - */ - $idx = ((ord($utf_char[0]) & 0x07) << 7) | ((ord($utf_char[1]) & 0x3F) << 1) | ((ord($utf_char[2]) & 0x20) >> 5); - } - else - { - /** - * 1110 nnnn 10nx xxxx 10xx xxxx - * 0000 0111 0010 0000 - */ - $idx = ((ord($utf_char[0]) & 0x07) << 1) | ((ord($utf_char[1]) & 0x20) >> 5); - } - } - else - { - /** - * 110x xxxx 10xx xxxx - * 0000 0000 0000 0000 - */ - $idx = 0; - } - - /** - * Check if the required conv table has been loaded already - */ - if (!isset($conv_loaded[$idx])) - { - $conv_loaded[$idx] = 1; - $file = $this->phpbb_root_path . 'includes/utf/data/search_indexer_' . $idx . '.' . $this->php_ext; - - if (file_exists($file)) - { - $conv += include($file); - } - } - - if (isset($conv[$utf_char])) - { - $ret .= $conv[$utf_char]; - } - else - { - /** - * We add an entry to the conversion table so that we - * don't have to convert to codepoint and perform the checks - * that are above this block - */ - $conv[$utf_char] = ' '; - $ret .= ' '; - } - } - while (1); - - return $ret; - } - - /** - * Returns a list of options for the ACP to display - */ - public function acp() - { - /** - * if we need any options, copied from fulltext_native for now, will have to be adjusted or removed - */ - - $tpl = ' -
-

' . $this->user->lang['YES_SEARCH_UPDATE_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['MIN_SEARCH_CHARS_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['MAX_SEARCH_CHARS_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['COMMON_WORD_THRESHOLD_EXPLAIN'] . '
-
%
-
- '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array('fulltext_native_load_upd' => 'bool', 'fulltext_native_min_chars' => 'integer:0:255', 'fulltext_native_max_chars' => 'integer:0:255', 'fulltext_native_common_thres' => 'double:0:100') - ); - } -} diff --git a/install/update/old/phpbb/search/fulltext_postgres.php b/install/update/old/phpbb/search/fulltext_postgres.php deleted file mode 100644 index 2f387e7..0000000 --- a/install/update/old/phpbb/search/fulltext_postgres.php +++ /dev/null @@ -1,1178 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\search; - -/** -* Fulltext search for PostgreSQL -*/ -class fulltext_postgres extends \phpbb\search\base -{ - /** - * Associative array holding index stats - * @var array - */ - protected $stats = array(); - - /** - * Holds the words entered by user, obtained by splitting the entered query on whitespace - * @var array - */ - protected $split_words = array(); - - /** - * Stores the tsearch query - * @var string - */ - protected $tsearch_query; - - /** - * True if phrase search is supported. - * PostgreSQL fulltext currently doesn't support it - * @var boolean - */ - protected $phrase_search = false; - - /** - * Config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Database connection - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Contains tidied search query. - * Operators are prefixed in search query and common words excluded - * @var string - */ - protected $search_query; - - /** - * Contains common words. - * Common words are words with length less/more than min/max length - * @var array - */ - protected $common_words = array(); - - /** - * Associative array stores the min and max word length to be searched - * @var array - */ - protected $word_length = array(); - - /** - * Constructor - * Creates a new \phpbb\search\fulltext_postgres, which is used as a search backend - * - * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $phpEx PHP file extension - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\db\driver\driver_interface Database object - * @param \phpbb\user $user User object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - */ - public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) - { - $this->config = $config; - $this->db = $db; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->user = $user; - - $this->word_length = array('min' => $this->config['fulltext_postgres_min_word_len'], 'max' => $this->config['fulltext_postgres_max_word_len']); - - /** - * Load the UTF tools - */ - if (!function_exists('utf8_strlen')) - { - include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - } - - $error = false; - } - - /** - * Returns the name of this search backend to be displayed to administrators - * - * @return string Name - */ - public function get_name() - { - return 'PostgreSQL Fulltext'; - } - - /** - * Returns the search_query - * - * @return string search query - */ - public function get_search_query() - { - return $this->search_query; - } - - /** - * Returns the common_words array - * - * @return array common words that are ignored by search backend - */ - public function get_common_words() - { - return $this->common_words; - } - - /** - * Returns the word_length array - * - * @return array min and max word length for searching - */ - public function get_word_length() - { - return $this->word_length; - } - - /** - * Returns if phrase search is supported or not - * - * @return bool - */ - public function supports_phrase_search() - { - return $this->phrase_search; - } - - /** - * Checks for correct PostgreSQL version and stores min/max word length in the config - * - * @return string|bool Language key of the error/incompatiblity occurred - */ - public function init() - { - if ($this->db->get_sql_layer() != 'postgres') - { - return $this->user->lang['FULLTEXT_POSTGRES_INCOMPATIBLE_DATABASE']; - } - - return false; - } - - /** - * Splits keywords entered by a user into an array of words stored in $this->split_words - * Stores the tidied search query in $this->search_query - * - * @param string &$keywords Contains the keyword as entered by the user - * @param string $terms is either 'all' or 'any' - * @return bool false if no valid keywords were found and otherwise true - */ - public function split_keywords(&$keywords, $terms) - { - if ($terms == 'all') - { - $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#(^|\s)\+#', '#(^|\s)-#', '#(^|\s)\|#'); - $replace = array(' +', ' |', ' -', ' +', ' -', ' |'); - - $keywords = preg_replace($match, $replace, $keywords); - } - - // Filter out as above - $split_keywords = preg_replace("#[\"\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords))); - - // Split words - $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches); - $this->split_words = $matches[1]; - - foreach ($this->split_words as $i => $word) - { - $clean_word = preg_replace('#^[+\-|"]#', '', $word); - - // check word length - $clean_len = utf8_strlen(str_replace('*', '', $clean_word)); - if (($clean_len < $this->config['fulltext_postgres_min_word_len']) || ($clean_len > $this->config['fulltext_postgres_max_word_len'])) - { - $this->common_words[] = $word; - unset($this->split_words[$i]); - } - } - - if ($terms == 'any') - { - $this->search_query = ''; - $this->tsearch_query = ''; - foreach ($this->split_words as $word) - { - if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0)) - { - $word = substr($word, 1); - } - $this->search_query .= $word . ' '; - $this->tsearch_query .= '|' . $word . ' '; - } - } - else - { - $this->search_query = ''; - $this->tsearch_query = ''; - foreach ($this->split_words as $word) - { - if (strpos($word, '+') === 0) - { - $this->search_query .= $word . ' '; - $this->tsearch_query .= '&' . substr($word, 1) . ' '; - } - else if (strpos($word, '-') === 0) - { - $this->search_query .= $word . ' '; - $this->tsearch_query .= '&!' . substr($word, 1) . ' '; - } - else if (strpos($word, '|') === 0) - { - $this->search_query .= $word . ' '; - $this->tsearch_query .= '|' . substr($word, 1) . ' '; - } - else - { - $this->search_query .= '+' . $word . ' '; - $this->tsearch_query .= '&' . $word . ' '; - } - } - } - - $this->tsearch_query = substr($this->tsearch_query, 1); - $this->search_query = utf8_htmlspecialchars($this->search_query); - - if ($this->search_query) - { - $this->split_words = array_values($this->split_words); - sort($this->split_words); - return true; - } - return false; - } - - /** - * Turns text into an array of words - * @param string $text contains post text/subject - */ - public function split_message($text) - { - // Split words - $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches); - $text = $matches[1]; - - // remove too short or too long words - $text = array_values($text); - for ($i = 0, $n = 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']) - { - unset($text[$i]); - } - } - - return array_values($text); - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No keywords? No posts - if (!$this->search_query) - { - return false; - } - - // When search query contains queries like -foo - if (strpos($this->search_query, '+') === false) - { - return false; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - implode(', ', $this->split_words), - $type, - $fields, - $terms, - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary) - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_postgres_by_keyword_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var string fields Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') - * @var string terms Searching terms ('all', 'any') - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'fields', - 'terms', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_by_keyword_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - if ($start < 0) - { - $start = 0; - } - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - $join_topic = ($type == 'posts') ? false : true; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $join_topic = true; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - // Build some display specific sql strings - switch ($fields) - { - case 'titleonly': - $sql_match = 'p.post_subject'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - case 'msgonly': - $sql_match = 'p.post_text'; - $sql_match_where = ''; - break; - - case 'firstpost': - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - default: - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ''; - break; - } - - $tsearch_query = $this->tsearch_query; - - /** - * Allow changing the query used to search for posts using fulltext_postgres - * - * @event core.search_postgres_keywords_main_query_before - * @var string tsearch_query The parsed keywords used for this search - * @var int result_count The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var bool join_topic Weather or not TOPICS_TABLE should be CROSS JOIN'ED - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on (!empty(author_ary) must be true, to be relevant) - * @var array ex_fid_ary Which forums not to search on - * @var int topic_id Limit the search to this topic_id only - * @var string sql_sort_table Extra tables to include in the SQL query. - * Used in conjunction with sql_sort_join - * @var string sql_sort_join SQL conditions to join all the tables used together. - * Used in conjunction with sql_sort_table - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sql_match Which columns to do the search on. - * @var string sql_match_where Extra conditions to use to properly filter the matching process - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'tsearch_query', - 'result_count', - 'join_topic', - 'author_ary', - 'author_name', - 'ex_fid_ary', - 'topic_id', - 'sql_sort_table', - 'sql_sort_join', - 'sort_days', - 'sql_match', - 'sql_match_where', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'start', - ); - 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, ' . $sort_by_sql[$sort_key]; - $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; - $field = ($type == 'posts') ? 'post_id' : 'topic_id'; - - 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 (count($author_ary)) - { - $sql_author = ' AND ' . $this->db->sql_in_set('p.poster_id', $author_ary); - } - else - { - $sql_author = ''; - } - - $sql_where_options = $sql_sort_join; - $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; - $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; - $sql_where_options .= (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; - - $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) . "')"; - - $this->db->sql_transaction('begin'); - - $sql_from = "FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p"; - $sql_where = "WHERE (" . $tmp_sql_match . ") - $sql_where_options"; - $sql = "SELECT $sql_select - $sql_from - $sql_where - ORDER BY $sql_sort"; - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - - // if the total result count is not cached yet, retrieve it from the db - if (!$result_count) - { - $sql_count = "SELECT COUNT(*) as result_count - $sql_from - $sql_where"; - $result = $this->db->sql_query($sql_count); - $result_count = (int) $this->db->sql_fetchfield('result_count'); - $this->db->sql_freeresult($result); - - if (!$result_count) - { - return false; - } - } - - $this->db->sql_transaction('commit'); - - if ($start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - } - - // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page - $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $result_count; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) - { - // No author? No posts - if (!count($author_ary)) - { - return 0; - } - - // generate a search_key from all the options to identify the results - $search_key_array = array( - '', - $type, - ($firstpost_only) ? 'firstpost' : '', - '', - '', - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - $post_visibility, - implode(',', $author_ary), - $author_name, - ); - - /** - * Allow changing the search_key for cached results - * - * @event core.search_postgres_by_author_modify_search_key - * @var array search_key_array Array with search parameters to generate the search_key - * @var string type Searching type ('posts', 'topics') - * @var boolean firstpost_only Flag indicating if only topic starting posts are considered - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name The username to search on - * @since 3.1.7-RC1 - */ - $vars = array( - 'search_key_array', - 'type', - 'firstpost_only', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - 'author_name', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_by_author_modify_search_key', compact($vars))); - - $search_key = md5(implode('#', $search_key_array)); - - if ($start < 0) - { - $start = 0; - } - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - // Create some display specific sql strings - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); - } - $sql_fora = (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' : ''; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; - $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - $m_approve_fid_sql = ' AND ' . $post_visibility; - - /** - * Allow changing the query used to search for posts by author in fulltext_postgres - * - * @event core.search_postgres_author_count_query_before - * @var int result_count The previous result count for the format of the query. - * Set to 0 to force a re-count - * @var string sql_sort_table CROSS JOIN'ed table to allow doing the sort chosen - * @var string sql_sort_join Condition to define how to join the CROSS JOIN'ed table specifyed in sql_sort_table - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name An extra username to search on - * @var string sql_author SQL WHERE condition for the post author ids - * @var int topic_id Limit the search to this topic_id only - * @var string sql_topic_id SQL of topic_id - * @var string sort_by_sql The possible predefined sort types - * @var string sort_key The sort type used from the possible sort types - * @var string sort_dir "a" for ASC or "d" dor DESC for the sort order used - * @var string sql_sort The result SQL when processing sort_by_sql + sort_key + sort_dir - * @var string sort_days Time, in days, that the oldest post showing can have - * @var string sql_time The SQL to search on the time specifyed by sort_days - * @var bool firstpost_only Wether or not to search only on the first post of the topics - * @var array ex_fid_ary Forum ids that must not be searched on - * @var array sql_fora SQL query for ex_fid_ary - * @var string m_approve_fid_sql WHERE clause condition on post_visibility restrictions - * @var int start How many posts to skip in the search results (used for pagination) - * @since 3.1.5-RC1 - */ - $vars = array( - 'result_count', - 'sql_sort_table', - 'sql_sort_join', - 'author_ary', - 'author_name', - 'sql_author', - 'topic_id', - 'sql_topic_id', - 'sort_by_sql', - 'sort_key', - 'sort_dir', - 'sql_sort', - 'sort_days', - 'sql_time', - 'firstpost_only', - 'ex_fid_ary', - 'sql_fora', - 'm_approve_fid_sql', - 'start', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_author_count_query_before', compact($vars))); - - // Build the query for really selecting the post_ids - if ($type == 'posts') - { - $sql = "SELECT p.post_id - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_sort_join - $sql_time - ORDER BY $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = "SELECT t.topic_id - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id, $sort_by_sql[$sort_key] - ORDER BY $sql_sort"; - $field = 'topic_id'; - } - - $this->db->sql_transaction('begin'); - - // Only read one block of posts from the db and then cache it - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = $row[$field]; - } - $this->db->sql_freeresult($result); - - // retrieve the total result count if needed - if (!$result_count) - { - if ($type == 'posts') - { - $sql_count = "SELECT COUNT(*) as result_count - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_sort_join - $sql_time"; - } - else - { - $sql_count = "SELECT COUNT(*) as result_count - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id, $sort_by_sql[$sort_key]"; - } - - $this->db->sql_query($sql_count); - $result_count = (int) $this->db->sql_fetchfield('result_count'); - - if (!$result_count) - { - return false; - } - } - - $this->db->sql_transaction('commit'); - - if ($start >= $result_count) - { - $start = floor(($result_count - 1) / $per_page) * $per_page; - - $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); - while ($row = $this->db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $this->db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - } - - if (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); - - return $result_count; - } - return false; - } - - /** - * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated - * - * @param string $mode contains the post mode: edit, post, reply, quote ... - * @param int $post_id contains the post id of the post to index - * @param string $message contains the post text of the post - * @param string $subject contains the subject of the post to index - * @param int $poster_id contains the user id of the poster - * @param int $forum_id contains the forum id of parent forum of the post - */ - public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - // Split old and new post/subject to obtain array of words - $split_text = $this->split_message($message); - $split_title = ($subject) ? $this->split_message($subject) : array(); - - $words = array_unique(array_merge($split_text, $split_title)); - - /** - * 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); - - // destroy cached search results containing any of the words removed or added - $this->destroy_cache($words, array($poster_id)); - - unset($words); - } - - /** - * Destroy cached results, that might be outdated after deleting a post - */ - public function index_remove($post_ids, $author_ids, $forum_ids) - { - $this->destroy_cache(array(), $author_ids); - } - - /** - * Destroy old cache entries - */ - public function tidy() - { - // destroy too old cached search results - $this->destroy_cache(array()); - - $this->config->set('search_last_gc', time(), false); - } - - /** - * Create fulltext index - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function create_index($acp_module, $u_action) - { - // Make sure we can actually use PostgreSQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $sql_queries = []; - - if (!isset($this->stats['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'])) - { - $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); - - return false; - } - - /** - * Drop fulltext index - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function delete_index($acp_module, $u_action) - { - // Make sure we can actually use PostgreSQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $sql_queries = []; - - if (isset($this->stats['post_subject'])) - { - $sql_queries[] = 'DROP INDEX ' . $this->stats['post_subject']['relname']; - } - - if (isset($this->stats['post_content'])) - { - $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); - - return false; - } - - /** - * Returns true if both FULLTEXT indexes exist - */ - public function index_created() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return (isset($this->stats['post_subject']) && isset($this->stats['post_content'])) ? true : false; - } - - /** - * Returns an associative array containing information about the indexes - */ - public function index_stats() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return array( - $this->user->lang['FULLTEXT_POSTGRES_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0, - ); - } - - /** - * Computes the stats and store them in the $this->stats associative array - */ - protected function get_stats() - { - if ($this->db->get_sql_layer() != 'postgres') - { - $this->stats = array(); - return; - } - - $sql = "SELECT c2.relname, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) AS indexdef - FROM pg_catalog.pg_class c1, pg_catalog.pg_index i, pg_catalog.pg_class c2 - WHERE c1.relname = '" . POSTS_TABLE . "' - AND pg_catalog.pg_table_is_visible(c1.oid) - AND c1.oid = i.indrelid - AND i.indexrelid = c2.oid"; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - // deal with older PostgreSQL versions which didn't use Index_type - if (strpos($row['indexdef'], 'to_tsvector') !== false) - { - if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_subject' || $row['relname'] == POSTS_TABLE . '_post_subject') - { - $this->stats['post_subject'] = $row; - } - else if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_content' || $row['relname'] == POSTS_TABLE . '_post_content') - { - $this->stats['post_content'] = $row; - } - } - } - $this->db->sql_freeresult($result); - - $this->stats['total_posts'] = $this->config['num_posts']; - } - - /** - * Display various options that can be configured for the backend from the acp - * - * @return associative array containing template and config variables - */ - public function acp() - { - $tpl = ' -
-

' . $this->user->lang['FULLTEXT_POSTGRES_VERSION_CHECK_EXPLAIN'] . '
-
' . (($this->db->get_sql_layer() == 'postgres') ? $this->user->lang['YES'] : $this->user->lang['NO']) . '
-
-
-

' . $this->user->lang['FULLTEXT_POSTGRES_TS_NAME_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_POSTGRES_MIN_WORD_LEN_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_POSTGRES_MAX_WORD_LEN_EXPLAIN'] . '
-
-
- '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array('fulltext_postgres_ts_name' => 'string', 'fulltext_postgres_min_word_len' => 'integer:0:255', 'fulltext_postgres_max_word_len' => 'integer:0:255') - ); - } -} diff --git a/install/update/old/phpbb/search/fulltext_sphinx.php b/install/update/old/phpbb/search/fulltext_sphinx.php deleted file mode 100644 index 2c2eb84..0000000 --- a/install/update/old/phpbb/search/fulltext_sphinx.php +++ /dev/null @@ -1,992 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\search; - -define('SPHINX_MAX_MATCHES', 20000); -define('SPHINX_CONNECT_RETRIES', 3); -define('SPHINX_CONNECT_WAIT_TIME', 300); - -/** -* Fulltext search based on the sphinx search deamon -*/ -class fulltext_sphinx -{ - /** - * Associative array holding index stats - * @var array - */ - protected $stats = array(); - - /** - * Holds the words entered by user, obtained by splitting the entered query on whitespace - * @var array - */ - protected $split_words = array(); - - /** - * Holds unique sphinx id - * @var string - */ - protected $id; - - /** - * Stores the names of both main and delta sphinx indexes - * separated by a semicolon - * @var string - */ - protected $indexes; - - /** - * Sphinx searchd client object - * @var SphinxClient - */ - protected $sphinx; - - /** - * Relative path to board root - * @var string - */ - protected $phpbb_root_path; - - /** - * PHP Extension - * @var string - */ - protected $php_ext; - - /** - * Auth object - * @var \phpbb\auth\auth - */ - protected $auth; - - /** - * Config object - * @var \phpbb\config\config - */ - protected $config; - - /** - * Database connection - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * Database Tools object - * @var \phpbb\db\tools\tools_interface - */ - protected $db_tools; - - /** - * Stores the database type if supported by sphinx - * @var string - */ - protected $dbtype; - - /** - * phpBB event dispatcher object - * @var \phpbb\event\dispatcher_interface - */ - protected $phpbb_dispatcher; - - /** - * User object - * @var \phpbb\user - */ - protected $user; - - /** - * Stores the generated content of the sphinx config file - * @var string - */ - protected $config_file_data = ''; - - /** - * Contains tidied search query. - * Operators are prefixed in search query and common words excluded - * @var string - */ - protected $search_query; - - /** - * Constructor - * Creates a new \phpbb\search\fulltext_postgres, which is used as a search backend - * - * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $phpEx PHP file extension - * @param \phpbb\auth\auth $auth Auth object - * @param \phpbb\config\config $config Config object - * @param \phpbb\db\driver\driver_interface Database object - * @param \phpbb\user $user User object - * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object - */ - public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) - { - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $phpEx; - $this->config = $config; - $this->phpbb_dispatcher = $phpbb_dispatcher; - $this->user = $user; - $this->db = $db; - $this->auth = $auth; - - // 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']) - { - $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'; - - if (!class_exists('SphinxClient')) - { - require($this->phpbb_root_path . 'includes/sphinxapi.' . $this->php_ext); - } - - // Initialize sphinx client - $this->sphinx = new \SphinxClient(); - - $this->sphinx->SetServer(($this->config['fulltext_sphinx_host'] ? $this->config['fulltext_sphinx_host'] : 'localhost'), ($this->config['fulltext_sphinx_port'] ? (int) $this->config['fulltext_sphinx_port'] : 9312)); - - $error = false; - } - - /** - * Returns the name of this search backend to be displayed to administrators - * - * @return string Name - */ - public function get_name() - { - return 'Sphinx Fulltext'; - } - - /** - * Returns the search_query - * - * @return string search query - */ - public function get_search_query() - { - return $this->search_query; - } - - /** - * Returns false as there is no word_len array - * - * @return false - */ - public function get_word_length() - { - return false; - } - - /** - * Returns an empty array as there are no common_words - * - * @return array common words that are ignored by search backend - */ - public function get_common_words() - { - return array(); - } - - /** - * Checks permissions and paths, if everything is correct it generates the config file - * - * @return string|bool Language key of the error/incompatiblity encountered, or false if successful - */ - public function init() - { - if ($this->db->get_sql_layer() != 'mysql' && $this->db->get_sql_layer() != 'mysql4' && $this->db->get_sql_layer() != 'mysqli' && $this->db->get_sql_layer() != 'postgres') - { - return $this->user->lang['FULLTEXT_SPHINX_WRONG_DATABASE']; - } - - // Move delta to main index each hour - $this->config->set('search_gc', 3600); - - return false; - } - - /** - * Generates content of sphinx.conf - * - * @return bool True if sphinx.conf content is correctly generated, false otherwise - */ - protected function config_generate() - { - // Check if Database is supported by Sphinx - if ($this->db->get_sql_layer() =='mysql' || $this->db->get_sql_layer() == 'mysql4' || $this->db->get_sql_layer() == 'mysqli') - { - $this->dbtype = 'mysql'; - } - else if ($this->db->get_sql_layer() == 'postgres') - { - $this->dbtype = 'pgsql'; - } - else - { - $this->config_file_data = $this->user->lang('FULLTEXT_SPHINX_WRONG_DATABASE'); - return false; - } - - // Check if directory paths have been filled - if (!$this->config['fulltext_sphinx_data_path']) - { - $this->config_file_data = $this->user->lang('FULLTEXT_SPHINX_NO_CONFIG_DATA'); - return false; - } - - include($this->phpbb_root_path . 'config.' . $this->php_ext); - - /* Now that we're sure everything was entered correctly, - generate a config for the index. We use a config value - fulltext_sphinx_id for this, as it should be unique. */ - $config_object = new \phpbb\search\sphinx\config($this->config_file_data); - $config_data = array( - 'source source_phpbb_' . $this->id . '_main' => array( - array('type', $this->dbtype . ' # mysql or pgsql'), - // This config value sql_host needs to be changed incase sphinx and sql are on different servers - array('sql_host', $dbhost . ' # SQL server host sphinx connects to'), - array('sql_user', '[dbuser]'), - array('sql_pass', '[dbpassword]'), - array('sql_db', $dbname), - array('sql_port', $dbport . ' # optional, default is 3306 for mysql and 5432 for pgsql'), - array('sql_query_pre', 'SET NAMES \'utf8\''), - array('sql_query_pre', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = (SELECT MAX(post_id) FROM ' . POSTS_TABLE . ') WHERE counter_id = 1'), - array('sql_query_range', 'SELECT MIN(post_id), MAX(post_id) FROM ' . POSTS_TABLE . ''), - array('sql_range_step', '5000'), - array('sql_query', 'SELECT - p.post_id AS id, - p.forum_id, - p.topic_id, - p.poster_id, - p.post_visibility, - CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, - p.post_time, - p.post_subject, - p.post_subject as title, - p.post_text as data, - t.topic_last_post_time, - 0 as deleted - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t - WHERE - p.topic_id = t.topic_id - AND p.post_id >= $start AND p.post_id <= $end'), - array('sql_query_post', ''), - array('sql_query_post_index', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = $maxid WHERE counter_id = 1'), - array('sql_attr_uint', 'forum_id'), - array('sql_attr_uint', 'topic_id'), - array('sql_attr_uint', 'poster_id'), - array('sql_attr_uint', 'post_visibility'), - array('sql_attr_bool', 'topic_first_post'), - array('sql_attr_bool', 'deleted'), - array('sql_attr_timestamp', 'post_time'), - array('sql_attr_timestamp', 'topic_last_post_time'), - array('sql_attr_string', 'post_subject'), - ), - 'source source_phpbb_' . $this->id . '_delta : source_phpbb_' . $this->id . '_main' => array( - array('sql_query_pre', 'SET NAMES \'utf8\''), - array('sql_query_range', ''), - array('sql_range_step', ''), - array('sql_query', 'SELECT - p.post_id AS id, - p.forum_id, - p.topic_id, - p.poster_id, - p.post_visibility, - CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, - p.post_time, - p.post_subject, - p.post_subject as title, - p.post_text as data, - t.topic_last_post_time, - 0 as deleted - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t - WHERE - p.topic_id = t.topic_id - AND p.post_id >= ( SELECT max_doc_id FROM ' . SPHINX_TABLE . ' WHERE counter_id=1 )'), - 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'), - array('source', 'source_phpbb_' . $this->id . '_main'), - array('docinfo', 'extern'), - array('morphology', 'none'), - array('stopwords', ''), - array('min_word_len', '2'), - array('charset_table', 'U+FF10..U+FF19->0..9, 0..9, U+FF41..U+FF5A->a..z, U+FF21..U+FF3A->a..z, A..Z->a..z, a..z, U+0149, U+017F, U+0138, U+00DF, U+00FF, U+00C0..U+00D6->U+00E0..U+00F6, U+00E0..U+00F6, U+00D8..U+00DE->U+00F8..U+00FE, U+00F8..U+00FE, U+0100->U+0101, U+0101, U+0102->U+0103, U+0103, U+0104->U+0105, U+0105, U+0106->U+0107, U+0107, U+0108->U+0109, U+0109, U+010A->U+010B, U+010B, U+010C->U+010D, U+010D, U+010E->U+010F, U+010F, U+0110->U+0111, U+0111, U+0112->U+0113, U+0113, U+0114->U+0115, U+0115, U+0116->U+0117, U+0117, U+0118->U+0119, U+0119, U+011A->U+011B, U+011B, U+011C->U+011D, U+011D, U+011E->U+011F, U+011F, U+0130->U+0131, U+0131, U+0132->U+0133, U+0133, U+0134->U+0135, U+0135, U+0136->U+0137, U+0137, U+0139->U+013A, U+013A, U+013B->U+013C, U+013C, U+013D->U+013E, U+013E, U+013F->U+0140, U+0140, U+0141->U+0142, U+0142, U+0143->U+0144, U+0144, U+0145->U+0146, U+0146, U+0147->U+0148, U+0148, U+014A->U+014B, U+014B, U+014C->U+014D, U+014D, U+014E->U+014F, U+014F, U+0150->U+0151, U+0151, U+0152->U+0153, U+0153, U+0154->U+0155, U+0155, U+0156->U+0157, U+0157, U+0158->U+0159, U+0159, U+015A->U+015B, U+015B, U+015C->U+015D, U+015D, U+015E->U+015F, U+015F, U+0160->U+0161, U+0161, U+0162->U+0163, U+0163, U+0164->U+0165, U+0165, U+0166->U+0167, U+0167, U+0168->U+0169, U+0169, U+016A->U+016B, U+016B, U+016C->U+016D, U+016D, U+016E->U+016F, U+016F, U+0170->U+0171, U+0171, U+0172->U+0173, U+0173, U+0174->U+0175, U+0175, U+0176->U+0177, U+0177, U+0178->U+00FF, U+00FF, U+0179->U+017A, U+017A, U+017B->U+017C, U+017C, U+017D->U+017E, U+017E, U+0410..U+042F->U+0430..U+044F, U+0430..U+044F, U+4E00..U+9FFF'), - array('min_prefix_len', '0'), - array('min_infix_len', '0'), - ), - 'index index_phpbb_' . $this->id . '_delta : index_phpbb_' . $this->id . '_main' => array( - array('path', $this->config['fulltext_sphinx_data_path'] . 'index_phpbb_' . $this->id . '_delta'), - array('source', 'source_phpbb_' . $this->id . '_delta'), - ), - 'indexer' => array( - array('mem_limit', $this->config['fulltext_sphinx_indexer_mem_limit'] . 'M'), - ), - 'searchd' => array( - array('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('binlog_path', $this->config['fulltext_sphinx_data_path']), - ), - ); - - $non_unique = array('sql_query_pre' => true, 'sql_attr_uint' => true, 'sql_attr_timestamp' => true, 'sql_attr_str2ordinal' => true, 'sql_attr_bool' => true); - $delete = array('sql_group_column' => true, 'sql_date_column' => true, 'sql_str2ordinal_column' => true); - - /** - * Allow adding/changing the Sphinx configuration data - * - * @event core.search_sphinx_modify_config_data - * @var array config_data Array with the Sphinx configuration data - * @var array non_unique Array with the Sphinx non-unique variables to delete - * @var array delete Array with the Sphinx variables to delete - * @since 3.1.7-RC1 - */ - $vars = array( - 'config_data', - 'non_unique', - 'delete', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_sphinx_modify_config_data', compact($vars))); - - foreach ($config_data as $section_name => $section_data) - { - $section = $config_object->get_section_by_name($section_name); - if (!$section) - { - $section = $config_object->add_section($section_name); - } - - foreach ($delete as $key => $void) - { - $section->delete_variables_by_name($key); - } - - foreach ($non_unique as $key => $void) - { - $section->delete_variables_by_name($key); - } - - foreach ($section_data as $entry) - { - $key = $entry[0]; - $value = $entry[1]; - - if (!isset($non_unique[$key])) - { - $variable = $section->get_variable_by_name($key); - if (!$variable) - { - $section->create_variable($key, $value); - } - else - { - $variable->set_value($value); - } - } - else - { - $section->create_variable($key, $value); - } - } - } - $this->config_file_data = $config_object->get_data(); - - return true; - } - - /** - * Splits keywords entered by a user into an array of words stored in $this->split_words - * Stores the tidied search query in $this->search_query - * - * @param string $keywords Contains the keyword as entered by the user - * @param string $terms is either 'all' or 'any' - * @return false if no valid keywords were found and otherwise true - */ - public function split_keywords(&$keywords, $terms) - { - if ($terms == 'all') - { - $match = array('#\sand\s#i', '#\sor\s#i', '#\snot\s#i', '#\+#', '#-#', '#\|#', '#@#'); - $replace = array(' & ', ' | ', ' - ', ' +', ' -', ' |', ''); - - $keywords = preg_replace($match, $replace, $keywords); - $this->sphinx->SetMatchMode(SPH_MATCH_EXTENDED); - } - else - { - $this->sphinx->SetMatchMode(SPH_MATCH_ANY); - } - - // Keep quotes and new lines - $keywords = str_replace(array('"', "\n"), array('"', ' '), trim($keywords)); - - if (strlen($keywords) > 0) - { - $this->search_query = str_replace('"', '"', $keywords); - return true; - } - - return false; - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $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) && !count($author_ary)) - { - return false; - } - - $id_ary = array(); - - // Sorting - - if ($type == 'topics') - { - switch ($sort_key) - { - case 'a': - $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'poster_id ' . (($sort_dir == 'a') ? 'ASC' : 'DESC')); - break; - - case 'f': - $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'forum_id ' . (($sort_dir == 'a') ? 'ASC' : 'DESC')); - break; - - case 'i': - - case 's': - $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'post_subject ' . (($sort_dir == 'a') ? 'ASC' : 'DESC')); - break; - - case 't': - - default: - $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'topic_last_post_time ' . (($sort_dir == 'a') ? 'ASC' : 'DESC')); - break; - } - } - else - { - switch ($sort_key) - { - case 'a': - $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'poster_id'); - break; - - case 'f': - $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'forum_id'); - break; - - case 'i': - - case 's': - $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_subject'); - break; - - case 't': - - default: - $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_time'); - break; - } - } - - // Most narrow filters first - if ($topic_id) - { - $this->sphinx->SetFilter('topic_id', array($topic_id)); - } - - /** - * Allow modifying the Sphinx search options - * - * @event core.search_sphinx_keywords_modify_options - * @var string type Searching type ('posts', 'topics') - * @var string fields Searching fields ('titleonly', 'msgonly', 'firstpost', 'all') - * @var string terms Searching terms ('all', 'any') - * @var int sort_days Time, in days, of the oldest possible post to list - * @var string sort_key The sort type used from the possible sort types - * @var int topic_id Limit the search to this topic_id only - * @var array ex_fid_ary Which forums not to search on - * @var string post_visibility Post visibility data - * @var array author_ary Array of user_id containing the users to filter the results to - * @var string author_name The username to search on - * @var object sphinx The Sphinx searchd client object - * @since 3.1.7-RC1 - */ - $sphinx = $this->sphinx; - $vars = array( - 'type', - 'fields', - 'terms', - 'sort_days', - 'sort_key', - 'topic_id', - 'ex_fid_ary', - 'post_visibility', - 'author_ary', - 'author_name', - 'sphinx', - ); - extract($this->phpbb_dispatcher->trigger_event('core.search_sphinx_keywords_modify_options', compact($vars))); - $this->sphinx = $sphinx; - unset($sphinx); - - $search_query_prefix = ''; - - switch ($fields) - { - case 'titleonly': - // Only search the title - if ($terms == 'all') - { - $search_query_prefix = '@title '; - } - // Weight for the title - $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); - // 1 is first_post, 0 is not first post - $this->sphinx->SetFilter('topic_first_post', array(1)); - break; - - case 'msgonly': - // Only search the body - if ($terms == 'all') - { - $search_query_prefix = '@data '; - } - // Weight for the body - $this->sphinx->SetFieldWeights(array("title" => 1, "data" => 5)); - break; - - case 'firstpost': - // More relative weight for the title, also search the body - $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); - // 1 is first_post, 0 is not first post - $this->sphinx->SetFilter('topic_first_post', array(1)); - break; - - default: - // More relative weight for the title, also search the body - $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); - break; - } - - if (count($author_ary)) - { - $this->sphinx->SetFilter('poster_id', $author_ary); - } - - // As this is not simply possible at the moment, we limit the result to approved posts. - // This will make it impossible for moderators to search unapproved and softdeleted posts, - // but at least it will also cause the same for normal users. - $this->sphinx->SetFilter('post_visibility', array(ITEM_APPROVED)); - - 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 (count($search_forums)) - { - $this->sphinx->SetFilter('forum_id', $search_forums); - } - } - - $this->sphinx->SetFilter('deleted', array(0)); - - $this->sphinx->SetLimits((int) $start, (int) $per_page, SPHINX_MAX_MATCHES); - $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); - - // Could be connection to localhost:9312 failed (errno=111, - // msg=Connection refused) during rotate, retry if so - $retries = SPHINX_CONNECT_RETRIES; - while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--) - { - usleep(SPHINX_CONNECT_WAIT_TIME); - $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); - } - - if ($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())); - } - else - { - trigger_error($this->user->lang('SPHINX_SEARCH_FAILED_LOG')); - } - } - - $result_count = $result['total_found']; - - if ($result_count && $start >= $result_count) - { - $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 . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); - - // Could be connection to localhost:9312 failed (errno=111, - // msg=Connection refused) during rotate, retry if so - $retries = SPHINX_CONNECT_RETRIES; - while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--) - { - usleep(SPHINX_CONNECT_WAIT_TIME); - $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); - } - } - - $id_ary = array(); - if (isset($result['matches'])) - { - if ($type == 'posts') - { - $id_ary = array_keys($result['matches']); - } - else - { - foreach ($result['matches'] as $key => $value) - { - $id_ary[] = $value['attrs']['topic_id']; - } - } - } - else - { - return false; - } - - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $result_count; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param string $post_visibility specifies which types of posts the user can view in which forums - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - */ - public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) - { - $this->search_query = ''; - - $this->sphinx->SetMatchMode(SPH_MATCH_FULLSCAN); - $fields = ($firstpost_only) ? 'firstpost' : 'all'; - $terms = 'all'; - return $this->keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, $id_ary, $start, $per_page); - } - - /** - * Updates wordlist and wordmatch tables when a message is posted or changed - * - * @param string $mode Contains the post mode: edit, post, reply, quote - * @param int $post_id The id of the post which is modified/created - * @param string &$message New or updated post content - * @param string &$subject New or updated post subject - * @param int $poster_id Post author's user id - * @param int $forum_id The id of the forum in which the post is located - */ - public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - /** - * 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))); - } - else if ($mode != 'post' && $post_id) - { - // Update topic_last_post_time for full topic - $sql_array = array( - 'SELECT' => 'p1.post_id', - 'FROM' => array( - POSTS_TABLE => 'p1', - ), - 'LEFT_JOIN' => array(array( - 'FROM' => array( - POSTS_TABLE => 'p2' - ), - 'ON' => 'p1.topic_id = p2.topic_id', - )), - 'WHERE' => 'p2.post_id = ' . ((int) $post_id), - ); - - $sql = $this->db->sql_build_query('SELECT', $sql_array); - $result = $this->db->sql_query($sql); - - $post_updates = array(); - $post_time = time(); - while ($row = $this->db->sql_fetchrow($result)) - { - $post_updates[(int) $row['post_id']] = array($post_time); - } - $this->db->sql_freeresult($result); - - if (count($post_updates)) - { - $this->sphinx->UpdateAttributes($this->indexes, array('topic_last_post_time'), $post_updates); - } - } - } - - /** - * Delete a post from the index after it was deleted - */ - public function index_remove($post_ids, $author_ids, $forum_ids) - { - $values = array(); - foreach ($post_ids as $post_id) - { - $values[$post_id] = array(1); - } - - $this->sphinx->UpdateAttributes($this->indexes, array('deleted'), $values); - } - - /** - * Nothing needs to be destroyed - */ - public function tidy($create = false) - { - $this->config->set('search_last_gc', time(), false); - } - - /** - * Create sphinx table - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function create_index($acp_module, $u_action) - { - if (!$this->index_created()) - { - $table_data = array( - 'COLUMNS' => array( - 'counter_id' => array('UINT', 0), - 'max_doc_id' => array('UINT', 0), - ), - 'PRIMARY_KEY' => 'counter_id', - ); - $this->db_tools->sql_create_table(SPHINX_TABLE, $table_data); - - $sql = 'TRUNCATE TABLE ' . SPHINX_TABLE; - $this->db->sql_query($sql); - - $data = array( - 'counter_id' => '1', - 'max_doc_id' => '0', - ); - $sql = 'INSERT INTO ' . SPHINX_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data); - $this->db->sql_query($sql); - } - - return false; - } - - /** - * Drop sphinx table - * - * @return string|bool error string is returned incase of errors otherwise false - */ - public function delete_index($acp_module, $u_action) - { - if (!$this->index_created()) - { - return false; - } - - $this->db_tools->sql_table_drop(SPHINX_TABLE); - - return false; - } - - /** - * Returns true if the sphinx table was created - * - * @return bool true if sphinx table was created - */ - public function index_created($allow_new_files = true) - { - $created = false; - - if ($this->db_tools->sql_table_exists(SPHINX_TABLE)) - { - $created = true; - } - - return $created; - } - - /** - * Returns an associative array containing information about the indexes - * - * @return string|bool Language string of error false otherwise - */ - public function index_stats() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return array( - $this->user->lang['FULLTEXT_SPHINX_MAIN_POSTS'] => ($this->index_created()) ? $this->stats['main_posts'] : 0, - $this->user->lang['FULLTEXT_SPHINX_DELTA_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] - $this->stats['main_posts'] : 0, - $this->user->lang['FULLTEXT_MYSQL_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0, - ); - } - - /** - * Collects stats that can be displayed on the index maintenance page - */ - protected function get_stats() - { - if ($this->index_created()) - { - $sql = 'SELECT COUNT(post_id) as total_posts - FROM ' . POSTS_TABLE; - $result = $this->db->sql_query($sql); - $this->stats['total_posts'] = (int) $this->db->sql_fetchfield('total_posts'); - $this->db->sql_freeresult($result); - - $sql = 'SELECT COUNT(p.post_id) as main_posts - FROM ' . POSTS_TABLE . ' p, ' . SPHINX_TABLE . ' m - WHERE p.post_id <= m.max_doc_id - AND m.counter_id = 1'; - $result = $this->db->sql_query($sql); - $this->stats['main_posts'] = (int) $this->db->sql_fetchfield('main_posts'); - $this->db->sql_freeresult($result); - } - } - - /** - * Returns a list of options for the ACP to display - * - * @return associative array containing template and config variables - */ - public function acp() - { - $config_vars = array( - 'fulltext_sphinx_data_path' => 'string', - 'fulltext_sphinx_host' => 'string', - 'fulltext_sphinx_port' => 'string', - 'fulltext_sphinx_indexer_mem_limit' => 'int', - ); - - $tpl = ' - ' . $this->user->lang['FULLTEXT_SPHINX_CONFIGURE']. ' -
-

' . $this->user->lang['FULLTEXT_SPHINX_DATA_PATH_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_SPHINX_HOST_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_SPHINX_PORT_EXPLAIN'] . '
-
-
-
-

' . $this->user->lang['FULLTEXT_SPHINX_INDEXER_MEM_LIMIT_EXPLAIN'] . '
-
' . $this->user->lang['MIB'] . '
-
-
-

' . $this->user->lang['FULLTEXT_SPHINX_CONFIG_FILE_EXPLAIN'] . '
-
' . (($this->config_generate()) ? '' : $this->config_file_data) . '
-
- '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => $config_vars - ); - } -} diff --git a/install/update/old/phpbb/session.php b/install/update/old/phpbb/session.php deleted file mode 100644 index 31f32af..0000000 --- a/install/update/old/phpbb/session.php +++ /dev/null @@ -1,1650 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* Session class -*/ -class session -{ - var $cookie_data = array(); - var $page = array(); - var $data = array(); - var $browser = ''; - var $forwarded_for = ''; - var $host = ''; - var $session_id = ''; - var $ip = ''; - var $load = 0; - var $time_now = 0; - var $update_session_page = true; - - /** - * Extract current session page - * - * @param string $root_path current root path (phpbb_root_path) - * @return array - */ - static function extract_current_page($root_path) - { - global $request, $symfony_request, $phpbb_filesystem; - - $page_array = array(); - - // First of all, get the request uri... - $script_name = $request->escape($symfony_request->getScriptName(), true); - $args = $request->escape(explode('&', $symfony_request->getQueryString()), true); - - // If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support... - if (!$script_name) - { - $script_name = htmlspecialchars_decode($request->server('REQUEST_URI')); - $script_name = (($pos = strpos($script_name, '?')) !== false) ? substr($script_name, 0, $pos) : $script_name; - $page_array['failover'] = 1; - } - - // Replace backslashes and doubled slashes (could happen on some proxy setups) - $script_name = str_replace(array('\\', '//'), '/', $script_name); - - // Now, remove the sid and let us get a clean query string... - $use_args = array(); - - // Since some browser do not encode correctly we need to do this with some "special" characters... - // " -> %22, ' => %27, < -> %3C, > -> %3E - $find = array('"', "'", '<', '>', '"', '<', '>'); - $replace = array('%22', '%27', '%3C', '%3E', '%22', '%3C', '%3E'); - - foreach ($args as $key => $argument) - { - if (strpos($argument, 'sid=') === 0) - { - continue; - } - - $use_args[] = str_replace($find, $replace, $argument); - } - unset($args); - - // The following examples given are for an request uri of {path to the phpbb directory}/adm/index.php?i=10&b=2 - - // The current query string - $query_string = trim(implode('&', $use_args)); - - // basenamed page name (for example: index.php) - $page_name = (substr($script_name, -1, 1) == '/') ? '' : basename($script_name); - $page_name = urlencode(htmlspecialchars($page_name)); - - $symfony_request_path = $phpbb_filesystem->clean_path($symfony_request->getPathInfo()); - if ($symfony_request_path !== '/') - { - $page_name .= str_replace('%2F', '/', urlencode($symfony_request_path)); - } - - 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('../', count($root_dirs)) . implode('/', $page_dirs); - - if ($page_dir && substr($page_dir, -1, 1) == '/') - { - $page_dir = substr($page_dir, 0, -1); - } - - // Current page from phpBB root (for example: adm/index.php?i=10&b=2) - $page = (($page_dir) ? $page_dir . '/' : '') . $page_name; - if ($query_string) - { - $page .= '?' . $query_string; - } - - // The script path from the webroot to the current directory (for example: /phpBB3/adm/) : always prefixed with / and ends in / - $script_path = $symfony_request->getBasePath(); - - // The script path from the webroot to the phpBB root (for example: /phpBB3/) - $script_dirs = explode('/', $script_path); - 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) - { - $root_script_path = ($page_dir) ? str_replace($page_dir, '', $script_path) : $script_path; - } - - $script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/'; - $root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/'; - - $forum_id = $request->variable('f', 0); - // maximum forum id value is maximum value of mediumint unsigned column - $forum_id = ($forum_id > 0 && $forum_id < 16777215) ? $forum_id : 0; - - $page_array += array( - 'page_name' => $page_name, - 'page_dir' => $page_dir, - - 'query_string' => $query_string, - 'script_path' => str_replace(' ', '%20', htmlspecialchars($script_path)), - 'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)), - - 'page' => $page, - 'forum' => $forum_id, - ); - - return $page_array; - } - - /** - * Get valid hostname/port. HTTP_HOST is used, SERVER_NAME if HTTP_HOST not present. - */ - function extract_current_hostname() - { - global $config, $request; - - // Get hostname - $host = htmlspecialchars_decode($request->header('Host', $request->server('SERVER_NAME'))); - - // Should be a string and lowered - $host = (string) strtolower($host); - - // If host is equal the cookie domain or the server name (if config is set), then we assume it is valid - if ((isset($config['cookie_domain']) && $host === $config['cookie_domain']) || (isset($config['server_name']) && $host === $config['server_name'])) - { - return $host; - } - - // Is the host actually a IP? If so, we use the IP... (IPv4) - if (long2ip(ip2long($host)) === $host) - { - return $host; - } - - // Now return the hostname (this also removes any port definition). The http:// is prepended to construct a valid URL, hosts never have a scheme assigned - $host = @parse_url('http://' . $host); - $host = (!empty($host['host'])) ? $host['host'] : ''; - - // Remove any portions not removed by parse_url (#) - $host = str_replace('#', '', $host); - - // If, by any means, the host is now empty, we will use a "best approach" way to guess one - if (empty($host)) - { - if (!empty($config['server_name'])) - { - $host = $config['server_name']; - } - else if (!empty($config['cookie_domain'])) - { - $host = (strpos($config['cookie_domain'], '.') === 0) ? substr($config['cookie_domain'], 1) : $config['cookie_domain']; - } - else - { - // Set to OS hostname or localhost - $host = (function_exists('php_uname')) ? php_uname('n') : 'localhost'; - } - } - - // It may be still no valid host, but for sure only a hostname (we may further expand on the cookie domain... if set) - return $host; - } - - /** - * Start session management - * - * This is where all session activity begins. We gather various pieces of - * information from the client and server. We test to see if a session already - * exists. If it does, fine and dandy. If it doesn't we'll go on to create a - * new one ... pretty logical heh? We also examine the system load (if we're - * running on a system which makes such information readily available) and - * halt if it's above an admin definable limit. - * - * @param bool $update_session_page if true the session page gets updated. - * This can be set to circumvent certain scripts to update the users last visited page. - */ - function session_begin($update_session_page = true) - { - global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path; - global $request, $phpbb_container, $user, $phpbb_log, $phpbb_dispatcher; - - // Give us some basic information - $this->time_now = time(); - $this->cookie_data = array('u' => 0, 'k' => ''); - $this->update_session_page = $update_session_page; - $this->browser = $request->header('User-Agent'); - $this->referer = $request->header('Referer'); - $this->forwarded_for = $request->header('X-Forwarded-For'); - - $this->host = $this->extract_current_hostname(); - $this->page = $this->extract_current_page($phpbb_root_path); - - // if the forwarded for header shall be checked we have to validate its contents - if ($config['forwarded_for_check']) - { - $this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for)); - - // split the list of IPs - $ips = explode(' ', $this->forwarded_for); - foreach ($ips as $ip) - { - // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly - if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) - { - // contains invalid data, don't use the forwarded for header - $this->forwarded_for = ''; - break; - } - } - } - else - { - $this->forwarded_for = ''; - } - - if ($request->is_set($config['cookie_name'] . '_sid', \phpbb\request\request_interface::COOKIE) || $request->is_set($config['cookie_name'] . '_u', \phpbb\request\request_interface::COOKIE)) - { - $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->variable('sid', ''); - $SID = '?sid=' . $this->session_id; - $this->cookie_data = array('u' => 0, 'k' => ''); - } - } - else - { - $this->session_id = $_SID = $request->variable('sid', ''); - $SID = '?sid=' . $this->session_id; - } - - $_EXTRA_URL = array(); - - // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests - // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. - $ip = htmlspecialchars_decode($request->server('REMOTE_ADDR')); - $ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $ip)); - - /** - * Event to alter user IP address - * - * @event core.session_ip_after - * @var string ip REMOTE_ADDR - * @since 3.1.10-RC1 - */ - $vars = array('ip'); - extract($phpbb_dispatcher->trigger_event('core.session_ip_after', compact($vars))); - - // split the list of IPs - $ips = explode(' ', trim($ip)); - - // Default IP if REMOTE_ADDR is invalid - $this->ip = '127.0.0.1'; - - foreach ($ips as $ip) - { - if (function_exists('phpbb_ip_normalise')) - { - // Normalise IP address - $ip = phpbb_ip_normalise($ip); - - if (empty($ip)) - { - // IP address is invalid. - break; - } - - // IP address is valid. - $this->ip = $ip; - - // Skip legacy code. - continue; - } - - if (preg_match(get_preg_expression('ipv4'), $ip)) - { - $this->ip = $ip; - } - else if (preg_match(get_preg_expression('ipv6'), $ip)) - { - // Quick check for IPv4-mapped address in IPv6 - if (stripos($ip, '::ffff:') === 0) - { - $ipv4 = substr($ip, 7); - - if (preg_match(get_preg_expression('ipv4'), $ipv4)) - { - $ip = $ipv4; - } - } - - $this->ip = $ip; - } - else - { - // We want to use the last valid address in the chain - // Leave foreach loop when address is invalid - break; - } - } - - $this->load = false; - - // Load limit check (if applicable) - if ($config['limit_load'] || $config['limit_search_load']) - { - if ((function_exists('sys_getloadavg') && $load = sys_getloadavg()) || ($load = explode(' ', @file_get_contents('/proc/loadavg')))) - { - $this->load = array_slice($load, 0, 1); - $this->load = floatval($this->load[0]); - } - else - { - $config->set('limit_load', '0'); - $config->set('limit_search_load', '0'); - } - } - - // if no session id is set, redirect to index.php - $session_id = $request->variable('sid', ''); - if (defined('NEED_SID') && (empty($session_id) || $this->session_id !== $session_id)) - { - send_status_line(401, 'Unauthorized'); - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - // if session id is set - if (!empty($this->session_id)) - { - $sql = 'SELECT u.*, s.* - FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u - WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "' - AND u.user_id = s.session_user_id"; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Did the session exist in the DB? - if (isset($this->data['user_id'])) - { - // Validate IP length according to admin ... enforces an IP - // check on bots if admin requires this -// $quadcheck = ($config['ip_check_bot'] && $this->data['user_type'] & USER_BOT) ? 4 : $config['ip_check']; - - if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false) - { - $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']); - $u_ip = short_ipv6($this->ip, $config['ip_check']); - } - else - { - $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); - $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); - } - - $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : ''; - $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : ''; - - $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; - $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; - - // referer checks - // The @ before $config['referer_validation'] suppresses notices present while running the updater - $check_referer_path = (@$config['referer_validation'] == REFERER_VALIDATE_PATH); - $referer_valid = true; - - // we assume HEAD and TRACE to be foul play and thus only whitelist GET - if (@$config['referer_validation'] && strtolower($request->server('REQUEST_METHOD')) !== 'get') - { - $referer_valid = $this->validate_referer($check_referer_path); - } - - if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for && $referer_valid) - { - $session_expired = false; - - // Check whether the session is still valid if we have one - /* @var $provider_collection \phpbb\auth\provider_collection */ - $provider_collection = $phpbb_container->get('auth.provider_collection'); - $provider = $provider_collection->get_provider(); - - if (!($provider instanceof \phpbb\auth\provider\provider_interface)) - { - throw new \RuntimeException($provider . ' must implement \phpbb\auth\provider\provider_interface'); - } - - $ret = $provider->validate_session($this->data); - if ($ret !== null && !$ret) - { - $session_expired = true; - } - - if (!$session_expired) - { - // Check the session length timeframe if autologin is not enabled. - // Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide. - if (!$this->data['session_autologin']) - { - if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60)) - { - $session_expired = true; - } - } - else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60)) - { - $session_expired = true; - } - } - - if (!$session_expired) - { - $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; - $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false; - $this->data['user_lang'] = basename($this->data['user_lang']); - - // Is user banned? Are they excluded? Won't return on ban, exists within method - $this->check_ban_for_current_session($config); - - return true; - } - } - else - { - // Added logging temporarly to help debug bugs... - if (defined('DEBUG') && $this->data['user_id'] != ANONYMOUS) - { - if ($referer_valid) - { - $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 - { - $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_REFERER_INVALID', false, array($this->referer)); - } - } - } - } - } - - // If we reach here then no (valid) session exists. So we'll create a new one - return $this->session_create(); - } - - /** - * Create a new session - * - * If upon trying to start a session we discover there is nothing existing we - * jump here. Additionally this method is called directly during login to regenerate - * the session for the specific user. In this method we carry out a number of tasks; - * garbage collection, (search)bot checking, banned user comparison. Basically - * though this method will result in a new session for a specific user. - */ - function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true) - { - global $SID, $_SID, $db, $config, $cache, $phpbb_container, $phpbb_dispatcher; - - $this->data = array(); - - /* Garbage collection ... remove old sessions updating user information - // if necessary. It means (potentially) 11 queries but only infrequently - if ($this->time_now > $config['session_last_gc'] + $config['session_gc']) - { - $this->session_gc(); - }*/ - - // Do we allow autologin on this board? No? Then override anything - // that may be requested here - if (!$config['allow_autologin']) - { - $this->cookie_data['k'] = $persist_login = false; - } - - /** - * Here we do a bot check, oh er saucy! No, not that kind of bot - * check. We loop through the list of bots defined by the admin and - * see if we have any useragent and/or IP matches. If we do, this is a - * bot, act accordingly - */ - $bot = false; - $active_bots = $cache->obtain_bots(); - - foreach ($active_bots as $row) - { - if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser)) - { - $bot = $row['user_id']; - } - - // If ip is supplied, we will make sure the ip is matching too... - if ($row['bot_ip'] && ($bot || !$row['bot_agent'])) - { - // Set bot to false, then we only have to set it to true if it is matching - $bot = false; - - foreach (explode(',', $row['bot_ip']) as $bot_ip) - { - $bot_ip = trim($bot_ip); - - if (!$bot_ip) - { - continue; - } - - if (strpos($this->ip, $bot_ip) === 0) - { - $bot = (int) $row['user_id']; - break; - } - } - } - - if ($bot) - { - break; - } - } - - /* @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 && isset($this->data['user_id']) && $this->data['user_id'] != $user_id) - { - $this->data = array(); - } - - if (isset($this->data['user_id'])) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = $this->data['user_id']; - } - - // If we're presented with an autologin key we'll join against it. - // Else if we've been passed a user_id we'll grab data based on that - if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && empty($this->data)) - { - $sql = 'SELECT u.* - FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k - WHERE u.user_id = ' . (int) $this->cookie_data['u'] . ' - AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ") - AND k.user_id = u.user_id - AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; - $result = $db->sql_query($sql); - $user_data = $db->sql_fetchrow($result); - - if ($user_id === false || (isset($user_data['user_id']) && $user_id == $user_data['user_id'])) - { - $this->data = $user_data; - $bot = false; - } - - $db->sql_freeresult($result); - } - - if ($user_id !== false && empty($this->data)) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = $user_id; - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $this->cookie_data['u'] . ' - AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - $bot = false; - } - - // Bot user, if they have a SID in the Request URI we need to get rid of it - // otherwise they'll index this page with the SID, duplicate content oh my! - if ($bot && isset($_GET['sid'])) - { - send_status_line(301, 'Moved Permanently'); - redirect(build_url(array('sid'))); - } - - // If no data was returned one or more of the following occurred: - // Key didn't match one in the DB - // User does not exist - // User is inactive - // User is bot - if (!is_array($this->data) || !count($this->data)) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS; - - if (!$bot) - { - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $this->cookie_data['u']; - } - else - { - // We give bots always the same session if it is not yet expired. - $sql = 'SELECT u.*, s.* - FROM ' . USERS_TABLE . ' u - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) - WHERE u.user_id = ' . (int) $bot; - } - - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - if ($this->data['user_id'] != ANONYMOUS && !$bot) - { - $this->data['session_last_visit'] = (isset($this->data['session_time']) && $this->data['session_time']) ? $this->data['session_time'] : (($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : time()); - } - else - { - $this->data['session_last_visit'] = $this->time_now; - } - - // Force user id to be integer... - $this->data['user_id'] = (int) $this->data['user_id']; - - // At this stage we should have a filled data array, defined cookie u and k data. - // data array should contain recent session info if we're a real user and a recent - // session exists in which case session_id will also be set - - // Is user banned? Are they excluded? Won't return on ban, exists within method - $this->check_ban_for_current_session($config); - - $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; - $this->data['is_bot'] = ($bot) ? true : false; - - // If our friend is a bot, we re-assign a previously assigned session - if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id']) - { - // Only assign the current session if the ip, browser and forwarded_for match... - if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false) - { - $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']); - $u_ip = short_ipv6($this->ip, $config['ip_check']); - } - else - { - $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); - $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); - } - - $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : ''; - $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : ''; - - $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; - $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; - - if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for) - { - $this->session_id = $this->data['session_id']; - - // Only update session DB a minute or so after last update or if page changes - if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) - { - // Update the last visit time - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - } - - $SID = '?sid='; - $_SID = ''; - return true; - } - else - { - // If the ip and browser does not match make sure we only have one bot assigned to one session - $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']); - } - } - - $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false; - $set_admin = ($set_admin && $this->data['is_registered']) ? true : false; - - // Create or update the session - $sql_ary = array( - 'session_user_id' => (int) $this->data['user_id'], - 'session_start' => (int) $this->time_now, - 'session_last_visit' => (int) $this->data['session_last_visit'], - 'session_time' => (int) $this->time_now, - 'session_browser' => (string) trim(substr($this->browser, 0, 149)), - 'session_forwarded_for' => (string) $this->forwarded_for, - 'session_ip' => (string) $this->ip, - 'session_autologin' => ($session_autologin) ? 1 : 0, - 'session_admin' => ($set_admin) ? 1 : 0, - 'session_viewonline' => ($viewonline) ? 1 : 0, - ); - - if ($this->update_session_page) - { - $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - } - - $db->sql_return_on_error(true); - - $sql = 'DELETE - FROM ' . SESSIONS_TABLE . ' - WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\' - AND session_user_id = ' . ANONYMOUS; - - if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows())) - { - // Limit new sessions in 1 minute period (if required) - if (empty($this->data['session_time']) && $config['active_sessions']) - { -// $db->sql_return_on_error(false); - - $sql = 'SELECT COUNT(session_id) AS sessions - FROM ' . SESSIONS_TABLE . ' - WHERE session_time >= ' . ($this->time_now - 60); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ((int) $row['sessions'] > (int) $config['active_sessions']) - { - send_status_line(503, 'Service Unavailable'); - trigger_error('BOARD_UNAVAILABLE'); - } - } - } - - // Since we re-create the session id here, the inserted row must be unique. Therefore, we display potential errors. - // Commented out because it will not allow forums to update correctly -// $db->sql_return_on_error(false); - - // Something quite important: session_page always holds the *last* page visited, except for the *first* visit. - // We are not able to simply have an empty session_page btw, therefore we need to tell phpBB how to detect this special case. - // If the session id is empty, we have a completely new one and will set an "identifier" here. This identifier is able to be checked later. - if (empty($this->data['session_id'])) - { - // This is a temporary variable, only set for the very first visit - $this->data['session_created'] = true; - } - - $this->session_id = $this->data['session_id'] = md5(unique_id()); - - $sql_ary['session_id'] = (string) $this->session_id; - $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - - $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $db->sql_return_on_error(false); - - // Regenerate autologin/persistent login key - if ($session_autologin) - { - $this->set_login_key(); - } - - // refresh data - $SID = '?sid=' . $this->session_id; - $_SID = $this->session_id; - $this->data = array_merge($this->data, $sql_ary); - - if (!$bot) - { - $cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000); - - $this->set_cookie('u', $this->cookie_data['u'], $cookie_expire); - $this->set_cookie('k', $this->cookie_data['k'], $cookie_expire); - $this->set_cookie('sid', $this->session_id, $cookie_expire); - - unset($cookie_expire); - - $sql = 'SELECT COUNT(session_id) AS sessions - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . (int) $this->data['user_id'] . ' - AND session_time >= ' . (int) ($this->time_now - (max((int) $config['session_length'], (int) $config['form_token_lifetime']))); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ((int) $row['sessions'] <= 1 || empty($this->data['user_form_salt'])) - { - $this->data['user_form_salt'] = unique_id(); - // Update the form key - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - } - } - else - { - $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now; - - // Update the last visit time - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - - $SID = '?sid='; - $_SID = ''; - } - - $session_data = $sql_ary; - /** - * Event to send new session data to extension - * Read-only event - * - * @event core.session_create_after - * @var array session_data Associative array of session keys to be updated - * @since 3.1.6-RC1 - */ - $vars = array('session_data'); - extract($phpbb_dispatcher->trigger_event('core.session_create_after', compact($vars))); - unset($session_data); - - return true; - } - - /** - * Kills a session - * - * This method does what it says on the tin. It will delete a pre-existing session. - * It resets cookie information (destroying any autologin key within that cookie data) - * and update the users information from the relevant session data. It will then - * grab guest user information. - */ - function session_kill($new_session = true) - { - global $SID, $_SID, $db, $phpbb_container, $phpbb_dispatcher; - - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - WHERE session_id = '" . $db->sql_escape($this->session_id) . "' - AND session_user_id = " . (int) $this->data['user_id']; - $db->sql_query($sql); - - $user_id = (int) $this->data['user_id']; - $session_id = $this->session_id; - /** - * Event to send session kill information to extension - * Read-only event - * - * @event core.session_kill_after - * @var int user_id user_id of the session user. - * @var string session_id current user's session_id - * @var bool new_session should we create new session for user - * @since 3.1.6-RC1 - */ - $vars = array('user_id', 'session_id', 'new_session'); - extract($phpbb_dispatcher->trigger_event('core.session_kill_after', compact($vars))); - unset($user_id); - 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); - - if ($this->data['user_id'] != ANONYMOUS) - { - // Delete existing session, update last visit info first! - if (!isset($this->data['session_time'])) - { - $this->data['session_time'] = time(); - } - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - - if ($this->cookie_data['k']) - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $this->data['user_id'] . " - AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; - $db->sql_query($sql); - } - - // Reset the data array - $this->data = array(); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . ANONYMOUS; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - $cookie_expire = $this->time_now - 31536000; - $this->set_cookie('u', '', $cookie_expire); - $this->set_cookie('k', '', $cookie_expire); - $this->set_cookie('sid', '', $cookie_expire); - unset($cookie_expire); - - $SID = '?sid='; - $this->session_id = $_SID = ''; - - // To make sure a valid session is created we create one for the anonymous user - if ($new_session) - { - $this->session_create(ANONYMOUS); - } - - return true; - } - - /** - * Session garbage collection - * - * This looks a lot more complex than it really is. Effectively we are - * deleting any sessions older than an admin definable limit. Due to the - * way in which we maintain session data we have to ensure we update user - * data before those sessions are destroyed. In addition this method - * removes autologin key information that is older than an admin defined - * limit. - */ - function session_gc() - { - global $db, $config, $phpbb_container, $phpbb_dispatcher; - - $batch_size = 10; - - if (!$this->time_now) - { - $this->time_now = time(); - } - - // Firstly, delete guest sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . ANONYMOUS . ' - AND session_time < ' . (int) ($this->time_now - $config['session_length']); - $db->sql_query($sql); - - // Get expired sessions, only most recent for each user - $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time - FROM ' . SESSIONS_TABLE . ' - WHERE session_time < ' . ($this->time_now - $config['session_length']) . ' - GROUP BY session_user_id, session_page'; - $result = $db->sql_query_limit($sql, $batch_size); - - $del_user_id = array(); - $del_sessions = 0; - - while ($row = $db->sql_fetchrow($result)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $row['session_user_id']; - $db->sql_query($sql); - - $del_user_id[] = (int) $row['session_user_id']; - $del_sessions++; - } - $db->sql_freeresult($result); - - if (count($del_user_id)) - { - // Delete expired sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . ' - AND session_time < ' . ($this->time_now - $config['session_length']); - $db->sql_query($sql); - } - - if ($del_sessions < $batch_size) - { - // Less than 10 users, update gc timer ... else we want gc - // called again to delete other sessions - $config->set('session_last_gc', $this->time_now, false); - - if ($config['max_autologin_time']) - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); - $db->sql_query($sql); - } - - // only called from CRON; should be a safe workaround until the infrastructure gets going - /* @var $captcha_factory \phpbb\captcha\factory */ - $captcha_factory = $phpbb_container->get('captcha.factory'); - $captcha_factory->garbage_collect($config['captcha_plugin']); - - $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']); - $db->sql_query($sql); - } - - /** - * Event to trigger extension on session_gc - * - * @event core.session_gc_after - * @since 3.1.6-RC1 - */ - $phpbb_dispatcher->dispatch('core.session_gc_after'); - - return; - } - - /** - * Sets a cookie - * - * Sets a cookie of the given name with the specified data for the given length of time. If no time is specified, a session cookie will be set. - * - * @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then. - * @param string $cookiedata The data to hold within the cookie - * @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set. - * @param bool $httponly Use HttpOnly. Defaults to true. Use false to make cookie accessible by client-side scripts. - */ - function set_cookie($name, $cookiedata, $cookietime, $httponly = true) - { - global $config; - - // If headers are already set, we just return - if (headers_sent()) - { - return; - } - - $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata); - $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime); - $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == '127.0.0.1' || strpos($config['cookie_domain'], '.') === false) ? '' : '; domain=' . $config['cookie_domain']; - - header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . ';' . (($httponly) ? ' HttpOnly' : ''), false); - } - - /** - * Check for banned user - * - * Checks whether the supplied user is banned by id, ip or email. If no parameters - * are passed to the method pre-existing session data is used. - * - * @param int|false $user_id The user id - * @param mixed $user_ips Can contain a string with one IP or an array of multiple IPs - * @param string|false $user_email The user email - * @param bool $return If $return is false this routine does not return on finding a banned user, - * it outputs a relevant message and stops execution. - */ - function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false) - { - global $config, $db, $phpbb_dispatcher; - - if (defined('IN_CHECK_BAN') || defined('SKIP_CHECK_BAN')) - { - return; - } - - $banned = false; - $cache_ttl = 3600; - $where_sql = array(); - - $sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end - FROM ' . BANLIST_TABLE . ' - WHERE '; - - // Determine which entries to check, only return those - if ($user_email === false) - { - $where_sql[] = "ban_email = ''"; - } - - if ($user_ips === false) - { - $where_sql[] = "(ban_ip = '' OR ban_exclude = 1)"; - } - - if ($user_id === false) - { - $where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)'; - } - else - { - $cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0; - $_sql = '(ban_userid = ' . $user_id; - - if ($user_email !== false) - { - $_sql .= " OR ban_email <> ''"; - } - - if ($user_ips !== false) - { - $_sql .= " OR ban_ip <> ''"; - } - - $_sql .= ')'; - - $where_sql[] = $_sql; - } - - $sql .= (count($where_sql)) ? implode(' AND ', $where_sql) : ''; - $result = $db->sql_query($sql, $cache_ttl); - - $ban_triggered_by = 'user'; - while ($row = $db->sql_fetchrow($result)) - { - if ($row['ban_end'] && $row['ban_end'] < time()) - { - continue; - } - - $ip_banned = false; - if (!empty($row['ban_ip'])) - { - if (!is_array($user_ips)) - { - $ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips); - } - else - { - foreach ($user_ips as $user_ip) - { - if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip)) - { - $ip_banned = true; - break; - } - } - } - } - - if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) || - $ip_banned || - (!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email))) - { - if (!empty($row['ban_exclude'])) - { - $banned = false; - break; - } - else - { - $banned = true; - $ban_row = $row; - - if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) - { - $ban_triggered_by = 'user'; - } - else if ($ip_banned) - { - $ban_triggered_by = 'ip'; - } - else - { - $ban_triggered_by = 'email'; - } - - // Don't break. Check if there is an exclude rule for this user - } - } - } - $db->sql_freeresult($result); - - /** - * Event to set custom ban type - * - * @event core.session_set_custom_ban - * @var bool return If $return is false this routine does not return on finding a banned user, it outputs a relevant message and stops execution - * @var bool banned Check if user already banned - * @var array|false ban_row Ban data - * @var string ban_triggered_by Method that caused ban, can be your custom method - * @since 3.1.3-RC1 - */ - $ban_row = isset($ban_row) ? $ban_row : false; - $vars = array('return', 'banned', 'ban_row', 'ban_triggered_by'); - extract($phpbb_dispatcher->trigger_event('core.session_set_custom_ban', compact($vars))); - - if ($banned && !$return) - { - global $phpbb_root_path, $phpEx; - - // If the session is empty we need to create a valid one... - if (empty($this->session_id)) - { - // This seems to be no longer needed? - #14971 -// $this->session_create(ANONYMOUS); - } - - // Initiate environment ... since it won't be set at this stage - $this->setup(); - - // Logout the user, banned users are unable to use the normal 'logout' link - if ($this->data['user_id'] != ANONYMOUS) - { - $this->session_kill(); - } - - // We show a login box here to allow founders accessing the board if banned by IP - if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS) - { - $this->setup('ucp'); - $this->data['is_registered'] = $this->data['is_bot'] = false; - - // Set as a precaution to allow login_box() handling this case correctly as well as this function not being executed again. - define('IN_CHECK_BAN', 1); - - login_box("index.$phpEx"); - - // The false here is needed, else the user is able to circumvent the ban. - $this->session_kill(false); - } - - // Ok, we catch the case of an empty session id for the anonymous user... - // This can happen if the user is logging in, banned by username and the login_box() being called "again". - if (empty($this->session_id) && defined('IN_CHECK_BAN')) - { - $this->session_create(ANONYMOUS); - } - - // Determine which message to output - $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : ''; - $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM'; - - $contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx); - $message = sprintf($this->lang[$message], $till_date, '', ''); - $message .= ($ban_row['ban_give_reason']) ? '

' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : ''; - $message .= '

' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . ''; - - // A very special case... we are within the cron script which is not supposed to print out the ban message... show blank page - if (defined('IN_CRON')) - { - garbage_collection(); - exit_handler(); - exit; - } - - // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again - $this->session_kill(false); - - trigger_error($message); - } - - if (!empty($ban_row)) - { - $ban_row['ban_triggered_by'] = $ban_triggered_by; - } - - return ($banned && $ban_row) ? $ban_row : $banned; - } - - /** - * Check the current session for bans - * - * @return true if session user is banned. - */ - protected function check_ban_for_current_session($config) - { - if (!defined('SKIP_CHECK_BAN') && $this->data['user_type'] != USER_FOUNDER) - { - if (!$config['forwarded_for_check']) - { - $this->check_ban($this->data['user_id'], $this->ip); - } - else - { - $ips = explode(' ', $this->forwarded_for); - $ips[] = $this->ip; - $this->check_ban($this->data['user_id'], $ips); - } - } - } - - /** - * Check if ip is blacklisted - * This should be called only where absolutely necessary - * - * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups) - * - * @author satmd (from the php manual) - * @param string $mode register/post - spamcop for example is ommitted for posting - * @param string|false $ip the IPv4 address to check - * - * @return false if ip is not blacklisted, else an array([checked server], [lookup]) - */ - function check_dnsbl($mode, $ip = false) - { - if ($ip === false) - { - $ip = $this->ip; - } - - // Neither Spamhaus nor Spamcop supports IPv6 addresses. - if (strpos($ip, ':') !== false) - { - return false; - } - - $dnsbl_check = array( - 'sbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=', - ); - - if ($mode == 'register') - { - $dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?'; - } - - if ($ip) - { - $quads = explode('.', $ip); - $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0]; - - // Need to be listed on all servers... - $listed = true; - $info = array(); - - foreach ($dnsbl_check as $dnsbl => $lookup) - { - if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true) - { - $info = array($dnsbl, $lookup . $ip); - } - else - { - $listed = false; - } - } - - if ($listed) - { - return $info; - } - } - - return false; - } - - /** - * Check if URI is blacklisted - * This should be called only where absolutly necessary, for example on the submitted website field - * This function is not in use at the moment and is only included for testing purposes, it may not work at all! - * This means it is untested at the moment and therefore commented out - * - * @param string $uri URI to check - * @return true if uri is on blacklist, else false. Only blacklist is checked (~zero FP), no grey lists - function check_uribl($uri) - { - // Normally parse_url() is not intended to parse uris - // We need to get the top-level domain name anyway... change. - $uri = parse_url($uri); - - if ($uri === false || empty($uri['host'])) - { - return false; - } - - $uri = trim($uri['host']); - - if ($uri) - { - // One problem here... the return parameter for the "windows" method is different from what - // we expect... this may render this check useless... - if (phpbb_checkdnsrr($uri . '.multi.uribl.com.', 'A') === true) - { - return true; - } - } - - return false; - } - */ - - /** - * Set/Update a persistent login key - * - * This method creates or updates a persistent session key. When a user makes - * use of persistent (formerly auto-) logins a key is generated and stored in the - * DB. When they revisit with the same key it's automatically updated in both the - * DB and cookie. Multiple keys may exist for each user representing different - * browsers or locations. As with _any_ non-secure-socket no passphrase login this - * remains vulnerable to exploit. - */ - function set_login_key($user_id = false, $key = false, $user_ip = false) - { - global $db; - - $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id; - $user_ip = ($user_ip === false) ? $this->ip : $user_ip; - $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key; - - $key_id = unique_id(hexdec(substr($this->session_id, 0, 8))); - - $sql_ary = array( - 'key_id' => (string) md5($key_id), - 'last_ip' => (string) $user_ip, - 'last_login' => (int) time() - ); - - if (!$key) - { - $sql_ary += array( - 'user_id' => (int) $user_id - ); - } - - if ($key) - { - $sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . (int) $user_id . " - AND key_id = '" . $db->sql_escape(md5($key)) . "'"; - } - else - { - $sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - } - $db->sql_query($sql); - - $this->cookie_data['k'] = $key_id; - - return false; - } - - /** - * Reset all login keys for the specified user - * - * This method removes all current login keys for a specified (or the current) - * user. It will be called on password change to render old keys unusable - */ - function reset_login_keys($user_id = false) - { - global $db; - - $user_id = ($user_id === false) ? (int) $this->data['user_id'] : (int) $user_id; - - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $user_id; - $db->sql_query($sql); - - // If the user is logged in, update last visit info first before deleting sessions - $sql = 'SELECT session_time, session_page - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . (int) $user_id . ' - ORDER BY session_time DESC'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['session_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $user_id; - $db->sql_query($sql); - } - - // Let's also clear any current sessions for the specified user_id - // If it's the current user then we'll leave this session intact - $sql_where = 'session_user_id = ' . (int) $user_id; - $sql_where .= ($user_id === (int) $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : ''; - - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - WHERE $sql_where"; - $db->sql_query($sql); - - // We're changing the password of the current user and they have a key - // Lets regenerate it to be safe - if ($user_id === (int) $this->data['user_id'] && $this->cookie_data['k']) - { - $this->set_login_key($user_id); - } - } - - - /** - * Check if the request originated from the same page. - * @param bool $check_script_path If true, the path will be checked as well - */ - function validate_referer($check_script_path = false) - { - global $config, $request; - - // no referer - nothing to validate, user's fault for turning it off (we only check on POST; so meta can't be the reason) - if (empty($this->referer) || empty($this->host)) - { - return true; - } - - $host = htmlspecialchars($this->host); - $ref = substr($this->referer, strpos($this->referer, '://') + 3); - - if (!(stripos($ref, $host) === 0) && (!$config['force_server_vars'] || !(stripos($ref, $config['server_name']) === 0))) - { - return false; - } - else if ($check_script_path && rtrim($this->page['root_script_path'], '/') !== '') - { - $ref = substr($ref, strlen($host)); - $server_port = $request->server('SERVER_PORT', 0); - - if ($server_port !== 80 && $server_port !== 443 && stripos($ref, ":$server_port") === 0) - { - $ref = substr($ref, strlen(":$server_port")); - } - - if (!(stripos(rtrim($ref, '/'), rtrim($this->page['root_script_path'], '/')) === 0)) - { - return false; - } - } - - return true; - } - - - function unset_admin() - { - global $db; - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_admin = 0 - WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\''; - $db->sql_query($sql); - } - - /** - * Update the session data - * - * @param array $session_data associative array of session keys to be updated - * @param string $session_id optional session_id, defaults to current user's session_id - */ - public function update_session($session_data, $session_id = null) - { - global $db, $phpbb_dispatcher; - - $session_id = ($session_id) ? $session_id : $this->session_id; - - $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $session_data) . " - WHERE session_id = '" . $db->sql_escape($session_id) . "'"; - $db->sql_query($sql); - - /** - * Event to send update session information to extension - * Read-only event - * - * @event core.update_session_after - * @var array session_data Associative array of session keys to be updated - * @var string session_id current user's session_id - * @since 3.1.6-RC1 - */ - $vars = array('session_data', 'session_id'); - extract($phpbb_dispatcher->trigger_event('core.update_session_after', compact($vars))); - } - - public function update_session_infos() - { - global $config, $db, $request; - - // No need to update if it's a new session. Informations are already inserted by session_create() - if (isset($this->data['session_created']) && $this->data['session_created']) - { - 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 || $page_changed) - { - $sql_ary = array('session_time' => $this->time_now); - - if ($page_changed) - { - $sql_ary['session_page'] = substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - } - - $db->sql_return_on_error(true); - - $this->update_session($sql_ary); - - $db->sql_return_on_error(false); - - $this->data = array_merge($this->data, $sql_ary); - - if ($this->data['user_id'] != ANONYMOUS && isset($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts']) - { - $this->leave_newly_registered(); - } - } - } -} diff --git a/install/update/old/phpbb/template/asset.php b/install/update/old/phpbb/template/asset.php deleted file mode 100644 index cb00f16..0000000 --- a/install/update/old/phpbb/template/asset.php +++ /dev/null @@ -1,210 +0,0 @@ - -* @license 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 asset -{ - protected $components = array(); - - /** @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, \phpbb\filesystem\filesystem $filesystem) - { - $this->path_helper = $path_helper; - $this->filesystem = $filesystem; - - $this->set_url($url); - } - - /** - * Set URL - * - * @param string $url URL - */ - public function set_url($url) - { - if (version_compare(PHP_VERSION, '5.4.7') < 0 && substr($url, 0, 2) === '//') - { - // Workaround for PHP 5.4.6 and older bug #62844 - add fake scheme and then remove it - $this->components = parse_url('http:' . $url); - $this->components['scheme'] = ''; - return; - } - $this->components = parse_url($url); - } - - /** - * Convert URL components into string - * - * @param array $components URL components - * @return string URL - */ - protected function join_url($components) - { - $path = ''; - if (isset($components['scheme'])) - { - $path = $components['scheme'] === '' ? '//' : $components['scheme'] . '://'; - } - - if (isset($components['user']) || isset($components['pass'])) - { - if ($path === '' && !isset($components['port'])) - { - $path = '//'; - } - $path .= $components['user']; - if (isset($components['pass'])) - { - $path .= ':' . $components['pass']; - } - $path .= '@'; - } - - if (isset($components['host'])) - { - if ($path === '' && !isset($components['port'])) - { - $path = '//'; - } - $path .= $components['host']; - if (isset($components['port'])) - { - $path .= ':' . $components['port']; - } - } - - if (isset($components['path'])) - { - $path .= $components['path']; - } - - if (isset($components['query'])) - { - $path .= '?' . $components['query']; - } - - if (isset($components['fragment'])) - { - $path .= '#' . $components['fragment']; - } - - return $path; - } - - /** - * Get URL - * - * @return string URL - */ - public function get_url() - { - return $this->path_helper->update_web_root_path($this->join_url($this->components)); - } - - /** - * Checks if URL is local and relative - * - * @return boolean True if URL is local and relative - */ - public function is_relative() - { - if (empty($this->components) || !isset($this->components['path'])) - { - // Invalid URL - return false; - } - return !isset($this->components['scheme']) && !isset($this->components['host']) && substr($this->components['path'], 0, 1) !== '/'; - } - - /** - * Get path component of current URL - * - * @return string Path - */ - public function get_path() - { - return isset($this->components['path']) ? $this->components['path'] : ''; - } - - /** - * Set path component - * - * @param string $path Path component - * @param boolean $urlencode If true, parts of path should be encoded with rawurlencode() - */ - 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. - $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 ($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 = $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))); - } - } - - if ($urlencode) - { - $paths = explode('/', $path); - foreach ($paths as &$dir) - { - $dir = rawurlencode($dir); - } - $path = implode('/', $paths); - } - - $this->components['path'] = $path; - } - - /** - * Add assets_version parameter to URL. - * Parameter will not be added if assets_version already exists in URL - * - * @param string $version Version - */ - public function add_assets_version($version) - { - if (!isset($this->components['query'])) - { - $this->components['query'] = 'assets_version=' . $version; - return; - } - $query = $this->components['query']; - if (!preg_match('/(^|[&;])assets_version=/', $query)) - { - $this->components['query'] = $query . '&assets_version=' . $version; - } - } -} diff --git a/install/update/old/phpbb/template/context.php b/install/update/old/phpbb/template/context.php deleted file mode 100644 index 202e29c..0000000 --- a/install/update/old/phpbb/template/context.php +++ /dev/null @@ -1,631 +0,0 @@ - -* @license 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; - -/** -* Stores variables assigned to template. -*/ -class context -{ - /** - * variable that holds all the data we'll be substituting into - * the compiled templates. Takes form: - * --> $this->tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value - * if it's a root-level variable, it'll be like this: - * --> $this->tpldata[.][0][varname] == value - * - * @var array - */ - private $tpldata = array('.' => array(0 => array())); - - /** - * @var array Reference to template->tpldata['.'][0] - */ - private $rootref; - - /** - * @var bool - */ - private $num_rows_is_set; - - public function __construct() - { - $this->clear(); - } - - /** - * Clears template data set. - */ - public function clear() - { - $this->tpldata = array('.' => array(0 => array())); - $this->rootref = &$this->tpldata['.'][0]; - $this->num_rows_is_set = false; - } - - /** - * Assign a single scalar value to a single key. - * - * Value can be a string, an integer or a boolean. - * - * @param string $varname Variable name - * @param string $varval Value to assign to variable - * @return true - */ - public function assign_var($varname, $varval) - { - $this->rootref[$varname] = $varval; - - return true; - } - - /** - * Append text to the string value stored in a key. - * - * Text is appended using the string concatenation operator (.). - * - * @param string $varname Variable name - * @param string $varval Value to append to variable - * @return true - */ - public function append_var($varname, $varval) - { - $this->rootref[$varname] = (isset($this->rootref[$varname]) ? $this->rootref[$varname] : '') . $varval; - - return true; - } - - /** - * 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. - * Users should alter template variables via functions in \phpbb\template\template. - * - * Note: modifying returned array will affect data stored in the context. - * - * @return array template data - */ - public function &get_data_ref() - { - // returning a reference directly is not - // something php is capable of doing - $ref = &$this->tpldata; - - if (!$this->num_rows_is_set) - { - /* - * We do not set S_NUM_ROWS while adding a row, to reduce the complexity - * If we would set it on adding, each subsequent adding would cause - * n modifications, resulting in a O(n!) complexity, rather then O(n) - */ - foreach ($ref as $loop_name => &$loop_data) - { - if ($loop_name === '.') - { - continue; - } - - $this->set_num_rows($loop_data); - } - $this->num_rows_is_set = true; - } - - return $ref; - } - - /** - * Set S_NUM_ROWS for each row in this template block - * - * @param array $loop_data - */ - protected function set_num_rows(&$loop_data) - { - $s_num_rows = count($loop_data); - foreach ($loop_data as &$mod_block) - { - foreach ($mod_block as $sub_block_name => &$sub_block) - { - // If the key name is lowercase and the data is an array, - // it could be a template loop. So we set the S_NUM_ROWS there - // aswell. - if ($sub_block_name === strtolower($sub_block_name) && is_array($sub_block)) - { - $this->set_num_rows($sub_block); - } - } - - // Check whether we are inside a block before setting the variable - if (isset($mod_block['S_BLOCK_NAME'])) - { - $mod_block['S_NUM_ROWS'] = $s_num_rows; - } - } - } - - /** - * Returns a reference to template root scope. - * - * This function is public so that template renderer may invoke it. - * Users should not need to invoke this function. - * - * Note: modifying returned array will affect data stored in the context. - * - * @return array template data - */ - public function &get_root_ref() - { - // rootref is already a reference - return $this->rootref; - } - - /** - * Assign key variable pairs from an array to a specified block - * - * @param string $blockname Name of block to assign $vararray to - * @param array $vararray A hash of variable name => value pairs - * @return true - */ - public function assign_block_vars($blockname, array $vararray) - { - $this->num_rows_is_set = false; - - // 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]; - $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]; - } - - // $block = &$block[$blocks[$i]]; // Do not traverse the last block as it might be empty - $name = $blocks[$i]; - - // 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; - - // Assign S_FIRST_ROW - if (!$s_row_count) - { - $vararray['S_FIRST_ROW'] = true; - } - - // Assign S_BLOCK_NAME - $vararray['S_BLOCK_NAME'] = $name; - - // 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; - } - - /** - * Assign key variable pairs from an array to a whole specified block loop - * - * @param string $blockname Name of block to assign $block_vars_array to - * @param array $block_vars_array An array of hashes of variable name => value pairs - * @return true - */ - public function assign_block_vars_array($blockname, array $block_vars_array) - { - foreach ($block_vars_array as $vararray) - { - $this->assign_block_vars($blockname, $vararray); - } - - return true; - } - - /** - * Retrieve key variable pairs from the specified block - * - * @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 retrieve_block_vars($blockname, array $vararray) - { - // 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++) - { - if (($pos = strpos($blocks[$i], '[')) !== false) - { - $name = substr($blocks[$i], 0, $pos); - - if (empty($block[$name])) - { - return array(); - } - - if (strpos($blocks[$i], '[]') === $pos) - { - $index = count($block[$name]) - 1; - } - else - { - $index = min((int) substr($blocks[$i], $pos + 1, -1), count($block[$name]) - 1); - } - } - else - { - $name = $blocks[$i]; - 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; - } - - $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[$name][$index]; - } - - if (!isset($block[$blocks[$i]])) - { - return false; - } - $block = $block[$blocks[$i]]; // Traverse the last block - - // Change key to zero (change first position) if false and to last position if true - if (is_bool($key)) - { - return (!$key) ? 0 : count($block) - 1; - } - - // Get correct position if array given - if (is_array($key)) - { - // Search array to get correct position - list($search_key, $search_value) = @each($key); - foreach ($block as $i => $val_ary) - { - if ($val_ary[$search_key] === $search_value) - { - return $i; - } - } - } - - return (is_int($key) && ((0 <= $key) && ($key < count($block)))) ? $key : false; - } - - /** - * Change already assigned key variable pair (one-dimensional - single loop entry) - * - * An example of how to use this function: - * {@example alter_block_array.php} - * - * @param string $blockname the blockname, for example 'loop' - * @param array $vararray the var array to insert/add or merge - * @param mixed $key Key to search for - * - * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] - * - * int: Position [the position to change or insert at directly given] - * - * If key is false the position is set to 0 - * If key is true the position is set to the last entry - * - * @param string $mode Mode to execute (valid modes are 'insert', '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) - * - * @return bool false on error, true on success - */ - public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') - { - $this->num_rows_is_set = false; - - // 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++) - { - if (($pos = strpos($blocks[$i], '[')) !== false) - { - $name = substr($blocks[$i], 0, $pos); - - if (strpos($blocks[$i], '[]') === $pos) - { - $index = count($block[$name]) - 1; - } - else - { - $index = min((int) substr($blocks[$i], $pos + 1, -1), count($block[$name]) - 1); - } - } - else - { - $name = $blocks[$i]; - $index = count($block[$name]) - 1; - } - $block = &$block[$name]; - $block = &$block[$index]; - } - $name = $blocks[$i]; - - // If last block does not exist and we are inserting, and not searching for key, we create it empty; otherwise, nothing to do - if (!isset($block[$name])) - { - if ($mode != 'insert' || is_array($key)) - { - return false; - } - $block[$name] = array(); - } - - $block = &$block[$name]; // Now we can traverse the last block - - // Change key to zero (change first position) if false and to last position if true - if ($key === false || $key === true) - { - $key = ($key === false) ? 0 : count($block); - } - - // Get correct position if array given - if (is_array($key)) - { - // Search array to get correct position - list($search_key, $search_value) = @each($key); - - $key = null; - foreach ($block as $i => $val_ary) - { - if ($val_ary[$search_key] === $search_value) - { - $key = $i; - break; - } - } - - // key/value pair not found - if ($key === null) - { - return false; - } - } - - // Insert Block - if ($mode == 'insert') - { - // Make sure we are not exceeding the last iteration - if ($key >= count($block)) - { - $key = count($block); - unset($block[($key - 1)]['S_LAST_ROW']); - $vararray['S_LAST_ROW'] = true; - } - if ($key <= 0) - { - $key = 0; - unset($block[0]['S_FIRST_ROW']); - $vararray['S_FIRST_ROW'] = true; - } - - // Assign S_BLOCK_NAME - $vararray['S_BLOCK_NAME'] = $name; - - // Re-position template blocks - for ($i = count($block); $i > $key; $i--) - { - $block[$i] = $block[$i-1]; - - $block[$i]['S_ROW_COUNT'] = $block[$i]['S_ROW_NUM'] = $i; - } - - // Insert vararray at given position - $block[$key] = $vararray; - $block[$key]['S_ROW_COUNT'] = $block[$key]['S_ROW_NUM'] = $key; - - return true; - } - - // Which block to change? - if ($mode == 'change') - { - // If key is out of bounds, do not change anything - if ($key > count($block) || $key < 0) - { - return false; - } - - if ($key == count($block)) - { - $key--; - } - - $block[$key] = array_merge($block[$key], $vararray); - - 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; - } - - /** - * Reset/empty complete block - * - * @param string $blockname Name of block to destroy - * @return true - */ - public function destroy_block_vars($blockname) - { - $this->num_rows_is_set = false; - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = count($blocks) - 1; - - $str = &$this->tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - $str = &$str[$blocks[$i]]; - $str = &$str[count($str) - 1]; - } - - unset($str[$blocks[$blockcount]]); - } - else - { - // Top-level block. - unset($this->tpldata[$blockname]); - } - - return true; - } -} diff --git a/install/update/old/phpbb/template/template.php b/install/update/old/phpbb/template/template.php deleted file mode 100644 index df83d5b..0000000 --- a/install/update/old/phpbb/template/template.php +++ /dev/null @@ -1,224 +0,0 @@ - -* @license 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; - -interface template -{ - - /** - * Clear the cache - * - * @return \phpbb\template\template - */ - public function clear_cache(); - - /** - * Sets the template filenames for handles. - * - * @param array $filename_array Should be a hash of handle => filename pairs. - * @return \phpbb\template\template $this - */ - public function set_filenames(array $filename_array); - - /** - * Get the style tree of the style preferred by the current user - * - * @return array Style tree, most specific first - */ - public function get_user_style(); - - /** - * Set style location based on (current) user's chosen style. - * - * @param array $style_directories The directories to add style paths for - * E.g. array('ext/foo/bar/styles', 'styles') - * Default: array('styles') (phpBB's style directory) - * @return \phpbb\template\template $this - */ - public function set_style($style_directories = array('styles')); - - /** - * Set custom style location (able to use directory outside of phpBB). - * - * Note: Templates are still compiled to phpBB's cache directory. - * - * @param string|array $names Array of names or string of name of template(s) in inheritance tree order, used by extensions. - * @param string|array or string $paths Array of style paths, relative to current root directory - * @return \phpbb\template\template $this - */ - public function set_custom_style($names, $paths); - - /** - * Clears all variables and blocks assigned to this template. - * - * @return \phpbb\template\template $this - */ - public function destroy(); - - /** - * Reset/empty complete block - * - * @param string $blockname Name of block to destroy - * @return \phpbb\template\template $this - */ - public function destroy_block_vars($blockname); - - /** - * Display a template for provided handle. - * - * The template will be loaded and compiled, if necessary, first. - * - * This function calls hooks. - * - * @param string $handle Handle to display - * @return \phpbb\template\template $this - */ - public function display($handle); - - /** - * Display the handle and assign the output to a template variable - * or return the compiled result. - * - * @param string $handle Handle to operate on - * @param string $template_var Template variable to assign compiled handle to - * @param bool $return_content If true return compiled handle, otherwise assign to $template_var - * @return \phpbb\template\template|string if $return_content is true return string of the compiled handle, otherwise return $this - */ - public function assign_display($handle, $template_var = '', $return_content = true); - - /** - * Assign key variable pairs from an array - * - * @param array $vararray A hash of variable name => value pairs - * @return \phpbb\template\template $this - */ - public function assign_vars(array $vararray); - - /** - * Assign a single scalar value to a single key. - * - * Value can be a string, an integer or a boolean. - * - * @param string $varname Variable name - * @param string $varval Value to assign to variable - * @return \phpbb\template\template $this - */ - public function assign_var($varname, $varval); - - /** - * Append text to the string value stored in a key. - * - * Text is appended using the string concatenation operator (.). - * - * @param string $varname Variable name - * @param string $varval Value to append to variable - * @return \phpbb\template\template $this - */ - 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 - * @return \phpbb\template\template $this - */ - public function assign_block_vars($blockname, array $vararray); - - /** - * Assign key variable pairs from an array to a whole specified block loop - * @param string $blockname Name of block to assign $block_vars_array to - * @param array $block_vars_array An array of hashes of variable name => value pairs - * @return \phpbb\template\template $this - */ - 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: - * {@example alter_block_array.php} - * - * @param string $blockname the blockname, for example 'loop' - * @param array $vararray the var array to insert/add or merge - * @param mixed $key Key to search for - * - * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] - * - * int: Position [the position to change or insert at directly given] - * - * If key is false the position is set to 0 - * If key is true the position is set to the last entry - * - * @param string $mode Mode to execute (valid modes are 'insert', '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) - * - * @return bool false on error, true on success - */ - public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert'); - - /** - * 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); - - /** - * Get path to template for handle (required for BBCode parser) - * - * @param string $handle Handle to retrieve the source file - * @return string - */ - public function get_source_file_for_handle($handle); -} diff --git a/install/update/old/phpbb/template/twig/extension.php b/install/update/old/phpbb/template/twig/extension.php deleted file mode 100644 index f6f8e03..0000000 --- a/install/update/old/phpbb/template/twig/extension.php +++ /dev/null @@ -1,185 +0,0 @@ - -* @license 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; - -class extension extends \Twig_Extension -{ - /** @var \phpbb\template\context */ - protected $context; - - /** @var \phpbb\language\language */ - protected $language; - - /** - * Constructor - * - * @param \phpbb\template\context $context - * @param \phpbb\language\language $language - * @return \phpbb\template\twig\extension - */ - public function __construct(\phpbb\template\context $context, $language) - { - $this->context = $context; - $this->language = $language; - } - - /** - * Get the name of this extension - * - * @return string - */ - public function getName() - { - return 'phpbb'; - } - - /** - * Returns the token parser instance to add to the existing list. - * - * @return array An array of Twig_TokenParser instances - */ - public function getTokenParsers() - { - return array( - new \phpbb\template\twig\tokenparser\defineparser, - new \phpbb\template\twig\tokenparser\includeparser, - new \phpbb\template\twig\tokenparser\includejs, - new \phpbb\template\twig\tokenparser\includecss, - new \phpbb\template\twig\tokenparser\event, - new \phpbb\template\twig\tokenparser\includephp, - new \phpbb\template\twig\tokenparser\php, - ); - } - - /** - * Returns a list of filters to add to the existing list. - * - * @return array An array of filters - */ - public function getFilters() - { - 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'), - ); - } - - /** - * Returns a list of global functions to add to the existing list. - * - * @return array An array of global functions - */ - public function getFunctions() - { - return array( - new \Twig_SimpleFunction('lang', array($this, 'lang')), - ); - } - - /** - * Returns a list of operators to add to the existing list. - * - * @return array An array of operators - */ - public function getOperators() - { - return array( - array( - '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'), - ), - array( - // precedence settings are copied from similar operators in Twig core extension - '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - 'eq' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - 'ne' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'neq' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - '<>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - '===' => array('precedence' => 20, 'class' => '\phpbb\template\twig\node\expression\binary\equalequal', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - '!==' => array('precedence' => 20, 'class' => '\phpbb\template\twig\node\expression\binary\notequalequal', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - 'gt' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'gte' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'ge' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'lt' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'lte' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - 'le' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - - 'mod' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT), - ), - ); - } - - /** - * Grabs a subset of a loop - * - * @param \Twig_Environment $env A Twig_Environment instance - * @param mixed $item A variable - * @param integer $start Start of the subset - * @param integer $end End of the subset - * @param Boolean $preserveKeys Whether to preserve key or not (when the input is an array) - * - * @return mixed The sliced variable - */ - function loop_subset(\Twig_Environment $env, $item, $start, $end = null, $preserveKeys = false) - { - // We do almost the same thing as Twig's slice (array_slice), except when $end is positive - if ($end >= 1) - { - // When end is > 1, subset will end on the last item in an array with the specified $end - // This is different from slice in that it is the number we end on rather than the number - // of items to grab (length) - - // Start must always be the actual starting number for this calculation (not negative) - $start = ($start < 0) ? count($item) + $start : $start; - $end = $end - $start; - } - - // We always include the last element (this was the past design) - $end = ($end == -1 || $end === null) ? null : $end + 1; - - return twig_slice($env, $item, $start, $end, $preserveKeys); - } - - /** - * Get output for a language variable (L_FOO, LA_FOO) - * - * This function checks to see if the language var was outputted to $context - * (e.g. in the ACP, L_TITLE) - * If not, we return the result of $user->lang() - * - * @return string - */ - function lang() - { - $args = func_get_args(); - $key = $args[0]; - - $context_vars = $this->context->get_root_ref(); - - if (is_string($key) && isset($context_vars['L_' . $key])) - { - return $context_vars['L_' . $key]; - } - - // LA_ is transformed into lang(\'$1\')|escape('js'), so we should not - // need to check for it - - return call_user_func_array(array($this->language, 'lang'), $args); - } -} diff --git a/install/update/old/phpbb/template/twig/lexer.php b/install/update/old/phpbb/template/twig/lexer.php deleted file mode 100644 index d0bcfa6..0000000 --- a/install/update/old/phpbb/template/twig/lexer.php +++ /dev/null @@ -1,368 +0,0 @@ - -* @license 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; - -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( - /*'BEGIN', - 'BEGINELSE', - 'END', - 'IF', - 'ELSE', - 'ELSEIF', - 'ENDIF', - 'DEFINE', - 'UNDEFINE',*/ - 'ENDDEFINE', - 'INCLUDE', - 'INCLUDEPHP', - 'INCLUDEJS', - 'INCLUDECSS', - 'PHP', - 'ENDPHP', - 'EVENT', - ); - - // Twig tag masks - $twig_tags = array( - 'autoescape', - 'endautoescape', - 'if', - 'elseif', - 'else', - 'endif', - 'block', - 'endblock', - 'use', - 'extends', - 'embed', - 'filter', - 'endfilter', - 'flush', - 'for', - 'endfor', - 'macro', - 'endmacro', - 'import', - 'from', - 'sandbox', - 'endsandbox', - 'set', - 'endset', - 'spaceless', - 'endspaceless', - 'verbatim', - 'endverbatim', - ); - - // Fix tokens that may have inline variables (e.g. with Twig style, {% TOKEN %} - // This also strips outer parenthesis, becomes - $code = preg_replace('##', '{% $1 $2 %}', $code); - - // Replace all of our twig masks with Twig code (e.g. with {% block $1 %}) - $code = $this->replace_twig_tag_masks($code, $twig_tags); - - // Replace all of our language variables, {L_VARNAME}, with Twig style, {{ lang('NAME') }} - // 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')|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); - - // Tokenize \Twig_Source instance - return parent::tokenize(new \Twig_Source($code, $filename)); - } - - /** - * Strip surrounding quotes - * - * First step to fix tokens that may have inline variables - * E.g. #', '', $code); - } - - /** - * Fix tokens that may have inline variables - * - * Second step to fix tokens that may have inline variables - * E.g. "; - }; - - return preg_replace_callback('##', $callback, $code); - } - - /** - * Add surrounding quotes - * - * Last step to fix tokens that may have inline variables - * E.g. #', '', $code); - } - - /** - * Fix begin tokens (convert our BEGIN to Twig for) - * - * Not meant to be used outside of this context, public because the anonymous function calls this - * - * @param string $code - * @param array $parent_nodes (used in recursion) - * @return string - */ - public function fix_begin_tokens($code, $parent_nodes = array()) - { - // PHP 5.3 cannot use $this in an anonymous function, so use this as a work-around - $parent_class = $this; - $callback = function ($matches) use ($parent_class, $parent_nodes) - { - $hard_parents = explode('.', $matches[1]); - array_pop($hard_parents); // ends with . - if ($hard_parents) - { - $parent_nodes = array_merge($hard_parents, $parent_nodes); - } - - $name = $matches[2]; - $subset = trim(substr($matches[3], 1, -1)); // Remove parenthesis - $body = $matches[4]; - - // Replace - $body = str_replace('', '{% else %}', $body); - - // Is the designer wanting to call another loop in a loop? - // - // - // - // - // 'loop2' is actually on the same nesting level as 'loop' you assign - // variables to it with template->assign_block_vars('loop2', array(...)) - if (strpos($name, '!') === 0) - { - // Count the number if ! occurrences - $count = substr_count($name, '!'); - for ($i = 0; $i < $count; $i++) - { - array_pop($parent_nodes); - $name = substr($name, 1); - } - } - - // Remove all parent nodes, e.g. foo, bar from foo.bar.foobar.VAR - foreach ($parent_nodes as $node) - { - $body = preg_replace('#([^a-zA-Z0-9_])' . $node . '\.([a-zA-Z0-9_]+)\.#', '$1$2.', $body); - } - - // Add current node to list of parent nodes for child nodes - $parent_nodes[] = $name; - - // Recursive...fix any child nodes - $body = $parent_class->fix_begin_tokens($body, $parent_nodes); - - // Need the parent variable name - array_pop($parent_nodes); - $parent = (!empty($parent_nodes)) ? end($parent_nodes) . '.' : ''; - - if ($subset !== '') - { - $subset = '|subset(' . $subset . ')'; - } - - $parent = ($parent) ?: 'loops.'; - // Turn into a Twig for loop - return "{% for {$name} in {$parent}{$name}{$subset} %}{$body}{% endfor %}"; - }; - - return preg_replace_callback('#(.+?)#s', $callback, $code); - } - - /** - * Fix IF statements - * - * @param string $code - * @return string - */ - protected function fix_if_tokens($code) - { - // Replace ELSE IF with ELSEIF - $code = preg_replace('##', '', $code); - - // Replace our "div by" with Twig's divisibleby (Twig does not like test names with spaces) - $code = preg_replace('# div by ([0-9]+)#', ' divisibleby($1)', $code); - - $callback = function($matches) - { - $inner = $matches[2]; - // Replace $TEST with definition.TEST - $inner = preg_replace('#(\s\(*!?)\$([a-zA-Z_0-9]+)#', '$1definition.$2', $inner); - - // Replace .foo with loops.foo|length - $inner = preg_replace('#(\s\(*!?)\.([a-zA-Z_0-9]+)([^a-zA-Z_0-9\.])#', '$1loops.$2|length$3', $inner); - - // Replace .foo.bar with foo.bar|length - $inner = preg_replace('#(\s\(*!?)\.([a-zA-Z_0-9\.]+)([^a-zA-Z_0-9\.])#', '$1$2|length$3', $inner); - - return ""; - }; - - return preg_replace_callback('##', $callback, $code); - } - - /** - * Fix DEFINE statements and {$VARNAME} variables - * - * @param string $code - * @return string - */ - protected function fix_define_tokens($code) - { - /** - * Changing $VARNAME to definition.varname because set is only local - * context (e.g. DEFINE $TEST will only make $TEST available in current - * template and any child templates, but not any parent templates). - * - * DEFINE handles setting it properly to definition in its node, but the - * variables reading FROM it need to be altered to definition.VARNAME - * - * Setting up definition as a class in the array passed to Twig - * ($context) makes set definition.TEST available in the global context - */ - - // Replace #', '{% DEFINE $1 %}', $code); - - // Changing UNDEFINE NAME to DEFINE NAME = null to save from creating an extra token parser/node - $code = preg_replace('##', '{% DEFINE $1= null %}', $code); - - // Replace all of our variables, {$VARNAME}, with Twig style, {{ definition.VARNAME }} - $code = preg_replace('#{\$([a-zA-Z0-9_\.]+)}#', '{{ definition.$1 }}', $code); - - // Replace all of our variables, ~ $VARNAME ~, with Twig style, ~ definition.VARNAME ~ - $code = preg_replace('#~ \$([a-zA-Z0-9_\.]+) ~#', '~ definition.$1 ~', $code); - - return $code; - } - - /** - * Replace Twig tag masks with Twig tag calls - * - * E.g. with {% block foo %} - * - * @param string $code - * @param array $twig_tags All tags we want to create a mask for - * @return string - */ - protected function replace_twig_tag_masks($code, $twig_tags) - { - $callback = function ($matches) - { - $matches[1] = strtolower($matches[1]); - - return "{% {$matches[1]}{$matches[2]}%}"; - }; - - foreach ($twig_tags as &$tag) - { - $tag = strtoupper($tag); - } - - // twig_tags is an array of the twig tags, which are all lowercase, but we use all uppercase tags - $code = preg_replace_callback('##',$callback, $code); - - return $code; - } -} diff --git a/install/update/old/phpbb/template/twig/loader.php b/install/update/old/phpbb/template/twig/loader.php deleted file mode 100644 index c13e3ee..0000000 --- a/install/update/old/phpbb/template/twig/loader.php +++ /dev/null @@ -1,176 +0,0 @@ - -* @license 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; - -/** -* Twig Template loader -*/ -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) - * @return \Twig_Loader_Filesystem - */ - public function setSafeDirectories($directories = array()) - { - $this->safe_directories = array(); - - if (!empty($directories)) - { - foreach ($directories as $directory) - { - $this->addSafeDirectory($directory); - } - } - - return $this; - } - - /** - * Add safe directory - * - * @param string $directory Directory that should be added - * @return \Twig_Loader_Filesystem - */ - public function addSafeDirectory($directory) - { - $directory = $this->filesystem->realpath($directory); - - if ($directory !== false) - { - $this->safe_directories[] = $directory; - } - - return $this; - } - - /** - * Get current safe directories - * - * @return array - */ - public function getSafeDirectories() - { - return $this->safe_directories; - } - - /** - * Override for parent::validateName() - * - * This is done because we added support for safe directories, and when Twig - * findTemplate() is called, validateName() is called first, which would - * always throw an exception if the file is outside of the configured - * template directories. - */ - protected function validateName($name) - { - return; - } - - /** - * 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 - * for loading from safe directories. - */ - protected function findTemplate($name) - { - $name = (string) $name; - - // normalize name - $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); - - // If this is in the cache we can skip the entire process below - // as it should have already been validated - if (isset($this->cache[$name])) - { - return $this->cache[$name]; - } - - // First, find the template name. The override above of validateName - // causes the validateName process to be skipped for this call - $file = parent::findTemplate($name); - - try - { - // Try validating the name (which may throw an exception) - parent::validateName($name); - } - catch (\Twig_Error_Loader $e) - { - if (strpos($e->getRawMessage(), 'Looks like you try to load a template outside configured directories') === 0) - { - // Ok, so outside of the configured template directories, we - // can now check if we're within a "safe" directory - - // Find the real path of the directory the file is in - $directory = $this->filesystem->realpath(dirname($file)); - - if ($directory === false) - { - // Some sort of error finding the actual path, must throw the exception - throw $e; - } - - foreach ($this->safe_directories as $safe_directory) - { - if (strpos($directory, $safe_directory) === 0) - { - // The directory being loaded is below a directory - // that is "safe". We're good to load it! - return $file; - } - } - } - - // Not within any safe directories - throw $e; - } - - // No exception from validateName, safe to load. - return $file; - } -} diff --git a/install/update/old/phpbb/template/twig/node/definenode.php b/install/update/old/phpbb/template/twig/node/definenode.php deleted file mode 100644 index ddbd151..0000000 --- a/install/update/old/phpbb/template/twig/node/definenode.php +++ /dev/null @@ -1,57 +0,0 @@ - -* @copyright Portions (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\node; - -class definenode extends \Twig_Node -{ - public function __construct($capture, \Twig_NodeInterface $name, \Twig_NodeInterface $value, $lineno, $tag = null) - { - parent::__construct(array('name' => $name, 'value' => $value), array('capture' => $capture, 'safe' => false), $lineno, $tag); - } - - /** - * Compiles the node to PHP. - * - * @param \Twig_Compiler A Twig_Compiler instance - */ - public function compile(\Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - if ($this->getAttribute('capture')) - { - $compiler - ->write("ob_start();\n") - ->subcompile($this->getNode('value')) - ; - - $compiler->write("\$value = ('' === \$value = ob_get_clean()) ? '' : new \Twig_Markup(\$value, \$this->env->getCharset());\n"); - } - else - { - $compiler - ->write("\$value = ") - ->subcompile($this->getNode('value')) - ->raw(";\n") - ; - } - - $compiler - ->write("\$context['definition']->set('") - ->raw($this->getNode('name')->getAttribute('name')) - ->raw("', \$value);\n") - ; - } -} diff --git a/install/update/old/phpbb/template/twig/node/includeasset.php b/install/update/old/phpbb/template/twig/node/includeasset.php deleted file mode 100644 index 12034b7..0000000 --- a/install/update/old/phpbb/template/twig/node/includeasset.php +++ /dev/null @@ -1,71 +0,0 @@ - -* @license 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\node; - -abstract class includeasset extends \Twig_Node -{ - /** @var \Twig_Environment */ - protected $environment; - - public function __construct(\Twig_Node_Expression $expr, \phpbb\template\twig\environment $environment, $lineno, $tag = null) - { - $this->environment = $environment; - - parent::__construct(array('expr' => $expr), array(), $lineno, $tag); - } - /** - * Compiles the node to PHP. - * - * @param \Twig_Compiler A Twig_Compiler instance - */ - public function compile(\Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - $config = $this->environment->get_phpbb_config(); - - $compiler - ->write("\$asset_file = ") - ->subcompile($this->getNode('expr')) - ->raw(";\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();") - ->write("\$local_file = \$this->getEnvironment()->get_phpbb_root_path() . \$asset_path;\n") - ->write("if (!file_exists(\$local_file)) {\n") - ->indent() - ->write("\$local_file = \$this->getEnvironment()->findTemplate(\$asset_path);\n") - ->write("\$asset->set_path(\$local_file, true);\n") - ->outdent() - ->write("}\n") - ->outdent() - ->write("}\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 name of the assets bag setter - * - * @return string (e.g. 'script') - */ - abstract public function get_setters_name(); -} diff --git a/install/update/old/phpbb/template/twig/node/includephp.php b/install/update/old/phpbb/template/twig/node/includephp.php deleted file mode 100644 index 76182c2..0000000 --- a/install/update/old/phpbb/template/twig/node/includephp.php +++ /dev/null @@ -1,91 +0,0 @@ - -* Sections (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\node; - -class includephp extends \Twig_Node -{ - /** @var \Twig_Environment */ - protected $environment; - - public function __construct(\Twig_Node_Expression $expr, \phpbb\template\twig\environment $environment, $lineno, $ignoreMissing = false, $tag = null) - { - $this->environment = $environment; - - parent::__construct(array('expr' => $expr), array('ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag); - } - - /** - * Compiles the node to PHP. - * - * @param \Twig_Compiler A Twig_Compiler instance - */ - public function compile(\Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - $config = $this->environment->get_phpbb_config(); - - if (!$config['tpl_allow_php']) - { - $compiler - ->write("// INCLUDEPHP Disabled\n") - ; - - return; - } - - if ($this->getAttribute('ignore_missing')) - { - $compiler - ->write("try {\n") - ->indent() - ; - } - - $compiler - ->write("\$location = ") - ->subcompile($this->getNode('expr')) - ->raw(";\n") - ->write("if (phpbb_is_absolute(\$location)) {\n") - ->indent() - // Absolute path specified - ->write("require(\$location);\n") - ->outdent() - ->write("} else if (file_exists(\$this->getEnvironment()->get_phpbb_root_path() . \$location)) {\n") - ->indent() - // PHP file relative to phpbb_root_path - ->write("require(\$this->getEnvironment()->get_phpbb_root_path() . \$location);\n") - ->outdent() - ->write("} else {\n") - ->indent() - // Local path (behaves like INCLUDE) - ->write("require(\$this->getEnvironment()->getLoader()->getCacheKey(\$location));\n") - ->outdent() - ->write("}\n") - ; - - if ($this->getAttribute('ignore_missing')) - { - $compiler - ->outdent() - ->write("} catch (\Twig_Error_Loader \$e) {\n") - ->indent() - ->write("// ignore missing template\n") - ->outdent() - ->write("}\n\n") - ; - } - } -} diff --git a/install/update/old/phpbb/template/twig/tokenparser/defineparser.php b/install/update/old/phpbb/template/twig/tokenparser/defineparser.php deleted file mode 100644 index b755836..0000000 --- a/install/update/old/phpbb/template/twig/tokenparser/defineparser.php +++ /dev/null @@ -1,76 +0,0 @@ - -* @copyright Portions (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\tokenparser; - -class defineparser extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_NodeInterface A Twig_NodeInterface instance - * @throws \Twig_Error_Syntax - * @throws \phpbb\template\twig\node\definenode - */ - public function parse(\Twig_Token $token) - { - $lineno = $token->getLine(); - $stream = $this->parser->getStream(); - $name = $this->parser->getExpressionParser()->parseExpression(); - - $capture = false; - if ($stream->test(\Twig_Token::OPERATOR_TYPE, '=')) - { - $stream->next(); - $value = $this->parser->getExpressionParser()->parseExpression(); - - if ($value instanceof \Twig_Node_Expression_Name) - { - // This would happen if someone improperly formed their DEFINE syntax - // e.g. - throw new \Twig_Error_Syntax('Invalid DEFINE', $token->getLine(), $this->parser->getFilename()); - } - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - } - else - { - $capture = true; - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - $value = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - } - - return new \phpbb\template\twig\node\definenode($capture, $name, $value, $lineno, $this->getTag()); - } - - public function decideBlockEnd(\Twig_Token $token) - { - return $token->test('ENDDEFINE'); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'DEFINE'; - } -} diff --git a/install/update/old/phpbb/template/twig/tokenparser/event.php b/install/update/old/phpbb/template/twig/tokenparser/event.php deleted file mode 100644 index f73ef4a..0000000 --- a/install/update/old/phpbb/template/twig/tokenparser/event.php +++ /dev/null @@ -1,44 +0,0 @@ - -* @license 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\tokenparser; - -class event extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_NodeInterface A Twig_NodeInterface instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - $stream = $this->parser->getStream(); - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\event($expr, $this->parser->getEnvironment(), $token->getLine(), $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'EVENT'; - } -} diff --git a/install/update/old/phpbb/template/twig/tokenparser/includecss.php b/install/update/old/phpbb/template/twig/tokenparser/includecss.php deleted file mode 100644 index 1f30811..0000000 --- a/install/update/old/phpbb/template/twig/tokenparser/includecss.php +++ /dev/null @@ -1,44 +0,0 @@ - -* @license 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\tokenparser; - -class includecss extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_NodeInterface A Twig_NodeInterface instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - $stream = $this->parser->getStream(); - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\includecss($expr, $this->parser->getEnvironment(), $token->getLine(), $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'INCLUDECSS'; - } -} diff --git a/install/update/old/phpbb/template/twig/tokenparser/includejs.php b/install/update/old/phpbb/template/twig/tokenparser/includejs.php deleted file mode 100644 index 4b67d2c..0000000 --- a/install/update/old/phpbb/template/twig/tokenparser/includejs.php +++ /dev/null @@ -1,44 +0,0 @@ - -* @license 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\tokenparser; - -class includejs extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_NodeInterface A Twig_NodeInterface instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - $stream = $this->parser->getStream(); - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\includejs($expr, $this->parser->getEnvironment(), $token->getLine(), $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'INCLUDEJS'; - } -} diff --git a/install/update/old/phpbb/template/twig/tokenparser/includeparser.php b/install/update/old/phpbb/template/twig/tokenparser/includeparser.php deleted file mode 100644 index aa7236a..0000000 --- a/install/update/old/phpbb/template/twig/tokenparser/includeparser.php +++ /dev/null @@ -1,44 +0,0 @@ - -* @copyright Portions (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\tokenparser; - -class includeparser extends \Twig_TokenParser_Include -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_NodeInterface A Twig_NodeInterface instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - list($variables, $only, $ignoreMissing) = $this->parseArguments(); - - return new \phpbb\template\twig\node\includenode($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'INCLUDE'; - } -} diff --git a/install/update/old/phpbb/template/twig/tokenparser/includephp.php b/install/update/old/phpbb/template/twig/tokenparser/includephp.php deleted file mode 100644 index 3992636..0000000 --- a/install/update/old/phpbb/template/twig/tokenparser/includephp.php +++ /dev/null @@ -1,55 +0,0 @@ - -* @copyright Portions (c) 2009 Fabien Potencier, Armin Ronacher -* @license 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\tokenparser; - -class includephp extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_NodeInterface A Twig_NodeInterface instance - */ - public function parse(\Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - $stream = $this->parser->getStream(); - - $ignoreMissing = false; - if ($stream->test(\Twig_Token::NAME_TYPE, 'ignore')) - { - $stream->next(); - $stream->expect(\Twig_Token::NAME_TYPE, 'missing'); - - $ignoreMissing = true; - } - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\includephp($expr, $this->parser->getEnvironment(), $token->getLine(), $ignoreMissing, $this->getTag()); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'INCLUDEPHP'; - } -} diff --git a/install/update/old/phpbb/template/twig/tokenparser/php.php b/install/update/old/phpbb/template/twig/tokenparser/php.php deleted file mode 100644 index f11ce35..0000000 --- a/install/update/old/phpbb/template/twig/tokenparser/php.php +++ /dev/null @@ -1,52 +0,0 @@ - -* @license 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\tokenparser; - -class php extends \Twig_TokenParser -{ - /** - * Parses a token and returns a node. - * - * @param \Twig_Token $token A Twig_Token instance - * - * @return \Twig_NodeInterface A Twig_NodeInterface instance - */ - public function parse(\Twig_Token $token) - { - $stream = $this->parser->getStream(); - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - $body = $this->parser->subparse(array($this, 'decideEnd'), true); - - $stream->expect(\Twig_Token::BLOCK_END_TYPE); - - return new \phpbb\template\twig\node\php($body, $this->parser->getEnvironment(), $token->getLine(), $this->getTag()); - } - - public function decideEnd(\Twig_Token $token) - { - return $token->test('ENDPHP'); - } - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag() - { - return 'PHP'; - } -} diff --git a/install/update/old/phpbb/textformatter/s9e/bbcode_merger.php b/install/update/old/phpbb/textformatter/s9e/bbcode_merger.php deleted file mode 100644 index a05ca3c..0000000 --- a/install/update/old/phpbb/textformatter/s9e/bbcode_merger.php +++ /dev/null @@ -1,183 +0,0 @@ - -* @license 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_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 array Merged definition - */ - 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'])); - } - - /** - * 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 = '' . $with['tag']->template . '' . $without['tag']->template . ''; - - 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('()', '{$1}', $template); - - // Beautify the template - $template = $this->indent_template($template); - - return $template; - } -} diff --git a/install/update/old/phpbb/textformatter/s9e/factory.php b/install/update/old/phpbb/textformatter/s9e/factory.php deleted file mode 100644 index 6191b9a..0000000 --- a/install/update/old/phpbb/textformatter/s9e/factory.php +++ /dev/null @@ -1,676 +0,0 @@ - -* @license 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} - 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' => '', - 'i' => '', - 'u' => '', - 'img' => '{L_IMAGE}', - 'size' => '', - 'color' => '', - 'email' => ' - - mailto: - - - ? - subject= - &body= - - - - ', - ); - - /** - * @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 = '' . $tag->template . ''; - } - - // 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'], - '{.}' - ); - } - - 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 = ' - - {.} - - - {.} - - '; - $tag->template = '' . str_replace('class="emoji"', 'class="emoji smilies"', $tag->template) . ''; - - /** - * 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 = ''; - - $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('#(.*?)#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'] . '' . $fragment; - } - } - } - - // Manually recompose and overwrite irregular templates - $templates['list'] = - ' - - ' . $fragments['ulist_open_default'] . '' . $fragments['ulist_close'] . ' - - - ' . $fragments['olist_open'] . '' . $fragments['olist_close'] . ' - - - ' . $fragments['ulist_open'] . '' . $fragments['ulist_close'] . ' - - '; - - $templates['li'] = $fragments['listitem'] . '' . $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'] . ' ia ia ' . $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 = ''; - foreach ($grouped_templates as $style_template => $exprs) - { - $template .= '' . $style_template . ''; - } - $template .= '' . $default_template . ''; - - return $template; - } -} diff --git a/install/update/old/phpbb/textformatter/s9e/link_helper.php b/install/update/old/phpbb/textformatter/s9e/link_helper.php deleted file mode 100644 index 483794a..0000000 --- a/install/update/old/phpbb/textformatter/s9e/link_helper.php +++ /dev/null @@ -1,115 +0,0 @@ - -* @license 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); - $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/install/update/old/phpbb/textformatter/s9e/parser.php b/install/update/old/phpbb/textformatter/s9e/parser.php deleted file mode 100644 index 3698dca..0000000 --- a/install/update/old/phpbb/textformatter/s9e/parser.php +++ /dev/null @@ -1,399 +0,0 @@ - -* @license 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; - -/** -* 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') - { - $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) - { - 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; - } -} diff --git a/install/update/old/phpbb/textformatter/s9e/quote_helper.php b/install/update/old/phpbb/textformatter/s9e/quote_helper.php deleted file mode 100644 index 86c33c7..0000000 --- a/install/update/old/phpbb/textformatter/s9e/quote_helper.php +++ /dev/null @@ -1,81 +0,0 @@ - -* @license 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 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->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) - { - $post_url = $this->post_url; - $profile_url = $this->profile_url; - $user = $this->user; - - return \s9e\TextFormatter\Utils::replaceAttributes( - $xml, - 'QUOTE', - function ($attributes) use ($post_url, $profile_url, $user) - { - if (isset($attributes['post_id'])) - { - $attributes['post_url'] = str_replace('{POST_ID}', $attributes['post_id'], $post_url); - } - if (isset($attributes['time'])) - { - $attributes['date'] = $user->format_date($attributes['time']); - } - if (isset($attributes['user_id'])) - { - $attributes['profile_url'] = str_replace('{USER_ID}', $attributes['user_id'], $profile_url); - } - - return $attributes; - } - ); - } -} diff --git a/install/update/old/phpbb/user.php b/install/update/old/phpbb/user.php deleted file mode 100644 index 7363290..0000000 --- a/install/update/old/phpbb/user.php +++ /dev/null @@ -1,814 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* Base user class -* -* This is the overarching class which contains (through session extend) -* all methods utilised for user functionality during a session. -*/ -class user extends \phpbb\session -{ - /** - * @var \phpbb\language\language - */ - protected $language; - - var $style = array(); - var $date_format; - - /** - * DateTimeZone object holding the timezone of the user - */ - public $timezone; - - /** - * @var string Class name of datetime object - */ - protected $datetime; - - var $lang_name = false; - var $lang_id = false; - var $lang_path; - 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 \phpbb\language\language $lang phpBB's Language loader - * @param string $datetime_class Class name of 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; - } - - /** - * Returns whether user::setup was called - * - * @return bool - */ - public function is_setup() - { - return $this->is_setup_flag; - } - - /** - * 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') - { - return $this->language->get_lang_array(); - } - else if ($param_name === 'help') - { - $help_array = $this->language->get_lang_array(); - return $help_array['__help']; - } - - return array(); - } - - /** - * Setup basic user-specific items (style, language, ...) - */ - function setup($lang_set = false, $style_id = false) - { - 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']); - $user_date_format = $this->data['user_dateformat']; - $user_timezone = $this->data['user_timezone']; - } - else - { - $lang_override = $request->variable('language', ''); - if ($lang_override) - { - $this->set_cookie('lang', $lang_override, 0, false); - } - else - { - $lang_override = $request->variable($config['cookie_name'] . '_lang', '', true, \phpbb\request\request_interface::COOKIE); - } - - if ($lang_override) - { - $use_lang = basename($lang_override); - $user_lang_name = (file_exists($this->lang_path . $use_lang . "/common.$phpEx")) ? $use_lang : basename($config['default_lang']); - $this->data['user_lang'] = $user_lang_name; - } - else - { - $user_lang_name = basename($config['default_lang']); - } - - $user_date_format = $config['default_dateformat']; - $user_timezone = $config['board_timezone']; - - /** - * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language - * If re-enabled we need to make sure only those languages installed are checked - * Commented out so we do not loose the code. - - if ($request->header('Accept-Language')) - { - $accept_lang_ary = explode(',', $request->header('Accept-Language')); - - foreach ($accept_lang_ary as $accept_lang) - { - // Set correct format ... guess full xx_YY form - $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2)); - $accept_lang = basename($accept_lang); - - if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx")) - { - $user_lang_name = $config['default_lang'] = $accept_lang; - break; - } - else - { - // No match on xx_YY so try xx - $accept_lang = substr($accept_lang, 0, 2); - $accept_lang = basename($accept_lang); - - if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx")) - { - $user_lang_name = $config['default_lang'] = $accept_lang; - break; - } - } - } - } - */ - } - - $user_data = $this->data; - $lang_set_ext = array(); - - /** - * 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 - * @var string user_date_format User's date/time format - * @var string user_timezone User's timezone, should be one of - * http://www.php.net/manual/en/timezones.php - * @var mixed lang_set String or array of language files - * @var array lang_set_ext Array containing entries of format - * array( - * 'ext_name' => (string) [extension name], - * 'lang_set' => (string|array) [language files], - * ) - * For performance reasons, only load translations - * that are absolutely needed globally using this - * event. Use local events otherwise. - * @var mixed style_id Style we are going to display - * @since 3.1.0-a1 - */ - $vars = array( - 'user_data', - 'user_lang_name', - 'user_date_format', - 'user_timezone', - 'lang_set', - 'lang_set_ext', - 'style_id', - ); - extract($phpbb_dispatcher->trigger_event('core.user_setup', compact($vars))); - - $this->data = $user_data; - $this->lang_name = $user_lang_name; - $this->date_format = $user_date_format; - - $this->language->set_user_language($user_lang_name); - - try - { - $this->timezone = new \DateTimeZone($user_timezone); - } - catch (\Exception $e) - { - // If the timezone the user has selected is invalid, we fall back to UTC. - $this->timezone = new \DateTimeZone('UTC'); - } - - $this->add_lang($lang_set); - unset($lang_set); - - foreach ($lang_set_ext as $ext_lang_pair) - { - $this->add_lang_ext($ext_lang_pair['ext_name'], $ext_lang_pair['lang_set']); - } - unset($lang_set_ext); - - $style_request = $request->variable('style', 0); - if ($style_request && (!$config['override_user_style'] || $auth->acl_get('a_styles')) && !defined('ADMIN_START')) - { - global $SID, $_EXTRA_URL; - - $style_id = $style_request; - $SID .= '&style=' . $style_id; - $_EXTRA_URL = array('style=' . $style_id); - } - else - { - // Set up style - $style_id = ($style_id) ? $style_id : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']); - } - - $sql = 'SELECT * - FROM ' . STYLES_TABLE . " s - WHERE s.style_id = $style_id"; - $result = $db->sql_query($sql, 3600); - $this->style = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Fallback to user's standard style - if (!$this->style && $style_id != $this->data['user_style']) - { - $style_id = $this->data['user_style']; - - $sql = 'SELECT * - FROM ' . STYLES_TABLE . " s - WHERE s.style_id = $style_id"; - $result = $db->sql_query($sql, 3600); - $this->style = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - if (!$this->style) - { - trigger_error('NO_STYLE_DATA', E_USER_ERROR); - } - - // Now parse the cfg file and cache it - $parsed_items = $cache->obtain_cfg_items($this->style); - - $check_for = array( - 'pagination_sep' => (string) ', ' - ); - - foreach ($check_for as $key => $default_value) - { - $this->style[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value; - settype($this->style[$key], gettype($default_value)); - - if (is_string($default_value)) - { - $this->style[$key] = htmlspecialchars($this->style[$key]); - } - } - - $template->set_style(); - - $this->img_lang = $this->lang_name; - - // Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes... - // After calling it we continue script execution... - phpbb_user_session_handler(); - - /** - * Execute code at the end of user setup - * - * @event core.user_setup_after - * @since 3.1.6-RC1 - */ - $phpbb_dispatcher->dispatch('core.user_setup_after'); - - // If this function got called from the error handler we are finished here. - if (defined('IN_ERROR_HANDLER')) - { - return; - } - - // Disable board if the install/ directory is still present - // For the brave development army we do not care about this, else we need to comment out this everytime we develop locally - if (!defined('DEBUG') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) - { - // Adjust the message slightly according to the permissions - if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) - { - $message = 'REMOVE_INSTALL'; - } - else - { - $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; - } - trigger_error($message); - } - - // Is board disabled and user not an admin or moderator? - if ($config['board_disable'] && !defined('IN_INSTALL') && !defined('IN_LOGIN') && !defined('SKIP_CHECK_DISABLED') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) - { - if ($this->data['is_bot']) - { - send_status_line(503, 'Service Unavailable'); - } - - $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; - trigger_error($message); - } - - // Is load exceeded? - if ($config['limit_load'] && $this->load !== false) - { - if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN') && !defined('IN_ADMIN')) - { - // Set board disabled to true to let the admins/mods get the proper notification - $config['board_disable'] = '1'; - - if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) - { - if ($this->data['is_bot']) - { - send_status_line(503, 'Service Unavailable'); - } - trigger_error('BOARD_UNAVAILABLE'); - } - } - } - - if (isset($this->data['session_viewonline'])) - { - // Make sure the user is able to hide his session - if (!$this->data['session_viewonline']) - { - // Reset online status if not allowed to hide the session... - if (!$auth->acl_get('u_hideonline')) - { - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_viewonline = 1 - WHERE session_user_id = ' . $this->data['user_id']; - $db->sql_query($sql); - $this->data['session_viewonline'] = 1; - } - } - else if (!$this->data['user_allow_viewonline']) - { - // the user wants to hide and is allowed to -> cloaking device on. - if ($auth->acl_get('u_hideonline')) - { - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_viewonline = 0 - WHERE session_user_id = ' . $this->data['user_id']; - $db->sql_query($sql); - $this->data['session_viewonline'] = 0; - } - } - } - - // Does the user need to change their password? If so, redirect to the - // ucp profile reg_details page ... of course do not redirect if we're already in the ucp - if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && !empty($this->data['is_registered']) && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) - { - if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx") - { - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&mode=reg_details')); - } - } - - $this->is_setup_flag = true; - - return; - } - - /** - * More advanced language substitution - * Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms. - * Params are the language key and the parameters to be substituted. - * This function/functionality is inspired by SHS` and Ashe. - * - * Example call: $user->lang('NUM_POSTS_IN_QUEUE', 1); - * - * If the first parameter is an array, the elements are used as keys and subkeys to get the language entry: - * Example: $user->lang(array('datetime', 'AGO'), 1) 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(); - return call_user_func_array(array($this->language, 'lang'), $args); - } - - /** - * Determine which plural form we should use. - * For some languages this is not as simple as for English. - * - * @param $number int|float The number we want to get the plural case for. Float numbers are floored. - * @param $force_rule mixed False to use the plural rule of the language package - * or an integer to force a certain plural rule - * @return int|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) - { - 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 @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: - * - * $lang_set = array('posting', 'help' => 'faq'); - * $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq')) - * $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq')) - * $lang_set = 'posting' - * $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting')) - * - * - * 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 = '') - { - if (is_array($lang_set)) - { - foreach ($lang_set as $key => $lang_file) - { - // Please do not delete this line. - // We have to force the type here, else [array] language inclusion will not work - $key = (string) $key; - - if ($key == 'db') - { - // This is never used - $this->add_lang($lang_file, true, $use_help, $ext_name); - } - else if ($key == 'help') - { - $this->add_lang($lang_file, $use_db, true, $ext_name); - } - else if (!is_array($lang_file)) - { - $this->set_lang($lang_file, $use_help, $ext_name); - } - else - { - $this->add_lang($lang_file, $use_db, $use_help, $ext_name); - } - } - unset($lang_set); - } - else if ($lang_set) - { - $this->set_lang($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); - } - - /** - * Add Language Items from an extension - use_db and use_help are assigned where needed (only use them to force inclusion) - * - * @param string $ext_name The extension to load language from, or empty for core files - * @param mixed $lang_set specifies the language entries to include - * @param bool $use_db internal variable for recursion, do not use - * @param bool $use_help internal variable for recursion, do not use - * - * 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) - { - if ($ext_name === '/') - { - $ext_name = ''; - } - - $this->add_lang($lang_set, $use_db, $use_help, $ext_name); - } - - /** - * Format user date - * - * @param int $gmepoch unix timestamp - * @param string $format date format in date() notation. | used to indicate relative dates, for example |d m Y|, h:i is translated to Today, h:i. - * @param bool $forcedate force non-relative date format. - * - * @return mixed translated date - */ - function format_date($gmepoch, $format = false, $forcedate = false) - { - global $phpbb_dispatcher; - static $utc; - - if (!isset($utc)) - { - $utc = new \DateTimeZone('UTC'); - } - - $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))); - - 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; - } - } - - /** - * Create a \phpbb\datetime object in the context of the current user - * - * @since 3.1 - * @param string $time String in a format accepted by strtotime(). - * @param DateTimeZone $timezone Time zone of the time. - * @return \phpbb\datetime Date time object linked to the current users locale - */ - public function create_datetime($time = 'now', \DateTimeZone $timezone = null) - { - $timezone = $timezone ?: $this->timezone; - return new $this->datetime($this, $time, $timezone); - } - - /** - * Get the UNIX timestamp for a datetime in the users timezone, so we can store it in the database. - * - * @param string $format Format of the entered date/time - * @param string $time Date/time with the timezone applied - * @param DateTimeZone $timezone Timezone of the date/time, falls back to timezone of current user - * @return int Returns the unix timestamp - */ - public function get_timestamp_from_format($format, $time, \DateTimeZone $timezone = null) - { - $timezone = $timezone ?: $this->timezone; - $date = \DateTime::createFromFormat($format, $time, $timezone); - return ($date !== false) ? $date->format('U') : false; - } - - /** - * Get language id currently used by the user - */ - function get_iso_lang_id() - { - global $config, $db; - - if (!empty($this->lang_id)) - { - return $this->lang_id; - } - - if (!$this->lang_name) - { - $this->lang_name = $config['default_lang']; - } - - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'"; - $result = $db->sql_query($sql); - $this->lang_id = (int) $db->sql_fetchfield('lang_id'); - $db->sql_freeresult($result); - - return $this->lang_id; - } - - /** - * Get users profile fields - */ - function get_profile_fields($user_id) - { - global $db; - - if (isset($this->profile_fields)) - { - return; - } - - $sql = 'SELECT * - FROM ' . PROFILE_FIELDS_DATA_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query_limit($sql, 1); - $this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row; - $db->sql_freeresult($result); - } - - /** - * Specify/Get image - */ - function img($img, $alt = '') - { - $title = ''; - - if ($alt) - { - $alt = $this->language->lang($alt); - $title = ' title="' . $alt . '"'; - } - return '' . $alt . ''; - } - - /** - * Get option bit field from user options. - * - * @param int $key option key, as defined in $keyoptions property. - * @param int $data bit field value to use, or false to use $this->data['user_options'] - * @return bool true if the option is set in the bit field, false otherwise - */ - function optionget($key, $data = false) - { - $var = ($data !== false) ? $data : $this->data['user_options']; - return phpbb_optionget($this->keyoptions[$key], $var); - } - - /** - * Set option bit field for user options. - * - * @param int $key Option key, as defined in $keyoptions property. - * @param bool $value True to set the option, false to clear the option. - * @param int $data Current bit field value, or false to use $this->data['user_options'] - * @return int|bool If $data is false, the bit field is modified and - * written back to $this->data['user_options'], and - * return value is true if the bit field changed and - * false otherwise. If $data is not false, the new - * bitfield value is returned. - */ - function optionset($key, $value, $data = false) - { - $var = ($data !== false) ? $data : $this->data['user_options']; - - $new_var = phpbb_optionset($this->keyoptions[$key], $value, $var); - - if ($data === false) - { - if ($new_var != $var) - { - $this->data['user_options'] = $new_var; - return true; - } - else - { - return false; - } - } - else - { - return $new_var; - } - } - - /** - * Funtion to make the user leave the NEWLY_REGISTERED system group. - * @access public - */ - function leave_newly_registered() - { - if (empty($this->data['user_new'])) - { - return false; - } - - if (!function_exists('remove_newly_registered')) - { - global $phpbb_root_path, $phpEx; - - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - if ($group = remove_newly_registered($this->data['user_id'], $this->data)) - { - $this->data['group_id'] = $group; - - } - $this->data['user_permissions'] = ''; - $this->data['user_new'] = 0; - - return true; - } - - /** - * Returns all password protected forum ids the user is currently NOT authenticated for. - * - * @return array Array of forum ids - * @access public - */ - function get_passworded_forums() - { - global $db; - - $sql = 'SELECT f.forum_id, fa.user_id - FROM ' . FORUMS_TABLE . ' f - LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa - ON (fa.forum_id = f.forum_id - AND fa.session_id = '" . $db->sql_escape($this->session_id) . "') - WHERE f.forum_password <> ''"; - $result = $db->sql_query($sql); - - $forum_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_id = (int) $row['forum_id']; - - if ($row['user_id'] != $this->data['user_id']) - { - $forum_ids[$forum_id] = $forum_id; - } - } - $db->sql_freeresult($result); - - return $forum_ids; - } -} diff --git a/install/update/old/phpbb/user_loader.php b/install/update/old/phpbb/user_loader.php deleted file mode 100644 index 9297450..0000000 --- a/install/update/old/phpbb/user_loader.php +++ /dev/null @@ -1,238 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb; - -/** -* User loader class -* -* This handles loading users from the database and -* storing in them in a temporary cache so we do not -* have to query the same user multiple times in -* different services. -*/ -class user_loader -{ - /** @var \phpbb\db\driver\driver_interface */ - protected $db = null; - - /** @var string */ - protected $phpbb_root_path = null; - - /** @var string */ - protected $php_ext = null; - - /** @var string */ - protected $users_table = null; - - /** - * Users loaded from the DB - * - * @var array Array of user data that we've loaded from the DB - */ - protected $users = array(); - - /** - * User loader constructor - * - * @param \phpbb\db\driver\driver_interface $db A database connection - * @param string $phpbb_root_path Path to the phpbb includes directory. - * @param string $php_ext php file extension - * @param string $users_table The name of the database table (phpbb_users) - */ - public function __construct(\phpbb\db\driver\driver_interface $db, $phpbb_root_path, $php_ext, $users_table) - { - $this->db = $db; - - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; - - $this->users_table = $users_table; - } - - /** - * Load user helper - * - * @param array $user_ids - * @param array $ignore_types user types to ignore - */ - public function load_users(array $user_ids, array $ignore_types = array()) - { - $user_ids[] = ANONYMOUS; - - // Make user_ids unique and convert to integer. - $user_ids = array_map('intval', array_unique($user_ids)); - - // Do not load users we already have in $this->users - $user_ids = array_diff($user_ids, array_keys($this->users)); - - if (count($user_ids)) - { - $sql = 'SELECT * - FROM ' . $this->users_table . ' - 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)) - { - $this->users[$row['user_id']] = $row; - } - $this->db->sql_freeresult($result); - } - } - - /** - * Load a user by username - * - * Stores the full data in the user cache so they do not need to be loaded again - * Returns the user id so you may use get_user() from the returned value - * - * @param string $username Raw username to load (will be cleaned) - * @return int User ID for the username - */ - public function load_user_by_username($username) - { - $sql = 'SELECT * - FROM ' . $this->users_table . " - WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - $this->users[$row['user_id']] = $row; - - return $row['user_id']; - } - - return ANONYMOUS; - } - - /** - * Get a user row from our users cache - * - * @param int $user_id User ID of the user you want to retreive - * @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() - * @return array|bool Row from the database of the user or Anonymous if the user wasn't loaded/does not exist - * or bool False if the anonymous user was not loaded - */ - public function get_user($user_id, $query = false) - { - if (isset($this->users[$user_id])) - { - return $this->users[$user_id]; - } - // Query them if we must (if ANONYMOUS is sent as the user_id and we have not loaded Anonymous yet, we must load Anonymous as a last resort) - else if ($query || $user_id == ANONYMOUS) - { - $this->load_users(array($user_id)); - - return $this->get_user($user_id); - } - - return $this->get_user(ANONYMOUS); - } - - /** - * Get username - * - * @param int $user_id User ID of the user you want to retreive the username for - * @param string $mode The mode to load (same as get_username_string). One of the following: - * 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) - * no_profile (the same as full but forcing no profile link) - * @param string $guest_username Optional parameter to specify the guest username. It will be used in favor of the GUEST language variable then. - * @param string $custom_profile_url Optional parameter to specify a profile url. The user id get appended to this url as &u={user_id} - * @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() - * @return string - */ - public function get_username($user_id, $mode, $guest_username = false, $custom_profile_url = false, $query = false) - { - if (!($user = $this->get_user($user_id, $query))) - { - return ''; - } - - return get_username_string($mode, $user['user_id'], $user['username'], $user['user_colour'], $guest_username, $custom_profile_url); - } - - /** - * Get avatar - * - * @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() - * @param bool @lazy If true, will be lazy loaded (requires JS) - * @return string - */ - public function get_avatar($user_id, $query = false, $lazy = false) - { - if (!($user = $this->get_user($user_id, $query))) - { - return ''; - } - - $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); - } - - /** - * Get rank - * - * @param int $user_id User ID of the user you want to retreive the rank 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() - * @return array Array with keys 'rank_title', 'rank_img', and 'rank_img_src' - */ - public function get_rank($user_id, $query = false) - { - if (!($user = $this->get_user($user_id, $query))) - { - return ''; - } - - if (!function_exists('phpbb_get_user_rank')) - { - include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext); - } - - $rank = array( - 'rank_title', - 'rank_img', - 'rank_img_src', - ); - - $user_rank_data = phpbb_get_user_rank($user, (($user['user_id'] == ANONYMOUS) ? false : $user['user_posts'])); - $rank['rank_title'] = $user_rank_data['title']; - $rank['rank_img'] = $user_rank_data['img']; - $rank['rank_img_src'] = $user_rank_data['img_src']; - - return $rank; - } -} diff --git a/install/update/old/posting.php b/install/update/old/posting.php deleted file mode 100644 index 75085a5..0000000 --- a/install/update/old/posting.php +++ /dev/null @@ -1,1990 +0,0 @@ - -* @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); -$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_posting.' . $phpEx); -include($phpbb_root_path . 'includes/functions_display.' . $phpEx); -include($phpbb_root_path . 'includes/message_parser.' . $phpEx); - - -// Start session management -$user->session_begin(); -$auth->acl($user->data); - - -// Grab only parameters needed here -$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; -$load = (isset($_POST['load'])) ? true : false; -$confirm = $request->is_set_post('confirm'); -$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->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))) -{ - $mode = 'soft_delete'; -} - -$error = $post_data = array(); -$current_time = time(); - -/** -* This event allows you to alter the above parameters, such as submit and mode -* -* Note: $refresh must be true to retain previously submitted form data. -* -* Note: The template class will not work properly until $user->setup() is -* called, and it has not been called yet. Extensions requiring template -* assignments should use an event that comes later in this file. -* -* @event core.modify_posting_parameters -* @var int post_id ID of the post -* @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 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 -* @var bool load Whether or not a draft is being loaded -* @var bool cancel Whether or not to cancel the form (returns to -* viewtopic or viewforum depending on if the user -* is posting a new topic or editing a post) -* @var bool refresh Whether or not to retain previously submitted data -* @var string mode What action to take if the form has been submitted -* post|reply|quote|edit|delete|bump|smilies|popup -* @var array error Any error strings; a non-empty array aborts -* form submission. -* NOTE: Should be actual language strings, NOT -* 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', - 'submit', - 'preview', - 'save', - 'load', - 'cancel', - 'refresh', - 'mode', - 'error', -); -extract($phpbb_dispatcher->trigger_event('core.modify_posting_parameters', compact($vars))); - -// Was cancel pressed? If so then redirect to the appropriate page -if ($cancel) -{ - $f = ($forum_id) ? 'f=' . $forum_id . '&' : ''; - $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"))); - redirect($redirect); -} - -if (in_array($mode, array('post', 'reply', 'quote', 'edit', 'delete')) && !$forum_id) -{ - 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. -switch ($mode) -{ - case 'post': - $sql = 'SELECT * - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - break; - - case 'bump': - case 'reply': - if (!$topic_id) - { - trigger_error('NO_TOPIC'); - } - - // Force forum id - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $f_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - $forum_id = (!$f_id) ? $forum_id : $f_id; - - $sql = 'SELECT f.*, t.* - FROM ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . " f - WHERE t.topic_id = $topic_id - AND f.forum_id = t.forum_id - AND " . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'); - break; - - case 'quote': - case 'edit': - case 'delete': - case 'soft_delete': - if (!$post_id) - { - $user->setup('posting'); - trigger_error('NO_POST'); - } - - // Force forum id - $sql = 'SELECT forum_id - FROM ' . POSTS_TABLE . ' - WHERE post_id = ' . $post_id; - $result = $db->sql_query($sql); - $f_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - $forum_id = (!$f_id) ? $forum_id : $f_id; - - $sql = 'SELECT f.*, t.*, p.*, u.username, u.username_clean, u.user_sig, u.user_sig_bbcode_uid, u.user_sig_bbcode_bitfield - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . ' f, ' . USERS_TABLE . " u - WHERE p.post_id = $post_id - AND t.topic_id = p.topic_id - AND u.user_id = p.poster_id - AND f.forum_id = t.forum_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.'); - break; - - case 'smilies': - $sql = ''; - generate_smilies('window', $forum_id); - break; - - case 'popup': - if ($forum_id) - { - $sql = 'SELECT forum_style - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $forum_id; - } - else - { - phpbb_upload_popup(); - return; - } - break; - - default: - $sql = ''; - break; -} - -if (!$sql) -{ - $user->setup('posting'); - trigger_error('NO_POST_MODE'); -} - -$result = $db->sql_query($sql); -$post_data = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -if (!$post_data) -{ - if (!($mode == 'post' || $mode == 'bump' || $mode == 'reply')) - { - $user->setup('posting'); - } - trigger_error(($mode == 'post' || $mode == 'bump' || $mode == 'reply') ? 'NO_TOPIC' : 'NO_POST'); -} - -// 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))) -{ - trigger_error(($mode == 'reply' || $mode == 'bump') ? 'TOPIC_UNAPPROVED' : 'POST_UNAPPROVED'); -} - -if ($mode == 'popup') -{ - phpbb_upload_popup($post_data['forum_style']); - return; -} - -$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; -$post_id = (!empty($post_data['post_id'])) ? (int) $post_data['post_id'] : (int) $post_id; - -// Need to login to passworded forum first? -if ($post_data['forum_password']) -{ - login_forum_box(array( - 'forum_id' => $forum_id, - 'forum_name' => $post_data['forum_name'], - 'forum_password' => $post_data['forum_password']) - ); -} - -// Check permissions -if ($user->data['is_bot']) -{ - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); -} - -// Is the user able to read within this forum? -if (!$auth->acl_get('f_read', $forum_id)) -{ - if ($user->data['user_id'] != ANONYMOUS) - { - trigger_error('USER_CANNOT_READ'); - } - $message = $user->lang['LOGIN_EXPLAIN_POST']; - - if ($request->is_ajax()) - { - $json = new phpbb\json_response(); - $json->send(array( - 'title' => $user->lang['INFORMATION'], - 'message' => $message, - )); - } - - login_box('', $message); -} - -// Permission to do the action asked? -$is_authed = false; - -switch ($mode) -{ - case 'post': - if ($auth->acl_get('f_post', $forum_id)) - { - $is_authed = true; - } - break; - - case 'bump': - if ($auth->acl_get('f_bump', $forum_id)) - { - $is_authed = true; - } - break; - - case 'quote': - - $post_data['post_edit_locked'] = 0; - - // no break; - - case 'reply': - if ($auth->acl_get('f_reply', $forum_id)) - { - $is_authed = true; - } - break; - - case 'edit': - if ($user->data['is_registered'] && $auth->acl_gets('f_edit', 'm_edit', $forum_id)) - { - $is_authed = true; - } - break; - - case 'delete': - if ($user->data['is_registered'] && ($auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id)))) - { - $is_authed = true; - } - - // no break; - - case 'soft_delete': - if (!$is_authed && $user->data['is_registered'] && $phpbb_content_visibility->can_soft_delete($forum_id, $post_data['poster_id'], $post_data['post_edit_locked'])) - { - // Fall back to soft_delete if we have no permissions to delete posts but to soft delete them - $is_authed = true; - $mode = 'soft_delete'; - } - break; -} -/** -* This event allows you to do extra auth checks and verify if the user -* has the required permissions -* -* Extensions should only change the error and is_authed variables. -* -* @event core.modify_posting_auth -* @var int post_id ID of the post -* @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 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 -* @var bool load Whether or not a draft is being loaded -* @var bool refresh Whether or not to retain previously submitted data -* @var string mode What action to take if the form has been submitted -* post|reply|quote|edit|delete|bump|smilies|popup -* @var array error Any error strings; a non-empty array aborts -* form submission. -* NOTE: Should be actual language strings, NOT -* language keys. -* @var bool is_authed Does the user have the required permissions? -* @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', - 'submit', - 'preview', - 'save', - 'load', - 'refresh', - 'mode', - 'error', - 'is_authed', - 'post_data', -); -extract($phpbb_dispatcher->trigger_event('core.modify_posting_auth', compact($vars))); - -if (!$is_authed || !empty($error)) -{ - $check_auth = ($mode == 'quote') ? 'reply' : (($mode == 'soft_delete') ? 'delete' : $mode); - - if ($user->data['is_registered']) - { - trigger_error(empty($error) ? 'USER_CANNOT_' . strtoupper($check_auth) : implode('
', $error)); - } - $message = $user->lang['LOGIN_EXPLAIN_' . strtoupper($mode)]; - - if ($request->is_ajax()) - { - $json = new phpbb\json_response(); - $json->send(array( - 'title' => $user->lang['INFORMATION'], - 'message' => $message, - )); - } - - login_box('', $message); -} - -// Is the user able to post within this forum? -if ($post_data['forum_type'] != FORUM_POST && in_array($mode, array('post', 'bump', 'quote', 'reply'))) -{ - trigger_error('USER_CANNOT_FORUM_POST'); -} - -// Forum/Topic locked? -if (($post_data['forum_status'] == ITEM_LOCKED || (isset($post_data['topic_status']) && $post_data['topic_status'] == ITEM_LOCKED)) && !$auth->acl_get('m_edit', $forum_id)) -{ - trigger_error(($post_data['forum_status'] == ITEM_LOCKED) ? 'FORUM_LOCKED' : 'TOPIC_LOCKED'); -} - -// Can we edit this post ... if we're a moderator with rights then always yes -// else it depends on editing times, lock status and if we're the correct user -if ($mode == 'edit' && !$auth->acl_get('m_edit', $forum_id)) -{ - $force_edit_allowed = false; - - $s_cannot_edit = $user->data['user_id'] != $post_data['poster_id']; - $s_cannot_edit_time = $config['edit_time'] && $post_data['post_time'] <= time() - ($config['edit_time'] * 60); - $s_cannot_edit_locked = $post_data['post_edit_locked']; - - /** - * This event allows you to modify the conditions for the "cannot edit post" checks - * - * @event core.posting_modify_cannot_edit_conditions - * @var array post_data Array with post data - * @var bool force_edit_allowed Allow the user to edit the post (all permissions and conditions are ignored) - * @var bool s_cannot_edit User can not edit the post because it's not his - * @var bool s_cannot_edit_locked User can not edit the post because it's locked - * @var bool s_cannot_edit_time User can not edit the post because edit_time has passed - * @since 3.1.0-b4 - */ - $vars = array( - 'post_data', - 'force_edit_allowed', - 's_cannot_edit', - 's_cannot_edit_locked', - 's_cannot_edit_time', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_cannot_edit_conditions', compact($vars))); - - if (!$force_edit_allowed) - { - if ($s_cannot_edit) - { - trigger_error('USER_CANNOT_EDIT'); - } - else if ($s_cannot_edit_time) - { - trigger_error('CANNOT_EDIT_TIME'); - } - else if ($s_cannot_edit_locked) - { - trigger_error('CANNOT_EDIT_POST_LOCKED'); - } - } -} - -// Handle delete mode... -if ($mode == 'delete' || $mode == 'soft_delete') -{ - if ($mode == 'soft_delete' && $post_data['post_visibility'] == ITEM_DELETED) - { - $user->setup('posting'); - trigger_error('NO_POST'); - } - - $delete_reason = $request->variable('delete_reason', '', true); - phpbb_handle_post_delete($forum_id, $topic_id, $post_id, $post_data, ($mode == 'soft_delete' && !$request->is_set_post('delete_permanent')), $delete_reason); - return; -} - -// Handle bump mode... -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->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); - $message = $user->lang['TOPIC_BUMPED']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('VIEW_MESSAGE', '', ''); - $message .= '

' . $user->lang('RETURN_FORUM', '', ''); - } - - trigger_error($message); - } - - trigger_error('BUMP_ERROR'); -} - -// Subject length limiting to 60 characters if first post... -if ($mode == 'post' || ($mode == 'edit' && $post_data['topic_first_post_id'] == $post_data['post_id'])) -{ - $template->assign_var('S_NEW_MESSAGE', true); -} - -// Determine some vars -if (isset($post_data['poster_id']) && $post_data['poster_id'] == ANONYMOUS) -{ - $post_data['quote_username'] = (!empty($post_data['post_username'])) ? $post_data['post_username'] : $user->lang['GUEST']; -} -else -{ - $post_data['quote_username'] = isset($post_data['username']) ? $post_data['username'] : ''; -} - -$post_data['post_edit_locked'] = (isset($post_data['post_edit_locked'])) ? (int) $post_data['post_edit_locked'] : 0; -$post_data['post_subject_md5'] = (isset($post_data['post_subject']) && $mode == 'edit') ? md5($post_data['post_subject']) : ''; -$post_data['post_subject'] = (in_array($mode, array('quote', 'edit'))) ? $post_data['post_subject'] : ((isset($post_data['topic_title'])) ? $post_data['topic_title'] : ''); -$post_data['topic_time_limit'] = (isset($post_data['topic_time_limit'])) ? (($post_data['topic_time_limit']) ? (int) $post_data['topic_time_limit'] / 86400 : (int) $post_data['topic_time_limit']) : 0; -$post_data['poll_length'] = (!empty($post_data['poll_length'])) ? (int) $post_data['poll_length'] / 86400 : 0; -$post_data['poll_start'] = (!empty($post_data['poll_start'])) ? (int) $post_data['poll_start'] : 0; -$post_data['icon_id'] = (!isset($post_data['icon_id']) || in_array($mode, array('quote', 'reply'))) ? 0 : (int) $post_data['icon_id']; -$post_data['poll_options'] = array(); - -// Get Poll Data -if ($post_data['poll_start']) -{ - $sql = 'SELECT poll_option_text - FROM ' . POLL_OPTIONS_TABLE . " - WHERE topic_id = $topic_id - ORDER BY poll_option_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $post_data['poll_options'][] = trim($row['poll_option_text']); - } - $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( - 'poll_title' => $post_data['poll_title'], - 'poll_length' => $post_data['poll_length'], - 'poll_max_options' => $post_data['poll_max_options'], - 'poll_option_text' => implode("\n", $post_data['poll_options']), - 'poll_start' => $post_data['poll_start'], - 'poll_last_vote' => $post_data['poll_last_vote'], - 'poll_vote_change' => $post_data['poll_vote_change'], - ); -} - -$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); - -if (isset($post_data['post_text'])) -{ - $message_parser->message = &$post_data['post_text']; - unset($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])) - { - $post_data[$var_name] = $default_value; - } -} -unset($uninit); - -// Always check if the submitted attachment data is valid and belongs to the user. -// Further down (especially in submit_post()) we do not check this again. -$message_parser->get_submitted_attachment_data($post_data['poster_id']); - -if ($post_data['post_attachment'] && !$submit && !$refresh && !$preview && $mode == 'edit') -{ - // Do not change to SELECT * - $sql = 'SELECT attach_id, is_orphan, attach_comment, real_filename, filesize - FROM ' . ATTACHMENTS_TABLE . " - WHERE post_msg_id = $post_id - AND in_message = 0 - AND is_orphan = 0 - ORDER BY attach_id DESC"; - $result = $db->sql_query($sql); - $message_parser->attachment_data = array_merge($message_parser->attachment_data, $db->sql_fetchrowset($result)); - $db->sql_freeresult($result); -} - -if ($post_data['poster_id'] == ANONYMOUS) -{ - $post_data['username'] = ($mode == 'quote' || $mode == 'edit') ? trim($post_data['post_username']) : ''; -} -else -{ - $post_data['username'] = ($mode == 'quote' || $mode == 'edit') ? trim($post_data['username']) : ''; -} - -$post_data['enable_urls'] = $post_data['enable_magic_url']; - -if ($mode != 'edit') -{ - $post_data['enable_sig'] = ($config['allow_sig'] && $user->optionget('attachsig')) ? true: false; - $post_data['enable_smilies'] = ($config['allow_smilies'] && $user->optionget('smilies')) ? true : false; - $post_data['enable_bbcode'] = ($config['allow_bbcode'] && $user->optionget('bbcode')) ? true : false; - $post_data['enable_urls'] = true; -} - -if ($mode == 'post') -{ - $post_data['topic_status'] = ($request->is_set_post('lock_topic') && $auth->acl_gets('m_lock', 'f_user_lock', $forum_id)) ? ITEM_LOCKED : ITEM_UNLOCKED; -} - -$post_data['enable_magic_url'] = $post_data['drafts'] = false; - -// User own some drafts? -if ($user->data['is_registered'] && $auth->acl_get('u_savedrafts') && ($mode == 'reply' || $mode == 'post' || $mode == 'quote')) -{ - $sql = 'SELECT draft_id - FROM ' . DRAFTS_TABLE . ' - WHERE user_id = ' . $user->data['user_id'] . - (($forum_id) ? ' AND forum_id = ' . (int) $forum_id : '') . - (($topic_id) ? ' AND topic_id = ' . (int) $topic_id : '') . - (($draft_id) ? " AND draft_id <> $draft_id" : ''); - $result = $db->sql_query_limit($sql, 1); - - if ($db->sql_fetchrow($result)) - { - $post_data['drafts'] = true; - } - $db->sql_freeresult($result); -} - -$check_value = (($post_data['enable_bbcode']+1) << 8) + (($post_data['enable_smilies']+1) << 4) + (($post_data['enable_urls']+1) << 2) + (($post_data['enable_sig']+1) << 1); - -// Check if user is watching this topic -if ($mode != 'post' && $config['allow_topic_notify'] && $user->data['is_registered']) -{ - $sql = 'SELECT topic_id - FROM ' . TOPICS_WATCH_TABLE . ' - WHERE topic_id = ' . $topic_id . ' - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - $post_data['notify_set'] = (int) $db->sql_fetchfield('topic_id'); - $db->sql_freeresult($result); -} - -// Do we want to edit our post ? -if ($mode == 'edit' && $post_data['bbcode_uid']) -{ - $message_parser->bbcode_uid = $post_data['bbcode_uid']; -} - -// HTML, BBCode, Smilies, Images and Flash status -$bbcode_status = ($config['allow_bbcode'] && $auth->acl_get('f_bbcode', $forum_id)) ? true : false; -$smilies_status = ($config['allow_smilies'] && $auth->acl_get('f_smilies', $forum_id)) ? true : false; -$img_status = ($bbcode_status && $auth->acl_get('f_img', $forum_id)) ? true : false; -$url_status = ($config['allow_post_links']) ? true : false; -$flash_status = ($bbcode_status && $auth->acl_get('f_flash', $forum_id) && $config['allow_post_flash']) ? true : false; -$quote_status = true; - -// Save Draft -if ($save && $user->data['is_registered'] && $auth->acl_get('u_savedrafts') && ($mode == 'reply' || $mode == 'post' || $mode == 'quote')) -{ - $subject = $request->variable('subject', '', true); - $subject = (!$subject && $mode != 'post') ? $post_data['topic_title'] : $subject; - $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_parser->message) - ); - $db->sql_query($sql); - - $meta_info = ($mode == 'post') ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) : append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id"); - - meta_refresh(3, $meta_info); - - $message = $user->lang['DRAFT_SAVED'] . '

'; - $message .= ($mode != 'post') ? sprintf($user->lang['RETURN_TOPIC'], '', '') . '

' : ''; - $message .= sprintf($user->lang['RETURN_FORUM'], '', ''); - - trigger_error($message); - } - else - { - $s_hidden_fields = build_hidden_fields(array( - 'mode' => $mode, - 'save' => true, - 'f' => $forum_id, - 't' => $topic_id, - 'subject' => $subject, - 'message' => $message, - 'attachment_data' => $message_parser->attachment_data, - ) - ); - - $hidden_fields = array( - 'icon_id' => 0, - - 'disable_bbcode' => false, - 'disable_smilies' => false, - 'disable_magic_url' => false, - 'attach_sig' => true, - 'lock_topic' => false, - - 'topic_type' => POST_NORMAL, - 'topic_time_limit' => 0, - - 'poll_title' => '', - 'poll_option_text' => '', - 'poll_max_options' => 1, - 'poll_length' => 0, - 'poll_vote_change' => false, - ); - - foreach ($hidden_fields as $name => $default) - { - if (!isset($_POST[$name])) - { - // Don't include it, if its not available - unset($hidden_fields[$name]); - continue; - } - - if (is_bool($default)) - { - // Use the string representation - $hidden_fields[$name] = $request->variable($name, ''); - } - else - { - $hidden_fields[$name] = $request->variable($name, $default); - } - } - - $s_hidden_fields .= build_hidden_fields($hidden_fields); - - confirm_box(false, 'SAVE_DRAFT', $s_hidden_fields); - } - } - else - { - if (utf8_clean_string($subject) === '') - { - $error[] = $user->lang['EMPTY_SUBJECT']; - } - - if (utf8_clean_string($message) === '') - { - $error[] = $user->lang['TOO_FEW_CHARS']; - } - } - unset($subject, $message); -} - -// Load requested Draft -if ($draft_id && ($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $user->data['is_registered'] && $auth->acl_get('u_savedrafts')) -{ - $sql = 'SELECT draft_subject, draft_message - FROM ' . DRAFTS_TABLE . " - WHERE draft_id = $draft_id - AND user_id = " . $user->data['user_id']; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $post_data['post_subject'] = $row['draft_subject']; - $message_parser->message = $row['draft_message']; - - $template->assign_var('S_DRAFT_LOADED', true); - } - else - { - $draft_id = 0; - } -} - -// Load draft overview -if ($load && ($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_data['drafts']) -{ - 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->variable('topic_cur_post_id', 0); - $post_data['post_subject'] = $request->variable('subject', '', true); - $message_parser->message = $request->variable('message', '', 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->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->variable('icon', (int) $post_data['icon_id']); - } - - $post_data['enable_bbcode'] = (!$bbcode_status || isset($_POST['disable_bbcode'])) ? false : true; - $post_data['enable_smilies'] = (!$smilies_status || isset($_POST['disable_smilies'])) ? false : true; - $post_data['enable_urls'] = (isset($_POST['disable_magic_url'])) ? 0 : 1; - $post_data['enable_sig'] = (!$config['allow_sig'] || !$auth->acl_get('f_sigs', $forum_id) || !$auth->acl_get('u_sig')) ? false : ((isset($_POST['attach_sig']) && $user->data['is_registered']) ? true : false); - - if ($config['allow_topic_notify'] && $user->data['is_registered']) - { - $notify = (isset($_POST['notify'])) ? true : false; - } - else - { - $notify = false; - } - - $topic_lock = (isset($_POST['lock_topic'])) ? true : false; - $post_lock = (isset($_POST['lock_post'])) ? true : false; - $poll_delete = (isset($_POST['poll_delete'])) ? true : false; - - if ($submit) - { - $status_switch = (($post_data['enable_bbcode']+1) << 8) + (($post_data['enable_smilies']+1) << 4) + (($post_data['enable_urls']+1) << 2) + (($post_data['enable_sig']+1) << 1); - $status_switch = ($status_switch != $check_value); - } - else - { - $status_switch = 1; - } - - // Delete Poll - 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')) - { - $sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . POLL_VOTES_TABLE . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - $topic_sql = array( - 'poll_title' => '', - 'poll_start' => 0, - 'poll_length' => 0, - 'poll_last_vote' => 0, - 'poll_max_options' => 0, - 'poll_vote_change' => 0 - ); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $topic_sql) . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - } - - $post_data['poll_title'] = $post_data['poll_option_text'] = ''; - $post_data['poll_vote_change'] = $post_data['poll_max_options'] = $post_data['poll_length'] = 0; - } - else - { - $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; - } - - // If replying/quoting and last post id has changed - // give user option to continue submit or return to post - // notify and show user the post made between his request and the final submit - if (($mode == 'reply' || $mode == 'quote') && $post_data['topic_cur_post_id'] && $post_data['topic_cur_post_id'] != $post_data['topic_last_post_id']) - { - // Only do so if it is allowed forum-wide - if ($post_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) - { - if (topic_review($topic_id, $forum_id, 'post_review', $post_data['topic_cur_post_id'])) - { - $template->assign_var('S_POST_REVIEW', true); - } - - $submit = false; - $refresh = true; - } - } - - // Parse Attachments - before checksum is calculated - $message_parser->parse_attachments('fileupload', $mode, $forum_id, $submit, $preview, $refresh); - - /** - * This event allows you to modify message text before parsing - * - * @event core.posting_modify_message_text - * @var array post_data Array with post data - * @var string mode What action to take if the form is submitted - * post|reply|quote|edit|delete|bump|smilies|popup - * @var int post_id ID of the post - * @var int topic_id ID of the topic - * @var int forum_id ID of the forum - * @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 - * @var bool load Whether or not a draft is being loaded - * @var bool cancel Whether or not to cancel the form (returns to - * viewtopic or viewforum depending on if the user - * is posting a new topic or editing a post) - * @var bool refresh Whether or not to retain previously submitted data - * @var object message_parser The message parser object - * @var array error Array of errors - * @since 3.1.2-RC1 - * @changed 3.1.11-RC1 Added error - */ - $vars = array( - 'post_data', - 'mode', - 'post_id', - 'topic_id', - 'forum_id', - 'submit', - 'preview', - 'save', - 'load', - 'cancel', - 'refresh', - 'message_parser', - 'error', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_message_text', compact($vars))); - - // Grab md5 'checksum' of new message - $message_md5 = md5($message_parser->message); - - // If editing and checksum has changed we know the post was edited while we're editing - // Notify and show user the changed post - if ($mode == 'edit' && $post_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) - { - $edit_post_message_checksum = $request->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 - // $edit_post_message_checksum is the checksum of the post we're editing - // ... - - // We make sure nobody else made exactly the same change - // we're about to submit by also checking $message_md5 != $post_data['post_checksum'] - if ($edit_post_message_checksum !== '' && - $edit_post_message_checksum != $post_data['post_checksum'] && - $message_md5 != $post_data['post_checksum'] - || - $edit_post_subject_checksum !== '' && - $edit_post_subject_checksum != $post_data['post_subject_md5'] && - md5($post_data['post_subject']) != $post_data['post_subject_md5']) - { - if (topic_review($topic_id, $forum_id, 'post_review_edit', $post_id)) - { - $template->assign_vars(array( - 'S_POST_REVIEW' => true, - - 'L_POST_REVIEW' => $user->lang['POST_REVIEW_EDIT'], - 'L_POST_REVIEW_EXPLAIN' => $user->lang['POST_REVIEW_EDIT_EXPLAIN'], - )); - } - - $submit = false; - $refresh = true; - } - } - - // Check checksum ... don't re-parse message if the same - $update_message = ($mode != 'edit' || $message_md5 != $post_data['post_checksum'] || $status_switch || strlen($post_data['bbcode_uid']) < BBCODE_UID_LEN) ? true : false; - - // Also check if subject got updated... - $update_subject = $mode != 'edit' || ($post_data['post_subject_md5'] && $post_data['post_subject_md5'] != md5($post_data['post_subject'])); - - // Parse message - if ($update_message) - { - if (count($message_parser->warn_msg)) - { - $error[] = implode('
', $message_parser->warn_msg); - $message_parser->warn_msg = array(); - } - - if (!$preview || !empty($message_parser->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']); - } - - // On a refresh we do not care about message parsing errors - if (count($message_parser->warn_msg) && $refresh && !$preview) - { - $message_parser->warn_msg = array(); - } - } - else - { - $message_parser->bbcode_bitfield = $post_data['bbcode_bitfield']; - } - - $ignore_flood = $auth->acl_get('u_ignoreflood') ? true : $auth->acl_get('f_ignoreflood', $forum_id); - if ($mode != 'edit' && !$preview && !$refresh && $config['flood_interval'] && !$ignore_flood) - { - // Flood check - $last_post_time = 0; - - if ($user->data['is_registered']) - { - $last_post_time = $user->data['user_lastpost_time']; - } - else - { - $sql = 'SELECT post_time AS last_post_time - FROM ' . POSTS_TABLE . " - WHERE poster_ip = '" . $user->ip . "' - AND post_time > " . ($current_time - $config['flood_interval']); - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) - { - $last_post_time = $row['last_post_time']; - } - $db->sql_freeresult($result); - } - - if ($last_post_time && ($current_time - $last_post_time) < intval($config['flood_interval'])) - { - $error[] = $user->lang['FLOOD_ERROR']; - } - } - - // Validate username - if (($post_data['username'] && !$user->data['is_registered']) || ($mode == 'edit' && $post_data['poster_id'] == ANONYMOUS && $post_data['username'] && $post_data['post_username'] && $post_data['post_username'] != $post_data['username'])) - { - if (!function_exists('validate_username')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $user->add_lang('ucp'); - - if (($result = validate_username($post_data['username'], (!empty($post_data['post_username'])) ? $post_data['post_username'] : '')) !== false) - { - $error[] = $user->lang[$result . '_USERNAME']; - } - - if (($result = validate_string($post_data['username'], false, $config['min_name_chars'], $config['max_name_chars'])) !== false) - { - $min_max_amount = ($result == 'TOO_SHORT') ? $config['min_name_chars'] : $config['max_name_chars']; - $error[] = $user->lang('FIELD_' . $result, $min_max_amount, $user->lang['USERNAME']); - } - } - - if ($config['enable_post_confirm'] && !$user->data['is_registered'] && in_array($mode, array('quote', 'post', 'reply'))) - { - $captcha_data = array( - 'message' => $request->variable('message', '', true), - 'subject' => $request->variable('subject', '', true), - 'username' => $request->variable('username', '', true), - ); - $vc_response = $captcha->validate($captcha_data); - if ($vc_response) - { - $error[] = $vc_response; - } - } - - // check form - if (($submit || $preview) && !check_form_key('posting')) - { - $error[] = $user->lang['FORM_INVALID']; - } - - if ($submit && $mode == 'edit' && $post_data['post_visibility'] == ITEM_DELETED && !isset($_POST['soft_delete']) && $auth->acl_get('m_approve', $forum_id)) - { - $is_first_post = ($post_id == $post_data['topic_first_post_id'] || !$post_data['topic_posts_approved']); - $is_last_post = ($post_id == $post_data['topic_last_post_id'] || !$post_data['topic_posts_approved']); - $updated_post_data = $phpbb_content_visibility->set_post_visibility(ITEM_APPROVED, $post_id, $post_data['topic_id'], $post_data['forum_id'], $user->data['user_id'], time(), '', $is_first_post, $is_last_post); - - if (!empty($updated_post_data)) - { - // Update the post_data, so we don't need to refetch it. - $post_data = array_merge($post_data, $updated_post_data); - } - } - - // Parse subject - if (!$preview && !$refresh && utf8_clean_string($post_data['post_subject']) === '' && ($mode == 'post' || ($mode == 'edit' && $post_data['topic_first_post_id'] == $post_id))) - { - $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)) - { - $character_list = implode('
', $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; - - if ($post_data['poll_option_text'] && - ($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_post_id']/* && (!$post_data['poll_last_vote'] || $auth->acl_get('m_edit', $forum_id))*/)) - && $auth->acl_get('f_poll', $forum_id)) - { - $poll = array( - 'poll_title' => $post_data['poll_title'], - 'poll_length' => $post_data['poll_length'], - 'poll_max_options' => $post_data['poll_max_options'], - 'poll_option_text' => $post_data['poll_option_text'], - 'poll_start' => $post_data['poll_start'], - 'poll_last_vote' => $post_data['poll_last_vote'], - 'poll_vote_change' => $post_data['poll_vote_change'], - 'enable_bbcode' => $post_data['enable_bbcode'], - 'enable_urls' => $post_data['enable_urls'], - 'enable_smilies' => $post_data['enable_smilies'], - 'img_status' => $img_status - ); - - $message_parser->parse_poll($poll); - - $post_data['poll_options'] = (isset($poll['poll_options'])) ? $poll['poll_options'] : array(); - $post_data['poll_title'] = (isset($poll['poll_title'])) ? $poll['poll_title'] : ''; - - /* We reset votes, therefore also allow removing options - if ($post_data['poll_last_vote'] && ($poll['poll_options_size'] < $orig_poll_options_size)) - { - $message_parser->warn_msg[] = $user->lang['NO_DELETE_POLL_OPTIONS']; - }*/ - } - else if ($mode == 'edit' && $post_id == $post_data['topic_first_post_id'] && $auth->acl_get('f_poll', $forum_id)) - { - // The user removed all poll options, this is equal to deleting the poll. - $poll = array( - 'poll_title' => '', - 'poll_length' => 0, - 'poll_max_options' => 0, - 'poll_option_text' => '', - 'poll_start' => 0, - 'poll_last_vote' => 0, - 'poll_vote_change' => 0, - 'poll_options' => array(), - ); - - $post_data['poll_options'] = array(); - $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']) && !$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'], - 'enable_smilies' => $post_data['enable_smilies'], - 'img_status' => $img_status, - )); - - $message_parser->parse_poll($poll); - - $post_data['poll_options'] = (isset($poll['poll_options'])) ? $poll['poll_options'] : array(); - $post_data['poll_title'] = (isset($poll['poll_title'])) ? $poll['poll_title'] : ''; - } - else - { - $poll = array(); - } - - // Check topic type - if ($post_data['topic_type'] != POST_NORMAL && ($mode == 'post' || ($mode == 'edit' && $post_data['topic_first_post_id'] == $post_id))) - { - switch ($post_data['topic_type']) - { - case POST_GLOBAL: - $auth_option = 'f_announce_global'; - break; - - case POST_ANNOUNCE: - $auth_option = 'f_announce'; - break; - - case POST_STICKY: - $auth_option = 'f_sticky'; - break; - - default: - $auth_option = ''; - break; - } - - if ($auth_option != '' && !$auth->acl_get($auth_option, $forum_id)) - { - // There is a special case where a user edits his post whereby the topic type got changed by an admin/mod. - // Another case would be a mod not having sticky permissions for example but edit permissions. - if ($mode == 'edit') - { - // To prevent non-authed users messing around with the topic type we reset it to the original one. - $post_data['topic_type'] = $post_data['orig_topic_type']; - } - else - { - $error[] = $user->lang['CANNOT_POST_' . str_replace('F_', '', strtoupper($auth_option))]; - } - } - } - - if (count($message_parser->warn_msg)) - { - $error[] = implode('
', $message_parser->warn_msg); - } - - // DNSBL check - if ($config['check_dnsbl'] && !$refresh) - { - if (($dnsbl = $user->check_dnsbl('post')) !== false) - { - $error[] = sprintf($user->lang['IP_BLACKLISTED'], $user->ip, $dnsbl[1]); - } - } - - /** - * This event allows you to define errors before the post action is performed - * - * @event core.posting_modify_submission_errors - * @var array post_data Array with post data - * @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 int post_id ID of the post - * @var int topic_id ID of the topic - * @var int forum_id ID of the forum - * @var bool submit Whether or not the form has been submitted - * @var array error Any error strings; a non-empty array aborts form submission. - * 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', - 'post_id', - 'topic_id', - 'forum_id', - 'submit', - 'error', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_submission_errors', compact($vars))); - - // Store message, sync counters - if (!count($error) && $submit) - { - if ($submit) - { - // Lock/Unlock Topic - $change_topic_status = $post_data['topic_status']; - $perm_lock_unlock = ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && !empty($post_data['topic_poster']) && $user->data['user_id'] == $post_data['topic_poster'] && $post_data['topic_status'] == ITEM_UNLOCKED)) ? true : false; - - if ($post_data['topic_status'] == ITEM_LOCKED && !$topic_lock && $perm_lock_unlock) - { - $change_topic_status = ITEM_UNLOCKED; - } - else if ($post_data['topic_status'] == ITEM_UNLOCKED && $topic_lock && $perm_lock_unlock) - { - $change_topic_status = ITEM_LOCKED; - } - - if ($change_topic_status != $post_data['topic_status']) - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_status = $change_topic_status - WHERE topic_id = $topic_id - AND topic_moved_id = 0"; - $db->sql_query($sql); - - $user_lock = ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $post_data['topic_poster']) ? 'USER_' : ''; - - $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 - if ($mode == 'edit' && $post_data['post_edit_locked'] == ITEM_LOCKED && !$post_lock && $auth->acl_get('m_edit', $forum_id)) - { - $post_data['post_edit_locked'] = ITEM_UNLOCKED; - } - else if ($mode == 'edit' && $post_data['post_edit_locked'] == ITEM_UNLOCKED && $post_lock && $auth->acl_get('m_edit', $forum_id)) - { - $post_data['post_edit_locked'] = ITEM_LOCKED; - } - - $data = array( - 'topic_title' => (empty($post_data['topic_title'])) ? $post_data['post_subject'] : $post_data['topic_title'], - 'topic_first_post_id' => (isset($post_data['topic_first_post_id'])) ? (int) $post_data['topic_first_post_id'] : 0, - 'topic_last_post_id' => (isset($post_data['topic_last_post_id'])) ? (int) $post_data['topic_last_post_id'] : 0, - 'topic_time_limit' => (int) $post_data['topic_time_limit'], - 'topic_attachment' => (isset($post_data['topic_attachment'])) ? (int) $post_data['topic_attachment'] : 0, - 'post_id' => (int) $post_id, - 'topic_id' => (int) $topic_id, - 'forum_id' => (int) $forum_id, - 'icon_id' => (int) $post_data['icon_id'], - 'poster_id' => (int) $post_data['poster_id'], - 'enable_sig' => (bool) $post_data['enable_sig'], - 'enable_bbcode' => (bool) $post_data['enable_bbcode'], - 'enable_smilies' => (bool) $post_data['enable_smilies'], - 'enable_urls' => (bool) $post_data['enable_urls'], - 'enable_indexing' => (bool) $post_data['enable_indexing'], - 'message_md5' => (string) $message_md5, - 'post_checksum' => (isset($post_data['post_checksum'])) ? (string) $post_data['post_checksum'] : '', - 'post_edit_reason' => $post_data['post_edit_reason'], - 'post_edit_user' => ($mode == 'edit') ? $user->data['user_id'] : ((isset($post_data['post_edit_user'])) ? (int) $post_data['post_edit_user'] : 0), - 'forum_parents' => $post_data['forum_parents'], - 'forum_name' => $post_data['forum_name'], - 'notify' => $notify, - 'notify_set' => $post_data['notify_set'], - 'poster_ip' => (isset($post_data['poster_ip'])) ? $post_data['poster_ip'] : $user->ip, - 'post_edit_locked' => (int) $post_data['post_edit_locked'], - 'bbcode_bitfield' => $message_parser->bbcode_bitfield, - 'bbcode_uid' => $message_parser->bbcode_uid, - 'message' => $message_parser->message, - 'attachment_data' => $message_parser->attachment_data, - 'filename_data' => $message_parser->filename_data, - 'topic_status' => $post_data['topic_status'], - - 'topic_visibility' => (isset($post_data['topic_visibility'])) ? $post_data['topic_visibility'] : false, - 'post_visibility' => (isset($post_data['post_visibility'])) ? $post_data['post_visibility'] : false, - ); - - if ($mode == 'edit') - { - $data['topic_posts_approved'] = $post_data['topic_posts_approved']; - $data['topic_posts_unapproved'] = $post_data['topic_posts_unapproved']; - $data['topic_posts_softdeleted'] = $post_data['topic_posts_softdeleted']; - } - - // Only return the username when it is either a guest posting or we are editing a post and - // the username was supplied; otherwise post_data might hold the data of the post that is - // being quoted (which could result in the username being returned being that of the quoted - // post's poster, not the poster of the current post). See: PHPBB3-11769 for more information. - $post_author_name = ((!$user->data['is_registered'] || $mode == 'edit') && $post_data['username'] !== '') ? $post_data['username'] : ''; - - /** - * This event allows you to define errors before the post action is performed - * - * @event core.posting_modify_submit_post_before - * @var array post_data Array with post data - * @var array poll Array with poll data - * @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 int post_id ID of the post - * @var int topic_id ID of the topic - * @var int forum_id ID of the forum - * @var string post_author_name Author name for guest posts - * @var bool update_message Boolean if the post message was changed - * @var bool update_subject Boolean if the post subject was changed - * 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', - 'post_id', - 'topic_id', - 'forum_id', - 'post_author_name', - 'update_message', - 'update_subject', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_submit_post_before', compact($vars))); - - // The last parameter tells submit_post if search indexer has to be run - $redirect_url = submit_post($mode, $post_data['post_subject'], $post_author_name, $post_data['topic_type'], $poll, $data, $update_message, ($update_message || $update_subject) ? true : false); - - /** - * This event allows you to define errors after the post action is performed - * - * @event core.posting_modify_submit_post_after - * @var array post_data Array with post data - * @var array poll Array with poll data - * @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 int post_id ID of the post - * @var int topic_id ID of the topic - * @var int forum_id ID of the forum - * @var string post_author_name Author name for guest posts - * @var bool update_message Boolean if the post message was changed - * @var bool update_subject Boolean if the post subject was changed - * @var string redirect_url URL the user is going to be redirected to - * 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', - 'post_id', - 'topic_id', - 'forum_id', - 'post_author_name', - 'update_message', - 'update_subject', - 'redirect_url', - ); - extract($phpbb_dispatcher->trigger_event('core.posting_modify_submit_post_after', compact($vars))); - - if ($config['enable_post_confirm'] && !$user->data['is_registered'] && (isset($captcha) && $captcha->is_solved() === true) && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) - { - $captcha->reset(); - } - - // Handle delete mode... - if ($request->is_set_post('delete') || $request->is_set_post('delete_permanent')) - { - $delete_reason = $request->variable('delete_reason', '', true); - phpbb_handle_post_delete($forum_id, $topic_id, $post_id, $post_data, !$request->is_set_post('delete_permanent'), $delete_reason); - return; - } - - // Check the permissions for post approval. - // Moderators must go through post approval like ordinary users. - if ((!$auth->acl_get('f_noapprove', $data['forum_id']) && empty($data['force_approved_state'])) || (isset($data['force_approved_state']) && !$data['force_approved_state'])) - { - meta_refresh(10, $redirect_url); - $message = ($mode == 'edit') ? $user->lang['POST_EDITED_MOD'] : $user->lang['POST_STORED_MOD']; - $message .= (($user->data['user_id'] == ANONYMOUS) ? '' : ' '. $user->lang['POST_APPROVAL_NOTIFY']); - $message .= '

' . sprintf($user->lang['RETURN_FORUM'], '', ''); - trigger_error($message); - } - - redirect($redirect_url); - } - } -} - -// Preview -if (!count($error) && $preview) -{ - $post_data['post_time'] = ($mode == 'edit') ? $post_data['post_time'] : $current_time; - - $preview_message = $message_parser->format_display($post_data['enable_bbcode'], $post_data['enable_urls'], $post_data['enable_smilies'], false); - - $preview_signature = ($mode == 'edit') ? $post_data['user_sig'] : $user->data['user_sig']; - $preview_signature_uid = ($mode == 'edit') ? $post_data['user_sig_bbcode_uid'] : $user->data['user_sig_bbcode_uid']; - $preview_signature_bitfield = ($mode == 'edit') ? $post_data['user_sig_bbcode_bitfield'] : $user->data['user_sig_bbcode_bitfield']; - - // Signature - if ($post_data['enable_sig'] && $config['allow_sig'] && $preview_signature && $auth->acl_get('f_sigs', $forum_id)) - { - $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 - { - $preview_signature = ''; - } - - $preview_subject = censor_text($post_data['post_subject']); - - // Poll Preview - if (!$poll_delete && ($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_post_id']/* && (!$post_data['poll_last_vote'] || $auth->acl_get('m_edit', $forum_id))*/)) - && $auth->acl_get('f_poll', $forum_id)) - { - $parse_poll = new parse_message($post_data['poll_title']); - $parse_poll->bbcode_uid = $message_parser->bbcode_uid; - $parse_poll->bbcode_bitfield = $message_parser->bbcode_bitfield; - - $parse_poll->format_display($post_data['enable_bbcode'], $post_data['enable_urls'], $post_data['enable_smilies']); - - if ($post_data['poll_length']) - { - $poll_end = ($post_data['poll_length'] * 86400) + (($post_data['poll_start']) ? $post_data['poll_start'] : time()); - } - - $template->assign_vars(array( - '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, - - 'L_POLL_LENGTH' => ($post_data['poll_length']) ? sprintf($user->lang['POLL_RUN_TILL'], $user->format_date($poll_end)) : '', - 'L_MAX_VOTES' => $user->lang('MAX_OPTIONS_SELECT', (int) $post_data['poll_max_options']), - )); - - $preview_poll_options = array(); - foreach ($post_data['poll_options'] as $poll_option) - { - $parse_poll->message = $poll_option; - $parse_poll->format_display($post_data['enable_bbcode'], $post_data['enable_urls'], $post_data['enable_smilies']); - $preview_poll_options[] = $parse_poll->message; - } - unset($parse_poll); - - foreach ($preview_poll_options as $key => $option) - { - $template->assign_block_vars('poll_option', array( - 'POLL_OPTION_CAPTION' => $option, - 'POLL_OPTION_ID' => $key + 1) - ); - } - unset($preview_poll_options); - } - - // Attachment Preview - if (count($message_parser->attachment_data)) - { - $template->assign_var('S_HAS_ATTACHMENTS', true); - - $update_count = array(); - $attachment_data = $message_parser->attachment_data; - - parse_attachments($forum_id, $preview_message, $attachment_data, $update_count, true); - - foreach ($attachment_data as $i => $attachment) - { - $template->assign_block_vars('attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - unset($attachment_data); - } - - if (!count($error)) - { - $template->assign_vars(array( - 'PREVIEW_SUBJECT' => $preview_subject, - 'PREVIEW_MESSAGE' => $preview_message, - 'PREVIEW_SIGNATURE' => $preview_signature, - - 'S_DISPLAY_PREVIEW' => !empty($preview_message), - )); - } -} - -// Remove quotes that would become nested too deep before decoding the text -$generate_quote = ($mode == 'quote' && !$submit && !$preview && !$refresh); -if ($generate_quote && $config['max_quote_depth'] > 0) -{ - $tmp_bbcode_uid = $message_parser->bbcode_uid; - $message_parser->bbcode_uid = $post_data['bbcode_uid']; - $message_parser->remove_nested_quotes($config['max_quote_depth'] - 1); - $message_parser->bbcode_uid = $tmp_bbcode_uid; -} - -// Decode text for message display -$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) -{ - // 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); - - $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'], - ); - - /** - * 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']); -} - -$attachment_data = $message_parser->attachment_data; -$filename_data = $message_parser->filename_data; -$post_data['post_text'] = $message_parser->message; - -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']; - - $message_parser->decode_message(); - $post_data['poll_title'] = $message_parser->message; - - $message_parser->message = implode("\n", $post_data['poll_options']); - $message_parser->decode_message(); - $post_data['poll_options'] = explode("\n", $message_parser->message); -} - -// MAIN POSTING PAGE BEGINS HERE - -// Forum moderators? -$moderators = array(); -if ($config['load_moderators']) -{ - get_moderators($moderators, $forum_id); -} - -// Generate smiley listing -generate_smilies('inline', $forum_id); - -// Generate inline attachment select box -posting_gen_inline_attachments($attachment_data); - -// Do show topic type selection only in first post. -$topic_type_toggle = false; - -if ($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_post_id'])) -{ - $topic_type_toggle = posting_gen_topic_types($forum_id, $post_data['topic_type']); -} - -$s_topic_icons = false; -if ($post_data['enable_icons'] && $auth->acl_get('f_icons', $forum_id)) -{ - $s_topic_icons = posting_gen_topic_icons($mode, $post_data['icon_id']); -} - -$bbcode_checked = (isset($post_data['enable_bbcode'])) ? !$post_data['enable_bbcode'] : (($config['allow_bbcode']) ? !$user->optionget('bbcode') : 1); -$smilies_checked = (isset($post_data['enable_smilies'])) ? !$post_data['enable_smilies'] : (($config['allow_smilies']) ? !$user->optionget('smilies') : 1); -$urls_checked = (isset($post_data['enable_urls'])) ? !$post_data['enable_urls'] : 0; -$sig_checked = $post_data['enable_sig']; -$lock_topic_checked = (isset($topic_lock) && $topic_lock) ? $topic_lock : (($post_data['topic_status'] == ITEM_LOCKED) ? 1 : 0); -$lock_post_checked = (isset($post_lock)) ? $post_lock : $post_data['post_edit_locked']; - -// If the user is replying or posting and not already watching this topic but set to always being notified we need to overwrite this setting -$notify_set = ($mode != 'edit' && $config['allow_topic_notify'] && $user->data['is_registered'] && !$post_data['notify_set']) ? $user->data['user_notify'] : $post_data['notify_set']; -$notify_checked = (isset($notify)) ? $notify : (($mode == 'post') ? $user->data['user_notify'] : $notify_set); - -// Page title & action URL -$s_action = append_sid("{$phpbb_root_path}posting.$phpEx", "mode=$mode&f=$forum_id"); -$s_action .= ($topic_id) ? "&t=$topic_id" : ''; -$s_action .= ($post_id) ? "&p=$post_id" : ''; - -switch ($mode) -{ - case 'post': - $page_title = $user->lang['POST_TOPIC']; - break; - - case 'quote': - case 'reply': - $page_title = $user->lang['POST_REPLY']; - break; - - case 'delete': - case 'edit': - $page_title = $user->lang['EDIT_POST']; - break; -} - -// Build Navigation Links -generate_forum_nav($post_data); - -// Build Forum Rules -generate_forum_rules($post_data); - -// Posting uses is_solved for legacy reasons. Plugins have to use is_solved to force themselves to be displayed. -if ($config['enable_post_confirm'] && !$user->data['is_registered'] && (isset($captcha) && $captcha->is_solved() === false) && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) -{ - - $template->assign_vars(array( - 'S_CONFIRM_CODE' => true, - 'CAPTCHA_TEMPLATE' => $captcha->get_template(), - )); -} - -$s_hidden_fields = ($mode == 'reply' || $mode == 'quote') ? '' : ''; -$s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '' : ''; - -if ($mode == 'edit') -{ - $s_hidden_fields .= build_hidden_fields(array( - 'edit_post_message_checksum' => $post_data['post_checksum'], - 'edit_post_subject_checksum' => $post_data['post_subject_md5'], - )); -} - -// Add the confirm id/code pair to the hidden fields, else an error is displayed on next submit/preview -if (isset($captcha) && $captcha->is_solved() !== false) -{ - $s_hidden_fields .= build_hidden_fields($captcha->get_hidden_fields()); -} - -$form_enctype = (@ini_get('file_uploads') == '0' || strtolower(@ini_get('file_uploads')) == 'off' || !$config['allow_attachments'] || !$auth->acl_get('u_attach') || !$auth->acl_get('f_attach', $forum_id)) ? '' : ' enctype="multipart/form-data"'; -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( - 'L_POST_A' => $page_title, - 'L_ICON' => ($mode == 'reply' || $mode == 'quote' || ($mode == 'edit' && $post_id != $post_data['topic_first_post_id'])) ? $user->lang['POST_ICON'] : $user->lang['TOPIC_ICON'], - 'L_MESSAGE_BODY_EXPLAIN' => $user->lang('MESSAGE_BODY_EXPLAIN', (int) $config['max_post_chars']), - 'L_DELETE_POST_PERMANENTLY' => $user->lang('DELETE_POST_PERMANENTLY', 1), - - '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' => (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' => $user->lang(($bbcode_status ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '', ''), - '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' => ($bbcode_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['POST']), - 'POST_DATE' => ($post_data['post_time']) ? $user->format_date($post_data['post_time']) : '', - 'ERROR' => (count($error)) ? implode('
', $error) : '', - 'TOPIC_TIME_LIMIT' => (int) $post_data['topic_time_limit'], - 'EDIT_REASON' => $request->variable('edit_reason', '', true), - 'SHOW_PANEL' => $request->variable('show_panel', ''), - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id"), - 'U_VIEW_TOPIC' => ($mode != 'post') ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id") : '', - 'U_PROGRESS_BAR' => append_sid("{$phpbb_root_path}posting.$phpEx", "f=$forum_id&mode=popup"), - 'UA_PROGRESS_BAR' => addslashes(append_sid("{$phpbb_root_path}posting.$phpEx", "f=$forum_id&mode=popup")), - - 'S_PRIVMSGS' => false, - 'S_CLOSE_PROGRESS_WINDOW' => (isset($_POST['add_file'])) ? true : false, - 'S_EDIT_POST' => ($mode == 'edit') ? true : false, - 'S_EDIT_REASON' => ($mode == 'edit' && $auth->acl_get('m_edit', $forum_id)) ? true : false, - 'S_DISPLAY_USERNAME' => (!$user->data['is_registered'] || ($mode == 'edit' && $post_data['poster_id'] == ANONYMOUS)) ? true : false, - 'S_SHOW_TOPIC_ICONS' => $s_topic_icons, - 'S_DELETE_ALLOWED' => ($mode == 'edit' && (($post_id == $post_data['topic_last_post_id'] && $post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time'])) || $auth->acl_get('m_delete', $forum_id))) ? true : false, - 'S_BBCODE_ALLOWED' => ($bbcode_status) ? 1 : 0, - 'S_BBCODE_CHECKED' => ($bbcode_checked) ? ' checked="checked"' : '', - 'S_SMILIES_ALLOWED' => $smilies_status, - 'S_SMILIES_CHECKED' => ($smilies_checked) ? ' checked="checked"' : '', - 'S_SIG_ALLOWED' => ($auth->acl_get('f_sigs', $forum_id) && $config['allow_sig'] && $user->data['is_registered']) ? true : false, - 'S_SIGNATURE_CHECKED' => ($sig_checked) ? ' checked="checked"' : '', - 'S_NOTIFY_ALLOWED' => (!$user->data['is_registered'] || ($mode == 'edit' && $user->data['user_id'] != $post_data['poster_id']) || !$config['allow_topic_notify'] || !$config['email_enable']) ? false : true, - 'S_NOTIFY_CHECKED' => ($notify_checked) ? ' checked="checked"' : '', - 'S_LOCK_TOPIC_ALLOWED' => (($mode == 'edit' || $mode == 'reply' || $mode == 'quote' || $mode == 'post') && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && !empty($post_data['topic_poster']) && $user->data['user_id'] == $post_data['topic_poster'] && $post_data['topic_status'] == ITEM_UNLOCKED))) ? true : false, - 'S_LOCK_TOPIC_CHECKED' => ($lock_topic_checked) ? ' checked="checked"' : '', - 'S_LOCK_POST_ALLOWED' => ($mode == 'edit' && $auth->acl_get('m_edit', $forum_id)) ? true : false, - 'S_LOCK_POST_CHECKED' => ($lock_post_checked) ? ' checked="checked"' : '', - 'S_SOFTDELETE_CHECKED' => ($mode == 'edit' && $post_data['post_visibility'] == ITEM_DELETED) ? ' checked="checked"' : '', - 'S_SOFTDELETE_ALLOWED' => ($mode == 'edit' && $phpbb_content_visibility->can_soft_delete($forum_id, $post_data['poster_id'], $lock_post_checked)) ? true : false, - 'S_RESTORE_ALLOWED' => $auth->acl_get('m_approve', $forum_id), - 'S_IS_DELETED' => ($mode == 'edit' && $post_data['post_visibility'] == ITEM_DELETED) ? true : false, - 'S_LINKS_ALLOWED' => $url_status, - 'S_MAGIC_URL_CHECKED' => ($urls_checked) ? ' checked="checked"' : '', - 'S_TYPE_TOGGLE' => $topic_type_toggle, - 'S_SAVE_ALLOWED' => ($auth->acl_get('u_savedrafts') && $user->data['is_registered'] && $mode != 'edit') ? true : false, - 'S_HAS_DRAFTS' => ($auth->acl_get('u_savedrafts') && $user->data['is_registered'] && $post_data['drafts']) ? true : false, - 'S_FORM_ENCTYPE' => $form_enctype, - - 'S_BBCODE_IMG' => $img_status, - 'S_BBCODE_URL' => $url_status, - 'S_BBCODE_FLASH' => $flash_status, - 'S_BBCODE_QUOTE' => $quote_status, - - 'S_POST_ACTION' => $s_action, - 'S_HIDDEN_FIELDS' => $s_hidden_fields, - 'S_ATTACH_DATA' => json_encode($message_parser->attachment_data), - 'S_IN_POSTING' => true, -); - -// Build custom bbcodes array -display_custom_bbcodes(); - -// Poll entry -if (($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_post_id']/* && (!$post_data['poll_last_vote'] || $auth->acl_get('m_edit', $forum_id))*/)) - && $auth->acl_get('f_poll', $forum_id)) -{ - $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' && 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']), - - 'VOTE_CHANGE_CHECKED' => (!empty($post_data['poll_vote_change'])) ? ' checked="checked"' : '', - 'POLL_TITLE' => (isset($post_data['poll_title'])) ? $post_data['poll_title'] : '', - 'POLL_OPTIONS' => (!empty($post_data['poll_options'])) ? implode("\n", $post_data['poll_options']) : '', - 'POLL_MAX_OPTIONS' => (isset($post_data['poll_max_options'])) ? (int) $post_data['poll_max_options'] : 1, - 'POLL_LENGTH' => $post_data['poll_length'], - ) - ); -} - -/** -* This event allows you to modify template variables for the posting screen -* -* @event core.posting_modify_template_vars -* @var array post_data Array with post data -* @var array moderators Array with forum moderators -* @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 bool s_topic_icons Whether or not to show the topic icons -* @var string form_enctype If attachments are allowed for this form -* "multipart/form-data" or empty string -* @var string s_action The URL to submit the POST data to -* @var string s_hidden_fields Concatenated hidden input tags of posting form -* @var int post_id ID of the post -* @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 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 -* @var bool load Whether or not a draft is being loaded -* @var bool cancel Whether or not to cancel the form (returns to -* viewtopic or viewforum depending on if the user -* is posting a new topic or editing a post) -* @var array error Any error strings; a non-empty array aborts -* form submission. -* NOTE: Should be actual language strings, NOT -* language keys. -* @var bool refresh Whether or not to retain previously submitted data -* @var array page_data Posting page data that should be passed to the -* posting page via $template->assign_vars() -* @var object message_parser The message parser object -* @since 3.1.0-a1 -* @changed 3.1.0-b3 Added vars post_data, moderators, mode, page_title, -* s_topic_icons, form_enctype, s_action, s_hidden_fields, -* post_id, topic_id, forum_id, submit, preview, save, load, -* delete, cancel, refresh, error, page_data, message_parser -* @changed 3.1.2-RC1 Removed 'delete' var as it does not exist -* @changed 3.1.5-RC1 Added poll variables to the page_data array -* @changed 3.1.6-RC1 Added 'draft_id' var -*/ -$vars = array( - 'post_data', - 'moderators', - 'mode', - 'page_title', - 's_topic_icons', - 'form_enctype', - 's_action', - 's_hidden_fields', - 'post_id', - 'topic_id', - 'forum_id', - 'draft_id', - 'submit', - 'preview', - 'save', - 'load', - 'cancel', - 'refresh', - 'error', - 'page_data', - 'message_parser', -); -extract($phpbb_dispatcher->trigger_event('core.posting_modify_template_vars', compact($vars))); - -// Start assigning vars for main posting page ... -$template->assign_vars($page_data); - -// Show attachment box for adding attachments if true -$allowed = ($auth->acl_get('f_attach', $forum_id) && $auth->acl_get('u_attach') && $config['allow_attachments'] && $form_enctype); - -if ($allowed) -{ - $max_files = ($auth->acl_get('a_') || $auth->acl_get('m_', $forum_id)) ? 0 : (int) $config['max_attachments']; - $plupload->configure($cache, $template, $s_action, $forum_id, $max_files); -} - -// Attachment entry -posting_gen_attachment_entry($attachment_data, $filename_data, $allowed); - -// Output page ... -page_header($page_title); - -$template->set_filenames(array( - 'body' => 'posting_body.html') -); - -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - -// Topic review -if ($mode == 'reply' || $mode == 'quote') -{ - if (topic_review($topic_id, $forum_id)) - { - $template->assign_var('S_DISPLAY_REVIEW', true); - } -} - -page_footer(); diff --git a/install/update/old/report.php b/install/update/old/report.php deleted file mode 100644 index bb26b97..0000000 --- a/install/update/old/report.php +++ /dev/null @@ -1,41 +0,0 @@ - -* @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\HttpFoundation\RedirectResponse; - -/** -* @ignore -*/ -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); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); - -$post_id = $request->variable('p', 0); -$pm_id = $request->variable('pm', 0); - -$redirect_route_name = ($pm_id === 0) ? 'phpbb_report_post_controller' : 'phpbb_report_pm_controller'; - -/** @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 -); -$response->send(); diff --git a/install/update/old/search.php b/install/update/old/search.php deleted file mode 100644 index 97a8f32..0000000 --- a/install/update/old/search.php +++ /dev/null @@ -1,1552 +0,0 @@ - -* @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); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -include($phpbb_root_path . 'common.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup('search'); - -// Define initial vars -$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->variable('terms', 'all'); -$search_fields = $request->variable('sf', 'all'); -$search_child = $request->variable('sc', true); - -$sort_days = $request->variable('st', 0); -$sort_key = $request->variable('sk', 't'); -$sort_dir = $request->variable('sd', 'd'); - -$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 - -switch ($search_id) -{ - // Egosearch is an author search - case 'egosearch': - $author_id = $user->data['user_id']; - if ($user->data['user_id'] == ANONYMOUS) - { - login_box('', $user->lang['LOGIN_EXPLAIN_EGOSEARCH']); - } - break; - - // Search for unread posts needs to be allowed and user to be logged in if topics tracking for guests is disabled - case 'unreadposts': - if (!$config['load_unreads_search']) - { - $template->assign_var('S_NO_SEARCH', true); - trigger_error('NO_SEARCH_UNREADS'); - } - else if (!$config['load_anon_lastread'] && !$user->data['is_registered']) - { - login_box('', $user->lang['LOGIN_EXPLAIN_UNREADSEARCH']); - } - break; - - // The "new posts" search uses user_lastvisit which is user based, so it should require user to log in. - case 'newposts': - if ($user->data['user_id'] == ANONYMOUS) - { - login_box('', $user->lang['LOGIN_EXPLAIN_NEWPOSTS']); - } - break; - - default: - // There's nothing to do here for now ;) - break; -} - -// Is user able to search? Has search been disabled? -if (!$auth->acl_get('u_search') || !$auth->acl_getf_global('f_search') || !$config['load_search']) -{ - $template->assign_var('S_NO_SEARCH', true); - trigger_error('NO_SEARCH'); -} - -// Check search load limit -if ($user->load && $config['limit_search_load'] && ($user->load > doubleval($config['limit_search_load']))) -{ - $template->assign_var('S_NO_SEARCH', true); - trigger_error('NO_SEARCH_LOAD'); -} - -// It is applicable if the configuration setting is non-zero, and the user cannot -// ignore the flood setting, and the search is a keyword search. -$interval = ($user->data['user_id'] == ANONYMOUS) ? $config['search_anonymous_interval'] : $config['search_interval']; -if ($interval && !in_array($search_id, array('unreadposts', 'unanswered', 'active_topics', 'egosearch')) && !$auth->acl_get('u_ignoreflood')) -{ - if ($user->data['user_last_search'] > time() - $interval) - { - $template->assign_var('S_NO_SEARCH', true); - trigger_error($user->lang('NO_SEARCH_TIME', (int) ($user->data['user_last_search'] + $interval - time()))); - } -} - -// Define some vars -$limit_days = array(0 => $user->lang['ALL_RESULTS'], 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_AUTHOR'], 't' => $user->lang['SORT_TIME'], 'f' => $user->lang['SORT_FORUM'], 'i' => $user->lang['SORT_TOPIC_TITLE'], 's' => $user->lang['SORT_POST_SUBJECT']); - -$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'); - -/** -* This event allows you to alter the above parameters, such as keywords and submit -* -* @event core.search_modify_submit_parameters -* @var string keywords The search keywords -* @var string author Specifies the author match, when ANONYMOUS is also a search-match -* @var int author_id ID of the author to search by -* @var string search_id Predefined search type name -* @var bool submit Whether or not the form has been submitted -* @since 3.1.10-RC1 -*/ -$vars = array( - 'keywords', - 'author', - 'author_id', - 'search_id', - 'submit', -); -extract($phpbb_dispatcher->trigger_event('core.search_modify_submit_parameters', compact($vars))); - -if ($keywords || $author || $author_id || $search_id || $submit) -{ - // clear arrays - $id_ary = array(); - - // If we are looking for authors get their ids - $author_id_ary = array(); - $sql_author_match = ''; - if ($author_id) - { - $author_id_ary[] = $author_id; - } - else if ($author) - { - if ((strpos($author, '*') !== false) && (utf8_strlen(str_replace(array('*', '%'), '', $author)) < $config['min_search_author_chars'])) - { - trigger_error($user->lang('TOO_FEW_AUTHOR_CHARS', (int) $config['min_search_author_chars'])); - } - - $sql_where = (strpos($author, '*') !== false) ? ' username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " username_clean = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; - - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . " - WHERE $sql_where - AND user_type <> " . USER_IGNORE; - $result = $db->sql_query_limit($sql, 100); - - while ($row = $db->sql_fetchrow($result)) - { - $author_id_ary[] = (int) $row['user_id']; - } - $db->sql_freeresult($result); - - $sql_where = (strpos($author, '*') !== false) ? ' post_username ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " post_username = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; - - $sql = 'SELECT 1 as guest_post - FROM ' . POSTS_TABLE . " - WHERE $sql_where - AND poster_id = " . ANONYMOUS; - $result = $db->sql_query_limit($sql, 1); - $found_guest_post = $db->sql_fetchfield('guest_post'); - $db->sql_freeresult($result); - - if ($found_guest_post) - { - $author_id_ary[] = ANONYMOUS; - $sql_author_match = (strpos($author, '*') !== false) ? ' ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; - } - - if (!count($author_id_ary)) - { - trigger_error('NO_SEARCH_RESULTS'); - } - } - - // if we search in an existing search result just add the additional keywords. But we need to use "all search terms"-mode - // so we can keep the old keywords in their old mode, but add the new ones as required words - if ($add_keywords) - { - if ($search_terms == 'all') - { - $keywords .= ' ' . $add_keywords; - } - else - { - $search_terms = 'all'; - $keywords = implode(' |', explode(' ', preg_replace('#\s+#u', ' ', $keywords))) . ' ' .$add_keywords; - } - } - - // Which forums should not be searched? Author searches are also carried out in unindexed forums - if (empty($keywords) && count($author_id_ary)) - { - $ex_fid_ary = array_keys($auth->acl_getf('!f_read', true)); - } - else - { - $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 = (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 - LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id - AND fa.session_id = '" . $db->sql_escape($user->session_id) . "') - $not_in_fid - ORDER BY f.left_id"; - $result = $db->sql_query($sql); - - $right_id = 0; - $reset_search_forum = true; - while ($row = $db->sql_fetchrow($result)) - { - if ($row['forum_password'] && $row['user_id'] != $user->data['user_id']) - { - $ex_fid_ary[] = (int) $row['forum_id']; - continue; - } - - // Exclude forums from active topics - if (!($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) && ($search_id == 'active_topics')) - { - $ex_fid_ary[] = (int) $row['forum_id']; - continue; - } - - if (count($search_forum)) - { - if ($search_child) - { - if (in_array($row['forum_id'], $search_forum) && $row['right_id'] > $right_id) - { - $right_id = (int) $row['right_id']; - } - else if ($row['right_id'] < $right_id) - { - continue; - } - } - - if (!in_array($row['forum_id'], $search_forum)) - { - $ex_fid_ary[] = (int) $row['forum_id']; - $reset_search_forum = false; - } - } - } - $db->sql_freeresult($result); - - // find out in which forums the user is allowed to view posts - $m_approve_posts_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('post', $ex_fid_ary, 'p.'); - $m_approve_topics_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('topic', $ex_fid_ary, 't.'); - - if ($reset_search_forum) - { - $search_forum = array(); - } - - // Select which method we'll use to obtain the post_id or topic_id information - $search_type = $config['search_type']; - - if (!class_exists($search_type)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } - // We do some additional checks in the module to ensure it can actually be utilised - $error = false; - $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); - - if ($error) - { - trigger_error($error); - } - - // let the search module split up the keywords - if ($keywords) - { - $correct_query = $search->split_keywords($keywords, $search_terms); - $common_words = $search->get_common_words(); - if (!$correct_query || (!$search->get_search_query() && !count($author_id_ary) && !$search_id)) - { - $ignored = (count($common_words)) ? sprintf($user->lang['IGNORED_TERMS_EXPLAIN'], implode(' ', $common_words)) . '
' : ''; - $word_length = $search->get_word_length(); - if ($word_length) - { - trigger_error($ignored . $user->lang('NO_KEYWORDS', $user->lang('CHARACTERS', (int) $word_length['min']), $user->lang('CHARACTERS', (int) $word_length['max']))); - } - else - { - trigger_error($ignored); - } - } - } - - 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->variable('sr', ($search_id == 'egosearch') ? 'topics' : 'posts'); - $show_results = ($show_results == 'posts') ? 'posts' : 'topics'; - } - - // define some variables needed for retrieving post_id/topic_id information - $sort_by_sql = array('a' => 'u.username_clean', 't' => (($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time'), 'f' => 'f.forum_id', 'i' => 't.topic_title', 's' => (($show_results == 'posts') ? 'p.post_subject' : 't.topic_title')); - - /** - * Event to modify the SQL parameters before pre-made searches - * - * @event core.search_modify_param_before - * @var string keywords String of the specified keywords - * @var array sort_by_sql Array of SQL sorting instructions - * @var array ex_fid_ary Array of excluded forum ids - * @var array author_id_ary Array of exclusive author ids - * @var string search_id The id of the search request - * @var array id_ary Array of post or topic ids for search result - * @var string show_results 'posts' or 'topics' type of ids - * @since 3.1.3-RC1 - * @changed 3.1.10-RC1 Added id_ary, show_results - */ - $vars = array( - 'keywords', - 'sort_by_sql', - 'ex_fid_ary', - 'author_id_ary', - 'search_id', - 'id_ary', - 'show_results', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_param_before', compact($vars))); - - // pre-made searches - $sql = $field = $l_search_title = ''; - if ($search_id) - { - switch ($search_id) - { - // Oh holy Bob, bring us some activity... - case 'active_topics': - $l_search_title = $user->lang['SEARCH_ACTIVE_TOPICS']; - $show_results = 'topics'; - $sort_key = 't'; - $sort_dir = 'd'; - $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); - $s_sort_key = $s_sort_dir = ''; - - $last_post_time_sql = ($sort_days) ? ' AND t.topic_last_post_time > ' . (time() - ($sort_days * 24 * 3600)) : ''; - - $sql = 'SELECT t.topic_last_post_time, t.topic_id - FROM ' . TOPICS_TABLE . " t - WHERE t.topic_moved_id = 0 - $last_post_time_sql - AND " . $m_approve_topics_fid_sql . ' - ' . ((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->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'; - $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - $sort_join = ($sort_key == 'f') ? FORUMS_TABLE . ' f, ' : ''; - $sql_sort = ($sort_key == 'f') ? ' AND f.forum_id = p.forum_id ' . $sql_sort : $sql_sort; - - if ($sort_days) - { - $last_post_time = 'AND p.post_time > ' . (time() - ($sort_days * 24 * 3600)); - } - else - { - $last_post_time = ''; - } - - if ($sort_key == 'a') - { - $sort_join = USERS_TABLE . ' u, '; - $sql_sort = ' AND u.user_id = p.poster_id ' . $sql_sort; - } - if ($show_results == 'posts') - { - $sql = "SELECT p.post_id - FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t - WHERE t.topic_posts_approved = 1 - AND p.topic_id = t.topic_id - $last_post_time - AND $m_approve_posts_fid_sql - " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " - $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = 'SELECT DISTINCT ' . $sort_by_sql[$sort_key] . ", p.topic_id - FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t - WHERE t.topic_posts_approved = 1 - AND t.topic_moved_id = 0 - AND p.topic_id = t.topic_id - $last_post_time - AND $m_approve_topics_fid_sql - " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " - $sql_sort"; - $field = 'topic_id'; - } - break; - - case 'unreadposts': - $l_search_title = $user->lang['SEARCH_UNREAD']; - // force sorting - $show_results = 'topics'; - $sort_key = 't'; - $sort_by_sql['t'] = 't.topic_last_post_time'; - $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - $sql_where = 'AND t.topic_moved_id = 0 - AND ' . $m_approve_topics_fid_sql . ' - ' . ((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 = ''; - - $template->assign_var('U_MARK_ALL_READ', ($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()) : ''); - break; - - case 'newposts': - $l_search_title = $user->lang['SEARCH_NEW']; - // force sorting - $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'; - $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - 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 = ''; - - if ($show_results == 'posts') - { - $sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p - WHERE p.post_time > ' . $user->data['user_lastvisit'] . ' - AND ' . $m_approve_posts_fid_sql . ' - ' . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . " - $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = 'SELECT t.topic_id - FROM ' . TOPICS_TABLE . ' t - WHERE t.topic_last_post_time > ' . $user->data['user_lastvisit'] . ' - AND t.topic_moved_id = 0 - AND ' . $m_approve_topics_fid_sql . ' - ' . ((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) - - Creates temporary table, query is far from optimized - - $sql = 'SELECT t.topic_id - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p - WHERE p.post_time > ' . $user->data['user_lastvisit'] . ' - AND t.topic_id = p.topic_id - AND t.topic_moved_id = 0 - AND ' . $m_approve_topics_fid_sql . " - GROUP BY t.topic_id - $sql_sort"; -*/ - $field = 'topic_id'; - } - break; - - case 'egosearch': - $l_search_title = $user->lang['SEARCH_SELF']; - break; - } - } - - /** - * Event to modify data after pre-made searches - * - * @event core.search_modify_param_after - * @var string l_search_title The title of the search page - * @var string search_id Predefined search type name - * @var string show_results Display topics or posts - * @var string sql SQL query corresponding to the pre-made search id - * @since 3.1.7-RC1 - */ - $vars = array( - 'l_search_title', - 'search_id', - 'show_results', - 'sql', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_param_after', compact($vars))); - - // show_results should not change after this - $per_page = ($show_results == 'posts') ? $config['posts_per_page'] : $config['topics_per_page']; - $total_match_count = 0; - - // Set limit for the $total_match_count to reduce server load - $total_matches_limit = 1000; - $found_more_search_matches = false; - - if ($search_id) - { - if ($sql) - { - // Only return up to $total_matches_limit+1 ids (the last one will be removed later) - $result = $db->sql_query_limit($sql, $total_matches_limit + 1); - - while ($row = $db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $db->sql_freeresult($result); - } - else if ($search_id == 'unreadposts') - { - // Only return up to $total_matches_limit+1 ids (the last one will be removed later) - $id_ary = array_keys(get_unread_topics($user->data['user_id'], $sql_where, $sql_sort, $total_matches_limit + 1)); - } - else - { - $search_id = ''; - } - - $total_match_count = count($id_ary); - if ($total_match_count) - { - // Limit the number to $total_matches_limit for pre-made searches - if ($total_match_count > $total_matches_limit) - { - $found_more_search_matches = true; - $total_match_count = $total_matches_limit; - } - - // Make sure $start is set to the last page if it exceeds the amount - $start = $pagination->validate_start($start, $per_page, $total_match_count); - - $id_ary = array_slice($id_ary, $start, $per_page); - } - else - { - // Set $start to 0 if no matches were found - $start = 0; - } - } - - // make sure that some arrays are always in the same order - sort($ex_fid_ary); - sort($author_id_ary); - - if ($search->get_search_query()) - { - $total_match_count = $search->keyword_search($show_results, $search_fields, $search_terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page); - } - 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); - } - - /** - * Event to search otherwise than by keywords or author - * - * @event core.search_backend_search_after - * @var string show_results 'posts' or 'topics' type of ids - * @var string search_fields The data fields to search in - * @var string search_terms Is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @var array sort_by_sql Array of SQL sorting instructions - * @var string sort_key The sort key - * @var string sort_dir The sort direction - * @var int sort_days Limit the age of results - * @var array ex_fid_ary Array of excluded forum ids - * @var string m_approve_posts_fid_sql Specifies which types of posts the user can view in which forums - * @var int topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @var array author_id_ary Array of exclusive author ids - * @var string sql_author_match Specifies the author match, when ANONYMOUS is also a search-match - * @var array id_ary Array of post or topic ids for search result - * @var int start The starting id of the results - * @var int per_page Number of ids each page is supposed to contain - * @var int total_match_count The total number of search matches - * @since 3.1.10-RC1 - */ - $vars = array( - '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', - 'total_match_count', - ); - extract($phpbb_dispatcher->trigger_event('core.search_backend_search_after', compact($vars))); - - $sql_where = ''; - - if (count($id_ary)) - { - $sql_where .= $db->sql_in_set(($show_results == 'posts') ? 'p.post_id' : 't.topic_id', $id_ary); - $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); - } - - if ($show_results == 'posts') - { - include($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - } - else - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } - - $user->add_lang('viewtopic'); - - // Grab icons - $icons = $cache->obtain_icons(); - - // define some vars for urls - // A single wildcard will make the search results look ugly - $hilit = phpbb_clean_search_string(str_replace(array('+', '-', '|', '(', ')', '"'), ' ', $keywords)); - $hilit = str_replace(' ', '|', $hilit); - - $u_hilit = urlencode(htmlspecialchars_decode(str_replace('|', ' ', $hilit))); - $u_show_results = '&sr=' . $show_results; - $u_search_forum = implode('&fid%5B%5D=', $search_forum); - - $u_search = append_sid("{$phpbb_root_path}search.$phpEx", $u_sort_param . $u_show_results); - $u_search .= ($search_id) ? '&search_id=' . $search_id : ''; - $u_search .= ($u_hilit) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; - $u_search .= ($search_terms != 'all') ? '&terms=' . $search_terms : ''; - $u_search .= ($topic_id) ? '&t=' . $topic_id : ''; - $u_search .= ($author) ? '&author=' . urlencode(htmlspecialchars_decode($author)) : ''; - $u_search .= ($author_id) ? '&author_id=' . $author_id : ''; - $u_search .= ($u_search_forum) ? '&fid%5B%5D=' . $u_search_forum : ''; - $u_search .= (!$search_child) ? '&sc=0' : ''; - $u_search .= ($search_fields != 'all') ? '&sf=' . $search_fields : ''; - $u_search .= ($return_chars != 300) ? '&ch=' . $return_chars : ''; - - /** - * Event to add or modify search URL parameters - * - * @event core.search_modify_url_parameters - * @var string u_search Search URL parameters string - * @var string search_id Predefined search type name - * @var string show_results String indicating the show results mode - * @var string sql_where The SQL WHERE string used by search to get topic data - * @var int total_match_count The total number of search matches - * @var array ex_fid_ary Array of excluded forum ids - * @since 3.1.7-RC1 - * @changed 3.1.10-RC1 Added show_results, sql_where, total_match_count - * @changed 3.1.11-RC1 Added ex_fid_ary - */ - $vars = array( - 'u_search', - 'search_id', - 'show_results', - 'sql_where', - 'total_match_count', - 'ex_fid_ary', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_url_parameters', compact($vars))); - - if ($sql_where) - { - if ($show_results == 'posts') - { - // @todo Joining this query to the one below? - $sql = 'SELECT zebra_id, friend, foe - FROM ' . ZEBRA_TABLE . ' - WHERE user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - $zebra = array(); - while ($row = $db->sql_fetchrow($result)) - { - $zebra[($row['friend']) ? 'friend' : 'foe'][] = $row['zebra_id']; - } - $db->sql_freeresult($result); - - $sql_array = array( - 'SELECT' => 'p.*, f.forum_id, f.forum_name, t.*, u.username, u.username_clean, u.user_sig, u.user_sig_bbcode_uid, u.user_colour', - 'FROM' => array( - POSTS_TABLE => 'p', - ), - 'LEFT_JOIN' => array( - array( - 'FROM' => array(TOPICS_TABLE => 't'), - 'ON' => 'p.topic_id = t.topic_id', - ), - array( - 'FROM' => array(FORUMS_TABLE => 'f'), - 'ON' => 'p.forum_id = f.forum_id', - ), - array( - 'FROM' => array(USERS_TABLE => 'u'), - 'ON' => 'p.poster_id = u.user_id', - ), - ), - 'WHERE' => $sql_where, - 'ORDER_BY' => $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'), - ); - - /** - * Event to modify the SQL query before the posts data is retrieved - * - * @event core.search_get_posts_data - * @var array sql_array The SQL array - * @var array zebra Array of zebra data for the current user - * @var int total_match_count The total number of search matches - * @var string keywords String of the specified keywords - * @var array sort_by_sql Array of SQL sorting instructions - * @var string s_sort_dir The sort direction - * @var string s_sort_key The sort key - * @var string s_limit_days Limit the age of results - * @var array ex_fid_ary Array of excluded forum ids - * @var array author_id_ary Array of exclusive author ids - * @var string search_fields The data fields to search in - * @var int search_id The id of the search request - * @var int start The starting id of the results - * @since 3.1.0-b3 - */ - $vars = array( - 'sql_array', - 'zebra', - 'total_match_count', - 'keywords', - 'sort_by_sql', - 's_sort_dir', - 's_sort_key', - 's_limit_days', - 'ex_fid_ary', - 'author_id_ary', - 'search_fields', - 'search_id', - 'start', - ); - extract($phpbb_dispatcher->trigger_event('core.search_get_posts_data', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_array); - } - else - { - $sql_from = TOPICS_TABLE . ' t - LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = t.forum_id) - ' . (($sort_key == 'a') ? ' LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = t.topic_poster) ' : ''); - $sql_select = 't.*, f.forum_id, f.forum_name'; - - if ($user->data['is_registered']) - { - if ($config['load_db_track'] && $author_id !== $user->data['user_id']) - { - $sql_from .= ' LEFT JOIN ' . TOPICS_POSTED_TABLE . ' tp ON (tp.user_id = ' . $user->data['user_id'] . ' - AND t.topic_id = tp.topic_id)'; - $sql_select .= ', tp.topic_posted'; - } - - if ($config['load_db_lastread']) - { - $sql_from .= ' LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.user_id = ' . $user->data['user_id'] . ' - AND t.topic_id = tt.topic_id) - LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . ' - AND ft.forum_id = f.forum_id)'; - $sql_select .= ', tt.mark_time, ft.mark_time as f_mark_time'; - } - } - - if ($config['load_anon_lastread'] || ($user->data['is_registered'] && !$config['load_db_lastread'])) - { - $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); - $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); - } - - $sql_order_by = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); - - /** - * Event to modify the SQL query before the topic data is retrieved - * - * @event core.search_get_topic_data - * @var string sql_select The SQL SELECT string used by search to get topic data - * @var string sql_from The SQL FROM string used by search to get topic data - * @var string sql_where The SQL WHERE string used by search to get topic data - * @var int total_match_count The total number of search matches - * @var array sort_by_sql Array of SQL sorting instructions - * @var string sort_dir The sorting direction - * @var string sort_key The sorting key - * @var string sql_order_by The SQL ORDER BY string used by search to get topic data - * @since 3.1.0-a1 - * @changed 3.1.0-RC5 Added total_match_count - * @changed 3.1.7-RC1 Added sort_by_sql, sort_dir, sort_key, sql_order_by - */ - $vars = array( - 'sql_select', - 'sql_from', - 'sql_where', - 'total_match_count', - 'sort_by_sql', - 'sort_dir', - 'sort_key', - 'sql_order_by', - ); - extract($phpbb_dispatcher->trigger_event('core.search_get_topic_data', compact($vars))); - - $sql = "SELECT $sql_select - FROM $sql_from - WHERE $sql_where - ORDER BY $sql_order_by"; - } - $result = $db->sql_query($sql); - $result_topic_id = 0; - - $rowset = $attachments = $topic_tracking_info = array(); - - if ($show_results == 'topics') - { - $forums = $rowset = $shadow_topic_list = array(); - while ($row = $db->sql_fetchrow($result)) - { - $row['forum_id'] = (int) $row['forum_id']; - $row['topic_id'] = (int) $row['topic_id']; - - if ($row['topic_status'] == ITEM_MOVED) - { - $shadow_topic_list[$row['topic_moved_id']] = $row['topic_id']; - } - - $rowset[$row['topic_id']] = $row; - - if (!isset($forums[$row['forum_id']]) && $user->data['is_registered'] && $config['load_db_lastread']) - { - $forums[$row['forum_id']]['mark_time'] = $row['f_mark_time']; - } - $forums[$row['forum_id']]['topic_list'][] = $row['topic_id']; - $forums[$row['forum_id']]['rowset'][$row['topic_id']] = &$rowset[$row['topic_id']]; - } - $db->sql_freeresult($result); - - // If we have some shadow topics, update the rowset to reflect their topic information - if (count($shadow_topic_list)) - { - $sql = 'SELECT * - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', array_keys($shadow_topic_list)); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $orig_topic_id = $shadow_topic_list[$row['topic_id']]; - - // We want to retain some values - $row = array_merge($row, array( - 'topic_moved_id' => $rowset[$orig_topic_id]['topic_moved_id'], - 'topic_status' => $rowset[$orig_topic_id]['topic_status'], - 'forum_name' => $rowset[$orig_topic_id]['forum_name']) - ); - - $rowset[$orig_topic_id] = $row; - } - $db->sql_freeresult($result); - } - unset($shadow_topic_list); - - foreach ($forums as $forum_id => $forum) - { - if ($user->data['is_registered'] && $config['load_db_lastread']) - { - $topic_tracking_info[$forum_id] = get_topic_tracking($forum_id, $forum['topic_list'], $forum['rowset'], array($forum_id => $forum['mark_time'])); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $topic_tracking_info[$forum_id] = get_complete_topic_tracking($forum_id, $forum['topic_list']); - - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - } - } - unset($forums); - } - else - { - $text_only_message = ''; - $attach_list = array(); - - 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']); - - $text_only_message = $row['post_text']; - // make list items visible as such - if ($row['bbcode_uid']) - { - $text_only_message = str_replace('[*:' . $row['bbcode_uid'] . ']', '⋅ ', $text_only_message); - // no BBCode in text only message - strip_bbcode($text_only_message, $row['bbcode_uid']); - } - - if ($return_chars == -1 || utf8_strlen($text_only_message) < ($return_chars + 3)) - { - $row['display_text_only'] = false; - - // Does this post have an attachment? If so, add it to the list - if ($row['post_attachment'] && $config['allow_attachments']) - { - $attach_list[$row['forum_id']][] = $row['post_id']; - } - } - else - { - $row['post_text'] = $text_only_message; - $row['display_text_only'] = true; - } - - $rowset[] = $row; - } - $db->sql_freeresult($result); - - unset($text_only_message); - - // Pull attachment data - if (count($attach_list)) - { - $use_attach_list = $attach_list; - $attach_list = array(); - - foreach ($use_attach_list as $forum_id => $_list) - { - if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id)) - { - $attach_list = array_merge($attach_list, $_list); - } - } - } - - if (count($attach_list)) - { - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . ' - AND in_message = 0 - ORDER BY filetime DESC, post_msg_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $attachments[$row['post_msg_id']][] = $row; - } - $db->sql_freeresult($result); - } - } - - if ($hilit) - { - // Remove bad highlights - $hilit_array = array_filter(explode('|', $hilit), 'strlen'); - foreach ($hilit_array as $key => $value) - { - $hilit_array[$key] = phpbb_clean_search_string($value); - $hilit_array[$key] = str_replace('\*', '\w*?', preg_quote($hilit_array[$key], '#')); - $hilit_array[$key] = preg_replace('#(^|\s)\\\\w\*\?(\s|$)#', '$1\w+?$2', $hilit_array[$key]); - } - $hilit = implode('|', $hilit_array); - } - - /** - * Modify the rowset data - * - * @event core.search_modify_rowset - * @var array attachments Array with posts attachments data - * @var string hilit String to highlight - * @var array rowset Array with the search results data - * @var string show_results String indicating the show results mode - * @var array topic_tracking_info Array with the topics tracking 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.1.0-b4 - * @changed 3.1.0-b5 Added var show_results - */ - $vars = array( - 'attachments', - 'hilit', - 'rowset', - 'show_results', - 'topic_tracking_info', - 'u_hilit', - 'view', - 'zebra', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_rowset', compact($vars))); - - foreach ($rowset as $row) - { - $forum_id = $row['forum_id']; - $result_topic_id = $row['topic_id']; - $topic_title = censor_text($row['topic_title']); - $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1; - - $view_topic_url_params = "f=$forum_id&t=$result_topic_id" . (($u_hilit) ? "&hilit=$u_hilit" : ''); - $view_topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params); - - if ($show_results == 'topics') - { - if ($config['load_db_track'] && $author_id === $user->data['user_id']) - { - $row['topic_posted'] = 1; - } - - $folder_img = $folder_alt = $topic_type = ''; - topic_status($row, $replies, (isset($topic_tracking_info[$forum_id][$row['topic_id']]) && $row['topic_last_post_time'] > $topic_tracking_info[$forum_id][$row['topic_id']]) ? true : false, $folder_img, $folder_alt, $topic_type); - - $unread_topic = (isset($topic_tracking_info[$forum_id][$row['topic_id']]) && $row['topic_last_post_time'] > $topic_tracking_info[$forum_id][$row['topic_id']]) ? true : false; - - $topic_unapproved = (($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $forum_id)) ? true : false; - $posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $forum_id)) ? true : false; - $topic_deleted = $row['topic_visibility'] == ITEM_DELETED; - $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . "&t=$result_topic_id", true, $user->session_id) : ''; - $u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&mode=deleted_topics&t=$result_topic_id", true, $user->session_id) : $u_mcp_queue; - - $row['topic_title'] = preg_replace('#(?!<.*)(?]*(?:)#isu', '$1', $row['topic_title']); - - $tpl_ary = array( - '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']), - 'FIRST_POST_TIME' => $user->format_date($row['topic_time']), - 'LAST_POST_SUBJECT' => $row['topic_last_post_subject'], - 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), - 'LAST_VIEW_TIME' => $user->format_date($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']), - - 'TOPIC_TYPE' => $topic_type, - - 'TOPIC_IMG_STYLE' => $folder_img, - 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'TOPIC_FOLDER_IMG_ALT' => $user->lang[$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'] : '', - 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', - 'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '', - - 'S_TOPIC_TYPE' => $row['topic_type'], - 'S_USER_POSTED' => (!empty($row['topic_posted'])) ? true : false, - 'S_UNREAD_TOPIC' => $unread_topic, - - 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_get('m_report', $forum_id)) ? true : false, - 'S_TOPIC_UNAPPROVED' => $topic_unapproved, - 'S_POSTS_UNAPPROVED' => $posts_unapproved, - 'S_TOPIC_DELETED' => $topic_deleted, - 'S_HAS_POLL' => ($row['poll_start']) ? true : false, - - 'U_LAST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&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_TOPIC_AUTHOR' => get_username_string('profile', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), - 'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&view=unread') . '#unread', - 'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=reports&t=' . $result_topic_id, true, $user->session_id), - 'U_MCP_QUEUE' => $u_mcp_queue, - ); - } - else - { - if ((isset($zebra['foe']) && in_array($row['poster_id'], $zebra['foe'])) && (!$view || $view != 'show' || $post_id != $row['post_id'])) - { - $template->assign_block_vars('searchresults', array( - 'S_IGNORE_POST' => true, - - 'L_IGNORE_POST' => sprintf($user->lang['POST_BY_FOE'], $row['username'], "', '')) - ); - - continue; - } - - // Replace naughty words such as farty pants - $row['post_subject'] = censor_text($row['post_subject']); - - if ($row['display_text_only']) - { - // now find context for the searched words - $row['post_text'] = get_context($row['post_text'], array_filter(explode('|', $hilit), 'strlen'), $return_chars); - $row['post_text'] = bbcode_nl2br($row['post_text']); - } - else - { - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - $row['post_text'] = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); - - if (!empty($attachments[$row['post_id']])) - { - parse_attachments($forum_id, $row['post_text'], $attachments[$row['post_id']], $update_count); - - // we only display inline attachments - unset($attachments[$row['post_id']]); - } - } - - if ($hilit) - { - // post highlighting - $row['post_text'] = preg_replace('#(?!<.*)(?]*(?:)#isu', '$1', $row['post_text']); - $row['post_subject'] = preg_replace('#(?!<.*)(?]*(?:)#isu', '$1', $row['post_subject']); - } - - $tpl_ary = array( - 'POST_AUTHOR_FULL' => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), - - 'POST_SUBJECT' => $row['post_subject'], - 'POST_DATE' => (!empty($row['post_time'])) ? $user->format_date($row['post_time']) : '', - 'MESSAGE' => $row['post_text'] - ); - } - - $tpl_ary = array_merge($tpl_ary, array( - 'FORUM_ID' => $forum_id, - 'TOPIC_ID' => $result_topic_id, - 'POST_ID' => ($show_results == 'posts') ? $row['post_id'] : false, - - 'FORUM_TITLE' => $row['forum_name'], - 'TOPIC_TITLE' => $topic_title, - 'TOPIC_REPLIES' => $replies, - 'TOPIC_VIEWS' => $row['topic_views'], - - 'U_VIEW_TOPIC' => $view_topic_url, - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id), - 'U_VIEW_POST' => (!empty($row['post_id'])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=" . $row['topic_id'] . '&p=' . $row['post_id'] . (($u_hilit) ? '&hilit=' . $u_hilit : '')) . '#p' . $row['post_id'] : '', - )); - - /** - * Modify the topic data before it is assigned to the template - * - * @event core.search_modify_tpl_ary - * @var array row Array with topic data - * @var array tpl_ary Template block array with topic data - * @var string show_results Display topics or posts - * @var string topic_title Cleaned topic title - * @var int replies The number of topic replies - * @var string view_topic_url The URL to the topic - * @var string folder_img The folder image of the topic - * @var string folder_alt The alt attribute of the topic folder img - * @var int topic_type The topic type - * @var bool unread_topic Whether the topic has unread posts - * @var bool topic_unapproved Whether the topic is unapproved - * @var int posts_unapproved The number of unapproved posts - * @var bool topic_deleted Whether the topic has been deleted - * @var string u_mcp_queue The URL to the corresponding MCP queue page - * @var array zebra The zebra data of the current user - * @var array attachments All the attachments of the search results - * @since 3.1.0-a1 - * @changed 3.1.0-b3 Added vars show_results, topic_title, replies, - * view_topic_url, folder_img, folder_alt, topic_type, unread_topic, - * topic_unapproved, posts_unapproved, topic_deleted, u_mcp_queue, - * zebra, attachments - */ - $vars = array( - 'row', - 'tpl_ary', - 'show_results', - 'topic_title', - 'replies', - 'view_topic_url', - 'folder_img', - 'folder_alt', - 'topic_type', - 'unread_topic', - 'topic_unapproved', - 'posts_unapproved', - 'topic_deleted', - 'u_mcp_queue', - 'zebra', - 'attachments', - ); - extract($phpbb_dispatcher->trigger_event('core.search_modify_tpl_ary', compact($vars))); - - $template->assign_block_vars('searchresults', $tpl_ary); - - if ($show_results == 'topics') - { - $pagination->generate_template_pagination($view_topic_url, 'searchresults.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true); - } - } - - if ($topic_id && ($topic_id == $result_topic_id)) - { - $template->assign_vars(array( - 'SEARCH_TOPIC' => $topic_title, - 'L_RETURN_TO_TOPIC' => $user->lang('RETURN_TO', $topic_title), - 'U_SEARCH_TOPIC' => $view_topic_url - )); - } - } - unset($rowset); - - // Output header - if ($found_more_search_matches) - { - $l_search_matches = $user->lang('FOUND_MORE_SEARCH_MATCHES', (int) $total_match_count); - } - else - { - $l_search_matches = $user->lang('FOUND_SEARCH_MATCHES', (int) $total_match_count); - } - - // Check if search backend supports phrase search or not - $phrase_search_disabled = ''; - if (strpos(html_entity_decode($keywords), '"') !== false && method_exists($search, 'supports_phrase_search')) - { - $phrase_search_disabled = $search->supports_phrase_search() ? false : true; - } - - $pagination->generate_template_pagination($u_search, 'pagination', 'start', $total_match_count, $per_page, $start); - - $template->assign_vars(array( - 'SEARCH_TITLE' => $l_search_title, - 'SEARCH_MATCHES' => $l_search_matches, - 'SEARCH_WORDS' => $keywords, - 'SEARCHED_QUERY' => $search->get_search_query(), - 'IGNORED_WORDS' => (!empty($common_words)) ? implode(' ', $common_words) : '', - - 'PHRASE_SEARCH_DISABLED' => $phrase_search_disabled, - - 'TOTAL_MATCHES' => $total_match_count, - 'SEARCH_IN_RESULTS' => ($search_id) ? false : true, - - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_SEARCH_ACTION' => $u_search, - 'S_SHOW_TOPICS' => ($show_results == 'posts') ? false : true, - - 'GOTO_PAGE_IMG' => $user->img('icon_post_target', 'GOTO_PAGE'), - 'NEWEST_POST_IMG' => $user->img('icon_topic_newest', 'VIEW_NEWEST_POST'), - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'TOPIC_REPORTED'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPIC_UNAPPROVED'), - 'DELETED_IMG' => $user->img('icon_topic_deleted', 'TOPIC_DELETED'), - 'POLL_IMG' => $user->img('icon_topic_poll', 'TOPIC_POLL'), - 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), - - 'U_SEARCH_WORDS' => $u_search, - )); - - /** - * Modify the title and/or load data for the search results page - * - * @event core.search_results_modify_search_title - * @var int author_id ID of the author to search by - * @var string l_search_title The title of the search page - * @var string search_id Predefined search type name - * @var string show_results Search results output mode - topics or posts - * @var int start The starting id of the results - * @var int total_match_count The count of search results - * @var string keywords The search keywords - * @since 3.1.0-RC4 - * @changed 3.1.6-RC1 Added total_match_count and keywords - */ - $vars = array( - 'author_id', - 'l_search_title', - 'search_id', - 'show_results', - 'start', - 'total_match_count', - 'keywords', - ); - extract($phpbb_dispatcher->trigger_event('core.search_results_modify_search_title', compact($vars))); - - page_header(($l_search_title) ? $l_search_title : $user->lang['SEARCH']); - - $template->set_filenames(array( - 'body' => 'search_results.html') - ); - make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - - page_footer(); -} - -// Search forum -$rowset = array(); -$s_forums = ''; -$sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f.right_id, f.forum_password, f.enable_indexing, fa.user_id - FROM ' . FORUMS_TABLE . ' f - LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id - AND fa.session_id = '" . $db->sql_escape($user->session_id) . "') - ORDER BY f.left_id ASC"; -$result = $db->sql_query($sql); - -while ($row = $db->sql_fetchrow($result)) -{ - $rowset[(int) $row['forum_id']] = $row; -} -$db->sql_freeresult($result); - -$right = $cat_right = $padding_inc = 0; -$padding = $forum_list = $holding = ''; -$pad_store = array('0' => ''); - -/** -* Modify the forum select list for advanced search page -* -* @event core.search_modify_forum_select_list -* @var array rowset Array with the forums list data -* @since 3.1.10-RC1 -*/ -$vars = array('rowset'); -extract($phpbb_dispatcher->trigger_event('core.search_modify_forum_select_list', compact($vars))); - -foreach ($rowset as $row) -{ - if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id'])) - { - // Non-postable forum with no subforums, don't display - continue; - } - - if ($row['forum_type'] == FORUM_POST && ($row['left_id'] + 1 == $row['right_id']) && !$row['enable_indexing']) - { - // Postable forum with no subforums and indexing disabled, don't display - continue; - } - - if ($row['forum_type'] == FORUM_LINK || ($row['forum_password'] && !$row['user_id'])) - { - // if this forum is a link or password protected (user has not entered the password yet) then skip to the next branch - continue; - } - - if ($row['left_id'] < $right) - { - $padding .= '   '; - $pad_store[$row['parent_id']] = $padding; - } - else if ($row['left_id'] > $right + 1) - { - if (isset($pad_store[$row['parent_id']])) - { - $padding = $pad_store[$row['parent_id']]; - } - else - { - continue; - } - } - - $right = $row['right_id']; - - if ($auth->acl_gets('!f_search', '!f_list', $row['forum_id'])) - { - // if the user does not have permissions to search or see this forum skip only this forum/category - continue; - } - - $selected = (in_array($row['forum_id'], $search_forum)) ? ' selected="selected"' : ''; - - if ($row['left_id'] > $cat_right) - { - // make sure we don't forget anything - $s_forums .= $holding; - $holding = ''; - } - - if ($row['right_id'] - $row['left_id'] > 1) - { - $cat_right = max($cat_right, $row['right_id']); - - $holding .= ''; - } - else - { - $s_forums .= $holding . ''; - $holding = ''; - } -} - -if ($holding) -{ - $s_forums .= $holding; -} - -unset($pad_store); -unset($rowset); - -if (!$s_forums) -{ - trigger_error('NO_SEARCH'); -} - -// Number of chars returned -$s_characters = ''; -$s_characters .= ''; -$s_characters .= ''; -$s_characters .= ''; - -for ($i = 100; $i <= 1000; $i += 100) -{ - $selected = ($i == 300) ? ' selected="selected"' : ''; - $s_characters .= ''; -} - -$s_hidden_fields = array('t' => $topic_id); - -if ($_SID) -{ - $s_hidden_fields['sid'] = $_SID; -} - -if (!empty($_EXTRA_URL)) -{ - foreach ($_EXTRA_URL as $url_param) - { - $url_param = explode('=', $url_param, 2); - $s_hidden_fields[$url_param[0]] = $url_param[1]; - } -} - -$template->assign_vars(array( - 'S_SEARCH_ACTION' => append_sid("{$phpbb_root_path}search.$phpEx", false, true, 0), // We force no ?sid= appending by using 0 - 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - 'S_CHARACTER_OPTIONS' => $s_characters, - 'S_FORUM_OPTIONS' => $s_forums, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'S_IN_SEARCH' => true, -)); - -// only show recent searches to search administrators -if ($auth->acl_get('a_search')) -{ - // Handle large objects differently for Oracle and MSSQL - switch ($db->get_sql_layer()) - { - case 'oracle': - $sql = 'SELECT search_time, search_keywords - FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE dbms_lob.getlength(search_keywords) > 0 - ORDER BY search_time DESC'; - break; - - case 'mssql_odbc': - case 'mssqlnative': - $sql = 'SELECT search_time, search_keywords - FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE DATALENGTH(search_keywords) > 0 - ORDER BY search_time DESC'; - break; - - default: - $sql = 'SELECT search_time, search_keywords - FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE search_keywords <> \'\' - ORDER BY search_time DESC'; - break; - } - $result = $db->sql_query_limit($sql, 5); - - while ($row = $db->sql_fetchrow($result)) - { - $keywords = $row['search_keywords']; - - $template->assign_block_vars('recentsearch', array( - 'KEYWORDS' => $keywords, - 'TIME' => $user->format_date($row['search_time']), - - 'U_KEYWORDS' => append_sid("{$phpbb_root_path}search.$phpEx", 'keywords=' . urlencode(htmlspecialchars_decode($keywords))) - )); - } - $db->sql_freeresult($result); -} - -// Output the basic page -page_header($user->lang['SEARCH']); - -$template->set_filenames(array( - 'body' => 'search_body.html') -); -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - -page_footer(); diff --git a/install/update/old/styles/prosilver/style.cfg b/install/update/old/styles/prosilver/style.cfg deleted file mode 100644 index 4485b17..0000000 --- a/install/update/old/styles/prosilver/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 -# @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 = prosilver -copyright = © phpBB Limited, 2007 -style_version = 3.2.7 -phpbb_version = 3.2.7 - -# Defining a different template bitfield -# template_bitfield = //g= - -# Parent style -# Set value to empty or to this style's name if this style does not have a parent style -parent = prosilver diff --git a/install/update/old/styles/prosilver/template/attachment.html b/install/update/old/styles/prosilver/template/attachment.html deleted file mode 100644 index 0978d91..0000000 --- a/install/update/old/styles/prosilver/template/attachment.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - -

[{_file.DENIED_MESSAGE}]

- - - - -
-
{_file.DOWNLOAD_NAME}
-
{_file.COMMENT}
-
- - - -
-
{_file.DOWNLOAD_NAME}
-
{_file.COMMENT}
-
{_file.DOWNLOAD_NAME} ({_file.FILESIZE} {_file.SIZE_LANG}) {_file.L_DOWNLOAD_COUNT}
-
- - - -
-
{_file.UPLOAD_ICON} {_file.DOWNLOAD_NAME}
-
{_file.COMMENT}
-
({_file.FILESIZE} {_file.SIZE_LANG}) {_file.L_DOWNLOAD_COUNT}
-
- - - - - - - - - - - - -

{_file.DOWNLOAD_NAME} [ {_file.FILESIZE} {_file.SIZE_LANG} | {_file.L_DOWNLOAD_COUNT} ]

- - - - - - diff --git a/install/update/old/styles/prosilver/template/bbcode.html b/install/update/old/styles/prosilver/template/bbcode.html deleted file mode 100644 index 940c0ac..0000000 --- a/install/update/old/styles/prosilver/template/bbcode.html +++ /dev/null @@ -1,75 +0,0 @@ -
    -
      -
    - -
      -
    - -
  • -
  • - -
    {USERNAME} {L_WROTE}{L_COLON} -
    -
    - -
    - - uncited - -
    - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    -
    - -
    -
    - - -

    {L_CODE}{L_COLON} {L_SELECT_ALL_CODE}

    
    -
    - -
    -
    - - - - - - - - - - -{TEXT} - -{TEXT} - -{L_IMAGE} - -{DESCRIPTION} - -{DESCRIPTION} - - diff --git a/install/update/old/styles/prosilver/template/captcha_recaptcha.html b/install/update/old/styles/prosilver/template/captcha_recaptcha.html deleted file mode 100644 index a123f54..0000000 --- a/install/update/old/styles/prosilver/template/captcha_recaptcha.html +++ /dev/null @@ -1,30 +0,0 @@ - -
    -
    - -

    {L_CONFIRMATION}

    -

    {L_CONFIRM_EXPLAIN}

    - -
    - - - -
    -

    {L_RECAPTCHA_EXPLAIN}
    -
    - - -
    -
    -
    - -{L_RECAPTCHA_NOT_AVAILABLE} - - - -
    -
    -
    - diff --git a/install/update/old/styles/prosilver/template/forum_fn.js b/install/update/old/styles/prosilver/template/forum_fn.js deleted file mode 100644 index 3f28f8a..0000000 --- a/install/update/old/styles/prosilver/template/forum_fn.js +++ /dev/null @@ -1,937 +0,0 @@ -/* global phpbb */ - -/** -* phpBB3 forum functions -*/ - -/** -* Find a member -*/ -function find_username(url) { - 'use strict'; - - popup(url, 760, 570, '_usersearch'); - return false; -} - -/** -* Window popup -*/ -function popup(url, width, height, name) { - 'use strict'; - - if (!name) { - name = '_popup'; - } - - window.open(url.replace(/&/g, '&'), name, 'height=' + height + ',resizable=yes,scrollbars=yes, width=' + width); - return false; -} - -/** -* Jump to page -*/ -function pageJump(item) { - 'use strict'; - - var page = parseInt(item.val(), 10), - perPage = item.attr('data-per-page'), - baseUrl = item.attr('data-base-url'), - startName = item.attr('data-start-name'); - - if (page !== null && !isNaN(page) && page === Math.floor(page) && page > 0) { - if (baseUrl.indexOf('?') === -1) { - document.location.href = baseUrl + '?' + startName + '=' + ((page - 1) * perPage); - } else { - document.location.href = baseUrl.replace(/&/g, '&') + '&' + startName + '=' + ((page - 1) * perPage); - } - } -} - -/** -* Mark/unmark checklist -* id = ID of parent container, name = name prefix, state = state [true/false] -*/ -function marklist(id, name, state) { - 'use strict'; - - jQuery('#' + id + ' input[type=checkbox][name]').each(function() { - var $this = jQuery(this); - if ($this.attr('name').substr(0, name.length) === name && !$this.prop('disabled')) { - $this.prop('checked', state); - } - }); -} - -/** -* Resize viewable area for attached image or topic review panel (possibly others to come) -* e = element -*/ -function viewableArea(e, itself) { - 'use strict'; - - if (!e) { - return; - } - - if (!itself) { - e = e.parentNode; - } - - if (!e.vaHeight) { - // Store viewable area height before changing style to auto - e.vaHeight = e.offsetHeight; - e.vaMaxHeight = e.style.maxHeight; - e.style.height = 'auto'; - e.style.maxHeight = 'none'; - e.style.overflow = 'visible'; - } else { - // Restore viewable area height to the default - e.style.height = e.vaHeight + 'px'; - e.style.overflow = 'auto'; - e.style.maxHeight = e.vaMaxHeight; - e.vaHeight = false; - } -} - -/** -* Alternate display of subPanels -*/ -jQuery(function($) { - 'use strict'; - - $('.sub-panels').each(function() { - - var $childNodes = $('a[data-subpanel]', this), - panels = $childNodes.map(function () { - return this.getAttribute('data-subpanel'); - }), - showPanel = this.getAttribute('data-show-panel'); - - if (panels.length) { - activateSubPanel(showPanel, panels); - $childNodes.click(function () { - activateSubPanel(this.getAttribute('data-subpanel'), panels); - return false; - }); - } - }); -}); - -/** -* Activate specific subPanel -*/ -function activateSubPanel(p, panels) { - 'use strict'; - - var i, showPanel; - - if (typeof p === 'string') { - showPanel = p; - } - $('input[name="show_panel"]').val(showPanel); - - if (typeof panels === 'undefined') { - panels = jQuery('.sub-panels a[data-subpanel]').map(function() { - return this.getAttribute('data-subpanel'); - }); - } - - for (i = 0; i < panels.length; i++) { - jQuery('#' + panels[i]).css('display', panels[i] === showPanel ? 'block' : 'none'); - jQuery('#' + panels[i] + '-tab').toggleClass('activetab', panels[i] === showPanel); - } -} - -function selectCode(a) { - 'use strict'; - - // Get ID of code block - var e = a.parentNode.parentNode.getElementsByTagName('CODE')[0]; - var s, r; - - // Not IE and IE9+ - if (window.getSelection) { - s = window.getSelection(); - // Safari and Chrome - if (s.setBaseAndExtent) { - var l = (e.innerText.length > 1) ? e.innerText.length - 1 : 1; - try { - s.setBaseAndExtent(e, 0, e, l); - } catch (error) { - r = document.createRange(); - r.selectNodeContents(e); - s.removeAllRanges(); - s.addRange(r); - } - } - // Firefox and Opera - else { - // workaround for bug # 42885 - if (window.opera && e.innerHTML.substring(e.innerHTML.length - 4) === '
    ') { - e.innerHTML = e.innerHTML + ' '; - } - - r = document.createRange(); - r.selectNodeContents(e); - s.removeAllRanges(); - s.addRange(r); - } - } - // Some older browsers - else if (document.getSelection) { - s = document.getSelection(); - r = document.createRange(); - r.selectNodeContents(e); - s.removeAllRanges(); - s.addRange(r); - } - // IE - else if (document.selection) { - r = document.body.createTextRange(); - r.moveToElementText(e); - r.select(); - } -} - -var inAutocomplete = false; -var lastKeyEntered = ''; - -/** -* Check event key -*/ -function phpbbCheckKey(event) { - 'use strict'; - - // Keycode is array down or up? - if (event.keyCode && (event.keyCode === 40 || event.keyCode === 38)) { - inAutocomplete = true; - } - - // Make sure we are not within an "autocompletion" field - if (inAutocomplete) { - // If return pressed and key changed we reset the autocompletion - if (!lastKeyEntered || lastKeyEntered === event.which) { - inAutocomplete = false; - return true; - } - } - - // Keycode is not return, then return. ;) - if (event.which !== 13) { - lastKeyEntered = event.which; - return true; - } - - return false; -} - -/** -* Apply onkeypress event for forcing default submit button on ENTER key press -*/ -jQuery(function($) { - 'use strict'; - - $('form input[type=text], form input[type=password]').on('keypress', function (e) { - var defaultButton = $(this).parents('form').find('input[type=submit].default-submit-action'); - - if (!defaultButton || defaultButton.length <= 0) { - return true; - } - - if (phpbbCheckKey(e)) { - return true; - } - - if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) { - defaultButton.click(); - return false; - } - - return true; - }); -}); - -/** -* Functions for user search popup -*/ -function insertUser(formId, value) { - 'use strict'; - - var $form = jQuery(formId), - formName = $form.attr('data-form-name'), - fieldName = $form.attr('data-field-name'), - item = opener.document.forms[formName][fieldName]; - - if (item.value.length && item.type === 'textarea') { - value = item.value + '\n' + value; - } - - item.value = value; -} - -function insert_marked_users(formId, users) { - 'use strict'; - - $(users).filter(':checked').each(function() { - insertUser(formId, this.value); - }); - - window.close(); -} - -function insert_single_user(formId, user) { - 'use strict'; - - insertUser(formId, user); - window.close(); -} - -/** -* Parse document block -*/ -function parseDocument($container) { - 'use strict'; - - var test = document.createElement('div'), - oldBrowser = (typeof test.style.borderRadius === 'undefined'), - $body = $('body'); - - /** - * Reset avatar dimensions when changing URL or EMAIL - */ - $container.find('input[data-reset-on-edit]').on('keyup', function() { - $(this.getAttribute('data-reset-on-edit')).val(''); - }); - - /** - * Pagination - */ - $container.find('.pagination .page-jump-form :button').click(function() { - var $input = $(this).siblings('input.inputbox'); - pageJump($input); - }); - - $container.find('.pagination .page-jump-form input.inputbox').on('keypress', function(event) { - if (event.which === 13 || event.keyCode === 13) { - event.preventDefault(); - pageJump($(this)); - } - }); - - $container.find('.pagination .dropdown-trigger').click(function() { - var $dropdownContainer = $(this).parent(); - // Wait a little bit to make sure the dropdown has activated - setTimeout(function() { - if ($dropdownContainer.hasClass('dropdown-visible')) { - $dropdownContainer.find('input.inputbox').focus(); - } - }, 100); - }); - - /** - * 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'); - // } - - /** - * Resize navigation (breadcrumbs) block to keep all links on same line - */ - $container.find('.navlinks').each(function() { - var $this = $(this), - $left = $this.children().not('.rightside'), - $right = $this.children('.rightside'); - - if ($left.length !== 1 || !$right.length) { - return; - } - - function resize() { - var width = 0, - diff = $left.outerWidth(true) - $left.width(), - minWidth = Math.max($this.width() / 3, 240), - maxWidth; - - $right.each(function() { - var $this = $(this); - if ($this.is(':visible')) { - width += $this.outerWidth(true); - } - }); - - maxWidth = $this.width() - width - diff; - $left.css('max-width', Math.floor(Math.max(maxWidth, minWidth)) + 'px'); - } - - resize(); - $(window).resize(resize); - }); - - /** - * Makes breadcrumbs responsive - */ - $container.find('.breadcrumbs:not([data-skip-responsive])').each(function() { - var $this = $(this), - $links = $this.find('.crumb'), - length = $links.length, - classes = ['wrapped-max', 'wrapped-wide', 'wrapped-medium', 'wrapped-small', 'wrapped-tiny'], - classesLength = classes.length, - maxHeight = 0, - lastWidth = false, - wrapped = false; - - // Set tooltips - $this.find('a').each(function() { - var $link = $(this); - $link.attr('title', $link.text()); - }); - - // Function that checks breadcrumbs - function check() { - var height = $this.height(), - width; - - // Test max-width set in code for .navlinks above - width = parseInt($this.css('max-width'), 10); - if (!width) { - width = $body.width(); - } - - maxHeight = parseInt($this.css('line-height'), 10); - $links.each(function() { - if ($(this).height() > 0) { - maxHeight = Math.max(maxHeight, $(this).outerHeight(true)); - } - }); - - if (height <= maxHeight) { - if (!wrapped || lastWidth === false || lastWidth >= width) { - return; - } - } - lastWidth = width; - - if (wrapped) { - $this.removeClass('wrapped').find('.crumb.wrapped').removeClass('wrapped ' + classes.join(' ')); - if ($this.height() <= maxHeight) { - return; - } - } - - wrapped = true; - $this.addClass('wrapped'); - if ($this.height() <= maxHeight) { - return; - } - - for (var i = 0; i < classesLength; i++) { - for (var j = length - 1; j >= 0; j--) { - $links.eq(j).addClass('wrapped ' + classes[i]); - if ($this.height() <= maxHeight) { - return; - } - } - } - } - - // Run function and set event - check(); - $(window).resize(check); - }); - - /** - * Responsive link lists - */ - var selector = '.linklist:not(.navlinks, [data-skip-responsive]),' + - '.postbody .post-buttons:not([data-skip-responsive])'; - $container.find(selector).each(function() { - var $this = $(this), - filterSkip = '.breadcrumbs, [data-skip-responsive]', - filterLast = '.edit-icon, .quote-icon, [data-last-responsive]', - $linksAll = $this.children(), - $linksNotSkip = $linksAll.not(filterSkip), // All items that can potentially be hidden - $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 = '', - 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) - if (!persistent) { - if ($linksNotSkip.is('.rightside')) { - $linksNotSkip.filter('.rightside:first').before(html); - $this.children('.responsive-menu').addClass('rightside'); - } else { - $this.append(html); - } - } - - // Set some object references and initial states - var $menu = $this.children('.responsive-menu'), - $menuContents = $menu.find('.dropdown-contents'), - persistentContent = $menuContents.find('li:not(.separator)').length, - lastWidth = false, - compact = false, - responsive1 = false, - responsive2 = false, - copied1 = false, - copied2 = false, - maxHeight = 0; - - // Find the tallest element in the list (we assume that all elements are roughly the same height) - $linksAll.each(function() { - if (!$(this).height()) { - return; - } - maxHeight = Math.max(maxHeight, $(this).outerHeight(true)); - }); - if (maxHeight < 1) { - return; // Shouldn't be possible, but just in case, abort - } else { - maxHeight = maxHeight + slack; - } - - function check() { - var width = $body.width(); - // We can't make it any smaller than this, so just skip - if (responsive2 && compact && (width <= lastWidth)) { - return; - } - lastWidth = width; - - // Reset responsive and compact layout - if (responsive1 || responsive2) { - $linksNotSkip.removeClass('hidden'); - $menuContents.children('.clone').addClass('hidden'); - responsive1 = responsive2 = false; - } - if (compact) { - $this.removeClass('compact'); - compact = false; - } - - // Unhide the quick-links menu if it has "persistent" content - if (persistent && persistentContent) { - $menu.removeClass('hidden'); - } else { - $menu.addClass('hidden'); - } - - // Nothing to resize if block's height is not bigger than tallest element's height - if ($this.height() <= maxHeight) { - return; - } - - // STEP 1: Compact - if (!compact) { - $this.addClass('compact'); - compact = true; - } - if ($this.height() <= maxHeight) { - return; - } - - // STEP 2: First responsive set - compact - if (compact) { - $this.removeClass('compact'); - compact = false; - } - // Copy the list items to the dropdown - if (!copied1) { - var $clones1 = $linksFirst.clone(); - $menuContents.prepend($clones1.addClass('clone clone-first').removeClass('leftside rightside')); - - if ($this.hasClass('post-buttons')) { - $('.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; - } - if (!responsive1) { - $linksFirst.addClass('hidden'); - responsive1 = true; - $menuContents.children('.clone-first').removeClass('hidden'); - $menu.removeClass('hidden'); - } - if ($this.height() <= maxHeight) { - return; - } - - // STEP 3: First responsive set + compact - if (!compact) { - $this.addClass('compact'); - compact = true; - } - if ($this.height() <= maxHeight) { - return; - } - - // STEP 4: Last responsive set - compact - if (!$linksLast.length) { - return; // No other links to hide, can't do more - } - if (compact) { - $this.removeClass('compact'); - compact = false; - } - // Copy the list items to the dropdown - if (!copied2) { - var $clones2 = $linksLast.clone(); - $menuContents.prepend($clones2.addClass('clone clone-last').removeClass('leftside rightside')); - copied2 = true; - } - if (!responsive2) { - $linksLast.addClass('hidden'); - responsive2 = true; - $menuContents.children('.clone-last').removeClass('hidden'); - } - if ($this.height() <= maxHeight) { - return; - } - - // STEP 5: Last responsive set + compact - if (!compact) { - $this.addClass('compact'); - compact = true; - } - } - - if (!persistent) { - 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).on('load', function() { - check(); - }); - }); - - check(); - $(window).resize(check); - }); - - /** - * Do not run functions below for old browsers - */ - if (oldBrowser) { - return; - } - - /** - * Adjust topiclist lists with check boxes - */ - $container.find('ul.topiclist dd.mark').siblings('dt').children('.list-inner').addClass('with-mark'); - - /** - * Appends contents of all extra columns to first column in - * .topiclist lists for mobile devices. Copies contents as is. - * - * To add that functionality to .topiclist list simply add - * responsive-show-all to list of classes - */ - $container.find('.topiclist.responsive-show-all > li > dl').each(function() { - var $this = $(this), - $block = $this.find('dt .responsive-show:last-child'), - first = true; - - // Create block that is visible only on mobile devices - if (!$block.length) { - $this.find('dt > .list-inner').append('
- -
-
- - - - -
-
- -
    - - - - - -
  • - -
    -
    - -
    - - - - - - {forumrow.FORUM_IMAGE} - - - {forumrow.FORUM_NAME} -
    {forumrow.FORUM_DESC} - -
    {forumrow.L_MODERATOR_STR}{L_COLON} {forumrow.MODERATORS} - - - -
    {forumrow.L_SUBFORUM_STR}{L_COLON} - - - {forumrow.subforum.SUBFORUM_NAME}{L_COMMA_SEPARATOR} - - - - - - - -
    -
    - -
    {L_REDIRECTS}{L_COLON} {forumrow.CLICKS}
    - -
    {forumrow.TOPICS} {L_TOPICS}
    -
    {forumrow.POSTS} {L_POSTS}
    -
    - - - - {L_TOPICS_UNAPPROVED} - - - - {L_POSTS_UNAPPROVED_FORUM} - - - - {L_LAST_POST} - - - {forumrow.LAST_POST_SUBJECT_TRUNCATED}
    - - {L_POST_BY_AUTHOR} {forumrow.LAST_POSTER_FULL} - - - {L_VIEW_LATEST_POST} - - -
    {forumrow.LAST_POST_TIME} - - {% if forumrow.U_UNAPPROVED_TOPICS %} - {{ lang('TOPIC_UNAPPROVED_FORUM', forumrow.TOPICS) }} - {% else %} - {{ lang('NO_POSTS') }} - {% endif %} - -
    -
    - -
     
    - -
    - -
  • - - - - -
- -
-
- - - - -
-
- {L_NO_FORUMS} -
-
- diff --git a/install/update/old/styles/prosilver/template/mcp_forum.html b/install/update/old/styles/prosilver/template/mcp_forum.html deleted file mode 100644 index f6c518e..0000000 --- a/install/update/old/styles/prosilver/template/mcp_forum.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - -

{L_FORUM}{L_COLON} {FORUM_NAME}

- -
- -
-
- -
- -
- - -
    -
  • -
    -
    {L_TOPICS}
    -
    {L_REPLIES}
    -
    {L_LAST_POST}
    -
    {L_MARK}
    -
    -
  • -
- - -
    -
  • {L_NO_TOPICS}

  • -
- - -
- - - -
- -
-
- - -
- - - - - - {S_FORM_TOKEN} -
- -
- - diff --git a/install/update/old/styles/prosilver/template/mcp_move.html b/install/update/old/styles/prosilver/template/mcp_move.html deleted file mode 100644 index 45a9ae8..0000000 --- a/install/update/old/styles/prosilver/template/mcp_move.html +++ /dev/null @@ -1,71 +0,0 @@ - - -

{MESSAGE_TITLE}

-

{MESSAGE_TEXT}

- -

{ADDITIONAL_MSG}

- - - - - - - - - - - -
-   - -
- - - - - - - -
- -
-
- -
-

{MESSAGE_TITLE}

-

{ADDITIONAL_MSG}

- -
-
-
-
-
-
-
-
-
 
-
{MESSAGE_TEXT}
-
-
- -
- {S_HIDDEN_FIELDS}  - - {S_FORM_TOKEN} -
- -
- -
-
-
- - - diff --git a/install/update/old/styles/prosilver/template/mcp_topic.html b/install/update/old/styles/prosilver/template/mcp_topic.html deleted file mode 100644 index b56ed18..0000000 --- a/install/update/old/styles/prosilver/template/mcp_topic.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - -
- -
-
- -
-
-

{L_POSTS_PER_PAGE_EXPLAIN}
-
-
-
-
-
{S_SELECT_SORT_DAYS}  
-
-
- - -
-

{L_SPLIT_TOPIC_EXPLAIN}

- - -
-
-
-
-
- - - -
-
-
-
- -
-
-
-
-
- - - -
-

{L_MERGE_TOPIC_EXPLAIN}

-
-
-
- - {L_SELECT_TOPIC} -
-
{TO_TOPIC_INFO}
-
-
- - -
-
- -
-
- -

- {L_EXPAND_VIEW} - {L_TOPIC_REVIEW}{L_COLON} {TOPIC_TITLE} -

- -
- - -
-
- -
- - - -

{postrow.POST_SUBJECT}

- - - -

- - {postrow.MINI_POST} - {L_POSTED} {postrow.POST_DATE} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} [ {L_POST_DETAILS} ] -

- - - -

- {L_POST_UNAPPROVED} -

- - - -

- {L_POST_DELETED} -

- - - -

- {L_POST_REPORTED} -

- - -
{postrow.MESSAGE}
- - - - -
-
{L_ATTACHMENTS}
- -
{postrow.attachment.DISPLAY_ATTACHMENT}
- -
- - - - -
- -
-
- -
- -
- -
- -
- -
-
- -
-   - - -{S_HIDDEN_FIELDS} -{S_FORM_TOKEN} -
- -
- - diff --git a/install/update/old/styles/prosilver/template/memberlist_body.html b/install/update/old/styles/prosilver/template/memberlist_body.html deleted file mode 100644 index 5f03ad9..0000000 --- a/install/update/old/styles/prosilver/template/memberlist_body.html +++ /dev/null @@ -1,179 +0,0 @@ - - - -
- - - - - - - - -{% EVENT memberlist_body_page_header_after %} - - - {% EVENT memberlist_body_group_name_before %} -

style="color:#{GROUP_COLOR};">{GROUP_NAME}

- {% EVENT memberlist_body_group_name_after %} - -

{L_MANAGE_GROUP}

- -

{GROUP_DESC} {GROUP_TYPE}

- - {% EVENT memberlist_body_group_desc_after %} - -

- {AVATAR_IMG} - {% EVENT memberlist_body_group_rank_before %} - {RANK_IMG} - {GROUP_RANK} - {% EVENT memberlist_body_group_rank_after %} -

- - {% EVENT memberlist_body_page_title_before %} -

{PAGE_TITLE}{L_COLON} {SEARCH_WORDS}

- -
- - - -
- - - -
-
- - - - - - - - - - {% EVENT memberlist_body_memberlist_after %} - - - - - - - - - - - - - - -
{L_RANK}{L_GROUP_LEADER}{L_USERNAME}{L_POSTS}{L_COMMA_SEPARATOR} {custom_fields.PROFILE_FIELD_NAME}{L_JOINED}{L_LAST_ACTIVE}
 
- -
-
- -
-
- - - - - - - - - - - {% EVENT memberlist_body_leaders_set_after %} - - - - - - - {% EVENT memberlist_body_show_group_after %} - - - - - - - - - - - - - - - {% EVENT memberlist_body_memberrow_after %} - - - - - - - -
{L_RANK}{L_GROUP_MEMBERS}{L_USERNAME}{L_POSTS}{% for field in custom_fields %}{% if not loop.first %}{L_COMMA_SEPARATOR} {% endif %}{{ field.PROFILE_FIELD_NAME }}{% endfor %}{L_JOINED}{L_LAST_ACTIVE}{L_GROUP_MEMBERS}{L_POSTS}{L_COMMA_SEPARATOR} {custom_fields.PROFILE_FIELD_NAME}{L_JOINED}{L_LAST_ACTIVE}
{memberrow.RANK_IMG}{memberrow.RANK_TITLE} {memberrow.USERNAME_FULL} ({L_INACTIVE})
{L_SELECT} ]
{memberrow.POSTS}{memberrow.POSTS}
{memberrow.custom_fields.PROFILE_FIELD_VALUE}
 
{memberrow.JOINED}{memberrow.LAST_ACTIVE} 
{L_NO_MEMBERS}
- -
-
- - -
- - -
- - - -
-
- - - -
- - - -
- - -
- -
- -
- -{% EVENT memberlist_body_page_footer_before %} - - - - - - - diff --git a/install/update/old/styles/prosilver/template/memberlist_search.html b/install/update/old/styles/prosilver/template/memberlist_search.html deleted file mode 100644 index b1c7a81..0000000 --- a/install/update/old/styles/prosilver/template/memberlist_search.html +++ /dev/null @@ -1,87 +0,0 @@ -

{L_FIND_USERNAME}

- -
-
-
- -

{L_FIND_USERNAME_EXPLAIN}

- - -
-
-
-
- - -
-
- -
-
-
-
- - -
-
-
-
- -
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- - -
- -
- -
- -
-   - - {S_FORM_TOKEN} -
- -
-
- -
diff --git a/install/update/old/styles/prosilver/template/navbar_header.html b/install/update/old/styles/prosilver/template/navbar_header.html deleted file mode 100644 index dc29285..0000000 --- a/install/update/old/styles/prosilver/template/navbar_header.html +++ /dev/null @@ -1,210 +0,0 @@ - diff --git a/install/update/old/styles/prosilver/template/overall_footer.html b/install/update/old/styles/prosilver/template/overall_footer.html deleted file mode 100644 index bdff1a0..0000000 --- a/install/update/old/styles/prosilver/template/overall_footer.html +++ /dev/null @@ -1,120 +0,0 @@ - -
- - - - - -
- -
- - {RUN_CRON_TASK} -
- - - - - - - - - - - - - - - - - - -{$SCRIPTS} - - - - - diff --git a/install/update/old/styles/prosilver/template/overall_header.html b/install/update/old/styles/prosilver/template/overall_header.html deleted file mode 100644 index 09824d0..0000000 --- a/install/update/old/styles/prosilver/template/overall_header.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - -{META} -<!-- 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 --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{$STYLESHEETS} - - - - - - - - -
- - - - - - -
- -
-
- {L_INFORMATION}{L_COLON} {L_BOARD_DISABLED} -
-
- - - diff --git a/install/update/old/styles/prosilver/template/plupload.html b/install/update/old/styles/prosilver/template/plupload.html deleted file mode 100644 index 1eb8437..0000000 --- a/install/update/old/styles/prosilver/template/plupload.html +++ /dev/null @@ -1,67 +0,0 @@ - - - diff --git a/install/update/old/styles/prosilver/template/posting_attach_body.html b/install/update/old/styles/prosilver/template/posting_attach_body.html deleted file mode 100644 index b46e9c9..0000000 --- a/install/update/old/styles/prosilver/template/posting_attach_body.html +++ /dev/null @@ -1,93 +0,0 @@ -
-
- -

{L_ADD_ATTACHMENT_EXPLAIN}

- -
-
-
-
- - -
-
-
-
-
-
-
- -
- -
- - {% EVENT posting_attach_body_file_list_before %} -
-
- - - - - - - - - - - - - - - - - {% EVENT posting_attach_body_attach_row_before %} - - {% EVENT posting_attach_body_attach_row_prepend %} - - - - - - - {% EVENT posting_attach_body_attach_row_append %} - - {% EVENT posting_attach_body_attach_row_after %} - -
{L_PLUPLOAD_FILENAME}{L_FILE_COMMENT}{L_PLUPLOAD_SIZE}{L_PLUPLOAD_STATUS}
- - -   - - - - - - - - - - - - -
- {attach_row.FILENAME} - {% EVENT posting_attach_body_attach_row_controls_prepend %} - -   - - - {% EVENT posting_attach_body_attach_row_controls_append %} - - - - {attach_row.S_HIDDEN} - - {attach_row.FILESIZE} - - -
-
-
- {% EVENT posting_attach_body_file_list_after %} -
-
diff --git a/install/update/old/styles/prosilver/template/posting_buttons.html b/install/update/old/styles/prosilver/template/posting_buttons.html deleted file mode 100644 index 122afdf..0000000 --- a/install/update/old/styles/prosilver/template/posting_buttons.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/install/update/old/styles/prosilver/template/posting_layout.html b/install/update/old/styles/prosilver/template/posting_layout.html deleted file mode 100644 index bca9195..0000000 --- a/install/update/old/styles/prosilver/template/posting_layout.html +++ /dev/null @@ -1,86 +0,0 @@ - - - -

{TOPIC_TITLE}

- -

{FORUM_NAME}

- - - -
-
- - - {L_FORUM_RULES} - - {L_FORUM_RULES}
- {FORUM_RULES} - - -
-
- - -
- - -
-
- -

{L_INFORMATION}

-

{L_DRAFT_LOADED}

- -
-
- - - - - - - -
-
-
-

{L_SELECT_DESTINATION_FORUM}

-

{L_UNGLOBALISE_EXPLAIN}

-
-
-
-
- -
-
 
-
-
-
- -
-
- - - - -
-
- -

{L_POST_A}

- - - - - {S_FORM_TOKEN} -
-
- - - - - - - - - -
- - diff --git a/install/update/old/styles/prosilver/template/posting_poll_body.html b/install/update/old/styles/prosilver/template/posting_poll_body.html deleted file mode 100644 index ee7100a..0000000 --- a/install/update/old/styles/prosilver/template/posting_poll_body.html +++ /dev/null @@ -1,53 +0,0 @@ -
-
- - -

{L_ADD_POLL_EXPLAIN}

- - -
- -
-
-
-
- - - -
-
-
-
-
-

{L_POLL_OPTIONS_EXPLAIN}
-
-
- -
- -
-
-
-
{L_POLL_MAX_OPTIONS_EXPLAIN}
-
-
-
-
-
{L_POLL_FOR_EXPLAIN}
-
- - -
- -
-
-
-
- - - - -
- -
-
diff --git a/install/update/old/styles/prosilver/template/posting_review.html b/install/update/old/styles/prosilver/template/posting_review.html deleted file mode 100644 index 1304046..0000000 --- a/install/update/old/styles/prosilver/template/posting_review.html +++ /dev/null @@ -1,44 +0,0 @@ -

{L_POST_REVIEW}

- -

{L_POST_REVIEW_EXPLAIN}

- - - -
-
- {post_review_row.L_IGNORE_POST} - -
-
- - -
-

{post_review_row.POST_SUBJECT}

-

- - {post_review_row.MINI_POST} - - - {post_review_row.MINI_POST} - - - {L_POST_BY_AUTHOR} {post_review_row.POST_AUTHOR_FULL} » {post_review_row.POST_DATE} -

-
{post_review_row.MESSAGE}
- - -
-
{L_ATTACHMENTS}
- -
{post_review_row.attachment.DISPLAY_ATTACHMENT}
- -
- - -
- -
-
- - -
diff --git a/install/update/old/styles/prosilver/template/posting_topic_review.html b/install/update/old/styles/prosilver/template/posting_topic_review.html deleted file mode 100644 index 93c4484..0000000 --- a/install/update/old/styles/prosilver/template/posting_topic_review.html +++ /dev/null @@ -1,89 +0,0 @@ - -

- {L_EXPAND_VIEW} - {L_TOPIC_REVIEW}{L_COLON} {TOPIC_TITLE} -

- -
- - - - -
-
- {topic_review_row.L_IGNORE_POST} - -
-
- {topic_review_row.L_DELETE_POST} - -
-
- - -
-

{topic_review_row.POST_SUBJECT}

- - - - - - -

- - {topic_review_row.MINI_POST} - - - {topic_review_row.MINI_POST} - - - {L_POST_BY_AUTHOR} {topic_review_row.POST_AUTHOR_FULL} » {topic_review_row.POST_DATE} -

- - -
{topic_review_row.MESSAGE}
- - - - -
-
{L_ATTACHMENTS}
- -
{topic_review_row.attachment.DISPLAY_ATTACHMENT}
- -
- - - - - -
-
-
- -
- -
- -

- - {L_BACK_TO_TOP} - -

diff --git a/install/update/old/styles/prosilver/template/search_results.html b/install/update/old/styles/prosilver/template/search_results.html deleted file mode 100644 index d4dc6aa..0000000 --- a/install/update/old/styles/prosilver/template/search_results.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - -

{SEARCH_TITLE}{SEARCH_MATCHES}{L_COLON} {SEARCH_WORDS}

-

{L_SEARCHED_QUERY}{L_COLON} {SEARCHED_QUERY}

-

{L_IGNORED_TERMS}{L_COLON} {IGNORED_WORDS}

-

{L_PHRASE_SEARCH_DISABLED}

- - - - - - - - - - -
- - - - - - - - -
- - - - - -
- -
-
    -
  • -
    -
    {L_TOPICS}
    -
    {L_REPLIES}
    -
    {L_VIEWS}
    -
    {L_LAST_POST}
    -
    -
  • -
- - -
-
- -
-
- {L_NO_SEARCH_RESULTS} -
-
- - - - - - -
-
- - -
- {searchresults.L_IGNORE_POST} -
- -
- -
{L_POST_BY_AUTHOR} {searchresults.POST_AUTHOR_FULL}
-
{searchresults.POST_DATE}
-
{L_FORUM}{L_COLON} {searchresults.FORUM_TITLE}
-
{L_TOPIC}{L_COLON} {searchresults.TOPIC_TITLE}
- -
{L_REPLIES}{L_COLON} {searchresults.TOPIC_REPLIES}
-
{L_VIEWS}{L_COLON} {searchresults.TOPIC_VIEWS}
- -
- -
-

{searchresults.POST_SUBJECT}

-
{searchresults.MESSAGE}
- -
- - - - - - -
-
- - -
-
- {L_NO_SEARCH_RESULTS} -
-
- - - -
- -
- -
- - - -
- - - - diff --git a/install/update/old/styles/prosilver/template/simple_footer.html b/install/update/old/styles/prosilver/template/simple_footer.html deleted file mode 100644 index 1ef44d1..0000000 --- a/install/update/old/styles/prosilver/template/simple_footer.html +++ /dev/null @@ -1,40 +0,0 @@ -
- - - -
-
 
-
-
- -
- - - -

-
-
- - - -
-
-
- - - - - - - - - -{$SCRIPTS} - -{% EVENT simple_footer_body_after %} - - - diff --git a/install/update/old/styles/prosilver/template/ucp_agreement.html b/install/update/old/styles/prosilver/template/ucp_agreement.html deleted file mode 100644 index ace6525..0000000 --- a/install/update/old/styles/prosilver/template/ucp_agreement.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - -
-

- - {S_HIDDEN_FIELDS} -

-
- -
- - - -
- -
-
-
-

{SITENAME} - {L_REGISTRATION}

- -

{L_COPPA_BIRTHDAY}{L_TERMS_OF_USE}

- -
-
-
- -
-
-
- - {L_COPPA_NO}  {L_COPPA_YES} - -   - - - {S_HIDDEN_FIELDS} - {S_FORM_TOKEN} -
-
-
-
- - - -
-
-
-

{SITENAME} - {AGREEMENT_TITLE}

-

{AGREEMENT_TEXT}

-
-

{L_BACK}

-
-
-
- - - - diff --git a/install/update/old/styles/prosilver/template/ucp_attachments.html b/install/update/old/styles/prosilver/template/ucp_attachments.html deleted file mode 100644 index 696f621..0000000 --- a/install/update/old/styles/prosilver/template/ucp_attachments.html +++ /dev/null @@ -1,83 +0,0 @@ - - -
- -

{L_TITLE}

- -
-
- -

{L_ATTACHMENTS_EXPLAIN}

- - -
- -
- - - - -
- - {S_FORM_TOKEN} - - -
- - -

{L_UCP_NO_ATTACHMENTS}

- - -
-
- - -
- - - {S_FORM_TOKEN} -
- -
- - diff --git a/install/update/old/styles/prosilver/template/ucp_avatar_options_upload.html b/install/update/old/styles/prosilver/template/ucp_avatar_options_upload.html deleted file mode 100644 index 63a734e..0000000 --- a/install/update/old/styles/prosilver/template/ucp_avatar_options_upload.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
-
-
- - -
-

{L_UPLOAD_AVATAR_URL_EXPLAIN}
-
-
- diff --git a/install/update/old/styles/prosilver/template/ucp_groups_manage.html b/install/update/old/styles/prosilver/template/ucp_groups_manage.html deleted file mode 100644 index f2b4f00..0000000 --- a/install/update/old/styles/prosilver/template/ucp_groups_manage.html +++ /dev/null @@ -1,247 +0,0 @@ - - - style="color:#{GROUP_COLOR};">{L_USERGROUPS} :: {GROUP_NAME}

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 z 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_63.png b/images/avatars/gallery/Civils_H/Civil_H_63.png deleted file mode 100644 index b74ae5cd88edab596fb9bcfd51a9d1dfbc3d71d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31848 zcmcF}<9}UU)a{8+?2|NB)2Oj++je84v2EMd6EtaTCyj06#5Qm4``&-ye%kxP{>?El z=9+7bwIdYeC6E#D5C8xGvXrE#G5`Sa^$I}=g#CKNgvrYR0NxBzqC%?f5N9bm(f9|? zLk3gPV8cs#E*es$`gX1a=s%>%r4$t3!xhDni5O^98#!zjqAGt@D;^_5)+m;2{>84O zflv-9AAnI_%bHaW0b)a+P*>9klaR*KNu^G|!EZM5wZGWjs4ifY1n|G9WPC=>PkNCdWjA)8a&SVLUtfEvTzkRNhcT0Y7%y9SC09;6ST!Sc1Q) z`jD^8+<&YiFZK6DFU9l(P2}NULGmg{p?AO-*zE*c z`QSd9*u&#$`Fl+1o`1lF^1&r7y^Sm_y#wT3d3*QR;1GOrF9y7Xk#ZtD_9^reCSwVf zeGG}naj;FvRP@0=5qW1NI&B+sLJ0VO!kKJv$VkRRYIf+tHTU{BaC9Uj_GD#(Z>XpX zXAW(s30@v|l%8JJUr6A}iVRvxXq1<{E`iwS2CZOm`+2kJkf9#Mu2tOKXi6i8@ zX(8B`P#h6F>1=CT91;D8d}aQ`{)XfY{1AT>)DlC;Z{D8vL-qx2B55erbG@dZKOuFX z@&mSJ`4ku9A&-z@cR03Dcj_*TSREKT2>D@&!@4d4>H`bB{G(X}rLGKu1d41z1%6S# zQG26bEb_^!$3sqwK=?)_ZVSLPpAwa)h!+*iLx+8$eGh5Tee67PD+aV7!hL34U0%Vv z7hMD>b6(w>9i4mU@-F3kbixw23wUGuDm``{o6~JTnL>9>y@~naZWeo`C$p}H8kJAC z$BN{ds1OO@w-P)z`b!@$tG#D>RvYcN@$H&D={(VSqs5+fnZJi(37RwQq-{f8v2XM{ zgmc{xn4s{%ZHjH{tqC3d{CAM(Usmg^7e=62wNTDFD7IY%o?CKFc-_{!LVuz_a@`v9 z6+*~o+26t0j@zcs2`bjfWs*xG$l~a%3bfzZ>R5RGPILFO*4BpsC&Xl}5shT8w3FQNsGU-lNMD{?g&&;&JBU$=8kF(6M=&^#X>W7cze zKa?#~ta&x!tfvNDQo+0sC@6tW;9uMGx`VmF+d`ZGX@Qyz_%OaPYpZ&`#}aLo(lO(7pbodePESB*$V7a^x38d z1;F`1DD(@soKE|SB5bd2+rMojLx0L!(Cw2E=yt33r~bCg*Q6MptYWOFV?QKX`U`mK ztTy_O1BCaiHEF4DpRbrth7)i(XWA+&geIT21*7|fwT`-VHWct4-fH>Iy}?4K?!Nbl zz>mZ+&D;DTYizTmji%VDs}x7TJU5bHNtwf(Mwb5V&8`Q$(j+IA9Ple0YmkW_F*4lz z`0X0X0mmEVMelvvClITr?+L{lWLIpBy{ogm z!{_QPwqI=9NL>V52y3ZKrZDKgkhkw2gl7wDa}AOZ<9S)zbJM5u5XY3YCP^|V-%NqGMIgT#=%zx+=7>qy?40fwV`Ek z#Z<3-D*IZ9svNXRSF*(N582DN+f?b?O*3H!9cAyuC2;P1-3dN49)}HNzhL7o`z}v8 zIe$WJmiktg{v!cG-4ozI;0W`K|(apQoZA)>GA&9&HKwV9Ft`Y<uL z%wF>?7=0md+jzPn;FELP^ zT4pv)5}4cNwn=HV(FzxQ1lJnm^>~zP#B^oygt;NYh|}-wQ9jQy0sd-!gj_g1Z28cB z{aOwxVT&Nff#0Z>2qj9HbVaNLFZ0XltKFxRczW&9DPo?m_HPll#IvI;#M6J0%#W8V z8e9rk#TK*$)f-F;sZ_!Hj&^ZZ&QDMqB6r-%0OF}1+oYW3dsmA+4Foo^p5fIK0bR30 zwmx|g)o0wXp7ha$q9}gV;wmXL$oV9{x9W2)HXD+}7ynbf+*ukQU`ED%z%@^O&!h=* z8~Sm?$?J2$n^H=nO0O~RK@>UsPiO8|al&Qquq*1!m?VTQA! zH+}&#S{>`Q5w2WVW;3_F6@7?h3u|WW!Is3tl?J-u@Z_8=Pt$C#PxEZ3Yt=%lcW0~N zc3bMN%4aJfNn$zmqvZ+~7sy`@cLSU;d3<4~2P3Y8Y+f}w9G6bs?hM{STfoj3teyoA zEdJSJ5$$G9`xS~S(BDzf>F7f<`|;)SYWzGXeF=zQ#|E@Q+&EGgAXQi{F%&O%%f)gk zdYkzt{c4w`W@lPZ_q5&w3+_Z=CC7=Xcx#8-gWuiB&eHKyMZ=v@g|IFydu|?=Um9+h zTdxT>%B5>Dz%0yuJZjqVF+?Y*2Y*ADlaqwKi5YHG6khkZQ6nfQ{Z2?8JHX(!Li>K9 z>Cu`^mqmhnsWu-X#=esg?K10;%XmWbsISm~DI=x%`P^2FTriH$= z2qtZU?TY!0pkw;I$P1s^pH{`+FQ9$R@sEsfXtFk}y$2@g--RY{&tJRS=g`EhvCD|M zXCLTX4&U%R6D*-#XN&&Tl)rnSMypMZ>8bSJ3W43VOQ(dL0lb)LI<3m3CO?LbpVL0Y z>~k~ojSKRnYc>X1;Bo^DE*}ayWB+$CyCaM1tJNQaF|+gdn8iULLIxqS`lDg-Dum>5 z912Ua`^v+#h9Vo#Yt&s=VL?kh@eP+&7g--Y5N25{ErV8h+j4oczlk|6^$mlUsamne zQm2nHQ_|T=G55?DyxIA^tdCs-n26xJ<|jnFa@Ko0yTD1M2zCjt- z%(0I2rt#*1f7%xSWO%eZv95>Jz}oiKh9XSZR8N{ zMB9;MUv}|2gQ(dCcf>?gSQVVN(-Q(T=yg_Wi9RN4!TQkS37lF2_M`Q-ww%v#sa~N! z{Oqr?JRP}b_0MoxZW>GbS@M<2D{N27H!HL8-QC<6+cnv-RHT_a{f{4=H+jueR4L{D zTWeH{D;MVYD@Yo>ENzz(JWqZPZH+v!wC#3F?QQKZ@1jKzkRoKOBQU!i!JtJN-jBtGV@2e!T8DP{>j7fD2jg7H5no*Kl6G-F9;3+45S3*^x_|7l1 zJ5%fFI@!7a!|HFB9}ud!?P7mbS6Ow@={nVFe#u9ZtkS@ubh*>wzwxO+75R$1FK*Yk z))&#Lg{@UEgsl5QB}t5tCuLB}F>S*hvInt$T!j_XFaDf zQk>{!-{FDPaYPVZuJ)#XX41o!; zEF7`Br8p4wZ5;U|0qyT-iWXA34GkMT&$3Y_M|QucJ-d$R8#k9Pe(ovaEaI-0>>H;( zr!(Z1XKuK`PlTNvdmKa$S%s8*>z6-H@11CISrq!%s)*m#ed+>V^ zlfDT=J{C@Xatg+HLJb48BKw3WgNyGgjFuwmCe#s``UQE-gw=v(e?QdiToGa}HWB`n zlGFq|akTSxFR@{3(Z(86MjShV<_78L$YS?A?>gBrt~pC-zI%c&1MmKe&vP~rnsXr> z!f5Q5Sp$3A;+5D!e01E6paR<_=yfL2O5x~hp8zTNd;YrYGklVMP zaWyd!VYL}&4Z*#72T}91OZNC|pa(y42kCD$YtUs z>y(L|+P%IVix>)iyaB{zA2s_)a=VHSJ;@4 zvrbbGEe?*O<1sW_N0h$yErEVR`c$Fj2qM|jRQV|?K{Yf3rm$8!0LCT=1~2C@HVuI@EWT#v%VT5l=LiHc|seW$zA8zt%oOakB@;3L#0^$Ok@h$v5=P*=j5QAt zJ^jQ^3S!xy4+A$L@qsbKvkmMfZh`=GyB9Br+~_~!Qf2>BkG0L#8rr~1)ClUx*7DnE zJWL3nBHzD3Q!PrkxkneOtW3Ak#No@Xw`|-cp45%5__0FO@tBm`$H3dzVG~I$c)Gl- zVfkF=PMfvOhN0JdNhV^~-2ZV#{tI$F`Aj}&+k-!Ge!aHS6FwsS&%{pa^;`u-=|8cy zOHsWv$pWfKw1A{Wgos}dv8T3OCSWk0vn0=gkvqY0t3XsbP|&}%NSn$=cIx(poiYka z;A10=Azypk&f1EyJ4G^Iz1lGCAcnL>JvBuzTh!_KtgpuN#%rx<@IJl;%Qg0Y965}$ zBDE7Ac7$awId5@4*d?QJjb4$?9dMOl z6!~-DDHDb{j;I92Wut^do6mPrjrtSitny$jN%=Obi{1UcyJ8zN9#eBlli-JtS=yTy z?}w>7tU4Q5Q=!S;(FsDhc*cbaL;xNHCh3R_vqwSSM!IAld zplCo8;7=xYNCh&!d9W6Z%gqW6U8>O)rp)j^g+U&lm@p|T`zNWKq%hKruS+hcW~2pw zR2g{Sj2K^G))_iw(sGfr8P?xhtQpBYOvQu_$d@*XX#--exNhiCJhW4Mel+I}3s*z0 zIS$^|X;mGNF@KW@AAo-EZIu4;Q)x_v1$$f-A&cxE(0WV3JFG`|{#h&{0suHD(k#wH zyyipfb4#7t={sJLyMep(S7wUSrH7h271aweL8kPjGb1w_%CA63othA#EWC8_UTbpW z!-q^Onq-icg$AS(y9P`La0zXuxgW1fjnw}gyIwnQD!+zM974bAX^8v^hoy+V2YKoA z!*;E=VuiWu^W^*W_$50vhcz#eNTV`n%8mUJI;gjCmJPWg`TM}VYIU?SJF-38$}^p2 zbbkXbBz0s-`E3-!SJ_J?GR9+uka5~jILsT<2L)aqn343>7W3B!j#V)-OJzs=s9fTu zwF?g`D+`rJ?y8Gy*RsG&6riF>I-2Nq02Uf&Pr=M7XY46yR?}6`rLOpDWPiz4=Qh)s zG3Es^O4pVUomr$IQ#$>@Kts+IuR=Ir$xAXjoV&T4@d8q@unvVM1Ap9Aj})>7Om27b z6tv~5#F=#7@=htZ#3qZieWhsnEyGkfxh`I+Z`!qOOJ9L>h~l3&y~wWWyoXqbBaT0U z*iBth>vhWvuNA9W%Jpg$gP~npaMSr6VHI_x#WwsqDr!y9ukR!(gbfwYv+B_&-R*_B z;NB)%Qdp5~Xfe8z^}?POM8OPU?r~8&x*1an!1&RnewY9459{}wZbUhif_R{;gL@qS zw=GnZEVjjxB(3Ra#jXr|YXos6l^uo#0RqteKO;uTqeelUo|f=wQw%+ha7lUi8fsF2 zk=7^QKy<-i`R_kR>VuD!QG))By4Eb6IvndhphI8=0HX9Wu%uvcKl`HMWh3ssOXB+pu$O7glI30MHH3@ z{0O~}tg6JR_$ryJM?ub}vOWvqb8Mt|n9;EG&3i2_C`1vJk;?QjM!{^n zJRpc+$KSbYvR_pTa0K}ih`r<|aSs^U5p_`-!zRKf5tKAs5~Sd%B@DN&OTfdUpl9T) zm#wNttrUoIVnOi7i5CT^S1r6+rIKO0nknG#ttY5OE(=jQ+}7PTL^BCi43Mo;{{QU}}#&4~uHGwNB|xE-fKm;YUSy|HOi;Px&9rGvu8Yx`7(viP?)tjf8NDb8s0wkZ9~U?Wjot zc6cIe*#L83yX{h`KJ3eu! zWOC0fpSVtm&NA?Yd^rE*cg`2E12W;-N@(3bj{v-lv!16Pj8lR$y-9$>k zNIhCMJWy38FMKkv1JfH6(GtK5->`L!N(W%gLw(+o$l09>#k+?k>*K+~$6EA-%6KCv z*kepkQ~PSo<+S|MUd@vLS(o1LD;&T4}Z{@CQXWFKwM1M89i@un^mW9TZbMr2h`yTu2SEPji=~< z>g&Nmk5ZoE*d#L+KnPPCR_(fqNxDd|LQcdMV~&DfxoHcqDZH zEnF0yUsTcKI_yH?!zaYXM_fYGZM5)4tz`GkleJZH7i5pC(c>jHz)s=!2_3wDw**ur zt62)cXKk&15tppE2$^b#zNPAn;o$dRrn*nSbQRuj=A-pXeh!QN|eO3 z5Oi71j-HO9cv^h-DD^qp{hNGR8c<-a%=h0q)S1zFW<_v8Z8bYdI*$(5y$F>h1O!W` zS>9!3HC_SGyX*%KdE`=u>4F>OOGTR^$t~j7M*K-08Lz*7DDh3L*?h=NE2yajk39s{ zRJ3@W!}7nKvCmdem|{dbZ1~@K-xti_jcOu2yFf;y2Q*U;5M;ru^Q$uW-F=wl*YQ z6mu_*SVe(geGg*mL|nRWkD(=$L~>Wi+iH^ubU~bAm^8|FLWZz3JcJWbT$I;9<56tu z>ucOO=hL?b7CP5BDb(<8vbwCdc;FcLzN0xWB$iK14tfww5mKPMWlz2^MfBtmNeNFe z&WBlBD_xRWz0u{#@x+LWM4?-%u{m&p0FK@$*ELqfMai?___T@QKDW`*hzD zH6H!KfEZ|-oPcDcOAq=T#;wIw_10(-7va{<3 zcS<8q^(m3uybu!GVr0B3uwPw`a;r-st;W*os-T(rgX*^bO9=nFdM<(;9x+g8j;`e9 zRGDVFWBWvxZ*=7&vJ_wVTp=ney2{+{sx%;}gwIqPgcKp1YHZXN4i~o+g6mMzbeiBU z$%stIVdop7(A^PL(n@1f*?UMN*U&CshZ>thMlIyj-SWPG8dnpNt5;sI7sKVd-*)lK z4g`YeXAB0MfoqV6`ujgFYd42$`JV`GSyVK6nL;q&0X&2}ytSuoIU=^Qih-j6g7Ge7 zvk}rnEC+O%KQV%attnvfHMOex9lb=W=Dw4hPZT}l$CQ$wU4}(4j}SioQz_Eld6uoK zW0p1c9i~`<&SC-?}mwH=_ zxI!VA8eXvGU^Mud5Dx8%!oIqqTzH`!Fam8@pj*52d3f=!s5!1aAXiNmnxw}-nfybC zEM#0@H7GmrC33VshA{B*lFvKPi}tkTrVrz=RA#!uv6Xa#f5Hci(W8Wj6nH5-n;uH3 zdo!R)bSfG@Y>oVP6j_gqJ1XGxMKpOkSLztulEAa}0nJ#G(Q=Ajc5kO>c>gexOCFXK&<0YIBt~D8~j@`Fr>@w+bN-t~3 zMt^l{_fzksVVmy2!XrNxh3bCqDH3G6ngpl1V1APv#RZipvxhTZA!aLWLUf<2-rtIt zU#qA*HZM*K``k6+$px^;z zCLp)evfF_GT=EY4vQN@^X2ikIrZd>Lj^yH0fM_nivw_OLx#$8#nz@Q&J+hx`#*0Fm zBDC@K3&$Qi1xu{;lEA>8#AAhHg@+n)h_MuBwV3eT&7jBfDXpfCkMJ!vDKrnM6d~Dv z&~wuR%{FV_>1Fg1QBdVQY>OaM`?uHHiWl?`Z&YADcCc0BQ# z+XI`AIC3D}&31~>^c)&POQTe1W%Q|5@xE)favgWj*~gaG{p|4=&c_kY-P0u##FBi3 zC+aYapLpYw3FV$(-RZ2?jN;u~87*eBGJQC#nOjb&*V=D~_dSJn=(DZ)LM6)-*@ED= zd8GOf=GkX5tp0(#kEQPXS3Ejelvj<*?a6Z;MK!TIHjjL?2np-cmc*?7X1~w8?WD)8 zK^$T~|CiMhdQvp!^6QP7kt-q|I0}KF(N&A42P`&9{&trdP4WJvKOf73oj(+=PP^M9 zW6jCUjwC6Q%H^lxfi8?ZdP6q{4enP9w!9r)5@+@TGgz_mODk3|-zrg;LLNcxpY#{@ z7dh5B;aQsHDUI5V-q%?c`R3?W^Z1~yE0A!mKwJ=!gvWTR=-iE-WMP9(T_{$sn@DOTrV_4)&DUUIh-EiOuKfT z8q({Q$r+Oe#iS2gMPPvpIs#XBom*~KezZJ~!fATFNdgo9?ybE=!H_u2?2x*Gm*9W^ z@Z`RNnNvECGla7Y_`2KggYt$Op0d-rIrA#m|L>of8$;8|UjAs%$I%;eD*ZdTw=~(q z&YC^+D+MX8q;F)>53BTAxt+tb=0Wa`9~D)A9A5-~!IrWpt^EdSZG%eDX@g-5tLRK? z$N<=d-FrCNNyMPc@VrwRYcmN}AMO-Uro1%@KOiWeBt*+f9yM=+%sk1|i32{gRH*2g zo6CsIO!#)S#chwf(wrWBOcK(9kT#)bTo$|A{ap^PO0ekGkzG3w>+AwH0)~SdK7~Xr zOtjCH0GA0-hM_BPbyRG<<%Pxjeu3~WAqNR^+}FMdYZx9{P^q}fZUx6UH^|Id1|Uqj z*EkUzf*A#dc}~ipyV&ybZ{G9_8=`4>z5l6%3ZkeI$A_>_^4_ky zqraF9d+Bp0cD(hT*6qLLn&N9H+$w5A`>kKKgmt;X;-#Y1^6Qp@?XSYXLiu&ZK)t3; z3uTPg-2t-uZ~VFa;7Yqlj~_Vl+xDC8GOX@@cw^M&utY~q5yN#XwHsnqR`5U;1X)~B zBE!zpn$>d)Vl}D(_RZ6!J~d1D7HdsUo23A>Ypin8n8y&=+Y@B%+H>ers(O;Y(px`e z7aSf^E`g73$2_^Gh9*Vwe}r5~W>}0FEk1v@i_uDjCnz$dw}7X9lI6(HwlyuUjUqDC z^Xx@g+ZWB)M7{(!?q2fw9b#Fjl-SXK$-jT4_6D@1gxIrnx|3L>B*A4e!iw-(2wi`Q zE?PgQ^wWkUf9rvBni(23F6SB&$-;^$BBQ=*7h+JL;|{139LAvop&>b$3^5GJaO*Hd zBQ3*G&WX_ldkSQ~hX;wO8jx#-$sIEq+pDZ=o4fzH*)5z_ z)YMe!S5{WFmvs*vdyaL2bG^2nyX+Sg&GmZF`}#U@raC^)W_f)+t51vjeBc5`3Hk~^ zVDQK^o1*~mtcG{8DSAzQtZzC7y1r2PU`QvB^A_jwJ8e#hv$=+aol(HQtY5Q2>4U1` ztb9`{Y$^Ot{g(y9#9rZaF-IrXTO`f;-?uE4k#3xG*;NAwSz#dl$cX?!Jo%dV*7ZP( zlMjBr%U>|&MJ7`;zg{tWLHe)W=vs|8AuS5kJ2JhS%B*!aJ zkMVO>2&B`lH9siy=8g;CF4vrFNR7)cFWmT~n`mZqw%*xo7xDI6h%!RuQM+&TwKHiI z=lS5I5~+XbsP=tx^?!G)fye~y@PeYWXiQnqC_aeJd5OSirww*(S|ax|NM&g5=BvyM z{8zDvcihm1Xv>zF7Lr@2!L&_oOp3n=_2$Y$xOjbWP2>Okaa0Mm(k`}ueP1?lOTb5G zgAz{CIDU!A>T@LSGS8T#`}X%^MX57*szCf(6QN?2eu272&;cc%!XXy59u@G3P{ebLLOM@)t$@fW|$ zgTGz=UsG_D946t-*x$AeLBtROJOR)tjgN7!7g}SS5^B36Q(8dFA0AY6>iIreXtY06 zR)}PwxNA1-!uGwrde(u)hc`boT;r9Cx7ELy|^Ub1vl_5mr#;BfA0cD zmi~ADtvN`n=$4P8?bk`5;5GY$B#G(zqs^xwhe0+&d}Resuv7D`;ckQA8SG@1)Jn0D zebCZ2U#9WpTdtVGNmi|4^}-;TR;pBe$2oa+&QLR_9VfQ`ng!`cG+|M^+>FY za*G*Ro9ggKR~fXdK4{9wcrcC)h<4e%f!+CmHnJOWIJ zf&yA7f$Rj$>0{xYAsgBKfsdQSMURW1Vm4Cd{-GOZ>^>{pw&ix*AGUsZQ<{GnHAqA_ zULFbL?@S0(${Xmn!*{H|fIE59$|Q(dvV0%ox}_=$!_y+hSP3;)b#bACFV<9c=_HkD zmZ%0g-d`^AuXSZ8a|#>A5c^=hZl$mC2&T4jA!>-fn|{L#v>$2iU<`XNp+X{0NSlf~ zHTtt}9$l_u&@O?LXg*py-z>n-GTE(D-DIoOs=RTXz0`%ct2tsWm3r{O>&N&2kqyX3 z==tqUe9bp-0Gzm44oW*7)6mDfpd4#nYdCn?UD5wKDjM~U(&y@Ja$LK|P@Tk=rASdu(TUFGp^ZB6%saoTv^@jK|BU#vy|ZQupxpAT4K_9TID zabv|c(NS({1paW$_OWR#7BSmr4L8DFMzN8+=j=vz+1RlQVa9&Q@70@y+=dm+R z)_F^4eyq@a>%;0EM!zmepDp0X^|7Gps$qQFfkbd_Xo2dwZFG9$DTGT_XgirXjtIrO z6!vSg7C2q=npPr@9qHMA&~$Rr)jqK~i49(tV|Z>XtuQ^|W`pX^(jXH6T9T#}vP6k> zEWMn*Vv3qT>Igi<|KBM((EOC=fENFe@OlZ_2YXRsKUVHN2Wqb81g(4EYBHjL&I6bt zU1X_20HwUYB9LuUsF#XsQb1)lGWkNkyz?2aHF|zqWwj8bIkW)<^*wJKjh&AsG46o^ zhAlsyjvQj!ue{55L;`t&(~fHz##}B#usMC`p#5{k?*n5S3b%yg&m1${oqXH`?^v$ZJ3_Q7kbZ#1rAA6R9OjKEq_=}|eFUo#?U3VRsJU6gD$!+;-=KPo9A2dbaC? z1WXxZ9j4mA5_g*IENjdp!_>@1RTNgh-5DjnZl0Kb7HxDP%1m+5VS}v_`TfG6siB)H zw(BB{yhE92XiZYA{V$>AC%4x0B7%XnAi>9-6s;w%WCt2R&^7kQ@K8Y|UPh=8>Xu&w zme>V1f>OU@(|YNGl@h^lLyZTbE_PH(+~H-~_nMpy1Em9BbKa(HA1XAnIo3Z6Fk7-E z3xkkd3$YLMq`vlx_e9^n@@M$=?GrNwW_I|AubEW=oCcp{+eF!{QLfEfdeBSQ+VBlEANMYybC~I!D)o(?1di?? z6b=NVY!}vmgIE#xJU{h{X%ML9OU1`l3PEwsqyQsaB6##|Jn#8&$Y}$VZWiPi`OwEL zae`r0s(q>?`5AA1xs~KWZ3)sz|B#NT)&EX;t^Q|QHi);YLoyb|yM;4g*NokEx{i^f zMK^8mv5lv8T5W3zhIJu<%y98sY(#w0ZODH<$IAeoC6^lAB^oQl|5w=44J@0c5m)JC#QCFcEg)NlCt;gV$vxpk)YGz2DL?#HcHS2BxXAsoIVIDA0iBd z{oJEumJ3qXNR@(tf65(w$Q?_wsENm3df%pW`C_R%C;cex`YM%5zoXQJLG4C`MB>4p zMZ;?rq!{(ILsD28wMyhRwbk|3&FEe)HMJNQZ(5ZENtIZ2pRkb58;xAiM9fHSr`}?P z5}WXzM2jcDfIii}#h>&ti}10l?9@HkPRVZr^hL4O9r#Ylpj zHMO$)+b~kttNv$ujA`kt16%{y!R zhuGPf3RsS@asq(5osLnvzhx^+k#ojPZ+#4cYfk6wnt$k%)S?SVr-x_j;W1MJg~R|%}LNtO4M8=ADej@bWpZFWhG-OIztJv&v)YSqKXb#rSve1oKEiF~$o z|AbEXSuGyOVZt%lxC)G3GNQXUipKqnIgEYc3Q^@?c|K zM)(zfH|HJkxdLxWwgk2ng(%K2#^~Ud^%gZUIki#NQgRoskU$pqhS@@m+J&Rt1GuC0 z6NGm$tm)>OjbgW{GX6-?+R6V~sCO#zo;6G+(&(${&%I^|DWJQfpMJcfW>`C7A)41N zTJ;^2kV2aZo6cG?%Q+YBZ{O=q72PX`G)i*5QIXEFrCfB?(F7NE#<98Utc}?v(T(jt zL+EuklHQ1MB7#~|1`FLeXweNJo*r~Kj^kuV`QApzcVAU$uwRli41C_>K3>5@J@JN= zA#(6Hx!wB?g_d?F;kF?2tS9>C#cSMXJ3WzO=}l3 z18wT*dIPYX-qT^Ldrn~;PPIG528CgTXNaVfiKYgA|6y1{l$5X&+le21#gJ^&s!+id zO>UCA=8Y7dpUW5K_u@1#1N2c9ru-+jDxQHi0s6Vh?okuP9n>svWulM^yz#rg{d6vT zo)3~YMVE949NY%&nxp5P`awW8%{(WTR+2|dT#~Vxp+TGC4vDTOz#CNYI2d*B%|4A4 z)7=C)Sor$-npA(yJjCd1;*%aTaLmjlXaCYe|)AYj_5e74ar~a+Cm<%Mn+$g21~2- zeu74n1eZp#gI$9A*W8V80^J;%t6R8&uweRK;8RO#dtiKgl;_B#2F>EQush^@0x%LX zK{Jy9p*KBv`5e3BGYdbY z6B{rDj~yU3fEgZqaO8H3&ARc~bHCTf%~K+f=zjL`HC)bw-D8wnrDIabvklaK(d;wN z+i><}oWALvBx1c`VoMQTPzFcu?8;7;JO`%Z2lgCD6V@2uTrk|D8Kjm}xAMj=sbYCl zr3zEZp=Yx@dJ_%zF&m5%pTPYSoX_<-7I;_D{m26Qo{-CIt+^mDyw}#gE!g`Vvb52S zy=`=e{5%4*)YUs2Syv{>KYh{8Rxgi)NmJwvya{*4*+WaxyGNrtMa4!d1g?A*Y9Fgxi+hUmPoVcxwIKij}a% zhvde|x3z&m`X8M}*1QWLP(-qZSdl2$K#R)IR~B^RNUydqA{P65eT5iY$&r~nxGd^Y ziu~VPDf|1c#|L!|+{pqgMp!eUH|QJIqz2qOggz+<%&sVgNH4XGlw~I1zhZm|K)T_A zc2F(!A0)l9WZML=>;4bYSMgS94SPGqR`oLF66vKynY*DFwn{b~VNTq>gKM2?j*)wA z;Xem2!ga=NO-)iu9MZUR6mTZS{~1W2Y@t%yW+m7ESM9oT-#ilgtOoQ4dzhTN)fzJC z)27gJrd{5w@O~bDGT*Ze!zA%XXbJO0i+PG|H|u-)mf{oP@a>zw!R)S~`NNgekfTC% zBlgF$%JEFMIi;zdEy7pSuOyS?LCn57nCp}O`sVW7N7MQ6-dwT6NvJWb`TH!Zg!wp= zCOd01JHEMl5<$`z(S#2zhmhZc-WNTa9Qj59jm>wGYt}N0cd4w7)`?F2z$yrI$R;$c zWX?j5C06Rxc|BC?^MSf4pSzR!F{z>;XFCyOxM)fYeLQ$zrgfs3yxQSts(0q!#6`KlGoJ&gpN@x}h%N ziiD7j5%-BK;n(~oMU%q6DR8Q|e!^iTDd_EAnokM(IS@Kp$ox);@B;TM<{sZ~m ztbm(p;-YYoNV=(rkstn6Rtf{e0|=Agd1Wa=10tD<85If*lf=QYtyTxa2P zY`x_Tnbs|E^v=?KH9N3G5WFY+qE8?NaWt%i25q;A{)8+5{1B>E$Il4L6380uL67l4 zi?QhZD@7DO$mkLSI*eqMG*9<$)W$?PyPy$mHjvS2Jjdo$Ut;|SW`VLUU&L1pKpWi< zbMLS`DsLA|f~^I6d}z07`(QO|{OIZ-x{Ay7as-XZLk|lBV0RE1x*1O~Jg+e=Zax(& z)OX6Sr-fvp$5^Rz_xqzLc>CQq4N@#kvt(S>h$yvNYCycI;)|Ayv&k?D3y zACp5q`4VZU_}|8d2QSgl0~rctvLXwM3oTf$pWgLHrnuf1i?usfzN=-;HnAnYA^Fme zF_)-NS1z8YtdvtUQbR%Di~1@-37Z9slv?^U)Y}TMg@42RJx}xy1rTo59Px3c$s!Dl zduuS@9zQ6JG@%8+V~`qpU(a=ORxxjiz9m#v3hcgqe8n0FM46yR{C0p0wJCHff2A_obp#r?MzVKSbd!=F01sroW7=J`*PK{>oCd=caJ8-Uj~y&J~tk zSblm{QJbNUaBLVFzY>I+=lVIGSQD`CYvC|Ty&cUFXC2%a9F}gzI4EJkqvOI%?r_p` z)%;jbPLL{-gmZil#v@9S&nPzH#SFfb7_^ITW77g9t*){-HXO5Bo}6cLgK^fg~*(z*jV9ab2R|B5$Yz^hTYra0h&cw+57#MZ-3*|k9EDb;vxV`=Y<`YxW zH&H%coEO4H@fnuWvu_%Kdd8exE*1L6KRV1-UMc*nn^~WM^=q~XxW+D~nJN`p5M>xJ z)3{S$Nke_|p%W4^KE$2+%Z3MY6KB$jEQ~0W$yLSAkPIGfyErkg;7eq+Bt;Kk=y>Zh z`gu&MucUUr;{e_J&5cCpozc9rh0IPElJ zeIX40YSV`((Pd`A7gkgP@sj8o0+)kImDp`X?pBQrDv~!!F4J4lC(IDR-zRS%*7eix zedF-uI{*|d{A*-huyB-`(1 zv((HkF)rZ&mPdQ-0@4wr$+2J&&EP{2nxBudR~P2`|3u$E5cf9Uop12DKU~%-ifN~( zjCF9qh$Mj#y7d?&)k`sIru?-H+eyHaC6%zl zlj^M}H(xiiTWvB|9d&f$XaOUVLPt@~$@|r=TVYR)Oqg3t`{wIPkUdW$QyqeNFRgL% zv_7OJIykOqztDQU(6`@7Fb2+2o5W)G5{ZL_(cD!TM!A;n3)3Sawy3ZkNyG78AfCGz zZlVlCk!HWTr_?gh2)DRDKut}gyx5XP@~8crKM8QeRnLk&Q?+`be8DE-t^Pm5SYbRK zuHXo8gJ8u-?-CtK=^qga6a;=KR4?SB^yCXX_XpCBdbG*E{8v&z z|4aXIXa<4DxjD(#|I^epw#U`A(TS~z)tHTKTTPmzNgCU>od%5?+qP{rjqM2^^fNgMQ9u@-4wEp-Zq<_D&`S@9^KAPSF~5+24dS zzQw`1Bj3RkK}yWv{6{!KV8N>W1$r$x*FIG3ms~Z9zr8eLHcU5Wl_z0`pBx*pdG}i zOP=^eL~s4ac>QG8qxnEoQ5>R^!Sqb=d8|SGlGvlM2?@Zo2xx6Q(<;us9xRBjTKgU4hFOa5>^Xb z;;ObWIHdDql=1s~5~zA(xGN+fT$q^eXNV!xat`G2*6HobaBCU2uR_i*QhZ_Bpm?8F zOjF?%PjQtm)wUG)C}A_MV&5s4OgjT59s!Bjnv@QUai7MD;D(>8iFWyR4`ugmfwN%)E6DLaSFb*e{tp6n3IOOUuC$JKcnyuQd*~egSlm@t~LC4(xj0 z&kAE5M@L7XLCkPApsjDMY^;T3WSG4!B}QE$qM~E38QJTktM9`ArUOQU$$-NB2uq$q ziBv4nKW++vR~53Mw~s`K>XxFve+GYJ?A#1s1d5zTA2CGi$KeCuW5j|i zo|f?6pZKgV#sARo#>&L}lyEo*BcMjiz?2LNAZpO}GGmwp%c*R+2R6s<@+TOb#MdEgEf@G|u4?Kz{JDG*s?tef$U z&5U;Z$7S#)Fqk_|kuCOL%>mYk5KO(dH38%B>LFO_(}YCV{G(Nv*M1f^NL-4P7WMpE zXeJcpVP*qJ-i;Cxq!by6B*FO4>-!ZIzFP0g2)fUDe>C8S~DSezA z#qVauGc}8VaIz0R%6Kp229cJ+I0h9sBO$Z7!w=1*6y>C2iGK;iiKO*kYZiXbzmCHy z;e48z?j@TqR%h7lAJWUsbM8$&ONwWQ4-*r}M`Sx$d&1tspc1{x*b2-%uykVfvv_mA z?o>mBQpL5=R6yPe_<-HJS;Pwd;9c5_BUFI{fyOBUu$3QIx_$n-Uho;H7)a?$@SdW% z=;xtIk|`iNn9;Jw??7TGRE{P@4cnH2xIdsHCY-5nw$)SURK4X01x~^z&E>Z1&>$a7 zfJi9R-L;NQw3158qT!fnBrACU3HV5z`I3AgV`QA>2EEO4+Ga zJLdOltr=mZ3cvtAYQzZ1Kx!UulCrOY!|Hn~l%jDVnr^)rs76pmbid5Q8JC{rzB(;D zi;FRjt)*DKfx1)86Rio<>9)&>w9no2^L)@kK;n@%$kwZBBhH&xLEl3C%H)%}i$>D0 z`a&Ollgm#&npR2%ob@d|%3gX_-VFM-X8}Zl;!bc#LDcP0#dh&b3jY`tOm$nisB|Zk zzGnQ6kJ>NROD1~~tdL*&6-cdFp;7vePP5{7pL46c5KWf_wXYs0Si9AN+8IkL9Vd#k zr?=(CzpYCga4ys5a2pcgJ+A&X>%Y^p)AJyBdi~>?DS&Gg{+e5}2tx5_coP z|Hgv$Iji!UR@mcCq@(*mzXw(>QIO}g&KsSb6_EqW7?;`SG^Br=ZJBcUNtiHDgr(LL zIn#rNlH{)e0?7r3t*3a&d0$m9!q+JW72KPinqmAZ;d9C)E%n^%-0oZVBL&B6nH+d? z6kf6S$~JsWx=_BL8KKOdR91jxy(rno0d^>@8AYDQ^d~*B@ck3x+B%8@iaa;I6>i_T zoPW*{w>gvpH!KgpFa|Z~XiJVq zEje~Ebbvn&g)=K6LviS+Zu`&<@6EsA%I~eMm&Sblg!6W(kMf-X471lY94Pxr>m1Rx zkreBJ>FXe=3|}U$33ffr;>WX5!`$>DPR`0o9XV{buC6Y{jF%Q-{(VIl0To4*2B%$~ zV^SE>*nac$TG|0kGw_+(EKnX*qM2sbfsQ`6PKc% z<=4PrGVH*(LiytFE&%&Mb(r!v$D(w2%>jE8wd4k|NoE~9_|U#Ib7|^X8%E~LG`M5w z+0C#uJ@f!ziwyMbKXfWNO3U4PLMNA|>!*(F`K&_*Vc(35vu_pXDY-hoy1(#1^8o5v zyu(+0d16qVLs#Z~YB5{uTHmFW?WScc&=L<2^_A`#)~aJCS^al^H&hV*Ey8&JG+MaE6t^s}lBoc{P|)Ta5a~)AUZqo5L20M*17+w|wrz zVM37^y06l0BPK`2PfVwTLucFWv73KB4OX{EbG(wpfBC%(41TOBfp5Bn3>i~^)_q`- zr!^O*nH#>rV!eZvRGVdO`u16O`<mqt9Nmy+A{X&SBl*KAQK0M;0(G z`$jX24OA{szv(#5yShS`=yv+S#=sxT<>bX0axVFQDD0V~;VDZvl)Fy)(qOv^H=?id ziw3Y-Dt|5LTxmG1@WQN4{&?4=n%e_KLodU6+w#~}ZJZ_m=^1}zB|t4=vN7sqGf$JW z2j;QN*Vq`Tk3@6i26VkY3MslJv#AcVe4GS_>tdkjrD}!)_T-`@=>@z*^}P&P(jYy= z-vw3|l7sMJK%W|1GVUT6REO+w;6+{cUA_{PMzv@}WX@w7OUFL)1>yaOjCQ%_yIe0a;UbxJ{E1KBy7|I zO>b1;^+((z=ibI}9*_+4qLtJQ?i?4!$apNOh(6k<{x*Xe{nz-+kQAx3zI})>f!7HN z>pp0A=+@5r`=UEa{m;$P#kI^&o86mAILvb9jpIkkR+*;^DZfEae7Fl4sFY^V#~i^c z>%@8f(f6YgTV5V}8SkQAeDNik9Q{_swH;3)tNBxZh(dN(TV)`oL+B(zKMz2dc=-64 z#sJ*{;7sb{mq?vGUwWbe!&DJ6tPP)zEe8P8aiF*#sWgnLLN!X9DHUG){#oA}bK3NdmkIwcP4+@s7lR&qrcL{^0$g2d5SV^QW(z< zDL^!*Zhvoj6NZVU?kmT`io1o-a!CU`VNjw$IFYiQEkLNQ6pl^U6&U#O?t8K76X{hk ze1)k#oQL&+0v2s60z~xbqi_=%?|DWA#_sJlU|k0@#ww-G9Dz6graApvtd_I-LQfoI zJ=_P(r3ScG>o;8f=KyzHXnS^5L6sBAXo`RZWTZdAcHrt+6^%YX8&0VL*F*WIUw& zb2}L|T8qLZPn#TUuA^@at;dOCXKx=Xb^^lYDr?FZ6P9iBGw{Ak~lKDwE2N2^Pm*=GrELi&}ZO*>at%JB#~9a}v3JP6wzy{46!ypWvL zoTU_G%RSK!>4QJSgW0zfDSH~B(R+DBU!Etl%8bzFQh0GEHb_?HZ{qmkxsQ0WiJtn` z$j*<1s_5m|p+@D?64oABt7(A)ThPt0D9wA&qtXIK|Iyf)V{f?8tf5ws^H682G`vyd zsEOJ)MFz5(0{Y*jJ2VqtDC;ZM9QUU;L*0wY>7>;wG^7{SVnIYVPeLWWr%3yIi%0%{ z-cGSMyM+;kn!^}I_u0X^p}U4$7SDf}nDarakKe2EB zmiB0Z`icEP1(qGw`raVMk~Xwv$+Fi0(dbh;AK|)B)sHw9VrY6>0KWwDr>Lu#5LVE3 z-6zocR9DI9g9nXJnfZoX*@EWEmh!kolU$0;7GuB=oAcQv$>mlcH83kMPKr`h(|yd> z^~9elEjUAYp*$A#B^=~7TK(eBnPw1pILiF%a1+_VL^@HrNejr~>TIopXzXW404`UF_tt5b<8913_dhCgOOsPjX3 zojd@Z_o&Lymvo|+K)+M};bk*ZhNmU>aS%`$TOz|k-0uO}K?6=+bh)PcUL%%T4_#3N zBXdQlFLNogBg9xyZJ-$>OZRoQep7pm+us`)^4{$ABsX?LP#Tvjb8#5VxTB0S zvG$j^Hw2ib4D_(^{Tfc3kYCk!Vfi7`E%(X-ei_Dy`bd79iNaUtb42Nwg2TWZi^3k( z+0%$Jy{Hb)a`F3s;s|micjVc&N*#dL!+G?8SB)qfH@Udz4>{_%4E%@aJv2NkCR*6p z+N(nIsL)q30ju|nGsw#QA%ng8xE9Iog+()yHFG4*9R8KrT+U3Tn{Imp!V7jByNv_j zRU@`YE3S1eu%l4H?I|T;5cBDpgO7nOWnQibe~jo0*^Z+NDKlJ|V$x#?L==#K^&tmO zAB6#xgU#Z%C>A9W3ANQSHJm3@XH02qt2VG*h&7Sd->N!Dqk#N`H6%689i1{`#}RZP zHPXirEn(WkJ)&hd51pEtYMf+@O8YX0jV4(-U2OwRvoBZjHLLf=9!CVpsS4}yMDTsm z@Og?={!FHMg3rqij%qDhi6@4sA!)a|gtPqvg!OHC8PuLN6`Z#ZPA@MyffsWv!zUYT zKphuX-rVx2m#3t&oRPqL(6kz7@`MT*4yEapR>H0W?ohlN?y*Kacrr=_^x;bzyB3ns zTWMrfyl#4q%W~A;i*>8e%GF z_Ps}LxCjxhf3D;16I9nr&5mNAySuu8>!IkQ*(E zXG}RVoECLoWhJv*VC@P5RhqO&OGsp;I`_s-iYdMmXx11NEgm%RW+&WyeVoE>W zn7$wT(ErWJ$*{JW6G^%a z#3dS12*N0&e|{S_D*Nn+gHB`Q=t$Q49J@n1SGXGik3z2dj;W@a;!8xwon~!L zvM63m^o`Y$ftSM=N1~2Sey7c;A%Tx}va{Jgg7=w^=YTVe)=(pubSX6u(__&v1CF|I zTp{5(;lYi!-qR_slb;2A#G27Fr<5e2lf7cOL{c|t^3E0Zl!$2GtSa_~nUSKR;xAPm zCXNvLjG$V$4GZXvjAdG5Z1oDRPxB&LD;#W0ReN0!&LIG-?3@ZmW~P2pL*yGVv8}dL z6U!Fy{ghc6wSLNe?f^~PzcIY4fW;MtTG-eB2mzhBQH(3Y%K?pV||DBkx9_(?_!f zt<#f3R@>*CdG8uIfG*`bm3mVY`@ui>!cK+J!yl6-OhR~?1Ln>m4jy=BgiInU-a@I$ z^UN1fa3+ofUEC$S(@zJEER7n;$~T(8Ku1T`45M=UJ$y?U_yhxkAoBxqge4*wIp6&C zeefqG73F=_fXAcRX4MTFd%6P^{8@CTeFo~;l^s8nM(A`4~hqxd80?eBD*JE0GY14+{!_naTCARd`-G?g1V!8=dzCi}u@9$~ll)meZ z7;b0T6OLCiQR1AHIA+_Ax%%%qVJ452f$uTit7}?XvEToD?SU(QcApbc-gE5H$=dc) z*y5jWEKMh$@kF!4m|={ZTu(ZCO)2X8`AYaZGFtUt-4rWk4%qcJOrI;0#(d0sA|^^# zc6K(fz-h7Z>i+KUB7OmmcQ?wpeC|XA3EKsky77i6FhQ z$s3zk<9yu2?^BwY>X2Hl%9#@NjR~4yoy`e zTaCQKFg{qd=4;&tlOnuLP~TsPB4%yx#H`-H_fPx({ai=!31z@~nFdc!`w4aIs30DDX`eo>}OQH#O%%c#!yHE917c^K8Kw_075 zC`gbCkWUhDaNyZmxlSZRB^8mM`KIq%@Q>ZqCH0bf7VO^)?OSwK*w48L zeaT16d8?k2{#BD9iHHv>SPD9B-_4D+razY(&|AH|Ez_kx4|w7FtyODZXWt78JENjf!&l9dbtAV?-bM z7$?FgkqCwDCeD??&nmMiW9Rw5!;$dwz)d!133vv7rID-P5OP-$a>R|KoJ^puU{RA# z$_vB3xNTSpQ}SKlLW`2ZNSY`Fy*&G1MM;GPUqmdj4mBuI%h0kp?@^L;HGBf~l-po7 zSxyf)^ow~2-WNmFtIJXv`+5;<|r5&%Y8gyKemS0Xp=)Ny3rWKWuTqbRJ!F?_d z1G??=0_!MEWryfm^*$1AszwtH9^b-Uw$cS)q|VnH4DYks@L6j`MGchVq5s%@c=0R& zwS_DM-mWqw?aLZ3+)P8m@%gy{{rx9|Eunp<0elyd6r^c}uRG1VP%9t+QQ$ zz=ndiy$)2oh(h{VjTV-~Ywe6ZTB2CDThu(E1!yj1?3N3QIf!NDD&h!`@82I3<%$(9 zdyXJe0wO{R&IW;=o>G$;!XRS;KJQa%l{{gDzG1Wt0T|F>(l3Ba>2yp>eZkrzZwhKq zY`y_Ds95uiEB@Qy)r0uTol4p+Aslk>(2)pAPnlNwfXYAtFe>7|7&7k6&Bs@HB$oq# z=Nkn3@cI`&@t7=s)c)xz=VgJmjj=r%0@uV*fpBa z8fuzxyy1yxx^Q$X;=%IH@kpzZE20?jZxP_Zj5;#@ zdb~vn8_D5v+*UE2Apr1xrn|UFGZgz$_=TWfhP@TYLK9dV2AZLh;Zi%v4!3x>Jf z-0ToU>R5o|LMgT0yG|@h7xu?1ki!wl!?3s40ghjTZ?wBz(c-N8k9N*$D1g6|5Bm?+ zyAjoss3BYA&kSp8wVgpI92p{Peu5f9G}HUx6`@|`*<}E@2`uB2%m)FGM%}{g)6@2I zGSWF6_TzDAA52KjwzDhf$_;7?y6lbjV^?(adXbNaq%?%iP^yL&epoK1R>s!A(#9`i5q@0n9{2 zH;%nfk>-&QEaB=q#~Xbi2(l*N6W|YL?Rn-#{rQsuQ$v?B{X6J@P{=1UvmPOwS$X`< zsnN#ftwp*>4eY@Api%oHx$o68V+($RgWb)Fh$^|siK)u`Om)=g{@mNyV#`Y+1#FL6^ z9V~dZ@=Mj94I_5098V1FI_LfOU)Tj&<8v=m9D5j!ePHNmGeQqp(fh9h$4Hh?4x$jc89Cc%^MAO?NMd!~(} z;%TolVRWW~!-1=;^igs9gpUf385Jhn*F?H1XQp#j*%N z5qdj+LUHqODf^Poa2x>RL_*E*=B~fP4c`x)0)e&#OFyf8q0Z;nxp4pv2XtMChkhC= zd59Q!Jry=4JdSF4R7q*NJe`p)ybP@+yO&jTZcS^=qzI=o2ou=jU--~Ts_zJBHBE*> zr67qz3_izm`bQ^&QD}KU&K<4qj7q0Xj{~$m*Nhb6fe0f{PiU3E+$!STBxK1sSaea> zjz?)?9YFj&+(dO}&vB@%n22un&-nD-7}-y#h5j&uRy{^#5jyaB-WnK2HqQsO$k{S; zOYr?@)d}q~GGnvnRiFs))9dvGIgP$T%rS`I`Tom%lcqZclMFXOwPM1YRoHzk7q!W@ zE_puJ)9^YBo}Y;u^gbs<+T1tl;K-GyS|^byDpw2?Qi(dBa%phvIdIQ$bglykm_iD6 z)!NZEVNeFXKp%~+%Hj1WPo+$j8XvftD4EhnehjJ4h^a{yVpWN&YmPUbR}@5#(ox~X z)PCsKIj=qfmquyWyXm;M@5JLGr9V~JU zCL-#!t<5bMjOVZz(a|G|4_qJ9lUUw3`prRHah{ULpd(KDwG`me4Cw7N1yeqL34Ohxk7gmI3la@rn&Of3fDxju~8Qts!Q=oszDek~cl(-u# zi69j4fJbQ)4a-m-(4q+T^4Celn&&ce;rB{r$BZ9?KqGPTZ3(YpZ|qjxwk-k7nvcp#R+Sao3-($iX~jsxL7KFF2-KZwo=)t7dNa} zoAlg_5kXNO-CLu!!YZ^NVt*qiZNBTlBI#Ef2Xx+A|F9~ufFNC7N6=-BZoB6dI^H2! zL0cQy$9;U?kKkZx8eaxs1xm15lSVRfnVgTiX7Si?;=YMr&){x^W|6QNw52m-8kZ!g z&&A}rTik{=W!xxV?f^fXBGfrCMM$6SIlgE1I ziq27o+NB4oErN?|*l0)**wr5(oKN~6G>ug#zl2iab2sEL!lfAbYuf~Pm$4CHF;U^^ z3n<5r&^SVv{0~tTY-FpPN5MS~wG}gWLm;|k&XY4bM%EoK$Xh#D=vv|4XAUDQ;tKp0+v&jx zIc6Be^%%Kfc)iz9`A%FqNZwEBMDdh0Jwsx=-|Fp&+v)R=s+qP|*~opxI- zUwoC}O8>5OoRco*&4LF@MSx0~cs$TA2JEc8^1A#sKoNSY$f2V5j*M>TCH~q&`Z(>) z>gi}u<~tqvQimXvJG3_!%CG1Dair~a8}-<=E;Lw-Yjn8C^ty=Obw?7&jFvzD_jfd^ zaP>ZZpBKh0f}4UA57b!0%E+!eOX$xq<$jOq!h|ybugg_$Q6vW0_2QxrJ@vBPx6qWS ze7m?VtnAwYIg+E=?r@lO4%C8#v^oa0`1wbb(d^n^6Aigv* zf*w37&+6f*sGaFrl6!4)mGEKi8vk?VlYigUW#*lYmamlzXVq5O;_1ou<-^{jH6Zmy!}C&t9#|m4LEK|!J0Ah)&u%{%8j;#U-F~u0Ul;c6MgAkfnM1fe#mv* z*9b~KbG+SI4;5G3ZZYhnxrijqbD+hLpM`!LpIf<6q)8|_D{HFNXgHq@v<-@nJ|IXS zO6!8aa8i^+rBI<_ss%$FFViM_@C=8pgRi|tR+<)jmZaO{3Tv>X*x1nY_(0xIeM9a# z-(a%bi)~6I0Lybdreq#u?FcM}n5DI>FQ2YL6=p%hJjYMp0Y>kuxRsx?6bjjLLWfQY zhoVF;n&HrYkj{MU>U2Mj9Tl+6uB0uZ!2$5H>|ORq9Q+n)An`qCX`_Nu=hpR)LD*1& zZUa%AE;IpdYTl)!(xR7zj-OVjX=7cCh)%y(k)S6QWXmT~d0Uw#3-KJrC()p@bMYFN zKxdAlac5V>j+)204d=ey=-r29@jX8!Sh|?xRw#2rA1d{jD09*apTypFsrcA_eTD@f zse@qyZjT>~J*x$Y?Zp7I7Ke>G%`Kjw^|RXG(yToZULe^rKLPBJo0MwybdesUAk8!w zd8;Cl6+CwIBS)%kJjiD^R$oh8%Y#nGsfJ?Xo|Gw+9a9rB=4Z zB)UZ>%4>>NX2!_I@7JvZb={4FWPxRQ$GWAPq2XPTicd~ZEb3fk?krPzkZmhm`xFrFczKeBz zs{F<{xab#o*T(R8-}Zq`_A&nB`ZifKe5*F-llWEtx8~Ls^*5QKG`FRs5Rn-Q0YM`D zahf+Po7~4m>ieF{I|2eCau`+zk!`n(q!F@cu@x?yGS^?wN5t7z)|JsN6_G}KjPpJ; zd*BNeRwYSEi*su3yMGL&;~d=jaPVblH1p3IxbQWW#Z4H#SMB%(_YTfIU%}5d-wEmB zd!=3qYrT5XYGv#qRxxhiCrX)~AvjH~WT znvwASk0<-00~6R|u*EBhi)csy9+e91u-M1|P+X{4|L>$37fz>j*zr|bnngDj6qNE^ zJg@kydJU$2E;Oj%lq%#j(VvUQ&gJ2+jhLWy^AL#9A~ft78nhi-vdz)(j_aAQ({qSh zkIT)B|J8Uy(YWOTtgH7O_a9EdI*O~3DT^Nq7qm@3uz!+9Ch-i#RNN zVo9(O!XVppJCnx^p|af|MmKt#!H}R#&_p%WG-dlqCnL+oEz)Un(=>7PhXtU(aN*Pm z!uWw@Z7usbLwI>RTw4}DB#~hA*Rw}g@@U%dOEl#!O5Pi4z~eEMQ{t25y;$K34@ux( z#DLe;qP?{Rx-XIbIw1>;yPZS@s9(oZL!f}f+x#O2iN)82M z=G5t=)S0;$=}>reu4X;LifR_!Xh}5_Z}F2fzZwxS?$M#|Z|?5or^`qBDh3A~(WffV z&oy95P0_3P6K6Oap?MbCj)^!=*|rchJV6XtRY>@Sn(in4+6eOAof~IJK5_JB{kaI* zI>}}~J0}p@Ho0rxRZV9d%6BXfHn2RI`K=(HcZB)o#MPN3GoF7t z$A#Or<=ti#k-|kSx_^gYTtxfZe7+fcXiJnBc*EJ@Mr6|=rED8+(k6b`ymyqEUi7^t zQUlxqF;?S*jhZj{r7WSf23nTR(l3DJR>CfQS|`d>F0CEFj^3*j+z!4ECS~LD*CA)Y zxr(n$b$&jcoaMG(E6#xm!zJzUKVIuprWU-)8u}YjO>aV0c@sBMJnK5)1$@|fXiLvd z53)xJz3F9!k8me?`s+EO$1TO`T70Dr7CD={CN;SVY&qC(WtfP3QHPnn10ZNvo-*Qs%Nnz62M(1Cu>?wT0W|b}%G^xuBdh&Poa8**Gl8vHgMs(nKFoMHy` ztxICkS0Lu>IDKrA_|9%jtLe^wXJJVoF=}o2L<>9;;bR1vC+3_CqsykAxy`6O#377dOivjf)Wa#EZd2QrP3&c0&2SvA&E7C7-m5 zAx*!xnjNWaHKu9^b}wT06BK)KqZnO>b9 zr~XO=joDdiI6wL~lkds2XK2;;n)G^X-QrJQ#O+`1{m=&^lXKL)eN)BEJaxlD%dQuM zx#gvs)8}fU(xB<*g+Z0-an9a!{gPXO_q_>!hb(UTS*B1!yP*`HD(Go zXgt@y01Nep$d4uy1}cw#g8zvC-kYdQqBO07f)HK^fmbxN-@=n(Qy4K&msd$S{M$J4 zjb?eOA{3O0F1*%EZB+y0pBlM(Bf>vdj@JKy6ayFzT+@YkqZ=0J66HtJ!stb9UHN7O zn_&vHW7>PQ`ExjWU&9fu$34j+CNFAV*13Z<6dh$1BLW_Y_2r97Dj6d@&xeQNU*!_= z&|1GC?aw(o9N>)3fa+F?PGym2~S%F zWInA9p&R?SGltcAEX29qr-a=vIgX*?fMl}{hqGm=|0nC1EM}~{!ONZ(cCK#R&VWQ^ zO`1x0Nwcqn9ZCwD-#^1LrHW>hB+O9eM4}84bkY)OHmtF8y5Xt>;>^8YI3ZBd7h}`^ z(+h){l}z!^1+etZ?mSyNB^s_wZsMJW@4#RT7bm}nidld1JY*uiE>+vMvpcY z3wjIUT49>M)ZImWr}#k%JI!zW*6+J^$8tS!q7* zO1P~yj#A{6kxmWgj8W8c zC09VpcX35ux>nVHlZ{`Kh4-GaRR|5=_h25kJwFf}+K%?d^hE#fl%66VV#7oZ2j`Hz z5|HL>&2}`{lB=Yf`2nfM;*p!QZPP~w3Cv(y^M+2sSP5k4fuS2`p(aggry+oZ;V8?z z!Q)-af|Qs9oQ+Jee%Fl5=;dJ2Rrkpa(CzbyZ}Uwqc7DV3&zaJ^Qa5E9LJfY7ZpK3c zw4aPkp!3yvS->%#RSgSN_R{aat-B|A!m$sVFCOcG`T#c=hR<;Rxsta-bH@sq;+tkV z3QG<)&2L&)p`}^eglWX9(h;|_iHc>guuR+`L2THuBdWX3F=mZ81GH(%YF};L3?nv< zWHQ!_5g+*IPaw<*oi$~U>_^c}WKcG>d~dA==%xzIr}r3SR9aDPLEX-zGygyuOJ#+gc!9x3m~ zk1DYB!U(w#Rz>lK7B^Y`gGFizgoXFH^+JjqCs^Kf*`+2M9qHp=_{{#t`-7mzg%adqm;H>0I0=z> z)Zj4VqEtl_mNTM1z3EScsoAf3ZSpHEzb5U690T8oU+)aJlwZ^$G>-hOzM7Zh&$vbg z@Db_DH$@V+u?eGza_^w=?jY*d+3z<{;EtdN(xbL$NOWjqv!f9oQYtqsKKvn^C+CEi zY*CkuCeB#y#xxiBj)}DUi~nk5_=Tdwh)G$a6H!XJx*Xf%*$p$t3}f~idC4YUt~CD3 zPvi4jB&FDRtZ@!l7|Cu=@L?X*xAqdWp3osxI}c}lMRrik2vEdhXJ>a2ykC!n%3J<_ zJjf}(!gYIlzq>0N5D6e$n!U@M8L+7MYTD!tOx_6FxyJBg56OxYm11ttVlX z-SAT*!P>DwZih)()m!civ`jg)*q3jFPGbf9&<{2kA2hMCB3qZ-F%S!x@0GHYT#@Q2 zyd;v0RyQbY=z2!LvbM+PcD8Rxoirc13ViV0^nJ*gMZ9ffTJev~($--(z9A_ji<8ls zw==>1R!NKg{#T!EYQ1bWI}FM)nU5f@pDbG9n;Cmw?NpGgcFkx+)&fZwpS7lf2anGZ zrKHOrQap*<&qmfxyoV=2q$RYbXnBr#xv36uVW1@4T<4_+N(3?w0Sm zmSc+l+kMl-pTbehOEmsiHaTG;I&?qL9?Seq`lDO(ZQ=~qSSX$~NR=8sZ38Cxvf?iX zqg!jE+8JyJAv^?^;gmVu%{S~?=9hEY)zPG8X>j_CR+?|n^E{5_f zKzopx&Zz6h)kCDzM*V}kZ~obx?d-@fTfH{3leZrkFgW>K)gD=2@qN0`} z;w_ladf+*M&s`F=JblXV$KfA4@# z2be|;I@;)I!~;$^kdPS1cvb^9qE_9&bSo%GeTPwJZmA8oW=mJMGft4e@h z!Sd8)w5lw4!@}S;TFr2yO4VnFH38T_dPbulfvlaA=H2k4+@Y>ZZy1r*C-$F+womRFGH_wO2P(7$tjqkBCMkE)+CRPRRf{=$Y>XW|uxAkdB1qfredl za{m{2Hq>w+(Eo;_eKR+rMjYD~8&H)vWibTF95TG?^qV|yJ;*Ntu4Zfx6TV>f7QG$*!gTa9h!#AxgjH@5Zket*ULWoACjHCTIQt+jWg zs*zSRU#LC1a`j2 zY5*l2TTm0+Z;x4AVZn=2I;vdqJ#t?o+#(Wq>4JJWb2&Bh_~g?i!K`wF_Cj~-+fQm~ z<>7JE1Kc_GB{u#X%r~jo`(pqHC0?<_2o*#Q6)YAqXxiNTj2Um12Z zVAe^4E?=PbgXOKTsmLm8cfc!aH(GWVbU6^aL8_aj^{I-&j?j1n!-{H&N>V9I2>Jin z(D;DaCJbrLPTl&ZRE68P7IUjjN|Sz2voDEa1g*i09_|-2S=63nXhGBwr2rIwMpfaJz48z8`|JBkJ3X$kJI7^F zTsDRE{l&>pB!#c&OKp|E4|UpGf|4A6u0C8R!sb_Jm3UvgN3>_T94 zYF3-xlz70eGS^fYBRQ}cp!Wf*PB4@~y%JFyJ2tQrTwCE)lQO7LF&KL+ud|I0QG9%vgACmNOq5(j4aw1ENAFE zHW(d+*aDg-PuwW55GaXIBo>vl{AffR69M5i@#p>^dC_qm|5g&A_PVdVP{iI|CRf~e%t&GetXn#q zXmf~lmsrH3jJbCYy=j=8V~;MiN=;TyPFZ@qBCMF0p5)N+AMALB;=4kaw zPLC~|nmoqna%TP5?PScW$dSEkFG1N-bvGld9gfz&Em=zmO_}Q{wg8dxs@in)Sn1He zf=}y0XXT z^Wyyu+P-W}Kv6!-drO#bR0hf=38r{^S?0pIy|TRax*n5_!^gH_O^Z3dJrHi+ar#A6 z?aN+iv@%bNCtG>HL6x6_8^CV59`yI(!otFCX8+=uWgsa>;xX?q7@eCVp53baC6=pR+` zrP{t15ai+Gp`sP#76=kABvTJB)vsBl=M@x;F;SJFYAnEdC)cXId7;(hQN?dOZZ)Vl z$j&T|C*pgLvC#dyJ||S{#YlYh`T{Vb5@Sxs{5iCuEszsrAovs*_$?)xNJ6fpX1NPdNp!a0kqPf0j^bX?||#ZAu>IDBtWy9*r$K;|~jiNl-?OrUKdKgxEso zop~Xkkf#zDDV|=Hz6PE1G2vGG`{aojzn+tRY&S?!L`t&rNeMb|D{~F8CQQc_sM1AP zE^xM;J1c}@CaeT%sIE*#j1*nJL5j;yR^3iaKd2d(^2@m!Jm#bkqyjMc9!F;VUUg)E z{LM5N8pGx%yf-c#L@=e4q5+9J^n>lN%JOqBUwUFy@HCTmNA;a-{h*TEOZ1fimU% zWh}-^0DOtd)<{@k&Q*?XxqE|jMQ0`V>75+VOJh-d2nP1vJw0vDt%U-FWyZhb2)Nf+ za{X{syPL9)Bq|ah#w2j(Z}+zS(Uk0G;%{^k(eQ`Y_VL&|E}Ms`S0q(F^5Nb~P+U~T zcfKt6aQ{n1`EfHH19-8qP3wcy_`E#_>Zfe*vh8WmfwRG=eHldlIe%3nEpZ#D-{Pl7 zDB$=W`S#3XBoC49dMN+bZp>7(nr@+N7}DLgnS7qWnJ1vXagvx!cEggT5N&yM-!!ZzbF}Ra)7-8{|$D(UfOKV6)Mr9;-+e;3v{{$ehIs-SC7NJyQk?D z>{WkmSKB_MKwA+LxTO2&2FL*t0#?>~T+hLB_q_CzK~+5A zQ9+kIo?@iR`%|`#gC;pu)J1R}!QETh{C9kso?bHSW>kiHHieNE1J@};tpJc1$#_*_gvR|w2zJ5KLAE`7Q%jS3rQt&zmgrr(_a0Fk_vEEJ~aRs$lch?fY;wkN7+ zw#4JspPxA~$jZ z1Zi;M7V3I>ByzNWDrG$@RIyAtB$fVPn)Hl0RnYE=%&yU4G}T;b@YXBg}n&>8^zWu5{-v(yE@Ot(fs@?>mww?UJxLlGmcu7jSh$A~2eT!bP;bzT9&_H|mpo(?19=dWA&ovMEFzzx8H&a&%7Uen1s(OD##~7U zTiK;$v>1!%FbTNC5CaE!%EqNUI((Bx=rL?r8(+UaN_nufranFpWaDr2(_cqjD!bvc zeIb|b@OC;YH0oZrj#XNiH8pbok(`XD(wabk1~4)1)ws>b5S->jd5u8$sn$BLZV+{*O4qj?l|}EaJDg zk)q~WRSj2$I2?uM#F(gQ3w|7iJRzg-$-uw?EQ4m}t(#9nug6wmuiF!=o0T0ujP#$u zvZ@o`v$vW2_MIqll?N_778V5=P0rM79^}Qwd63^#Rvs{dcH!Q~A6Dn)<%#Lb(N8N? zv9)Tax{Vj1E${=?88`|%EI=g>dyJ&KPt5Orq{27l{{Qe2I{Uu1f>z|(1{6qpj4As` zaid;o+T7A|=N)u(KDxv`ewNX~Xlzl&qPRe|l4E^!9=5R(H1h-NyM@IQShpoNr{y2}q zq(MiLCfRv(zebMk;!9ETByom66mgw87a!#Kcepjm-C3-X&S5mUj_8CEsS->EY z5V3O(yc8Pzv(s+P%1Bn1!Foo(zkU8A)CGE6`WEp%^lG4(_`PproXIQ32ea2ej&nQ>25t`i#DLd7BmzN_u3ulO;c=n5^Ju8&(<`yvI+%RnJu%6?XMMYC5WoFPX)U@a}6~hlhU(5-m zonay?@I_r{_4=e>pe%Oc&mGtt4NLlq9{O3J1*Ak0frF^*Z9*((ZSxAd^bNUZME8oh zLtIc*ghY>iPDqx^iK@NFU2ud6*B3=&lSPN;Dakp=tIff5M>|#y5WkJfzwz3H`>v(t z1LoLi0rBGtAo!j8%Cwg4ytCcSl4O4ggEU~uiUCL2*o#QJ_Znk;n#Sb?kOurq?)auE z@nqn+%7^r=n+}1^|COj?8$xg;kzopAx5|KFl~+h$B!Yy_OSfUthQu}|aJQqF!~otJ zKfoD5117PMc4c@8FaKZyy>v&)nO!=CTZF0*Ru=`{ZSBbhrm~aIp^k=Q-`8o|k#mDM zCpW){J2t)71>1ayU63K*J9Btbyinj|9e~8pMHD9CNO1f5Bux06C=7e|eiL6&adv?E zdJjtw1^B?mr8n@th{tbu+)KNs#-VN6jBSC6uqh@f^@y2?Ix3S{~Z+_-Sj-Hkj|DD zcgPLphd03>N)nM|(;5&9$)ScvG@T#4D13kLaVAH0vN?D)nF~ zm;<_58|#@*0>9L_WQJD<=@Ii!vWfru6p`H|TKepAF1S}9r}tqrOYu@gI?C~1(wI4} zk754&tGDeq79G3NZg?#XDXg2Vw5Pzo@LF=C8n5T|J3Z`$SHj8+zh2E*|0HsYNquEx zQ;kBZIy83pGRJ;{Sd5wOWlN@@*nfage07@fgfuB%`WK|GIvE7OQ)$SN?k#;%NNYX5 zoUVJCZjYDf!-gArqLsN~Rw56SAq4+6T+PHeo0j^9UWBc&p}Y389&lc|38km?oi-s_ zMMHWx3aA63Oc2k2a>0}zWf!na!h-bz#@=6V@7Fv^t(1A?>5<8kdIo=7^vSrIfuKxJo7UR%<7eGoC2tF7^U;5zD+(VPSSLr(~AMd7Z} zG0t^h-^+a~KNZ+7=6o@S9{>On5WClBtKS@Lpy1mBY@db}vTchNUKq+`BXoaHZ%6ju z@SqW*L<&e7Q@p4qwjU6L8!9=6#iHdonz>h6FL`~KJW7PwS}6&MU`auZ?w2*So2dIH z4*Hv1zUA|qS!FbQpi9$(n|BY~^qDDho8Jh)yF`vy`?sM`pzGFzDWa)PA!$km$zXeN z>Pe^c7f{Dgf8c(R@nab}t}Av}h?_Wk7fq%Z2TE;rsR#>?3wpZX#kGo=;&`Vj$$*Dg z;m;W#^&eYqWs#I@vd10?f6|$6@<3VG?cOLQuofs$A!s!P*Qu!STob!iV#XOo(EA|g z=Vj^SSnTD5&I8>rYs_4DZa<-Op#D+sA^5ofFi zE+T-KNs)-j{o6dxgXw(ML9GzFRly@TVR?!@L{oA$^+$`+o=^Y1f4sopI;stfW%nVW zQS>ov&x1`fjM4%I-UHOcRIVpP;?@@3s+XNJ4(aFpH}+BH`ZyGQx^Qe-{9YIgu;a(m zVG2$p$SnuLmRNVqZx$ zU$+>xUw7gfSaf{$%~W8Oas-`S^P^%^&Sp2Wqvd9?eLQk!u3o&}&jsbZ^&ey2F3`-w zSweS*<-+1Ew1$X5lj1ALoCJjR|Kd$R1q`M~45PhBGa@_6A~5nA34=@kFPQtU_!`eD z=?~b}=dJ*)@lAuZ5LXtf3)m#uiPn;Mp-9W>;OGOuF;3adDWO6|8iIh**Vs$k&&8{< zrm_?Dfwl5$eDzA=1~(TF$PMim`Q;AH=~=l!(P2iQKPMNVe!@T74^ zDUx9WG`k$Ob^ zyItbm*e#x0wgX1Gf__YS?69vCZTXWI_))n zm@-ZK{x(in?w;ug_OKv_}F;$B8o(@&iPKh(5jC*j(&gazmWqRxYvfl!JV z@n!*g@Efr>GB~v{-Fl|vsFAqqrSRPS|C=G`!4?fbT{W6HS$Pl;_VaQ0qX4QaYv1h! zCaTjrMXrH$-k}XGsh#x46XvsZohuD)4Ds#;o=03bc07m>4hIae&_tgqMi%VH6YIEA zQSJy^ib(-LBw*j8QU`BiC83G_3vAkBKhUEufQVmZ2FN66I`ag|o0uQwehy-l>@X?L zXageF=w9Db_S7 z@7sMIar3-&;eLCGXKqe-PU8ZN6+4tkp1*=}O5IPrJ)?h5jI*PMLRg-J=_Xu?U|<>x z?pjd2*o)uE17W+L5AsUd_v_P#4V}uRQaI;bQ>$Bev~W;$%B|Pw;Lq-tcX~l*5Ac5> zKOU#`yJiWRBFtZ8!29-BJIJB~d3dy5%07u zN&rFPwW%vsQDqMX{;B8cjq?4W+-ShMBjlt39o;Ua!w|;QMq>{{o}!;{lFOjC7wXC! zoKXV^2hJwK7scVK0r7(^pEhyUJT9*R@+Jcvyqt~zOKT$yS0GBch}$ihXga|vQ{XlW zZ&`j|_*Zc(>icy0&3f!cyL|tafssrsQ9SrWCJZ)=hp&{&p-3+awjFO=yvW;MtAmZq zNc0@zi~)h(SNiwhI&T=Ul>wU?aw$`hLiIkufi?wip927p*Jcr?iIhB0mH9xnIZN{` zClwR@?!$ytvg~J(!PNc;sxL&}qX23D8ILyWcX~`lK4)wapcy)*Dh_xq+`PX$GhcqJC9MC=&Fo&C@C!!oVUzJ-y#IYehC9(tz^q8=ZO(DIC4KQ=!XnZCC-hH|10|YBFh)IbTzf$)3C0f=LzRF zzypVSpnRb%tZ)De_m5-@L1YFKi}PSRt%FB(z>%{7sXb64J10FiGW7F&KRP8mXi~ej zK!>qN4_{2!n5^CcN-R5 zE0(ew;{~AWfKPz64Ge6-wc874K<*W;-~HCm%&zR-&R6`-)`b>R7kU9)9K-;Sx#VXj zufC${J?s+)5+r)$=lash%^vM135%dN$JgqDF1nS z(I3yDeh%xG9H~p&Xu^h7Z($Eyl6XUhVk1hRD;qz%^vmI2wIgPEcB7pFK_k4-iWQzY z8y+|+NdLzh?Q6oTFF0v=Z$&iD<0IOeWuDy8!NrQH^!8?QH2Hx7h`~1sH`W6|ni?SO ziltYFbD;^GfF`HW>x4Vtv{ajwN3GEJPbmwJMF8^*cad+LwPC3^Nm$x%_ktbDW1m&? z`myd~?Va?kZLC!|)@AJInv6EMEG%C1&E*C+7dDaWhQ`JaZmrKNuQyjJ5WI7OUQ;aL zw-$Txv-tDecB4mChp~^p{-pYb+=yYKwN&cB6SI>?Ch&wUmZW#@?huFGTS0R09cyk- zry)I!AKpG;z7LVoM7EeW@GjlyWQq~oF>2o>5!7Qs`(yP*H|L1I9mWXeShMKEEWtgO zOp6OJq-{7%z_*>cVk}XrDIIE{SL!Fw!Et=@CVbJsbhZxOJ6hl3s^e@1B8)M9jl3G@ zSa5yb&i8f9t!`D?GY=ojgo%PO7p1TeYx2Uz;Q7VKK#|bWqSc-k4iRZ-^P54uCsVww zX0WNaG7_=jQwId7L;tI*;y1G&2Fcu||F=`_B~(Y>IMplx-bVujzuFDsfj7i@NH5@0 zYP}!ccX37q3sWXttLNzc%i9WNicdo02N87*Dx282Ykl#ZW)7qPS$a%OElkEi-h(Ca z_ZjI1RdF=Ci{ytpYf^l_ZJ#jV8a7?K;Hw^ykD;No*}&n*P?lKI_gcr-Q_`2EoevHj zw`(yxIc%17K5$7BxVFK5>`ixKj2H#xpR%ML=y85GHm5Wp;E@aD>G06qI!A2C#C(&A z!^b}2`O2yJcP4f)$6F-Mvr4O>`1LiQJ4}8P`!n<=4R@maJle~Nj%(U?;@R1!_o?Ed z{kOtR4r_Hr&eY}KY9d;f-i%=atK=)~ZKw>f`xo6%a$4k`4^V>HQF#haf->AlHO`2D zzS}%ff>uiuMr8(oluci+o6o~rUWXS!c{#02|{3=hEaf&rF_d(hZ;P|bdRD@Z6n~g6E8a>#DN{@VtCh{FwAl; zOWX}EAs}FnLXG+0B$v9wq4RQi9PpZVx6ULu8*YEve1*er*!Gm;VpFq7AoT3_hWj~P z@9tXQjIrxO+pAxYazrD2v-qO%{DJyG97#tzW2Fy66kn(yN{E%Ja*ZUspC48j zX})DtjcEX7+@)Nq53FnhK$7?t=Jq0J9uOa4po;t1-2A$JVP2 zxp_f+Ufl7AG4?vNa4xm1j=h;@nC4Kn$KpuFgpg0Z{k`F>sCI)#e`s-$nQTcuBQry! zx=<-AiGPo=$(H7*xF8ugYLGNY15#5atnPcb6PeF3%o&-8-56S)4g|^tUx{eEt!>xo zBnJC0tns~%16MD^E2wZBh$1DZ%q-LQze(VP_%Y_dg9nF+Xh{6Q z%ku#weUHXpm_~q`p^BLAPQIn&u2U*;{mbHj*QR_KgUpe&==h;L{@^7Re*_)}BdO{O z6SLo05RJs59?9Z`qJu56n}GpieAQ7=>IS2KF7%ypYT4SHafCQOSDBRG^a5$hQd6R$vBy-%<=vtJ`m`wISVwC&FO zG@Fs|iZLlaNC6_};1#OO;Mmal2Dx{e2*!>1?~F3_YaItjcsdaAqu+2V7rH8a)7I0& zneu{B+*jd=)TY$ms9pyoAXcP{V}X^8dD*#=$-^X=q7-P<=*p62V^Bk2jUWk;1RoTf z`0+Sg$$tciICh;u(Qx3ow9WLgW+!TISTL(v;rU!fL~^eMB+0NzCcT2#Aa)lUA1A79 z#<}7^e$H*GHR^n7e>He8Vx?MFv%Ag&5lr-Fj_ZDZ2nA@yd=S0Ikc1nVLw*lXF(D+) zCTp8N{4lAYdVG+E)voISFJBmZ*X|+KQ2D2cG!~vWQ2oGK^jGTZy$}=#QF6d4+#xu( z@XRSKe%Eqed*;7$Mn$Wb?bhrlo~<-=b}OFMMJjLveEfE0&e8B6kY7vwqWI;=3ZUVm z6guOr6@Av&`Lf4svO4;_x;Sg=l_WMUeS}^7q-;SP!dVm>mJ7Uks}Sm1Kul-2rGh`L zyepr(+6l|x2TzH`f1D_Xod~Y~eZK02&{AE_h zi7Z&Aa~NFiuF9V?G{^fg(d9VScY0$gj3!4NjyN)Q^KEToFO(BnE8L|c%I7{tS;ybO zIAp!^x-BL?Vh`Qln>_uP@_Zksb$WVJE*|i0zCzY#)!ugAw}!Tr5dbPzk3rB&?m~jT zyI9f_&_Qeor`f$yiXu9koAHI3T1vxnm>dref3s~W12~$BGct3jpRxkZ5(z8$D<}Hb zClIz@YOjX7`i=$WbZGJRX{tJ-HyjN{&L&ZMAM*WB%PcK--2@i%a~R6Z8=~;|?x^IU z^@(cME;0U&JF|H)J_35lyzN|5+zf@WaW zXV!W1oKN8C#qv9_2N?9fnj9C6K#OU?y2h4*oY5=iNP3-pkX4LyhEcoE2q$o0V z4zIks>8T~eBh4PZok)U{r__mhG2r(IaXMrl6dx%_bQ`I7WS?su&tnVX&_ z>-P##_qhwG3;|E@tCtSrqBH95&(z6g2guLUvwCzB4@&|+F$u+4agWoyH+!6#0RSd$ z#0Wh$MDq6#|A(!e7$WT4QvGj@b-LHWybcLs&ye?9{`jq}m$WJ0Sb7~-`G`EGR9kx1 z+y!|Lq-nHPb1dx8A&hZpfY)bVS5og6$9*xz?>AQo!IllM2mHlLY~Z1xQ>JLVaSJ0C zhx!yGwd=n6@(j+h554VpF@k2*A!7^@EHNfQCj0BNWKC!Fn46v6kjmxIxh5L?X8{`p zDB#F;VqCwC;yzw(cc8Grqeo>o9j{m`te;aBCQj|!Ybn9liK2=S0zzO-w9(J_B(ow< z?8Rm50@G$4{^7mn-Rd8KJgG0Gcx&61f;6L5av3lKQ<}dt_aZs~Rjj|kp z1P56W)+Ezte?`%pBo}ERnJ2XjGN7itS3UfUuf3u2#H7q@TwtoJC#^jFG7bWctM|R`5YtUEREBJ8i~Y_xD!6P^DgOu_g0JhN{U%#EViXsl zSJkIX`!Jm&?`bU0KGWN<-aE_p#Vi}Gww~v^aW%3!iUW|K*CantChY|`-P;7N+YaHZ z_KZdbu*6}4H$5v#gfAce(&bzy&dJXo+>dV3acnN>q!AOhqWiaJTawLu0o<9NudomW$f zTq#j!sOETd@SLASSt-8g!cF$xbb>?x^-1fmzLw-4QuGcA9zX3Gw2&7ixQ?Q`JA1TC z%Ao##Hn--4R*C}lDqnU^)f%Kyv8NbX1mv-ccc6`b;eAeUG|X}9cm33lx#q<}R66l> z+?m8^SOMmtY2|6qH6L6Cr~kiX-p{t=c#lf*_gwowyeX9VrC3AZo4hC?qd{1|&7^YBeLwJ_RxXmdQY8;eGXmB~Z+#CQ$Qad)!|IpJ;0);(kZyA+ zlodLaMA^Jrb8&&L)=1!)h+tj31Gs9;g01$rm%lWIwR}lS)pZN>X~Bdbbgw$dE`Lt_ zAf*^zVnxEL#B=tmDuU;%CG2nHw!qae9^x$McrBy8M0>ZNVK4FaOPIMy7{a}30GVTG z%helO{mqI<8`<#xk(sPZh2<=}9;d^)>nk@jMlNM?q-5F|pJ^W%-z#x}dhMqBA3;lhQ$@*2cr54h$Gp4e z)$rm=Y;bHC=kwEw-!)QT>=8)9T?H1pjlwWmQ78jx9azWa$9C&&2B_V`eCE2rq|ZG) zmmVKXwc*VbPT;0sFWY48r_gkp{THVdLTgV$&1i2ITnj?QNY*K+!BH4~2vfP?EI2bOwjXFDl2m7SXji^L zZOP{Gn!q21|M=E}w9>Yc$~0O@VZa15Em;K?gZ%fn01n2rU^?Yxf|7oVL@d615VBh3 z>c%5OTnG)F3wOUwO(ZhJ+#F`PfRKQk>RID=rA?m8foE1=WI#NsJ}r2CaO7R-z%dYX z!;u=YW$k_#P>ubKZzq`SVbkjwDf2K z3)Y++H^@7WH@lWleVG05?v;|kM7V30M5=hpqxAZOUyR_vo)H;yzU_Uupk)cJvv$8I zV>Xd;RGoGW|HYuhOP%yn*i47i532{4h*f_|cKYF5;V1FlsqD1kVBV+*D$?+oUz8z5ye z4XhnnIP=@f^cBEEn;$iJxs(AOU?A8;kc>Sm_5{G&r|N%#(Hf7CEFkElft{i-Lw8+z zd{;$bSGm@T;ucJ2@aq1GlE>g{40Xzb2Si1%n_f9p`{RWPJ#}uFT(6#RbMv#unOX}h zVbc2v3J3ETF%>Pi&zY!$qqy|A$vtgh@21kfSF~Y*vM(5>gJ*t)871Y z8+(YQv71Z@)?Tn7fI|OCjwAZi^G*J$PXcvjiIWMV0UYQ)oJqR4U~UNAJUd-RIo*gf zVYsvROAft|xZM3l{8?*ePK^nB&d#$GHD6}WCF;4W%mzMTQP)=$w{LbXKG^q)(g97i z2`4fwKAE_F?X+n7d`xJC6o(x#09AkY4OVqI^DcE#i}zdG;Zv}VV2778xxS(OfV=O( z9geij-CoGYHMMP25<~@cXvmdCjGG~&%4e8A%~>cfg#d#PPgu|L8@%s-x@wawBaf%D zid~aYr`OY0#J48GBmswl`l5-{`I`*b&oo3CG$^`NXe>mjMZy-UKG@%WF3P>6QFmGl z-kR0kfiy_P191_9UK_%b_E%P$kV)y|WNC=rt7%e0;nhP%XCMCw6aFu&%uXWq{BJ{P zfkU%yE?6kb?f2wQ(fdxT-U`fA?ABH5J~)Z`DU;aE0!*FpSD8W#C!>^P0$LXbGXat>MHkJL3pIJmsAD||YPG0)!o`I#MIs9HIK@{|s znS>FzV%5B+6s^-?rjoawT&13O)lLp zF&I=_D0EIHXS+PBwu|IF^zz}TA=)Q_3xW9LCM0j%ka<$lO#oG*%>4#xzr1K8(XH0Zv>3 z7Py}%Do6YkAm_E34$&V^J{Lxead=NPEM*T>s*AaO`*+bvW;ZghY4-_xCH* z(6Y0CZY^`(onMfKNd#ZHbTQ&AV!>G!-ntQ~l=JDP9l%Wu-@xULZgXM2PPGeAkS!eY z?-;j803Zyz!yqOwX~62@cU$B|0(Dk?M*_xb?C9hu;Mb1__(GQnsMFhv9zfFtP6 zE36iA_2IkBQ8y{G%JX zNQ7A=LHZx2Qw*?Z@2Y0DbwgObNh&d$djUn1Pvy&Wor6H?@ynsOd24rzP4*7g8O{<` zGIw)&ggunq-hoL;!PR_dqk5)iQ&}(%HF}6N(}=rG`yX*DcKr4BkcW*-D`XKK7qfRj zLEJ6Zu(Co0aDy5yQ;qpGbE~htes13gXLV4uhEMML+5m1In02up1DuQ)9ywBS)ujK; zHuiJ>rdofo0ryy_X6itbX%Yt;bC!c_enh|>Al?N@Hix?-R(cQRkw|;Fkm_tsQwifc zoQb$vuSHw6I=I=B`QJ&YP_V@-1W`lnU0z{+V$@P~lz%|}B`pEb1SN>5uN!}nK zH)D42LGTAY5*9LPJjmzoUR%Y-rZS5-49bU@LjR;>mp+^qEC_%E7Od^)2`v~FI5KJW zLsYOYHlW}RKq_pgyT}(*r(T=XwYnE00B@L+RA6LmT~0i(p_B#04*y*OoF{T8oaJ!rviBI62ui zXT7}J83!oF#EV-PxShcGCjg*SgZs^B4@R##{#B!>a-M7;2evNQ7cV&!$(h&G)G2~PB#6zNP|Aa*lSxb)I7IZWZsPIp}U#b_z0r|_1~ zyCn9X$G!l0X`GXC9CO#NG~Q-D+-X;M!L&EN>1;AqS!R!rQ08-(;)eyKOKw6&8diS^ zzupmn(^G>J{5Vk=*fuE5#f@4!B3LFauG{e@pr2T zcL{M$0_{IroMQ?LTX_f*C0$tz+6$0~yMQGVQ95So=cI+&p~Wx+VkWA(cOKbC6HTUH zA$sIpLh{zifc+Mu^fC*|=t~yqHmcNBT?CkZ!QFim5fzHrbPlSjk|3pp+Ds!>Td|LH;W z*Y`!bvQY-Q1J}P8!{}mz6w`WvIdo*`eUGE;4mHa+!ySAvDTu4q&DQ;R#gyhyZS)}W zP{U%Pa{~yI@-z5r8a|feB~m1#p6%2kRw2W}9fXdb&0oj`9nTwf4FdM&XjIKu-uRE`+c9HSy!o9~6#7UD-9v+-bTvd{w^{SY7D}>Wk*oq7Mttkx`LPIc( zBJBA>5QsiNcC%wp8>u1WZ3=#@tW>n*fpKjeM*;3_{}Z_m?RSf`KFF@M%j+>x>X%iq z0f|_lYKdSFQwQ4*B>froxkATvO|oVP0gEF|cq9@&W)3#)?YRQZDh}jHwKG zgt^0en@E;3$pmh5l$8wHNmiiRV{y#Q?g=R%der85PH4EvLI zzypm@uM46p#~mHE0#ql9EfLa8D3E*1a19(^bcRo#!Jl$QuRiH>e%q&6V<1Z7Sm9A+ zO$Gmrji`w?a%QFMQP^h3vpkORKwtnr|d}5D)j3?Eh*`gMMg)vvYu3(a3fWV9xhUtKVn=9t z47vTTykW}F^^pI+Ak5q8}0!7t_+UhmqFH-yb{T4_yQ}d5S#pdRR!1jo;pKpc{O>S|0%{lhtE4L205@p zf_b?#M=Qv-4z3bUr;MCTK$DLDV6n4oKBu$0OZyUIxqWpwGWb>qV`Yc(lRC~cNAp=& z>O#xL%JXV4DdO>-Gj{mzFJ{4=;KFQ(F{1&LMQ1_h-W-dFCdv8l*c=7ten`d*){%4^ zg&cy@9x_KleY`AWJ_qs-(#f^waSX#5e}ko~l`b(Zbwn?rjJ`;m;)FY#B>P*&KRA_A z1!3-bs}s1WXMk}rJ>jo#E%El=w_i=#G^}YB$A(`!AH6-NOY2)pOF}}`Li;)-Do#Wr z%61X<;`LaKAYKd%Nww7?Su~1-NSnl_xN|Xx^yw@HDiJ|1ErS9UbpARCD%Ng1fS;7AEjo}@`6BQgp zVY|-Qi&UC(PgFCv~6#?V5A)3D)Gj~?b`KMy; z!t>OlES`1c_>Sh?!8bin7WB&dDkT>Ol#JUzk8H_(5s_=P1haMb0%>40IuPCkKV11| zmDx5!pjwW~X6X__!njVCQY9F==K{~bigOvKoT<)eqDi8+!G<`Vr%Sq!4wMlQ+nVj{ zMmEV7pOj?z=(g`}8y?G^@KP|6ao>0R{HrkaZ>pBhcRmAFcraT)tB`to94bTW>R%4n z4PGPTM3ZI1 z2;6dCmk~z&Nwl}P7r-QJICe#Mb~UDdS{Y z+`6GBQ5!_BBHX9DJX1WlK`>LSKje1e?HyyKP7*l1(|cU8xrSF^Qi}phQiY&7cLf#)tncp}j-2+(4!4j8|ma|E>V6!m!=TeF5?= zwJu(uyn!x4PvFCiPk9~HwrdY|*ezI*W)dQw+OBSZ7Om2()b+r?N@fLf4hm+nIYmNR zEr^hZL8tC}Lu0EvuD)2y_rp6KzHIxAstD*T8gNX|WHRRUJ6NoAGK%%U;jf9G@O`{Z zqBKvX>Ve+MrhXnUu1yPcn2MPyN00Au9QL&T66@96dSi`=KY0B+!=rcB@(U^NB{&I@ zTULa9qi^n)Z=SvZQvVQM8SESaZuXw+I{S7^?Ve+M!gAV>_IER+S_%DOqWOOWhMQI( zbikU-lG!bE@BdOChR9M9RTOr_R1B0LtK#{tR=uKD%~jv6SL#!oZs((~qo_mcSekHf&}yP?6{B0N1}=XXc6W*Tm|HR+nLQ)$Dk zHn@UWid6C0cJ4;EbUU#?2roGCA#-Fz5OxDCsxw_xqR=$pGwkjVi~kFYFm%s> zPM%2uGJiyn1OQ(mV02-W95RH(u{mcq1is#Q^-kFNE8trE%_-R`M*+7|so=)->&huh zr4q{JNleid&z?SojAJPPt?qnj*L~Z2P$+XtellJfQJIUh11C73Ut?40p0KdHV+GrF3vMQL*>$F1>A$Uv8m?YNm{pC z)i-KLl0?DUr(b0J#<)N5pmY%M)Y%LQKGFF<_|&-fKMdu)AX+&!S8`9z7U9ulb}>Ih zQH1j36kTINU29#ZYWV@(#753_x^Q(|Og99;I&R&#f#sVw5QH4(W|Twh6XQIOLF+srdc&hEM|6Xo zB!!&GWHB>6t2%v8hS33IYoW?B+jd~Fh&QTL<$^1>Z>e|POh!4yK_EP+d_pG;;^gVm zIDPgZ=3=X7ZOK!64OGcL2qV=v1aiqwAQ$J`EkDV>QLiHkBEq-H_5Ls8ZA1QUL(^e_ z>(|iW6P^FV`^E`>-}B@5&y;gGdvX$f81Fc+SBNvybE=U00o+TD>#Aa{tgYeZ^(CyW ztf=_}LPY`w1EIhc)0G1{(nPt8#d8m1YI+)B7$RcG?>oKM4_eA=eTT6k*-IS7Xw+&# zFn6$N?B8Sj>w#=N&6qM^dq({sn)1wU-)+J~Yz#UqPTDC8ZwK!TmhE@EMqC#O&< zO{nYrNQzp*vMktykQRwm!gpioRaDp4l?54wvF*FsT{qg!V>pjMW*R0=EiTgS&eC;l zH0e$$*A!p|CCRtdY{F}K+vR?S@yfs!8-WG|T~FpHl791he-f9z{Mk_~H7vd86C#1* z_F4n^tfM-9zYFwB93lvPRm}U96ulIw&v1f}KvT9u{cb(p4(jk=HZjTUCgIe31IyX&gc@q-{x4r5z3 zk~G=ZB5uY-t-67LVY?1tY{8)mo?JLh5KnYmbQ>`4hDGkTLezn^&4!T8=9B}j(^&&Q zP`T!EIquI?zzjmtOnlE*P;cXUzdNMwG%yVlx}HV`pQ!X*KdAn;&i~OUmmP${eAY#! z)?guNSYB_SRB&0W(%tWdK{~yFBJSrBp8dclph&?MCnr!Rd?BHT>2d-`i|*t&4oteC zE`_`Ww)W=#w#>U}6g0y`v)NP*D=sLHZQF*M%^b+7_p_gf%}2vF-3j>gFh0_tGz#!U zBZaT0>>J;W#<%}q97`WoUXD&wYk11(nqEi%n^>4DB2MCM%S!2g~6@P*iLz`bsSop&UWlO*MpGkA!hTD2BhnE zoz7PoHwXWTj;2uo*RQd_C(1wd7f^lfOXFJppz>V0PR6m&@B-MDfwf8#lf?{N+dvfG z4VV;j82AW7j<=nC7k0{V1|iE82w<%ST^y0XiQ0rS>YGRF{jcqB6FnEwjLzSl+uC&1 zv^^NtlV%|bJipTr?uPF(16gQ*8V7hHeVm(~c=LNy90Rqarg9la-I#`1DS*D@fPl{EFiO;aS-caCeXKqq}VHhw%7&|!RZjyDf`5Y|E8YqA= zuefHuSWr&Y-mY^TPzKM&_kFaQEjr%jy&7~tKZuaFwPzU^XN=S7w#poL0{!X%SbgqG z<4$F(JVuZtsg(*bA7Ie31onrlzud{Go3p!>Nl9V|TC>pKJikLSiSs^i4m%+w%1%0U&K zdS;x<-=%vBzMcfadkjFI(Mr-ZFTiD88yig@j%Bd8G~8ZmpqO`A%$-8(mlUE;_zLOf z=lhkwBE>BLHdw$tAa|6w*bcv^-5l})o;5h|q`@?5b*_s|xtRnnic_qtSJizcs&m^k(DFhSSOW|5CB#X`S$a~g z5C)78wq+mK{X_zZ?byiVvS>9LFwD+p6A*hLYieCrY^w&)fl%v)jFE)%#R4qb8VGpe zax#wsuY2E92fPHU)jGl`MzN5CWtrJgf4H^66Qf>o-@0ev>(@QvgyMdP2~So)V0b~u zA~Rsy239LgOcpb69ZMBmPg3|%93cpO{^lMEK9M-8o6YcV48P?;=eknt0=IUua?bij4ehke_4~kM9$^?0yzXzh#xt^*pPn1#2V2fO zHp=A=tYZP6sON-Zgitx37>L0_%ef9(exQDkF7Np{Z3m8>uS z8U!zjqPxKJg9xi#@T5t}`A817W6QHlyW13o8OH%U(XoS1G$sJO-h~vDZ5ebwTY)Ij zyG6N7_e)shM%NugQn2Da0o_lW>L`-p61Pc{^iHwuHD1OJ3OoU+*=QmR!n?uqLpokf zxvtUOr?|CcnS|ex95Qzr#1LXR` z`6tGGJP!_hJ&h2+R{u>*_sOuEXC1m<@|vrdEWF!mO@bD~GG9Ahlf~!z9vY20pIhTT zwgXFG^E?k8;S&gZviQ8^y#`+YZ=$xq=UB=m*?2O1WRH6<_lk}^e4-Hn*xLF)*EQra z&ZcJqoF7J5S#J=y&Bv>0I@Z=#(QGwfS;q%J0Vkldd5tD?HWzVj330qe%g6dg13LG% z6};}I;n?J@WA<5wJLvo>r8kcIhz_Ou0zQ!dIQ`Zi8s-wstq-C&MTXAjSSFIR<9=<1 z+^0R8-8F|Q?G4(AjM^yrgFa|N$)&242{15OSh^BqZk?6 zR0S(&nj9}$Ub&4R2lp;EM)0b&juUPNo=AX`{n~6Y zX{R~K<_8AfaRyIx-@zwZ$t(_I+R}CplXi-n>#)cS1*1s**p`8&7vaK7D_GlTs(XuL zQvPVLAf*_WS8mZgBRZgY=iPfnIzda51dWZl%1!SFuijGN$+fuNPLe&^+?xQ{Zr^E6 z?oo3S=#D#hB6Hjc3`_p(lQ_Nj5TYnl_todVbkr%|x7|Z=JlC-ZpiMXM6<|F%wn67h z@zPQSwT6%R=^`>57lg4YNO2VbaBlVl?=8+1L0Qb0C7=m#jar=mCCUL6cznK5Z=&At zU>Y45cazLv^K1mtgdlfyB@nY!x!t5pw|uB~8s zz2137NCm(!46w3tTSl`;59fdaK|+vIHiEr?*mEwu^S*#5%|XBu7zLnet-&VJQrG)k z$Fc3Lk1~hN?S2AJ^uWM3@#gm&<@I;(_G8SV&pNhpK)K#3snd*YLVkMXMip0=*5HQ` z$D42*2cGX?Wp!D(o?*P^ocoo6kIo`4brksIT}{)`tTzxbKa;tbY!YdjVy#+7qvi9N zxvw>(iO9P);gk3K#FZtULG1LJ(6(p&!GVPE~ey#^#Kux!SGZJ8{# z_KxF(4RJi7@zq-!xctg0nqG)vAq&rIV0CR(x!*w@tj+b)l<~X?esw4i8}DvUFY0%9zVO?_@Dk4zl{%l^mF*F&;K!Io;b@!putE3+|PQT z;5($wc4Jowd=A0Ox;A3E#BP$p76%jvYmESxuC3zw?G0FTiNJ55TCK2XErPm#0LAsB z;M+TMzoQHS;(I>)R!cdR7lc?@-=I7DbZdiP9=uEhIOU%DUC@4j@qWCn2M@m4r{9aO zUtGe!{LKHtuYdN-`+4PE`<+_~Kj%6uI34?CKme5DzP?kS_z4}bhE}siD9pVl z=sIK@J^0!Oa!qmBkg$cm4~=rJdx>#CVp2Xwowa_FGg{vmYMU(dIc{d%xD#C&w~i8ah_iTe$qnIxf9*jZg*1W?ThSFE+VW z7^2l^s^@LGRTM^h!l!`eI^xfbS_73@6IDh`fW_?&V4RyI>jumxm&;<|)I4MwapN8I zV~iih11xjg3Ebm)h;iy5FNpi)2#Zy3scVyf>{r5T&jrIc#nq*C)S3al>xoB{i^P1U z@powyGEP8C=z1>QR-kXUQxyWRJd?t2ce_CUUrp1IqzP7**HGE0(f!&4S>Lx~ZYKpE z-P55{FD{;Be!6N5d(8RY7;k4hJDksVZ|imVcGm|F`a;U$7WbGeWN~}FhPI9aJBeUo zn>tL>!RmSwfAZ`FOce9#H-SzHTVPA#SlO7V+^X}O_6LV9=89XY@%o*2I?(D0wDq+L z)+;sTp7Q=tBx^@etma-keFC;+!VmTYPvr9LZ}IQnWc)TG7|?e+7J41No%KtMe|ne~ z#qmmnFN_mZ2!a&jK_vi6>E^PoD(oA#SG&$7zp4LJv5OP-OBK8tM2C~#wazmEPyR}C z$aBugd=?h-I*QwM*5iKJ1jJ>}o;ihVHlrMHzw;*C+v0rrKNNHBukiNcjDLU!M6bhl zw`Lf>!+76eCy?4t;uJFz1%xcFrWe3rp|=k;SI5~7;!d)D2jA}h-T%_Gt@6<_Pz@ns zb2zG!Bqe+a7EaBhNOuSTx4&Q6~4aVmfQ-hdHK#S;pCX0Tag((2U zX*x0hx0Apkc?g8@#et$Efoofsn=B$t+sYBgC0W{FGcXMU=@Ie}NA(F_ zv6#oHQ*($3Pm&&fzIxNcqo?Qa8&A)D z@h?5|hEMoW{I+z6P=s-e0=xQDDUUc##YA0wdBp7|VC=+d*&qP zF?b)U=SNYy``;VSp5(b0c=6gz{NSH^QaMAa8`EuQAMB3mX^nB2aj7rl+g@R8jQn5^ zsRseRUuFE`?)A4B-}s4lyyclnwQ79r(sjK3iA6kqY8KU|H`FA=byC7U!ww%t2|O0D zV;UHq-)=96s|hsRIPzBv*=F25Kb#4K_|Ht3LwcBg>?#E9e4G&bJCB|F2(XR?R0QTJRV&8RT zV4FCg^l>dbB+W8@gz;|}FS1yEM(gjIItxAY(P%WVI9tZasUj|3U&Tf%AQZzt3Mtiy zMQoWJ0L4Y(WHjW-D!Q)0)QtnfF0LKXsZX4k!Q^BKK^P7^KXMJtG6>%(wEPekmu}G- zOr$#DJ9>ATWIV(8DaNlbewXnL#x=&XjE^%u$S4eaW4q|M!zYLOUdFF6z8uHNwM-`a zxni;S^VMqQiDt6_)3WXi)>wFH*g~t-!t6u=kDr>sm0Rn$zP5q9YmX#h1z?;Y>pGa3 zEFz)%wMSrmvWCItBhGiw^@1S6?Cca~rpwClhH@@En4sn3@zZlSGdG17E-%4v1~5#U zXEwC+5!l|$_({gc7%wsYBjbk|*02`s>A1lsgnS?4LyRw?)49HYPB;60mY6HWRhlTP z0^6uoHWgYsj$mYX-u$2zcmB{^8BKQCYs*!bhB1H!yMIMdjEQ^}A;1oi;#t_4H-V!p8%Ndqi8i+k+@tT zpTok!98x-Tk_@*=Bx%a#=->@!PGGsR!S7OqlgU79r+4Kh`;n0AA!&i}bLiCD^XN4A zw+wOtb6A-lL60-u3FTy}>zp~r%kn{V-N3};B&wA))HXKQJqvv$4>&VtP+xf&^Q8hF zJ2{Q#uie6}N)3zC6R5HKj!KCXPuj*@xrB%y3V^n0?9k_rCgDxoUDH{t>F#5D;JL1i z#l@5AK4eoHVxcP;oImBdmzS0?RV4It)9}LWfaf@ZI_!M<^rmk78slq>&vxVGqfB}) zINw8z4>0~6IvwUajE^#Y3I_zQCvm?*p@?E>0+sbOcwP&pDSbvm5;W+3Ct()nV5K1* zJ~@SrriYi8E3hqdD22b1q;z5ykTo5G=rcnp5{5R8HC~R z!4u`^de>Jf_{s~H@${n$c>L@FYON5xrrA@QPS|O(9S0n--p=?4<0|9xjK9H{Kg>kq zfNzHJe#XCI{AqU+pJ4oLbh^ut)ov#+2-{?N3PBj4R;wyERFaNqSa9bag2ygVvnizyjGK?&gEe0xouFc-;b@$?B~GAq^?tUjQ zN04NZ@m9t=8Q;%%8zVdHbBVj|SI8GpU0=uKQe0`!ggtc{^;?%PYc%lK$r-%3 zbQ?D-bu7?<>RvE{W7(`Qj#0?Eh$iw_VICG;cu*zZbBPXoyV0j1iek*qPouN0Ze4CBXf7H*PV0kMSACAMN(iFq}_- z{$9pEV*C%r%iSb?mGLeN9lVZGI-E&2nJAahYPC?W)nL*M!P;vlF$^aMlK?t;8xNnD z!g{@hrPU3%EcziB&%P9~_{zmRCJI@EgkVsT{TPN0L)UkOPa2cs*qA645r%_Xe?Q9D zHf~pHc=pmOc=DlBc<975s-B`xcCckXDVvGTZ#O*okGk4E*4A3=5nZ1R@v1fXe>f$=SkRtL-=AVhf^gNrCbJA zZ>_`UJK_@Kkbn`htItdnkaHcnVKNZ+OIfU@ZV*6iSNLMOZ?TY901AjB+czW6^S^R^ z85dr?g{L1|M4ry;CvEkuw&p0%8FcZjP~L+&$N2k#A z+ZtQW2_0KBKUIQl8Uq1Pcr#5Mx~A_~t^%dW^@?=fw41}I#Fn58?u9GYm7_g%?v!*4 zv^8@RU^*L!z$ec-@Et2X&G_ex7a9MX@pFfP?=0g#qvLLW4IR4gS*dPboFIfQs?~MX z(KQyKeC;$2VN5NeSenGcb0r1dt1DGx9BXVnRX~ekIu#vyu3S=$KPC)E1<+)%YP(Dl z(eZP+EV5ZwU5`>Oo85Y)j&ELg8Bd-)iANS@(QNu?>*gkN)3^coegf!j4t@;uPR4H@ z1im8U*BKWXe|_B9?^p7%9M`4$O=DxDie{tHbw4)O(1Tr?fmS+!#gdI83-8j+HM&hq zml$8p0!c*2%R06KFrf=1M<_NaT7h{lmFRlfZiEg=1wwym={ElCr5kwWiL)qA6yQZE zQaT@7GtxDPM{29XSa~K#qsj_9O4nXo=S>cdGajImR;PcG;n>bM%TGFK5$G2EYp$7rMz-OiGxVhHjCRd z45T~2CoWPf7I-G+ksS6gvMmFRdK1rGeie@_%;4O~8TgGlVv~))%tCK>_N(iLY7Dx@ zk{yFP4?{b__jbk?8J}W2HSQz_p_JXUG%+E(VWV2%_v>z*g{K)7%&A2zPER1iVtDEH zI=k>_i*V<>+X{|p!gq3d5*f!v$RZS%*pI~R47!HIc3jEawr!&zu1By(UDo34FWp#G z@IC$58Jw6d!3#q8P8q26W&uyLO z{r}?Z8x8=11VunxMN*_h$%|~qZfz%-c-qXgO*?IGdeOh2#AhQ7b7D1PPMZm$Uz#_XR1DS|Y_U32tA_5f6YD2hV%X z^Laiy65sP+7$#CZX_QK9Xt$b>B#BQ^WP|HlWdi-V0#>1_YaB zs03gV{XGdXh6I<49z3EE!!V+KGWcQ~#I0ch@d)I2+=Q;F^c%sh?u*qUC=xE-%A?wB zJ)n7<_+5$5lGMPDiZU1?^-!&xL7P1Yi%=*NXgsvIol)5V|dhJ%bn@8-qj-{YGJ( zH~LX7g)Ut2Uv^dvnr;8xS({^^yUz1R*mbvzhBN2s`Tp+AuTU!+O>x zfMYRX*Xw5xNt%j}=L%S@)G;%bgCIs|OL2H~2%)>NlECvkgh2>Z)erUWm(j8NtD)C`D=k1m_1~t)k6R1G)|5VV}7}ae5ndUmAhT?FHI1J970(V(Vt3i z2yH{>P3mmGDRcP3ZQt_=P+iv$w+uS>cD-&^m)~}9;l=_6(g{o+&md?yaFw3Ugxp+5 z)^4?1+~BIJ9ys$Is<4MA2qMzyUNoCcvR@UFEc5pRuLUWd#^m%2f_4M9mP_0m`ym0D zff-LzWE`Vr9_UT-a~45}kty$AZ^uo@wD<7d4|gFJfj_^zj`wHh@bu&`M*9;exguOS zvBi2+I}HxkaR@@OD~8_59IV|uW<1Y@6}QQNajdTu5%>YOUknlIG<{D@pT+1v23HoA zQL49~kX80ed@`O#`!RJDIkI41GS1)MYK)Lj*||yzLga5*C!pPK^I@T}TEn|g9)ui9_*i_;L)^BZ>jp~eYXoHH!AA6e1yREE znWw?txlvf9NxVNNE*mm_u)SeJHh4sVTQA&V!`+OfsaRN9$9q@i@YLi8#xe=4`6@iw zf)ILl)`^mYR;!5^!Kx@qN0|pGhZa6I@g-SCZ*Lzel`@*mCOu%4e^#qiFgkhyql3pW zn_olKi6FQQMkc8v*6q@NtuX7ErUApy;rrgM|32eKGc{b9U&gJaRXja02*uJ-7i@IA zymc|z&~f;4i4GWeEQc1p7(vABXD3onRSm_J0)O^0P1sheg}%NFrY0tEeQqALo=Nnb zdQts&q7cP`1KM=FxYnx z`aWx94e_`MuM5^=(NzU2>lJ)3JBOJQIgDphD0&(KK}9SI@2nF=3C(7ML#SyQe^v)A zhZ;T>pPJB4B%vDyO6zL`;7wF2Wj=K$CZ{kwJcC)6Br&DLn@UfD}-1sEFr(Rz~6Id0$;s$1&XF2aGMC4Rj7SK+=9l? z8H8>dL94c>0rWhdtY=X(Yt-1?X=aUv+*+xM_pi+1^k^0*a>r2gRJv{3@0%zJdVb zQAD#*hd_3e6@}M-5OW0Ioy5op9vQ+zI^Bn%;W20gpl#b2$R5Y}56|QF?ORBudN!8F z5c*`iW(7)54#_8e3+BjEhj{507Ged;%-Q75wxkKSrz3fI>E8 z(|L0sGXSF~M10~o4xyavhu)JQ z1|i%&44Ca4$3Z}V8ivXL9@HGc_khF*7}s?Xh6I$IzzZ+Dh}=LH7cX7F)vF(4Wo3y& z#Q@#3U_?e?z%lR`fY#VK{*hlVA@rQC?Zx*4=$eMOWpV>{E4HcO#$pj4UYp0WlUby5 zpH;~cCF@}&JlbM2?LP9S1PSzY-}9QKKmIgF3w|ZZ57o@ z8S}SppxJB^fEr)BnV?xE5M7v~PZ5N_O@E(;sG9J}j-k`sy!!6!fz?CiVAfL*1U?MU~2j_ zYLyb&?KX19hfpq;aO>tZg0To$Rv=NML{ZeSVBjNYRUsO2SSQXQarPC&CtrYM_abQ5 z`Da7|U%R8V({ISK3_EV|ee7mpWHd2oK?psBdJl@R0larDkCAK!gA->_ZPI55?*q^C zJ-Ds|!!QwbWmxQ9j^KMlSVJ(wofw}$GS!2d1Y9O_3`0XB)Ep7!=Wb%*_8ffQhpK7Y zz8ku21dTFcf(T>qG!ipkfIa;(w9F{Nz~!GYP7`q**+Xd{0 z)a!NRvV)jDHG}i#-$y>bh>_6~&~yXKg*;YP3TQOy$mRxN+cpQ09Sq!#3B3-4q6Dpf zjNluATQ0y^nS--7PoI?#lQjtPc6fiCFbNBSfH+x?nAp(>WVsj_E+XI@ISEHe!Br9n zM4jpgkycgQzJ3Aa(kdn=r=ig6kgO&UaI(~CLC0}WSuUWkw8*Wesu~RscV`Rla*p78 zj09vS)3R{t)EWHno$ur7)hlGaVcsOeBV(}EiUeT+H?Lns|G)tH`ud?L>h|Vg5QYJQ zR)t;&P!hBzm4#NDfV+Ad&gwk;+8PH`P>l^Md~#|S{FZ6(!=v+0J28Sv2s``pB@>R8 zflJ_da-6IukpVq!KsEr{tp+Y%zKBewA1B6XzXY19Y4AM{)k+1mT9y8m;kXW2+CaKD zL(uN<#MlElg6}cH4Cb`kG_|M5YzbVx^buZu`STnuk*0Tle-@@;VTq>p;_Z1f>KzNR zMslg4BAW6HzKyHV5g~9I{FS8JkjKtJ8<^k#I>lS?Dl1%FqH2PEprf&0G0ZHMWk8ff z_)hSt-3x)BVx|iO8ErM)v7F2-rxB0=hfaWZXT52f$S*G7!Y|I_$)}#d$jAw-t`<=t z*ec}`nvDh|vY(wuU?4F_!@}agvU?l5bI%TDj^KOD)ax}24vk=D<_Y}b7eB|!$}*D4 z6rb8b5O6b&jE+-dt&j!txK4H)$Q?&dPnv_^(UgBsGlgCo@LFU%1;*fMX#Hbw*YgD8 z9Q|EH)ON^(CSsEO*buVcQxqA7sq@-?-Q2ZY44!1cRT2bUlAlxI{4*(NJ@C7UL<&Fo z@sIfZ8Xg)&vABY(vzNKqEGv%O;1B_7K_e5g`@@XQj)M*!%MpB!83s>ZUk0a6pTRpn z_%5z|d=bC*r9a?MvPNUt&;KUFG9)d=hdRZa> zN1h?e3j-w6B1!OrDEv=8BOLiw5s$%fSl-ulFCBMuEH(O5rp#u;W_~-lMM|HEraCVuv!dLgAm*N z{P8UkBdD0kA~KpM#|bu@j!nzO9%?zZA4!(^xzlc=Tq?nJT39M9;r#gzaGHkJGv}Uz zOlw54ctkd3h6^0O+mE(u5np}v%irvF5&I?Wc8kC}j*;OpeE)m@jUWB!e=#w65>r#B zQLA+f$eNHfl}H9lCX)n#g=)3JL1YkE@i-Jk;mya^KR6v&m<=P}fvA~KdxxQBD+?cwqlLZ)r;3j-zGcvFxg&Qw)n{bNr+>p$I*!aB|{R`+is;VGv znRFg)k>1^!qWesE*PzUBzHIT=Lg3y98w$>I7Y-Ttbu1*Wc@~{8pU*Y-Z zU&P|#0)Z6V0g$bi$qWqA3fX{}fEkoEsb$&Jq&5u0;h^!D}B5V1JKp64NvNaDhU5Ah%0`8T}s$`|p>b1x8#;uIr*q!=X^fqqw|;w$tV&J9aFGzRWR#EX9q;jLi;K zBipk@1BTs?+1bnZ!$0~HWHSAHUq`u{*p=BEyYoa3U^W{qmm9=KADzdWfBhPV?kj)s zI$nC|^H`>4^?iREfLp`f7pZXtYIfGRtU2ohbiH1qrgymgOtOh>C&-!xfv7SB5zsXm z*q?S7MC>;xHnRvkRn@qF{fE?{sw&m*;jOpcU^4@M{?%_l zmSn!Cquh0DJ6^z`&1&fwP#hy*6vm*=^^^r|M+dHwp&asApXzVxL(M!F}B)zxCRAJ?7>gRj=@ zBKCJ;)W8t|vVf_n8GQ9?-^4%s{ag6wfBHL`^e$fbjh6_b8gK4j77n6+7er0dIE=l0 z{b;vaXpjx7)e7>9^V~e_Gt;u5YC6aIQP+R)@DTX-%H!c#kuX1R;ixFJI)=n?5zOF?gZ}4xq!F{}1Af2||D0a9RKW002ovPDHLkV1gi$ Bno9rx diff --git a/images/avatars/gallery/Civils_H/Civil_H_65.png b/images/avatars/gallery/Civils_H/Civil_H_65.png deleted file mode 100644 index cde1758da22420b8cc358efb232f0406c4d427de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22843 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 VSf_K`#Ml4;002ovPDHLkV1hr}*wO$1 diff --git a/images/avatars/gallery/Civils_H/Civil_H_66.png b/images/avatars/gallery/Civils_H/Civil_H_66.png deleted file mode 100644 index 9dfaf11246334d3da3e8df131e05aa988b12b14c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21236 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

- -
- -
-
- - -
-

{ERROR_MSG}

-
- - -

{L_GROUPS_EXPLAIN}

- - -

{L_GROUP_DETAILS}

- -
-
-
-
style="color: #{GROUP_COLOUR};">{GROUP_NAME} -
-
-
-
-
-
  
-
- -
-

{L_GROUP_TYPE_EXPLAIN}
-
- - - - -
-
- - - -
- -
-
- -
-
-

{L_GROUP_SETTINGS_SAVE}

- -
-
-

{L_GROUP_COLOR_EXPLAIN}
-
- -     - [ {L_COLOUR_SWATCH} ] - -
-
-
-
-
-
-
- -
-
- - - -
- {S_HIDDEN_FIELDS} -   - - {S_FORM_TOKEN} -
- - - - - - - - - - - - - - - - - - - - - - - - - -
{L_GROUP_LEAD}{L_GROUP_DEFAULT}{L_POSTS}{L_JOINED}{L_MARK}
{leader.USERNAME_FULL}{L_YES}{L_NO}{leader.USER_POSTS}{leader.JOINED} 
- - - - - - - - - - - - - - - - - - -
{L_GROUP_PENDING}{L_GROUP_DEFAULT}{L_POSTS}{L_JOINED}{L_MARK}
- - - - - - - - - - - - - - - - - - - - - - -
{L_GROUP_APPROVED}{L_GROUP_DEFAULT}{L_POSTS}{L_JOINED}{L_MARK}
{member.USERNAME_FULL}{L_YES}{L_NO}{member.USER_POSTS}{member.JOINED}
- - - - - - - - - - - -
{L_MEMBERS}
{L_GROUPS_NO_MEMBERS}
- - -
- -
- - - - - -
- - - -
- -
-
- -

{L_ADD_USERS}

- -

{L_ADD_USERS_UCP_EXPLAIN}

- -
-
-

{L_USER_GROUP_DEFAULT_EXPLAIN}
-
- - -
-
-
-

{L_USERNAMES_EXPLAIN}
-
-
{L_FIND_USERNAME}
-
-
- -
-
- -
- - {S_FORM_TOKEN} -
- - - - -
    -
  • -
    -
    {L_GROUP_LEADER}
    -
    {L_OPTIONS}
    -
    -
  • -
- - -

{L_NO_LEADERS}

- - - - - - -
- - diff --git a/install/update/old/styles/prosilver/template/ucp_pm_history.html b/install/update/old/styles/prosilver/template/ucp_pm_history.html deleted file mode 100644 index 6362a0b..0000000 --- a/install/update/old/styles/prosilver/template/ucp_pm_history.html +++ /dev/null @@ -1,57 +0,0 @@ - -

- {L_EXPAND_VIEW} - {L_MESSAGE_HISTORY}{L_COLON} -

- - -
- - -
-
- -
-

class="current">{history_row.SUBJECT}

- - - - - - - - -

- {history_row.MINI_POST} {L_SENT_AT}{L_COLON} {history_row.SENT_DATE} -
- {L_MESSAGE_BY_AUTHOR} {history_row.MESSAGE_AUTHOR_FULL} -

-
{history_row.MESSAGE}{L_MESSAGE_REMOVED_FROM_OUTBOX}
- -
- -
-
- -
- - -
-

- - {L_BACK_TO_TOP} - -

- diff --git a/install/update/old/styles/prosilver/template/ucp_pm_viewmessage_print.html b/install/update/old/styles/prosilver/template/ucp_pm_viewmessage_print.html deleted file mode 100644 index 7a88492..0000000 --- a/install/update/old/styles/prosilver/template/ucp_pm_viewmessage_print.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - -{META} -{SITENAME} • {PAGE_TITLE} - - - - - - -
- - - - -
-
{PAGE_NUMBER}
-
-

{SUBJECT}

-
{L_SENT_AT} {SENT_DATE}
-
{L_PM_FROM} {MESSAGE_AUTHOR}
- -
{L_TO} {to_recipient.NAME} 
- - -
{L_BCC} {bcc_recipient.NAME} 
- -
-
{MESSAGE}
-
-
-
- - -
- - - diff --git a/install/update/old/styles/prosilver/template/ucp_profile_profile_info.html b/install/update/old/styles/prosilver/template/ucp_profile_profile_info.html deleted file mode 100644 index 69eda8c..0000000 --- a/install/update/old/styles/prosilver/template/ucp_profile_profile_info.html +++ /dev/null @@ -1,51 +0,0 @@ - - -
- -

{L_TITLE} [ {L_VIEW_PROFILE} ]

- -
-
-

{L_PROFILE_INFO_NOTICE}

- -
-

{ERROR}

- - -
-

{L_BIRTHDAY_EXPLAIN}
-
- - - -
-
- - -
-
-
-
- - -
-
for="{profile_fields.FIELD_ID}">{profile_fields.LANG_NAME}{L_COLON} * -
{profile_fields.LANG_EXPLAIN}
-
{profile_fields.ERROR}
-
{profile_fields.FIELD}
-
- - -
- -
-
- -
- {S_HIDDEN_FIELDS}  - - {S_FORM_TOKEN} -
-
- - diff --git a/install/update/old/styles/prosilver/template/ucp_register.html b/install/update/old/styles/prosilver/template/ucp_register.html deleted file mode 100644 index bf39990..0000000 --- a/install/update/old/styles/prosilver/template/ucp_register.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - -
- -
-
- -

{SITENAME} - {L_REGISTRATION}

- -
-
{ERROR}
- -
{L_REG_COND}
- - -
-

{L_USERNAME_EXPLAIN}
-
-
-
-
-
-
-
-

{L_PASSWORD_EXPLAIN}
-
-
-
-
-
-
- - -
- - -
-
-
-
- - - - - -
{L_ITEMS_REQUIRED}
- - -
-
for="{profile_fields.FIELD_ID}">{profile_fields.LANG_NAME}{L_COLON} * -
{profile_fields.LANG_EXPLAIN} -
{profile_fields.ERROR}
-
{profile_fields.FIELD}
-
- - - - -
-
-
- - - - - - -
-
- -

{L_COPPA_COMPLIANCE}

- -

{L_COPPA_EXPLAIN}

-
-
- - - - -
-
- -
- {S_HIDDEN_FIELDS} -   - - {S_FORM_TOKEN} -
- -
-
-
- - diff --git a/install/update/old/styles/prosilver/template/viewforum_body.html b/install/update/old/styles/prosilver/template/viewforum_body.html deleted file mode 100644 index d7099f3..0000000 --- a/install/update/old/styles/prosilver/template/viewforum_body.html +++ /dev/null @@ -1,313 +0,0 @@ - - -

{FORUM_NAME}

- - -
- -
{FORUM_DESC}
-

{L_MODERATOR}{L_MODERATORS}{L_COLON} {MODERATORS}

-
- - - -
-
- - - {L_FORUM_RULES} - - {L_FORUM_RULES}
- {FORUM_RULES} - - -
-
- - - - - - - - - - -
- - - - - - - {L_BUTTON_FORUM_LOCKED} - - {L_BUTTON_NEW_TOPIC} - - - - - - - - - - - -
- - - - -
-
- {L_NO_READ_ACCESS} -
-
- - - -
- -
-
- -
-

{L_LOGIN_LOGOUT}  •  {L_REGISTER}

- -
-
-
-
-
-
-
-
-
-
-
-
-
 
-
-
- {S_LOGIN_REDIRECT} - {S_FORM_TOKEN_LOGIN} -
-
- -
-
- -
- - - - - - - - - - - - - - - - -
-
-
    -
  • -
    - id="active_topics">
    {L_ACTIVE_TOPICS}{L_ANNOUNCEMENTS}{L_TOPICS}
    -
    {L_REPLIES}
    -
    {L_VIEWS}
    -
    {L_LAST_POST}
    -
    -
  • -
- -
-
- - - - -
-
- {L_NO_TOPICS} -
-
- -
-
- {L_NO_FORUMS_IN_CATEGORY} -
-
- - - - -
- - - - - - {L_BUTTON_FORUM_LOCKED} - - {L_BUTTON_NEW_TOPIC} - - - - - - - -
- -
- - - -
- - - - - -
-

{L_WHO_IS_ONLINE}

-

{LOGGED_IN_USER_LIST}

-
- - - -
-

{L_FORUM_PERMISSIONS}

-

{rules.RULE}

-
- - - diff --git a/install/update/old/styles/prosilver/template/viewtopic_body.html b/install/update/old/styles/prosilver/template/viewtopic_body.html deleted file mode 100644 index 8d7e26f..0000000 --- a/install/update/old/styles/prosilver/template/viewtopic_body.html +++ /dev/null @@ -1,452 +0,0 @@ - - - -

{TOPIC_TITLE}

- - -
{FORUM_DESC}
- - -

- {L_MODERATOR}{L_MODERATORS}{L_COLON} {MODERATORS} -

- - - -
-
- - - {L_FORUM_RULES} - - {L_FORUM_RULES}
- {FORUM_RULES} - - -
-
- - -
- - - - - - {L_BUTTON_TOPIC_LOCKED} - - {L_BUTTON_POST_REPLY} - - - - - - - - - - - - - - - - -
- - - - -
- -
-
- -
-

{POLL_QUESTION}

-

{L_POLL_LENGTH}
{L_MAX_VOTES}

- -
- - -
title="{L_POLL_VOTED_OPTION}" data-alt-text="{L_POLL_VOTED_OPTION}" data-poll-option-id="{poll_option.POLL_OPTION_ID}"> -
{poll_option.POLL_OPTION_CAPTION}
-
checked="checked" /> checked="checked" />
-
{poll_option.POLL_OPTION_RESULT}
-
{L_NO_VOTES}{poll_option.POLL_OPTION_PERCENT}
-
- - - -
-
 
-
{L_TOTAL_VOTES}{L_COLON} {TOTAL_VOTES}
-
- - -
-
 
-
-
- - - -
-
 
-
{L_VIEW_RESULTS}
-
- -
- -
- -
- {S_FORM_TOKEN} - {S_HIDDEN_FIELDS} -
- -
-
- - - - - - - - data-url="{postrow.U_MINI_POST}"> - -
-
- -
style="display: none;"> -
-
- - - {postrow.POSTER_AVATAR}{postrow.POSTER_AVATAR} - - -
- - {postrow.POST_AUTHOR_FULL}{postrow.POST_AUTHOR_FULL} - -
- - -
{postrow.RANK_TITLE}
{postrow.RANK_IMG}
- - -
{L_POSTS}{L_COLON} {postrow.POSTER_POSTS}
-
{L_JOINED}{L_COLON} {postrow.POSTER_JOINED}
-
{L_WARNINGS}{L_COLON} {postrow.POSTER_WARNINGS}
- - - -
{postrow.PROFILE_FIELD1_NAME}{L_COLON} {postrow.PROFILE_FIELD1_VALUE}
- - - - - -
{postrow.custom_fields.PROFILE_FIELD_NAME}{L_COLON} {postrow.custom_fields.PROFILE_FIELD_VALUE}
- - - - - - -
- {L_CONTACT}{L_COLON} - -
- - - -
- -
- - -
- {postrow.L_POST_DELETED_MESSAGE}
- {postrow.L_POST_DISPLAY} -
- -
- {postrow.L_IGNORE_POST}
- {postrow.L_POST_DISPLAY} -
- - -
style="display: none;"> - - -

class="first">{postrow.POST_ICON_IMG_ALT} {postrow.POST_SUBJECT}

- - - - - - - - - - - -

- - {postrow.MINI_POST} - - - {postrow.MINI_POST} - - - {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} » {postrow.POST_DATE} -

- - - -
-

- - {L_POST_UNAPPROVED_ACTION} - - - - {S_FORM_TOKEN} -

-
- -
-

- {L_POST_DELETED_ACTION} - - - - - - {S_FORM_TOKEN} -

-
- - - -

- {L_POST_REPORTED} -

- - -
{postrow.MESSAGE}
- - - - -
-
- {L_ATTACHMENTS} -
- -
{postrow.attachment.DISPLAY_ATTACHMENT}
- -
- - - -
{L_DOWNLOAD_NOTICE}
- -
- {postrow.DELETED_MESSAGE} -
{L_REASON}{L_COLON} {postrow.DELETE_REASON} -
- -
- {postrow.EDITED_MESSAGE} -
{L_REASON}{L_COLON} {postrow.EDIT_REASON} -
- - -


{postrow.BUMPED_MESSAGE}
- -
{postrow.SIGNATURE}
- - -
- -
- - - - - -
-
- -
- - - - - - - - -
- - - - - - {L_BUTTON_TOPIC_LOCKED} - - {L_BUTTON_POST_REPLY} - - - - - - - - -
- -
- - - - - - - - - - - -
- - - - - -
-

{L_WHO_IS_ONLINE}

-

{LOGGED_IN_USER_LIST}

-
- - - diff --git a/install/update/old/styles/prosilver/template/viewtopic_print.html b/install/update/old/styles/prosilver/template/viewtopic_print.html deleted file mode 100644 index b504949..0000000 --- a/install/update/old/styles/prosilver/template/viewtopic_print.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - -{META} -{SITENAME} • {PAGE_TITLE} - - - - - - -
- - - - -
-
{PAGE_NUMBER}
- -
-

{postrow.POST_SUBJECT}

-
{L_POSTED}{L_COLON} {postrow.POST_DATE}
-
{L_POST_BY_AUTHOR} {postrow.POST_AUTHOR}
-
{postrow.MESSAGE}
-
-
- -
- - -
- - - diff --git a/install/update/old/styles/prosilver/theme/colours.css b/install/update/old/styles/prosilver/theme/colours.css deleted file mode 100644 index ffaa710..0000000 --- a/install/update/old/styles/prosilver/theme/colours.css +++ /dev/null @@ -1,1163 +0,0 @@ -/* --------------------------------------------------------------- -Colours and backgrounds for common.css --------------------------------------------------------------- */ - -html, body { - color: #536482; - background-color: #F5F7FA; -} - -h1 { - color: #FFFFFF; -} - -h2 { - color: #28313F; -} - -h3 { - border-bottom-color: #CCCCCC; - color: #115098; -} - -hr { - border-color: #FFFFFF; - border-top-color: #CCCCCC; -} - -/* --------------------------------------------------------------- -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; -} - -.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 { - background-color: #FFF; - border-color: #E6E9ED; -} - -.headerbar { - color: #FFFFFF; -} - -.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: -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; -} - -.navbar { - background-color: #CADCEB; -} - -.panel { - background-color: #ECF1F3; - color: #28313F; -} - -.post:target .content { - color: #000000; -} - -.post:target h3 a { - color: #000000; -} - -.bg1 { - background-color: #ECF3F7; -} - -table.zebra-list tr:nth-child(odd) td, ul.zebra-list li:nth-child(odd) { - background-color: #ECF3F7; -} - -.bg2 { - background-color: #E1EBF2; -} - -table.zebra-list tr:nth-child(even) td, ul.zebra-list li:nth-child(even) { - background-color: #E1EBF2; -} - -.bg3 { - background-color: #CADCEB; -} - -.ucprowbg { - background-color: #DCDEE2; -} - -.fieldsbg { - background-color: #E7E8EA; -} - -.site_logo { - background-image: url("./images/site_logo.gif"); -} - -/* Horizontal lists -----------------------------------------*/ - -ul.navlinks { - border-top-color: #FFFFFF; -} - -/* Table styles -----------------------------------------*/ -table.table1 thead th { - color: #FFFFFF; -} - -table.table1 tbody tr { - border-color: #BFC1CF; -} - -table.table1 tbody tr:hover, table.table1 tbody tr.hover { - background-color: #CFE1F6; - color: #000; -} - -table.table1 td { - color: #536482; -} - -table.table1 tbody td { - border-top-color: #FAFAFA; -} - -table.table1 tbody th { - border-bottom-color: #000000; - color: #333333; - background-color: #FFFFFF; -} - -table.info tbody th { - color: #000000; -} - -/* Misc layout styles ----------------------------------------- */ -dl.details dt { - color: #000000; -} - -dl.details dd { - color: #536482; -} - -.sep { - color: #1198D9; -} - -/* Icon styles ----------------------------------------- */ -.icon.icon-blue, a:hover .icon.icon-blue { - color: #196db5; -} - -.icon.icon-green, a:hover .icon.icon-green{ - color: #1b9A1B; -} - -.icon.icon-red, a:hover .icon.icon-red{ - color: #BC2A4D; -} - -.icon.icon-orange, a:hover .icon.icon-orange{ - color: #FF6600; -} - -.icon.icon-bluegray, a:hover .icon.icon-bluegray{ - color: #536482; -} - -.icon.icon-gray, a:hover .icon.icon-gray{ - color: #777777; -} - -.icon.icon-lightgray, a:hover .icon.icon-lightgray{ - color: #999999; -} - -.icon.icon-black, a:hover .icon.icon-black{ - color: #333333; -} - -.alert_close .icon:before { - background-color: #FFFFFF; -} - -/* Jumpbox */ -.jumpbox .dropdown li { - border-top-color: #CCCCCC; -} - -.jumpbox-cat-link { - background-color: #0076b1; - border-top-color: #0076B1; - color: #FFFFFF; -} - -.jumpbox-cat-link:hover { - background-color: #12A3EB; - border-top-color: #12A3EB; - color: #FFFFFF; -} - -.jumpbox-forum-link { - background-color: #E1EBF2; -} - -.jumpbox-forum-link:hover { - background-color: #F6F4D0; -} - -.jumpbox .dropdown .pointer-inner { - border-color: #E1EBF2 transparent; -} - -.jumpbox-sub-link { - background-color: #E1EBF2; -} - -.jumpbox-sub-link:hover { - background-color: #F1F8FF; -} - -/* Miscellaneous styles ----------------------------------------- */ - -.copyright { - color: #555555; -} - -.error { - color: #BC2A4D; -} - -.reported { - background-color: #F7ECEF; -} - -li.reported:hover { - background-color: #ECD5D8 !important; -} -.sticky, .announce { - /* you can add a background for stickies and announcements*/ -} - -div.rules { - background-color: #ECD5D8; - color: #BC2A4D; -} - -p.post-notice { - background-color: #ECD5D8; - background-image: none; -} - -/* --------------------------------------------------------------- -Colours and backgrounds for content.css --------------------------------------------------------------- */ - -ul.forums { - 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 { - color: #4C5D77; -} - -ul.topiclist dd { - border-left-color: #FFFFFF; -} - -.rtl ul.topiclist dd { - border-right-color: #FFFFFF; - border-left-color: transparent; -} - -li.row { - border-top-color: #FFFFFF; - border-bottom-color: #00608F; -} - -li.row strong { - color: #000000; -} - -li.row:hover { - background-color: #F6F4D0; -} - -li.row:hover dd { - border-left-color: #CCCCCC; -} - -.rtl li.row:hover dd { - border-right-color: #CCCCCC; - border-left-color: transparent; -} - -li.header dt, li.header dd { - color: #FFFFFF; -} - -/* Post body styles -----------------------------------------*/ -.postbody { - color: #333333; -} - -/* Content container styles -----------------------------------------*/ -.content { - color: #333333; -} - -.content h2, .panel h2 { - color: #115098; - border-bottom-color: #CCCCCC; -} - -dl.faq dt { - color: #333333; -} - -.posthilit { - background-color: #F3BFCC; - color: #BC2A4D; -} - -.announce, .unreadpost { - /* Highlight the announcements & unread posts box */ -} - -/* Post signature */ -.signature { - border-top-color: #CCCCCC; -} - -/* Post noticies */ -.notice { - border-top-color: #CCCCCC; -} - -/* BB Code styles -----------------------------------------*/ -/* Quote block */ -blockquote { - background-color: #EBEADD; - border-color:#DBDBCE; -} - -blockquote blockquote { - /* Nested quotes */ - background-color:#EFEED9; -} - -blockquote blockquote blockquote { - /* Nested quotes */ - background-color: #EBEADD; -} - -/* Code block */ -.codebox { - background-color: #FFFFFF; - border-color: #C9D2D8; -} - -.codebox p { - border-bottom-color: #CCCCCC; -} - -.codebox code { - color: #2E8B57; -} - -/* Attachments -----------------------------------------*/ -.attachbox { - background-color: #FFFFFF; - border-color: #C9D2D8; -} - -.pm-message .attachbox { - background-color: #F2F3F3; -} - -.attachbox dd { - border-top-color: #C9D2D8; -} - -.attachbox p { - color: #666666; -} - -.attachbox p.stats { - color: #666666; -} - -.attach-image img { - border-color: #999999; -} - -/* Inline image thumbnails */ - -dl.file dd { - color: #666666; -} - -dl.thumbnail img { - border-color: #666666; - background-color: #FFFFFF; -} - -dl.thumbnail dd { - color: #666666; -} - -dl.thumbnail dt a:hover { - background-color: #EEEEEE; -} - -dl.thumbnail dt a:hover img { - border-color: #368AD2; -} - -/* Post poll styles -----------------------------------------*/ - -fieldset.polls dl { - border-top-color: #DCDEE2; - color: #666666; -} - -fieldset.polls dl.voted { - color: #000000; -} - -fieldset.polls dd div { - color: #FFFFFF; -} - -.rtl .pollbar1, .rtl .pollbar2, .rtl .pollbar3, .rtl .pollbar4, .rtl .pollbar5 { - border-right-color: transparent; -} - -.pollbar1 { - background-color: #AA2346; - border-bottom-color: #74162C; - border-right-color: #74162C; -} - -.rtl .pollbar1 { - border-left-color: #74162C; -} - -.pollbar2 { - background-color: #BE1E4A; - border-bottom-color: #8C1C38; - border-right-color: #8C1C38; -} - -.rtl .pollbar2 { - border-left-color: #8C1C38; -} - -.pollbar3 { - background-color: #D11A4E; - border-bottom-color: #AA2346; - border-right-color: #AA2346; -} - -.rtl .pollbar3 { - border-left-color: #AA2346; -} - -.pollbar4 { - background-color: #E41653; - border-bottom-color: #BE1E4A; - border-right-color: #BE1E4A; -} - -.rtl .pollbar4 { - border-left-color: #BE1E4A; -} - -.pollbar5 { - background-color: #F81157; - border-bottom-color: #D11A4E; - border-right-color: #D11A4E; -} - -.rtl .pollbar5 { - border-left-color: #D11A4E; -} - -/* Poster profile block -----------------------------------------*/ -.postprofile { - color: #666666; - border-color: #FFFFFF; -} - -.pm .postprofile { - border-color: #DDDDDD; -} - -.postprofile strong { - color: #000000; -} - -.online { - background-image: url("./en/icon_user_online.gif"); -} - -dd.profile-warnings { - color: #BC2A4D; -} - -/* --------------------------------------------------------------- -Colours and backgrounds for buttons.css --------------------------------------------------------------- */ -.button { - border-color: #C7C3BF; - 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; -} - -.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 .icon, -.button-secondary { - color: #8f8f8f; -} - -.button-secondary:focus, -.button-secondary:hover, -.button:focus .icon, -.button:hover .icon { - color: #0A8ED0; -} - -.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 ----------------------------------------- */ - -.contact-icon { background-image: url("./images/icons_contact.png"); } - -/* Profile & navigation 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; } - -/* 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"); } -.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"); } - - -/* --------------------------------------------------------------- -Colours and backgrounds for cp.css --------------------------------------------------------------- */ - -/* Main CP box -----------------------------------------*/ - -.panel-container h3, .panel-container hr, .cp-menu hr { - border-color: #A4B3BF; -} - -.panel-container .panel li.row { - border-bottom-color: #B5C1CB; - border-top-color: #F9F9F9; -} - -ul.cplist { - border-top-color: #B5C1CB; -} - -.panel-container .panel li.header dd, .panel-container .panel li.header dt { - color: #000000; -} - -.panel-container table.table1 thead th { - color: #333333; - border-bottom-color: #333333; -} - -.cp-main .pm-message { - border-color: #DBDEE2; - background-color: #FFFFFF; -} - -/* CP tabbed menu -----------------------------------------*/ -.tabs .tab > a { - background: #BACCD9; - color: #536482; -} - -.tabs .tab > a:hover { - background: #DDEDFB; - color: #D31141; -} - -.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 { - color: #000000; -} - -/* Mini tabbed menu used in MCP -----------------------------------------*/ -.minitabs .tab > a { - background-color: #E1EBF2; -} - -.minitabs .activetab > a, -.minitabs .activetab > a:hover { - background-color: #F9F9F9; - color: #333333; -} - -/* Responsive tabs -----------------------------------------*/ -.responsive-tab .responsive-tab-link:before { - border-color: #536482; -} - -.responsive-tab .responsive-tab-link:hover:before { - border-color: #D31141; -} - -/* UCP navigation menu -----------------------------------------*/ - -/* Link styles for the sub-section links */ -.navigation a { - color: #333; - background: #CADCEB; /* Old browsers */ /* FF3.6+ */ - background: -webkit-linear-gradient(left, #B4C4D1 50%, #CADCEB 100%); - 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; /* 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 { - background: #AABAC6; - color: #BC2A4D; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -} - -.navigation .active-subsection a { - background: #F9F9F9; - color: #D31141; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -} - -.navigation .active-subsection a:hover { - color: #D31141; -} - -@media only screen and (max-width: 900px), only screen and (max-device-width: 900px) -{ - #navigation a, .rtl #navigation a { - background: #B2C2CF; - } -} - -/* Preferences pane layout -----------------------------------------*/ -.panel-container h2 { - color: #333333; -} - -.panel-container .panel { - background-color: #F9F9F9; -} - -.cp-main .pm { - background-color: #FFFFFF; -} - -/* Friends list */ -.cp-mini { - background-color: #EEF5F9; -} - -dl.mini dt { - color: #425067; -} - -/* PM Styles -----------------------------------------*/ -/* PM Message history */ -.current { - color: #000000 !important; -} - -/* PM marking colours */ -.pmlist li.pm_message_reported_colour, .pm_message_reported_colour { - border-left-color: #BC2A4D; - border-right-color: #BC2A4D; -} - -.pmlist li.pm_marked_colour, .pm_marked_colour { - border-color: #FF6600; -} - -.pmlist li.pm_replied_colour, .pm_replied_colour { - border-color: #A9B8C2; -} - -.pmlist li.pm_friend_colour, .pm_friend_colour { - border-color: #5D8FBD; -} - -.pmlist li.pm_foe_colour, .pm_foe_colour { - border-color: #000000; -} - -/* Avatar gallery */ -.gallery label { - background: #FFFFFF; - border-color: #CCC; -} - -.gallery label:hover { - background-color: #EEE; -} - -/* --------------------------------------------------------------- -Colours and backgrounds for forms.css --------------------------------------------------------------- */ - -/* General form styles -----------------------------------------*/ -select { - border-color: #666666; - background-color: #FAFAFA; - color: #000; -} - -label { - color: #425067; -} - -option.disabled-option { - color: graytext; -} - -/* Definition list layout for forms ----------------------------------------- */ -dd label { - color: #333; -} - -fieldset.fields1 { - background-color: transparent; -} - -/* Hover effects */ -fieldset dl:hover dt label { - color: #000000; -} - -fieldset.fields2 dl:hover dt label { - color: inherit; -} - -/* Quick-login on index page */ -fieldset.quick-login input.inputbox { - background-color: #F2F3F3; -} - -/* Posting page styles -----------------------------------------*/ - -.message-box textarea { - color: #333333; -} - -.message-box textarea.drag-n-drop { - outline-color: rgba(102, 102, 102, 0.5); -} - -.message-box textarea.drag-n-drop-highlight { - outline-color: rgba(17, 163, 234, 0.5); -} - -/* Input field styles ----------------------------------------- */ -.inputbox { - background-color: #FFFFFF; - border-color: #B4BAC0; - color: #333333; -} - -.inputbox:-moz-placeholder { - color: #333333; -} - -.inputbox::-webkit-input-placeholder { - color: #333333; -} - -.inputbox:hover { - border-color: #11A3EA; -} - -.inputbox:focus { - border-color: #11A3EA; -} - -.inputbox:focus:-moz-placeholder { - color: transparent; -} - -.inputbox:focus::-webkit-input-placeholder { - color: transparent; -} - - -/* Form button styles ----------------------------------------- */ - -a.button1, input.button1, input.button3, a.button2, input.button2 { - color: #000; - 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 { - border-color: #666666; -} - -input.button3 { - background-image: none; -} - -/* Alternative button */ -a.button2, input.button2, input.button3 { - border-color: #666666; -} - -/* button in the style of the form buttons */ -a.button1, a.button2 { - color: #000000; -} - -/* Hover states */ -a.button1:hover, input.button1:hover, a.button2:hover, input.button2:hover, input.button3:hover { - 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 */ -input.button1:focus, input.button2:focus, input.button3:focus { - border-color: #11A3EA; - color: #0F4987; -} - -input.disabled { - color: #666666; -} - -/* jQuery popups ----------------------------------------- */ -.phpbb_alert { - background-color: #FFFFFF; - border-color: #999999; -} -.darken { - background-color: #000000; -} - -.loading_indicator { - background-color: #000000; - background-image: url("./images/loading.gif"); -} - -.dropdown-extended ul li { - border-top-color: #B9B9B9; -} - -.dropdown-extended ul li:hover { - background-color: #CFE1F6; - color: #000000; -} - -.dropdown-extended .header, .dropdown-extended .footer { - border-color: #B9B9B9; - color: #000000; -} - -.dropdown-extended .footer { - border-top-style: solid; - border-top-width: 1px; -} - -.dropdown-extended .header { - 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 { - border-color: #B9B9B9 transparent; -} - -.dropdown .pointer-inner { - border-color: #FFF transparent; -} - -.dropdown-extended .pointer-inner { - border-color: #F1F8FF transparent; -} - -.dropdown .dropdown-contents { - background: #fff; - border-color: #B9B9B9; - box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2); -} - -.dropdown-up .dropdown-contents { - box-shadow: 1px 0 5px rgba(0, 0, 0, 0.2); -} - -.dropdown li, .dropdown li li { - border-color: #DCDCDC; -} - -.dropdown li.separator { - border-color: #DCDCDC; -} - -/* Notifications ----------------------------------------- */ - -.notification_list p.notification-time { - color: #4C5D77; -} - -li.notification-reported strong, li.notification-disapproved strong { - color: #D31141; -} - -.badge { - background-color: #D31141; - color: #ffffff; -} diff --git a/install/update/old/styles/prosilver/theme/common.css b/install/update/old/styles/prosilver/theme/common.css deleted file mode 100644 index a0dc5e0..0000000 --- a/install/update/old/styles/prosilver/theme/common.css +++ /dev/null @@ -1,1287 +0,0 @@ -/* General Markup Styles ----------------------------------------- */ -html { - font-size: 100%; - /* Always show a scrollbar for short pages - stops the jump when the scrollbar appears. non-IE browsers */ - height: 101%; -} - -body { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 10px; - line-height: normal; - margin: 0; - padding: 12px 0; - word-wrap: break-word; - -webkit-print-color-adjust: exact; -} - -h1 { - /* Forum name */ - font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; - margin-right: 200px; - margin-top: 15px; - font-weight: bold; - font-size: 2em; -} - -h2 { - /* Forum header titles */ - font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; - font-weight: normal; - font-size: 2em; - margin: 0.8em 0 0.2em 0; -} - -h2.solo { - margin-bottom: 1em; -} - -h3 { - /* Sub-headers (also used as post headers, but defined later) */ - font-family: Arial, Helvetica, sans-serif; - font-weight: bold; - text-transform: uppercase; - border-bottom: 1px solid transparent; - margin-bottom: 3px; - padding-bottom: 2px; - font-size: 1.05em; - margin-top: 20px; -} - -h4 { - /* Forum and topic list titles */ - font-family: "Trebuchet MS", Verdana, Helvetica, Arial, Sans-serif; - font-size: 1.3em; -} - -p { - line-height: 1.3em; - font-size: 1.1em; - margin-bottom: 1.5em; -} - -img { - border-width: 0; -} - -hr { - border: 0 solid transparent; - border-top-width: 1px; - height: 1px; - margin: 5px 0; - display: block; - clear: both; -} - -hr.dashed { - border-top-style: dashed; - margin: 10px 0; -} - -hr.divider { - display: none; -} - -p.right { - text-align: right; -} - -p.jumpbox-return { - margin-top: 10px; - margin-bottom: 0; - float: left; -} - -b, strong { - font-weight: bold; -} - -.text-strong { - font-weight: bold; -} - -i, em { - font-style: italic; -} - -.text-italics { - font-style: italic; -} - -u { - text-decoration: underline; -} - -ul { - list-style-type: disc; -} - -ol { - list-style-type: decimal; -} - -li { - display: list-item; -} - -ul ul, ol ul { - list-style-type: circle; -} - -ol ol ul, ol ul ul, ul ol ul, ul ul ul { - list-style-type: square; -} - -a:hover { text-decoration: underline; } - -/* Main blocks ----------------------------------------- */ -.wrap { - border: 1px solid transparent; - border-radius: 8px; - margin: 0 auto; - max-width: 1152px; - min-width: 625px; - padding: 15px; -} - -@media only screen and (max-width: 1220px), only screen and (max-device-width: 1220px) { - .wrap { - margin: 0 12px; - } -} - -.page-body { - margin: 4px 0; - clear: both; -} - -.page-footer { - clear: both; -} - -.page-footer h3 { - margin-top: 20px; -} - -.logo { - float: left; - width: auto; - padding: 10px 13px 0 10px; -} - -.logo:hover { - text-decoration: none; -} - -.site_logo { - display: inline-block; - width: 149px; - height: 52px; -} - -/* Site description and logo */ -.site-description { - float: left; - width: 65%; -} - -.site-description h1 { - margin-right: 0; -} - -/* Round cornered boxes and backgrounds ----------------------------------------- */ -.headerbar { - margin-bottom: 4px; - padding: 5px; - border-radius: 7px; -} - -.navbar { - padding: 3px 10px; - border-radius: 7px; -} - -.forabg { - margin-bottom: 4px; - padding: 5px; - clear: both; - border-radius: 7px; -} - -.forumbg { - margin-bottom: 4px; - padding: 5px; - clear: both; - border-radius: 7px; -} - -.panel { - margin-bottom: 4px; - padding: 5px 10px; - border-radius: 7px; -} - -.post { - padding: 5px 10px; - margin-bottom: 4px; - background-repeat: no-repeat; - background-position: 100% 0; - border-radius: 7px; - position: relative; -} - -.rowbg { - margin: 5px 5px 2px 5px; -} - -/* Horizontal lists -----------------------------------------*/ -.navbar ul.linklist { - padding: 2px 0; - list-style-type: none; -} - -ul.linklist { - display: block; - margin: 0; -} - -.cp-main .panel { - padding: 5px 10px; -} - -ul.linklist > li { - float: left; - font-size: 1.1em; - line-height: 2.2em; - list-style-type: none; - margin-right: 7px; - padding-top: 1px; - width: auto; -} - -ul.linklist > li.rightside, p.rightside, a.rightside { - float: right; - margin-right: 0; - margin-left: 7px; - text-align: right; -} - -ul.navlinks { - border-top: 1px solid transparent; -} - -ul.leftside { - float: left; - margin-left: 0; - margin-right: 5px; - text-align: left; -} - -ul.rightside { - float: right; - margin-left: 5px; - margin-right: -5px; - text-align: right; -} - -ul.linklist li.responsive-menu { - position: relative; - margin: 0 5px 0 0; -} - -.hasjs ul.linklist.leftside, .hasjs ul.linklist.rightside { - max-width: 48%; -} - -.hasjs ul.linklist.fullwidth { - max-width: none; -} - -li.responsive-menu.dropdown-right .dropdown { - left: -9px; -} - -li.responsive-menu.dropdown-left .dropdown { - right: -6px; -} - -ul.linklist .dropdown { - top: 22px; -} - -ul.linklist .dropdown-up .dropdown { - bottom: 18px; - top: auto; -} - -/* Bulletin icons for list items -----------------------------------------*/ -ul.linklist.bulletin > li:before { - display: inline-block; - content: "\2022"; - font-size: inherit; - line-height: inherit; - padding-right: 4px; -} - -ul.linklist.bulletin > li:first-child:before, -ul.linklist.bulletin > li.rightside:last-child:before { - content: none; -} - -ul.linklist.bulletin > li.no-bulletin:before { - content: none; -} - -.responsive-menu:before { - display: none !important; -} - -/* Profile in overall_header.html */ -.header-profile { - display: inline-block; - vertical-align: top; -} - -a.header-avatar, -a.header-avatar:hover { - text-decoration: none; -} - -a.header-avatar img { - margin-bottom: 2px; - max-height: 20px; - vertical-align: middle; - width: auto; -} - -a.header-avatar span:after { - content: '\f0dd'; - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - padding-left: 6px; - padding-top: 2px; - vertical-align: top; -} - -/* Dropdown menu -----------------------------------------*/ -.dropdown-container { - position: relative; -} - -.dropdown-container-right { - float: right; -} - -.dropdown-container-left { - float: left; -} - -.nojs .dropdown-container:hover .dropdown { - display: block !important; -} - -.dropdown { - display: none; - position: absolute; - left: 0; - top: 1.2em; - z-index: 2; - border: 1px solid transparent; - border-radius: 5px; - padding: 9px 0 0; - margin-right: -500px; -} - -.dropdown.live-search { - top: auto; -} - -.dropdown-container.topic-tools { - float: left; -} - -.dropdown-up .dropdown { - top: auto; - bottom: 1.2em; - padding: 0 0 9px; -} - -.dropdown-left .dropdown, .nojs .rightside .dropdown { - left: auto; - right: 0; - margin-left: -500px; - margin-right: 0; -} - -.dropdown-button-control .dropdown { - top: 24px; -} - -.dropdown-button-control.dropdown-up .dropdown { - top: auto; - bottom: 24px; -} - -.dropdown .pointer, .dropdown .pointer-inner { - position: absolute; - width: 0; - height: 0; - border-top-width: 0; - border-bottom: 10px solid transparent; - border-left: 10px dashed transparent; - border-right: 10px dashed transparent; - -webkit-transform: rotate(360deg); /* better anti-aliasing in webkit */ - display: block; -} - -.dropdown-up .pointer, .dropdown-up .pointer-inner { - border-bottom-width: 0; - border-top: 10px solid transparent; -} - -.dropdown .pointer { - right: auto; - left: 10px; - top: -1px; - z-index: 3; -} - -.dropdown-up .pointer { - bottom: -1px; - top: auto; -} - -.dropdown-left .dropdown .pointer, .nojs .rightside .dropdown .pointer { - left: auto; - right: 10px; -} - -.dropdown .pointer-inner { - top: auto; - bottom: -11px; - left: -10px; -} - -.dropdown-up .pointer-inner { - bottom: auto; - top: -11px; -} - -.dropdown .dropdown-contents { - z-index: 2; - overflow: hidden; - overflow-y: auto; - border: 1px solid transparent; - border-radius: 5px; - padding: 5px; - position: relative; - max-height: 300px; -} - -.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; - white-space: nowrap; - text-align: left; -} - -.dropdown-contents > li { - padding-right: 15px; -} - -.dropdown-nonscroll > li { - padding-right: 0; -} - -.dropdown li:first-child, .dropdown li.separator + li, .dropdown li li { - border-top: 0; -} - -.dropdown li li:first-child { - margin-top: 4px; -} - -.dropdown li li:last-child { - padding-bottom: 0; -} - -.dropdown li li { - border-top: 1px dotted transparent; - padding-left: 18px; -} - -.wrap .dropdown li, .dropdown.wrap li, .dropdown-extended li { - white-space: normal; -} - -.dropdown li.separator { - border-top: 1px solid transparent; - padding: 0; -} - -.dropdown li.separator:first-child, .dropdown li.separator:last-child { - display: none !important; -} - -/* Responsive breadcrumbs -----------------------------------------*/ -.breadcrumbs .crumb { - float: left; - font-weight: bold; - word-wrap: normal; -} - -.breadcrumbs .crumb:before { - content: '\2039'; - font-weight: bold; - padding: 0 0.5em; -} - -.breadcrumbs .crumb:first-child:before { - content: none; -} - -.breadcrumbs .crumb a { - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: bottom; - overflow: hidden; -} - -.breadcrumbs.wrapped .crumb a { letter-spacing: -.3px; } -.breadcrumbs.wrapped .crumb.wrapped-medium a { letter-spacing: -.4px; } -.breadcrumbs.wrapped .crumb.wrapped-tiny a { letter-spacing: -.5px; } - -.breadcrumbs .crumb.wrapped-max a { max-width: 120px; } -.breadcrumbs .crumb.wrapped-wide a { max-width: 100px; } -.breadcrumbs .crumb.wrapped-medium a { max-width: 80px; } -.breadcrumbs .crumb.wrapped-small a { max-width: 60px; } -.breadcrumbs .crumb.wrapped-tiny a { max-width: 40px; } - -/* Table styles -----------------------------------------*/ -table.table1 { - width: 100%; -} - -.ucp-main table.table1 { - padding: 2px; -} - -table.table1 thead th { - font-weight: normal; - text-transform: uppercase; - line-height: 1.3em; - font-size: 1em; - padding: 0 0 4px 3px; -} - -table.table1 thead th span { - padding-left: 7px; -} - -table.table1 tbody tr { - border: 1px solid transparent; -} - -table.table1 td { - font-size: 1.1em; -} - -table.table1 tbody td { - padding: 5px; - border-top: 1px solid transparent; -} - -table.table1 tbody th { - padding: 5px; - border-bottom: 1px solid transparent; - text-align: left; -} - -/* Specific column styles */ -table.table1 .name { text-align: left; } -table.table1 .center { text-align: center; } -table.table1 .reportby { width: 15%; } -table.table1 .posts { text-align: center; width: 7%; } -table.table1 .joined { text-align: left; width: 15%; } -table.table1 .active { text-align: left; width: 15%; } -table.table1 .mark { text-align: center; width: 7%; } -table.table1 .info { text-align: left; width: 30%; } -table.table1 .info div { width: 100%; white-space: normal; overflow: hidden; } -table.table1 .autocol { line-height: 2em; white-space: nowrap; } -table.table1 thead .autocol { padding-left: 1em; } - -table.table1 span.rank-img { - float: right; - width: auto; -} - -table.info td { - padding: 3px; -} - -table.info tbody th { - padding: 3px; - text-align: right; - vertical-align: top; - font-weight: normal; -} - -.forumbg table.table1 { - margin: 0; -} - -.forumbg-table > .inner { - margin: 0 -1px; -} - -.color_palette_placeholder table { - border-collapse: separate; - border-spacing: 1px; -} - -/* Misc layout styles ----------------------------------------- */ -/* column[1-2] styles are containers for two column layouts */ -.column1 { - float: left; - clear: left; - width: 49%; -} - -.column2 { - float: right; - clear: right; - width: 49%; -} - -/* General classes for placing floating blocks */ -.left-box { - float: left; - width: auto; - text-align: left; - max-width: 100%; -} - -.left-box.profile-details { - width: 80%; -} - -.right-box { - float: right; - width: auto; - text-align: right; - max-width: 100%; -} - -dl.details { - /*font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif;*/ - font-size: 1.1em; -} - -dl.details dt { - float: left; - clear: left; - width: 30%; - text-align: right; - display: block; -} - -dl.details dd { - margin-left: 0; - padding-left: 5px; - margin-bottom: 5px; - float: left; - width: 65%; - overflow: hidden; - text-overflow: ellipsis; -} - -.clearfix, fieldset dl, ul.topiclist dl, dl.polls { - overflow: hidden; -} - -fieldset.fields1 ul.recipients { - list-style-type: none; - line-height: 1.8; - max-height: 150px; - overflow-y: auto; -} - -fieldset.fields1 dd.recipients { - clear: left; - margin-left: 1em; -} - -fieldset.fields1 ul.recipients input.button2{ - font-size: 0.8em; - margin-right: 0; - padding: 0; -} - -fieldset.fields1 dl.pmlist > dt { - width: auto !important; -} - -fieldset.fields1 dl.pmlist dd.recipients { - margin-left: 0 !important; -} - -/* Action-bars (container for post/reply buttons, pagination, etc.) ----------------------------------------- */ -.action-bar { - font-size: 11px; - margin: 4px 0; -} - -.forabg + .action-bar { - margin-top: 2em; -} - -.action-bar .button { - margin-right: 5px; - float: left; -} - -.action-bar .button-search { - margin-right: 0; -} - -/* Pagination ----------------------------------------- */ -.pagination { - float: right; - text-align: right; - width: auto; -} - -.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; - margin-left: 5px; -} - -.pagination > ul > li { - display: inline-block !important; - padding: 0; - font-size: 100%; - line-height: normal; - vertical-align: middle; -} - -.pagination li a, .pagination li span { - border-radius: 2px; - padding: 2px 5px; -} - -.pagination li.active span { - display: inline-block; - font-size: 13px; - font-weight: normal; - font-family: "Open Sans", "Droid Sans", Verdana, Arial, Helvetica; - line-height: 1.4; - text-align: center; - white-space: nowrap; - vertical-align: middle; - border: 1px solid transparent; -} - -.pagination li.ellipsis span { - border: none; - padding: 0; -} - -.pagination li.page-jump { - margin-right: 5px; -} - -.pagination li.page-jump a { - padding: 0 8px; -} - -.pagination li.page-jump a i { - font-size: 21px; -} - -.pagination .arrow a { - padding: 2px 0; -} - -/* Pagination in viewforum for multipage topics */ -.row .pagination { - display: block; - margin-top: 3px; - margin-bottom: 3px; -} - -.row .pagination > ul { - margin: 0; -} - -.row .pagination li a, .row .pagination li span { - border-radius: 2px; - padding: 1px 3px; - font-size: 9px; -} - -/* jQuery popups ----------------------------------------- */ -.phpbb_alert { - border: 1px solid transparent; - display: none; - left: 0; - padding: 0 25px 20px 25px; - position: fixed; - right: 0; - top: 150px; - z-index: 50; - width: 620px; - margin: 0 auto; -} - -@media only screen and (max-height: 500px), only screen and (max-device-width: 500px) -{ - .phpbb_alert { - top: 25px; - } -} - -.phpbb_alert .alert_close { - float: right; - margin-right: -36px; - margin-top: -8px; -} - -.phpbb_alert p { - margin: 8px 0; - padding-bottom: 8px; -} - -.phpbb_alert label { - display: block; - margin: 8px 0; - padding-bottom: 8px; -} - -.phpbb_alert div.alert_text > p, -.phpbb_alert div.alert_text > label, -.phpbb_alert div.alert_text > select, -.phpbb_alert div.alert_text > textarea, -.phpbb_alert div.alert_text > input { - font-size: 1.1em; -} - -.darkenwrapper { - display: none; - position: relative; - z-index: 44; -} - -.darken { - position: fixed; - left: 0; - top: 0; - width: 100%; - height: 100%; - opacity: 0.5; - z-index: 45; -} - -.loading_indicator { - background: center center no-repeat; - border-radius: 5px; - display: none; - opacity: 0.8; - margin-top: -50px; - margin-left: -50px; - height: 50px; - width: 50px; - position: fixed; - left: 50%; - top: 50%; - z-index: 51; -} - -/* Miscellaneous styles ----------------------------------------- */ -.copyright { - font-size: 10px; - text-align: center; - padding: 10px; -} - -.footer-row { - font-size: 10px; - line-height: 1.8; - margin: 0; -} - -.small { - font-size: 0.9em !important; -} - -.titlespace { - margin-bottom: 15px; -} - -.headerspace { - margin-top: 20px; -} - -.error { - font-weight: bold; - font-size: 1em; -} - -div.rules { - margin: 10px 0; - font-size: 1.1em; - padding: 5px 10px; - border-radius: 7px; -} - -div.rules ul, div.rules ol { - margin-left: 20px; -} - -p.post-notice { - position: relative; - padding: 5px; - min-height: 14px; - margin-bottom: 1em; -} - -form > p.post-notice strong { - line-height: 20px; -} - -.stat-block { - clear: both; -} - -.top-anchor { - display: block; - position: absolute; - top: -20px; -} - -.clear { - display: block; - clear: both; - font-size: 1px; - line-height: 1px; - background: transparent; -} - -/* Inner box-model clearing */ -.inner:after, -ul.linklist:after, -.action-bar:after, -.notification_text:after, -.tabs-container:after, -.tabs > ul:after, -.minitabs > ul:after, -.postprofile .avatar-container:after { - clear: both; - content: ''; - display: block; -} - -.emoji { - min-height: 18px; - min-width: 18px; - height: 1em; - width: 1em; -} - -.smilies { - vertical-align: text-bottom; -} - -.icon-notification { - position: relative; -} - -.member-search { - float: left; - margin: 0; - padding: 6px 10px; -} - -.member-search strong { - font-size: 0.95em; -} - -.dropdown-extended { - display: none; - z-index: 1; -} - -.dropdown-extended ul { - max-height: 350px; - overflow-y: auto; - overflow-x: hidden; - clear: both; -} - -.dropdown-extended ul li { - padding: 0; - margin: 0 !important; - float: none; - border-top: 1px solid; - list-style-type: none; - font-size: 0.95em; - clear: both; - position: relative; -} - -.dropdown-extended ul li:first-child { - border-top: none; -} - -.dropdown-extended ul li.no_notifications { - padding: 10px; -} - -.dropdown-extended .dropdown-contents { - max-height: none; - padding: 0; - position: absolute; - width: 340px; -} - -.nojs .dropdown-extended .dropdown-contents { - position: relative; -} - -.dropdown-extended .header { - padding: 0 10px; - font-family: Arial, "Helvetica Neue", Helvetica, Arial, sans-serif; - font-weight: bold; - text-align: left; - text-shadow: 1px 1px 1px white; - text-transform: uppercase; - line-height: 3em; - border-bottom: 1px solid; - border-radius: 5px 5px 0 0; -} - -.dropdown-extended .header .header_settings { - float: right; - font-weight: normal; - text-transform: none; -} - -.dropdown-extended .header .header_settings a { - display: inline-block; - padding: 0 5px; -} - -.dropdown-extended .header:after { - content: ''; - display: table; - clear: both; -} - -.dropdown-extended .footer { - text-align: center; - font-size: 1.1em; -} - -.dropdown-extended ul li a, .dropdown-extended ul li.no-url { - padding: 8px; -} - -.dropdown-extended .footer > a { - padding: 5px 0; -} - -.dropdown-extended ul li a, .notification_list dt > a, .dropdown-extended .footer > a { - display: block; - text-decoration: none; -} - -.notification_list ul li img { - float: left; - max-height: 50px; - max-width: 50px; - width: auto !important; - height: auto !important; - margin-right: 5px; -} - -.notification_list ul li p { - margin-bottom: 4px; - font-size: 1em; -} - -.notification_list p.notification-reference, -.notification_list p.notification-location, -.notification_list li a p.notification-reason { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.notification_list p.notification-time { - font-size: 0.9em; - margin: 0; - text-align: right; -} - -.notification_list div.notifications { - margin-left: 50px; - padding: 5px; -} - -.notification_list div.notifications a { - display: block; -} - -.notification_list p.notifications_title { - font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; - font-size: 1.2em !important; -} - -.notification_list p.notifications_title strong { - font-weight: bold; -} - -.notification_list p.notifications_time { - font-size: 0.9em !important; -} - -.notification_text { - margin-left: 58px; -} - -.badge { - border-radius: 10px; - opacity: 0.8; - text-align: center; - white-space: nowrap; - font-size: 10px; - line-height: 1; - float: right; - display: inline-block; - margin-left: 3px; - vertical-align: baseline; - position: relative; - top: 3px; - padding: 4px 6px; -} - -.badge.hidden { - display: none; -} - -/* Navbar specific list items -----------------------------------------*/ - -.linklist .quick-links { - margin: 0 7px 0 0; -} - -.linklist.compact .rightside > a > span { - display: none; -} - -.dropdown-page-jump .dropdown { - top: 20px; -} - -.dropdown-page-jump.dropdown-up .dropdown { - bottom: 20px; -} - -.dropdown-page-jump input.tiny { - width: 50px; -} - -.dropdown .clone.hidden { - display: none; -} - -.dropdown .clone.hidden + li.separator { - display: none; -} - -.dropdown .clone.hidden + li { - border-top: none; -} diff --git a/install/update/old/styles/prosilver/theme/forms.css b/install/update/old/styles/prosilver/theme/forms.css deleted file mode 100644 index 5646a7d..0000000 --- a/install/update/old/styles/prosilver/theme/forms.css +++ /dev/null @@ -1,429 +0,0 @@ -/* Form Styles ----------------------------------------- */ - -/* General form styles -----------------------------------------*/ -fieldset { - border-width: 0; - font-family: Verdana, Helvetica, Arial, sans-serif; - font-size: 1.1em; -} - -input { - font-weight: normal; - vertical-align: middle; - padding: 0 3px; - font-size: 1em; - font-family: Verdana, Helvetica, Arial, sans-serif; -} - -select { - font-family: Verdana, Helvetica, Arial, sans-serif; - font-weight: normal; - cursor: pointer; - vertical-align: middle; - border: 1px solid transparent; - padding: 1px; - font-size: 1em; -} - -select:focus { - outline-style: none; -} - -option { - padding-right: 1em; -} - -select optgroup option { - padding-right: 1em; - font-family: Verdana, Helvetica, Arial, sans-serif; -} - -textarea { - font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; - width: 60%; - padding: 2px; - font-size: 1em; - line-height: 1.4em; -} - -label { - cursor: default; - padding-right: 5px; -} - -label input { - vertical-align: middle; -} - -label img { - vertical-align: middle; -} - -/* Definition list layout for forms ----------------------------------------- */ -fieldset dl { - padding: 4px 0; -} - -fieldset dt { - float: left; - width: 40%; - text-align: left; - display: block; -} - -fieldset dd { - margin-left: 41%; - vertical-align: top; - margin-bottom: 3px; -} - -/* Specific layout 1 */ -fieldset.fields1 dt { - width: 15em; - border-right-width: 0; -} - -fieldset.fields1 dd { - margin-left: 15em; - border-left-width: 0; -} - -fieldset.fields1 div { - margin-bottom: 3px; -} - -/* Set it back to 0px for the reCaptcha divs: PHPBB3-9587 */ -fieldset.fields1 .live-search div { - margin-bottom: 0; -} - -/* Specific layout 2 */ -fieldset.fields2 dt { - width: 15em; - border-right-width: 0; -} - -fieldset.fields2 dd { - margin-left: 16em; - border-left-width: 0; -} - -/* Form elements */ -dt label { - font-weight: bold; - text-align: left; -} - -dd label { - white-space: nowrap; -} - -dd input, dd textarea { - margin-right: 3px; -} - -dd select { - width: auto; -} - -dd select[multiple] { - width: 100%; -} - -dd textarea { - width: 85%; -} - -/* Hover effects */ -.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; -} - -fieldset.quick-login input { - width: auto; -} - -fieldset.quick-login input.inputbox { - width: 15%; - vertical-align: middle; - margin-right: 5px; -} - -fieldset.quick-login label { - white-space: nowrap; - padding-right: 2px; -} - -/* Display options on viewtopic/viewforum pages */ -fieldset.display-options { - text-align: center; - margin: 3px 0 5px 0; -} - -fieldset.display-options label { - white-space: nowrap; - padding-right: 2px; -} - -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; - line-height: 2em; - white-space: nowrap; - padding-right: 1em; -} - -fieldset.display-actions label { - white-space: nowrap; - padding-right: 2px; -} - -fieldset.sort-options { - line-height: 2em; -} - -/* MCP forum selection*/ -fieldset.forum-selection { - margin: 5px 0 3px 0; - float: right; -} - -fieldset.forum-selection2 { - margin: 13px 0 3px 0; - float: right; -} - -/* Submit button fieldset */ -fieldset.submit-buttons { - text-align: center; - vertical-align: middle; - margin: 5px 0; -} - -fieldset.submit-buttons input { - vertical-align: middle; -} - -/* Posting page styles -----------------------------------------*/ - -/* Buttons used in the editor */ -.format-buttons { - margin: 15px 0 2px 0; -} - -.format-buttons input, .format-buttons select { - vertical-align: middle; -} - -/* Main message box */ -.message-box { - width: 80%; -} - -.message-box textarea { - font-family: "Trebuchet MS", Verdana, Helvetica, Arial, sans-serif; - width: 450px; - height: 270px; - min-width: 100%; - max-width: 100%; - font-size: 1.2em; - resize: vertical; - outline: 3px dashed transparent; - outline-offset: -4px; - -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 { - width: 18%; - float: right; -} - -.smiley-box img { - margin: 3px; -} - -/* Input field styles ----------------------------------------- */ -.inputbox { - border: 1px solid transparent; - padding: 2px; -} - -.inputbox:hover, .inputbox:focus { - border: 1px solid transparent; - outline-style: none; -} - -input.inputbox { width: 85%; } -input.medium { width: 50%; } -input.narrow { width: 25%; } -input.tiny { width: 150px; } - -textarea.inputbox { - width: 85%; -} - -.autowidth { - width: auto !important; -} - -input[type="number"] { - -moz-padding-end: 0; -} - -input[type="search"] { - -webkit-appearance: textfield; - -webkit-box-sizing: content-box; -} - -input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-decoration { - display: none; -} - -input[type="search"]::-webkit-search-cancel-button { - cursor: pointer; -} - -/* Form button styles ----------------------------------------- */ -input.button1, input.button2 { - font-size: 1em; -} - -a.button1, input.button1, input.button3, a.button2, input.button2 { - width: auto !important; - padding-top: 1px; - 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 { - font-weight: bold; - border: 1px solid transparent; -} - -input.button3 { - padding: 0; - margin: 0; - line-height: 5px; - height: 12px; - background-image: none; - font-variant: small-caps; -} - -input[type="button"], input[type="submit"], input[type="reset"], input[type="checkbox"], input[type="radio"] { - cursor: pointer; -} - -/* Alternative button */ -a.button2, input.button2, input.button3 { - border: 1px solid transparent; -} - -/* button in the style of the form buttons */ -a.button1, a.button2 { - text-decoration: none; - padding: 0 3px; - vertical-align: text-bottom; -} - -/* Hover states */ -a.button1:hover, input.button1:hover, a.button2:hover, input.button2:hover, input.button3:hover { - border: 1px solid transparent; -} - -input.disabled { - font-weight: normal; -} - -/* Focus states */ -input.button1:focus, input.button2:focus, input.button3:focus { - outline-style: none; -} - -/* Topic and forum Search */ -.search-box { - float: left; -} - -.search-box .inputbox { - background-image: none; - border-right-width: 0; - border-radius: 4px 0 0 4px; - float: left; - height: 24px; - padding: 3px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -/* Search box (header) ---------------------------------------------- */ -.search-header { - border-radius: 4px; - display: block; - float: right; - margin-right: 5px; - margin-top: 30px; -} - -.search-header .inputbox { border: 0; } - -.navbar .linklist > li.responsive-search { display: none; } - -input.search { - background-image: none; - background-repeat: no-repeat; - background-position: left 1px; - padding-left: 17px; -} - -.full { width: 95%; } -.medium { width: 50%;} -.narrow { width: 25%;} -.tiny { width: 10%;} diff --git a/install/update/old/styles/prosilver/theme/icons.css b/install/update/old/styles/prosilver/theme/icons.css deleted file mode 100644 index 6643f12..0000000 --- a/install/update/old/styles/prosilver/theme/icons.css +++ /dev/null @@ -1,96 +0,0 @@ -/* -------------------------------------------------------------- - $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/install/update/old/styles/prosilver/theme/plupload.css b/install/update/old/styles/prosilver/theme/plupload.css deleted file mode 100644 index f466803..0000000 --- a/install/update/old/styles/prosilver/theme/plupload.css +++ /dev/null @@ -1,86 +0,0 @@ -.attach-panel-multi { - display: none; - margin-bottom: 1em; -} - -.file-list td { - vertical-align: middle; -} - -.attach-name { - width: 50%; -} - -.attach-comment { - width: 30%; -} - -.attach-comment .inputbox { - resize: vertical; - width: 100%; -} - -.attach-filesize { - width: 15%; -} - -.attach-status { - width: 5%; -} - -.attach-filesize, .attach-status { - text-align: center; -} - -.attach-controls { - display: inline-block; - float: right; -} - -.nojs .file-inline-bbcode { - display: none; -} - -.file-total-progress { - height: 2px; - display: block; - position: relative; - margin: 4px -10px -6px -10px; -} - -.file-progress { - background-color: #CCCCCC; - display:inline-block; - height: 8px; - width: 50px; -} - -.file-progress-bar, .file-total-progress-bar { - background-color: green; - display: block; - height: 100%; - width: 0; -} - -.file-status.file-working { - background: url('./images/plupload/throbber.gif'); -} - -.file-status.file-uploaded { - background: url('./images/plupload/done.gif'); -} - -.file-status.file-error { - background: url('./images/plupload/error.gif'); -} - -.file-status { - display: inline-block; - height: 16px; - width: 16px; -} - -.file-name { - max-width: 65%; - vertical-align: bottom; -} diff --git a/install/update/old/styles/prosilver/theme/print.css b/install/update/old/styles/prosilver/theme/print.css deleted file mode 100644 index 9445279..0000000 --- a/install/update/old/styles/prosilver/theme/print.css +++ /dev/null @@ -1,150 +0,0 @@ -/* Print Style Sheet ----------------------------------------- */ - - -/* Lots still TODO here! */ - -/* General markup styles */ -* { - padding: 0; - margin: 0; -} - -body { - font: 11pt Verdana, Arial, Helvetica, sans-serif; - color:#000000; -} - -a:link { color: #000000; text-decoration: none; } -a:visited { color: #000000; text-decoration: none; } -a:active { color: #000000; text-decoration: none; } - -img, .noprint, .navbar, .box1, .divider, .signature { display: none; } -/* Display smilies (Bug #47265) */ -.content img { - display: inline; -} - -/* Container for the main body */ -.wrap { - margin: 0 2em; -} - -p { font-size: 85%; } -.copyright { font-size: 75%; } -.page-number { float:right; width: auto; text-align: right; font-size: 75%; } - -h1, h2, h3, h1 a, h2 a, h3 a { - font-family: "Trebuchet MS",georgia,Verdana,Sans-serif; - color: #000000; - background: none; - text-decoration: none; - font-weight: bold; -} - -h1 { font-size: 20pt; } -h2 { font-size: 16pt; margin-top: 1em; } -h3 { font-size: 14pt; margin-top: 1em; } - -.content { - font-size: 11pt; - line-height: 14pt; - margin-bottom: 1em; - font-family: "Lucida Grande", "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; - overflow: hidden; -} - -/* CSS2 Print tip from: http://www.alistapart.com/articles/goingtoprint/ */ -.postbody a:link, .postbody a:visited, .postbody a:hover, .postbody a:active { - text-decoration: underline; - padding: 0.1em 0.2em; - margin: -0.1em -0.2em; - color: #666; - background: none; - font-size: 100%; -} - -html>body .postbody a:link:after, html>body .postbody a:visited:after { - content: " (" attr(href) ") "; - font-size: 90%; - text-decoration: none; -} - -hr { - height: 1px; - background-color: #999999; - border-width: 0; -} - -.author { - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 75%; - margin-bottom: 0.6em; -} - -.date { - font-family: Verdana, Arial, Helvetica, sans-serif; - float: right; - position: relative; - text-align: right; - font-size: 75%; -} - -/* Dont want to print url for names or titles in content area */ -.postbody .author a:link, .postbody .author a:visited, -html>body .postbody .author a:link:after, -html>body .postbody .author a:visited:after, -.postquote .quote-by a:link, .postquote .quote-by a:visited, -html>body .postquote .quote-by a:link:after, -html>body .postquote .quote-by a:visited:after, -html>body .postbody h1 a:link:after, html>body .postbody h2 a:link:after { - text-decoration: none; - content: ""; -} - -/* Poster profile */ -.postprofile { display: none; } -.grip-show { display:none; } - -/* Quote */ -.postquote, blockquote { - font-size: 85%; - margin: 1em 18% 1em 4%; - padding: 0.5em; - position: relative; - line-height: 1.5em; - border: 1px #999999 solid; -} - -.postquote img { display: none; } -.postquote span { display: block; } -.postquote span .postquote { font-size: 100%; } -.quote-by, blockquote cite { - color: black; - display : block; - font-weight: bold; -} - -/* List */ -ol, ul { - margin-left: 15pt -} - -/* 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/install/update/old/styles/prosilver/theme/stylesheet.css b/install/update/old/styles/prosilver/theme/stylesheet.css deleted file mode 100644 index 45eb5b6..0000000 --- a/install/update/old/styles/prosilver/theme/stylesheet.css +++ /dev/null @@ -1,21 +0,0 @@ -/* phpBB3 Style Sheet - -------------------------------------------------------------- - 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("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/install/update/old/ucp.php b/install/update/old/ucp.php deleted file mode 100644 index 96a3efe..0000000 --- a/install/update/old/ucp.php +++ /dev/null @@ -1,406 +0,0 @@ - -* @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); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -require($phpbb_root_path . 'common.' . $phpEx); -require($phpbb_root_path . 'includes/functions_user.' . $phpEx); -require($phpbb_root_path . 'includes/functions_module.' . $phpEx); - -// Basic parameter data -$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); -$user->setup('ucp'); - -// Setting a variable to let the style designer know where he is... -$template->assign_var('S_IN_UCP', true); - -$module = new p_master(); -$default = false; - -// Basic "global" modes -switch ($mode) -{ - case 'activate': - $module->load('ucp', 'activate'); - $module->display($user->lang['UCP_ACTIVATE']); - - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - break; - - case 'resend_act': - $module->load('ucp', 'resend'); - $module->display($user->lang['UCP_RESEND']); - break; - - case 'sendpassword': - $module->load('ucp', 'remind'); - $module->display($user->lang['UCP_REMIND']); - break; - - case 'register': - if ($user->data['is_registered'] || isset($_REQUEST['not_agreed'])) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - $module->load('ucp', 'register'); - $module->display($user->lang['REGISTER']); - break; - - case 'confirm': - $module->load('ucp', 'confirm'); - break; - - case 'login': - if ($user->data['is_registered']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - login_box($request->variable('redirect', "index.$phpEx")); - break; - - case 'login_link': - if ($user->data['is_registered']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - $module->load('ucp', 'login_link'); - $module->display($user->lang['UCP_LOGIN_LINK']); - break; - - case 'logout': - if ($user->data['user_id'] != ANONYMOUS && $request->is_set('sid') && $request->variable('sid', '') === $user->session_id) - { - $user->session_kill(); - } - else if ($user->data['user_id'] != ANONYMOUS) - { - meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx")); - - $message = $user->lang['LOGOUT_FAILED'] . '

' . sprintf($user->lang['RETURN_INDEX'], '
', ' '); - trigger_error($message); - } - - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - break; - - case 'terms': - case 'privacy': - - $message = ($mode == 'terms') ? 'TERMS_OF_USE_CONTENT' : 'PRIVACY_POLICY'; - $title = ($mode == 'terms') ? 'TERMS_USE' : 'PRIVACY'; - - if (empty($user->lang[$message])) - { - if ($user->data['is_registered']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - login_box(); - } - - $template->set_filenames(array( - 'body' => 'ucp_agreement.html') - ); - - // Disable online list - page_header($user->lang[$title]); - - $template->assign_vars(array( - 'S_AGREEMENT' => true, - '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_PREV'], - )); - - page_footer(); - - break; - - case 'delete_cookies': - - // Delete Cookies with dynamic names (do NOT delete poll cookies) - if (confirm_box(true)) - { - $set_time = time() - 31536000; - - foreach ($request->variable_names(\phpbb\request\request_interface::COOKIE) as $cookie_name) - { - $cookie_data = $request->variable($cookie_name, '', true, \phpbb\request\request_interface::COOKIE); - - // Only delete board cookies, no other ones... - if (strpos($cookie_name, $config['cookie_name'] . '_') !== 0) - { - continue; - } - - $cookie_name = str_replace($config['cookie_name'] . '_', '', $cookie_name); - - /** - * Event to save custom cookies from deletion - * - * @event core.ucp_delete_cookies - * @var string cookie_name Cookie name to checking - * @var bool retain_cookie Do we retain our cookie or not, true if retain - * @since 3.1.3-RC1 - */ - $retain_cookie = false; - $vars = array('cookie_name', 'retain_cookie'); - extract($phpbb_dispatcher->trigger_event('core.ucp_delete_cookies', compact($vars))); - if ($retain_cookie) - { - continue; - } - - // Polls are stored as {cookie_name}_poll_{topic_id}, cookie_name_ got removed, therefore checking for poll_ - if (strpos($cookie_name, 'poll_') !== 0) - { - $user->set_cookie($cookie_name, '', $set_time); - } - } - - $user->set_cookie('track', '', $set_time); - $user->set_cookie('u', '', $set_time); - $user->set_cookie('k', '', $set_time); - $user->set_cookie('sid', '', $set_time); - - // We destroy the session here, the user will be logged out nevertheless - $user->session_kill(); - $user->session_begin(); - - meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx")); - - $message = $user->lang['COOKIES_DELETED'] . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - trigger_error($message); - } - else - { - confirm_box(false, 'DELETE_COOKIES', ''); - } - - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - - break; - - case 'switch_perm': - - $user_id = $request->variable('u', 0); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $user_id; - $result = $db->sql_query($sql); - $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->variable('hash', ''), 'switchperm')) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - include($phpbb_root_path . 'includes/acp/auth.' . $phpEx); - - $auth_admin = new auth_admin(); - if (!$auth_admin->ghost_permissions($user_id, $user->data['user_id'])) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - $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']) . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - - /** - * Event to run code after permissions are switched - * - * @event core.ucp_switch_permissions - * @var int user_id User ID to switch permission to - * @var array user_row User data - * @var string message Success message - * @since 3.1.11-RC1 - */ - $vars = array('user_id', 'user_row', 'message'); - extract($phpbb_dispatcher->trigger_event('core.ucp_switch_permissions', compact($vars))); - - trigger_error($message); - - break; - - case 'restore_perm': - - if (!$user->data['user_perm_from'] || !$auth->acl_get('a_switchperm')) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - $auth->acl_cache($user->data); - - $sql = 'SELECT username - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user->data['user_perm_from']; - $result = $db->sql_query($sql); - $username = $db->sql_fetchfield('username'); - $db->sql_freeresult($result); - - $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ACL_RESTORE_PERMISSIONS', false, array($username)); - - $message = $user->lang['PERMISSIONS_RESTORED'] . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); - - /** - * Event to run code after permissions are restored - * - * @event core.ucp_restore_permissions - * @var string username User name - * @var string message Success message - * @since 3.1.11-RC1 - */ - $vars = array('username', 'message'); - extract($phpbb_dispatcher->trigger_event('core.ucp_restore_permissions', compact($vars))); - - trigger_error($message); - - break; - - default: - $default = true; - break; -} - -// We use this approach because it does not impose large code changes -if (!$default) -{ - return true; -} - -// Only registered users can go beyond this point -if (!$user->data['is_registered']) -{ - if ($user->data['is_bot']) - { - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - if ($id == 'pm' && $mode == 'view' && isset($_GET['p'])) - { - $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']); - } - - login_box('', $user->lang['LOGIN_EXPLAIN_UCP']); -} - -// Instantiate module system and generate list of available modules -$module->list_modules('ucp'); - -// Check if the zebra module is set -if ($module->is_active('zebra', 'friends')) -{ - // Output listing of friends online - $update_time = $config['load_online_time'] * 60; - - $sql_ary = array( - 'SELECT' => 'u.user_id, u.username, u.username_clean, u.user_colour, MAX(s.session_time) as online_time, MIN(s.session_viewonline) AS viewonline', - - 'FROM' => array( - USERS_TABLE => 'u', - ZEBRA_TABLE => 'z', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(SESSIONS_TABLE => 's'), - 'ON' => 's.session_user_id = z.zebra_id', - ), - ), - - 'WHERE' => 'z.user_id = ' . $user->data['user_id'] . ' - AND z.friend = 1 - AND u.user_id = z.zebra_id', - - 'GROUP_BY' => 'z.zebra_id, u.user_id, u.username_clean, u.user_colour, u.username', - - 'ORDER_BY' => 'u.username_clean ASC', - ); - - $sql = $db->sql_build_query('SELECT_DISTINCT', $sql_ary); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $which = (time() - $update_time < $row['online_time'] && ($row['viewonline'] || $auth->acl_get('u_viewonline'))) ? 'online' : 'offline'; - - $template->assign_block_vars("friends_{$which}", array( - 'USER_ID' => $row['user_id'], - - 'U_PROFILE' => get_username_string('profile', $row['user_id'], $row['username'], $row['user_colour']), - 'USER_COLOUR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'])) - ); - } - $db->sql_freeresult($result); -} - -// Do not display subscribed topics/forums if not allowed -if (!$config['allow_topic_notify'] && !$config['allow_forum_notify']) -{ - $module->set_display('main', 'subscribed', false); -} - -/** -* Use this event to enable and disable additional UCP modules -* -* @event core.ucp_display_module_before -* @var p_master module Object holding all modules and their status -* @var mixed id Active module category (can be the int or string) -* @var string mode Active module -* @since 3.1.0-a1 -*/ -$vars = array('module', 'id', 'mode'); -extract($phpbb_dispatcher->trigger_event('core.ucp_display_module_before', compact($vars))); - -// Select the active module -$module->set_active($id, $mode); - -// Load and execute the relevant module -$module->load_active(); - -// Assign data to the template engine for the list of modules -$module->assign_tpl_vars(append_sid("{$phpbb_root_path}ucp.$phpEx")); - -// Generate the page, do not display/query online list -$module->display($module->get_page_title()); diff --git a/install/update/old/viewforum.php b/install/update/old/viewforum.php deleted file mode 100644 index 5525a0d..0000000 --- a/install/update/old/viewforum.php +++ /dev/null @@ -1,1059 +0,0 @@ - -* @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); -$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 -$user->session_begin(); -$auth->acl($user->data); - -// Start initial var setup -$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->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 -// If not give them a nice error page. -if (!$forum_id) -{ - trigger_error('NO_FORUM'); -} - -$sql_from = FORUMS_TABLE . ' f'; -$lastread_select = ''; - -// Grab appropriate forum data -if ($config['load_db_lastread'] && $user->data['is_registered']) -{ - $sql_from .= ' LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . ' - AND ft.forum_id = f.forum_id)'; - $lastread_select .= ', ft.mark_time'; -} - -if ($user->data['is_registered']) -{ - $sql_from .= ' LEFT JOIN ' . FORUMS_WATCH_TABLE . ' fw ON (fw.forum_id = f.forum_id AND fw.user_id = ' . $user->data['user_id'] . ')'; - $lastread_select .= ', fw.notify_status'; -} - -$sql = "SELECT f.* $lastread_select - FROM $sql_from - WHERE f.forum_id = $forum_id"; -$result = $db->sql_query($sql); -$forum_data = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -if (!$forum_data) -{ - trigger_error('NO_FORUM'); -} - - -// Configure style, language, etc. -$user->setup('viewforum', $forum_data['forum_style']); - -// Redirect to login upon emailed notification links -if (isset($_GET['e']) && !$user->data['is_registered']) -{ - login_box('', $user->lang['LOGIN_NOTIFY_FORUM']); -} - -// Permissions check -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'); - } - - login_box('', $user->lang['LOGIN_VIEWFORUM']); -} - -// Forum is passworded ... check whether access has been granted to this -// user this session, if not show login box -if ($forum_data['forum_password']) -{ - login_forum_box($forum_data); -} - -// Is this forum a link? ... User got here either because the -// number of clicks is being tracked or they guessed the id -if ($forum_data['forum_type'] == FORUM_LINK && $forum_data['forum_link']) -{ - // Does it have click tracking enabled? - if ($forum_data['forum_flags'] & FORUM_FLAG_LINK_TRACK) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_posts_approved = forum_posts_approved + 1 - WHERE forum_id = ' . $forum_id; - $db->sql_query($sql); - } - - // We redirect to the url. The third parameter indicates that external redirects are allowed. - redirect($forum_data['forum_link'], false, true); - return; -} - -// Build navigation links -generate_forum_nav($forum_data); - -// Forum Rules -if ($auth->acl_get('f_read', $forum_id)) -{ - generate_forum_rules($forum_data); -} - -// Do we have subforums? -$active_forum_ary = $moderators = array(); - -if ($forum_data['left_id'] != $forum_data['right_id'] - 1) -{ - list($active_forum_ary, $moderators) = display_forums($forum_data, $config['load_moderators'], $config['load_moderators']); -} -else -{ - $template->assign_var('S_HAS_SUBFORUM', false); - if ($config['load_moderators']) - { - get_moderators($moderators, $forum_id); - } -} - -// Is a forum specific topic count required? -if ($forum_data['forum_topics_per_page']) -{ - $config['topics_per_page'] = $forum_data['forum_topics_per_page']; -} - -/* @var $phpbb_content_visibility \phpbb\content_visibility */ -$phpbb_content_visibility = $phpbb_container->get('content.visibility'); - -// Dump out the page header and load viewforum template -$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_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') -); - -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_id); - -$template->assign_vars(array( - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . (($start == 0) ? '' : "&start=$start")), -)); - -// Not postable forum or showing active topics? -if (!($forum_data['forum_type'] == FORUM_POST || (($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) && $forum_data['forum_type'] == FORUM_CAT))) -{ - page_footer(); -} - -// 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_gets('f_read', 'f_list_topics', $forum_id)) -{ - // Add form token for login box - add_form_key('login', '_LOGIN'); - - $template->assign_vars(array( - 'S_NO_READ_ACCESS' => true, - )); - - page_footer(); -} - -// Handle marking posts -if ($mark_read == 'topics') -{ - $token = $request->variable('hash', ''); - if (check_link_hash($token, 'global')) - { - 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); - - if ($request->is_ajax()) - { - // Tell the ajax script what language vars and URL need to be replaced - $data = array( - 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'], - 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'], - 'U_MARK_TOPICS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . "&f=$forum_id&mark=topics&mark_time=" . time()) : '', - 'MESSAGE_TITLE' => $user->lang['INFORMATION'], - 'MESSAGE_TEXT' => $user->lang['TOPICS_MARKED'] - ); - $json_response = new \phpbb\json_response(); - $json_response->send($data); - } - - trigger_error($user->lang['TOPICS_MARKED'] . '

' . sprintf($user->lang['RETURN_FORUM'], '', '')); -} - -// 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'); - $task->set_forum_data($forum_data); - - if ($task->is_ready()) - { - $url = $task->get_url(); - $template->assign_var('RUN_CRON_TASK', 'cron'); - } - else - { - // See if we should prune the shadow topics instead - $task = $cron->find_task('cron.task.core.prune_shadow_topics'); - $task->set_forum_data($forum_data); - - if ($task->is_ready()) - { - $url = $task->get_url(); - $template->assign_var('RUN_CRON_TASK', 'cron'); - } - } -} - -// Forum rules and subscription info -$s_watching_forum = array( - 'link' => '', - 'link_toggle' => '', - 'title' => '', - 'title_toggle' => '', - 'is_watching' => false, -); - -if ($config['allow_forum_notify'] && $forum_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_subscribe', $forum_id) || $user->data['user_id'] == ANONYMOUS)) -{ - $notify_status = (isset($forum_data['notify_status'])) ? $forum_data['notify_status'] : NULL; - watch_topic_forum('forum', $s_watching_forum, $user->data['user_id'], $forum_id, 0, $notify_status, $start, $forum_data['forum_name']); -} - -$s_forum_rules = ''; -gen_forum_auth_level('forum', $forum_id, $forum_data['forum_status']); - -// Topic ordering options -$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'], '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); - -// Limit topics to certain time frame, obtain correct topic count -if ($sort_days) -{ - $min_post_time = time() - ($sort_days * 86400); - - $sql_array = array( - 'SELECT' => 'COUNT(t.topic_id) AS num_topics', - 'FROM' => array( - TOPICS_TABLE => 't', - ), - 'WHERE' => 't.forum_id = ' . $forum_id . ' - AND (t.topic_last_post_time >= ' . $min_post_time . ' - OR t.topic_type = ' . POST_ANNOUNCE . ' - OR t.topic_type = ' . POST_GLOBAL . ') - AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'), - ); - - /** - * Modify the sort data SQL query for getting additional fields if needed - * - * @event core.viewforum_modify_sort_data_sql - * @var int forum_id The forum_id whose topics are being listed - * @var int start Variable containing start for pagination - * @var int sort_days The oldest topic displayable in elapsed days - * @var string sort_key The sorting by. It is one of the first character of (in low case): - * Author, Post time, Replies, Subject, Views - * @var string sort_dir Either "a" for ascending or "d" for descending - * @var array sql_array The SQL array to get the data of all topics - * @since 3.1.9-RC1 - */ - $vars = array( - 'forum_id', - 'start', - 'sort_days', - 'sort_key', - 'sort_dir', - 'sql_array', - ); - extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_sort_data_sql', compact($vars))); - - $result = $db->sql_query($db->sql_build_query('SELECT', $sql_array)); - $topics_count = (int) $db->sql_fetchfield('num_topics'); - $db->sql_freeresult($result); - - if (isset($_POST['sort'])) - { - $start = 0; - } - $sql_limit_time = "AND t.topic_last_post_time >= $min_post_time"; - - // Make sure we have information about day selection ready - $template->assign_var('S_SORT_DAYS', true); -} -else -{ - $sql_limit_time = ''; -} - -// Basic pagewide vars -$post_alt = ($forum_data['forum_status'] == ITEM_LOCKED) ? $user->lang['FORUM_LOCKED'] : $user->lang['POST_NEW_TOPIC']; - -// Display active topics? -$s_display_active = ($forum_data['forum_type'] == FORUM_CAT && ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) ? true : false; - -$s_search_hidden_fields = array('fid' => array($forum_id)); -if ($_SID) -{ - $s_search_hidden_fields['sid'] = $_SID; -} - -if (!empty($_EXTRA_URL)) -{ - foreach ($_EXTRA_URL as $url_param) - { - $url_param = explode('=', $url_param, 2); - $s_search_hidden_fields[$url_param[0]] = $url_param[1]; - } -} - -$template->assign_vars(array( - 'MODERATORS' => (!empty($moderators[$forum_id])) ? implode($user->lang['COMMA_SEPARATOR'], $moderators[$forum_id]) : '', - - 'POST_IMG' => ($forum_data['forum_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', $post_alt) : $user->img('button_topic_new', $post_alt), - 'NEWEST_POST_IMG' => $user->img('icon_topic_newest', 'VIEW_NEWEST_POST'), - 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), - 'FOLDER_IMG' => $user->img('topic_read', 'NO_UNREAD_POSTS'), - 'FOLDER_UNREAD_IMG' => $user->img('topic_unread', 'UNREAD_POSTS'), - 'FOLDER_HOT_IMG' => $user->img('topic_read_hot', 'NO_UNREAD_POSTS_HOT'), - 'FOLDER_HOT_UNREAD_IMG' => $user->img('topic_unread_hot', 'UNREAD_POSTS_HOT'), - 'FOLDER_LOCKED_IMG' => $user->img('topic_read_locked', 'NO_UNREAD_POSTS_LOCKED'), - 'FOLDER_LOCKED_UNREAD_IMG' => $user->img('topic_unread_locked', 'UNREAD_POSTS_LOCKED'), - 'FOLDER_STICKY_IMG' => $user->img('sticky_read', 'POST_STICKY'), - 'FOLDER_STICKY_UNREAD_IMG' => $user->img('sticky_unread', 'POST_STICKY'), - 'FOLDER_ANNOUNCE_IMG' => $user->img('announce_read', 'POST_ANNOUNCEMENT'), - 'FOLDER_ANNOUNCE_UNREAD_IMG'=> $user->img('announce_unread', 'POST_ANNOUNCEMENT'), - 'FOLDER_MOVED_IMG' => $user->img('topic_moved', 'TOPIC_MOVED'), - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'TOPIC_REPORTED'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPIC_UNAPPROVED'), - 'DELETED_IMG' => $user->img('icon_topic_deleted', 'TOPIC_DELETED'), - 'POLL_IMG' => $user->img('icon_topic_poll', 'TOPIC_POLL'), - 'GOTO_PAGE_IMG' => $user->img('icon_post_target', 'GOTO_PAGE'), - - 'L_NO_TOPICS' => ($forum_data['forum_status'] == ITEM_LOCKED) ? $user->lang['POST_FORUM_LOCKED'] : $user->lang['NO_TOPICS'], - - 'S_DISPLAY_POST_INFO' => ($forum_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false, - - 'S_IS_POSTABLE' => ($forum_data['forum_type'] == FORUM_POST) ? true : false, - 'S_USER_CAN_POST' => ($auth->acl_get('f_post', $forum_id)) ? true : false, - 'S_DISPLAY_ACTIVE' => $s_display_active, - '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 && 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'], - 'S_WATCH_FORUM_TOGGLE' => $s_watching_forum['title_toggle'], - 'S_WATCHING_FORUM' => $s_watching_forum['is_watching'], - 'S_FORUM_ACTION' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . (($start == 0) ? '' : "&start=$start")), - '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]) && count($moderators[$forum_id]) > 1) ? false : true, - 'S_IS_LOCKED' => ($forum_data['forum_status'] == ITEM_LOCKED) ? true : false, - 'S_VIEWFORUM' => true, - - 'U_MCP' => ($auth->acl_get('m_', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "f=$forum_id&i=main&mode=forum_view", true, $user->session_id) : '', - 'U_POST_NEW_TOPIC' => ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=post&f=' . $forum_id) : '', - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($start == 0) ? '' : "&start=$start")), - 'U_CANONICAL' => generate_board_url() . '/' . append_sid("viewforum.$phpEx", "f=$forum_id" . (($start) ? "&start=$start" : ''), true, ''), - '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()) : '', -)); - -// Grab icons -$icons = $cache->obtain_icons(); - -// Grab all topic data -$rowset = $announcement_list = $topic_list = $global_announce_forums = array(); - -$sql_array = array( - 'SELECT' => 't.*', - 'FROM' => array( - TOPICS_TABLE => 't' - ), - 'LEFT_JOIN' => array(), -); - -/** -* Event to modify the SQL query before the topic data is retrieved -* -* It may also be used to override the above assigned template vars -* -* @event core.viewforum_get_topic_data -* @var array forum_data Array with forum data -* @var array sql_array The SQL array to get the data of all topics -* @var int forum_id The forum_id whose topics are being listed -* @var int topics_count The total number of topics for display -* @var int sort_days The oldest topic displayable in elapsed days -* @var string sort_key The sorting by. It is one of the first character of (in low case): -* Author, Post time, Replies, Subject, Views -* @var string sort_dir Either "a" for ascending or "d" for descending -* @since 3.1.0-a1 -* @changed 3.1.0-RC4 Added forum_data var -* @changed 3.1.4-RC1 Added forum_id, topics_count, sort_days, sort_key and sort_dir vars -* @changed 3.1.9-RC1 Fix types of properties -*/ -$vars = array( - 'forum_data', - 'sql_array', - 'forum_id', - 'topics_count', - 'sort_days', - 'sort_key', - 'sort_dir', -); -extract($phpbb_dispatcher->trigger_event('core.viewforum_get_topic_data', compact($vars))); - -$sql_approved = ' AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'); - -if ($user->data['is_registered']) -{ - if ($config['load_db_track']) - { - $sql_array['LEFT_JOIN'][] = array('FROM' => array(TOPICS_POSTED_TABLE => 'tp'), 'ON' => 'tp.topic_id = t.topic_id AND tp.user_id = ' . $user->data['user_id']); - $sql_array['SELECT'] .= ', tp.topic_posted'; - } - - if ($config['load_db_lastread']) - { - $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 && 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'; - } - } -} - -if ($forum_data['forum_type'] == FORUM_POST) -{ - // Get global announcement forums - $g_forum_ary = $auth->acl_getf('f_read', true); - $g_forum_ary = array_unique(array_keys($g_forum_ary)); - - $sql_anounce_array['LEFT_JOIN'] = $sql_array['LEFT_JOIN']; - $sql_anounce_array['LEFT_JOIN'][] = array('FROM' => array(FORUMS_TABLE => 'f'), 'ON' => 'f.forum_id = t.forum_id'); - $sql_anounce_array['SELECT'] = $sql_array['SELECT'] . ', f.forum_name'; - - // Obtain announcements ... removed sort ordering, sort by time in all cases - $sql_ary = array( - 'SELECT' => $sql_anounce_array['SELECT'], - 'FROM' => $sql_array['FROM'], - 'LEFT_JOIN' => $sql_anounce_array['LEFT_JOIN'], - - 'WHERE' => '(t.forum_id = ' . $forum_id . ' - AND t.topic_type = ' . POST_ANNOUNCE . ') OR - (' . $db->sql_in_set('t.forum_id', $g_forum_ary, false, true) . ' - AND t.topic_type = ' . POST_GLOBAL . ')', - - 'ORDER_BY' => 't.topic_time DESC', - ); - - /** - * Event to modify the SQL query before the announcement topic ids data is retrieved - * - * @event core.viewforum_get_announcement_topic_ids_data - * @var array forum_data Data about the forum - * @var array g_forum_ary Global announcement forums array - * @var array sql_anounce_array SQL announcement array - * @var array sql_ary SQL query array to get the announcement topic ids data - * @var int forum_id The forum ID - * - * @since 3.1.10-RC1 - */ - $vars = array( - 'forum_data', - 'g_forum_ary', - 'sql_anounce_array', - 'sql_ary', - 'forum_id', - ); - extract($phpbb_dispatcher->trigger_event('core.viewforum_get_announcement_topic_ids_data', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_ary); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$phpbb_content_visibility->is_visible('topic', $row['forum_id'], $row)) - { - // Do not display announcements that are waiting for approval or soft deleted. - continue; - } - - $rowset[$row['topic_id']] = $row; - $announcement_list[] = $row['topic_id']; - - if ($forum_id != $row['forum_id']) - { - $topics_count++; - $global_announce_forums[] = $row['forum_id']; - } - } - $db->sql_freeresult($result); -} - -$forum_tracking_info = array(); - -if ($user->data['is_registered'] && $config['load_db_lastread']) -{ - $forum_tracking_info[$forum_id] = $forum_data['mark_time']; - - if (!empty($global_announce_forums)) - { - $sql = 'SELECT forum_id, mark_time - FROM ' . FORUMS_TRACK_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $global_announce_forums) . ' - AND user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $forum_tracking_info[$row['forum_id']] = $row['mark_time']; - } - $db->sql_freeresult($result); - } -} - -// If the user is trying to reach late pages, start searching from the end -$store_reverse = false; -$sql_limit = $config['topics_per_page']; -if ($start > $topics_count / 2) -{ - $store_reverse = true; - - // Select the sort order - $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC'); - - $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 -{ - // Select the sort order - $direction = (($sort_dir == 'd') ? 'DESC' : 'ASC'); - $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; -} -else -{ - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction; -} - -if ($forum_data['forum_type'] == FORUM_POST || !count($active_forum_ary)) -{ - $sql_where = 't.forum_id = ' . $forum_id; -} -else if (empty($active_forum_ary['exclude_forum_id'])) -{ - $sql_where = $db->sql_in_set('t.forum_id', $active_forum_ary['forum_id']); -} -else -{ - $get_forum_ids = array_diff($active_forum_ary['forum_id'], $active_forum_ary['exclude_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 -$sql_ary = array( - 'SELECT' => 't.topic_id', - 'FROM' => array( - TOPICS_TABLE => 't', - ), - 'WHERE' => "$sql_where - AND t.topic_type IN (" . POST_NORMAL . ', ' . POST_STICKY . ") - $sql_approved - $sql_limit_time", - 'ORDER_BY' => 't.topic_type ' . ((!$store_reverse) ? 'DESC' : 'ASC') . ', ' . $sql_sort_order, -); - -/** -* Event to modify the SQL query before the topic ids data is retrieved -* -* @event core.viewforum_get_topic_ids_data -* @var array forum_data Data about the forum -* @var array sql_ary SQL query array to get the topic ids data -* @var string sql_approved Topic visibility SQL string -* @var int sql_limit Number of records to select -* @var string sql_limit_time SQL string to limit topic_last_post_time data -* @var array sql_sort_order SQL sorting string -* @var int sql_start Offset point to start selection from -* @var string sql_where SQL WHERE clause string -* @var bool store_reverse Flag indicating if we select from the late pages -* -* @since 3.1.0-RC4 -* -* @changed 3.1.3 Added forum_data -*/ -$vars = array( - 'forum_data', - 'sql_ary', - 'sql_approved', - 'sql_limit', - 'sql_limit_time', - 'sql_sort_order', - 'sql_start', - 'sql_where', - 'store_reverse', -); -extract($phpbb_dispatcher->trigger_event('core.viewforum_get_topic_ids_data', compact($vars))); - -$sql = $db->sql_build_query('SELECT', $sql_ary); -$result = $db->sql_query_limit($sql, $sql_limit, $sql_start); - -while ($row = $db->sql_fetchrow($result)) -{ - $topic_list[] = (int) $row['topic_id']; -} -$db->sql_freeresult($result); - -// For storing shadow topics -$shadow_topic_list = array(); - -if (count($topic_list)) -{ - // SQL array for obtaining topics/stickies - $sql_array = array( - 'SELECT' => $sql_array['SELECT'], - 'FROM' => $sql_array['FROM'], - 'LEFT_JOIN' => $sql_array['LEFT_JOIN'], - - 'WHERE' => $db->sql_in_set('t.topic_id', $topic_list), - ); - - // If store_reverse, then first obtain topics, then stickies, else the other way around... - // Funnily enough you typically save one query if going from the last page to the middle (store_reverse) because - // the number of stickies are not known - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_status'] == ITEM_MOVED) - { - $shadow_topic_list[$row['topic_moved_id']] = $row['topic_id']; - } - - $rowset[$row['topic_id']] = $row; - } - $db->sql_freeresult($result); -} - -// If we have some shadow topics, update the rowset to reflect their topic information -if (count($shadow_topic_list)) -{ - // SQL array for obtaining shadow topics - $sql_array = array( - 'SELECT' => 't.*', - 'FROM' => array( - TOPICS_TABLE => 't' - ), - 'WHERE' => $db->sql_in_set('t.topic_id', array_keys($shadow_topic_list)), - ); - - /** - * Event to modify the SQL query before the shadowtopic data is retrieved - * - * @event core.viewforum_get_shadowtopic_data - * @var array sql_array SQL array to get the data of any shadowtopics - * @since 3.1.0-a1 - */ - $vars = array('sql_array'); - extract($phpbb_dispatcher->trigger_event('core.viewforum_get_shadowtopic_data', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $orig_topic_id = $shadow_topic_list[$row['topic_id']]; - - // If the shadow topic is already listed within the rowset (happens for active topics for example), then do not include it... - if (isset($rowset[$row['topic_id']])) - { - // We need to remove any trace regarding this topic. :) - unset($rowset[$orig_topic_id]); - unset($topic_list[array_search($orig_topic_id, $topic_list)]); - $topics_count--; - - continue; - } - - // Do not include those topics the user has no permission to access - 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]); - unset($topic_list[array_search($orig_topic_id, $topic_list)]); - $topics_count--; - - continue; - } - - // We want to retain some values - $row = array_merge($row, array( - 'topic_moved_id' => $rowset[$orig_topic_id]['topic_moved_id'], - 'topic_status' => $rowset[$orig_topic_id]['topic_status'], - 'topic_type' => $rowset[$orig_topic_id]['topic_type'], - 'topic_title' => $rowset[$orig_topic_id]['topic_title'], - )); - - // Shadow topics are never reported - $row['topic_reported'] = 0; - - $rowset[$orig_topic_id] = $row; - } - $db->sql_freeresult($result); -} -unset($shadow_topic_list); - -// Ok, adjust topics count for active topics list -if ($s_display_active) -{ - $topics_count = 1; -} - -// 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 - count($announcement_list); - -$base_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . ((strlen($u_sort_param)) ? "&$u_sort_param" : '')); -$pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_topic_count, $config['topics_per_page'], $start); - -$template->assign_vars(array( - 'TOTAL_TOPICS' => ($s_display_active) ? false : $user->lang('VIEW_FORUM_TOPICS', (int) $total_topic_count), -)); - -$topic_list = ($store_reverse) ? array_merge($announcement_list, array_reverse($topic_list)) : array_merge($announcement_list, $topic_list); -$topic_tracking_info = $tracking_topics = array(); - -/** -* Modify topics data before we display the viewforum page -* -* @event core.viewforum_modify_topics_data -* @var array topic_list Array with current viewforum page topic ids -* @var array rowset Array with topics data (in topic_id => topic_data format) -* @var int total_topic_count Forum's total topic count -* @var int forum_id Forum identifier -* @since 3.1.0-b3 -* @changed 3.1.11-RC1 Added forum_id -*/ -$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 (count($topic_list)) -{ - $mark_forum_read = true; - $mark_time_forum = 0; - - // Generate topic forum list... - $topic_forum_list = array(); - foreach ($rowset as $t_id => $row) - { - if (isset($forum_tracking_info[$row['forum_id']])) - { - $row['forum_mark_time'] = $forum_tracking_info[$row['forum_id']]; - } - - $topic_forum_list[$row['forum_id']]['forum_mark_time'] = ($config['load_db_lastread'] && $user->data['is_registered'] && isset($row['forum_mark_time'])) ? $row['forum_mark_time'] : 0; - $topic_forum_list[$row['forum_id']]['topics'][] = (int) $t_id; - } - - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - foreach ($topic_forum_list as $f_id => $topic_row) - { - $topic_tracking_info += get_topic_tracking($f_id, $topic_row['topics'], $rowset, array($f_id => $topic_row['forum_mark_time'])); - } - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - foreach ($topic_forum_list as $f_id => $topic_row) - { - $topic_tracking_info += get_complete_topic_tracking($f_id, $topic_row['topics']); - } - } - - unset($topic_forum_list); - - if (!$s_display_active) - { - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $mark_time_forum = (!empty($forum_data['mark_time'])) ? $forum_data['mark_time'] : $user->data['user_lastmark']; - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - if (!$user->data['is_registered']) - { - $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0; - } - $mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark']; - } - } - - $s_type_switch = 0; - foreach ($topic_list as $topic_id) - { - $row = &$rowset[$topic_id]; - - $topic_forum_id = ($row['forum_id']) ? (int) $row['forum_id'] : $forum_id; - - // This will allow the style designer to output a different header - // or even separate the list of announcements from sticky and normal topics - $s_type_switch_test = ($row['topic_type'] == POST_ANNOUNCE || $row['topic_type'] == POST_GLOBAL) ? 1 : 0; - - // Replies - $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $topic_forum_id) - 1; - - if ($row['topic_status'] == ITEM_MOVED) - { - $topic_id = $row['topic_moved_id']; - $unread_topic = false; - } - else - { - $unread_topic = (isset($topic_tracking_info[$topic_id]) && $row['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); - - // Generate all the URIs ... - $view_topic_url_params = 'f=' . $row['forum_id'] . '&t=' . $topic_id; - $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'])); - $topic_deleted = $row['topic_visibility'] == ITEM_DELETED; - - $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . "&t=$topic_id", true, $user->session_id) : ''; - $u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=deleted_topics&t=' . $topic_id, true, $user->session_id) : $u_mcp_queue; - - // Send vars to template - $topic_row = array( - 'FORUM_ID' => $row['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']), - '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']), - 'LAST_POST_SUBJECT' => censor_text($row['topic_last_post_subject']), - 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), - 'LAST_VIEW_TIME' => $user->format_date($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']), - - 'REPLIES' => $replies, - 'VIEWS' => $row['topic_views'], - 'TOPIC_TITLE' => censor_text($row['topic_title']), - 'TOPIC_TYPE' => $topic_type, - 'FORUM_NAME' => (isset($row['forum_name'])) ? $row['forum_name'] : $forum_data['forum_name'], - - 'TOPIC_IMG_STYLE' => $folder_img, - 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'TOPIC_FOLDER_IMG_ALT' => $user->lang[$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'] : '', - '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']) : '', - 'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '', - - 'S_TOPIC_TYPE' => $row['topic_type'], - 'S_USER_POSTED' => (isset($row['topic_posted']) && $row['topic_posted']) ? true : false, - 'S_UNREAD_TOPIC' => $unread_topic, - 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_get('m_report', $row['forum_id'])) ? true : false, - 'S_TOPIC_UNAPPROVED' => $topic_unapproved, - 'S_POSTS_UNAPPROVED' => $posts_unapproved, - 'S_TOPIC_DELETED' => $topic_deleted, - 'S_HAS_POLL' => ($row['poll_start']) ? true : false, - 'S_POST_ANNOUNCE' => ($row['topic_type'] == POST_ANNOUNCE) ? true : false, - 'S_POST_GLOBAL' => ($row['topic_type'] == POST_GLOBAL) ? true : false, - 'S_POST_STICKY' => ($row['topic_type'] == POST_STICKY) ? true : false, - 'S_TOPIC_LOCKED' => ($row['topic_status'] == ITEM_LOCKED) ? true : false, - 'S_TOPIC_MOVED' => ($row['topic_status'] == ITEM_MOVED) ? true : false, - - 'U_NEWEST_POST' => $auth->acl_get('f_read', $forum_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&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 . '&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, - 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), - 'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=reports&f=' . $row['forum_id'] . '&t=' . $topic_id, true, $user->session_id), - 'U_MCP_QUEUE' => $u_mcp_queue, - - 'S_TOPIC_TYPE_SWITCH' => ($s_type_switch == $s_type_switch_test) ? -1 : $s_type_switch_test, - ); - - /** - * Modify the topic data before it is assigned to the template - * - * @event core.viewforum_modify_topicrow - * @var array row Array with topic data - * @var array topic_row Template array with topic data - * @var bool s_type_switch Flag indicating if the topic type is [global] announcement - * @var bool s_type_switch_test Flag indicating if the test topic type is [global] announcement - * @since 3.1.0-a1 - * - * @changed 3.1.10-RC1 Added s_type_switch, s_type_switch_test - */ - $vars = array('row', 'topic_row', 's_type_switch', 's_type_switch_test'); - extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_topicrow', compact($vars))); - - $template->assign_block_vars('topicrow', $topic_row); - - $pagination->generate_template_pagination($view_topic_url, 'topicrow.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true); - - $s_type_switch = ($row['topic_type'] == POST_ANNOUNCE || $row['topic_type'] == POST_GLOBAL) ? 1 : 0; - - /** - * Event after the topic data has been assigned to the template - * - * @event core.viewforum_topic_row_after - * @var array row Array with the topic data - * @var array rowset Array with topics data (in topic_id => topic_data format) - * @var bool s_type_switch Flag indicating if the topic type is [global] announcement - * @var int topic_id The topic ID - * @var array topic_list Array with current viewforum page topic ids - * @var array topic_row Template array with topic data - * @since 3.1.3-RC1 - */ - $vars = array( - 'row', - 'rowset', - 's_type_switch', - 'topic_id', - 'topic_list', - 'topic_row', - ); - extract($phpbb_dispatcher->trigger_event('core.viewforum_topic_row_after', compact($vars))); - - if ($unread_topic) - { - $mark_forum_read = false; - } - - unset($rowset[$topic_id]); - } -} - -/** -* 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 && count($topic_list) && $mark_forum_read) -{ - update_forum_tracking_info($forum_id, $forum_data['forum_last_post_time'], false, $mark_time_forum); -} - -page_footer(); diff --git a/install/update/old/viewonline.php b/install/update/old/viewonline.php deleted file mode 100644 index d5ddb0b..0000000 --- a/install/update/old/viewonline.php +++ /dev/null @@ -1,517 +0,0 @@ - -* @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); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -include($phpbb_root_path . 'common.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); -$user->setup('memberlist'); - -// Get and set some variables -$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']); -$sort_key_sql = array('a' => 'u.username_clean', 'b' => 's.session_time', 'c' => 's.session_page'); - -// Sorting and order -if (!isset($sort_key_text[$sort_key])) -{ - $sort_key = 'b'; -} - -$order_by = $sort_key_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); - -// Whois requested -if ($mode == 'whois' && $auth->acl_get('a_') && $session_id) -{ - if (!function_exists('user_get_id_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - $sql = 'SELECT u.user_id, u.username, u.user_type, s.session_ip - FROM ' . USERS_TABLE . ' u, ' . SESSIONS_TABLE . " s - WHERE s.session_id = '" . $db->sql_escape($session_id) . "' - AND u.user_id = s.session_user_id"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $template->assign_var('WHOIS', user_ipwhois($row['session_ip'])); - } - $db->sql_freeresult($result); - - // Output the page - page_header($user->lang['WHO_IS_ONLINE']); - - $template->set_filenames(array( - 'body' => 'viewonline_whois.html') - ); - make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - - page_footer(); -} - -$user->update_session_infos(); - -// Forum info -$sql_ary = array( - 'SELECT' => 'f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f.right_id', - 'FROM' => array( - FORUMS_TABLE => 'f', - ), - 'ORDER_BY' => 'f.left_id ASC', -); - -/** -* Modify the forum data SQL query for getting additional fields if needed -* -* @event core.viewonline_modify_forum_data_sql -* @var array sql_ary The SQL array -* @since 3.1.5-RC1 -*/ -$vars = array('sql_ary'); -extract($phpbb_dispatcher->trigger_event('core.viewonline_modify_forum_data_sql', compact($vars))); - -$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary), 600); -unset($sql_ary); - -$forum_data = array(); -while ($row = $db->sql_fetchrow($result)) -{ - $forum_data[$row['forum_id']] = $row; -} -$db->sql_freeresult($result); - -$guest_counter = 0; - -// Get number of online guests (if we do not display them) -if (!$show_guests) -{ - switch ($db->get_sql_layer()) - { - case 'sqlite3': - $sql = 'SELECT COUNT(session_ip) as num_guests - FROM ( - SELECT DISTINCT session_ip - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . ANONYMOUS . ' - AND session_time >= ' . (time() - ($config['load_online_time'] * 60)) . - ')'; - break; - - default: - $sql = 'SELECT COUNT(DISTINCT session_ip) as num_guests - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . ANONYMOUS . ' - AND session_time >= ' . (time() - ($config['load_online_time'] * 60)); - break; - } - $result = $db->sql_query($sql); - $guest_counter = (int) $db->sql_fetchfield('num_guests'); - $db->sql_freeresult($result); -} - -// Get user list -$sql_ary = array( - 'SELECT' => 'u.user_id, u.username, u.username_clean, u.user_type, u.user_colour, s.session_id, s.session_time, s.session_page, s.session_ip, s.session_browser, s.session_viewonline, s.session_forum_id', - 'FROM' => array( - USERS_TABLE => 'u', - SESSIONS_TABLE => 's', - ), - 'WHERE' => 'u.user_id = s.session_user_id - AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) . - ((!$show_guests) ? ' AND s.session_user_id <> ' . ANONYMOUS : ''), - 'ORDER_BY' => $order_by, -); - -/** -* Modify the SQL query for getting the user data to display viewonline list -* -* @event core.viewonline_modify_sql -* @var array sql_ary The SQL array -* @var bool show_guests Do we display guests in the list -* @var int guest_counter Number of guests displayed -* @var array forum_data Array with forum data -* @since 3.1.0-a1 -* @changed 3.1.0-a2 Added vars guest_counter and forum_data -*/ -$vars = array('sql_ary', 'show_guests', 'guest_counter', 'forum_data'); -extract($phpbb_dispatcher->trigger_event('core.viewonline_modify_sql', compact($vars))); - -$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']])) - { - $view_online = $s_user_hidden = false; - $user_colour = ($row['user_colour']) ? ' style="color:#' . $row['user_colour'] . '" class="username-coloured"' : ''; - - $username_full = ($row['user_type'] != USER_IGNORE) ? get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']) : '' . $row['username'] . ''; - - if (!$row['session_viewonline']) - { - $view_online = ($auth->acl_get('u_viewonline') || $row['user_id'] === $user->data['user_id']) ? true : false; - $logged_hidden_online++; - - $username_full = '' . $username_full . ''; - $s_user_hidden = true; - } - else - { - $view_online = true; - $logged_visible_online++; - } - - $prev_id[$row['user_id']] = 1; - - if ($view_online) - { - $counter++; - } - - if (!$view_online || $counter > $start + $config['topics_per_page'] || $counter <= $start) - { - continue; - } - } - else if ($show_guests && $row['user_id'] == ANONYMOUS && !isset($prev_ip[$row['session_ip']])) - { - $prev_ip[$row['session_ip']] = 1; - $guest_counter++; - $counter++; - - if ($counter > $start + $config['topics_per_page'] || $counter <= $start) - { - continue; - } - - $s_user_hidden = false; - $username_full = get_username_string('full', $row['user_id'], $user->lang['GUEST']); - } - else - { - continue; - } - - $on_page = $viewonline_helper->get_user_page($row['session_page']); - - switch ($on_page[1]) - { - case 'index': - $location = $user->lang['INDEX']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case $phpbb_adm_relative_path . 'index': - $location = $user->lang['ACP']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case 'posting': - case 'viewforum': - case 'viewtopic': - $forum_id = $row['session_forum_id']; - - if ($forum_id && $auth->acl_get('f_list', $forum_id)) - { - $location = ''; - $location_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); - - if ($forum_data[$forum_id]['forum_type'] == FORUM_LINK) - { - $location = sprintf($user->lang['READING_LINK'], $forum_data[$forum_id]['forum_name']); - break; - } - - switch ($on_page[1]) - { - case 'posting': - preg_match('#mode=([a-z]+)#', $row['session_page'], $on_page); - $posting_mode = (!empty($on_page[1])) ? $on_page[1] : ''; - - switch ($posting_mode) - { - case 'reply': - case 'quote': - $location = sprintf($user->lang['REPLYING_MESSAGE'], $forum_data[$forum_id]['forum_name']); - break; - - default: - $location = sprintf($user->lang['POSTING_MESSAGE'], $forum_data[$forum_id]['forum_name']); - break; - } - break; - - case 'viewtopic': - $location = sprintf($user->lang['READING_TOPIC'], $forum_data[$forum_id]['forum_name']); - break; - - case 'viewforum': - $location = sprintf($user->lang['READING_FORUM'], $forum_data[$forum_id]['forum_name']); - break; - } - } - else - { - $location = $user->lang['INDEX']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - } - break; - - case 'search': - $location = $user->lang['SEARCHING_FORUMS']; - $location_url = append_sid("{$phpbb_root_path}search.$phpEx"); - break; - - case 'viewonline': - $location = $user->lang['VIEWING_ONLINE']; - $location_url = append_sid("{$phpbb_root_path}viewonline.$phpEx"); - break; - - case 'memberlist': - $location_url = append_sid("{$phpbb_root_path}memberlist.$phpEx"); - - if (strpos($row['session_page'], 'mode=viewprofile') !== false) - { - $location = $user->lang['VIEWING_MEMBER_PROFILE']; - } - else if (strpos($row['session_page'], 'mode=contactadmin') !== false) - { - $location = $user->lang['VIEWING_CONTACT_ADMIN']; - $location_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin'); - } - else - { - $location = $user->lang['VIEWING_MEMBERS']; - } - break; - - case 'mcp': - $location = $user->lang['VIEWING_MCP']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case 'ucp': - $location = $user->lang['VIEWING_UCP']; - - // Grab some common modules - $url_params = array( - 'mode=register' => 'VIEWING_REGISTER', - 'i=pm&mode=compose' => 'POSTING_PRIVATE_MESSAGE', - 'i=pm&' => 'VIEWING_PRIVATE_MESSAGES', - 'i=profile&' => 'CHANGING_PROFILE', - 'i=prefs&' => 'CHANGING_PREFERENCES', - ); - - foreach ($url_params as $param => $lang) - { - if (strpos($row['session_page'], $param) !== false) - { - $location = $user->lang[$lang]; - break; - } - } - - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case 'download/file': - $location = $user->lang['DOWNLOADING_FILE']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - case 'report': - $location = $user->lang['REPORTING_POST']; - $location_url = append_sid("{$phpbb_root_path}index.$phpEx"); - break; - - 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; - } - - /** - * Overwrite the location's name and URL, which are displayed in the list - * - * @event core.viewonline_overwrite_location - * @var array on_page File name and query string - * @var array row Array with the users sql row - * @var string location Page name to displayed in the list - * @var string location_url Page url to displayed in the list - * @var array forum_data Array with forum data - * @since 3.1.0-a1 - * @changed 3.1.0-a2 Added var forum_data - */ - $vars = array('on_page', 'row', 'location', 'location_url', 'forum_data'); - extract($phpbb_dispatcher->trigger_event('core.viewonline_overwrite_location', compact($vars))); - - $template_row = array( - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => $row['user_colour'], - 'USERNAME_FULL' => $username_full, - 'LASTUPDATE' => $user->format_date($row['session_time']), - 'FORUM_LOCATION' => $location, - 'USER_IP' => ($auth->acl_get('a_')) ? (($mode == 'lookup' && $session_id == $row['session_id']) ? gethostbyaddr($row['session_ip']) : $row['session_ip']) : '', - 'USER_BROWSER' => ($auth->acl_get('a_user')) ? $row['session_browser'] : '', - - 'U_USER_PROFILE' => ($row['user_type'] != USER_IGNORE) ? get_username_string('profile', $row['user_id'], '') : '', - 'U_USER_IP' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'mode=lookup' . (($mode != 'lookup' || $row['session_id'] != $session_id) ? '&s=' . $row['session_id'] : '') . "&sg=$show_guests&start=$start&sk=$sort_key&sd=$sort_dir"), - 'U_WHOIS' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'mode=whois&s=' . $row['session_id']), - 'U_FORUM_LOCATION' => $location_url, - - 'S_USER_HIDDEN' => $s_user_hidden, - 'S_GUEST' => ($row['user_id'] == ANONYMOUS) ? true : false, - 'S_USER_TYPE' => $row['user_type'], - ); - - /** - * Modify viewonline template data before it is displayed in the list - * - * @event core.viewonline_modify_user_row - * @var array on_page File name and query string - * @var array row Array with the users sql row - * @var array forum_data Array with forum data - * @var array template_row Array with template variables for the user row - * @since 3.1.0-RC4 - */ - $vars = array('on_page', 'row', 'forum_data', 'template_row'); - extract($phpbb_dispatcher->trigger_event('core.viewonline_modify_user_row', compact($vars))); - - $template->assign_block_vars('user_row', $template_row); -} -$db->sql_freeresult($result); -unset($prev_id, $prev_ip); - -$order_legend = ($config['legend_sort_groupname']) ? 'group_name' : 'group_legend'; -// Grab group details for legend display -if ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) -{ - $sql = 'SELECT group_id, group_name, group_colour, group_type, group_legend - FROM ' . GROUPS_TABLE . ' - WHERE group_legend > 0 - ORDER BY ' . $order_legend . ' ASC'; -} -else -{ - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, g.group_legend - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug - ON ( - g.group_id = ug.group_id - AND ug.user_id = ' . $user->data['user_id'] . ' - AND ug.user_pending = 0 - ) - WHERE g.group_legend > 0 - AND (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ') - ORDER BY g.' . $order_legend . ' ASC'; -} -$result = $db->sql_query($sql); - -$legend = ''; -while ($row = $db->sql_fetchrow($result)) -{ - if ($row['group_name'] == 'BOTS') - { - $legend .= (($legend != '') ? ', ' : '') . '' . $user->lang['G_BOTS'] . ''; - } - else - { - $legend .= (($legend != '') ? ', ' : '') . '' . $group_helper->get_name($row['group_name']) . ''; - } -} -$db->sql_freeresult($result); - -// Refreshing the page every 60 seconds... -meta_refresh(60, append_sid("{$phpbb_root_path}viewonline.$phpEx", "sg=$show_guests&sk=$sort_key&sd=$sort_dir&start=$start")); - -$start = $pagination->validate_start($start, $config['topics_per_page'], $counter); -$base_url = append_sid("{$phpbb_root_path}viewonline.$phpEx", "sg=$show_guests&sk=$sort_key&sd=$sort_dir"); -$pagination->generate_template_pagination($base_url, 'pagination', 'start', $counter, $config['topics_per_page'], $start); - -// Send data to template -$template->assign_vars(array( - 'TOTAL_REGISTERED_USERS_ONLINE' => $user->lang('REG_USERS_ONLINE', (int) $logged_visible_online, $user->lang('HIDDEN_USERS_ONLINE', (int) $logged_hidden_online)), - 'TOTAL_GUEST_USERS_ONLINE' => $user->lang('GUEST_USERS_ONLINE', (int) $guest_counter), - 'LEGEND' => $legend, - - 'U_SORT_USERNAME' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'sk=a&sd=' . (($sort_key == 'a' && $sort_dir == 'a') ? 'd' : 'a') . '&sg=' . ((int) $show_guests)), - 'U_SORT_UPDATED' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'sk=b&sd=' . (($sort_key == 'b' && $sort_dir == 'a') ? 'd' : 'a') . '&sg=' . ((int) $show_guests)), - 'U_SORT_LOCATION' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'sk=c&sd=' . (($sort_key == 'c' && $sort_dir == 'a') ? 'd' : 'a') . '&sg=' . ((int) $show_guests)), - - 'U_SWITCH_GUEST_DISPLAY' => append_sid("{$phpbb_root_path}viewonline.$phpEx", 'sg=' . ((int) !$show_guests)), - 'L_SWITCH_GUEST_DISPLAY' => ($show_guests) ? $user->lang['HIDE_GUESTS'] : $user->lang['DISPLAY_GUESTS'], - 'S_SWITCH_GUEST_DISPLAY' => ($config['load_online_guests']) ? true : false, - 'S_VIEWONLINE' => true, -)); - -// We do not need to load the who is online box here. ;) -$config['load_online'] = false; - -// Output the page -page_header($user->lang['WHO_IS_ONLINE']); - -$template->set_filenames(array( - 'body' => 'viewonline_body.html') -); -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx")); - -page_footer(); diff --git a/install/update/old/viewtopic.php b/install/update/old/viewtopic.php deleted file mode 100644 index eb2d52c..0000000 --- a/install/update/old/viewtopic.php +++ /dev/null @@ -1,2380 +0,0 @@ - -* @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); -$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); -include($phpbb_root_path . 'includes/bbcode.' . $phpEx); -include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - -// Start session management -$user->session_begin(); -$auth->acl($user->data); - -// Initial var setup -$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 = (count($voted_id) > 1) ? array_unique($voted_id) : $voted_id; - - -$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->variable('st', $default_sort_days); -$sort_key = $request->variable('sk', $default_sort_key); -$sort_dir = $request->variable('sd', $default_sort_dir); - -$update = $request->variable('update', false); - -/* @var $pagination \phpbb\pagination */ -$pagination = $phpbb_container->get('pagination'); - -$s_can_vote = false; -/** -* @todo normalize? -*/ -$hilit_words = $request->variable('hilit', '', true); - -// Do we have a topic or post id? -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 -if ($view && !$post_id) -{ - if (!$forum_id) - { - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . " - WHERE topic_id = $topic_id"; - $result = $db->sql_query($sql); - $forum_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - if (!$forum_id) - { - trigger_error('NO_TOPIC'); - } - } - - if ($view == 'unread') - { - // Get topic tracking info - $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id); - $topic_last_read = (isset($topic_tracking_info[$topic_id])) ? $topic_tracking_info[$topic_id] : 0; - - $sql = 'SELECT post_id, topic_id, forum_id - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . " - AND post_time > $topic_last_read - AND forum_id = $forum_id - ORDER BY post_time ASC, post_id ASC"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $sql = 'SELECT topic_last_post_id as post_id, topic_id, forum_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - if (!$row) - { - // Setup user environment so we can process lang string - $user->setup('viewtopic'); - - trigger_error('NO_TOPIC'); - } - - $post_id = $row['post_id']; - $topic_id = $row['topic_id']; - } - else if ($view == 'next' || $view == 'previous') - { - $sql_condition = ($view == 'next') ? '>' : '<'; - $sql_ordering = ($view == 'next') ? 'ASC' : 'DESC'; - - $sql = 'SELECT forum_id, topic_last_post_time - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $user->setup('viewtopic'); - // OK, the topic doesn't exist. This error message is not helpful, but technically correct. - trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS'); - } - else - { - $sql = 'SELECT topic_id, forum_id - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = ' . $row['forum_id'] . " - AND topic_moved_id = 0 - AND topic_last_post_time $sql_condition {$row['topic_last_post_time']} - AND " . $phpbb_content_visibility->get_visibility_sql('topic', $row['forum_id']) . " - ORDER BY topic_last_post_time $sql_ordering, topic_last_post_id $sql_ordering"; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $sql = 'SELECT forum_style - FROM ' . FORUMS_TABLE . " - WHERE forum_id = $forum_id"; - $result = $db->sql_query($sql); - $forum_style = (int) $db->sql_fetchfield('forum_style'); - $db->sql_freeresult($result); - - $user->setup('viewtopic', $forum_style); - trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS'); - } - else - { - $topic_id = $row['topic_id']; - $forum_id = $row['forum_id']; - } - } - } - - if (isset($row) && $row['forum_id']) - { - $forum_id = $row['forum_id']; - } -} - -// This rather complex gaggle of code handles querying for topics but -// also allows for direct linking to a post (and the calculation of which -// page the post is on and the correct display of viewtopic) -$sql_array = array( - 'SELECT' => 't.*, f.*', - - 'FROM' => array(FORUMS_TABLE => 'f'), -); - -// The FROM-Order is quite important here, else t.* columns can not be correctly bound. -if ($post_id) -{ - $sql_array['SELECT'] .= ', p.post_visibility, p.post_time, p.post_id'; - $sql_array['FROM'][POSTS_TABLE] = 'p'; -} - -// Topics table need to be the last in the chain -$sql_array['FROM'][TOPICS_TABLE] = 't'; - -if ($user->data['is_registered']) -{ - $sql_array['SELECT'] .= ', tw.notify_status'; - $sql_array['LEFT_JOIN'] = array(); - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_WATCH_TABLE => 'tw'), - 'ON' => 'tw.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tw.topic_id' - ); - - if ($config['allow_bookmarks']) - { - $sql_array['SELECT'] .= ', bm.topic_id as bookmarked'; - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(BOOKMARKS_TABLE => 'bm'), - 'ON' => 'bm.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = bm.topic_id' - ); - } - - if ($config['load_db_lastread']) - { - $sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time'; - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_TRACK_TABLE => 'tt'), - 'ON' => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id' - ); - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(FORUMS_TRACK_TABLE => 'ft'), - 'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id' - ); - } -} - -if (!$post_id) -{ - $sql_array['WHERE'] = "t.topic_id = $topic_id"; -} -else -{ - $sql_array['WHERE'] = "p.post_id = $post_id AND t.topic_id = p.topic_id"; -} - -$sql_array['WHERE'] .= ' AND f.forum_id = t.forum_id'; - -$sql = $db->sql_build_query('SELECT', $sql_array); -$result = $db->sql_query($sql); -$topic_data = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -// link to unapproved post or incorrect link -if (!$topic_data) -{ - // If post_id was submitted, we try at least to display the topic as a last resort... - if ($post_id && $topic_id) - { - redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&f=$forum_id" : ''))); - } - - trigger_error('NO_TOPIC'); -} - -$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 (!$phpbb_content_visibility->is_visible('topic', $forum_id, $topic_data)) -{ - trigger_error('NO_TOPIC'); -} - -// This is for determining where we are (page) -if ($post_id) -{ - // are we where we are supposed to be? - if (($topic_data['post_visibility'] == ITEM_UNAPPROVED || $topic_data['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $topic_data['forum_id'])) - { - // If post_id was submitted, we try at least to display the topic as a last resort... - if ($topic_id) - { - redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&f=$forum_id" : ''))); - } - - trigger_error('NO_TOPIC'); - } - if ($post_id == $topic_data['topic_first_post_id'] || $post_id == $topic_data['topic_last_post_id']) - { - $check_sort = ($post_id == $topic_data['topic_first_post_id']) ? 'd' : 'a'; - - if ($sort_dir == $check_sort) - { - $topic_data['prev_posts'] = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1; - } - else - { - $topic_data['prev_posts'] = 0; - } - } - else - { - $sql = 'SELECT COUNT(p.post_id) AS prev_posts - FROM ' . POSTS_TABLE . " p - WHERE p.topic_id = {$topic_data['topic_id']} - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.'); - - if ($sort_dir == 'd') - { - $sql .= " AND (p.post_time > {$topic_data['post_time']} OR (p.post_time = {$topic_data['post_time']} AND p.post_id >= {$topic_data['post_id']}))"; - } - else - { - $sql .= " AND (p.post_time < {$topic_data['post_time']} OR (p.post_time = {$topic_data['post_time']} AND p.post_id <= {$topic_data['post_id']}))"; - } - - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $topic_data['prev_posts'] = $row['prev_posts'] - 1; - } -} - -$topic_id = (int) $topic_data['topic_id']; -$topic_replies = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1; - -// 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 - WHERE topic_id = ' . $topic_id; - $db->sql_query($sql); - - $topic_data['topic_type'] = POST_NORMAL; - $topic_data['topic_time_limit'] = 0; -} - -// 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; - -/** -* Event to apply extra permissions and to override original phpBB's f_read permission and forum password check -* on viewtopic access -* -* @event core.viewtopic_before_f_read_check -* @var int forum_id The forum id from where the topic belongs -* @var int topic_id The id of the topic the user tries to access -* @var int post_id The id of the post the user tries to start viewing at. -* It may be 0 for none given. -* @var array topic_data All the information from the topic and forum tables for this topic -* It includes posts information if post_id is not 0 -* @var bool overrides_f_read_check Set true to remove f_read check afterwards -* @var bool overrides_forum_password_check Set true to remove forum_password check afterwards -* @var array topic_tracking_info Information upon calling get_topic_tracking() -* Set it to NULL to allow auto-filling later. -* Set it to an array to override original data. -* @since 3.1.3-RC1 -*/ -$vars = array( - 'forum_id', - 'topic_id', - 'post_id', - 'topic_data', - 'overrides_f_read_check', - 'overrides_forum_password_check', - 'topic_tracking_info', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_before_f_read_check', compact($vars))); - -// Start auth check -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'); - } - - login_box('', $user->lang['LOGIN_VIEWFORUM']); -} - -// Forum is passworded ... check whether access has been granted to this -// user this session, if not show login box -if (!$overrides_forum_password_check && $topic_data['forum_password']) -{ - login_forum_box($topic_data); -} - -// Redirect to login upon emailed notification links if user is not logged in. -if (isset($_GET['e']) && $user->data['user_id'] == ANONYMOUS) -{ - login_box(build_url('e') . '#unread', $user->lang['LOGIN_NOTIFY_TOPIC']); -} - -// What is start equal to? -if ($post_id) -{ - $start = floor(($topic_data['prev_posts']) / $config['posts_per_page']) * $config['posts_per_page']; -} - -// Get topic tracking info -if (!isset($topic_tracking_info)) -{ - $topic_tracking_info = array(); - - // Get topic tracking info - if ($config['load_db_lastread'] && $user->data['is_registered']) - { - $tmp_topic_data = array($topic_id => $topic_data); - $topic_tracking_info = get_topic_tracking($forum_id, $topic_id, $tmp_topic_data, array($forum_id => $topic_data['forum_mark_time'])); - unset($tmp_topic_data); - } - else if ($config['load_anon_lastread'] || $user->data['is_registered']) - { - $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id); - } -} - -// Post ordering options -$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' => array('u.username_clean', 'p.post_id'), 't' => array('p.post_time', 'p.post_id'), 's' => array('p.post_subject', 'p.post_id')); -$join_user_sql = array('a' => true, 't' => false, 's' => false); - -$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - -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 -// requested anything different -if ($sort_days) -{ - $min_post_time = time() - ($sort_days * 86400); - - $sql = 'SELECT COUNT(post_id) AS num_posts - FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id - AND post_time >= $min_post_time - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id); - $result = $db->sql_query($sql); - $total_posts = (int) $db->sql_fetchfield('num_posts'); - $db->sql_freeresult($result); - - $limit_posts_time = "AND p.post_time >= $min_post_time "; - - if (isset($_POST['sort'])) - { - $start = 0; - } -} -else -{ - $total_posts = $topic_replies + 1; - $limit_posts_time = ''; -} - -// Was a highlight request part of the URI? -$highlight_match = $highlight = ''; -if ($hilit_words) -{ - $highlight_match = phpbb_clean_search_string($hilit_words); - $highlight = urlencode($highlight_match); - $highlight_match = str_replace('\*', '\w+?', preg_quote($highlight_match, '#')); - $highlight_match = preg_replace('#(?<=^|\s)\\\\w\*\?(?=\s|$)#', '\w+?', $highlight_match); - $highlight_match = str_replace(' ', '|', $highlight_match); -} - -// Make sure $start is set to the last page if it exceeds the amount -$start = $pagination->validate_start($start, $config['posts_per_page'], $total_posts); - -// General Viewtopic URL for return links -$viewtopic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($highlight_match) ? "&hilit=$highlight" : '')); - -// Are we watching this topic? -$s_watching_topic = array( - 'link' => '', - 'link_toggle' => '', - 'title' => '', - 'title_toggle' => '', - 'is_watching' => false, -); - -if ($config['allow_topic_notify']) -{ - $notify_status = (isset($topic_data['notify_status'])) ? $topic_data['notify_status'] : null; - watch_topic_forum('topic', $s_watching_topic, $user->data['user_id'], $forum_id, $topic_id, $notify_status, $start, $topic_data['topic_title']); - - // Reset forum notification if forum notify is set - if ($config['allow_forum_notify'] && $auth->acl_get('f_subscribe', $forum_id)) - { - $s_watching_forum = $s_watching_topic; - watch_topic_forum('forum', $s_watching_forum, $user->data['user_id'], $forum_id, 0); - } -} - -/** -* Event to modify highlight. -* -* @event core.viewtopic_highlight_modify -* @var string highlight String to be highlighted -* @var string highlight_match Highlight string to be used in preg_replace -* @var array topic_data Topic data -* @var int start Pagination start -* @var int total_posts Number of posts -* @var string viewtopic_url Current viewtopic URL -* @since 3.1.11-RC1 -*/ -$vars = array( - 'highlight', - 'highlight_match', - 'topic_data', - 'start', - 'total_posts', - 'viewtopic_url', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_highlight_modify', compact($vars))); - -// Bookmarks -if ($config['allow_bookmarks'] && $user->data['is_registered'] && $request->variable('bookmark', 0)) -{ - if (check_link_hash($request->variable('hash', ''), "topic_$topic_id")) - { - if (!$topic_data['bookmarked']) - { - $sql = 'INSERT INTO ' . BOOKMARKS_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'user_id' => $user->data['user_id'], - 'topic_id' => $topic_id, - )); - $db->sql_query($sql); - } - else - { - $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND topic_id = $topic_id"; - $db->sql_query($sql); - } - $message = (($topic_data['bookmarked']) ? $user->lang['BOOKMARK_REMOVED'] : $user->lang['BOOKMARK_ADDED']); - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_TOPIC', '', ''); - } - } - else - { - $message = $user->lang['BOOKMARK_ERR']; - - if (!$request->is_ajax()) - { - $message .= '

' . $user->lang('RETURN_TOPIC', '', ''); - } - } - meta_refresh(3, $viewtopic_url); - - trigger_error($message); -} - -// Grab ranks -$ranks = $cache->obtain_ranks(); - -// Grab icons -$icons = $cache->obtain_icons(); - -// Grab extensions -$extensions = array(); -if ($topic_data['topic_attachment']) -{ - $extensions = $cache->obtain_attach_extensions($forum_id); -} - -// Forum rules listing -$s_forum_rules = ''; -gen_forum_auth_level('topic', $forum_id, $topic_data['forum_status']); - -// Quick mod tools -$allow_change_type = ($auth->acl_get('m_', $forum_id) || ($user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'])) ? true : false; - -$s_quickmod_action = append_sid( - "{$phpbb_root_path}mcp.$phpEx", - array( - 'f' => $forum_id, - 't' => $topic_id, - 'start' => $start, - 'quickmod' => 1, - 'redirect' => urlencode(str_replace('&', '&', $viewtopic_url)), - ), - true, - $user->session_id -); - -$quickmod_array = array( -// 'key' => array('LANG_KEY', $userHasPermissions), - - 'lock' => array('LOCK_TOPIC', ($topic_data['topic_status'] == ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster']))), - 'unlock' => array('UNLOCK_TOPIC', ($topic_data['topic_status'] != ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id))), - 'delete_topic' => array('DELETE_TOPIC', ($auth->acl_get('m_delete', $forum_id) || (($topic_data['topic_visibility'] != ITEM_DELETED) && $auth->acl_get('m_softdelete', $forum_id)))), - 'restore_topic' => array('RESTORE_TOPIC', (($topic_data['topic_visibility'] == ITEM_DELETED) && $auth->acl_get('m_approve', $forum_id))), - 'move' => array('MOVE_TOPIC', $auth->acl_get('m_move', $forum_id) && $topic_data['topic_status'] != ITEM_MOVED), - 'split' => array('SPLIT_TOPIC', $auth->acl_get('m_split', $forum_id)), - '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', '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_global', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL)), - 'topic_logs' => array('VIEW_TOPIC_LOGS', $auth->acl_get('m_', $forum_id)), -); - -/** -* Event to modify data in the quickmod_array before it gets sent to the -* phpbb_add_quickmod_option function. -* -* @event core.viewtopic_add_quickmod_option_before -* @var int forum_id Forum ID -* @var int post_id Post ID -* @var array quickmod_array Array with quick moderation options data -* @var array topic_data Array with topic data -* @var int topic_id Topic ID -* @var array topic_tracking_info Array with topic tracking data -* @var string viewtopic_url URL to the topic page -* @var bool allow_change_type Topic change permissions check -* @since 3.1.9-RC1 -*/ -$vars = array( - 'forum_id', - 'post_id', - 'quickmod_array', - 'topic_data', - 'topic_id', - 'topic_tracking_info', - 'viewtopic_url', - 'allow_change_type', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_add_quickmod_option_before', compact($vars))); - -foreach ($quickmod_array as $option => $qm_ary) -{ - if (!empty($qm_ary[1])) - { - phpbb_add_quickmod_option($s_quickmod_action, $option, $qm_ary[0]); - } -} - -// Navigation links -generate_forum_nav($topic_data); - -// Forum Rules -generate_forum_rules($topic_data); - -// Moderators -$forum_moderators = array(); -if ($config['load_moderators']) -{ - get_moderators($forum_moderators, $forum_id); -} - -// This is only used for print view so ... -$server_path = (!$view) ? $phpbb_root_path : generate_board_url() . '/'; - -// Replace naughty words in title -$topic_data['topic_title'] = censor_text($topic_data['topic_title']); - -$s_search_hidden_fields = array( - 't' => $topic_id, - 'sf' => 'msgonly', -); -if ($_SID) -{ - $s_search_hidden_fields['sid'] = $_SID; -} - -if (!empty($_EXTRA_URL)) -{ - foreach ($_EXTRA_URL as $url_param) - { - $url_param = explode('=', $url_param, 2); - $s_search_hidden_fields[$url_param[0]] = $url_param[1]; - } -} - -// If we've got a hightlight set pass it on to pagination. -$base_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . ((strlen($u_sort_param)) ? "&$u_sort_param" : '') . (($highlight_match) ? "&hilit=$highlight" : '')); - -/** -* Event to modify data before template variables are being assigned -* -* @event core.viewtopic_assign_template_vars_before -* @var string base_url URL to be passed to generate pagination -* @var int forum_id Forum ID -* @var int post_id Post ID -* @var array quickmod_array Array with quick moderation options data -* @var int start Pagination information -* @var array topic_data Array with topic data -* @var int topic_id Topic ID -* @var array topic_tracking_info Array with topic tracking data -* @var int total_posts Topic total posts count -* @var string viewtopic_url URL to the topic page -* @since 3.1.0-RC4 -* @changed 3.1.2-RC1 Added viewtopic_url -*/ -$vars = array( - 'base_url', - 'forum_id', - 'post_id', - 'quickmod_array', - 'start', - 'topic_data', - 'topic_id', - 'topic_tracking_info', - 'total_posts', - 'viewtopic_url', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_assign_template_vars_before', compact($vars))); - -$pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_posts, $config['posts_per_page'], $start); - -// Send vars to template -$template->assign_vars(array( - 'FORUM_ID' => $forum_id, - 'FORUM_NAME' => $topic_data['forum_name'], - 'FORUM_DESC' => generate_text_for_display($topic_data['forum_desc'], $topic_data['forum_desc_uid'], $topic_data['forum_desc_bitfield'], $topic_data['forum_desc_options']), - 'TOPIC_ID' => $topic_id, - 'TOPIC_TITLE' => $topic_data['topic_title'], - 'TOPIC_POSTER' => $topic_data['topic_poster'], - - 'TOPIC_AUTHOR_FULL' => get_username_string('full', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']), - 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']), - 'TOPIC_AUTHOR' => get_username_string('username', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']), - - '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&mode=topic_view&f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . ((strlen($u_sort_param)) ? "&$u_sort_param" : ''), true, $user->session_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'), - 'REPLY_IMG' => ($topic_data['forum_status'] == ITEM_LOCKED || $topic_data['topic_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'TOPIC_LOCKED') : $user->img('button_topic_reply', 'REPLY_TO_TOPIC'), - 'EDIT_IMG' => $user->img('icon_post_edit', 'EDIT_POST'), - 'DELETE_IMG' => $user->img('icon_post_delete', 'DELETE_POST'), - 'DELETED_IMG' => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'), - 'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'), - 'PROFILE_IMG' => $user->img('icon_user_profile', 'READ_PROFILE'), - 'SEARCH_IMG' => $user->img('icon_user_search', 'SEARCH_USER_POSTS'), - 'PM_IMG' => $user->img('icon_contact_pm', 'SEND_PRIVATE_MESSAGE'), - 'EMAIL_IMG' => $user->img('icon_contact_email', 'SEND_EMAIL'), - 'JABBER_IMG' => $user->img('icon_contact_jabber', 'JABBER') , - 'REPORT_IMG' => $user->img('icon_post_report', 'REPORT_POST'), - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'), - 'WARN_IMG' => $user->img('icon_user_warn', 'WARN_USER'), - - 'S_IS_LOCKED' => ($topic_data['topic_status'] == ITEM_UNLOCKED && $topic_data['forum_status'] == ITEM_UNLOCKED) ? false : true, - 'S_SELECT_SORT_DIR' => $s_sort_dir, - 'S_SELECT_SORT_KEY' => $s_sort_key, - 'S_SELECT_SORT_DAYS' => $s_limit_days, - '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&t=$topic_id" . (($start == 0) ? '' : "&start=$start")), - 'S_MOD_ACTION' => $s_quickmod_action, - - 'L_RETURN_TO_FORUM' => $user->lang('RETURN_TO', $topic_data['forum_name']), - 'S_VIEWTOPIC' => true, - 'S_UNREAD_VIEW' => $view == 'unread', - '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_DISPLAY_POST_INFO' => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false, - 'S_DISPLAY_REPLY_INFO' => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false, - 'S_ENABLE_FEEDS_TOPIC' => ($config['feed_topic'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $topic_data['forum_options'])) ? true : false, - - 'U_TOPIC' => "{$server_path}viewtopic.$phpEx?f=$forum_id&t=$topic_id", - 'U_FORUM' => $server_path, - 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start") . (strlen($u_sort_param) ? "&$u_sort_param" : '')), - 'U_CANONICAL' => generate_board_url() . '/' . append_sid("viewtopic.$phpEx", "t=$topic_id" . (($start) ? "&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&t=$topic_id&view=previous"), - 'U_VIEW_NEWER_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=next"), - 'U_PRINT_TOPIC' => ($auth->acl_get('f_print', $forum_id)) ? $viewtopic_url . '&view=print' : '', - 'U_EMAIL_TOPIC' => ($auth->acl_get('f_email', $forum_id) && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&t=$topic_id") : '', - - 'U_WATCH_TOPIC' => $s_watching_topic['link'], - 'U_WATCH_TOPIC_TOGGLE' => $s_watching_topic['link_toggle'], - 'S_WATCH_TOPIC_TITLE' => $s_watching_topic['title'], - 'S_WATCH_TOPIC_TOGGLE' => $s_watching_topic['title_toggle'], - 'S_WATCHING_TOPIC' => $s_watching_topic['is_watching'], - - 'U_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks']) ? $viewtopic_url . '&bookmark=1&hash=' . generate_link_hash("topic_$topic_id") : '', - 'S_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], - 'S_BOOKMARK_TOGGLE' => (!$user->data['is_registered'] || !$config['allow_bookmarks'] || !$topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], - 'S_BOOKMARKED_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? true : false, - - 'U_POST_NEW_TOPIC' => ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=post&f=$forum_id") : '', - 'U_POST_REPLY_TOPIC' => ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&f=$forum_id&t=$topic_id") : '', - 'U_BUMP_TOPIC' => (bump_topic_allowed($forum_id, $topic_data['topic_bumped'], $topic_data['topic_last_post_time'], $topic_data['topic_poster'], $topic_data['topic_last_poster_id'])) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=bump&f=$forum_id&t=$topic_id&hash=" . generate_link_hash("topic_$topic_id")) : '') -); - -// Does this topic contain a poll? -if (!empty($topic_data['poll_start'])) -{ - $sql = 'SELECT o.*, p.bbcode_bitfield, p.bbcode_uid - FROM ' . POLL_OPTIONS_TABLE . ' o, ' . POSTS_TABLE . " p - WHERE o.topic_id = $topic_id - AND p.post_id = {$topic_data['topic_first_post_id']} - AND p.topic_id = o.topic_id - ORDER BY o.poll_option_id"; - $result = $db->sql_query($sql); - - $poll_info = $vote_counts = array(); - while ($row = $db->sql_fetchrow($result)) - { - $poll_info[] = $row; - $option_id = (int) $row['poll_option_id']; - $vote_counts[$option_id] = (int) $row['poll_option_total']; - } - $db->sql_freeresult($result); - - $cur_voted_id = array(); - if ($user->data['is_registered']) - { - $sql = 'SELECT poll_option_id - FROM ' . POLL_VOTES_TABLE . ' - WHERE topic_id = ' . $topic_id . ' - AND vote_user_id = ' . $user->data['user_id']; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $cur_voted_id[] = $row['poll_option_id']; - } - $db->sql_freeresult($result); - } - else - { - // Cookie based guest tracking ... I don't like this but hum ho - // it's oft requested. This relies on "nice" users who don't feel - // the need to delete cookies to mess with results. - if ($request->is_set($config['cookie_name'] . '_poll_' . $topic_id, \phpbb\request\request_interface::COOKIE)) - { - $cur_voted_id = explode(',', $request->variable($config['cookie_name'] . '_poll_' . $topic_id, '', true, \phpbb\request\request_interface::COOKIE)); - $cur_voted_id = array_map('intval', $cur_voted_id); - } - } - - // Can not vote at all if no vote permission - $s_can_vote = ($auth->acl_get('f_vote', $forum_id) && - (($topic_data['poll_length'] != 0 && $topic_data['poll_start'] + $topic_data['poll_length'] > time()) || $topic_data['poll_length'] == 0) && - $topic_data['topic_status'] != ITEM_LOCKED && - $topic_data['forum_status'] != ITEM_LOCKED && - (!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 && count($cur_voted_id)) || $view == 'viewpoll') ? true : false; - - /** - * Event to manipulate the poll data - * - * @event core.viewtopic_modify_poll_data - * @var array cur_voted_id Array with options' IDs current user has voted for - * @var int forum_id The topic's forum id - * @var array poll_info Array with the poll information - * @var bool s_can_vote Flag indicating if a user can vote - * @var bool s_display_results Flag indicating if results or poll options should be displayed - * @var int topic_id The id of the topic the user tries to access - * @var array topic_data All the information from the topic and forum tables for this topic - * @var string viewtopic_url URL to the topic page - * @var array vote_counts Array with the vote counts for every poll option - * @var array voted_id Array with updated options' IDs current user is voting for - * @since 3.1.5-RC1 - */ - $vars = array( - 'cur_voted_id', - 'forum_id', - 'poll_info', - 's_can_vote', - 's_display_results', - 'topic_id', - 'topic_data', - 'viewtopic_url', - 'vote_counts', - 'voted_id', - ); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_data', compact($vars))); - - if ($update && $s_can_vote) - { - - 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&t=$topic_id" . (($start == 0) ? '' : "&start=$start")); - - meta_refresh(5, $redirect_url); - if (!count($voted_id)) - { - $message = 'NO_VOTE_OPTION'; - } - else if (count($voted_id) > $topic_data['poll_max_options']) - { - $message = 'TOO_MANY_VOTE_OPTIONS'; - } - else if (in_array(VOTE_CONVERTED, $cur_voted_id)) - { - $message = 'VOTE_CONVERTED'; - } - else - { - $message = 'FORM_INVALID'; - } - - $message = $user->lang[$message] . '

' . sprintf($user->lang['RETURN_TOPIC'], '', ''); - trigger_error($message); - } - - foreach ($voted_id as $option) - { - if (in_array($option, $cur_voted_id)) - { - continue; - } - - $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . ' - SET poll_option_total = poll_option_total + 1 - WHERE poll_option_id = ' . (int) $option . ' - AND topic_id = ' . (int) $topic_id; - $db->sql_query($sql); - - $vote_counts[$option]++; - - if ($user->data['is_registered']) - { - $sql_ary = array( - 'topic_id' => (int) $topic_id, - 'poll_option_id' => (int) $option, - 'vote_user_id' => (int) $user->data['user_id'], - 'vote_user_ip' => (string) $user->ip, - ); - - $sql = 'INSERT INTO ' . POLL_VOTES_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - } - } - - foreach ($cur_voted_id as $option) - { - if (!in_array($option, $voted_id)) - { - $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . ' - SET poll_option_total = poll_option_total - 1 - WHERE poll_option_id = ' . (int) $option . ' - AND topic_id = ' . (int) $topic_id; - $db->sql_query($sql); - - $vote_counts[$option]--; - - if ($user->data['is_registered']) - { - $sql = 'DELETE FROM ' . POLL_VOTES_TABLE . ' - WHERE topic_id = ' . (int) $topic_id . ' - AND poll_option_id = ' . (int) $option . ' - AND vote_user_id = ' . (int) $user->data['user_id']; - $db->sql_query($sql); - } - } - } - - if ($user->data['user_id'] == ANONYMOUS && !$user->data['is_bot']) - { - $user->set_cookie('poll_' . $topic_id, implode(',', $voted_id), time() + 31536000); - } - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET poll_last_vote = ' . time() . " - WHERE topic_id = $topic_id"; - //, topic_last_post_time = ' . time() . " -- for bumping topics with new votes, ignore for now - $db->sql_query($sql); - - $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id" . (($start == 0) ? '' : "&start=$start")); - $message = $user->lang['VOTE_SUBMITTED'] . '

' . sprintf($user->lang['RETURN_TOPIC'], '', ''); - - if ($request->is_ajax()) - { - // Filter out invalid options - $valid_user_votes = array_intersect(array_keys($vote_counts), $voted_id); - - $data = array( - 'NO_VOTES' => $user->lang['NO_VOTES'], - 'success' => true, - 'user_votes' => array_flip($valid_user_votes), - 'vote_counts' => $vote_counts, - 'total_votes' => array_sum($vote_counts), - '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); - } - - meta_refresh(5, $redirect_url); - trigger_error($message); - } - - $poll_total = 0; - $poll_most = 0; - foreach ($poll_info as $poll_option) - { - $poll_total += $poll_option['poll_option_total']; - $poll_most = ($poll_option['poll_option_total'] >= $poll_most) ? $poll_option['poll_option_total'] : $poll_most; - } - - $parse_flags = ($poll_info[0]['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - - 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); - } - - $topic_data['poll_title'] = generate_text_for_display($topic_data['poll_title'], $poll_info[0]['bbcode_uid'], $poll_info[0]['bbcode_bitfield'], $parse_flags, true); - - $poll_template_data = $poll_options_template_data = array(); - foreach ($poll_info as $poll_option) - { - $option_pct = ($poll_total > 0) ? $poll_option['poll_option_total'] / $poll_total : 0; - $option_pct_txt = sprintf("%.1d%%", round($option_pct * 100)); - $option_pct_rel = ($poll_most > 0) ? $poll_option['poll_option_total'] / $poll_most : 0; - $option_pct_rel_txt = sprintf("%.1d%%", round($option_pct_rel * 100)); - $option_most_votes = ($poll_option['poll_option_total'] > 0 && $poll_option['poll_option_total'] == $poll_most) ? true : false; - - $poll_options_template_data[] = array( - 'POLL_OPTION_ID' => $poll_option['poll_option_id'], - 'POLL_OPTION_CAPTION' => $poll_option['poll_option_text'], - 'POLL_OPTION_RESULT' => $poll_option['poll_option_total'], - 'POLL_OPTION_PERCENT' => $option_pct_txt, - 'POLL_OPTION_PERCENT_REL' => $option_pct_rel_txt, - 'POLL_OPTION_PCT' => round($option_pct * 100), - 'POLL_OPTION_WIDTH' => round($option_pct * 250), - 'POLL_OPTION_VOTED' => (in_array($poll_option['poll_option_id'], $cur_voted_id)) ? true : false, - 'POLL_OPTION_MOST_VOTES' => $option_most_votes, - ); - } - - $poll_end = $topic_data['poll_length'] + $topic_data['poll_start']; - - $poll_template_data = array( - 'POLL_QUESTION' => $topic_data['poll_title'], - 'TOTAL_VOTES' => $poll_total, - 'POLL_LEFT_CAP_IMG' => $user->img('poll_left'), - 'POLL_RIGHT_CAP_IMG'=> $user->img('poll_right'), - - 'L_MAX_VOTES' => $user->lang('MAX_OPTIONS_SELECT', (int) $topic_data['poll_max_options']), - 'L_POLL_LENGTH' => ($topic_data['poll_length']) ? sprintf($user->lang[($poll_end > time()) ? 'POLL_RUN_TILL' : 'POLL_ENDED_AT'], $user->format_date($poll_end)) : '', - - 'S_HAS_POLL' => true, - 'S_CAN_VOTE' => $s_can_vote, - 'S_DISPLAY_RESULTS' => $s_display_results, - 'S_IS_MULTI_CHOICE' => ($topic_data['poll_max_options'] > 1) ? true : false, - 'S_POLL_ACTION' => $viewtopic_url, - - 'U_VIEW_RESULTS' => $viewtopic_url . '&view=viewpoll', - ); - - /** - * Event to add/modify poll template data - * - * @event core.viewtopic_modify_poll_template_data - * @var array cur_voted_id Array with options' IDs current user has voted for - * @var int poll_end The poll end time - * @var array poll_info Array with the poll information - * @var array poll_options_template_data Array with the poll options template data - * @var array poll_template_data Array with the common poll template data - * @var int poll_total Total poll votes count - * @var int poll_most Mostly voted option votes count - * @var array topic_data All the information from the topic and forum tables for this topic - * @var string viewtopic_url URL to the topic page - * @var array vote_counts Array with the vote counts for every poll option - * @var array voted_id Array with updated options' IDs current user is voting for - * @since 3.1.5-RC1 - */ - $vars = array( - 'cur_voted_id', - 'poll_end', - 'poll_info', - 'poll_options_template_data', - 'poll_template_data', - 'poll_total', - 'poll_most', - 'topic_data', - 'viewtopic_url', - 'vote_counts', - 'voted_id', - ); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_template_data', compact($vars))); - - $template->assign_block_vars_array('poll_option', $poll_options_template_data); - - $template->assign_vars($poll_template_data); - - unset($poll_end, $poll_info, $poll_options_template_data, $poll_template_data, $voted_id); -} - -// If the user is trying to reach the second half of the topic, fetch it starting from the end -$store_reverse = false; -$sql_limit = $config['posts_per_page']; -$sql_sort_order = $direction = ''; - -if ($start > $total_posts / 2) -{ - $store_reverse = true; - - // Select the sort order - $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC'); - - $sql_limit = $pagination->reverse_limit($start, $sql_limit, $total_posts); - $sql_start = $pagination->reverse_start($start, $sql_limit, $total_posts); -} -else -{ - // Select the sort order - $direction = (($sort_dir == 'd') ? 'DESC' : 'ASC'); - $sql_start = $start; -} - -if (is_array($sort_by_sql[$sort_key])) -{ - $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction; -} -else -{ - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction; -} - -// Container for user details, only process once -$post_list = $user_cache = $id_cache = $attachments = $attach_list = $rowset = $update_count = $post_edit_list = $post_delete_list = array(); -$has_unapproved_attachments = $has_approved_attachments = $display_notice = false; -$i = $i_total = 0; - -// Go ahead and pull all data for this topic -$sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p' . (($join_user_sql[$sort_key]) ? ', ' . USERS_TABLE . ' u': '') . " - WHERE p.topic_id = $topic_id - AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . " - " . (($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; -while ($row = $db->sql_fetchrow($result)) -{ - $post_list[$i] = (int) $row['post_id']; - ($store_reverse) ? $i-- : $i++; -} -$db->sql_freeresult($result); - -if (!count($post_list)) -{ - if ($sort_days) - { - trigger_error('NO_POSTS_TIME_FRAME'); - } - else - { - trigger_error('NO_TOPIC'); - } -} - -// Holding maximum post time for marking topic read -// We need to grab it because we do reverse ordering sometimes -$max_post_time = 0; - -$sql_ary = array( - 'SELECT' => 'u.*, z.friend, z.foe, p.*', - - 'FROM' => array( - USERS_TABLE => 'u', - POSTS_TABLE => 'p', - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ZEBRA_TABLE => 'z'), - 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id', - ), - ), - - 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . ' - AND u.user_id = p.poster_id', -); - -/** -* Event to modify the SQL query before the post and poster data is retrieved -* -* @event core.viewtopic_get_post_data -* @var int forum_id Forum ID -* @var int topic_id Topic ID -* @var array topic_data Array with topic data -* @var array post_list Array with post_ids we are going to retrieve -* @var int sort_days Display posts of previous x days -* @var string sort_key Key the posts are sorted by -* @var string sort_dir Direction the posts are sorted by -* @var int start Pagination information -* @var array sql_ary The SQL array to get the data of posts and posters -* @since 3.1.0-a1 -* @changed 3.1.0-a2 Added vars forum_id, topic_id, topic_data, post_list, sort_days, sort_key, sort_dir, start -*/ -$vars = array( - 'forum_id', - 'topic_id', - 'topic_data', - 'post_list', - 'sort_days', - 'sort_key', - 'sort_dir', - 'start', - 'sql_ary', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_get_post_data', compact($vars))); - -$sql = $db->sql_build_query('SELECT', $sql_ary); -$result = $db->sql_query($sql); - -$now = $user->create_datetime(); -$now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset()); - -// Posts are stored in the $rowset array while $attach_list, $user_cache -// and the global bbcode_bitfield are built -while ($row = $db->sql_fetchrow($result)) -{ - // Set max_post_time - if ($row['post_time'] > $max_post_time) - { - $max_post_time = $row['post_time']; - } - - $poster_id = (int) $row['poster_id']; - - // Does post have an attachment? If so, add it to the list - if ($row['post_attachment'] && $config['allow_attachments']) - { - $attach_list[] = (int) $row['post_id']; - - if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) - { - $has_unapproved_attachments = true; - } - else if ($row['post_visibility'] == ITEM_APPROVED) - { - $has_approved_attachments = true; - } - } - - $rowset_data = array( - 'hide_post' => (($row['foe'] || $row['post_visibility'] == ITEM_DELETED) && ($view != 'show' || $post_id != $row['post_id'])) ? true : false, - - 'post_id' => $row['post_id'], - 'post_time' => $row['post_time'], - 'user_id' => $row['user_id'], - 'username' => $row['username'], - 'user_colour' => $row['user_colour'], - 'topic_id' => $row['topic_id'], - 'forum_id' => $row['forum_id'], - 'post_subject' => $row['post_subject'], - 'post_edit_count' => $row['post_edit_count'], - 'post_edit_time' => $row['post_edit_time'], - 'post_edit_reason' => $row['post_edit_reason'], - 'post_edit_user' => $row['post_edit_user'], - 'post_edit_locked' => $row['post_edit_locked'], - 'post_delete_time' => $row['post_delete_time'], - 'post_delete_reason'=> $row['post_delete_reason'], - 'post_delete_user' => $row['post_delete_user'], - - // Make sure the icon actually exists - 'icon_id' => (isset($icons[$row['icon_id']]['img'], $icons[$row['icon_id']]['height'], $icons[$row['icon_id']]['width'])) ? $row['icon_id'] : 0, - 'post_attachment' => $row['post_attachment'], - 'post_visibility' => $row['post_visibility'], - 'post_reported' => $row['post_reported'], - 'post_username' => $row['post_username'], - 'post_text' => $row['post_text'], - 'bbcode_uid' => $row['bbcode_uid'], - 'bbcode_bitfield' => $row['bbcode_bitfield'], - 'enable_smilies' => $row['enable_smilies'], - 'enable_sig' => $row['enable_sig'], - 'friend' => $row['friend'], - 'foe' => $row['foe'], - ); - - /** - * Modify the post rowset containing data to be displayed with posts - * - * @event core.viewtopic_post_rowset_data - * @var array rowset_data Array with the rowset data for this post - * @var array row Array with original user and post data - * @since 3.1.0-a1 - */ - $vars = array('rowset_data', 'row'); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_rowset_data', compact($vars))); - - $rowset[$row['post_id']] = $rowset_data; - - // Cache various user specific data ... so we don't have to recompute - // this each time the same user appears on this page - if (!isset($user_cache[$poster_id])) - { - if ($poster_id == ANONYMOUS) - { - $user_cache_data = array( - 'user_type' => USER_IGNORE, - 'joined' => '', - 'posts' => '', - - 'sig' => '', - 'sig_bbcode_uid' => '', - 'sig_bbcode_bitfield' => '', - - 'online' => false, - 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '', - 'rank_title' => '', - 'rank_image' => '', - 'rank_image_src' => '', - 'pm' => '', - 'email' => '', - 'jabber' => '', - 'search' => '', - 'age' => '', - - 'username' => $row['username'], - 'user_colour' => $row['user_colour'], - 'contact_user' => '', - - 'warnings' => 0, - 'allow_pm' => 0, - ); - - /** - * Modify the guest user's data displayed with the posts - * - * @event core.viewtopic_cache_guest_data - * @var array user_cache_data Array with the user's data - * @var int poster_id Poster's user id - * @var array row Array with original user and post data - * @since 3.1.0-a1 - */ - $vars = array('user_cache_data', 'poster_id', 'row'); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_guest_data', compact($vars))); - - $user_cache[$poster_id] = $user_cache_data; - - $user_rank_data = phpbb_get_user_rank($row, false); - $user_cache[$poster_id]['rank_title'] = $user_rank_data['title']; - $user_cache[$poster_id]['rank_image'] = $user_rank_data['img']; - $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src']; - } - else - { - $user_sig = ''; - - // We add the signature to every posters entry because enable_sig is post dependent - if ($row['user_sig'] && $config['allow_sig'] && $user->optionget('viewsigs')) - { - $user_sig = $row['user_sig']; - } - - $id_cache[] = $poster_id; - - $user_cache_data = array( - 'user_type' => $row['user_type'], - 'user_inactive_reason' => $row['user_inactive_reason'], - - 'joined' => $user->format_date($row['user_regdate']), - 'posts' => $row['user_posts'], - 'warnings' => (isset($row['user_warnings'])) ? $row['user_warnings'] : 0, - - 'sig' => $user_sig, - 'sig_bbcode_uid' => (!empty($row['user_sig_bbcode_uid'])) ? $row['user_sig_bbcode_uid'] : '', - 'sig_bbcode_bitfield' => (!empty($row['user_sig_bbcode_bitfield'])) ? $row['user_sig_bbcode_bitfield'] : '', - - 'viewonline' => $row['user_allow_viewonline'], - 'allow_pm' => $row['user_allow_pm'], - - 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '', - 'age' => '', - - 'rank_title' => '', - 'rank_image' => '', - 'rank_image_src' => '', - - 'username' => $row['username'], - 'user_colour' => $row['user_colour'], - 'contact_user' => $user->lang('CONTACT_USER', get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['username'])), - - 'online' => false, - 'jabber' => ($config['jab_enable'] && $row['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=jabber&u=$poster_id") : '', - 'search' => ($config['load_search'] && $auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$poster_id&sr=posts") : '', - - 'author_full' => get_username_string('full', $poster_id, $row['username'], $row['user_colour']), - 'author_colour' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour']), - 'author_username' => get_username_string('username', $poster_id, $row['username'], $row['user_colour']), - 'author_profile' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour']), - ); - - /** - * Modify the users' data displayed with their posts - * - * @event core.viewtopic_cache_user_data - * @var array user_cache_data Array with the user's data - * @var int poster_id Poster's user id - * @var array row Array with original user and post data - * @since 3.1.0-a1 - */ - $vars = array('user_cache_data', 'poster_id', 'row'); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_user_data', compact($vars))); - - $user_cache[$poster_id] = $user_cache_data; - - $user_rank_data = phpbb_get_user_rank($row, $row['user_posts']); - $user_cache[$poster_id]['rank_title'] = $user_rank_data['title']; - $user_cache[$poster_id]['rank_image'] = $user_rank_data['img']; - $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src']; - - if ((!empty($row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email')) - { - $user_cache[$poster_id]['email'] = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&u=$poster_id") : (($config['board_hide_emails'] && !$auth->acl_get('a_email')) ? '' : 'mailto:' . $row['user_email']); - } - else - { - $user_cache[$poster_id]['email'] = ''; - } - - if ($config['allow_birthdays'] && !empty($row['user_birthday'])) - { - list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $row['user_birthday'])); - - if ($bday_year) - { - $diff = $now['mon'] - $bday_month; - if ($diff == 0) - { - $diff = ($now['mday'] - $bday_day < 0) ? 1 : 0; - } - else - { - $diff = ($diff < 0) ? 1 : 0; - } - - $user_cache[$poster_id]['age'] = (int) ($now['year'] - $bday_year - $diff); - } - } - } - } -} -$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 - $profile_fields_tmp = $cp->grab_profile_fields_data($id_cache); - - // filter out fields not to be displayed on viewtopic. Yes, it's a hack, but this shouldn't break any MODs. - $profile_fields_cache = array(); - foreach ($profile_fields_tmp as $profile_user_id => $profile_fields) - { - $profile_fields_cache[$profile_user_id] = array(); - foreach ($profile_fields as $used_ident => $profile_field) - { - if ($profile_field['data']['field_show_on_vt']) - { - $profile_fields_cache[$profile_user_id][$used_ident] = $profile_field; - } - } - } - unset($profile_fields_tmp); -} - -// Generate online information for user -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 . ' - WHERE ' . $db->sql_in_set('session_user_id', $id_cache) . ' - GROUP BY session_user_id'; - $result = $db->sql_query($sql); - - $update_time = $config['load_online_time'] * 60; - while ($row = $db->sql_fetchrow($result)) - { - $user_cache[$row['session_user_id']]['online'] = (time() - $update_time < $row['online_time'] && (($row['viewonline']) || $auth->acl_get('u_viewonline'))) ? true : false; - } - $db->sql_freeresult($result); -} -unset($id_cache); - -// Pull attachment data -if (count($attach_list)) -{ - if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id)) - { - $sql = 'SELECT * - FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . ' - AND in_message = 0 - ORDER BY attach_id DESC, post_msg_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $attachments[$row['post_msg_id']][] = $row; - } - $db->sql_freeresult($result); - - // No attachments exist, but post table thinks they do so go ahead and reset post_attach flags - if (!count($attachments)) - { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_attachment = 0 - WHERE ' . $db->sql_in_set('post_id', $attach_list); - $db->sql_query($sql); - - // We need to update the topic indicator too if the complete topic is now without an attachment - 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 - FROM ' . ATTACHMENTS_TABLE . ' a, ' . POSTS_TABLE . " p - WHERE p.topic_id = $topic_id - AND p.post_visibility = " . ITEM_APPROVED . ' - AND p.topic_id = a.topic_id'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_attachment = 0 - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - } - } - else - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_attachment = 0 - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - } - } - else if ($has_approved_attachments && !$topic_data['topic_attachment']) - { - // Topic has approved attachments but its flag is wrong - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_attachment = 1 - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - $topic_data['topic_attachment'] = 1; - } - else if ($has_unapproved_attachments && !$topic_data['topic_attachment']) - { - // Topic has only unapproved attachments but we have the right to see and download them - $topic_data['topic_attachment'] = 1; - } - } - else - { - $display_notice = true; - } -} - -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); -} -else -{ - $can_receive_pm_list = array_keys($user_cache); - $permanently_banned_users = []; -} - -$i_total = count($rowset) - 1; -$prev_post_id = ''; - -$template->assign_vars(array( - 'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'], - 'S_NUM_POSTS' => count($post_list)) -); - -/** -* Event to modify the post, poster and attachment data before assigning the posts -* -* @event core.viewtopic_modify_post_data -* @var int forum_id Forum ID -* @var int topic_id Topic ID -* @var array topic_data Array with topic data -* @var array post_list Array with post_ids we are going to display -* @var array rowset Array with post_id => post data -* @var array user_cache Array with prepared user data -* @var int start Pagination information -* @var int sort_days Display posts of previous x days -* @var string sort_key Key the posts are sorted by -* @var string sort_dir Direction the posts are sorted by -* @var bool display_notice Shall we display a notice instead of attachments -* @var bool has_approved_attachments Does the topic have approved attachments -* @var array attachments List of attachments post_id => array of attachments -* @var array permanently_banned_users List of permanently banned users -* @var array can_receive_pm_list Array with posters that can receive pms -* @since 3.1.0-RC3 -*/ -$vars = array( - 'forum_id', - 'topic_id', - 'topic_data', - 'post_list', - 'rowset', - 'user_cache', - 'sort_days', - 'sort_key', - 'sort_dir', - 'start', - 'permanently_banned_users', - 'can_receive_pm_list', - 'display_notice', - 'has_approved_attachments', - 'attachments', -); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_data', compact($vars))); - -// Output the posts -$first_unread = $post_unread = false; -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. - if (!isset($rowset[$post_list[$i]])) - { - continue; - } - - $row = $rowset[$post_list[$i]]; - $poster_id = $row['user_id']; - - // End signature parsing, only if needed - if ($user_cache[$poster_id]['sig'] && $row['enable_sig'] && empty($user_cache[$poster_id]['sig_parsed'])) - { - $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 - $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; - $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true); - - if (!empty($attachments[$row['post_id']])) - { - parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count); - } - - // Replace naughty words such as farty pants - $row['post_subject'] = censor_text($row['post_subject']); - - // Highlight active words (primarily for search) - if ($highlight_match) - { - $message = preg_replace('#(?!<.*)(?]*(?:)#is', '\1', $message); - $row['post_subject'] = preg_replace('#(?!<.*)(?]*(?:)#is', '\1', $row['post_subject']); - } - - // Editing information - if (($row['post_edit_count'] && $config['display_last_edited']) || $row['post_edit_reason']) - { - // Get usernames for all following posts if not already stored - 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); - - $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . ' - AND p.post_edit_count <> 0 - AND p.post_edit_user <> 0 - AND p.post_edit_user = u.user_id'; - $result2 = $db->sql_query($sql); - while ($user_edit_row = $db->sql_fetchrow($result2)) - { - $post_edit_list[$user_edit_row['user_id']] = $user_edit_row; - } - $db->sql_freeresult($result2); - - unset($post_storage_list); - } - - if ($row['post_edit_reason']) - { - // User having edited the post also being the post author? - if (!$row['post_edit_user'] || $row['post_edit_user'] == $poster_id) - { - $display_username = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); - } - else - { - $display_username = get_username_string('full', $row['post_edit_user'], $post_edit_list[$row['post_edit_user']]['username'], $post_edit_list[$row['post_edit_user']]['user_colour']); - } - - $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true)); - } - else - { - if ($row['post_edit_user'] && !isset($user_cache[$row['post_edit_user']])) - { - $user_cache[$row['post_edit_user']] = $post_edit_list[$row['post_edit_user']]; - } - - // User having edited the post also being the post author? - if (!$row['post_edit_user'] || $row['post_edit_user'] == $poster_id) - { - $display_username = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); - } - else - { - $display_username = get_username_string('full', $row['post_edit_user'], $user_cache[$row['post_edit_user']]['username'], $user_cache[$row['post_edit_user']]['user_colour']); - } - - $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true)); - } - } - else - { - $l_edited_by = ''; - } - - // Deleting information - if ($row['post_visibility'] == ITEM_DELETED && $row['post_delete_user']) - { - // Get usernames for all following posts if not already stored - 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); - - $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . ' - AND p.post_delete_user <> 0 - AND p.post_delete_user = u.user_id'; - $result2 = $db->sql_query($sql); - while ($user_delete_row = $db->sql_fetchrow($result2)) - { - $post_delete_list[$user_delete_row['user_id']] = $user_delete_row; - } - $db->sql_freeresult($result2); - - unset($post_storage_list); - } - - if ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']])) - { - $user_cache[$row['post_delete_user']] = $post_delete_list[$row['post_delete_user']]; - } - - $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']); - - // User having deleted the post also being the post author? - if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id) - { - $display_username = $display_postername; - } - else - { - $display_username = get_username_string('full', $row['post_delete_user'], $user_cache[$row['post_delete_user']]['username'], $user_cache[$row['post_delete_user']]['user_colour']); - } - - if ($row['post_delete_reason']) - { - $l_deleted_message = $user->lang('POST_DELETED_BY_REASON', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true), $row['post_delete_reason']); - } - else - { - $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true)); - } - $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($row['post_delete_time'], false, true)); - } - else - { - $l_deleted_by = $l_deleted_message = ''; - } - - // Bump information - if ($topic_data['topic_bumped'] && $row['post_id'] == $topic_data['topic_last_post_id'] && isset($user_cache[$topic_data['topic_bumper']]) ) - { - // It is safe to grab the username from the user cache array, we are at the last - // post and only the topic poster and last poster are allowed to bump. - // Admins and mods are bound to the above rules too... - $l_bumped_by = sprintf($user->lang['BUMPED_BY'], $user_cache[$topic_data['topic_bumper']]['username'], $user->format_date($topic_data['topic_last_post_time'], false, true)); - } - else - { - $l_bumped_by = ''; - } - - $cp_row = array(); - - // - if ($config['load_cpf_viewtopic']) - { - $cp_row = (isset($profile_fields_cache[$poster_id])) ? $cp->generate_profile_fields_template_data($profile_fields_cache[$poster_id]) : array(); - } - - $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false; - - $s_first_unread = false; - if (!$first_unread && $post_unread) - { - $s_first_unread = $first_unread = true; - } - - $force_edit_allowed = $force_delete_allowed = $force_softdelete_allowed = false; - - $s_cannot_edit = !$auth->acl_get('f_edit', $forum_id) || $user->data['user_id'] != $poster_id; - $s_cannot_edit_time = $config['edit_time'] && $row['post_time'] <= time() - ($config['edit_time'] * 60); - $s_cannot_edit_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked']; - - $s_cannot_delete = $user->data['user_id'] != $poster_id || ( - !$auth->acl_get('f_delete', $forum_id) && - (!$auth->acl_get('f_softdelete', $forum_id) || $row['post_visibility'] == ITEM_DELETED) - ); - $s_cannot_delete_lastpost = $topic_data['topic_last_post_id'] != $row['post_id']; - $s_cannot_delete_time = $config['delete_time'] && $row['post_time'] <= time() - ($config['delete_time'] * 60); - // we do not want to allow removal of the last post if a moderator locked it! - $s_cannot_delete_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked']; - - /** - * This event allows you to modify the conditions for the "can edit post" and "can delete post" checks - * - * @event core.viewtopic_modify_post_action_conditions - * @var array row Array with post data - * @var array topic_data Array with topic data - * @var bool force_edit_allowed Allow the user to edit the post (all permissions and conditions are ignored) - * @var bool s_cannot_edit User can not edit the post because it's not his - * @var bool s_cannot_edit_locked User can not edit the post because it's locked - * @var bool s_cannot_edit_time User can not edit the post because edit_time has passed - * @var bool force_delete_allowed Allow the user to delete the post (all permissions and conditions are ignored) - * @var bool s_cannot_delete User can not delete the post because it's not his - * @var bool s_cannot_delete_lastpost User can not delete the post because it's not the last post of the topic - * @var bool s_cannot_delete_locked User can not delete the post because it's locked - * @var bool s_cannot_delete_time User can not delete the post because edit_time has passed - * @var bool force_softdelete_allowed Allow the user to ыoftdelete the post (all permissions and conditions are ignored) - * @since 3.1.0-b4 - * @changed 3.1.11-RC1 Added force_softdelete_allowed var - */ - $vars = array( - 'row', - 'topic_data', - 'force_edit_allowed', - 's_cannot_edit', - 's_cannot_edit_locked', - 's_cannot_edit_time', - 'force_delete_allowed', - 's_cannot_delete', - 's_cannot_delete_lastpost', - 's_cannot_delete_locked', - 's_cannot_delete_time', - 'force_softdelete_allowed', - ); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_action_conditions', compact($vars))); - - $edit_allowed = $force_edit_allowed || ($user->data['is_registered'] && ($auth->acl_get('m_edit', $forum_id) || ( - !$s_cannot_edit && - !$s_cannot_edit_time && - !$s_cannot_edit_locked - ))); - - $quote_allowed = $auth->acl_get('m_edit', $forum_id) || ($topic_data['topic_status'] != ITEM_LOCKED && - ($user->data['user_id'] == ANONYMOUS || $auth->acl_get('f_reply', $forum_id)) - ); - - // Only display the quote button if the post is quotable. Posts not approved are not quotable. - $quote_allowed = ($quote_allowed && $row['post_visibility'] == ITEM_APPROVED) ? true : false; - - $delete_allowed = $force_delete_allowed || ($user->data['is_registered'] && ( - ($auth->acl_get('m_delete', $forum_id) || ($auth->acl_get('m_softdelete', $forum_id) && $row['post_visibility'] != ITEM_DELETED)) || - (!$s_cannot_delete && !$s_cannot_delete_lastpost && !$s_cannot_delete_time && !$s_cannot_delete_locked) - )); - - $softdelete_allowed = $force_softdelete_allowed || (($auth->acl_get('m_softdelete', $forum_id) || - ($auth->acl_get('f_softdelete', $forum_id) && $user->data['user_id'] == $poster_id)) && ($row['post_visibility'] != ITEM_DELETED)); - - $permanent_delete_allowed = $force_delete_allowed || ($auth->acl_get('m_delete', $forum_id) || - ($auth->acl_get('f_delete', $forum_id) && $user->data['user_id'] == $poster_id)); - - // Can this user receive a Private Message? - $can_receive_pm = ( - // They must be a "normal" user - $user_cache[$poster_id]['user_type'] != USER_IGNORE && - - // They must not be deactivated by the administrator - ($user_cache[$poster_id]['user_type'] != USER_INACTIVE || $user_cache[$poster_id]['user_inactive_reason'] != INACTIVE_MANUAL) && - - // They must be able to read PMs - in_array($poster_id, $can_receive_pm_list) && - - // They must not be permanently banned - !in_array($poster_id, $permanently_banned_users) && - - // They must allow users to contact via PM - (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $user_cache[$poster_id]['allow_pm']) - ); - - $u_pm = ''; - - if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm) - { - $u_pm = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&action=quotepost&p=' . $row['post_id']); - } - - // - $post_row = array( - 'POST_AUTHOR_FULL' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_full'] : get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_colour'] : get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_username'] : get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_profile'] : get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - - 'RANK_TITLE' => $user_cache[$poster_id]['rank_title'], - 'RANK_IMG' => $user_cache[$poster_id]['rank_image'], - 'RANK_IMG_SRC' => $user_cache[$poster_id]['rank_image_src'], - 'POSTER_JOINED' => $user_cache[$poster_id]['joined'], - 'POSTER_POSTS' => $user_cache[$poster_id]['posts'], - 'POSTER_AVATAR' => $user_cache[$poster_id]['avatar'], - 'POSTER_WARNINGS' => $auth->acl_get('m_warn') ? $user_cache[$poster_id]['warnings'] : '', - 'POSTER_AGE' => $user_cache[$poster_id]['age'], - 'CONTACT_USER' => $user_cache[$poster_id]['contact_user'], - - 'POST_DATE' => $user->format_date($row['post_time'], false, ($view == 'print') ? true : false), - 'POST_SUBJECT' => $row['post_subject'], - 'MESSAGE' => $message, - 'SIGNATURE' => ($row['enable_sig']) ? $user_cache[$poster_id]['sig'] : '', - 'EDITED_MESSAGE' => $l_edited_by, - 'EDIT_REASON' => $row['post_edit_reason'], - 'DELETED_MESSAGE' => $l_deleted_by, - 'DELETE_REASON' => $row['post_delete_reason'], - 'BUMPED_MESSAGE' => $l_bumped_by, - - 'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'), - '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), - - 'U_EDIT' => ($edit_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&f=$forum_id&p={$row['post_id']}") : '', - 'U_QUOTE' => ($quote_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=quote&f=$forum_id&p={$row['post_id']}") : '', - 'U_INFO' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=post_details&f=$forum_id&p=" . $row['post_id'], true, $user->session_id) : '', - 'U_DELETE' => ($delete_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=' . (($softdelete_allowed) ? 'soft_delete' : 'delete') . "&f=$forum_id&p={$row['post_id']}") : '', - - 'U_SEARCH' => $user_cache[$poster_id]['search'], - 'U_PM' => $u_pm, - 'U_EMAIL' => $user_cache[$poster_id]['email'], - 'U_JABBER' => $user_cache[$poster_id]['jabber'], - - 'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&p={$row['post_id']}&f=$forum_id&redirect=" . urlencode(str_replace('&', '&', $viewtopic_url . '&p=' . $row['post_id'] . '#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&mode=report_details&f=' . $forum_id . '&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&mode=approve_details&f=' . $forum_id . '&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&mode=' . (($topic_data['topic_visibility'] != ITEM_DELETED) ? 'deleted_posts' : 'deleted_topics') . '&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', - 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'], - 'U_NEXT_POST_ID' => ($i < $i_total && isset($rowset[$post_list[$i + 1]])) ? $rowset[$post_list[$i + 1]]['post_id'] : '', - 'U_PREV_POST_ID' => $prev_post_id, - 'U_NOTES' => ($auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $poster_id, true, $user->session_id) : '', - 'U_WARN' => ($auth->acl_get('m_warn') && $poster_id != $user->data['user_id'] && $poster_id != ANONYMOUS) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_post&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', - - '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']]) && 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, - 'S_POST_REPORTED' => ($row['post_reported'] && $auth->acl_get('m_report', $forum_id)) ? true : false, - 'S_DISPLAY_NOTICE' => $display_notice && $row['post_attachment'], - 'S_FRIEND' => ($row['friend']) ? true : false, - 'S_UNREAD_POST' => $post_unread, - 'S_FIRST_UNREAD' => $s_first_unread, - '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'])) : '', - 'S_POST_HIDDEN' => $row['hide_post'], - 'L_POST_DISPLAY' => ($row['hide_post']) ? $user->lang('POST_DISPLAY', '', '') : '', - 'S_DELETE_PERMANENT' => $permanent_delete_allowed, - ); - - $user_poster_data = $user_cache[$poster_id]; - - $current_row_number = $i; - - /** - * Modify the posts template block - * - * @event core.viewtopic_modify_post_row - * @var int start Start item of this page - * @var int current_row_number Number of the post on this page - * @var int end Number of posts on this page - * @var int total_posts Total posts count - * @var int poster_id Post author id - * @var array row Array with original post and user data - * @var array cp_row Custom profile field data of the poster - * @var array attachments List of attachments - * @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', - 'current_row_number', - 'end', - 'total_posts', - 'poster_id', - 'row', - 'cp_row', - 'attachments', - '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']) && count($cp_row['row'])) - { - $post_row = array_merge($post_row, $cp_row['row']); - } - - // Dump vars into template - $template->assign_block_vars('postrow', $post_row); - - $contact_fields = array( - array( - 'ID' => 'pm', - 'NAME' => $user->lang['SEND_PRIVATE_MESSAGE'], - 'U_CONTACT' => $post_row['U_PM'], - ), - array( - 'ID' => 'email', - 'NAME' => $user->lang['SEND_EMAIL'], - 'U_CONTACT' => $user_cache[$poster_id]['email'], - ), - array( - 'ID' => 'jabber', - 'NAME' => $user->lang['JABBER'], - 'U_CONTACT' => $user_cache[$poster_id]['jabber'], - ), - ); - - foreach ($contact_fields as $field) - { - if ($field['U_CONTACT']) - { - $template->assign_block_vars('postrow.contact', $field); - } - } - - if (!empty($cp_row['blockrow'])) - { - foreach ($cp_row['blockrow'] as $field_data) - { - $template->assign_block_vars('postrow.custom_fields', $field_data); - - if ($field_data['S_PROFILE_CONTACT']) - { - $template->assign_block_vars('postrow.contact', array( - 'ID' => $field_data['PROFILE_FIELD_IDENT'], - 'NAME' => $field_data['PROFILE_FIELD_NAME'], - 'U_CONTACT' => $field_data['PROFILE_FIELD_CONTACT'], - )); - } - } - } - - // Display not already displayed Attachments for this post, we already parsed them. ;) - if (!empty($attachments[$row['post_id']])) - { - foreach ($attachments[$row['post_id']] as $attachment) - { - $template->assign_block_vars('postrow.attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); - } - } - - $current_row_number = $i; - - /** - * Event after the post data has been assigned to the template - * - * @event core.viewtopic_post_row_after - * @var int start Start item of this page - * @var int current_row_number Number of the post on this page - * @var int end Number of posts on this page - * @var int total_posts Total posts count - * @var array row Array with original post and user data - * @var array cp_row Custom profile field data of the poster - * @var array attachments List of attachments - * @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 - * @since 3.1.0-a3 - * @changed 3.1.0-b3 Added topic_data array, total_posts - */ - $vars = array( - 'start', - 'current_row_number', - 'end', - 'total_posts', - 'row', - 'cp_row', - 'attachments', - 'user_poster_data', - 'post_row', - 'topic_data', - ); - extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_row_after', compact($vars))); - - $i = $current_row_number; - - $prev_post_id = $row['post_id']; - - unset($rowset[$post_list[$i]]); - unset($attachments[$row['post_id']]); -} -unset($rowset, $user_cache); - -// Update topic view and if necessary attachment view counters ... but only for humans and if this is the first 'page view' -if (isset($user->data['session_page']) && !$user->data['is_bot'] && (strpos($user->data['session_page'], '&t=' . $topic_id) === false || isset($user->data['session_created']))) -{ - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_views = topic_views + 1, topic_last_view_time = ' . time() . " - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - // Update the attachment download counts - if (count($update_count)) - { - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET download_count = download_count + 1 - WHERE ' . $db->sql_in_set('attach_id', array_unique($update_count)); - $db->sql_query($sql); - } -} - -// Only mark topic if it's currently unread. Also make sure we do not set topic tracking back if earlier pages are viewed. -if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id] && $max_post_time > $topic_tracking_info[$topic_id]) -{ - markread('topic', $forum_id, $topic_id, $max_post_time); - - // Update forum info - $all_marked_read = update_forum_tracking_info($forum_id, $topic_data['forum_last_post_time'], (isset($topic_data['forum_mark_time'])) ? $topic_data['forum_mark_time'] : false, false); -} -else -{ - $all_marked_read = true; -} - -// If there are absolutely no more unread posts in this forum -// and unread posts shown, we can safely show the #unread link -if ($all_marked_read) -{ - if ($post_unread) - { - $template->assign_vars(array( - 'U_VIEW_UNREAD_POST' => '#unread', - )); - } - else if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id]) - { - $template->assign_vars(array( - 'U_VIEW_UNREAD_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=unread") . '#unread', - )); - } -} -else if (!$all_marked_read) -{ - $last_page = ((floor($start / $config['posts_per_page']) + 1) == max(ceil($total_posts / $config['posts_per_page']), 1)) ? true : false; - - // What can happen is that we are at the last displayed page. If so, we also display the #unread link based in $post_unread - if ($last_page && $post_unread) - { - $template->assign_vars(array( - 'U_VIEW_UNREAD_POST' => '#unread', - )); - } - else if (!$last_page) - { - $template->assign_vars(array( - 'U_VIEW_UNREAD_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=unread") . '#unread', - )); - } -} - -// let's set up quick_reply -$s_quick_reply = false; -if ($user->data['is_registered'] && $config['allow_quick_reply'] && ($topic_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) && $auth->acl_get('f_reply', $forum_id)) -{ - // Quick reply enabled forum - $s_quick_reply = (($topic_data['forum_status'] == ITEM_UNLOCKED && $topic_data['topic_status'] == ITEM_UNLOCKED) || $auth->acl_get('m_edit', $forum_id)) ? true : false; -} - -if ($s_can_vote || $s_quick_reply) -{ - add_form_key('posting'); - - if ($s_quick_reply) - { - $s_attach_sig = $config['allow_sig'] && $user->optionget('attachsig') && $auth->acl_get('f_sigs', $forum_id) && $auth->acl_get('u_sig'); - $s_smilies = $config['allow_smilies'] && $user->optionget('smilies') && $auth->acl_get('f_smilies', $forum_id); - $s_bbcode = $config['allow_bbcode'] && $user->optionget('bbcode') && $auth->acl_get('f_bbcode', $forum_id); - $s_notify = $config['allow_topic_notify'] && ($user->data['user_notify'] || $s_watching_topic['is_watching']); - - $qr_hidden_fields = array( - 'topic_cur_post_id' => (int) $topic_data['topic_last_post_id'], - 'topic_id' => (int) $topic_data['topic_id'], - 'forum_id' => (int) $forum_id, - ); - - // Originally we use checkboxes and check with isset(), so we only provide them if they would be checked - (!$s_bbcode) ? $qr_hidden_fields['disable_bbcode'] = 1 : true; - (!$s_smilies) ? $qr_hidden_fields['disable_smilies'] = 1 : true; - (!$config['allow_post_links']) ? $qr_hidden_fields['disable_magic_url'] = 1 : true; - ($s_attach_sig) ? $qr_hidden_fields['attach_sig'] = 1 : true; - ($s_notify) ? $qr_hidden_fields['notify'] = 1 : true; - ($topic_data['topic_status'] == ITEM_LOCKED) ? $qr_hidden_fields['lock_topic'] = 1 : true; - - $template->assign_vars(array( - 'S_QUICK_REPLY' => true, - 'U_QR_ACTION' => append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&f=$forum_id&t=$topic_id"), - 'QR_HIDDEN_FIELDS' => build_hidden_fields($qr_hidden_fields), - 'SUBJECT' => 'Re: ' . censor_text($topic_data['topic_title']), - )); - } -} -// now I have the urge to wash my hands :( - - -// We overwrite $_REQUEST['f'] if there is no forum specified -// to be able to display the correct online list. -// One downside is that the user currently viewing this topic/post is not taken into account. -if (!$request->variable('f', 0)) -{ - $request->overwrite('f', $forum_id); -} - -// We need to do the same with the topic_id. See #53025. -if (!$request->variable('t', 0) && !empty($topic_id)) -{ - $request->overwrite('t', $topic_id); -} - -$page_title = $topic_data['topic_title'] . ($start ? ' - ' . sprintf($user->lang['PAGE_TITLE_NUMBER'], $pagination->get_on_page($config['posts_per_page'], $start)) : ''); - -/** -* You can use this event to modify the page title of the viewtopic page -* -* @event core.viewtopic_modify_page_title -* @var string page_title Title of the viewtopic page -* @var array topic_data Array with topic data -* @var int forum_id Forum ID of the topic -* @var int start Start offset used to calculate the page -* @var array post_list Array with post_ids we are going to display -* @since 3.1.0-a1 -* @changed 3.1.0-RC4 Added post_list var -*/ -$vars = array('page_title', 'topic_data', 'forum_id', 'start', 'post_list'); -extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_page_title', compact($vars))); - -// Output the page -page_header($page_title, true, $forum_id); - -$template->set_filenames(array( - 'body' => ($view == 'print') ? 'viewtopic_print.html' : 'viewtopic_body.html') -); -make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_id); - -page_footer(); diff --git a/language/fr/email/user_activate_passwd.txt b/language/fr/email/user_activate_passwd.txt deleted file mode 100644 index 739d00d..0000000 --- a/language/fr/email/user_activate_passwd.txt +++ /dev/null @@ -1,17 +0,0 @@ -Subject: Activation d’un nouveau mot de passe - -Bonjour {USERNAME}, - -Vous recevez cette notification car vous (ou quelqu’un se faisant passer pour vous) avez demandé qu’un nouveau mot de passe vous soit envoyé pour votre compte sur « {SITENAME} ». Si vous n’avez pas demandé cette modification, veuillez alors l’ignorer. Si vous continuez à recevoir cette notification, veuillez contacter un administrateur du forum. - -Pour utiliser le nouveau mot de passe, vous avez besoin de l’activer. Pour cela, veuillez cliquer sur le lien ci-dessous : - -{U_ACTIVATE} - -Si cela a fonctionné, vous pourrez vous connecter en utilisant le mot de passe suivant : - -Mot de passe : {PASSWORD} - -Vous pouvez modifier ce mot de passe dans le panneau de contrôle de l’utilisateur. Si vous éprouvez une quelconque difficulté durant ces étapes, veuillez contacter un administrateur du forum. - -{EMAIL_SIG} diff --git a/styles/Milk_v2/theme/blank.css.css b/styles/Milk_v2/theme/blank.css.css deleted file mode 100644 index 34f1449..0000000 --- a/styles/Milk_v2/theme/blank.css.css +++ /dev/null @@ -1,3 +0,0 @@ -/* This file is intentionally left blank. -It's used by the light/dark toggle -If deleted, you'll get a console log error (but things will still work) */ diff --git a/styles/Milk_v2/theme/images/icon_download.gif b/styles/Milk_v2/theme/images/icon_download.gif deleted file mode 100644 index 70cd61caf2dbe1af64969b183e7ce9c31a37ba15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 198 zcmZ?wbhEHbz6NIK7IQ1_U+qe&z{}8ckk}qyEks!c=P!?ST_Me@h1x-1A{Pw4oDryP6k%z2PV8u znOw~pT#m2VnyfYk#vV4(ers(vjj0t+TYO%FO?Ak4xy;bKFn0540!^&=klT6(mYBm*W`^lWZfPjE#xcj)cxMZ>MtgNhEmBm|^$)BH}c6N4m!T)2f?N^Mr zfW`k>caP7{&t!v~U#R7e%>Rwb{npmjhRFYm!ts87ers!MkB^UMwfC09?4zTjf}y%* zsNh~+UVOs*hrH=|!vAQu`dD*``T6-^s_2=r$Dg*!dU|?rwC&8y%x#aYaFeiQvGR4m z|M2keA^8LW002J#EC2ui01E&M000JPz~9di02l)f;g1j)F)kEcfbbIp7B`g$#<~my z0FNz1;=~%fg>hBlWEzP`3t}w1d^N>)Yy0Rlon06Q-Cq-+2H diff --git a/styles/Milk_v2/theme/images/icon_rate_bad.gif b/styles/Milk_v2/theme/images/icon_rate_bad.gif deleted file mode 100644 index 790188940877c1c9cc92c67b41b0ca989588e711..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 465 zcmV;?0WSVWNk%w1VH5x;0M!5h1_1)*dz9;dncIPu&xV)2jhM2Wp(_Ck9svmAV1N2@ zlJa$v)MkPBdYJEblpqik>v@#oeU-&-gZPc7-+z|gVU@kB5FC`^9O+z{+BqpAvKRGHSTC6`eDI_?uKQ$(|xV*T(z`?@6GBh7F9!xXG z6$;J`2ul;r&Ivv~A<_v83l8280zOI;-w+TC2iHm$3;_WV5fl^y7UD=3@bd!_AwDDP z0|HvWfPp{;4fc+J@KG>>4*=J)DFLvdV!|dq3KZb*kChJ&9HPlW(7`}QRu4p6EVXjj Hk01a$`g+4M diff --git a/styles/Milk_v2/theme/images/icon_rate_good.gif b/styles/Milk_v2/theme/images/icon_rate_good.gif deleted file mode 100644 index 6d23034d71c11a1266960200abe623da0a7e37b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 462 zcmV;<0WtnZNk%w1VH5x;0M!5hX=-fA%FHe?H30<*Q(R{O5+wl*8h5htfxG#Iy7P^= z=99MEn6=fKwbG=s!@R`J0R#tSrRaUT{cWS$fV1g`x$bwN&5F6|o5%H!xZ{ww;E%Q4 zmA2WW#O9r}%&f!OY;bg(s<*ht(?&>1dV72O`}_Cz_wn)Z?d|R9>FMR=<>27p-rnBa z+}zmM*wob2iHV7BZf9}w>-7(cq%)COm-9v;V61T`KF4LkxfGb2nN3=A9`3kw<<8`nl3=^E=613vCX9To}-7Z(*3 z2`Jnn(xKnK1QQC_V}fBqf&>U6N;oi(2nLA~BG?-c#Ya5}ASW{8Vh@5xUMN$l{1F5I EJK2rEx&QzG diff --git a/styles/Milk_v2/theme/images/quote.gif b/styles/Milk_v2/theme/images/quote.gif deleted file mode 100644 index d1992273e6d8ae066d8adc58760cf46d33e67acf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153 zcmV;K0A~M3Nk%w1VGjTd0J9GOaByxvKR>OksiB~qh=_*X-Pl-HR(yPVOG`_|#ld7` zV!61r($UP7l#w$tGwSK&A^8LW000jFEC2ui01p5R000C=@X1LlU4~Jn5*3c4OiAD% zg_MMd_Aq9!Oi1WHN;pdcONI^#04R_&fQ?BGs5t-~yJcwbAUulW9q2h+ diff --git a/styles/Milk_v2/theme/images/quote_rtl.gif b/styles/Milk_v2/theme/images/quote_rtl.gif deleted file mode 100644 index ac719cf280fba68810d89e25246a5eda18411f7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154 zcmV;L0A>G2Nk%w1VGjTd0J8u9aByxvKR>OksiB~qh=_*X-Pl-HR(yPVOG`_|#ld7` zV!61r($UP7l#w$tGwSK&A^8LW000jFEC2ui01p5R000C>@X1N*ONvou7A=SqB$MJe z0<{F9_AsGCPRprG%!yQ|JjH`aqt}oKdH_kScX;(2x5uzYcnqG==_$256(s=ggm6k) I&XWiLJOAfD!vFvP diff --git a/styles/Milk_v2/theme/images/sticky_read_locked.gif b/styles/Milk_v2/theme/images/sticky_read_locked.gif deleted file mode 100644 index 79f581be79318432809028e06cdb23a165c9e13e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 646 zcmV;10(t#MNk%w1VH*G&0M$PLFe%trqb^3@$BvJ=IQM1^ZAIg z*_gfF{r&#*_W0D~@nvOYl9G}~io~YI;;E{u-{I!h*Vv1gqh_7Xxzp%uY-~M*!T9<5 z_4)kt_4eT6=fc?Qq?FEGp9?A++|#m2{sjEuz8(=wpy0THh;g) z;PCJ8@?may3K=F>l*)B=b(ol$0002;^!HGZ$A7NY@$&TO@b_L`US@H7t*xyyGc*7H z|NsC0A^8LW002J#EC2ui02=@s000L6z@Kn994S^B*6P+GI-kNsigj6_FpG=EHiAMG zDh24|EBhF^1?%P|Dl{U7uX7*}4z+U2#%|{XB0d`g02GE49s~_O4jKw=HVc9X9+j4r z2pv8cEM6iJIX;8{G&C}&G5`Ps3<)uhPX!kY9SEuqGr75{060DiHc%`WJ_fwU$Onun zP%0xn2ME%o57pJu2MizrAWkRF#nR&A;vqdDFd73>iw4bkSn~ z0uuxVcyw}O1qhKiTvR|Azy*$@jv*{q=-7kDlN1+jZs>qxfQ$+?HuRXVc5g8UY4G^%2y<1RiKRdMUt-L4yDj8lZup?<&?dEKmq)&|m|D7BJEZ&g!I54h9uU zlnB6}#tU;jB1c{b1w(`y3}!&sY=FZG32mMj_EBLo2_Fd}d}>Fe(7?eOR6?36c6a;DPr_4ob${_64g$Cjd(z22tA;)t`^sj90;i^cW$`QPE@ z*Vou&oXyjPn2njE`1$(4bcW;Z_P1quz0>C4;^!?dFg%06`~3aloUO&i$H*;Gj*gD7 z&E|<7I5mF0VsCm1876aca{vGU*R;HVuGaJ7=JnOxU|?X+-|p|>Wr#*fA2q1_2$};FaInQg!2p;hK74@LgU6H(9gc#C zFd%^p4iP}~zyJdV!h}PKXgF{n+}4g^eMJ3$frnj~WPU(!CqaV&3>qX%i1FbpLcDoT zv~Uz5tb`mf?n+K8rND^^5;(A6VSpG6d_6*k_DF_Ah6oY}Y-R!IfQ7tdEW_fEOvRoI w0AQ0*%mxJtJpcmej{PEsnkP9jTo`UAKnDvJY6PgkJZ}UD88SeaFgyqVJ1cA_#{d8T diff --git a/styles/Milk_v2/theme/images/sticky_read_mine.gif b/styles/Milk_v2/theme/images/sticky_read_mine.gif deleted file mode 100644 index 8f5f28fe5e3f88713baad319c16301c27cb4825b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 633 zcmV-<0*3uZNk%w1VH*G&0M!5hxXRng-tK2-XLX~@mX?;Xva{Ic^N_gNWt_|G?eOE~ z>FMk4hK7c(Fit0Sx&8kBNsGf+lgIY=_~PyMq)}yab93nN_|H6F=jrUy+2N?g-}w3Z z*VouMfWF1i-jpLgGkm=C_4eT6=koLP_xk+7!o%I*<+su2Edc`?=oD;Y!Q(-fGV#PoV8O8f zItDCRNbq669i9OZCisvrf(3_`S_MY9m}%i8o*xkq=;RT?1%nD4LTvC+vl_((LfrSncu9h9rA%&w5BSJg~;9#y4039qm;J|=E2_G~* z`5jUN0*wdA7`Px2;lN@cfM0PqR^mZoXqSJ~bpvCK55A!>ci_Y3fdL2uQVSWd0)Yk% T13(~}F@x8kL=+S1sFHA%E)c>VqU>AJ=2?eOXA z?#zRi$60jp*4)|4)9lOB$!~|$yv6wG?Z=y^%YBlL+j^E+t0002YOKS7<_Q613@Xy!w>T&K7#=;Ffpbv7y$|gC>M@T5FZB{76AbyF1fk30Vh5K3{VvaJ}JD%$O(%8 zPyiu52^P|%B-Pc@31=i+L@Lh3(&6Ia2|5xL+(ZBmJ}q=~0tE#&?+PhCH2?%pkUnyA z3FOI(@Xi;43SL;O(2*j6LmUDzI8348z=u6gyfyGKB8A5Z1wa_^m_ktq5)QhExX^*) zi4+b%fS8ctgdzznAn>{Hp{0h44JR^yARt474+$SksNh3@0gGoEWK6)Z!DtN@Cid|W z0)a$_10w`17;)g-g{51E4D*p=!v;k(n57*Op#rEL88Qf9#X!JZAp#hnIAEZ#ff_3= zO!)hwE~p2E1^7T=!Y^YE2zVUWj7Kixx-@o_X~19&V<8j(d>Amm0|3*fg%A*7f&+w< Ie1ZS~JLA_Pb^rhX diff --git a/styles/Milk_v2/theme/stylesheet.css b/styles/Milk_v2/theme/stylesheet.css deleted file mode 100644 index 0d19a04..0000000 --- a/styles/Milk_v2/theme/stylesheet.css +++ /dev/null @@ -1,40 +0,0 @@ -/* phpBB3 Style Sheet - -------------------------------------------------------------- - phpBB style name: Milk v2 - Based on style: Merlin Framework (http://www.planetstyles.net) - -------------------------------------------------------------- -*/ - -/* Core */ -@import url("merlin.css?v=3.3"); -@import url("normalize.css?v=3.3"); -@import url("base.css?v=3.3"); -@import url("utilities.css?v=3.3"); -@import url("common.css?v=3.3"); -@import url("links.css?v=3.3"); -@import url("content.css?v=3.3"); -@import url("buttons.css?v=3.3"); -@import url("cp.css?v=3.3"); -@import url("forms.css?v=3.3"); - -/* Icons */ -@import url("icons.css?v=3.3"); -@import url("icons_forums_topics.css?v=3.3"); - -/* Custom Additions */ -@import url("animate.css?v=3.3"); -@import url("tooltipster.bundle.min.css?v=3.3"); -@import url("tooltipster-sideTip-borderless.min.css?v=3.3"); - -/* Responsive */ -@import url("responsive/responsive.css?v=3.3"); -@import url("responsive/xs-phones.css?v=3.3"); -@import url("responsive/small-smaller-tablets.css?v=3.3"); -@import url("responsive/medium-ipad.css?v=3.3"); -@import url("responsive/large-desktops.css?v=3.3"); -@import url("responsive/squishy.css?v=3.3"); - -/* Facelift */ -@import url("colours.css?v=3.3"); -@import url("fonts.css?v=3.3"); -@import url("milk.css?v=3.3"); diff --git a/styles/Milk_v2/theme/stylesheet_jour.css b/styles/Milk_v2/theme/stylesheet_jour.css index 96f21db..0d19a04 100644 --- a/styles/Milk_v2/theme/stylesheet_jour.css +++ b/styles/Milk_v2/theme/stylesheet_jour.css @@ -6,35 +6,35 @@ */ /* Core */ -@import url("merlin.css"); -@import url("normalize.css"); -@import url("base.css"); -@import url("utilities.css"); -@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("merlin.css?v=3.3"); +@import url("normalize.css?v=3.3"); +@import url("base.css?v=3.3"); +@import url("utilities.css?v=3.3"); +@import url("common.css?v=3.3"); +@import url("links.css?v=3.3"); +@import url("content.css?v=3.3"); +@import url("buttons.css?v=3.3"); +@import url("cp.css?v=3.3"); +@import url("forms.css?v=3.3"); /* Icons */ -@import url("icons.css"); -@import url("icons_forums_topics.css"); +@import url("icons.css?v=3.3"); +@import url("icons_forums_topics.css?v=3.3"); /* Custom Additions */ -@import url("animate.css"); -@import url("tooltipster.bundle.min.css"); -@import url("tooltipster-sideTip-borderless.min.css"); +@import url("animate.css?v=3.3"); +@import url("tooltipster.bundle.min.css?v=3.3"); +@import url("tooltipster-sideTip-borderless.min.css?v=3.3"); /* Responsive */ -@import url("responsive/responsive.css"); -@import url("responsive/xs-phones.css"); -@import url("responsive/small-smaller-tablets.css"); -@import url("responsive/medium-ipad.css"); -@import url("responsive/large-desktops.css"); -@import url("responsive/squishy.css"); +@import url("responsive/responsive.css?v=3.3"); +@import url("responsive/xs-phones.css?v=3.3"); +@import url("responsive/small-smaller-tablets.css?v=3.3"); +@import url("responsive/medium-ipad.css?v=3.3"); +@import url("responsive/large-desktops.css?v=3.3"); +@import url("responsive/squishy.css?v=3.3"); /* Facelift */ -@import url("colours.css"); -@import url("fonts.css"); -@import url("milk.css"); \ No newline at end of file +@import url("colours.css?v=3.3"); +@import url("fonts.css?v=3.3"); +@import url("milk.css?v=3.3"); diff --git a/styles/Milk_v2/theme/stylesheet_nuit.css b/styles/Milk_v2/theme/stylesheet_nuit.css index 96f21db..0d19a04 100644 --- a/styles/Milk_v2/theme/stylesheet_nuit.css +++ b/styles/Milk_v2/theme/stylesheet_nuit.css @@ -6,35 +6,35 @@ */ /* Core */ -@import url("merlin.css"); -@import url("normalize.css"); -@import url("base.css"); -@import url("utilities.css"); -@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("merlin.css?v=3.3"); +@import url("normalize.css?v=3.3"); +@import url("base.css?v=3.3"); +@import url("utilities.css?v=3.3"); +@import url("common.css?v=3.3"); +@import url("links.css?v=3.3"); +@import url("content.css?v=3.3"); +@import url("buttons.css?v=3.3"); +@import url("cp.css?v=3.3"); +@import url("forms.css?v=3.3"); /* Icons */ -@import url("icons.css"); -@import url("icons_forums_topics.css"); +@import url("icons.css?v=3.3"); +@import url("icons_forums_topics.css?v=3.3"); /* Custom Additions */ -@import url("animate.css"); -@import url("tooltipster.bundle.min.css"); -@import url("tooltipster-sideTip-borderless.min.css"); +@import url("animate.css?v=3.3"); +@import url("tooltipster.bundle.min.css?v=3.3"); +@import url("tooltipster-sideTip-borderless.min.css?v=3.3"); /* Responsive */ -@import url("responsive/responsive.css"); -@import url("responsive/xs-phones.css"); -@import url("responsive/small-smaller-tablets.css"); -@import url("responsive/medium-ipad.css"); -@import url("responsive/large-desktops.css"); -@import url("responsive/squishy.css"); +@import url("responsive/responsive.css?v=3.3"); +@import url("responsive/xs-phones.css?v=3.3"); +@import url("responsive/small-smaller-tablets.css?v=3.3"); +@import url("responsive/medium-ipad.css?v=3.3"); +@import url("responsive/large-desktops.css?v=3.3"); +@import url("responsive/squishy.css?v=3.3"); /* Facelift */ -@import url("colours.css"); -@import url("fonts.css"); -@import url("milk.css"); \ No newline at end of file +@import url("colours.css?v=3.3"); +@import url("fonts.css?v=3.3"); +@import url("milk.css?v=3.3"); diff --git a/styles/prosilver/theme/stylesheet.css b/styles/prosilver/theme/stylesheet.css deleted file mode 100644 index c402d56..0000000 --- a/styles/prosilver/theme/stylesheet.css +++ /dev/null @@ -1,21 +0,0 @@ -/* phpBB3 Style Sheet - -------------------------------------------------------------- - Style name: prosilver (the default phpBB 3.3.x style) - Based on style: - Original author: Tom Beddard ( http://www.subblue.com/ ) - Modified by: phpBB Limited ( https://www.phpbb.com/ ) - -------------------------------------------------------------- -*/ - -@import url("normalize.css?v=3.3"); -@import url("base.css?v=3.3"); -@import url("utilities.css?v=3.3"); -@import url("common.css?v=3.3"); -@import url("links.css?v=3.3"); -@import url("content.css?v=3.3"); -@import url("buttons.css?v=3.3"); -@import url("cp.css?v=3.3"); -@import url("forms.css?v=3.3"); -@import url("icons.css?v=3.3"); -@import url("colours.css?v=3.3"); -@import url("responsive.css?v=3.3"); diff --git a/styles/prosilver/theme/stylesheet_jour.css b/styles/prosilver/theme/stylesheet_jour.css index 45eb5b6..c402d56 100644 --- a/styles/prosilver/theme/stylesheet_jour.css +++ b/styles/prosilver/theme/stylesheet_jour.css @@ -1,21 +1,21 @@ /* phpBB3 Style Sheet -------------------------------------------------------------- - Style name: prosilver (the default phpBB 3.2.x style) + Style name: prosilver (the default phpBB 3.3.x style) Based on style: Original author: Tom Beddard ( http://www.subblue.com/ ) Modified by: phpBB Limited ( https://www.phpbb.com/ ) -------------------------------------------------------------- */ -@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"); +@import url("normalize.css?v=3.3"); +@import url("base.css?v=3.3"); +@import url("utilities.css?v=3.3"); +@import url("common.css?v=3.3"); +@import url("links.css?v=3.3"); +@import url("content.css?v=3.3"); +@import url("buttons.css?v=3.3"); +@import url("cp.css?v=3.3"); +@import url("forms.css?v=3.3"); +@import url("icons.css?v=3.3"); +@import url("colours.css?v=3.3"); +@import url("responsive.css?v=3.3"); diff --git a/styles/prosilver/theme/stylesheet_nuit.css b/styles/prosilver/theme/stylesheet_nuit.css index 45eb5b6..c402d56 100644 --- a/styles/prosilver/theme/stylesheet_nuit.css +++ b/styles/prosilver/theme/stylesheet_nuit.css @@ -1,21 +1,21 @@ /* phpBB3 Style Sheet -------------------------------------------------------------- - Style name: prosilver (the default phpBB 3.2.x style) + Style name: prosilver (the default phpBB 3.3.x style) Based on style: Original author: Tom Beddard ( http://www.subblue.com/ ) Modified by: phpBB Limited ( https://www.phpbb.com/ ) -------------------------------------------------------------- */ -@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"); +@import url("normalize.css?v=3.3"); +@import url("base.css?v=3.3"); +@import url("utilities.css?v=3.3"); +@import url("common.css?v=3.3"); +@import url("links.css?v=3.3"); +@import url("content.css?v=3.3"); +@import url("buttons.css?v=3.3"); +@import url("cp.css?v=3.3"); +@import url("forms.css?v=3.3"); +@import url("icons.css?v=3.3"); +@import url("colours.css?v=3.3"); +@import url("responsive.css?v=3.3"); diff --git a/vendor/guzzlehttp/guzzle/src/BatchResults.php b/vendor/guzzlehttp/guzzle/src/BatchResults.php deleted file mode 100644 index e5af433..0000000 --- a/vendor/guzzlehttp/guzzle/src/BatchResults.php +++ /dev/null @@ -1,148 +0,0 @@ -hash = $hash; - } - - /** - * Get the keys that are available on the batch result. - * - * @return array - */ - public function getKeys() - { - return iterator_to_array($this->hash); - } - - /** - * Gets a result from the container for the given object. When getting - * results for a batch of requests, provide the request object. - * - * @param object $forObject Object to retrieve the result for. - * - * @return mixed|null - */ - public function getResult($forObject) - { - return isset($this->hash[$forObject]) ? $this->hash[$forObject] : null; - } - - /** - * Get an array of successful results. - * - * @return array - */ - public function getSuccessful() - { - $results = []; - foreach ($this->hash as $key) { - if (!($this->hash[$key] instanceof \Exception)) { - $results[] = $this->hash[$key]; - } - } - - return $results; - } - - /** - * Get an array of failed results. - * - * @return array - */ - public function getFailures() - { - $results = []; - foreach ($this->hash as $key) { - if ($this->hash[$key] instanceof \Exception) { - $results[] = $this->hash[$key]; - } - } - - return $results; - } - - /** - * Allows iteration over all batch result values. - * - * @return \ArrayIterator - */ - public function getIterator() - { - $results = []; - foreach ($this->hash as $key) { - $results[] = $this->hash[$key]; - } - - return new \ArrayIterator($results); - } - - /** - * Counts the number of elements in the batch result. - * - * @return int - */ - public function count() - { - return count($this->hash); - } - - /** - * Checks if the batch contains a specific numerical array index. - * - * @param int $key Index to access - * - * @return bool - */ - public function offsetExists($key) - { - return $key < count($this->hash); - } - - /** - * Allows access of the batch using a numerical array index. - * - * @param int $key Index to access. - * - * @return mixed|null - */ - public function offsetGet($key) - { - $i = -1; - foreach ($this->hash as $obj) { - if ($key === ++$i) { - return $this->hash[$obj]; - } - } - - return null; - } - - public function offsetUnset($key) - { - throw new \RuntimeException('Not implemented'); - } - - public function offsetSet($key, $value) - { - throw new \RuntimeException('Not implemented'); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Collection.php b/vendor/guzzlehttp/guzzle/src/Collection.php deleted file mode 100644 index 4aabd20..0000000 --- a/vendor/guzzlehttp/guzzle/src/Collection.php +++ /dev/null @@ -1,236 +0,0 @@ -data = $data; - } - - /** - * Create a new collection from an array, validate the keys, and add default - * values where missing - * - * @param array $config Configuration values to apply. - * @param array $defaults Default parameters - * @param array $required Required parameter names - * - * @return self - * @throws \InvalidArgumentException if a parameter is missing - */ - public static function fromConfig( - array $config = [], - array $defaults = [], - array $required = [] - ) { - $data = $config + $defaults; - - if ($missing = array_diff($required, array_keys($data))) { - throw new \InvalidArgumentException( - 'Config is missing the following keys: ' . - implode(', ', $missing)); - } - - return new self($data); - } - - /** - * Removes all key value pairs - */ - public function clear() - { - $this->data = []; - } - - /** - * Get a specific key value. - * - * @param string $key Key to retrieve. - * - * @return mixed|null Value of the key or NULL - */ - public function get($key) - { - return isset($this->data[$key]) ? $this->data[$key] : null; - } - - /** - * Set a key value pair - * - * @param string $key Key to set - * @param mixed $value Value to set - */ - public function set($key, $value) - { - $this->data[$key] = $value; - } - - /** - * Add a value to a key. If a key of the same name has already been added, - * the key value will be converted into an array and the new value will be - * pushed to the end of the array. - * - * @param string $key Key to add - * @param mixed $value Value to add to the key - */ - public function add($key, $value) - { - if (!array_key_exists($key, $this->data)) { - $this->data[$key] = $value; - } elseif (is_array($this->data[$key])) { - $this->data[$key][] = $value; - } else { - $this->data[$key] = array($this->data[$key], $value); - } - } - - /** - * Remove a specific key value pair - * - * @param string $key A key to remove - */ - public function remove($key) - { - unset($this->data[$key]); - } - - /** - * Get all keys in the collection - * - * @return array - */ - public function getKeys() - { - return array_keys($this->data); - } - - /** - * Returns whether or not the specified key is present. - * - * @param string $key The key for which to check the existence. - * - * @return bool - */ - public function hasKey($key) - { - return array_key_exists($key, $this->data); - } - - /** - * Checks if any keys contains a certain value - * - * @param string $value Value to search for - * - * @return mixed Returns the key if the value was found FALSE if the value - * was not found. - */ - public function hasValue($value) - { - return array_search($value, $this->data, true); - } - - /** - * Replace the data of the object with the value of an array - * - * @param array $data Associative array of data - */ - public function replace(array $data) - { - $this->data = $data; - } - - /** - * Add and merge in a Collection or array of key value pair data. - * - * @param Collection|array $data Associative array of key value pair data - */ - public function merge($data) - { - foreach ($data as $key => $value) { - $this->add($key, $value); - } - } - - /** - * Overwrite key value pairs in this collection with all of the data from - * an array or collection. - * - * @param array|\Traversable $data Values to override over this config - */ - public function overwriteWith($data) - { - if (is_array($data)) { - $this->data = $data + $this->data; - } elseif ($data instanceof Collection) { - $this->data = $data->toArray() + $this->data; - } else { - foreach ($data as $key => $value) { - $this->data[$key] = $value; - } - } - } - - /** - * Returns a Collection containing all the elements of the collection after - * applying the callback function to each one. - * - * The callable should accept three arguments: - * - (string) $key - * - (string) $value - * - (array) $context - * - * The callable must return a the altered or unaltered value. - * - * @param callable $closure Map function to apply - * @param array $context Context to pass to the callable - * - * @return Collection - */ - public function map(callable $closure, array $context = []) - { - $collection = new static(); - foreach ($this as $key => $value) { - $collection[$key] = $closure($key, $value, $context); - } - - return $collection; - } - - /** - * Iterates over each key value pair in the collection passing them to the - * callable. If the callable returns true, the current value from input is - * returned into the result Collection. - * - * The callable must accept two arguments: - * - (string) $key - * - (string) $value - * - * @param callable $closure Evaluation function - * - * @return Collection - */ - public function filter(callable $closure) - { - $collection = new static(); - foreach ($this->data as $key => $value) { - if ($closure($key, $value)) { - $collection[$key] = $value; - } - } - - return $collection; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php b/vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php deleted file mode 100644 index 0d2f4db..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php +++ /dev/null @@ -1,20 +0,0 @@ -propagationStopped; - } - - public function stopPropagation() - { - $this->propagationStopped = true; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php b/vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php deleted file mode 100644 index 8a6ee47..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php +++ /dev/null @@ -1,61 +0,0 @@ -transaction = $transaction; - } - - /** - * Get the HTTP client associated with the event. - * - * @return ClientInterface - */ - public function getClient() - { - return $this->transaction->client; - } - - /** - * Get the request object - * - * @return RequestInterface - */ - public function getRequest() - { - return $this->transaction->request; - } - - /** - * Get the number of transaction retries. - * - * @return int - */ - public function getRetryCount() - { - return $this->transaction->retries; - } - - /** - * @return Transaction - */ - public function getTransaction() - { - return $this->transaction; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.php b/vendor/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.php deleted file mode 100644 index bbbdfaf..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.php +++ /dev/null @@ -1,40 +0,0 @@ -transaction->state = 'retry'; - - if ($afterDelay) { - $this->transaction->request->getConfig()->set('delay', $afterDelay); - } - - $this->stopPropagation(); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php b/vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php deleted file mode 100644 index 3b106df..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php +++ /dev/null @@ -1,63 +0,0 @@ -transaction->transferInfo; - } - - return isset($this->transaction->transferInfo[$name]) - ? $this->transaction->transferInfo[$name] - : null; - } - - /** - * Returns true/false if a response is available. - * - * @return bool - */ - public function hasResponse() - { - return !($this->transaction->response instanceof FutureInterface); - } - - /** - * Get the response. - * - * @return ResponseInterface|null - */ - public function getResponse() - { - return $this->hasResponse() ? $this->transaction->response : null; - } - - /** - * Intercept the request and associate a response - * - * @param ResponseInterface $response Response to set - */ - public function intercept(ResponseInterface $response) - { - $this->transaction->response = $response; - $this->transaction->exception = null; - $this->stopPropagation(); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php b/vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php deleted file mode 100644 index f313c37..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php +++ /dev/null @@ -1,26 +0,0 @@ -transaction->response = $response; - $this->transaction->exception = null; - $this->stopPropagation(); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php b/vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php deleted file mode 100644 index 56cc557..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php +++ /dev/null @@ -1,14 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - * - * @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher - */ -class Emitter implements EmitterInterface -{ - /** @var array */ - private $listeners = []; - - /** @var array */ - private $sorted = []; - - public function on($eventName, callable $listener, $priority = 0) - { - if ($priority === 'first') { - $priority = isset($this->listeners[$eventName]) - ? max(array_keys($this->listeners[$eventName])) + 1 - : 1; - } elseif ($priority === 'last') { - $priority = isset($this->listeners[$eventName]) - ? min(array_keys($this->listeners[$eventName])) - 1 - : -1; - } - - $this->listeners[$eventName][$priority][] = $listener; - unset($this->sorted[$eventName]); - } - - public function once($eventName, callable $listener, $priority = 0) - { - $onceListener = function ( - EventInterface $event - ) use (&$onceListener, $eventName, $listener, $priority) { - $this->removeListener($eventName, $onceListener); - $listener($event, $eventName); - }; - - $this->on($eventName, $onceListener, $priority); - } - - public function removeListener($eventName, callable $listener) - { - if (empty($this->listeners[$eventName])) { - return; - } - - foreach ($this->listeners[$eventName] as $priority => $listeners) { - if (false !== ($key = array_search($listener, $listeners, true))) { - unset( - $this->listeners[$eventName][$priority][$key], - $this->sorted[$eventName] - ); - } - } - } - - public function listeners($eventName = null) - { - // Return all events in a sorted priority order - if ($eventName === null) { - foreach (array_keys($this->listeners) as $eventName) { - if (empty($this->sorted[$eventName])) { - $this->listeners($eventName); - } - } - return $this->sorted; - } - - // Return the listeners for a specific event, sorted in priority order - if (empty($this->sorted[$eventName])) { - $this->sorted[$eventName] = []; - if (isset($this->listeners[$eventName])) { - krsort($this->listeners[$eventName], SORT_NUMERIC); - foreach ($this->listeners[$eventName] as $listeners) { - foreach ($listeners as $listener) { - $this->sorted[$eventName][] = $listener; - } - } - } - } - - return $this->sorted[$eventName]; - } - - public function hasListeners($eventName) - { - return !empty($this->listeners[$eventName]); - } - - public function emit($eventName, EventInterface $event) - { - if (isset($this->listeners[$eventName])) { - foreach ($this->listeners($eventName) as $listener) { - $listener($event, $eventName); - if ($event->isPropagationStopped()) { - break; - } - } - } - - return $event; - } - - public function attach(SubscriberInterface $subscriber) - { - foreach ($subscriber->getEvents() as $eventName => $listeners) { - if (is_array($listeners[0])) { - foreach ($listeners as $listener) { - $this->on( - $eventName, - [$subscriber, $listener[0]], - isset($listener[1]) ? $listener[1] : 0 - ); - } - } else { - $this->on( - $eventName, - [$subscriber, $listeners[0]], - isset($listeners[1]) ? $listeners[1] : 0 - ); - } - } - } - - public function detach(SubscriberInterface $subscriber) - { - foreach ($subscriber->getEvents() as $eventName => $listener) { - $this->removeListener($eventName, [$subscriber, $listener[0]]); - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php b/vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php deleted file mode 100644 index 9783efd..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php +++ /dev/null @@ -1,96 +0,0 @@ -transaction->exception; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/ErrorEvent.php b/vendor/guzzlehttp/guzzle/src/Event/ErrorEvent.php deleted file mode 100644 index 7432134..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/ErrorEvent.php +++ /dev/null @@ -1,27 +0,0 @@ -transaction->exception; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/EventInterface.php b/vendor/guzzlehttp/guzzle/src/Event/EventInterface.php deleted file mode 100644 index 97247e8..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/EventInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -emitter) { - $this->emitter = new Emitter(); - } - - return $this->emitter; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.php b/vendor/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.php deleted file mode 100644 index 407dc92..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.php +++ /dev/null @@ -1,88 +0,0 @@ -getEmitter(); - foreach ($listeners as $el) { - if ($el['once']) { - $emitter->once($el['name'], $el['fn'], $el['priority']); - } else { - $emitter->on($el['name'], $el['fn'], $el['priority']); - } - } - } - - /** - * Extracts the allowed events from the provided array, and ignores anything - * else in the array. The event listener must be specified as a callable or - * as an array of event listener data ("name", "fn", "priority", "once"). - * - * @param array $source Array containing callables or hashes of data to be - * prepared as event listeners. - * @param array $events Names of events to look for in the provided $source - * array. Other keys are ignored. - * @return array - */ - private function prepareListeners(array $source, array $events) - { - $listeners = []; - foreach ($events as $name) { - if (isset($source[$name])) { - $this->buildListener($name, $source[$name], $listeners); - } - } - - return $listeners; - } - - /** - * Creates a complete event listener definition from the provided array of - * listener data. Also works recursively if more than one listeners are - * contained in the provided array. - * - * @param string $name Name of the event the listener is for. - * @param array|callable $data Event listener data to prepare. - * @param array $listeners Array of listeners, passed by reference. - * - * @throws \InvalidArgumentException if the event data is malformed. - */ - private function buildListener($name, $data, &$listeners) - { - static $defaults = ['priority' => 0, 'once' => false]; - - // If a callable is provided, normalize it to the array format. - if (is_callable($data)) { - $data = ['fn' => $data]; - } - - // Prepare the listener and add it to the array, recursively. - if (isset($data['fn'])) { - $data['name'] = $name; - $listeners[] = $data + $defaults; - } elseif (is_array($data)) { - foreach ($data as $listenerData) { - $this->buildListener($name, $listenerData, $listeners); - } - } else { - throw new \InvalidArgumentException('Each event listener must be a ' - . 'callable or an associative array containing a "fn" key.'); - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/ProgressEvent.php b/vendor/guzzlehttp/guzzle/src/Event/ProgressEvent.php deleted file mode 100644 index 3fd0de4..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/ProgressEvent.php +++ /dev/null @@ -1,51 +0,0 @@ -downloadSize = $downloadSize; - $this->downloaded = $downloaded; - $this->uploadSize = $uploadSize; - $this->uploaded = $uploaded; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php b/vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php deleted file mode 100644 index f51d420..0000000 --- a/vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php +++ /dev/null @@ -1,56 +0,0 @@ - ['methodName']] - * - ['eventName' => ['methodName', $priority]] - * - ['eventName' => [['methodName'], ['otherMethod']] - * - ['eventName' => [['methodName'], ['otherMethod', $priority]] - * - ['eventName' => [['methodName', $priority], ['otherMethod', $priority]] - * - * @return array - */ - public function getEvents(); -} diff --git a/vendor/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.php b/vendor/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.php deleted file mode 100644 index fbe2dcd..0000000 --- a/vendor/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.php +++ /dev/null @@ -1,4 +0,0 @@ -response = $response; - } - /** - * Get the associated response - * - * @return ResponseInterface|null - */ - public function getResponse() - { - return $this->response; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Exception/StateException.php b/vendor/guzzlehttp/guzzle/src/Exception/StateException.php deleted file mode 100644 index a7652a3..0000000 --- a/vendor/guzzlehttp/guzzle/src/Exception/StateException.php +++ /dev/null @@ -1,4 +0,0 @@ -error = $error; - } - - /** - * Get the associated error - * - * @return \LibXMLError|null - */ - public function getError() - { - return $this->error; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/HasDataTrait.php b/vendor/guzzlehttp/guzzle/src/HasDataTrait.php deleted file mode 100644 index 020dfc9..0000000 --- a/vendor/guzzlehttp/guzzle/src/HasDataTrait.php +++ /dev/null @@ -1,75 +0,0 @@ -data); - } - - public function offsetGet($offset) - { - return isset($this->data[$offset]) ? $this->data[$offset] : null; - } - - public function offsetSet($offset, $value) - { - $this->data[$offset] = $value; - } - - public function offsetExists($offset) - { - return isset($this->data[$offset]); - } - - public function offsetUnset($offset) - { - unset($this->data[$offset]); - } - - public function toArray() - { - return $this->data; - } - - public function count() - { - return count($this->data); - } - - /** - * Get a value from the collection using a path syntax to retrieve nested - * data. - * - * @param string $path Path to traverse and retrieve a value from - * - * @return mixed|null - */ - public function getPath($path) - { - return Utils::getPath($this->data, $path); - } - - /** - * Set a value into a nested array key. Keys will be created as needed to - * set the value. - * - * @param string $path Path to set - * @param mixed $value Value to set at the key - * - * @throws \RuntimeException when trying to setPath using a nested path - * that travels through a scalar value - */ - public function setPath($path, $value) - { - Utils::setPath($this->data, $path, $value); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php b/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php deleted file mode 100644 index f118e0f..0000000 --- a/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php +++ /dev/null @@ -1,253 +0,0 @@ -getBody(); - } - - public function getProtocolVersion() - { - return $this->protocolVersion; - } - - public function getBody() - { - return $this->body; - } - - public function setBody(StreamInterface $body = null) - { - if ($body === null) { - // Setting a null body will remove the body of the request - $this->removeHeader('Content-Length'); - $this->removeHeader('Transfer-Encoding'); - } - - $this->body = $body; - } - - public function addHeader($header, $value) - { - if (is_array($value)) { - $current = array_merge($this->getHeaderAsArray($header), $value); - } else { - $current = $this->getHeaderAsArray($header); - $current[] = (string) $value; - } - - $this->setHeader($header, $current); - } - - public function addHeaders(array $headers) - { - foreach ($headers as $name => $header) { - $this->addHeader($name, $header); - } - } - - public function getHeader($header) - { - $name = strtolower($header); - return isset($this->headers[$name]) - ? implode(', ', $this->headers[$name]) - : ''; - } - - public function getHeaderAsArray($header) - { - $name = strtolower($header); - return isset($this->headers[$name]) ? $this->headers[$name] : []; - } - - public function getHeaders() - { - $headers = []; - foreach ($this->headers as $name => $values) { - $headers[$this->headerNames[$name]] = $values; - } - - return $headers; - } - - public function setHeader($header, $value) - { - $header = trim($header); - $name = strtolower($header); - $this->headerNames[$name] = $header; - - if (is_array($value)) { - foreach ($value as &$v) { - $v = trim($v); - } - $this->headers[$name] = $value; - } else { - $this->headers[$name] = [trim($value)]; - } - } - - public function setHeaders(array $headers) - { - $this->headers = $this->headerNames = []; - foreach ($headers as $key => $value) { - $this->addHeader($key, $value); - } - } - - public function hasHeader($header) - { - return isset($this->headers[strtolower($header)]); - } - - public function removeHeader($header) - { - $name = strtolower($header); - unset($this->headers[$name], $this->headerNames[$name]); - } - - /** - * Parse an array of header values containing ";" separated data into an - * array of associative arrays representing the header key value pair - * data of the header. When a parameter does not contain a value, but just - * contains a key, this function will inject a key with a '' string value. - * - * @param MessageInterface $message That contains the header - * @param string $header Header to retrieve from the message - * - * @return array Returns the parsed header values. - */ - public static function parseHeader(MessageInterface $message, $header) - { - static $trimmed = "\"' \n\t\r"; - $params = $matches = []; - - foreach (self::normalizeHeader($message, $header) as $val) { - $part = []; - foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { - if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { - $m = $matches[0]; - if (isset($m[1])) { - $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed); - } else { - $part[] = trim($m[0], $trimmed); - } - } - } - if ($part) { - $params[] = $part; - } - } - - return $params; - } - - /** - * Converts an array of header values that may contain comma separated - * headers into an array of headers with no comma separated values. - * - * @param MessageInterface $message That contains the header - * @param string $header Header to retrieve from the message - * - * @return array Returns the normalized header field values. - */ - public static function normalizeHeader(MessageInterface $message, $header) - { - $h = $message->getHeaderAsArray($header); - for ($i = 0, $total = count($h); $i < $total; $i++) { - if (strpos($h[$i], ',') === false) { - continue; - } - foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) { - $h[] = trim($v); - } - unset($h[$i]); - } - - return $h; - } - - /** - * Gets the start-line and headers of a message as a string - * - * @param MessageInterface $message - * - * @return string - */ - public static function getStartLineAndHeaders(MessageInterface $message) - { - return static::getStartLine($message) - . self::getHeadersAsString($message); - } - - /** - * Gets the headers of a message as a string - * - * @param MessageInterface $message - * - * @return string - */ - public static function getHeadersAsString(MessageInterface $message) - { - $result = ''; - foreach ($message->getHeaders() as $name => $values) { - $result .= "\r\n{$name}: " . implode(', ', $values); - } - - return $result; - } - - /** - * Gets the start line of a message - * - * @param MessageInterface $message - * - * @return string - * @throws \InvalidArgumentException - */ - public static function getStartLine(MessageInterface $message) - { - if ($message instanceof RequestInterface) { - return trim($message->getMethod() . ' ' - . $message->getResource()) - . ' HTTP/' . $message->getProtocolVersion(); - } elseif ($message instanceof ResponseInterface) { - return 'HTTP/' . $message->getProtocolVersion() . ' ' - . $message->getStatusCode() . ' ' - . $message->getReasonPhrase(); - } else { - throw new \InvalidArgumentException('Unknown message type'); - } - } - - /** - * Accepts and modifies the options provided to the message in the - * constructor. - * - * Can be overridden in subclasses as necessary. - * - * @param array $options Options array passed by reference. - */ - protected function handleOptions(array &$options) - { - if (isset($options['protocol_version'])) { - $this->protocolVersion = $options['protocol_version']; - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Message/AppliesHeadersInterface.php b/vendor/guzzlehttp/guzzle/src/Message/AppliesHeadersInterface.php deleted file mode 100644 index ca42f20..0000000 --- a/vendor/guzzlehttp/guzzle/src/Message/AppliesHeadersInterface.php +++ /dev/null @@ -1,24 +0,0 @@ -then($onFulfilled, $onRejected, $onProgress), - [$future, 'wait'], - [$future, 'cancel'] - ); - } - - public function getStatusCode() - { - return $this->_value->getStatusCode(); - } - - public function setStatusCode($code) - { - $this->_value->setStatusCode($code); - } - - public function getReasonPhrase() - { - return $this->_value->getReasonPhrase(); - } - - public function setReasonPhrase($phrase) - { - $this->_value->setReasonPhrase($phrase); - } - - public function getEffectiveUrl() - { - return $this->_value->getEffectiveUrl(); - } - - public function setEffectiveUrl($url) - { - $this->_value->setEffectiveUrl($url); - } - - public function json(array $config = []) - { - return $this->_value->json($config); - } - - public function xml(array $config = []) - { - return $this->_value->xml($config); - } - - public function __toString() - { - try { - return $this->_value->__toString(); - } catch (\Exception $e) { - trigger_error($e->getMessage(), E_USER_WARNING); - return ''; - } - } - - public function getProtocolVersion() - { - return $this->_value->getProtocolVersion(); - } - - public function setBody(StreamInterface $body = null) - { - $this->_value->setBody($body); - } - - public function getBody() - { - return $this->_value->getBody(); - } - - public function getHeaders() - { - return $this->_value->getHeaders(); - } - - public function getHeader($header) - { - return $this->_value->getHeader($header); - } - - public function getHeaderAsArray($header) - { - return $this->_value->getHeaderAsArray($header); - } - - public function hasHeader($header) - { - return $this->_value->hasHeader($header); - } - - public function removeHeader($header) - { - $this->_value->removeHeader($header); - } - - public function addHeader($header, $value) - { - $this->_value->addHeader($header, $value); - } - - public function addHeaders(array $headers) - { - $this->_value->addHeaders($headers); - } - - public function setHeader($header, $value) - { - $this->_value->setHeader($header, $value); - } - - public function setHeaders(array $headers) - { - $this->_value->setHeaders($headers); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php b/vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php deleted file mode 100644 index b366d6d..0000000 --- a/vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php +++ /dev/null @@ -1,364 +0,0 @@ - 1, 'timeout' => 1, 'verify' => 1, 'ssl_key' => 1, - 'cert' => 1, 'proxy' => 1, 'debug' => 1, 'save_to' => 1, 'stream' => 1, - 'expect' => 1, 'future' => 1 - ]; - - /** @var array Default allow_redirects request option settings */ - private static $defaultRedirect = [ - 'max' => 5, - 'strict' => false, - 'referer' => false, - 'protocols' => ['http', 'https'] - ]; - - /** - * @param array $customOptions Associative array of custom request option - * names mapping to functions used to apply - * the option. The function accepts the request - * and the option value to apply. - */ - public function __construct(array $customOptions = []) - { - $this->errorPlugin = new HttpError(); - $this->redirectPlugin = new Redirect(); - $this->customOptions = $customOptions; - } - - public function createResponse( - $statusCode, - array $headers = [], - $body = null, - array $options = [] - ) { - if (null !== $body) { - $body = Stream::factory($body); - } - - return new Response($statusCode, $headers, $body, $options); - } - - public function createRequest($method, $url, array $options = []) - { - // Handle the request protocol version option that needs to be - // specified in the request constructor. - if (isset($options['version'])) { - $options['config']['protocol_version'] = $options['version']; - unset($options['version']); - } - - $request = new Request($method, $url, [], null, - isset($options['config']) ? $options['config'] : []); - - unset($options['config']); - - // Use a POST body by default - if (strtoupper($method) == 'POST' - && !isset($options['body']) - && !isset($options['json']) - ) { - $options['body'] = []; - } - - if ($options) { - $this->applyOptions($request, $options); - } - - return $request; - } - - /** - * Create a request or response object from an HTTP message string - * - * @param string $message Message to parse - * - * @return RequestInterface|ResponseInterface - * @throws \InvalidArgumentException if unable to parse a message - */ - public function fromMessage($message) - { - static $parser; - if (!$parser) { - $parser = new MessageParser(); - } - - // Parse a response - if (strtoupper(substr($message, 0, 4)) == 'HTTP') { - $data = $parser->parseResponse($message); - return $this->createResponse( - $data['code'], - $data['headers'], - $data['body'] === '' ? null : $data['body'], - $data - ); - } - - // Parse a request - if (!($data = ($parser->parseRequest($message)))) { - throw new \InvalidArgumentException('Unable to parse request'); - } - - return $this->createRequest( - $data['method'], - Url::buildUrl($data['request_url']), - [ - 'headers' => $data['headers'], - 'body' => $data['body'] === '' ? null : $data['body'], - 'config' => [ - 'protocol_version' => $data['protocol_version'] - ] - ] - ); - } - - /** - * Apply POST fields and files to a request to attempt to give an accurate - * representation. - * - * @param RequestInterface $request Request to update - * @param array $body Body to apply - */ - protected function addPostData(RequestInterface $request, array $body) - { - static $fields = ['string' => true, 'array' => true, 'NULL' => true, - 'boolean' => true, 'double' => true, 'integer' => true]; - - $post = new PostBody(); - foreach ($body as $key => $value) { - if (isset($fields[gettype($value)])) { - $post->setField($key, $value); - } elseif ($value instanceof PostFileInterface) { - $post->addFile($value); - } else { - $post->addFile(new PostFile($key, $value)); - } - } - - if ($request->getHeader('Content-Type') == 'multipart/form-data') { - $post->forceMultipartUpload(true); - } - - $request->setBody($post); - } - - protected function applyOptions( - RequestInterface $request, - array $options = [] - ) { - $config = $request->getConfig(); - $emitter = $request->getEmitter(); - - foreach ($options as $key => $value) { - - if (isset(self::$configMap[$key])) { - $config[$key] = $value; - continue; - } - - switch ($key) { - - case 'allow_redirects': - - if ($value === false) { - continue 2; - } - - if ($value === true) { - $value = self::$defaultRedirect; - } elseif (!is_array($value)) { - throw new Iae('allow_redirects must be true, false, or array'); - } else { - // Merge the default settings with the provided settings - $value += self::$defaultRedirect; - } - - $config['redirect'] = $value; - $emitter->attach($this->redirectPlugin); - break; - - case 'decode_content': - - if ($value === false) { - continue 2; - } - - $config['decode_content'] = true; - if ($value !== true) { - $request->setHeader('Accept-Encoding', $value); - } - break; - - case 'headers': - - if (!is_array($value)) { - throw new Iae('header value must be an array'); - } - foreach ($value as $k => $v) { - $request->setHeader($k, $v); - } - break; - - case 'exceptions': - - if ($value === true) { - $emitter->attach($this->errorPlugin); - } - break; - - case 'body': - - if (is_array($value)) { - $this->addPostData($request, $value); - } elseif ($value !== null) { - $request->setBody(Stream::factory($value)); - } - break; - - case 'auth': - - if (!$value) { - continue 2; - } - - if (is_array($value)) { - $type = isset($value[2]) ? strtolower($value[2]) : 'basic'; - } else { - $type = strtolower($value); - } - - $config['auth'] = $value; - - if ($type == 'basic') { - $request->setHeader( - 'Authorization', - 'Basic ' . base64_encode("$value[0]:$value[1]") - ); - } elseif ($type == 'digest') { - // @todo: Do not rely on curl - $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); - $config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]"); - } - break; - - case 'query': - - if ($value instanceof Query) { - $original = $request->getQuery(); - // Do not overwrite existing query string variables by - // overwriting the object with the query string data passed - // in the URL - $value->overwriteWith($original->toArray()); - $request->setQuery($value); - } elseif (is_array($value)) { - // Do not overwrite existing query string variables - $query = $request->getQuery(); - foreach ($value as $k => $v) { - if (!isset($query[$k])) { - $query[$k] = $v; - } - } - } else { - throw new Iae('query must be an array or Query object'); - } - break; - - case 'cookies': - - if ($value === true) { - static $cookie = null; - if (!$cookie) { - $cookie = new Cookie(); - } - $emitter->attach($cookie); - } elseif (is_array($value)) { - $emitter->attach( - new Cookie(CookieJar::fromArray($value, $request->getHost())) - ); - } elseif ($value instanceof CookieJarInterface) { - $emitter->attach(new Cookie($value)); - } elseif ($value !== false) { - throw new Iae('cookies must be an array, true, or CookieJarInterface'); - } - break; - - case 'events': - - if (!is_array($value)) { - throw new Iae('events must be an array'); - } - - $this->attachListeners($request, - $this->prepareListeners( - $value, - ['before', 'complete', 'error', 'progress', 'end'] - ) - ); - break; - - case 'subscribers': - - if (!is_array($value)) { - throw new Iae('subscribers must be an array'); - } - - foreach ($value as $subscribers) { - $emitter->attach($subscribers); - } - break; - - case 'json': - - $request->setBody(Stream::factory(json_encode($value))); - if (!$request->hasHeader('Content-Type')) { - $request->setHeader('Content-Type', 'application/json'); - } - break; - - default: - - // Check for custom handler functions. - if (isset($this->customOptions[$key])) { - $fn = $this->customOptions[$key]; - $fn($request, $value); - continue 2; - } - - throw new Iae("No method can handle the {$key} config key"); - } - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php b/vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php deleted file mode 100644 index 86ae9c7..0000000 --- a/vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php +++ /dev/null @@ -1,71 +0,0 @@ -getHeaders() as $name => $values) { - * echo $name . ": " . implode(", ", $values); - * } - * - * @return array Returns an associative array of the message's headers. - */ - public function getHeaders(); - - /** - * Retrieve a header by the given case-insensitive name. - * - * @param string $header Case-insensitive header name. - * - * @return string - */ - public function getHeader($header); - - /** - * Retrieves a header by the given case-insensitive name as an array of strings. - * - * @param string $header Case-insensitive header name. - * - * @return string[] - */ - public function getHeaderAsArray($header); - - /** - * Checks if a header exists by the given case-insensitive name. - * - * @param string $header Case-insensitive header name. - * - * @return bool Returns true if any header names match the given header - * name using a case-insensitive string comparison. Returns false if - * no matching header name is found in the message. - */ - public function hasHeader($header); - - /** - * Remove a specific header by case-insensitive name. - * - * @param string $header Case-insensitive header name. - */ - public function removeHeader($header); - - /** - * Appends a header value to any existing values associated with the - * given header name. - * - * @param string $header Header name to add - * @param string $value Value of the header - */ - public function addHeader($header, $value); - - /** - * Merges in an associative array of headers. - * - * Each array key MUST be a string representing the case-insensitive name - * of a header. Each value MUST be either a string or an array of strings. - * For each value, the value is appended to any existing header of the same - * name, or, if a header does not already exist by the given name, then the - * header is added. - * - * @param array $headers Associative array of headers to add to the message - */ - public function addHeaders(array $headers); - - /** - * Sets a header, replacing any existing values of any headers with the - * same case-insensitive name. - * - * The header values MUST be a string or an array of strings. - * - * @param string $header Header name - * @param string|array $value Header value(s) - */ - public function setHeader($header, $value); - - /** - * Sets headers, replacing any headers that have already been set on the - * message. - * - * The array keys MUST be a string. The array values must be either a - * string or an array of strings. - * - * @param array $headers Headers to set. - */ - public function setHeaders(array $headers); -} diff --git a/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php b/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php deleted file mode 100644 index c3cc195..0000000 --- a/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php +++ /dev/null @@ -1,171 +0,0 @@ -parseMessage($message))) { - return false; - } - - // Parse the protocol and protocol version - if (isset($parts['start_line'][2])) { - $startParts = explode('/', $parts['start_line'][2]); - $protocol = strtoupper($startParts[0]); - $version = isset($startParts[1]) ? $startParts[1] : '1.1'; - } else { - $protocol = 'HTTP'; - $version = '1.1'; - } - - $parsed = [ - 'method' => strtoupper($parts['start_line'][0]), - 'protocol' => $protocol, - 'protocol_version' => $version, - 'headers' => $parts['headers'], - 'body' => $parts['body'] - ]; - - $parsed['request_url'] = $this->getUrlPartsFromMessage( - (isset($parts['start_line'][1]) ? $parts['start_line'][1] : ''), $parsed); - - return $parsed; - } - - /** - * Parse an HTTP response message into an associative array of parts. - * - * @param string $message HTTP response to parse - * - * @return array|bool Returns false if the message is invalid - */ - public function parseResponse($message) - { - if (!($parts = $this->parseMessage($message))) { - return false; - } - - list($protocol, $version) = explode('/', trim($parts['start_line'][0])); - - return [ - 'protocol' => $protocol, - 'protocol_version' => $version, - 'code' => $parts['start_line'][1], - 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '', - 'headers' => $parts['headers'], - 'body' => $parts['body'] - ]; - } - - /** - * Parse a message into parts - * - * @param string $message Message to parse - * - * @return array|bool - */ - private function parseMessage($message) - { - if (!$message) { - return false; - } - - $startLine = null; - $headers = []; - $body = ''; - - // Iterate over each line in the message, accounting for line endings - $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); - for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { - - $line = $lines[$i]; - - // If two line breaks were encountered, then this is the end of body - if (empty($line)) { - if ($i < $totalLines - 1) { - $body = implode('', array_slice($lines, $i + 2)); - } - break; - } - - // Parse message headers - if (!$startLine) { - $startLine = explode(' ', $line, 3); - } elseif (strpos($line, ':')) { - $parts = explode(':', $line, 2); - $key = trim($parts[0]); - $value = isset($parts[1]) ? trim($parts[1]) : ''; - if (!isset($headers[$key])) { - $headers[$key] = $value; - } elseif (!is_array($headers[$key])) { - $headers[$key] = [$headers[$key], $value]; - } else { - $headers[$key][] = $value; - } - } - } - - return [ - 'start_line' => $startLine, - 'headers' => $headers, - 'body' => $body - ]; - } - - /** - * Create URL parts from HTTP message parts - * - * @param string $requestUrl Associated URL - * @param array $parts HTTP message parts - * - * @return array - */ - private function getUrlPartsFromMessage($requestUrl, array $parts) - { - // Parse the URL information from the message - $urlParts = ['path' => $requestUrl, 'scheme' => 'http']; - - // Check for the Host header - if (isset($parts['headers']['Host'])) { - $urlParts['host'] = $parts['headers']['Host']; - } elseif (isset($parts['headers']['host'])) { - $urlParts['host'] = $parts['headers']['host']; - } else { - $urlParts['host'] = null; - } - - if (false === strpos($urlParts['host'], ':')) { - $urlParts['port'] = ''; - } else { - $hostParts = explode(':', $urlParts['host']); - $urlParts['host'] = trim($hostParts[0]); - $urlParts['port'] = (int) trim($hostParts[1]); - if ($urlParts['port'] == 443) { - $urlParts['scheme'] = 'https'; - } - } - - // Check if a query is present - $path = $urlParts['path']; - $qpos = strpos($path, '?'); - if ($qpos) { - $urlParts['query'] = substr($path, $qpos + 1); - $urlParts['path'] = substr($path, 0, $qpos); - } else { - $urlParts['query'] = ''; - } - - return $urlParts; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Message/Request.php b/vendor/guzzlehttp/guzzle/src/Message/Request.php deleted file mode 100644 index 38714af..0000000 --- a/vendor/guzzlehttp/guzzle/src/Message/Request.php +++ /dev/null @@ -1,195 +0,0 @@ -setUrl($url); - $this->method = strtoupper($method); - $this->handleOptions($options); - $this->transferOptions = new Collection($options); - $this->addPrepareEvent(); - - if ($body !== null) { - $this->setBody($body); - } - - if ($headers) { - foreach ($headers as $key => $value) { - $this->addHeader($key, $value); - } - } - } - - public function __clone() - { - if ($this->emitter) { - $this->emitter = clone $this->emitter; - } - $this->transferOptions = clone $this->transferOptions; - $this->url = clone $this->url; - } - - public function setUrl($url) - { - $this->url = $url instanceof Url ? $url : Url::fromString($url); - $this->updateHostHeaderFromUrl(); - } - - public function getUrl() - { - return (string) $this->url; - } - - public function setQuery($query) - { - $this->url->setQuery($query); - } - - public function getQuery() - { - return $this->url->getQuery(); - } - - public function setMethod($method) - { - $this->method = strtoupper($method); - } - - public function getMethod() - { - return $this->method; - } - - public function getScheme() - { - return $this->url->getScheme(); - } - - public function setScheme($scheme) - { - $this->url->setScheme($scheme); - } - - public function getPort() - { - return $this->url->getPort(); - } - - public function setPort($port) - { - $this->url->setPort($port); - $this->updateHostHeaderFromUrl(); - } - - public function getHost() - { - return $this->url->getHost(); - } - - public function setHost($host) - { - $this->url->setHost($host); - $this->updateHostHeaderFromUrl(); - } - - public function getPath() - { - return '/' . ltrim($this->url->getPath(), '/'); - } - - public function setPath($path) - { - $this->url->setPath($path); - } - - public function getResource() - { - $resource = $this->getPath(); - if ($query = (string) $this->url->getQuery()) { - $resource .= '?' . $query; - } - - return $resource; - } - - public function getConfig() - { - return $this->transferOptions; - } - - protected function handleOptions(array &$options) - { - parent::handleOptions($options); - // Use a custom emitter if one is specified, and remove it from - // options that are exposed through getConfig() - if (isset($options['emitter'])) { - $this->emitter = $options['emitter']; - unset($options['emitter']); - } - } - - /** - * Adds a subscriber that ensures a request's body is prepared before - * sending. - */ - private function addPrepareEvent() - { - static $subscriber; - if (!$subscriber) { - $subscriber = new Prepare(); - } - - $this->getEmitter()->attach($subscriber); - } - - private function updateHostHeaderFromUrl() - { - $port = $this->url->getPort(); - $scheme = $this->url->getScheme(); - if ($host = $this->url->getHost()) { - if (($port == 80 && $scheme == 'http') || - ($port == 443 && $scheme == 'https') - ) { - $this->setHeader('Host', $host); - } else { - $this->setHeader('Host', "{$host}:{$port}"); - } - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php b/vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php deleted file mode 100644 index f6a69d1..0000000 --- a/vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php +++ /dev/null @@ -1,136 +0,0 @@ - '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', - 208 => 'Already Reported', - 226 => 'IM Used', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 308 => 'Permanent 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', - 425 => 'Reserved for WebDAV advanced collections expired proposal', - 426 => 'Upgrade required', - 428 => 'Precondition Required', - 429 => 'Too Many Requests', - 431 => 'Request Header Fields Too Large', - 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 (Experimental)', - 507 => 'Insufficient Storage', - 508 => 'Loop Detected', - 510 => 'Not Extended', - 511 => 'Network Authentication Required', - ]; - - /** @var string The reason phrase of the response (human readable code) */ - private $reasonPhrase; - - /** @var string The status code of the response */ - private $statusCode; - - /** @var string The effective URL that returned this response */ - private $effectiveUrl; - - /** - * @param int|string $statusCode The response status code (e.g. 200) - * @param array $headers The response headers - * @param StreamInterface $body The body of the response - * @param array $options Response message options - * - reason_phrase: Set a custom reason phrase - * - protocol_version: Set a custom protocol version - */ - public function __construct( - $statusCode, - array $headers = [], - StreamInterface $body = null, - array $options = [] - ) { - $this->statusCode = (int) $statusCode; - $this->handleOptions($options); - - // Assume a reason phrase if one was not applied as an option - if (!$this->reasonPhrase && - isset(self::$statusTexts[$this->statusCode]) - ) { - $this->reasonPhrase = self::$statusTexts[$this->statusCode]; - } - - if ($headers) { - $this->setHeaders($headers); - } - - if ($body) { - $this->setBody($body); - } - } - - public function getStatusCode() - { - return $this->statusCode; - } - - public function setStatusCode($code) - { - return $this->statusCode = (int) $code; - } - - public function getReasonPhrase() - { - return $this->reasonPhrase; - } - - public function setReasonPhrase($phrase) - { - return $this->reasonPhrase = $phrase; - } - - public function json(array $config = []) - { - try { - return Utils::jsonDecode( - (string) $this->getBody(), - isset($config['object']) ? !$config['object'] : true, - 512, - isset($config['big_int_strings']) ? JSON_BIGINT_AS_STRING : 0 - ); - } catch (\InvalidArgumentException $e) { - throw new ParseException( - $e->getMessage(), - $this - ); - } - } - - public function xml(array $config = []) - { - $disableEntities = libxml_disable_entity_loader(true); - $internalErrors = libxml_use_internal_errors(true); - - try { - // Allow XML to be retrieved even if there is no response body - $xml = new \SimpleXMLElement( - (string) $this->getBody() ?: '', - isset($config['libxml_options']) ? $config['libxml_options'] : LIBXML_NONET, - false, - isset($config['ns']) ? $config['ns'] : '', - isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false - ); - libxml_disable_entity_loader($disableEntities); - libxml_use_internal_errors($internalErrors); - } catch (\Exception $e) { - libxml_disable_entity_loader($disableEntities); - libxml_use_internal_errors($internalErrors); - throw new XmlParseException( - 'Unable to parse response body into XML: ' . $e->getMessage(), - $this, - $e, - (libxml_get_last_error()) ?: null - ); - } - - return $xml; - } - - public function getEffectiveUrl() - { - return $this->effectiveUrl; - } - - public function setEffectiveUrl($url) - { - $this->effectiveUrl = $url; - } - - /** - * Accepts and modifies the options provided to the response in the - * constructor. - * - * @param array $options Options array passed by reference. - */ - protected function handleOptions(array &$options = []) - { - parent::handleOptions($options); - if (isset($options['reason_phrase'])) { - $this->reasonPhrase = $options['reason_phrase']; - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php b/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php deleted file mode 100644 index c0ae9be..0000000 --- a/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php +++ /dev/null @@ -1,111 +0,0 @@ - 'text/vnd.in3d.3dml', - '3g2' => 'video/3gpp2', - '3gp' => 'video/3gpp', - '7z' => 'application/x-7z-compressed', - 'aab' => 'application/x-authorware-bin', - 'aac' => 'audio/x-aac', - 'aam' => 'application/x-authorware-map', - 'aas' => 'application/x-authorware-seg', - 'abw' => 'application/x-abiword', - 'ac' => 'application/pkix-attr-cert', - 'acc' => 'application/vnd.americandynamics.acc', - 'ace' => 'application/x-ace-compressed', - 'acu' => 'application/vnd.acucobol', - 'acutc' => 'application/vnd.acucorp', - 'adp' => 'audio/adpcm', - 'aep' => 'application/vnd.audiograph', - 'afm' => 'application/x-font-type1', - 'afp' => 'application/vnd.ibm.modcap', - 'ahead' => 'application/vnd.ahead.space', - 'ai' => 'application/postscript', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'air' => 'application/vnd.adobe.air-application-installer-package+zip', - 'ait' => 'application/vnd.dvb.ait', - 'ami' => 'application/vnd.amiga.ami', - 'apk' => 'application/vnd.android.package-archive', - 'application' => 'application/x-ms-application', - 'apr' => 'application/vnd.lotus-approach', - 'asa' => 'text/plain', - 'asax' => 'application/octet-stream', - 'asc' => 'application/pgp-signature', - 'ascx' => 'text/plain', - 'asf' => 'video/x-ms-asf', - 'ashx' => 'text/plain', - 'asm' => 'text/x-asm', - 'asmx' => 'text/plain', - 'aso' => 'application/vnd.accpac.simply.aso', - 'asp' => 'text/plain', - 'aspx' => 'text/plain', - 'asx' => 'video/x-ms-asf', - 'atc' => 'application/vnd.acucorp', - 'atom' => 'application/atom+xml', - 'atomcat' => 'application/atomcat+xml', - 'atomsvc' => 'application/atomsvc+xml', - 'atx' => 'application/vnd.antix.game-component', - 'au' => 'audio/basic', - 'avi' => 'video/x-msvideo', - 'aw' => 'application/applixware', - 'axd' => 'text/plain', - 'azf' => 'application/vnd.airzip.filesecure.azf', - 'azs' => 'application/vnd.airzip.filesecure.azs', - 'azw' => 'application/vnd.amazon.ebook', - 'bat' => 'application/x-msdownload', - 'bcpio' => 'application/x-bcpio', - 'bdf' => 'application/x-font-bdf', - 'bdm' => 'application/vnd.syncml.dm+wbxml', - 'bed' => 'application/vnd.realvnc.bed', - 'bh2' => 'application/vnd.fujitsu.oasysprs', - 'bin' => 'application/octet-stream', - 'bmi' => 'application/vnd.bmi', - 'bmp' => 'image/bmp', - 'book' => 'application/vnd.framemaker', - 'box' => 'application/vnd.previewsystems.box', - 'boz' => 'application/x-bzip2', - 'bpk' => 'application/octet-stream', - 'btif' => 'image/prs.btif', - 'bz' => 'application/x-bzip', - 'bz2' => 'application/x-bzip2', - 'c' => 'text/x-c', - 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', - 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', - 'c4d' => 'application/vnd.clonk.c4group', - 'c4f' => 'application/vnd.clonk.c4group', - 'c4g' => 'application/vnd.clonk.c4group', - 'c4p' => 'application/vnd.clonk.c4group', - 'c4u' => 'application/vnd.clonk.c4group', - 'cab' => 'application/vnd.ms-cab-compressed', - 'car' => 'application/vnd.curl.car', - 'cat' => 'application/vnd.ms-pki.seccat', - 'cc' => 'text/x-c', - 'cct' => 'application/x-director', - 'ccxml' => 'application/ccxml+xml', - 'cdbcmsg' => 'application/vnd.contact.cmsg', - 'cdf' => 'application/x-netcdf', - 'cdkey' => 'application/vnd.mediastation.cdkey', - 'cdmia' => 'application/cdmi-capability', - 'cdmic' => 'application/cdmi-container', - 'cdmid' => 'application/cdmi-domain', - 'cdmio' => 'application/cdmi-object', - 'cdmiq' => 'application/cdmi-queue', - 'cdx' => 'chemical/x-cdx', - 'cdxml' => 'application/vnd.chemdraw+xml', - 'cdy' => 'application/vnd.cinderella', - 'cer' => 'application/pkix-cert', - 'cfc' => 'application/x-coldfusion', - 'cfm' => 'application/x-coldfusion', - 'cgm' => 'image/cgm', - 'chat' => 'application/x-chat', - 'chm' => 'application/vnd.ms-htmlhelp', - 'chrt' => 'application/vnd.kde.kchart', - 'cif' => 'chemical/x-cif', - 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', - 'cil' => 'application/vnd.ms-artgalry', - 'cla' => 'application/vnd.claymore', - 'class' => 'application/java-vm', - 'clkk' => 'application/vnd.crick.clicker.keyboard', - 'clkp' => 'application/vnd.crick.clicker.palette', - 'clkt' => 'application/vnd.crick.clicker.template', - 'clkw' => 'application/vnd.crick.clicker.wordbank', - 'clkx' => 'application/vnd.crick.clicker', - 'clp' => 'application/x-msclip', - 'cmc' => 'application/vnd.cosmocaller', - 'cmdf' => 'chemical/x-cmdf', - 'cml' => 'chemical/x-cml', - 'cmp' => 'application/vnd.yellowriver-custom-menu', - 'cmx' => 'image/x-cmx', - 'cod' => 'application/vnd.rim.cod', - 'com' => 'application/x-msdownload', - 'conf' => 'text/plain', - 'cpio' => 'application/x-cpio', - 'cpp' => 'text/x-c', - 'cpt' => 'application/mac-compactpro', - 'crd' => 'application/x-mscardfile', - 'crl' => 'application/pkix-crl', - 'crt' => 'application/x-x509-ca-cert', - 'cryptonote' => 'application/vnd.rig.cryptonote', - 'cs' => 'text/plain', - 'csh' => 'application/x-csh', - 'csml' => 'chemical/x-csml', - 'csp' => 'application/vnd.commonspace', - 'css' => 'text/css', - 'cst' => 'application/x-director', - 'csv' => 'text/csv', - 'cu' => 'application/cu-seeme', - 'curl' => 'text/vnd.curl', - 'cww' => 'application/prs.cww', - 'cxt' => 'application/x-director', - 'cxx' => 'text/x-c', - 'dae' => 'model/vnd.collada+xml', - 'daf' => 'application/vnd.mobius.daf', - 'dataless' => 'application/vnd.fdsn.seed', - 'davmount' => 'application/davmount+xml', - 'dcr' => 'application/x-director', - 'dcurl' => 'text/vnd.curl.dcurl', - 'dd2' => 'application/vnd.oma.dd2+xml', - 'ddd' => 'application/vnd.fujixerox.ddd', - 'deb' => 'application/x-debian-package', - 'def' => 'text/plain', - 'deploy' => 'application/octet-stream', - 'der' => 'application/x-x509-ca-cert', - 'dfac' => 'application/vnd.dreamfactory', - 'dic' => 'text/x-c', - 'dir' => 'application/x-director', - 'dis' => 'application/vnd.mobius.dis', - 'dist' => 'application/octet-stream', - 'distz' => 'application/octet-stream', - 'djv' => 'image/vnd.djvu', - 'djvu' => 'image/vnd.djvu', - 'dll' => 'application/x-msdownload', - 'dmg' => 'application/octet-stream', - 'dms' => 'application/octet-stream', - 'dna' => 'application/vnd.dna', - 'doc' => 'application/msword', - 'docm' => 'application/vnd.ms-word.document.macroenabled.12', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'dot' => 'application/msword', - 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', - 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', - 'dp' => 'application/vnd.osgi.dp', - 'dpg' => 'application/vnd.dpgraph', - 'dra' => 'audio/vnd.dra', - 'dsc' => 'text/prs.lines.tag', - 'dssc' => 'application/dssc+der', - 'dtb' => 'application/x-dtbook+xml', - 'dtd' => 'application/xml-dtd', - 'dts' => 'audio/vnd.dts', - 'dtshd' => 'audio/vnd.dts.hd', - 'dump' => 'application/octet-stream', - 'dvi' => 'application/x-dvi', - 'dwf' => 'model/vnd.dwf', - 'dwg' => 'image/vnd.dwg', - 'dxf' => 'image/vnd.dxf', - 'dxp' => 'application/vnd.spotfire.dxp', - 'dxr' => 'application/x-director', - 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', - 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', - 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', - 'ecma' => 'application/ecmascript', - 'edm' => 'application/vnd.novadigm.edm', - 'edx' => 'application/vnd.novadigm.edx', - 'efif' => 'application/vnd.picsel', - 'ei6' => 'application/vnd.pg.osasli', - 'elc' => 'application/octet-stream', - 'eml' => 'message/rfc822', - 'emma' => 'application/emma+xml', - 'eol' => 'audio/vnd.digital-winds', - 'eot' => 'application/vnd.ms-fontobject', - 'eps' => 'application/postscript', - 'epub' => 'application/epub+zip', - 'es3' => 'application/vnd.eszigno3+xml', - 'esf' => 'application/vnd.epson.esf', - 'et3' => 'application/vnd.eszigno3+xml', - 'etx' => 'text/x-setext', - 'exe' => 'application/x-msdownload', - 'exi' => 'application/exi', - 'ext' => 'application/vnd.novadigm.ext', - 'ez' => 'application/andrew-inset', - 'ez2' => 'application/vnd.ezpix-album', - 'ez3' => 'application/vnd.ezpix-package', - 'f' => 'text/x-fortran', - 'f4v' => 'video/x-f4v', - 'f77' => 'text/x-fortran', - 'f90' => 'text/x-fortran', - 'fbs' => 'image/vnd.fastbidsheet', - 'fcs' => 'application/vnd.isac.fcs', - 'fdf' => 'application/vnd.fdf', - 'fe_launch' => 'application/vnd.denovo.fcselayout-link', - 'fg5' => 'application/vnd.fujitsu.oasysgp', - 'fgd' => 'application/x-director', - 'fh' => 'image/x-freehand', - 'fh4' => 'image/x-freehand', - 'fh5' => 'image/x-freehand', - 'fh7' => 'image/x-freehand', - 'fhc' => 'image/x-freehand', - 'fig' => 'application/x-xfig', - 'fli' => 'video/x-fli', - 'flo' => 'application/vnd.micrografx.flo', - 'flv' => 'video/x-flv', - 'flw' => 'application/vnd.kde.kivio', - 'flx' => 'text/vnd.fmi.flexstor', - 'fly' => 'text/vnd.fly', - 'fm' => 'application/vnd.framemaker', - 'fnc' => 'application/vnd.frogans.fnc', - 'for' => 'text/x-fortran', - 'fpx' => 'image/vnd.fpx', - 'frame' => 'application/vnd.framemaker', - 'fsc' => 'application/vnd.fsc.weblaunch', - 'fst' => 'image/vnd.fst', - 'ftc' => 'application/vnd.fluxtime.clip', - 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', - 'fvt' => 'video/vnd.fvt', - 'fxp' => 'application/vnd.adobe.fxp', - 'fxpl' => 'application/vnd.adobe.fxp', - 'fzs' => 'application/vnd.fuzzysheet', - 'g2w' => 'application/vnd.geoplan', - 'g3' => 'image/g3fax', - 'g3w' => 'application/vnd.geospace', - 'gac' => 'application/vnd.groove-account', - 'gdl' => 'model/vnd.gdl', - 'geo' => 'application/vnd.dynageo', - 'gex' => 'application/vnd.geometry-explorer', - 'ggb' => 'application/vnd.geogebra.file', - 'ggt' => 'application/vnd.geogebra.tool', - 'ghf' => 'application/vnd.groove-help', - 'gif' => 'image/gif', - 'gim' => 'application/vnd.groove-identity-message', - 'gmx' => 'application/vnd.gmx', - 'gnumeric' => 'application/x-gnumeric', - 'gph' => 'application/vnd.flographit', - 'gqf' => 'application/vnd.grafeq', - 'gqs' => 'application/vnd.grafeq', - 'gram' => 'application/srgs', - 'gre' => 'application/vnd.geometry-explorer', - 'grv' => 'application/vnd.groove-injector', - 'grxml' => 'application/srgs+xml', - 'gsf' => 'application/x-font-ghostscript', - 'gtar' => 'application/x-gtar', - 'gtm' => 'application/vnd.groove-tool-message', - 'gtw' => 'model/vnd.gtw', - 'gv' => 'text/vnd.graphviz', - 'gxt' => 'application/vnd.geonext', - 'h' => 'text/x-c', - 'h261' => 'video/h261', - 'h263' => 'video/h263', - 'h264' => 'video/h264', - 'hal' => 'application/vnd.hal+xml', - 'hbci' => 'application/vnd.hbci', - 'hdf' => 'application/x-hdf', - 'hh' => 'text/x-c', - 'hlp' => 'application/winhlp', - 'hpgl' => 'application/vnd.hp-hpgl', - 'hpid' => 'application/vnd.hp-hpid', - 'hps' => 'application/vnd.hp-hps', - 'hqx' => 'application/mac-binhex40', - 'hta' => 'application/octet-stream', - 'htc' => 'text/html', - 'htke' => 'application/vnd.kenameaapp', - 'htm' => 'text/html', - 'html' => 'text/html', - 'hvd' => 'application/vnd.yamaha.hv-dic', - 'hvp' => 'application/vnd.yamaha.hv-voice', - 'hvs' => 'application/vnd.yamaha.hv-script', - 'i2g' => 'application/vnd.intergeo', - 'icc' => 'application/vnd.iccprofile', - 'ice' => 'x-conference/x-cooltalk', - 'icm' => 'application/vnd.iccprofile', - 'ico' => 'image/x-icon', - 'ics' => 'text/calendar', - 'ief' => 'image/ief', - 'ifb' => 'text/calendar', - 'ifm' => 'application/vnd.shana.informed.formdata', - 'iges' => 'model/iges', - 'igl' => 'application/vnd.igloader', - 'igm' => 'application/vnd.insors.igm', - 'igs' => 'model/iges', - 'igx' => 'application/vnd.micrografx.igx', - 'iif' => 'application/vnd.shana.informed.interchange', - 'imp' => 'application/vnd.accpac.simply.imp', - 'ims' => 'application/vnd.ms-ims', - 'in' => 'text/plain', - 'ini' => 'text/plain', - 'ipfix' => 'application/ipfix', - 'ipk' => 'application/vnd.shana.informed.package', - 'irm' => 'application/vnd.ibm.rights-management', - 'irp' => 'application/vnd.irepository.package+xml', - 'iso' => 'application/octet-stream', - 'itp' => 'application/vnd.shana.informed.formtemplate', - 'ivp' => 'application/vnd.immervision-ivp', - 'ivu' => 'application/vnd.immervision-ivu', - 'jad' => 'text/vnd.sun.j2me.app-descriptor', - 'jam' => 'application/vnd.jam', - 'jar' => 'application/java-archive', - 'java' => 'text/x-java-source', - 'jisp' => 'application/vnd.jisp', - 'jlt' => 'application/vnd.hp-jlyt', - 'jnlp' => 'application/x-java-jnlp-file', - 'joda' => 'application/vnd.joost.joda-archive', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'jpgm' => 'video/jpm', - 'jpgv' => 'video/jpeg', - 'jpm' => 'video/jpm', - 'js' => 'text/javascript', - 'json' => 'application/json', - 'kar' => 'audio/midi', - 'karbon' => 'application/vnd.kde.karbon', - 'kfo' => 'application/vnd.kde.kformula', - 'kia' => 'application/vnd.kidspiration', - 'kml' => 'application/vnd.google-earth.kml+xml', - 'kmz' => 'application/vnd.google-earth.kmz', - 'kne' => 'application/vnd.kinar', - 'knp' => 'application/vnd.kinar', - 'kon' => 'application/vnd.kde.kontour', - 'kpr' => 'application/vnd.kde.kpresenter', - 'kpt' => 'application/vnd.kde.kpresenter', - 'ksp' => 'application/vnd.kde.kspread', - 'ktr' => 'application/vnd.kahootz', - 'ktx' => 'image/ktx', - 'ktz' => 'application/vnd.kahootz', - 'kwd' => 'application/vnd.kde.kword', - 'kwt' => 'application/vnd.kde.kword', - 'lasxml' => 'application/vnd.las.las+xml', - 'latex' => 'application/x-latex', - 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', - 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', - 'les' => 'application/vnd.hhe.lesson-player', - 'lha' => 'application/octet-stream', - 'link66' => 'application/vnd.route66.link66+xml', - 'list' => 'text/plain', - 'list3820' => 'application/vnd.ibm.modcap', - 'listafp' => 'application/vnd.ibm.modcap', - 'log' => 'text/plain', - 'lostxml' => 'application/lost+xml', - 'lrf' => 'application/octet-stream', - 'lrm' => 'application/vnd.ms-lrm', - 'ltf' => 'application/vnd.frogans.ltf', - 'lvp' => 'audio/vnd.lucent.voice', - 'lwp' => 'application/vnd.lotus-wordpro', - 'lzh' => 'application/octet-stream', - 'm13' => 'application/x-msmediaview', - 'm14' => 'application/x-msmediaview', - 'm1v' => 'video/mpeg', - 'm21' => 'application/mp21', - 'm2a' => 'audio/mpeg', - 'm2v' => 'video/mpeg', - 'm3a' => 'audio/mpeg', - 'm3u' => 'audio/x-mpegurl', - 'm3u8' => 'application/vnd.apple.mpegurl', - 'm4a' => 'audio/mp4', - 'm4u' => 'video/vnd.mpegurl', - 'm4v' => 'video/mp4', - 'ma' => 'application/mathematica', - 'mads' => 'application/mads+xml', - 'mag' => 'application/vnd.ecowin.chart', - 'maker' => 'application/vnd.framemaker', - 'man' => 'text/troff', - 'mathml' => 'application/mathml+xml', - 'mb' => 'application/mathematica', - 'mbk' => 'application/vnd.mobius.mbk', - 'mbox' => 'application/mbox', - 'mc1' => 'application/vnd.medcalcdata', - 'mcd' => 'application/vnd.mcd', - 'mcurl' => 'text/vnd.curl.mcurl', - 'mdb' => 'application/x-msaccess', - 'mdi' => 'image/vnd.ms-modi', - 'me' => 'text/troff', - 'mesh' => 'model/mesh', - 'meta4' => 'application/metalink4+xml', - 'mets' => 'application/mets+xml', - 'mfm' => 'application/vnd.mfmp', - 'mgp' => 'application/vnd.osgeo.mapguide.package', - 'mgz' => 'application/vnd.proteus.magazine', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mif' => 'application/vnd.mif', - 'mime' => 'message/rfc822', - 'mj2' => 'video/mj2', - 'mjp2' => 'video/mj2', - 'mlp' => 'application/vnd.dolby.mlp', - 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', - 'mmf' => 'application/vnd.smaf', - 'mmr' => 'image/vnd.fujixerox.edmics-mmr', - 'mny' => 'application/x-msmoney', - 'mobi' => 'application/x-mobipocket-ebook', - 'mods' => 'application/mods+xml', - 'mov' => 'video/quicktime', - 'movie' => 'video/x-sgi-movie', - 'mp2' => 'audio/mpeg', - 'mp21' => 'application/mp21', - 'mp2a' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mp4' => 'video/mp4', - 'mp4a' => 'audio/mp4', - 'mp4s' => 'application/mp4', - 'mp4v' => 'video/mp4', - 'mpc' => 'application/vnd.mophun.certificate', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpg4' => 'video/mp4', - 'mpga' => 'audio/mpeg', - 'mpkg' => 'application/vnd.apple.installer+xml', - 'mpm' => 'application/vnd.blueice.multipass', - 'mpn' => 'application/vnd.mophun.application', - 'mpp' => 'application/vnd.ms-project', - 'mpt' => 'application/vnd.ms-project', - 'mpy' => 'application/vnd.ibm.minipay', - 'mqy' => 'application/vnd.mobius.mqy', - 'mrc' => 'application/marc', - 'mrcx' => 'application/marcxml+xml', - 'ms' => 'text/troff', - 'mscml' => 'application/mediaservercontrol+xml', - 'mseed' => 'application/vnd.fdsn.mseed', - 'mseq' => 'application/vnd.mseq', - 'msf' => 'application/vnd.epson.msf', - 'msh' => 'model/mesh', - 'msi' => 'application/x-msdownload', - 'msl' => 'application/vnd.mobius.msl', - 'msty' => 'application/vnd.muvee.style', - 'mts' => 'model/vnd.mts', - 'mus' => 'application/vnd.musician', - 'musicxml' => 'application/vnd.recordare.musicxml+xml', - 'mvb' => 'application/x-msmediaview', - 'mwf' => 'application/vnd.mfer', - 'mxf' => 'application/mxf', - 'mxl' => 'application/vnd.recordare.musicxml', - 'mxml' => 'application/xv+xml', - 'mxs' => 'application/vnd.triscape.mxs', - 'mxu' => 'video/vnd.mpegurl', - 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', - 'n3' => 'text/n3', - 'nb' => 'application/mathematica', - 'nbp' => 'application/vnd.wolfram.player', - 'nc' => 'application/x-netcdf', - 'ncx' => 'application/x-dtbncx+xml', - 'ngdat' => 'application/vnd.nokia.n-gage.data', - 'nlu' => 'application/vnd.neurolanguage.nlu', - 'nml' => 'application/vnd.enliven', - 'nnd' => 'application/vnd.noblenet-directory', - 'nns' => 'application/vnd.noblenet-sealer', - 'nnw' => 'application/vnd.noblenet-web', - 'npx' => 'image/vnd.net-fpx', - 'nsf' => 'application/vnd.lotus-notes', - 'oa2' => 'application/vnd.fujitsu.oasys2', - 'oa3' => 'application/vnd.fujitsu.oasys3', - 'oas' => 'application/vnd.fujitsu.oasys', - 'obd' => 'application/x-msbinder', - 'oda' => 'application/oda', - 'odb' => 'application/vnd.oasis.opendocument.database', - 'odc' => 'application/vnd.oasis.opendocument.chart', - 'odf' => 'application/vnd.oasis.opendocument.formula', - 'odft' => 'application/vnd.oasis.opendocument.formula-template', - 'odg' => 'application/vnd.oasis.opendocument.graphics', - 'odi' => 'application/vnd.oasis.opendocument.image', - 'odm' => 'application/vnd.oasis.opendocument.text-master', - 'odp' => 'application/vnd.oasis.opendocument.presentation', - 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', - 'odt' => 'application/vnd.oasis.opendocument.text', - 'oga' => 'audio/ogg', - 'ogg' => 'audio/ogg', - 'ogv' => 'video/ogg', - 'ogx' => 'application/ogg', - 'onepkg' => 'application/onenote', - 'onetmp' => 'application/onenote', - 'onetoc' => 'application/onenote', - 'onetoc2' => 'application/onenote', - 'opf' => 'application/oebps-package+xml', - 'oprc' => 'application/vnd.palm', - 'org' => 'application/vnd.lotus-organizer', - 'osf' => 'application/vnd.yamaha.openscoreformat', - 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', - 'otc' => 'application/vnd.oasis.opendocument.chart-template', - 'otf' => 'application/x-font-otf', - 'otg' => 'application/vnd.oasis.opendocument.graphics-template', - 'oth' => 'application/vnd.oasis.opendocument.text-web', - 'oti' => 'application/vnd.oasis.opendocument.image-template', - 'otp' => 'application/vnd.oasis.opendocument.presentation-template', - 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', - 'ott' => 'application/vnd.oasis.opendocument.text-template', - 'oxt' => 'application/vnd.openofficeorg.extension', - 'p' => 'text/x-pascal', - 'p10' => 'application/pkcs10', - 'p12' => 'application/x-pkcs12', - 'p7b' => 'application/x-pkcs7-certificates', - 'p7c' => 'application/pkcs7-mime', - 'p7m' => 'application/pkcs7-mime', - 'p7r' => 'application/x-pkcs7-certreqresp', - 'p7s' => 'application/pkcs7-signature', - 'p8' => 'application/pkcs8', - 'pas' => 'text/x-pascal', - 'paw' => 'application/vnd.pawaafile', - 'pbd' => 'application/vnd.powerbuilder6', - 'pbm' => 'image/x-portable-bitmap', - 'pcf' => 'application/x-font-pcf', - 'pcl' => 'application/vnd.hp-pcl', - 'pclxl' => 'application/vnd.hp-pclxl', - 'pct' => 'image/x-pict', - 'pcurl' => 'application/vnd.curl.pcurl', - 'pcx' => 'image/x-pcx', - 'pdb' => 'application/vnd.palm', - 'pdf' => 'application/pdf', - 'pfa' => 'application/x-font-type1', - 'pfb' => 'application/x-font-type1', - 'pfm' => 'application/x-font-type1', - 'pfr' => 'application/font-tdpfr', - 'pfx' => 'application/x-pkcs12', - 'pgm' => 'image/x-portable-graymap', - 'pgn' => 'application/x-chess-pgn', - 'pgp' => 'application/pgp-encrypted', - 'php' => 'text/x-php', - 'phps' => 'application/x-httpd-phps', - 'pic' => 'image/x-pict', - 'pkg' => 'application/octet-stream', - 'pki' => 'application/pkixcmp', - 'pkipath' => 'application/pkix-pkipath', - 'plb' => 'application/vnd.3gpp.pic-bw-large', - 'plc' => 'application/vnd.mobius.plc', - 'plf' => 'application/vnd.pocketlearn', - 'pls' => 'application/pls+xml', - 'pml' => 'application/vnd.ctc-posml', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', - 'portpkg' => 'application/vnd.macports.portpkg', - 'pot' => 'application/vnd.ms-powerpoint', - 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', - 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', - 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', - 'ppd' => 'application/vnd.cups-ppd', - 'ppm' => 'image/x-portable-pixmap', - 'pps' => 'application/vnd.ms-powerpoint', - 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', - 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'pqa' => 'application/vnd.palm', - 'prc' => 'application/x-mobipocket-ebook', - 'pre' => 'application/vnd.lotus-freelance', - 'prf' => 'application/pics-rules', - 'ps' => 'application/postscript', - 'psb' => 'application/vnd.3gpp.pic-bw-small', - 'psd' => 'image/vnd.adobe.photoshop', - 'psf' => 'application/x-font-linux-psf', - 'pskcxml' => 'application/pskc+xml', - 'ptid' => 'application/vnd.pvi.ptid1', - 'pub' => 'application/x-mspublisher', - 'pvb' => 'application/vnd.3gpp.pic-bw-var', - 'pwn' => 'application/vnd.3m.post-it-notes', - 'pya' => 'audio/vnd.ms-playready.media.pya', - 'pyv' => 'video/vnd.ms-playready.media.pyv', - 'qam' => 'application/vnd.epson.quickanime', - 'qbo' => 'application/vnd.intu.qbo', - 'qfx' => 'application/vnd.intu.qfx', - 'qps' => 'application/vnd.publishare-delta-tree', - 'qt' => 'video/quicktime', - 'qwd' => 'application/vnd.quark.quarkxpress', - 'qwt' => 'application/vnd.quark.quarkxpress', - 'qxb' => 'application/vnd.quark.quarkxpress', - 'qxd' => 'application/vnd.quark.quarkxpress', - 'qxl' => 'application/vnd.quark.quarkxpress', - 'qxt' => 'application/vnd.quark.quarkxpress', - 'ra' => 'audio/x-pn-realaudio', - 'ram' => 'audio/x-pn-realaudio', - 'rar' => 'application/x-rar-compressed', - 'ras' => 'image/x-cmu-raster', - 'rb' => 'text/plain', - 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', - 'rdf' => 'application/rdf+xml', - 'rdz' => 'application/vnd.data-vision.rdz', - 'rep' => 'application/vnd.businessobjects', - 'res' => 'application/x-dtbresource+xml', - 'resx' => 'text/xml', - 'rgb' => 'image/x-rgb', - 'rif' => 'application/reginfo+xml', - 'rip' => 'audio/vnd.rip', - 'rl' => 'application/resource-lists+xml', - 'rlc' => 'image/vnd.fujixerox.edmics-rlc', - 'rld' => 'application/resource-lists-diff+xml', - 'rm' => 'application/vnd.rn-realmedia', - 'rmi' => 'audio/midi', - 'rmp' => 'audio/x-pn-realaudio-plugin', - 'rms' => 'application/vnd.jcp.javame.midlet-rms', - 'rnc' => 'application/relax-ng-compact-syntax', - 'roff' => 'text/troff', - 'rp9' => 'application/vnd.cloanto.rp9', - 'rpss' => 'application/vnd.nokia.radio-presets', - 'rpst' => 'application/vnd.nokia.radio-preset', - 'rq' => 'application/sparql-query', - 'rs' => 'application/rls-services+xml', - 'rsd' => 'application/rsd+xml', - 'rss' => 'application/rss+xml', - 'rtf' => 'application/rtf', - 'rtx' => 'text/richtext', - 's' => 'text/x-asm', - 'saf' => 'application/vnd.yamaha.smaf-audio', - 'sbml' => 'application/sbml+xml', - 'sc' => 'application/vnd.ibm.secure-container', - 'scd' => 'application/x-msschedule', - 'scm' => 'application/vnd.lotus-screencam', - 'scq' => 'application/scvp-cv-request', - 'scs' => 'application/scvp-cv-response', - 'scurl' => 'text/vnd.curl.scurl', - 'sda' => 'application/vnd.stardivision.draw', - 'sdc' => 'application/vnd.stardivision.calc', - 'sdd' => 'application/vnd.stardivision.impress', - 'sdkd' => 'application/vnd.solent.sdkm+xml', - 'sdkm' => 'application/vnd.solent.sdkm+xml', - 'sdp' => 'application/sdp', - 'sdw' => 'application/vnd.stardivision.writer', - 'see' => 'application/vnd.seemail', - 'seed' => 'application/vnd.fdsn.seed', - 'sema' => 'application/vnd.sema', - 'semd' => 'application/vnd.semd', - 'semf' => 'application/vnd.semf', - 'ser' => 'application/java-serialized-object', - 'setpay' => 'application/set-payment-initiation', - 'setreg' => 'application/set-registration-initiation', - 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', - 'sfs' => 'application/vnd.spotfire.sfs', - 'sgl' => 'application/vnd.stardivision.writer-global', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', - 'sh' => 'application/x-sh', - 'shar' => 'application/x-shar', - 'shf' => 'application/shf+xml', - 'sig' => 'application/pgp-signature', - 'silo' => 'model/mesh', - 'sis' => 'application/vnd.symbian.install', - 'sisx' => 'application/vnd.symbian.install', - 'sit' => 'application/x-stuffit', - 'sitx' => 'application/x-stuffitx', - 'skd' => 'application/vnd.koan', - 'skm' => 'application/vnd.koan', - 'skp' => 'application/vnd.koan', - 'skt' => 'application/vnd.koan', - 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', - 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', - 'slt' => 'application/vnd.epson.salt', - 'sm' => 'application/vnd.stepmania.stepchart', - 'smf' => 'application/vnd.stardivision.math', - 'smi' => 'application/smil+xml', - 'smil' => 'application/smil+xml', - 'snd' => 'audio/basic', - 'snf' => 'application/x-font-snf', - 'so' => 'application/octet-stream', - 'spc' => 'application/x-pkcs7-certificates', - 'spf' => 'application/vnd.yamaha.smaf-phrase', - 'spl' => 'application/x-futuresplash', - 'spot' => 'text/vnd.in3d.spot', - 'spp' => 'application/scvp-vp-response', - 'spq' => 'application/scvp-vp-request', - 'spx' => 'audio/ogg', - 'src' => 'application/x-wais-source', - 'sru' => 'application/sru+xml', - 'srx' => 'application/sparql-results+xml', - 'sse' => 'application/vnd.kodak-descriptor', - 'ssf' => 'application/vnd.epson.ssf', - 'ssml' => 'application/ssml+xml', - 'st' => 'application/vnd.sailingtracker.track', - 'stc' => 'application/vnd.sun.xml.calc.template', - 'std' => 'application/vnd.sun.xml.draw.template', - 'stf' => 'application/vnd.wt.stf', - 'sti' => 'application/vnd.sun.xml.impress.template', - 'stk' => 'application/hyperstudio', - 'stl' => 'application/vnd.ms-pki.stl', - 'str' => 'application/vnd.pg.format', - 'stw' => 'application/vnd.sun.xml.writer.template', - 'sub' => 'image/vnd.dvb.subtitle', - 'sus' => 'application/vnd.sus-calendar', - 'susp' => 'application/vnd.sus-calendar', - 'sv4cpio' => 'application/x-sv4cpio', - 'sv4crc' => 'application/x-sv4crc', - 'svc' => 'application/vnd.dvb.service', - 'svd' => 'application/vnd.svd', - 'svg' => 'image/svg+xml', - 'svgz' => 'image/svg+xml', - 'swa' => 'application/x-director', - 'swf' => 'application/x-shockwave-flash', - 'swi' => 'application/vnd.aristanetworks.swi', - 'sxc' => 'application/vnd.sun.xml.calc', - 'sxd' => 'application/vnd.sun.xml.draw', - 'sxg' => 'application/vnd.sun.xml.writer.global', - 'sxi' => 'application/vnd.sun.xml.impress', - 'sxm' => 'application/vnd.sun.xml.math', - 'sxw' => 'application/vnd.sun.xml.writer', - 't' => 'text/troff', - 'tao' => 'application/vnd.tao.intent-module-archive', - 'tar' => 'application/x-tar', - 'tcap' => 'application/vnd.3gpp2.tcap', - 'tcl' => 'application/x-tcl', - 'teacher' => 'application/vnd.smart.teacher', - 'tei' => 'application/tei+xml', - 'teicorpus' => 'application/tei+xml', - 'tex' => 'application/x-tex', - 'texi' => 'application/x-texinfo', - 'texinfo' => 'application/x-texinfo', - 'text' => 'text/plain', - 'tfi' => 'application/thraud+xml', - 'tfm' => 'application/x-tex-tfm', - 'thmx' => 'application/vnd.ms-officetheme', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'tmo' => 'application/vnd.tmobile-livetv', - 'torrent' => 'application/x-bittorrent', - 'tpl' => 'application/vnd.groove-tool-template', - 'tpt' => 'application/vnd.trid.tpt', - 'tr' => 'text/troff', - 'tra' => 'application/vnd.trueapp', - 'trm' => 'application/x-msterminal', - 'tsd' => 'application/timestamped-data', - 'tsv' => 'text/tab-separated-values', - 'ttc' => 'application/x-font-ttf', - 'ttf' => 'application/x-font-ttf', - 'ttl' => 'text/turtle', - 'twd' => 'application/vnd.simtech-mindmapper', - 'twds' => 'application/vnd.simtech-mindmapper', - 'txd' => 'application/vnd.genomatix.tuxedo', - 'txf' => 'application/vnd.mobius.txf', - 'txt' => 'text/plain', - 'u32' => 'application/x-authorware-bin', - 'udeb' => 'application/x-debian-package', - 'ufd' => 'application/vnd.ufdl', - 'ufdl' => 'application/vnd.ufdl', - 'umj' => 'application/vnd.umajin', - 'unityweb' => 'application/vnd.unity', - 'uoml' => 'application/vnd.uoml+xml', - 'uri' => 'text/uri-list', - 'uris' => 'text/uri-list', - 'urls' => 'text/uri-list', - 'ustar' => 'application/x-ustar', - 'utz' => 'application/vnd.uiq.theme', - 'uu' => 'text/x-uuencode', - 'uva' => 'audio/vnd.dece.audio', - 'uvd' => 'application/vnd.dece.data', - 'uvf' => 'application/vnd.dece.data', - 'uvg' => 'image/vnd.dece.graphic', - 'uvh' => 'video/vnd.dece.hd', - 'uvi' => 'image/vnd.dece.graphic', - 'uvm' => 'video/vnd.dece.mobile', - 'uvp' => 'video/vnd.dece.pd', - 'uvs' => 'video/vnd.dece.sd', - 'uvt' => 'application/vnd.dece.ttml+xml', - 'uvu' => 'video/vnd.uvvu.mp4', - 'uvv' => 'video/vnd.dece.video', - 'uvva' => 'audio/vnd.dece.audio', - 'uvvd' => 'application/vnd.dece.data', - 'uvvf' => 'application/vnd.dece.data', - 'uvvg' => 'image/vnd.dece.graphic', - 'uvvh' => 'video/vnd.dece.hd', - 'uvvi' => 'image/vnd.dece.graphic', - 'uvvm' => 'video/vnd.dece.mobile', - 'uvvp' => 'video/vnd.dece.pd', - 'uvvs' => 'video/vnd.dece.sd', - 'uvvt' => 'application/vnd.dece.ttml+xml', - 'uvvu' => 'video/vnd.uvvu.mp4', - 'uvvv' => 'video/vnd.dece.video', - 'uvvx' => 'application/vnd.dece.unspecified', - 'uvx' => 'application/vnd.dece.unspecified', - 'vcd' => 'application/x-cdlink', - 'vcf' => 'text/x-vcard', - 'vcg' => 'application/vnd.groove-vcard', - 'vcs' => 'text/x-vcalendar', - 'vcx' => 'application/vnd.vcx', - 'vis' => 'application/vnd.visionary', - 'viv' => 'video/vnd.vivo', - 'vor' => 'application/vnd.stardivision.writer', - 'vox' => 'application/x-authorware-bin', - 'vrml' => 'model/vrml', - 'vsd' => 'application/vnd.visio', - 'vsf' => 'application/vnd.vsf', - 'vss' => 'application/vnd.visio', - 'vst' => 'application/vnd.visio', - 'vsw' => 'application/vnd.visio', - 'vtu' => 'model/vnd.vtu', - 'vxml' => 'application/voicexml+xml', - 'w3d' => 'application/x-director', - 'wad' => 'application/x-doom', - 'wav' => 'audio/x-wav', - 'wax' => 'audio/x-ms-wax', - 'wbmp' => 'image/vnd.wap.wbmp', - 'wbs' => 'application/vnd.criticaltools.wbs+xml', - 'wbxml' => 'application/vnd.wap.wbxml', - 'wcm' => 'application/vnd.ms-works', - 'wdb' => 'application/vnd.ms-works', - 'weba' => 'audio/webm', - 'webm' => 'video/webm', - 'webp' => 'image/webp', - 'wg' => 'application/vnd.pmi.widget', - 'wgt' => 'application/widget', - 'wks' => 'application/vnd.ms-works', - 'wm' => 'video/x-ms-wm', - 'wma' => 'audio/x-ms-wma', - 'wmd' => 'application/x-ms-wmd', - 'wmf' => 'application/x-msmetafile', - 'wml' => 'text/vnd.wap.wml', - 'wmlc' => 'application/vnd.wap.wmlc', - 'wmls' => 'text/vnd.wap.wmlscript', - 'wmlsc' => 'application/vnd.wap.wmlscriptc', - 'wmv' => 'video/x-ms-wmv', - 'wmx' => 'video/x-ms-wmx', - 'wmz' => 'application/x-ms-wmz', - 'woff' => 'application/x-font-woff', - 'wpd' => 'application/vnd.wordperfect', - 'wpl' => 'application/vnd.ms-wpl', - 'wps' => 'application/vnd.ms-works', - 'wqd' => 'application/vnd.wqd', - 'wri' => 'application/x-mswrite', - 'wrl' => 'model/vrml', - 'wsdl' => 'application/wsdl+xml', - 'wspolicy' => 'application/wspolicy+xml', - 'wtb' => 'application/vnd.webturbo', - 'wvx' => 'video/x-ms-wvx', - 'x32' => 'application/x-authorware-bin', - 'x3d' => 'application/vnd.hzn-3d-crossword', - 'xap' => 'application/x-silverlight-app', - 'xar' => 'application/vnd.xara', - 'xbap' => 'application/x-ms-xbap', - 'xbd' => 'application/vnd.fujixerox.docuworks.binder', - 'xbm' => 'image/x-xbitmap', - 'xdf' => 'application/xcap-diff+xml', - 'xdm' => 'application/vnd.syncml.dm+xml', - 'xdp' => 'application/vnd.adobe.xdp+xml', - 'xdssc' => 'application/dssc+xml', - 'xdw' => 'application/vnd.fujixerox.docuworks', - 'xenc' => 'application/xenc+xml', - 'xer' => 'application/patch-ops-error+xml', - 'xfdf' => 'application/vnd.adobe.xfdf', - 'xfdl' => 'application/vnd.xfdl', - 'xht' => 'application/xhtml+xml', - 'xhtml' => 'application/xhtml+xml', - 'xhvml' => 'application/xv+xml', - 'xif' => 'image/vnd.xiff', - 'xla' => 'application/vnd.ms-excel', - 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', - 'xlc' => 'application/vnd.ms-excel', - 'xlm' => 'application/vnd.ms-excel', - 'xls' => 'application/vnd.ms-excel', - 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', - 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xlt' => 'application/vnd.ms-excel', - 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', - 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', - 'xlw' => 'application/vnd.ms-excel', - 'xml' => 'application/xml', - 'xo' => 'application/vnd.olpc-sugar', - 'xop' => 'application/xop+xml', - 'xpi' => 'application/x-xpinstall', - 'xpm' => 'image/x-xpixmap', - 'xpr' => 'application/vnd.is-xpr', - 'xps' => 'application/vnd.ms-xpsdocument', - 'xpw' => 'application/vnd.intercon.formnet', - 'xpx' => 'application/vnd.intercon.formnet', - 'xsl' => 'application/xml', - 'xslt' => 'application/xslt+xml', - 'xsm' => 'application/vnd.syncml+xml', - 'xspf' => 'application/xspf+xml', - 'xul' => 'application/vnd.mozilla.xul+xml', - 'xvm' => 'application/xv+xml', - 'xvml' => 'application/xv+xml', - 'xwd' => 'image/x-xwindowdump', - 'xyz' => 'chemical/x-xyz', - 'yaml' => 'text/yaml', - 'yang' => 'application/yang', - 'yin' => 'application/yin+xml', - 'yml' => 'text/yaml', - 'zaz' => 'application/vnd.zzazz.deck+xml', - 'zip' => 'application/zip', - 'zir' => 'application/vnd.zul', - 'zirz' => 'application/vnd.zul', - 'zmm' => 'application/vnd.handheld-entertainment+xml' - ); - - /** - * Get a singleton instance of the class - * - * @return self - * @codeCoverageIgnore - */ - public static function getInstance() - { - if (!self::$instance) { - self::$instance = new self(); - } - - return self::$instance; - } - - /** - * Get a mimetype value from a file extension - * - * @param string $extension File extension - * - * @return string|null - * - */ - public function fromExtension($extension) - { - $extension = strtolower($extension); - - return isset($this->mimetypes[$extension]) - ? $this->mimetypes[$extension] - : null; - } - - /** - * Get a mimetype from a filename - * - * @param string $filename Filename to generate a mimetype from - * - * @return string|null - */ - public function fromFilename($filename) - { - return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION)); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php b/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php deleted file mode 100644 index 1149e62..0000000 --- a/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php +++ /dev/null @@ -1,109 +0,0 @@ -boundary = $boundary ?: uniqid(); - $this->stream = $this->createStream($fields, $files); - } - - /** - * Get the boundary - * - * @return string - */ - public function getBoundary() - { - return $this->boundary; - } - - public function isWritable() - { - return false; - } - - /** - * Get the string needed to transfer a POST field - */ - private function getFieldString($name, $value) - { - return sprintf( - "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", - $this->boundary, - $name, - $value - ); - } - - /** - * Get the headers needed before transferring the content of a POST file - */ - private function getFileHeaders(PostFileInterface $file) - { - $headers = ''; - foreach ($file->getHeaders() as $key => $value) { - $headers .= "{$key}: {$value}\r\n"; - } - - return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n"; - } - - /** - * Create the aggregate stream that will be used to upload the POST data - */ - protected function createStream(array $fields, array $files) - { - $stream = new AppendStream(); - - foreach ($fields as $name => $fieldValues) { - foreach ((array) $fieldValues as $value) { - $stream->addStream( - Stream::factory($this->getFieldString($name, $value)) - ); - } - } - - foreach ($files as $file) { - - if (!$file instanceof PostFileInterface) { - throw new \InvalidArgumentException('All POST fields must ' - . 'implement PostFieldInterface'); - } - - $stream->addStream( - Stream::factory($this->getFileHeaders($file)) - ); - $stream->addStream($file->getContent()); - $stream->addStream(Stream::factory("\r\n")); - } - - // Add the trailing boundary with CRLF - $stream->addStream(Stream::factory("--{$this->boundary}--\r\n")); - - return $stream; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Post/PostBody.php b/vendor/guzzlehttp/guzzle/src/Post/PostBody.php deleted file mode 100644 index ed14d1f..0000000 --- a/vendor/guzzlehttp/guzzle/src/Post/PostBody.php +++ /dev/null @@ -1,287 +0,0 @@ -files || $this->forceMultipart) { - $request->setHeader( - 'Content-Type', - 'multipart/form-data; boundary=' . $this->getBody()->getBoundary() - ); - } elseif ($this->fields && !$request->hasHeader('Content-Type')) { - $request->setHeader( - 'Content-Type', - 'application/x-www-form-urlencoded' - ); - } - - if ($size = $this->getSize()) { - $request->setHeader('Content-Length', $size); - } - } - - public function forceMultipartUpload($force) - { - $this->forceMultipart = $force; - } - - public function setAggregator(callable $aggregator) - { - $this->aggregator = $aggregator; - } - - public function setField($name, $value) - { - $this->fields[$name] = $value; - $this->mutate(); - } - - public function replaceFields(array $fields) - { - $this->fields = $fields; - $this->mutate(); - } - - public function getField($name) - { - return isset($this->fields[$name]) ? $this->fields[$name] : null; - } - - public function removeField($name) - { - unset($this->fields[$name]); - $this->mutate(); - } - - public function getFields($asString = false) - { - if (!$asString) { - return $this->fields; - } - - $query = new Query($this->fields); - $query->setEncodingType(Query::RFC1738); - $query->setAggregator($this->getAggregator()); - - return (string) $query; - } - - public function hasField($name) - { - return isset($this->fields[$name]); - } - - public function getFile($name) - { - foreach ($this->files as $file) { - if ($file->getName() == $name) { - return $file; - } - } - - return null; - } - - public function getFiles() - { - return $this->files; - } - - public function addFile(PostFileInterface $file) - { - $this->files[] = $file; - $this->mutate(); - } - - public function clearFiles() - { - $this->files = []; - $this->mutate(); - } - - /** - * Returns the numbers of fields + files - * - * @return int - */ - public function count() - { - return count($this->files) + count($this->fields); - } - - public function __toString() - { - return (string) $this->getBody(); - } - - public function getContents($maxLength = -1) - { - return $this->getBody()->getContents(); - } - - public function close() - { - $this->detach(); - } - - public function detach() - { - $this->detached = true; - $this->fields = $this->files = []; - - if ($this->body) { - $this->body->close(); - $this->body = null; - } - } - - public function attach($stream) - { - throw new CannotAttachException(); - } - - public function eof() - { - return $this->getBody()->eof(); - } - - public function tell() - { - return $this->body ? $this->body->tell() : 0; - } - - public function isSeekable() - { - return true; - } - - public function isReadable() - { - return true; - } - - public function isWritable() - { - return false; - } - - public function getSize() - { - return $this->getBody()->getSize(); - } - - public function seek($offset, $whence = SEEK_SET) - { - return $this->getBody()->seek($offset, $whence); - } - - public function read($length) - { - return $this->getBody()->read($length); - } - - public function write($string) - { - return false; - } - - public function getMetadata($key = null) - { - return $key ? null : []; - } - - /** - * Return a stream object that is built from the POST fields and files. - * - * If one has already been created, the previously created stream will be - * returned. - */ - private function getBody() - { - if ($this->body) { - return $this->body; - } elseif ($this->files || $this->forceMultipart) { - return $this->body = $this->createMultipart(); - } elseif ($this->fields) { - return $this->body = $this->createUrlEncoded(); - } else { - return $this->body = Stream::factory(); - } - } - - /** - * Get the aggregator used to join multi-valued field parameters - * - * @return callable - */ - final protected function getAggregator() - { - if (!$this->aggregator) { - $this->aggregator = Query::phpAggregator(); - } - - return $this->aggregator; - } - - /** - * Creates a multipart/form-data body stream - * - * @return MultipartBody - */ - private function createMultipart() - { - // Flatten the nested query string values using the correct aggregator - return new MultipartBody( - call_user_func($this->getAggregator(), $this->fields), - $this->files - ); - } - - /** - * Creates an application/x-www-form-urlencoded stream body - * - * @return StreamInterface - */ - private function createUrlEncoded() - { - return Stream::factory($this->getFields(true)); - } - - /** - * Get rid of any cached data - */ - private function mutate() - { - $this->body = null; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php b/vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php deleted file mode 100644 index c2ec9a6..0000000 --- a/vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php +++ /dev/null @@ -1,109 +0,0 @@ -headers = $headers; - $this->name = $name; - $this->prepareContent($content); - $this->prepareFilename($filename); - $this->prepareDefaultHeaders(); - } - - public function getName() - { - return $this->name; - } - - public function getFilename() - { - return $this->filename; - } - - public function getContent() - { - return $this->content; - } - - public function getHeaders() - { - return $this->headers; - } - - /** - * Prepares the contents of a POST file. - * - * @param mixed $content Content of the POST file - */ - private function prepareContent($content) - { - $this->content = $content; - - if (!($this->content instanceof StreamInterface)) { - $this->content = Stream::factory($this->content); - } elseif ($this->content instanceof MultipartBody) { - if (!$this->hasHeader('Content-Disposition')) { - $disposition = 'form-data; name="' . $this->name .'"'; - $this->headers['Content-Disposition'] = $disposition; - } - - if (!$this->hasHeader('Content-Type')) { - $this->headers['Content-Type'] = sprintf( - "multipart/form-data; boundary=%s", - $this->content->getBoundary() - ); - } - } - } - - /** - * Applies a file name to the POST file based on various checks. - * - * @param string|null $filename Filename to apply (or null to guess) - */ - private function prepareFilename($filename) - { - $this->filename = $filename; - - if (!$this->filename) { - $this->filename = $this->content->getMetadata('uri'); - } - - if (!$this->filename || substr($this->filename, 0, 6) === 'php://') { - $this->filename = $this->name; - } - } - - /** - * Applies default Content-Disposition and Content-Type headers if needed. - */ - private function prepareDefaultHeaders() - { - // Set a default content-disposition header if one was no provided - if (!$this->hasHeader('Content-Disposition')) { - $this->headers['Content-Disposition'] = sprintf( - 'form-data; name="%s"; filename="%s"', - $this->name, - basename($this->filename) - ); - } - - // Set a default Content-Type if one was not supplied - if (!$this->hasHeader('Content-Type')) { - $this->headers['Content-Type'] = Mimetypes::getInstance() - ->fromFilename($this->filename) ?: 'text/plain'; - } - } - - /** - * Check if a specific header exists on the POST file by name. - * - * @param string $name Case-insensitive header to check - * - * @return bool - */ - private function hasHeader($name) - { - return isset(array_change_key_case($this->headers)[strtolower($name)]); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php b/vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php deleted file mode 100644 index 2e816c0..0000000 --- a/vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php +++ /dev/null @@ -1,41 +0,0 @@ -setEncodingType($urlEncoding); - } - - $qp->parseInto($q, $query, $urlEncoding); - - return $q; - } - - /** - * Convert the query string parameters to a query string string - * - * @return string - */ - public function __toString() - { - if (!$this->data) { - return ''; - } - - // The default aggregator is statically cached - static $defaultAggregator; - - if (!$this->aggregator) { - if (!$defaultAggregator) { - $defaultAggregator = self::phpAggregator(); - } - $this->aggregator = $defaultAggregator; - } - - $result = ''; - $aggregator = $this->aggregator; - $encoder = $this->encoding; - - foreach ($aggregator($this->data) as $key => $values) { - foreach ($values as $value) { - if ($result) { - $result .= '&'; - } - $result .= $encoder($key); - if ($value !== null) { - $result .= '=' . $encoder($value); - } - } - } - - return $result; - } - - /** - * Controls how multi-valued query string parameters are aggregated into a - * string. - * - * $query->setAggregator($query::duplicateAggregator()); - * - * @param callable $aggregator Callable used to convert a deeply nested - * array of query string variables into a flattened array of key value - * pairs. The callable accepts an array of query data and returns a - * flattened array of key value pairs where each value is an array of - * strings. - */ - public function setAggregator(callable $aggregator) - { - $this->aggregator = $aggregator; - } - - /** - * Specify how values are URL encoded - * - * @param string|bool $type One of 'RFC1738', 'RFC3986', or false to disable encoding - * - * @throws \InvalidArgumentException - */ - public function setEncodingType($type) - { - switch ($type) { - case self::RFC3986: - $this->encoding = 'rawurlencode'; - break; - case self::RFC1738: - $this->encoding = 'urlencode'; - break; - case false: - $this->encoding = function ($v) { return $v; }; - break; - default: - throw new \InvalidArgumentException('Invalid URL encoding type'); - } - } - - /** - * Query string aggregator that does not aggregate nested query string - * values and allows duplicates in the resulting array. - * - * Example: http://test.com?q=1&q=2 - * - * @return callable - */ - public static function duplicateAggregator() - { - return function (array $data) { - return self::walkQuery($data, '', function ($key, $prefix) { - return is_int($key) ? $prefix : "{$prefix}[{$key}]"; - }); - }; - } - - /** - * Aggregates nested query string variables using the same technique as - * ``http_build_query()``. - * - * @param bool $numericIndices Pass false to not include numeric indices - * when multi-values query string parameters are present. - * - * @return callable - */ - public static function phpAggregator($numericIndices = true) - { - return function (array $data) use ($numericIndices) { - return self::walkQuery( - $data, - '', - function ($key, $prefix) use ($numericIndices) { - return !$numericIndices && is_int($key) - ? "{$prefix}[]" - : "{$prefix}[{$key}]"; - } - ); - }; - } - - /** - * Easily create query aggregation functions by providing a key prefix - * function to this query string array walker. - * - * @param array $query Query string to walk - * @param string $keyPrefix Key prefix (start with '') - * @param callable $prefixer Function used to create a key prefix - * - * @return array - */ - public static function walkQuery(array $query, $keyPrefix, callable $prefixer) - { - $result = []; - foreach ($query as $key => $value) { - if ($keyPrefix) { - $key = $prefixer($key, $keyPrefix); - } - if (is_array($value)) { - $result += self::walkQuery($value, $key, $prefixer); - } elseif (isset($result[$key])) { - $result[$key][] = $value; - } else { - $result[$key] = array($value); - } - } - - return $result; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/QueryParser.php b/vendor/guzzlehttp/guzzle/src/QueryParser.php deleted file mode 100644 index 90727cc..0000000 --- a/vendor/guzzlehttp/guzzle/src/QueryParser.php +++ /dev/null @@ -1,163 +0,0 @@ -duplicates = false; - $this->numericIndices = true; - $decoder = self::getDecoder($urlEncoding); - - foreach (explode('&', $str) as $kvp) { - - $parts = explode('=', $kvp, 2); - $key = $decoder($parts[0]); - $value = isset($parts[1]) ? $decoder($parts[1]) : null; - - // Special handling needs to be taken for PHP nested array syntax - if (strpos($key, '[') !== false) { - $this->parsePhpValue($key, $value, $result); - continue; - } - - if (!isset($result[$key])) { - $result[$key] = $value; - } else { - $this->duplicates = true; - if (!is_array($result[$key])) { - $result[$key] = [$result[$key]]; - } - $result[$key][] = $value; - } - } - - $query->replace($result); - - if (!$this->numericIndices) { - $query->setAggregator(Query::phpAggregator(false)); - } elseif ($this->duplicates) { - $query->setAggregator(Query::duplicateAggregator()); - } - } - - /** - * Returns a callable that is used to URL decode query keys and values. - * - * @param string|bool $type One of true, false, RFC3986, and RFC1738 - * - * @return callable|string - */ - private static function getDecoder($type) - { - if ($type === true) { - return function ($value) { - return rawurldecode(str_replace('+', ' ', $value)); - }; - } elseif ($type == Query::RFC3986) { - return 'rawurldecode'; - } elseif ($type == Query::RFC1738) { - return 'urldecode'; - } else { - return function ($str) { return $str; }; - } - } - - /** - * Parses a PHP style key value pair. - * - * @param string $key Key to parse (e.g., "foo[a][b]") - * @param string|null $value Value to set - * @param array $result Result to modify by reference - */ - private function parsePhpValue($key, $value, array &$result) - { - $node =& $result; - $keyBuffer = ''; - - for ($i = 0, $t = strlen($key); $i < $t; $i++) { - switch ($key[$i]) { - case '[': - if ($keyBuffer) { - $this->prepareNode($node, $keyBuffer); - $node =& $node[$keyBuffer]; - $keyBuffer = ''; - } - break; - case ']': - $k = $this->cleanKey($node, $keyBuffer); - $this->prepareNode($node, $k); - $node =& $node[$k]; - $keyBuffer = ''; - break; - default: - $keyBuffer .= $key[$i]; - break; - } - } - - if (isset($node)) { - $this->duplicates = true; - $node[] = $value; - } else { - $node = $value; - } - } - - /** - * Prepares a value in the array at the given key. - * - * If the key already exists, the key value is converted into an array. - * - * @param array $node Result node to modify - * @param string $key Key to add or modify in the node - */ - private function prepareNode(&$node, $key) - { - if (!isset($node[$key])) { - $node[$key] = null; - } elseif (!is_array($node[$key])) { - $node[$key] = [$node[$key]]; - } - } - - /** - * Returns the appropriate key based on the node and key. - */ - private function cleanKey($node, $key) - { - if ($key === '') { - $key = $node ? (string) count($node) : 0; - // Found a [] key, so track this to ensure that we disable numeric - // indexing of keys in the resolved query aggregator. - $this->numericIndices = false; - } - - return $key; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/RequestFsm.php b/vendor/guzzlehttp/guzzle/src/RequestFsm.php deleted file mode 100644 index b37c190..0000000 --- a/vendor/guzzlehttp/guzzle/src/RequestFsm.php +++ /dev/null @@ -1,153 +0,0 @@ -mf = $messageFactory; - $this->maxTransitions = $maxTransitions; - $this->handler = $handler; - } - - /** - * Runs the state machine until a terminal state is entered or the - * optionally supplied $finalState is entered. - * - * @param Transaction $trans Transaction being transitioned. - * - * @throws \Exception if a terminal state throws an exception. - */ - public function __invoke(Transaction $trans) - { - $trans->_transitionCount = 0; - - if (!$trans->state) { - $trans->state = 'before'; - } - - transition: - - if (++$trans->_transitionCount > $this->maxTransitions) { - throw new StateException("Too many state transitions were " - . "encountered ({$trans->_transitionCount}). This likely " - . "means that a combination of event listeners are in an " - . "infinite loop."); - } - - switch ($trans->state) { - case 'before': goto before; - case 'complete': goto complete; - case 'error': goto error; - case 'retry': goto retry; - case 'send': goto send; - case 'end': goto end; - default: throw new StateException("Invalid state: {$trans->state}"); - } - - before: { - try { - $trans->request->getEmitter()->emit('before', new BeforeEvent($trans)); - $trans->state = 'send'; - if ((bool) $trans->response) { - $trans->state = 'complete'; - } - } catch (\Exception $e) { - $trans->state = 'error'; - $trans->exception = $e; - } - goto transition; - } - - complete: { - try { - if ($trans->response instanceof FutureInterface) { - // Futures will have their own end events emitted when - // dereferenced. - return; - } - $trans->state = 'end'; - $trans->response->setEffectiveUrl($trans->request->getUrl()); - $trans->request->getEmitter()->emit('complete', new CompleteEvent($trans)); - } catch (\Exception $e) { - $trans->state = 'error'; - $trans->exception = $e; - } - goto transition; - } - - error: { - try { - // Convert non-request exception to a wrapped exception - $trans->exception = RequestException::wrapException( - $trans->request, $trans->exception - ); - $trans->state = 'end'; - $trans->request->getEmitter()->emit('error', new ErrorEvent($trans)); - // An intercepted request (not retried) transitions to complete - if (!$trans->exception && $trans->state !== 'retry') { - $trans->state = 'complete'; - } - } catch (\Exception $e) { - $trans->state = 'end'; - $trans->exception = $e; - } - goto transition; - } - - retry: { - $trans->retries++; - $trans->response = null; - $trans->exception = null; - $trans->state = 'before'; - goto transition; - } - - send: { - $fn = $this->handler; - $trans->response = FutureResponse::proxy( - $fn(RingBridge::prepareRingRequest($trans)), - function ($value) use ($trans) { - RingBridge::completeRingResponse($trans, $value, $this->mf, $this); - $this($trans); - return $trans->response; - } - ); - return; - } - - end: { - $trans->request->getEmitter()->emit('end', new EndEvent($trans)); - // Throw exceptions in the terminal event if the exception - // was not handled by an "end" event listener. - if ($trans->exception) { - if (!($trans->exception instanceof RequestException)) { - $trans->exception = RequestException::wrapException( - $trans->request, $trans->exception - ); - } - throw $trans->exception; - } - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/RingBridge.php b/vendor/guzzlehttp/guzzle/src/RingBridge.php deleted file mode 100644 index bc6841d..0000000 --- a/vendor/guzzlehttp/guzzle/src/RingBridge.php +++ /dev/null @@ -1,165 +0,0 @@ -getConfig()->toArray(); - $url = $request->getUrl(); - // No need to calculate the query string twice (in URL and query). - $qs = ($pos = strpos($url, '?')) ? substr($url, $pos + 1) : null; - - return [ - 'scheme' => $request->getScheme(), - 'http_method' => $request->getMethod(), - 'url' => $url, - 'uri' => $request->getPath(), - 'headers' => $request->getHeaders(), - 'body' => $request->getBody(), - 'version' => $request->getProtocolVersion(), - 'client' => $options, - 'query_string' => $qs, - 'future' => isset($options['future']) ? $options['future'] : false - ]; - } - - /** - * Creates a Ring request from a request object AND prepares the callbacks. - * - * @param Transaction $trans Transaction to update. - * - * @return array Converted Guzzle Ring request. - */ - public static function prepareRingRequest(Transaction $trans) - { - // Clear out the transaction state when initiating. - $trans->exception = null; - $request = self::createRingRequest($trans->request); - - // Emit progress events if any progress listeners are registered. - if ($trans->request->getEmitter()->hasListeners('progress')) { - $emitter = $trans->request->getEmitter(); - $request['client']['progress'] = function ($a, $b, $c, $d) use ($trans, $emitter) { - $emitter->emit('progress', new ProgressEvent($trans, $a, $b, $c, $d)); - }; - } - - return $request; - } - - /** - * Handles the process of processing a response received from a ring - * handler. The created response is added to the transaction, and the - * transaction stat is set appropriately. - * - * @param Transaction $trans Owns request and response. - * @param array $response Ring response array - * @param MessageFactoryInterface $messageFactory Creates response objects. - */ - public static function completeRingResponse( - Transaction $trans, - array $response, - MessageFactoryInterface $messageFactory - ) { - $trans->state = 'complete'; - $trans->transferInfo = isset($response['transfer_stats']) - ? $response['transfer_stats'] : []; - - if (!empty($response['status'])) { - $options = []; - if (isset($response['version'])) { - $options['protocol_version'] = $response['version']; - } - if (isset($response['reason'])) { - $options['reason_phrase'] = $response['reason']; - } - $trans->response = $messageFactory->createResponse( - $response['status'], - isset($response['headers']) ? $response['headers'] : [], - isset($response['body']) ? $response['body'] : null, - $options - ); - if (isset($response['effective_url'])) { - $trans->response->setEffectiveUrl($response['effective_url']); - } - } elseif (empty($response['error'])) { - // When nothing was returned, then we need to add an error. - $response['error'] = self::getNoRingResponseException($trans->request); - } - - if (isset($response['error'])) { - $trans->state = 'error'; - $trans->exception = $response['error']; - } - } - - /** - * Creates a Guzzle request object using a ring request array. - * - * @param array $request Ring request - * - * @return Request - * @throws \InvalidArgumentException for incomplete requests. - */ - public static function fromRingRequest(array $request) - { - $options = []; - if (isset($request['version'])) { - $options['protocol_version'] = $request['version']; - } - - if (!isset($request['http_method'])) { - throw new \InvalidArgumentException('No http_method'); - } - - return new Request( - $request['http_method'], - Core::url($request), - isset($request['headers']) ? $request['headers'] : [], - isset($request['body']) ? Stream::factory($request['body']) : null, - $options - ); - } - - /** - * Get an exception that can be used when a RingPHP handler does not - * populate a response. - * - * @param RequestInterface $request - * - * @return RequestException - */ - public static function getNoRingResponseException(RequestInterface $request) - { - $message = <<cookieJar = $cookieJar ?: new CookieJar(); - } - - public function getEvents() - { - // Fire the cookie plugin complete event before redirecting - return [ - 'before' => ['onBefore'], - 'complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE + 10] - ]; - } - - /** - * Get the cookie cookieJar - * - * @return CookieJarInterface - */ - public function getCookieJar() - { - return $this->cookieJar; - } - - public function onBefore(BeforeEvent $event) - { - $this->cookieJar->addCookieHeader($event->getRequest()); - } - - public function onComplete(CompleteEvent $event) - { - $this->cookieJar->extractCookies( - $event->getRequest(), - $event->getResponse() - ); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Subscriber/History.php b/vendor/guzzlehttp/guzzle/src/Subscriber/History.php deleted file mode 100644 index 5cf0611..0000000 --- a/vendor/guzzlehttp/guzzle/src/Subscriber/History.php +++ /dev/null @@ -1,172 +0,0 @@ -limit = $limit; - } - - public function getEvents() - { - return [ - 'complete' => ['onComplete', RequestEvents::EARLY], - 'error' => ['onError', RequestEvents::EARLY], - ]; - } - - /** - * Convert to a string that contains all request and response headers - * - * @return string - */ - public function __toString() - { - $lines = array(); - foreach ($this->transactions as $entry) { - $response = isset($entry['response']) ? $entry['response'] : ''; - $lines[] = '> ' . trim($entry['sent_request']) - . "\n\n< " . trim($response) . "\n"; - } - - return implode("\n", $lines); - } - - public function onComplete(CompleteEvent $event) - { - $this->add($event->getRequest(), $event->getResponse()); - } - - public function onError(ErrorEvent $event) - { - // Only track when no response is present, meaning this didn't ever - // emit a complete event - if (!$event->getResponse()) { - $this->add($event->getRequest()); - } - } - - /** - * Returns an Iterator that yields associative array values where each - * associative array contains the following key value pairs: - * - * - request: Representing the actual request that was received. - * - sent_request: A clone of the request that will not be mutated. - * - response: The response that was received (if available). - * - * @return \Iterator - */ - public function getIterator() - { - return new \ArrayIterator($this->transactions); - } - - /** - * Get all of the requests sent through the plugin. - * - * Requests can be modified after they are logged by the history - * subscriber. By default this method will return the actual request - * instances that were received. Pass true to this method if you wish to - * get copies of the requests that represent the request state when it was - * initially logged by the history subscriber. - * - * @param bool $asSent Set to true to get clones of the requests that have - * not been mutated since the request was received by - * the history subscriber. - * - * @return RequestInterface[] - */ - public function getRequests($asSent = false) - { - return array_map(function ($t) use ($asSent) { - return $asSent ? $t['sent_request'] : $t['request']; - }, $this->transactions); - } - - /** - * Get the number of requests in the history - * - * @return int - */ - public function count() - { - return count($this->transactions); - } - - /** - * Get the last request sent. - * - * Requests can be modified after they are logged by the history - * subscriber. By default this method will return the actual request - * instance that was received. Pass true to this method if you wish to get - * a copy of the request that represents the request state when it was - * initially logged by the history subscriber. - * - * @param bool $asSent Set to true to get a clone of the last request that - * has not been mutated since the request was received - * by the history subscriber. - * - * @return RequestInterface - */ - public function getLastRequest($asSent = false) - { - return $asSent - ? end($this->transactions)['sent_request'] - : end($this->transactions)['request']; - } - - /** - * Get the last response in the history - * - * @return ResponseInterface|null - */ - public function getLastResponse() - { - return end($this->transactions)['response']; - } - - /** - * Clears the history - */ - public function clear() - { - $this->transactions = array(); - } - - /** - * Add a request to the history - * - * @param RequestInterface $request Request to add - * @param ResponseInterface $response Response of the request - */ - private function add( - RequestInterface $request, - ResponseInterface $response = null - ) { - $this->transactions[] = [ - 'request' => $request, - 'sent_request' => clone $request, - 'response' => $response - ]; - if (count($this->transactions) > $this->limit) { - array_shift($this->transactions); - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php b/vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php deleted file mode 100644 index ed9de5b..0000000 --- a/vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php +++ /dev/null @@ -1,36 +0,0 @@ - ['onComplete', RequestEvents::VERIFY_RESPONSE]]; - } - - /** - * Throw a RequestException on an HTTP protocol error - * - * @param CompleteEvent $event Emitted event - * @throws RequestException - */ - public function onComplete(CompleteEvent $event) - { - $code = (string) $event->getResponse()->getStatusCode(); - // Throw an exception for an unsuccessful response - if ($code[0] >= 4) { - throw RequestException::create( - $event->getRequest(), - $event->getResponse() - ); - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php b/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php deleted file mode 100644 index 2af4d37..0000000 --- a/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php +++ /dev/null @@ -1,147 +0,0 @@ -factory = new MessageFactory(); - $this->readBodies = $readBodies; - $this->addMultiple($items); - } - - public function getEvents() - { - // Fire the event last, after signing - return ['before' => ['onBefore', RequestEvents::SIGN_REQUEST - 10]]; - } - - /** - * @throws \OutOfBoundsException|\Exception - */ - public function onBefore(BeforeEvent $event) - { - if (!$item = array_shift($this->queue)) { - throw new \OutOfBoundsException('Mock queue is empty'); - } elseif ($item instanceof RequestException) { - throw $item; - } - - // Emulate reading a response body - $request = $event->getRequest(); - if ($this->readBodies && $request->getBody()) { - while (!$request->getBody()->eof()) { - $request->getBody()->read(8096); - } - } - - $saveTo = $event->getRequest()->getConfig()->get('save_to'); - - if (null !== $saveTo) { - $body = $item->getBody(); - - if (is_resource($saveTo)) { - fwrite($saveTo, $body); - } elseif (is_string($saveTo)) { - file_put_contents($saveTo, $body); - } elseif ($saveTo instanceof StreamInterface) { - $saveTo->write($body); - } - } - - $event->intercept($item); - } - - public function count() - { - return count($this->queue); - } - - /** - * Add a response to the end of the queue - * - * @param string|ResponseInterface $response Response or path to response file - * - * @return self - * @throws \InvalidArgumentException if a string or Response is not passed - */ - public function addResponse($response) - { - if (is_string($response)) { - $response = file_exists($response) - ? $this->factory->fromMessage(file_get_contents($response)) - : $this->factory->fromMessage($response); - } elseif (!($response instanceof ResponseInterface)) { - throw new \InvalidArgumentException('Response must a message ' - . 'string, response object, or path to a file'); - } - - $this->queue[] = $response; - - return $this; - } - - /** - * Add an exception to the end of the queue - * - * @param RequestException $e Exception to throw when the request is executed - * - * @return self - */ - public function addException(RequestException $e) - { - $this->queue[] = $e; - - return $this; - } - - /** - * Add multiple items to the queue - * - * @param array $items Items to add - */ - public function addMultiple(array $items) - { - foreach ($items as $item) { - if ($item instanceof RequestException) { - $this->addException($item); - } else { - $this->addResponse($item); - } - } - } - - /** - * Clear the queue - */ - public function clearQueue() - { - $this->queue = []; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php b/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php deleted file mode 100644 index b5ed4e2..0000000 --- a/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php +++ /dev/null @@ -1,130 +0,0 @@ - ['onBefore', RequestEvents::PREPARE_REQUEST]]; - } - - public function onBefore(BeforeEvent $event) - { - $request = $event->getRequest(); - - // Set the appropriate Content-Type for a request if one is not set and - // there are form fields - if (!($body = $request->getBody())) { - return; - } - - $this->addContentLength($request, $body); - - if ($body instanceof AppliesHeadersInterface) { - // Synchronize the body with the request headers - $body->applyRequestHeaders($request); - } elseif (!$request->hasHeader('Content-Type')) { - $this->addContentType($request, $body); - } - - $this->addExpectHeader($request, $body); - } - - private function addContentType( - RequestInterface $request, - StreamInterface $body - ) { - if (!($uri = $body->getMetadata('uri'))) { - return; - } - - // Guess the content-type based on the stream's "uri" metadata value. - // The file extension is used to determine the appropriate mime-type. - if ($contentType = Mimetypes::getInstance()->fromFilename($uri)) { - $request->setHeader('Content-Type', $contentType); - } - } - - private function addContentLength( - RequestInterface $request, - StreamInterface $body - ) { - // Set the Content-Length header if it can be determined, and never - // send a Transfer-Encoding: chunked and Content-Length header in - // the same request. - if ($request->hasHeader('Content-Length')) { - // Remove transfer-encoding if content-length is set. - $request->removeHeader('Transfer-Encoding'); - return; - } - - if ($request->hasHeader('Transfer-Encoding')) { - return; - } - - if (null !== ($size = $body->getSize())) { - $request->setHeader('Content-Length', $size); - $request->removeHeader('Transfer-Encoding'); - } elseif ('1.1' == $request->getProtocolVersion()) { - // Use chunked Transfer-Encoding if there is no determinable - // content-length header and we're using HTTP/1.1. - $request->setHeader('Transfer-Encoding', 'chunked'); - $request->removeHeader('Content-Length'); - } - } - - private function addExpectHeader( - RequestInterface $request, - StreamInterface $body - ) { - // Determine if the Expect header should be used - if ($request->hasHeader('Expect')) { - return; - } - - $expect = $request->getConfig()['expect']; - - // Return if disabled or if you're not using HTTP/1.1 - if ($expect === false || $request->getProtocolVersion() !== '1.1') { - return; - } - - // The expect header is unconditionally enabled - if ($expect === true) { - $request->setHeader('Expect', '100-Continue'); - return; - } - - // By default, send the expect header when the payload is > 1mb - if ($expect === null) { - $expect = 1048576; - } - - // Always add if the body cannot be rewound, the size cannot be - // determined, or the size is greater than the cutoff threshold - $size = $body->getSize(); - if ($size === null || $size >= (int) $expect || !$body->isSeekable()) { - $request->setHeader('Expect', '100-Continue'); - } - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php b/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php deleted file mode 100644 index ff99226..0000000 --- a/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php +++ /dev/null @@ -1,176 +0,0 @@ - ['onComplete', RequestEvents::REDIRECT_RESPONSE]]; - } - - /** - * Rewind the entity body of the request if needed - * - * @param RequestInterface $redirectRequest - * @throws CouldNotRewindStreamException - */ - public static function rewindEntityBody(RequestInterface $redirectRequest) - { - // Rewind the entity body of the request if needed - if ($body = $redirectRequest->getBody()) { - // Only rewind the body if some of it has been read already, and - // throw an exception if the rewind fails - if ($body->tell() && !$body->seek(0)) { - throw new CouldNotRewindStreamException( - 'Unable to rewind the non-seekable request body after redirecting', - $redirectRequest - ); - } - } - } - - /** - * Called when a request receives a redirect response - * - * @param CompleteEvent $event Event emitted - * @throws TooManyRedirectsException - */ - public function onComplete(CompleteEvent $event) - { - $response = $event->getResponse(); - - if (substr($response->getStatusCode(), 0, 1) != '3' - || !$response->hasHeader('Location') - ) { - return; - } - - $request = $event->getRequest(); - $config = $request->getConfig(); - - // Increment the redirect and initialize the redirect state. - if ($redirectCount = $config['redirect_count']) { - $config['redirect_count'] = ++$redirectCount; - } else { - $config['redirect_scheme'] = $request->getScheme(); - $config['redirect_count'] = $redirectCount = 1; - } - - $max = $config->getPath('redirect/max') ?: 5; - - if ($redirectCount > $max) { - throw new TooManyRedirectsException( - "Will not follow more than {$redirectCount} redirects", - $request - ); - } - - $this->modifyRedirectRequest($request, $response); - $event->retry(); - } - - private function modifyRedirectRequest( - RequestInterface $request, - ResponseInterface $response - ) { - $config = $request->getConfig(); - $protocols = $config->getPath('redirect/protocols') ?: ['http', 'https']; - - // Use a GET request if this is an entity enclosing request and we are - // not forcing RFC compliance, but rather emulating what all browsers - // would do. - $statusCode = $response->getStatusCode(); - if ($statusCode == 303 || - ($statusCode <= 302 && $request->getBody() && !$config->getPath('redirect/strict')) - ) { - $request->setMethod('GET'); - $request->setBody(null); - } - - $previousUrl = $request->getUrl(); - $this->setRedirectUrl($request, $response, $protocols); - $this->rewindEntityBody($request); - - // Add the Referer header if it is told to do so and only - // add the header if we are not redirecting from https to http. - if ($config->getPath('redirect/referer') - && ($request->getScheme() == 'https' || $request->getScheme() == $config['redirect_scheme']) - ) { - $url = Url::fromString($previousUrl); - $url->setUsername(null); - $url->setPassword(null); - $request->setHeader('Referer', (string) $url); - } else { - $request->removeHeader('Referer'); - } - } - - /** - * Set the appropriate URL on the request based on the location header - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @param array $protocols - */ - private function setRedirectUrl( - RequestInterface $request, - ResponseInterface $response, - array $protocols - ) { - $location = $response->getHeader('Location'); - $location = Url::fromString($location); - - // Combine location with the original URL if it is not absolute. - if (!$location->isAbsolute()) { - $originalUrl = Url::fromString($request->getUrl()); - // Remove query string parameters and just take what is present on - // the redirect Location header - $originalUrl->getQuery()->clear(); - $location = $originalUrl->combine($location); - } - - // Ensure that the redirect URL is allowed based on the protocols. - if (!in_array($location->getScheme(), $protocols)) { - throw new BadResponseException( - sprintf( - 'Redirect URL, %s, does not use one of the allowed redirect protocols: %s', - $location, - implode(', ', $protocols) - ), - $request, - $response - ); - } - - $request->setUrl($location); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/ToArrayInterface.php b/vendor/guzzlehttp/guzzle/src/ToArrayInterface.php deleted file mode 100644 index d57c022..0000000 --- a/vendor/guzzlehttp/guzzle/src/ToArrayInterface.php +++ /dev/null @@ -1,15 +0,0 @@ -client = $client; - $this->request = $request; - $this->_future = $future; - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Url.php b/vendor/guzzlehttp/guzzle/src/Url.php deleted file mode 100644 index 637f60c..0000000 --- a/vendor/guzzlehttp/guzzle/src/Url.php +++ /dev/null @@ -1,595 +0,0 @@ - 80, 'https' => 443, 'ftp' => 21]; - private static $pathPattern = '/[^a-zA-Z0-9\-\._~!\$&\'\(\)\*\+,;=%:@\/]+|%(?![A-Fa-f0-9]{2})/'; - private static $queryPattern = '/[^a-zA-Z0-9\-\._~!\$\'\(\)\*\+,;%:@\/\?=&]+|%(?![A-Fa-f0-9]{2})/'; - /** @var Query|string Query part of the URL */ - private $query; - - /** - * Factory method to create a new URL from a URL string - * - * @param string $url Full URL used to create a Url object - * - * @return Url - * @throws \InvalidArgumentException - */ - public static function fromString($url) - { - static $defaults = ['scheme' => null, 'host' => null, - 'path' => null, 'port' => null, 'query' => null, - 'user' => null, 'pass' => null, 'fragment' => null]; - - if (false === ($parts = parse_url($url))) { - throw new \InvalidArgumentException('Unable to parse malformed ' - . 'url: ' . $url); - } - - $parts += $defaults; - - // Convert the query string into a Query object - if ($parts['query'] || 0 !== strlen($parts['query'])) { - $parts['query'] = Query::fromString($parts['query']); - } - - return new static($parts['scheme'], $parts['host'], $parts['user'], - $parts['pass'], $parts['port'], $parts['path'], $parts['query'], - $parts['fragment']); - } - - /** - * Build a URL from parse_url parts. The generated URL will be a relative - * URL if a scheme or host are not provided. - * - * @param array $parts Array of parse_url parts - * - * @return string - */ - public static function buildUrl(array $parts) - { - $url = $scheme = ''; - - if (!empty($parts['scheme'])) { - $scheme = $parts['scheme']; - $url .= $scheme . ':'; - } - - if (!empty($parts['host'])) { - $url .= '//'; - if (isset($parts['user'])) { - $url .= $parts['user']; - if (isset($parts['pass'])) { - $url .= ':' . $parts['pass']; - } - $url .= '@'; - } - - $url .= $parts['host']; - - // Only include the port if it is not the default port of the scheme - if (isset($parts['port']) && - (!isset(self::$defaultPorts[$scheme]) || - $parts['port'] != self::$defaultPorts[$scheme]) - ) { - $url .= ':' . $parts['port']; - } - } - - // Add the path component if present - if (isset($parts['path']) && strlen($parts['path'])) { - // Always ensure that the path begins with '/' if set and something - // is before the path - if (!empty($parts['host']) && $parts['path'][0] != '/') { - $url .= '/'; - } - $url .= $parts['path']; - } - - // Add the query string if present - if (isset($parts['query'])) { - $queryStr = (string) $parts['query']; - if ($queryStr || $queryStr === '0') { - $url .= '?' . $queryStr; - } - } - - // Ensure that # is only added to the url if fragment contains anything. - if (isset($parts['fragment'])) { - $url .= '#' . $parts['fragment']; - } - - return $url; - } - - /** - * Create a new URL from URL parts - * - * @param string $scheme Scheme of the URL - * @param string $host Host of the URL - * @param string $username Username of the URL - * @param string $password Password of the URL - * @param int $port Port of the URL - * @param string $path Path of the URL - * @param Query|array|string $query Query string of the URL - * @param string $fragment Fragment of the URL - */ - public function __construct( - $scheme, - $host, - $username = null, - $password = null, - $port = null, - $path = null, - $query = null, - $fragment = null - ) { - $this->scheme = strtolower($scheme); - $this->host = $host; - $this->port = $port; - $this->username = $username; - $this->password = $password; - $this->fragment = $fragment; - - if ($query) { - $this->setQuery($query); - } - - $this->setPath($path); - } - - /** - * Clone the URL - */ - public function __clone() - { - if ($this->query instanceof Query) { - $this->query = clone $this->query; - } - } - - /** - * Returns the URL as a URL string - * - * @return string - */ - public function __toString() - { - return static::buildUrl($this->getParts()); - } - - /** - * Get the parts of the URL as an array - * - * @return array - */ - public function getParts() - { - return array( - 'scheme' => $this->scheme, - 'user' => $this->username, - 'pass' => $this->password, - 'host' => $this->host, - 'port' => $this->port, - 'path' => $this->path, - 'query' => $this->query, - 'fragment' => $this->fragment, - ); - } - - /** - * Set the host of the request. - * - * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com) - * - * @return Url - */ - public function setHost($host) - { - if (strpos($host, ':') === false) { - $this->host = $host; - } else { - list($host, $port) = explode(':', $host); - $this->host = $host; - $this->setPort($port); - } - } - - /** - * Get the host part of the URL - * - * @return string - */ - public function getHost() - { - return $this->host; - } - - /** - * Set the scheme part of the URL (http, https, ftp, etc.) - * - * @param string $scheme Scheme to set - */ - public function setScheme($scheme) - { - // Remove the default port if one is specified - if ($this->port - && isset(self::$defaultPorts[$this->scheme]) - && self::$defaultPorts[$this->scheme] == $this->port - ) { - $this->port = null; - } - - $this->scheme = strtolower($scheme); - } - - /** - * Get the scheme part of the URL - * - * @return string - */ - public function getScheme() - { - return $this->scheme; - } - - /** - * Set the port part of the URL - * - * @param int $port Port to set - */ - public function setPort($port) - { - $this->port = $port; - } - - /** - * Get the port part of the URl. - * - * If no port was set, this method will return the default port for the - * scheme of the URI. - * - * @return int|null - */ - public function getPort() - { - if ($this->port) { - return $this->port; - } elseif (isset(self::$defaultPorts[$this->scheme])) { - return self::$defaultPorts[$this->scheme]; - } - - return null; - } - - /** - * Set the path part of the URL. - * - * The provided URL is URL encoded as necessary. - * - * @param string $path Path string to set - */ - public function setPath($path) - { - $this->path = self::encodePath($path); - } - - /** - * Removes dot segments from a URL - * @link http://tools.ietf.org/html/rfc3986#section-5.2.4 - */ - public function removeDotSegments() - { - static $noopPaths = ['' => true, '/' => true, '*' => true]; - static $ignoreSegments = ['.' => true, '..' => true]; - - if (isset($noopPaths[$this->path])) { - return; - } - - $results = []; - $segments = $this->getPathSegments(); - foreach ($segments as $segment) { - if ($segment == '..') { - array_pop($results); - } elseif (!isset($ignoreSegments[$segment])) { - $results[] = $segment; - } - } - - $newPath = implode('/', $results); - - // Add the leading slash if necessary - if (substr($this->path, 0, 1) === '/' && - substr($newPath, 0, 1) !== '/' - ) { - $newPath = '/' . $newPath; - } - - // Add the trailing slash if necessary - if ($newPath != '/' && isset($ignoreSegments[end($segments)])) { - $newPath .= '/'; - } - - $this->path = $newPath; - } - - /** - * Add a relative path to the currently set path. - * - * @param string $relativePath Relative path to add - */ - public function addPath($relativePath) - { - if ($relativePath != '/' && - is_string($relativePath) && - strlen($relativePath) > 0 - ) { - // Add a leading slash if needed - if ($relativePath[0] !== '/' && - substr($this->path, -1, 1) !== '/' - ) { - $relativePath = '/' . $relativePath; - } - - $this->setPath($this->path . $relativePath); - } - } - - /** - * Get the path part of the URL - * - * @return string - */ - public function getPath() - { - return $this->path; - } - - /** - * Get the path segments of the URL as an array - * - * @return array - */ - public function getPathSegments() - { - return explode('/', $this->path); - } - - /** - * Set the password part of the URL - * - * @param string $password Password to set - */ - public function setPassword($password) - { - $this->password = $password; - } - - /** - * Get the password part of the URL - * - * @return null|string - */ - public function getPassword() - { - return $this->password; - } - - /** - * Set the username part of the URL - * - * @param string $username Username to set - */ - public function setUsername($username) - { - $this->username = $username; - } - - /** - * Get the username part of the URl - * - * @return null|string - */ - public function getUsername() - { - return $this->username; - } - - /** - * Get the query part of the URL as a Query object - * - * @return Query - */ - public function getQuery() - { - // Convert the query string to a query object if not already done. - if (!$this->query instanceof Query) { - $this->query = $this->query === null - ? new Query() - : Query::fromString($this->query); - } - - return $this->query; - } - - /** - * Set the query part of the URL. - * - * You may provide a query string as a string and pass $rawString as true - * to provide a query string that is not parsed until a call to getQuery() - * is made. Setting a raw query string will still encode invalid characters - * in a query string. - * - * @param Query|string|array $query Query string value to set. Can - * be a string that will be parsed into a Query object, an array - * of key value pairs, or a Query object. - * @param bool $rawString Set to true when providing a raw query string. - * - * @throws \InvalidArgumentException - */ - public function setQuery($query, $rawString = false) - { - if ($query instanceof Query) { - $this->query = $query; - } elseif (is_string($query)) { - if (!$rawString) { - $this->query = Query::fromString($query); - } else { - // Ensure the query does not have illegal characters. - $this->query = preg_replace_callback( - self::$queryPattern, - [__CLASS__, 'encodeMatch'], - $query - ); - } - - } elseif (is_array($query)) { - $this->query = new Query($query); - } else { - throw new \InvalidArgumentException('Query must be a Query, ' - . 'array, or string. Got ' . Core::describeType($query)); - } - } - - /** - * Get the fragment part of the URL - * - * @return null|string - */ - public function getFragment() - { - return $this->fragment; - } - - /** - * Set the fragment part of the URL - * - * @param string $fragment Fragment to set - */ - public function setFragment($fragment) - { - $this->fragment = $fragment; - } - - /** - * Check if this is an absolute URL - * - * @return bool - */ - public function isAbsolute() - { - return $this->scheme && $this->host; - } - - /** - * Combine the URL with another URL and return a new URL instance. - * - * Follows the rules specific in RFC 3986 section 5.4. - * - * @param string $url Relative URL to combine with - * - * @return Url - * @throws \InvalidArgumentException - * @link http://tools.ietf.org/html/rfc3986#section-5.4 - */ - public function combine($url) - { - $url = static::fromString($url); - - // Use the more absolute URL as the base URL - if (!$this->isAbsolute() && $url->isAbsolute()) { - $url = $url->combine($this); - } - - $parts = $url->getParts(); - - // Passing a URL with a scheme overrides everything - if ($parts['scheme']) { - return clone $url; - } - - // Setting a host overrides the entire rest of the URL - if ($parts['host']) { - return new static( - $this->scheme, - $parts['host'], - $parts['user'], - $parts['pass'], - $parts['port'], - $parts['path'], - $parts['query'] instanceof Query - ? clone $parts['query'] - : $parts['query'], - $parts['fragment'] - ); - } - - if (!$parts['path'] && $parts['path'] !== '0') { - // The relative URL has no path, so check if it is just a query - $path = $this->path ?: ''; - $query = $parts['query'] ?: $this->query; - } else { - $query = $parts['query']; - if ($parts['path'][0] == '/' || !$this->path) { - // Overwrite the existing path if the rel path starts with "/" - $path = $parts['path']; - } else { - // If the relative URL does not have a path or the base URL - // path does not end in a "/" then overwrite the existing path - // up to the last "/" - $path = substr($this->path, 0, strrpos($this->path, '/') + 1) . $parts['path']; - } - } - - $result = new self( - $this->scheme, - $this->host, - $this->username, - $this->password, - $this->port, - $path, - $query instanceof Query ? clone $query : $query, - $parts['fragment'] - ); - - if ($path) { - $result->removeDotSegments(); - } - - return $result; - } - - /** - * Encodes the path part of a URL without double-encoding percent-encoded - * key value pairs. - * - * @param string $path Path to encode - * - * @return string - */ - public static function encodePath($path) - { - static $cb = [__CLASS__, 'encodeMatch']; - return preg_replace_callback(self::$pathPattern, $cb, $path); - } - - private static function encodeMatch(array $match) - { - return rawurlencode($match[0]); - } -} diff --git a/vendor/guzzlehttp/guzzle/src/Utils.php b/vendor/guzzlehttp/guzzle/src/Utils.php deleted file mode 100644 index 1754719..0000000 --- a/vendor/guzzlehttp/guzzle/src/Utils.php +++ /dev/null @@ -1,215 +0,0 @@ -expand($template, $variables); - } - - /** - * Wrapper for JSON decode that implements error detection with helpful - * error messages. - * - * @param string $json JSON data to parse - * @param bool $assoc When true, returned objects will be converted - * into associative arrays. - * @param int $depth User specified recursion depth. - * @param int $options Bitmask of JSON decode options. - * - * @return mixed - * @throws \InvalidArgumentException if the JSON cannot be parsed. - * @link http://www.php.net/manual/en/function.json-decode.php - */ - public static function jsonDecode($json, $assoc = false, $depth = 512, $options = 0) - { - if ($json === '' || $json === null) { - return null; - } - - static $jsonErrors = [ - JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded', - JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch', - JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found', - JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON', - JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded' - ]; - - $data = \json_decode($json, $assoc, $depth, $options); - - if (JSON_ERROR_NONE !== json_last_error()) { - $last = json_last_error(); - throw new \InvalidArgumentException( - 'Unable to parse JSON data: ' - . (isset($jsonErrors[$last]) - ? $jsonErrors[$last] - : 'Unknown error') - ); - } - - return $data; - } - - /** - * Get the default User-Agent string to use with Guzzle - * - * @return string - */ - public static function getDefaultUserAgent() - { - static $defaultAgent = ''; - if (!$defaultAgent) { - $defaultAgent = 'Guzzle/' . ClientInterface::VERSION; - if (extension_loaded('curl')) { - $defaultAgent .= ' curl/' . curl_version()['version']; - } - $defaultAgent .= ' PHP/' . PHP_VERSION; - } - - return $defaultAgent; - } - - /** - * Create a default handler to use based on the environment - * - * @throws \RuntimeException if no viable Handler is available. - */ - public static function getDefaultHandler() - { - $default = $future = null; - - if (extension_loaded('curl')) { - $config = [ - 'select_timeout' => getenv('GUZZLE_CURL_SELECT_TIMEOUT') ?: 1 - ]; - if ($maxHandles = getenv('GUZZLE_CURL_MAX_HANDLES')) { - $config['max_handles'] = $maxHandles; - } - if (function_exists('curl_reset')) { - $default = new CurlHandler(); - $future = new CurlMultiHandler($config); - } else { - $default = new CurlMultiHandler($config); - } - } - - if (ini_get('allow_url_fopen')) { - $default = !$default - ? new StreamHandler() - : Middleware::wrapStreaming($default, new StreamHandler()); - } elseif (!$default) { - throw new \RuntimeException('Guzzle requires cURL, the ' - . 'allow_url_fopen ini setting, or a custom HTTP handler.'); - } - - return $future ? Middleware::wrapFuture($default, $future) : $default; - } -} diff --git a/vendor/guzzlehttp/ringphp/.editorconfig b/vendor/guzzlehttp/ringphp/.editorconfig deleted file mode 100644 index 70dabca..0000000 --- a/vendor/guzzlehttp/ringphp/.editorconfig +++ /dev/null @@ -1,12 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_size = 4 -indent_style = space -insert_final_newline = true -trim_trailing_whitespace = true - -[{Makefile,*.mk}] -indent_style = tab diff --git a/vendor/guzzlehttp/ringphp/LICENSE b/vendor/guzzlehttp/ringphp/LICENSE deleted file mode 100644 index 71d3b78..0000000 --- a/vendor/guzzlehttp/ringphp/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling - -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. diff --git a/vendor/guzzlehttp/ringphp/composer.json b/vendor/guzzlehttp/ringphp/composer.json deleted file mode 100644 index 8df60ec..0000000 --- a/vendor/guzzlehttp/ringphp/composer.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "guzzlehttp/ringphp", - "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", - "license": "MIT", - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "require": { - "php": ">=5.4.0", - "guzzlehttp/streams": "~3.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" - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Ring\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "GuzzleHttp\\Tests\\Ring\\": "tests/" - } - }, - "scripts": { - "test": "make test", - "test-ci": "make coverage" - }, - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Client/ClientUtils.php b/vendor/guzzlehttp/ringphp/src/Client/ClientUtils.php deleted file mode 100644 index 27d5fe7..0000000 --- a/vendor/guzzlehttp/ringphp/src/Client/ClientUtils.php +++ /dev/null @@ -1,74 +0,0 @@ -getDefaultOptions($request, $headers); - $this->applyMethod($request, $options); - - if (isset($request['client'])) { - $this->applyHandlerOptions($request, $options); - } - - $this->applyHeaders($request, $options); - unset($options['_headers']); - - // Add handler options from the request's configuration options - if (isset($request['client']['curl'])) { - $options = $this->applyCustomCurlOptions( - $request['client']['curl'], - $options - ); - } - - if (!$handle) { - $handle = curl_init(); - } - - $body = $this->getOutputBody($request, $options); - curl_setopt_array($handle, $options); - - return [$handle, &$headers, $body]; - } - - /** - * Creates a response hash from a cURL result. - * - * @param callable $handler Handler that was used. - * @param array $request Request that sent. - * @param array $response Response hash to update. - * @param array $headers Headers received during transfer. - * @param resource $body Body fopen response. - * - * @return array - */ - public static function createResponse( - callable $handler, - array $request, - array $response, - array $headers, - $body - ) { - if (isset($response['transfer_stats']['url'])) { - $response['effective_url'] = $response['transfer_stats']['url']; - } - - if (!empty($headers)) { - $startLine = explode(' ', array_shift($headers), 3); - $headerList = Core::headersFromLines($headers); - $response['headers'] = $headerList; - $response['version'] = isset($startLine[0]) ? substr($startLine[0], 5) : null; - $response['status'] = isset($startLine[1]) ? (int) $startLine[1] : null; - $response['reason'] = isset($startLine[2]) ? $startLine[2] : null; - $response['body'] = $body; - Core::rewindBody($response); - } - - return !empty($response['curl']['errno']) || !isset($response['status']) - ? self::createErrorResponse($handler, $request, $response) - : $response; - } - - private static function createErrorResponse( - callable $handler, - array $request, - array $response - ) { - static $connectionErrors = [ - CURLE_OPERATION_TIMEOUTED => true, - CURLE_COULDNT_RESOLVE_HOST => true, - CURLE_COULDNT_CONNECT => true, - CURLE_SSL_CONNECT_ERROR => true, - CURLE_GOT_NOTHING => true, - ]; - - // Retry when nothing is present or when curl failed to rewind. - if (!isset($response['err_message']) - && (empty($response['curl']['errno']) - || $response['curl']['errno'] == 65) - ) { - return self::retryFailedRewind($handler, $request, $response); - } - - $message = isset($response['err_message']) - ? $response['err_message'] - : sprintf('cURL error %s: %s', - $response['curl']['errno'], - isset($response['curl']['error']) - ? $response['curl']['error'] - : 'See http://curl.haxx.se/libcurl/c/libcurl-errors.html'); - - $error = isset($response['curl']['errno']) - && isset($connectionErrors[$response['curl']['errno']]) - ? new ConnectException($message) - : new RingException($message); - - return $response + [ - 'status' => null, - 'reason' => null, - 'body' => null, - 'headers' => [], - 'error' => $error, - ]; - } - - private function getOutputBody(array $request, array &$options) - { - // Determine where the body of the response (if any) will be streamed. - if (isset($options[CURLOPT_WRITEFUNCTION])) { - return $request['client']['save_to']; - } - - if (isset($options[CURLOPT_FILE])) { - return $options[CURLOPT_FILE]; - } - - if ($request['http_method'] != 'HEAD') { - // Create a default body if one was not provided - return $options[CURLOPT_FILE] = fopen('php://temp', 'w+'); - } - - return null; - } - - private function getDefaultOptions(array $request, array &$headers) - { - $url = Core::url($request); - $startingResponse = false; - - $options = [ - '_headers' => $request['headers'], - CURLOPT_CUSTOMREQUEST => $request['http_method'], - CURLOPT_URL => $url, - CURLOPT_RETURNTRANSFER => false, - CURLOPT_HEADER => false, - CURLOPT_CONNECTTIMEOUT => 150, - CURLOPT_HEADERFUNCTION => function ($ch, $h) use (&$headers, &$startingResponse) { - $value = trim($h); - if ($value === '') { - $startingResponse = true; - } elseif ($startingResponse) { - $startingResponse = false; - $headers = [$value]; - } else { - $headers[] = $value; - } - return strlen($h); - }, - ]; - - if (isset($request['version'])) { - if ($request['version'] == 2.0) { - $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0; - } else if ($request['version'] == 1.1) { - $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1; - } else { - $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0; - } - } - - if (defined('CURLOPT_PROTOCOLS')) { - $options[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; - } - - return $options; - } - - private function applyMethod(array $request, array &$options) - { - if (isset($request['body'])) { - $this->applyBody($request, $options); - return; - } - - switch ($request['http_method']) { - case 'PUT': - case 'POST': - // See http://tools.ietf.org/html/rfc7230#section-3.3.2 - if (!Core::hasHeader($request, 'Content-Length')) { - $options[CURLOPT_HTTPHEADER][] = 'Content-Length: 0'; - } - break; - case 'HEAD': - $options[CURLOPT_NOBODY] = true; - unset( - $options[CURLOPT_WRITEFUNCTION], - $options[CURLOPT_READFUNCTION], - $options[CURLOPT_FILE], - $options[CURLOPT_INFILE] - ); - } - } - - private function applyBody(array $request, array &$options) - { - $contentLength = Core::firstHeader($request, 'Content-Length'); - $size = $contentLength !== null ? (int) $contentLength : null; - - // Send the body as a string if the size is less than 1MB OR if the - // [client][curl][body_as_string] request value is set. - if (($size !== null && $size < 1000000) || - isset($request['client']['curl']['body_as_string']) || - is_string($request['body']) - ) { - $options[CURLOPT_POSTFIELDS] = Core::body($request); - // Don't duplicate the Content-Length header - $this->removeHeader('Content-Length', $options); - $this->removeHeader('Transfer-Encoding', $options); - } else { - $options[CURLOPT_UPLOAD] = true; - if ($size !== null) { - // Let cURL handle setting the Content-Length header - $options[CURLOPT_INFILESIZE] = $size; - $this->removeHeader('Content-Length', $options); - } - $this->addStreamingBody($request, $options); - } - - // If the Expect header is not present, prevent curl from adding it - if (!Core::hasHeader($request, 'Expect')) { - $options[CURLOPT_HTTPHEADER][] = 'Expect:'; - } - - // cURL sometimes adds a content-type by default. Prevent this. - if (!Core::hasHeader($request, 'Content-Type')) { - $options[CURLOPT_HTTPHEADER][] = 'Content-Type:'; - } - } - - private function addStreamingBody(array $request, array &$options) - { - $body = $request['body']; - - if ($body instanceof StreamInterface) { - $options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) { - return (string) $body->read($length); - }; - if (!isset($options[CURLOPT_INFILESIZE])) { - if ($size = $body->getSize()) { - $options[CURLOPT_INFILESIZE] = $size; - } - } - } elseif (is_resource($body)) { - $options[CURLOPT_INFILE] = $body; - } elseif ($body instanceof \Iterator) { - $buf = ''; - $options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body, &$buf) { - if ($body->valid()) { - $buf .= $body->current(); - $body->next(); - } - $result = (string) substr($buf, 0, $length); - $buf = substr($buf, $length); - return $result; - }; - } else { - throw new \InvalidArgumentException('Invalid request body provided'); - } - } - - private function applyHeaders(array $request, array &$options) - { - foreach ($options['_headers'] as $name => $values) { - foreach ($values as $value) { - $options[CURLOPT_HTTPHEADER][] = "$name: $value"; - } - } - - // Remove the Accept header if one was not set - if (!Core::hasHeader($request, 'Accept')) { - $options[CURLOPT_HTTPHEADER][] = 'Accept:'; - } - } - - /** - * Takes an array of curl options specified in the 'curl' option of a - * request's configuration array and maps them to CURLOPT_* options. - * - * This method is only called when a request has a 'curl' config setting. - * - * @param array $config Configuration array of custom curl option - * @param array $options Array of existing curl options - * - * @return array Returns a new array of curl options - */ - private function applyCustomCurlOptions(array $config, array $options) - { - $curlOptions = []; - foreach ($config as $key => $value) { - if (is_int($key)) { - $curlOptions[$key] = $value; - } - } - - return $curlOptions + $options; - } - - /** - * Remove a header from the options array. - * - * @param string $name Case-insensitive header to remove - * @param array $options Array of options to modify - */ - private function removeHeader($name, array &$options) - { - foreach (array_keys($options['_headers']) as $key) { - if (!strcasecmp($key, $name)) { - unset($options['_headers'][$key]); - return; - } - } - } - - /** - * Applies an array of request client options to a the options array. - * - * This method uses a large switch rather than double-dispatch to save on - * high overhead of calling functions in PHP. - */ - private function applyHandlerOptions(array $request, array &$options) - { - foreach ($request['client'] as $key => $value) { - switch ($key) { - // Violating PSR-4 to provide more room. - case 'verify': - - if ($value === false) { - unset($options[CURLOPT_CAINFO]); - $options[CURLOPT_SSL_VERIFYHOST] = 0; - $options[CURLOPT_SSL_VERIFYPEER] = false; - continue 2; - } - - $options[CURLOPT_SSL_VERIFYHOST] = 2; - $options[CURLOPT_SSL_VERIFYPEER] = true; - - if (is_string($value)) { - $options[CURLOPT_CAINFO] = $value; - if (!file_exists($value)) { - throw new \InvalidArgumentException( - "SSL CA bundle not found: $value" - ); - } - } - break; - - case 'decode_content': - - if ($value === false) { - continue 2; - } - - $accept = Core::firstHeader($request, 'Accept-Encoding'); - if ($accept) { - $options[CURLOPT_ENCODING] = $accept; - } else { - $options[CURLOPT_ENCODING] = ''; - // Don't let curl send the header over the wire - $options[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:'; - } - break; - - case 'save_to': - - if (is_string($value)) { - if (!is_dir(dirname($value))) { - throw new \RuntimeException(sprintf( - 'Directory %s does not exist for save_to value of %s', - dirname($value), - $value - )); - } - $value = new LazyOpenStream($value, 'w+'); - } - - if ($value instanceof StreamInterface) { - $options[CURLOPT_WRITEFUNCTION] = - function ($ch, $write) use ($value) { - return $value->write($write); - }; - } elseif (is_resource($value)) { - $options[CURLOPT_FILE] = $value; - } else { - throw new \InvalidArgumentException('save_to must be a ' - . 'GuzzleHttp\Stream\StreamInterface or resource'); - } - break; - - case 'timeout': - - if (defined('CURLOPT_TIMEOUT_MS')) { - $options[CURLOPT_TIMEOUT_MS] = $value * 1000; - } else { - $options[CURLOPT_TIMEOUT] = $value; - } - break; - - case 'connect_timeout': - - if (defined('CURLOPT_CONNECTTIMEOUT_MS')) { - $options[CURLOPT_CONNECTTIMEOUT_MS] = $value * 1000; - } else { - $options[CURLOPT_CONNECTTIMEOUT] = $value; - } - break; - - case 'proxy': - - if (!is_array($value)) { - $options[CURLOPT_PROXY] = $value; - } elseif (isset($request['scheme'])) { - $scheme = $request['scheme']; - if (isset($value[$scheme])) { - $options[CURLOPT_PROXY] = $value[$scheme]; - } - } - break; - - case 'cert': - - if (is_array($value)) { - $options[CURLOPT_SSLCERTPASSWD] = $value[1]; - $value = $value[0]; - } - - if (!file_exists($value)) { - throw new \InvalidArgumentException( - "SSL certificate not found: {$value}" - ); - } - - $options[CURLOPT_SSLCERT] = $value; - break; - - case 'ssl_key': - - if (is_array($value)) { - $options[CURLOPT_SSLKEYPASSWD] = $value[1]; - $value = $value[0]; - } - - if (!file_exists($value)) { - throw new \InvalidArgumentException( - "SSL private key not found: {$value}" - ); - } - - $options[CURLOPT_SSLKEY] = $value; - break; - - case 'progress': - - if (!is_callable($value)) { - throw new \InvalidArgumentException( - 'progress client option must be callable' - ); - } - - $options[CURLOPT_NOPROGRESS] = false; - $options[CURLOPT_PROGRESSFUNCTION] = - function () use ($value) { - $args = func_get_args(); - // PHP 5.5 pushed the handle onto the start of the args - if (is_resource($args[0])) { - array_shift($args); - } - call_user_func_array($value, $args); - }; - break; - - case 'debug': - - if ($value) { - $options[CURLOPT_STDERR] = Core::getDebugResource($value); - $options[CURLOPT_VERBOSE] = true; - } - break; - } - } - } - - /** - * This function ensures that a response was set on a transaction. If one - * was not set, then the request is retried if possible. This error - * typically means you are sending a payload, curl encountered a - * "Connection died, retrying a fresh connect" error, tried to rewind the - * stream, and then encountered a "necessary data rewind wasn't possible" - * error, causing the request to be sent through curl_multi_info_read() - * without an error status. - */ - private static function retryFailedRewind( - callable $handler, - array $request, - array $response - ) { - // If there is no body, then there is some other kind of issue. This - // is weird and should probably never happen. - if (!isset($request['body'])) { - $response['err_message'] = 'No response was received for a request ' - . 'with no body. This could mean that you are saturating your ' - . 'network.'; - return self::createErrorResponse($handler, $request, $response); - } - - if (!Core::rewindBody($request)) { - $response['err_message'] = 'The connection unexpectedly failed ' - . 'without providing an error. The request would have been ' - . 'retried, but attempting to rewind the request body failed.'; - return self::createErrorResponse($handler, $request, $response); - } - - // Retry no more than 3 times before giving up. - if (!isset($request['curl']['retries'])) { - $request['curl']['retries'] = 1; - } elseif ($request['curl']['retries'] == 2) { - $response['err_message'] = 'The cURL request was retried 3 times ' - . 'and did no succeed. cURL was unable to rewind the body of ' - . 'the request and subsequent retries resulted in the same ' - . 'error. Turn on the debug option to see what went wrong. ' - . 'See https://bugs.php.net/bug.php?id=47204 for more information.'; - return self::createErrorResponse($handler, $request, $response); - } else { - $request['curl']['retries']++; - } - - return $handler($request); - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Client/CurlHandler.php b/vendor/guzzlehttp/ringphp/src/Client/CurlHandler.php deleted file mode 100644 index e00aa4e..0000000 --- a/vendor/guzzlehttp/ringphp/src/Client/CurlHandler.php +++ /dev/null @@ -1,135 +0,0 @@ -handles = $this->ownedHandles = []; - $this->factory = isset($options['handle_factory']) - ? $options['handle_factory'] - : new CurlFactory(); - $this->maxHandles = isset($options['max_handles']) - ? $options['max_handles'] - : 5; - } - - public function __destruct() - { - foreach ($this->handles as $handle) { - if (is_resource($handle)) { - curl_close($handle); - } - } - } - - /** - * @param array $request - * - * @return CompletedFutureArray - */ - public function __invoke(array $request) - { - return new CompletedFutureArray( - $this->_invokeAsArray($request) - ); - } - - /** - * @internal - * - * @param array $request - * - * @return array - */ - public function _invokeAsArray(array $request) - { - $factory = $this->factory; - - // Ensure headers are by reference. They're updated elsewhere. - $result = $factory($request, $this->checkoutEasyHandle()); - $h = $result[0]; - $hd =& $result[1]; - $bd = $result[2]; - Core::doSleep($request); - curl_exec($h); - $response = ['transfer_stats' => curl_getinfo($h)]; - $response['curl']['error'] = curl_error($h); - $response['curl']['errno'] = curl_errno($h); - $response['transfer_stats'] = array_merge($response['transfer_stats'], $response['curl']); - $this->releaseEasyHandle($h); - - return CurlFactory::createResponse([$this, '_invokeAsArray'], $request, $response, $hd, $bd); - } - - private function checkoutEasyHandle() - { - // Find an unused handle in the cache - if (false !== ($key = array_search(false, $this->ownedHandles, true))) { - $this->ownedHandles[$key] = true; - return $this->handles[$key]; - } - - // Add a new handle - $handle = curl_init(); - $id = (int) $handle; - $this->handles[$id] = $handle; - $this->ownedHandles[$id] = true; - - return $handle; - } - - private function releaseEasyHandle($handle) - { - $id = (int) $handle; - if (count($this->ownedHandles) > $this->maxHandles) { - curl_close($this->handles[$id]); - unset($this->handles[$id], $this->ownedHandles[$id]); - } else { - // curl_reset doesn't clear these out for some reason - static $unsetValues = [ - CURLOPT_HEADERFUNCTION => null, - CURLOPT_WRITEFUNCTION => null, - CURLOPT_READFUNCTION => null, - CURLOPT_PROGRESSFUNCTION => null, - ]; - curl_setopt_array($handle, $unsetValues); - curl_reset($handle); - $this->ownedHandles[$id] = false; - } - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Client/CurlMultiHandler.php b/vendor/guzzlehttp/ringphp/src/Client/CurlMultiHandler.php deleted file mode 100644 index f84cf19..0000000 --- a/vendor/guzzlehttp/ringphp/src/Client/CurlMultiHandler.php +++ /dev/null @@ -1,248 +0,0 @@ -_mh = $options['mh']; - } - $this->factory = isset($options['handle_factory']) - ? $options['handle_factory'] : new CurlFactory(); - $this->selectTimeout = isset($options['select_timeout']) - ? $options['select_timeout'] : 1; - $this->maxHandles = isset($options['max_handles']) - ? $options['max_handles'] : 100; - } - - public function __get($name) - { - if ($name === '_mh') { - return $this->_mh = curl_multi_init(); - } - - throw new \BadMethodCallException(); - } - - public function __destruct() - { - // Finish any open connections before terminating the script. - if ($this->handles) { - $this->execute(); - } - - if (isset($this->_mh)) { - curl_multi_close($this->_mh); - unset($this->_mh); - } - } - - public function __invoke(array $request) - { - $factory = $this->factory; - $result = $factory($request); - $entry = [ - 'request' => $request, - 'response' => [], - 'handle' => $result[0], - 'headers' => &$result[1], - 'body' => $result[2], - 'deferred' => new Deferred(), - ]; - - $id = (int) $result[0]; - - $future = new FutureArray( - $entry['deferred']->promise(), - [$this, 'execute'], - function () use ($id) { - return $this->cancel($id); - } - ); - - $this->addRequest($entry); - - // Transfer outstanding requests if there are too many open handles. - if (count($this->handles) >= $this->maxHandles) { - $this->execute(); - } - - return $future; - } - - /** - * Runs until all outstanding connections have completed. - */ - public function execute() - { - do { - - if ($this->active && - curl_multi_select($this->_mh, $this->selectTimeout) === -1 - ) { - // Perform a usleep if a select returns -1. - // See: https://bugs.php.net/bug.php?id=61141 - usleep(250); - } - - // Add any delayed futures if needed. - if ($this->delays) { - $this->addDelays(); - } - - do { - $mrc = curl_multi_exec($this->_mh, $this->active); - } while ($mrc === CURLM_CALL_MULTI_PERFORM); - - $this->processMessages(); - - // If there are delays but no transfers, then sleep for a bit. - if (!$this->active && $this->delays) { - usleep(500); - } - - } while ($this->active || $this->handles); - } - - private function addRequest(array &$entry) - { - $id = (int) $entry['handle']; - $this->handles[$id] = $entry; - - // If the request is a delay, then add the reques to the curl multi - // pool only after the specified delay. - if (isset($entry['request']['client']['delay'])) { - $this->delays[$id] = microtime(true) + ($entry['request']['client']['delay'] / 1000); - } elseif (empty($entry['request']['future'])) { - curl_multi_add_handle($this->_mh, $entry['handle']); - } else { - curl_multi_add_handle($this->_mh, $entry['handle']); - // "lazy" futures are only sent once the pool has many requests. - if ($entry['request']['future'] !== 'lazy') { - do { - $mrc = curl_multi_exec($this->_mh, $this->active); - } while ($mrc === CURLM_CALL_MULTI_PERFORM); - $this->processMessages(); - } - } - } - - private function removeProcessed($id) - { - if (isset($this->handles[$id])) { - curl_multi_remove_handle( - $this->_mh, - $this->handles[$id]['handle'] - ); - curl_close($this->handles[$id]['handle']); - unset($this->handles[$id], $this->delays[$id]); - } - } - - /** - * Cancels a handle from sending and removes references to it. - * - * @param int $id Handle ID to cancel and remove. - * - * @return bool True on success, false on failure. - */ - private function cancel($id) - { - // Cannot cancel if it has been processed. - if (!isset($this->handles[$id])) { - return false; - } - - $handle = $this->handles[$id]['handle']; - unset($this->delays[$id], $this->handles[$id]); - curl_multi_remove_handle($this->_mh, $handle); - curl_close($handle); - - return true; - } - - private function addDelays() - { - $currentTime = microtime(true); - - foreach ($this->delays as $id => $delay) { - if ($currentTime >= $delay) { - unset($this->delays[$id]); - curl_multi_add_handle( - $this->_mh, - $this->handles[$id]['handle'] - ); - } - } - } - - private function processMessages() - { - while ($done = curl_multi_info_read($this->_mh)) { - $id = (int) $done['handle']; - - if (!isset($this->handles[$id])) { - // Probably was cancelled. - continue; - } - - $entry = $this->handles[$id]; - $entry['response']['transfer_stats'] = curl_getinfo($done['handle']); - - if ($done['result'] !== CURLM_OK) { - $entry['response']['curl']['errno'] = $done['result']; - $entry['response']['curl']['error'] = curl_error($done['handle']); - } - - $result = CurlFactory::createResponse( - $this, - $entry['request'], - $entry['response'], - $entry['headers'], - $entry['body'] - ); - - $this->removeProcessed($id); - $entry['deferred']->resolve($result); - } - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Client/Middleware.php b/vendor/guzzlehttp/ringphp/src/Client/Middleware.php deleted file mode 100644 index 6fa7318..0000000 --- a/vendor/guzzlehttp/ringphp/src/Client/Middleware.php +++ /dev/null @@ -1,58 +0,0 @@ -result = $result; - } - - public function __invoke(array $request) - { - Core::doSleep($request); - $response = is_callable($this->result) - ? call_user_func($this->result, $request) - : $this->result; - - if (is_array($response)) { - $response = new CompletedFutureArray($response + [ - 'status' => null, - 'body' => null, - 'headers' => [], - 'reason' => null, - 'effective_url' => null, - ]); - } elseif (!$response instanceof FutureArrayInterface) { - throw new \InvalidArgumentException( - 'Response must be an array or FutureArrayInterface. Found ' - . Core::describeType($request) - ); - } - - return $response; - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Client/StreamHandler.php b/vendor/guzzlehttp/ringphp/src/Client/StreamHandler.php deleted file mode 100644 index 4bacec1..0000000 --- a/vendor/guzzlehttp/ringphp/src/Client/StreamHandler.php +++ /dev/null @@ -1,414 +0,0 @@ -options = $options; - } - - public function __invoke(array $request) - { - $url = Core::url($request); - Core::doSleep($request); - - try { - // Does not support the expect header. - $request = Core::removeHeader($request, 'Expect'); - $stream = $this->createStream($url, $request); - return $this->createResponse($request, $url, $stream); - } catch (RingException $e) { - return $this->createErrorResponse($url, $e); - } - } - - private function createResponse(array $request, $url, $stream) - { - $hdrs = $this->lastHeaders; - $this->lastHeaders = null; - $parts = explode(' ', array_shift($hdrs), 3); - $response = [ - 'version' => substr($parts[0], 5), - 'status' => $parts[1], - 'reason' => isset($parts[2]) ? $parts[2] : null, - 'headers' => Core::headersFromLines($hdrs), - 'effective_url' => $url, - ]; - - $stream = $this->checkDecode($request, $response, $stream); - - // If not streaming, then drain the response into a stream. - if (empty($request['client']['stream'])) { - $dest = isset($request['client']['save_to']) - ? $request['client']['save_to'] - : fopen('php://temp', 'r+'); - $stream = $this->drain($stream, $dest); - } - - $response['body'] = $stream; - - return new CompletedFutureArray($response); - } - - private function checkDecode(array $request, array $response, $stream) - { - // Automatically decode responses when instructed. - if (!empty($request['client']['decode_content'])) { - switch (Core::firstHeader($response, 'Content-Encoding', true)) { - case 'gzip': - case 'deflate': - $stream = new InflateStream(Stream::factory($stream)); - break; - } - } - - return $stream; - } - - /** - * Drains the stream into the "save_to" client option. - * - * @param resource $stream - * @param string|resource|StreamInterface $dest - * - * @return Stream - * @throws \RuntimeException when the save_to option is invalid. - */ - private function drain($stream, $dest) - { - if (is_resource($stream)) { - if (!is_resource($dest)) { - $stream = Stream::factory($stream); - } else { - stream_copy_to_stream($stream, $dest); - fclose($stream); - rewind($dest); - return $dest; - } - } - - // Stream the response into the destination stream - $dest = is_string($dest) - ? new Stream(Utils::open($dest, 'r+')) - : Stream::factory($dest); - - Utils::copyToStream($stream, $dest); - $dest->seek(0); - $stream->close(); - - return $dest; - } - - /** - * Creates an error response for the given stream. - * - * @param string $url - * @param RingException $e - * - * @return array - */ - private function createErrorResponse($url, RingException $e) - { - // Determine if the error was a networking error. - $message = $e->getMessage(); - - // This list can probably get more comprehensive. - if (strpos($message, 'getaddrinfo') // DNS lookup failed - || strpos($message, 'Connection refused') - ) { - $e = new ConnectException($e->getMessage(), 0, $e); - } - - return new CompletedFutureArray([ - 'status' => null, - 'body' => null, - 'headers' => [], - 'effective_url' => $url, - 'error' => $e - ]); - } - - /** - * Create a resource and check to ensure it was created successfully - * - * @param callable $callback Callable that returns stream resource - * - * @return resource - * @throws \RuntimeException on error - */ - private function createResource(callable $callback) - { - $errors = null; - set_error_handler(function ($_, $msg, $file, $line) use (&$errors) { - $errors[] = [ - 'message' => $msg, - 'file' => $file, - 'line' => $line - ]; - return true; - }); - - $resource = $callback(); - restore_error_handler(); - - if (!$resource) { - $message = 'Error creating resource: '; - foreach ($errors as $err) { - foreach ($err as $key => $value) { - $message .= "[$key] $value" . PHP_EOL; - } - } - throw new RingException(trim($message)); - } - - return $resource; - } - - private function createStream($url, array $request) - { - static $methods; - if (!$methods) { - $methods = array_flip(get_class_methods(__CLASS__)); - } - - // HTTP/1.1 streams using the PHP stream wrapper require a - // Connection: close header - if ((!isset($request['version']) || $request['version'] == '1.1') - && !Core::hasHeader($request, 'Connection') - ) { - $request['headers']['Connection'] = ['close']; - } - - // Ensure SSL is verified by default - if (!isset($request['client']['verify'])) { - $request['client']['verify'] = true; - } - - $params = []; - $options = $this->getDefaultOptions($request); - - if (isset($request['client'])) { - foreach ($request['client'] as $key => $value) { - $method = "add_{$key}"; - if (isset($methods[$method])) { - $this->{$method}($request, $options, $value, $params); - } - } - } - - return $this->createStreamResource( - $url, - $request, - $options, - $this->createContext($request, $options, $params) - ); - } - - private function getDefaultOptions(array $request) - { - $headers = ""; - foreach ($request['headers'] as $name => $value) { - foreach ((array) $value as $val) { - $headers .= "$name: $val\r\n"; - } - } - - $context = [ - 'http' => [ - 'method' => $request['http_method'], - 'header' => $headers, - 'protocol_version' => isset($request['version']) ? $request['version'] : 1.1, - 'ignore_errors' => true, - 'follow_location' => 0, - ], - ]; - - $body = Core::body($request); - if (isset($body)) { - $context['http']['content'] = $body; - // Prevent the HTTP handler from adding a Content-Type header. - if (!Core::hasHeader($request, 'Content-Type')) { - $context['http']['header'] .= "Content-Type:\r\n"; - } - } - - $context['http']['header'] = rtrim($context['http']['header']); - - return $context; - } - - private function add_proxy(array $request, &$options, $value, &$params) - { - if (!is_array($value)) { - $options['http']['proxy'] = $value; - } else { - $scheme = isset($request['scheme']) ? $request['scheme'] : 'http'; - if (isset($value[$scheme])) { - $options['http']['proxy'] = $value[$scheme]; - } - } - } - - private function add_timeout(array $request, &$options, $value, &$params) - { - $options['http']['timeout'] = $value; - } - - private function add_verify(array $request, &$options, $value, &$params) - { - if ($value === true) { - // PHP 5.6 or greater will find the system cert by default. When - // < 5.6, use the Guzzle bundled cacert. - if (PHP_VERSION_ID < 50600) { - $options['ssl']['cafile'] = ClientUtils::getDefaultCaBundle(); - } - } elseif (is_string($value)) { - $options['ssl']['cafile'] = $value; - if (!file_exists($value)) { - throw new RingException("SSL CA bundle not found: $value"); - } - } elseif ($value === false) { - $options['ssl']['verify_peer'] = false; - $options['ssl']['allow_self_signed'] = true; - return; - } else { - throw new RingException('Invalid verify request option'); - } - - $options['ssl']['verify_peer'] = true; - $options['ssl']['allow_self_signed'] = false; - } - - private function add_cert(array $request, &$options, $value, &$params) - { - if (is_array($value)) { - $options['ssl']['passphrase'] = $value[1]; - $value = $value[0]; - } - - if (!file_exists($value)) { - throw new RingException("SSL certificate not found: {$value}"); - } - - $options['ssl']['local_cert'] = $value; - } - - private function add_progress(array $request, &$options, $value, &$params) - { - $fn = function ($code, $_1, $_2, $_3, $transferred, $total) use ($value) { - if ($code == STREAM_NOTIFY_PROGRESS) { - $value($total, $transferred, null, null); - } - }; - - // Wrap the existing function if needed. - $params['notification'] = isset($params['notification']) - ? Core::callArray([$params['notification'], $fn]) - : $fn; - } - - private function add_debug(array $request, &$options, $value, &$params) - { - if ($value === false) { - return; - } - - static $map = [ - STREAM_NOTIFY_CONNECT => 'CONNECT', - STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED', - STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT', - STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS', - STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS', - STREAM_NOTIFY_REDIRECTED => 'REDIRECTED', - STREAM_NOTIFY_PROGRESS => 'PROGRESS', - STREAM_NOTIFY_FAILURE => 'FAILURE', - STREAM_NOTIFY_COMPLETED => 'COMPLETED', - STREAM_NOTIFY_RESOLVE => 'RESOLVE', - ]; - - static $args = ['severity', 'message', 'message_code', - 'bytes_transferred', 'bytes_max']; - - $value = Core::getDebugResource($value); - $ident = $request['http_method'] . ' ' . Core::url($request); - $fn = function () use ($ident, $value, $map, $args) { - $passed = func_get_args(); - $code = array_shift($passed); - fprintf($value, '<%s> [%s] ', $ident, $map[$code]); - foreach (array_filter($passed) as $i => $v) { - fwrite($value, $args[$i] . ': "' . $v . '" '); - } - fwrite($value, "\n"); - }; - - // Wrap the existing function if needed. - $params['notification'] = isset($params['notification']) - ? Core::callArray([$params['notification'], $fn]) - : $fn; - } - - private function applyCustomOptions(array $request, array &$options) - { - if (!isset($request['client']['stream_context'])) { - return; - } - - if (!is_array($request['client']['stream_context'])) { - throw new RingException('stream_context must be an array'); - } - - $options = array_replace_recursive( - $options, - $request['client']['stream_context'] - ); - } - - private function createContext(array $request, array $options, array $params) - { - $this->applyCustomOptions($request, $options); - return $this->createResource( - function () use ($request, $options, $params) { - return stream_context_create($options, $params); - }, - $request, - $options - ); - } - - private function createStreamResource( - $url, - array $request, - array $options, - $context - ) { - return $this->createResource( - function () use ($url, $context) { - if (false === strpos($url, 'http')) { - trigger_error("URL is invalid: {$url}", E_USER_WARNING); - return null; - } - $resource = fopen($url, 'r', null, $context); - $this->lastHeaders = $http_response_header; - return $resource; - }, - $request, - $options - ); - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Core.php b/vendor/guzzlehttp/ringphp/src/Core.php deleted file mode 100644 index dd7d1a0..0000000 --- a/vendor/guzzlehttp/ringphp/src/Core.php +++ /dev/null @@ -1,364 +0,0 @@ - $value) { - if (!strcasecmp($name, $header)) { - $result = array_merge($result, $value); - } - } - } - - return $result; - } - - /** - * Gets a header value from a message as a string or null - * - * This method searches through the "headers" key of a message for a header - * using a case-insensitive search. The lines of the header are imploded - * using commas into a single string return value. - * - * @param array $message Request or response hash. - * @param string $header Header to retrieve - * - * @return string|null Returns the header string if found, or null if not. - */ - public static function header($message, $header) - { - $match = self::headerLines($message, $header); - return $match ? implode(', ', $match) : null; - } - - /** - * Returns the first header value from a message as a string or null. If - * a header line contains multiple values separated by a comma, then this - * function will return the first value in the list. - * - * @param array $message Request or response hash. - * @param string $header Header to retrieve - * - * @return string|null Returns the value as a string if found. - */ - public static function firstHeader($message, $header) - { - if (!empty($message['headers'])) { - foreach ($message['headers'] as $name => $value) { - if (!strcasecmp($name, $header)) { - // Return the match itself if it is a single value. - $pos = strpos($value[0], ','); - return $pos ? substr($value[0], 0, $pos) : $value[0]; - } - } - } - - return null; - } - - /** - * Returns true if a message has the provided case-insensitive header. - * - * @param array $message Request or response hash. - * @param string $header Header to check - * - * @return bool - */ - public static function hasHeader($message, $header) - { - if (!empty($message['headers'])) { - foreach ($message['headers'] as $name => $value) { - if (!strcasecmp($name, $header)) { - return true; - } - } - } - - return false; - } - - /** - * Parses an array of header lines into an associative array of headers. - * - * @param array $lines Header lines array of strings in the following - * format: "Name: Value" - * @return array - */ - public static function headersFromLines($lines) - { - $headers = []; - - foreach ($lines as $line) { - $parts = explode(':', $line, 2); - $headers[trim($parts[0])][] = isset($parts[1]) - ? trim($parts[1]) - : null; - } - - return $headers; - } - - /** - * Removes a header from a message using a case-insensitive comparison. - * - * @param array $message Message that contains 'headers' - * @param string $header Header to remove - * - * @return array - */ - public static function removeHeader(array $message, $header) - { - if (isset($message['headers'])) { - foreach (array_keys($message['headers']) as $key) { - if (!strcasecmp($header, $key)) { - unset($message['headers'][$key]); - } - } - } - - return $message; - } - - /** - * Replaces any existing case insensitive headers with the given value. - * - * @param array $message Message that contains 'headers' - * @param string $header Header to set. - * @param array $value Value to set. - * - * @return array - */ - public static function setHeader(array $message, $header, array $value) - { - $message = self::removeHeader($message, $header); - $message['headers'][$header] = $value; - - return $message; - } - - /** - * Creates a URL string from a request. - * - * If the "url" key is present on the request, it is returned, otherwise - * the url is built up based on the scheme, host, uri, and query_string - * request values. - * - * @param array $request Request to get the URL from - * - * @return string Returns the request URL as a string. - * @throws \InvalidArgumentException if no Host header is present. - */ - public static function url(array $request) - { - if (isset($request['url'])) { - return $request['url']; - } - - $uri = (isset($request['scheme']) - ? $request['scheme'] : 'http') . '://'; - - if ($host = self::header($request, 'host')) { - $uri .= $host; - } else { - throw new \InvalidArgumentException('No Host header was provided'); - } - - if (isset($request['uri'])) { - $uri .= $request['uri']; - } - - if (isset($request['query_string'])) { - $uri .= '?' . $request['query_string']; - } - - return $uri; - } - - /** - * Reads the body of a message into a string. - * - * @param array|FutureArrayInterface $message Array containing a "body" key - * - * @return null|string Returns the body as a string or null if not set. - * @throws \InvalidArgumentException if a request body is invalid. - */ - public static function body($message) - { - if (!isset($message['body'])) { - return null; - } - - if ($message['body'] instanceof StreamInterface) { - return (string) $message['body']; - } - - switch (gettype($message['body'])) { - case 'string': - return $message['body']; - case 'resource': - return stream_get_contents($message['body']); - case 'object': - if ($message['body'] instanceof \Iterator) { - return implode('', iterator_to_array($message['body'])); - } elseif (method_exists($message['body'], '__toString')) { - return (string) $message['body']; - } - default: - throw new \InvalidArgumentException('Invalid request body: ' - . self::describeType($message['body'])); - } - } - - /** - * Rewind the body of the provided message if possible. - * - * @param array $message Message that contains a 'body' field. - * - * @return bool Returns true on success, false on failure - */ - public static function rewindBody($message) - { - if ($message['body'] instanceof StreamInterface) { - return $message['body']->seek(0); - } - - if ($message['body'] instanceof \Generator) { - return false; - } - - if ($message['body'] instanceof \Iterator) { - $message['body']->rewind(); - return true; - } - - if (is_resource($message['body'])) { - return rewind($message['body']); - } - - return is_string($message['body']) - || (is_object($message['body']) - && method_exists($message['body'], '__toString')); - } - - /** - * Debug function used to describe the provided value type and class. - * - * @param mixed $input - * - * @return string Returns a string containing the type of the variable and - * if a class is provided, the class name. - */ - public static function describeType($input) - { - switch (gettype($input)) { - case 'object': - return 'object(' . get_class($input) . ')'; - case 'array': - return 'array(' . count($input) . ')'; - default: - ob_start(); - var_dump($input); - // normalize float vs double - return str_replace('double(', 'float(', rtrim(ob_get_clean())); - } - } - - /** - * Sleep for the specified amount of time specified in the request's - * ['client']['delay'] option if present. - * - * This function should only be used when a non-blocking sleep is not - * possible. - * - * @param array $request Request to sleep - */ - public static function doSleep(array $request) - { - if (isset($request['client']['delay'])) { - usleep($request['client']['delay'] * 1000); - } - } - - /** - * Returns a proxied future that modifies the dereferenced value of another - * future using a promise. - * - * @param FutureArrayInterface $future Future to wrap with a new future - * @param callable $onFulfilled Invoked when the future fulfilled - * @param callable $onRejected Invoked when the future rejected - * @param callable $onProgress Invoked when the future progresses - * - * @return FutureArray - */ - public static function proxy( - FutureArrayInterface $future, - callable $onFulfilled = null, - callable $onRejected = null, - callable $onProgress = null - ) { - return new FutureArray( - $future->then($onFulfilled, $onRejected, $onProgress), - [$future, 'wait'], - [$future, 'cancel'] - ); - } - - /** - * Returns a debug stream based on the provided variable. - * - * @param mixed $value Optional value - * - * @return resource - */ - public static function getDebugResource($value = null) - { - if (is_resource($value)) { - return $value; - } elseif (defined('STDOUT')) { - return STDOUT; - } else { - return fopen('php://output', 'w'); - } - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Exception/CancelledException.php b/vendor/guzzlehttp/ringphp/src/Exception/CancelledException.php deleted file mode 100644 index 95b353a..0000000 --- a/vendor/guzzlehttp/ringphp/src/Exception/CancelledException.php +++ /dev/null @@ -1,7 +0,0 @@ -wrappedPromise = $promise; - $this->waitfn = $wait; - $this->cancelfn = $cancel; - } - - public function wait() - { - if (!$this->isRealized) { - $this->addShadow(); - if (!$this->isRealized && $this->waitfn) { - $this->invokeWait(); - } - if (!$this->isRealized) { - $this->error = new RingException('Waiting did not resolve future'); - } - } - - if ($this->error) { - throw $this->error; - } - - return $this->result; - } - - public function promise() - { - return $this->wrappedPromise; - } - - public function then( - callable $onFulfilled = null, - callable $onRejected = null, - callable $onProgress = null - ) { - return $this->wrappedPromise->then($onFulfilled, $onRejected, $onProgress); - } - - public function cancel() - { - if (!$this->isRealized) { - $cancelfn = $this->cancelfn; - $this->waitfn = $this->cancelfn = null; - $this->isRealized = true; - $this->error = new CancelledFutureAccessException(); - if ($cancelfn) { - $cancelfn($this); - } - } - } - - private function addShadow() - { - // Get the result and error when the promise is resolved. Note that - // calling this function might trigger the resolution immediately. - $this->wrappedPromise->then( - function ($value) { - $this->isRealized = true; - $this->result = $value; - $this->waitfn = $this->cancelfn = null; - }, - function ($error) { - $this->isRealized = true; - $this->error = $error; - $this->waitfn = $this->cancelfn = null; - } - ); - } - - private function invokeWait() - { - try { - $wait = $this->waitfn; - $this->waitfn = null; - $wait(); - } catch (\Exception $e) { - // Defer can throw to reject. - $this->error = $e; - $this->isRealized = true; - } - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureArray.php b/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureArray.php deleted file mode 100644 index 0a90c93..0000000 --- a/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureArray.php +++ /dev/null @@ -1,43 +0,0 @@ -result[$offset]); - } - - public function offsetGet($offset) - { - return $this->result[$offset]; - } - - public function offsetSet($offset, $value) - { - $this->result[$offset] = $value; - } - - public function offsetUnset($offset) - { - unset($this->result[$offset]); - } - - public function count() - { - return count($this->result); - } - - public function getIterator() - { - return new \ArrayIterator($this->result); - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureValue.php b/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureValue.php deleted file mode 100644 index 0d25af7..0000000 --- a/vendor/guzzlehttp/ringphp/src/Future/CompletedFutureValue.php +++ /dev/null @@ -1,57 +0,0 @@ -result = $result; - $this->error = $e; - } - - public function wait() - { - if ($this->error) { - throw $this->error; - } - - return $this->result; - } - - public function cancel() {} - - public function promise() - { - if (!$this->cachedPromise) { - $this->cachedPromise = $this->error - ? new RejectedPromise($this->error) - : new FulfilledPromise($this->result); - } - - return $this->cachedPromise; - } - - public function then( - callable $onFulfilled = null, - callable $onRejected = null, - callable $onProgress = null - ) { - return $this->promise()->then($onFulfilled, $onRejected, $onProgress); - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Future/FutureArray.php b/vendor/guzzlehttp/ringphp/src/Future/FutureArray.php deleted file mode 100644 index 3d64c96..0000000 --- a/vendor/guzzlehttp/ringphp/src/Future/FutureArray.php +++ /dev/null @@ -1,40 +0,0 @@ -_value[$offset]); - } - - public function offsetGet($offset) - { - return $this->_value[$offset]; - } - - public function offsetSet($offset, $value) - { - $this->_value[$offset] = $value; - } - - public function offsetUnset($offset) - { - unset($this->_value[$offset]); - } - - public function count() - { - return count($this->_value); - } - - public function getIterator() - { - return new \ArrayIterator($this->_value); - } -} diff --git a/vendor/guzzlehttp/ringphp/src/Future/FutureArrayInterface.php b/vendor/guzzlehttp/ringphp/src/Future/FutureArrayInterface.php deleted file mode 100644 index 58f5f73..0000000 --- a/vendor/guzzlehttp/ringphp/src/Future/FutureArrayInterface.php +++ /dev/null @@ -1,11 +0,0 @@ -_value = $this->wait(); - } -} diff --git a/vendor/guzzlehttp/streams/LICENSE b/vendor/guzzlehttp/streams/LICENSE deleted file mode 100644 index 71d3b78..0000000 --- a/vendor/guzzlehttp/streams/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling - -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. diff --git a/vendor/guzzlehttp/streams/composer.json b/vendor/guzzlehttp/streams/composer.json deleted file mode 100644 index 6d70343..0000000 --- a/vendor/guzzlehttp/streams/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "guzzlehttp/streams", - "description": "Provides a simple abstraction over streams of data", - "homepage": "http://guzzlephp.org/", - "keywords": ["stream", "guzzle"], - "license": "MIT", - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "autoload": { - "psr-4": { "GuzzleHttp\\Stream\\": "src/" } - }, - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - } -} diff --git a/vendor/guzzlehttp/streams/src/AppendStream.php b/vendor/guzzlehttp/streams/src/AppendStream.php deleted file mode 100644 index 94bda71..0000000 --- a/vendor/guzzlehttp/streams/src/AppendStream.php +++ /dev/null @@ -1,220 +0,0 @@ -addStream($stream); - } - } - - public function __toString() - { - try { - $this->seek(0); - return $this->getContents(); - } catch (\Exception $e) { - return ''; - } - } - - /** - * Add a stream to the AppendStream - * - * @param StreamInterface $stream Stream to append. Must be readable. - * - * @throws \InvalidArgumentException if the stream is not readable - */ - public function addStream(StreamInterface $stream) - { - if (!$stream->isReadable()) { - throw new \InvalidArgumentException('Each stream must be readable'); - } - - // The stream is only seekable if all streams are seekable - if (!$stream->isSeekable()) { - $this->seekable = false; - } - - $this->streams[] = $stream; - } - - public function getContents() - { - return Utils::copyToString($this); - } - - /** - * Closes each attached stream. - * - * {@inheritdoc} - */ - public function close() - { - $this->pos = $this->current = 0; - - foreach ($this->streams as $stream) { - $stream->close(); - } - - $this->streams = []; - } - - /** - * Detaches each attached stream - * - * {@inheritdoc} - */ - public function detach() - { - $this->close(); - $this->detached = true; - } - - public function attach($stream) - { - throw new CannotAttachException(); - } - - public function tell() - { - return $this->pos; - } - - /** - * Tries to calculate the size by adding the size of each stream. - * - * If any of the streams do not return a valid number, then the size of the - * append stream cannot be determined and null is returned. - * - * {@inheritdoc} - */ - public function getSize() - { - $size = 0; - - foreach ($this->streams as $stream) { - $s = $stream->getSize(); - if ($s === null) { - return null; - } - $size += $s; - } - - return $size; - } - - public function eof() - { - return !$this->streams || - ($this->current >= count($this->streams) - 1 && - $this->streams[$this->current]->eof()); - } - - /** - * Attempts to seek to the given position. Only supports SEEK_SET. - * - * {@inheritdoc} - */ - public function seek($offset, $whence = SEEK_SET) - { - if (!$this->seekable || $whence !== SEEK_SET) { - return false; - } - - $success = true; - $this->pos = $this->current = 0; - - // Rewind each stream - foreach ($this->streams as $stream) { - if (!$stream->seek(0)) { - $success = false; - } - } - - if (!$success) { - return false; - } - - // Seek to the actual position by reading from each stream - while ($this->pos < $offset && !$this->eof()) { - $this->read(min(8096, $offset - $this->pos)); - } - - return $this->pos == $offset; - } - - /** - * Reads from all of the appended streams until the length is met or EOF. - * - * {@inheritdoc} - */ - public function read($length) - { - $buffer = ''; - $total = count($this->streams) - 1; - $remaining = $length; - - while ($remaining > 0) { - // Progress to the next stream if needed. - if ($this->streams[$this->current]->eof()) { - if ($this->current == $total) { - break; - } - $this->current++; - } - $buffer .= $this->streams[$this->current]->read($remaining); - $remaining = $length - strlen($buffer); - } - - $this->pos += strlen($buffer); - - return $buffer; - } - - public function isReadable() - { - return true; - } - - public function isWritable() - { - return false; - } - - public function isSeekable() - { - return $this->seekable; - } - - public function write($string) - { - return false; - } - - public function getMetadata($key = null) - { - return $key ? null : []; - } -} diff --git a/vendor/guzzlehttp/streams/src/AsyncReadStream.php b/vendor/guzzlehttp/streams/src/AsyncReadStream.php deleted file mode 100644 index 25ad960..0000000 --- a/vendor/guzzlehttp/streams/src/AsyncReadStream.php +++ /dev/null @@ -1,207 +0,0 @@ -isReadable() || !$buffer->isWritable()) { - throw new \InvalidArgumentException( - 'Buffer must be readable and writable' - ); - } - - if (isset($config['size'])) { - $this->size = $config['size']; - } - - static $callables = ['pump', 'drain']; - foreach ($callables as $check) { - if (isset($config[$check])) { - if (!is_callable($config[$check])) { - throw new \InvalidArgumentException( - $check . ' must be callable' - ); - } - $this->{$check} = $config[$check]; - } - } - - $this->hwm = $buffer->getMetadata('hwm'); - - // Cannot drain when there's no high water mark. - if ($this->hwm === null) { - $this->drain = null; - } - - $this->stream = $buffer; - } - - /** - * Factory method used to create new async stream and an underlying buffer - * if no buffer is provided. - * - * This function accepts the same options as AsyncReadStream::__construct, - * but added the following key value pairs: - * - * - buffer: (StreamInterface) Buffer used to buffer data. If none is - * provided, a default buffer is created. - * - hwm: (int) High water mark to use if a buffer is created on your - * behalf. - * - max_buffer: (int) If provided, wraps the utilized buffer in a - * DroppingStream decorator to ensure that buffer does not exceed a given - * length. When exceeded, the stream will begin dropping data. Set the - * max_buffer to 0, to use a NullStream which does not store data. - * - write: (callable) A function that is invoked when data is written - * to the underlying buffer. The function accepts the buffer as the first - * argument, and the data being written as the second. The function MUST - * return the number of bytes that were written or false to let writers - * know to slow down. - * - drain: (callable) See constructor documentation. - * - pump: (callable) See constructor documentation. - * - * @param array $options Associative array of options. - * - * @return array Returns an array containing the buffer used to buffer - * data, followed by the ready to use AsyncReadStream object. - */ - public static function create(array $options = []) - { - $maxBuffer = isset($options['max_buffer']) - ? $options['max_buffer'] - : null; - - if ($maxBuffer === 0) { - $buffer = new NullStream(); - } elseif (isset($options['buffer'])) { - $buffer = $options['buffer']; - } else { - $hwm = isset($options['hwm']) ? $options['hwm'] : 16384; - $buffer = new BufferStream($hwm); - } - - if ($maxBuffer > 0) { - $buffer = new DroppingStream($buffer, $options['max_buffer']); - } - - // Call the on_write callback if an on_write function was provided. - if (isset($options['write'])) { - $onWrite = $options['write']; - $buffer = FnStream::decorate($buffer, [ - 'write' => function ($string) use ($buffer, $onWrite) { - $result = $buffer->write($string); - $onWrite($buffer, $string); - return $result; - } - ]); - } - - return [$buffer, new self($buffer, $options)]; - } - - public function getSize() - { - return $this->size; - } - - public function isWritable() - { - return false; - } - - public function write($string) - { - return false; - } - - public function read($length) - { - if (!$this->needsDrain && $this->drain) { - $this->needsDrain = $this->stream->getSize() >= $this->hwm; - } - - $result = $this->stream->read($length); - - // If we need to drain, then drain when the buffer is empty. - if ($this->needsDrain && $this->stream->getSize() === 0) { - $this->needsDrain = false; - $drainFn = $this->drain; - $drainFn($this->stream); - } - - $resultLen = strlen($result); - - // If a pump was provided, the buffer is still open, and not enough - // data was given, then block until the data is provided. - if ($this->pump && $resultLen < $length) { - $pumpFn = $this->pump; - $result .= $pumpFn($length - $resultLen); - } - - return $result; - } -} diff --git a/vendor/guzzlehttp/streams/src/BufferStream.php b/vendor/guzzlehttp/streams/src/BufferStream.php deleted file mode 100644 index 0fffbd6..0000000 --- a/vendor/guzzlehttp/streams/src/BufferStream.php +++ /dev/null @@ -1,138 +0,0 @@ -hwm = $hwm; - } - - public function __toString() - { - return $this->getContents(); - } - - public function getContents() - { - $buffer = $this->buffer; - $this->buffer = ''; - - return $buffer; - } - - public function close() - { - $this->buffer = ''; - } - - public function detach() - { - $this->close(); - } - - public function attach($stream) - { - throw new CannotAttachException(); - } - - public function getSize() - { - return strlen($this->buffer); - } - - public function isReadable() - { - return true; - } - - public function isWritable() - { - return true; - } - - public function isSeekable() - { - return false; - } - - public function seek($offset, $whence = SEEK_SET) - { - return false; - } - - public function eof() - { - return strlen($this->buffer) === 0; - } - - public function tell() - { - return false; - } - - /** - * Reads data from the buffer. - */ - public function read($length) - { - $currentLength = strlen($this->buffer); - - if ($length >= $currentLength) { - // No need to slice the buffer because we don't have enough data. - $result = $this->buffer; - $this->buffer = ''; - } else { - // Slice up the result to provide a subset of the buffer. - $result = substr($this->buffer, 0, $length); - $this->buffer = substr($this->buffer, $length); - } - - return $result; - } - - /** - * Writes data to the buffer. - */ - public function write($string) - { - $this->buffer .= $string; - - if (strlen($this->buffer) >= $this->hwm) { - return false; - } - - return strlen($string); - } - - public function getMetadata($key = null) - { - if ($key == 'hwm') { - return $this->hwm; - } - - return $key ? null : []; - } -} diff --git a/vendor/guzzlehttp/streams/src/CachingStream.php b/vendor/guzzlehttp/streams/src/CachingStream.php deleted file mode 100644 index 60bb905..0000000 --- a/vendor/guzzlehttp/streams/src/CachingStream.php +++ /dev/null @@ -1,122 +0,0 @@ -remoteStream = $stream; - $this->stream = $target ?: new Stream(fopen('php://temp', 'r+')); - } - - public function getSize() - { - return max($this->stream->getSize(), $this->remoteStream->getSize()); - } - - /** - * {@inheritdoc} - * @throws SeekException When seeking with SEEK_END or when seeking - * past the total size of the buffer stream - */ - public function seek($offset, $whence = SEEK_SET) - { - if ($whence == SEEK_SET) { - $byte = $offset; - } elseif ($whence == SEEK_CUR) { - $byte = $offset + $this->tell(); - } else { - return false; - } - - // You cannot skip ahead past where you've read from the remote stream - if ($byte > $this->stream->getSize()) { - throw new SeekException( - $this, - $byte, - sprintf('Cannot seek to byte %d when the buffered stream only' - . ' contains %d bytes', $byte, $this->stream->getSize()) - ); - } - - return $this->stream->seek($byte); - } - - public function read($length) - { - // Perform a regular read on any previously read data from the buffer - $data = $this->stream->read($length); - $remaining = $length - strlen($data); - - // More data was requested so read from the remote stream - if ($remaining) { - // If data was written to the buffer in a position that would have - // been filled from the remote stream, then we must skip bytes on - // the remote stream to emulate overwriting bytes from that - // position. This mimics the behavior of other PHP stream wrappers. - $remoteData = $this->remoteStream->read( - $remaining + $this->skipReadBytes - ); - - if ($this->skipReadBytes) { - $len = strlen($remoteData); - $remoteData = substr($remoteData, $this->skipReadBytes); - $this->skipReadBytes = max(0, $this->skipReadBytes - $len); - } - - $data .= $remoteData; - $this->stream->write($remoteData); - } - - return $data; - } - - public function write($string) - { - // When appending to the end of the currently read stream, you'll want - // to skip bytes from being read from the remote stream to emulate - // other stream wrappers. Basically replacing bytes of data of a fixed - // length. - $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell(); - if ($overflow > 0) { - $this->skipReadBytes += $overflow; - } - - return $this->stream->write($string); - } - - public function eof() - { - return $this->stream->eof() && $this->remoteStream->eof(); - } - - /** - * Close both the remote stream and buffer stream - */ - public function close() - { - $this->remoteStream->close() && $this->stream->close(); - } -} diff --git a/vendor/guzzlehttp/streams/src/DroppingStream.php b/vendor/guzzlehttp/streams/src/DroppingStream.php deleted file mode 100644 index 56ee80c..0000000 --- a/vendor/guzzlehttp/streams/src/DroppingStream.php +++ /dev/null @@ -1,42 +0,0 @@ -stream = $stream; - $this->maxLength = $maxLength; - } - - public function write($string) - { - $diff = $this->maxLength - $this->stream->getSize(); - - // Begin returning false when the underlying stream is too large. - if ($diff <= 0) { - return false; - } - - // Write the stream or a subset of the stream if needed. - if (strlen($string) < $diff) { - return $this->stream->write($string); - } - - $this->stream->write(substr($string, 0, $diff)); - - return false; - } -} diff --git a/vendor/guzzlehttp/streams/src/Exception/CannotAttachException.php b/vendor/guzzlehttp/streams/src/Exception/CannotAttachException.php deleted file mode 100644 index e631b9f..0000000 --- a/vendor/guzzlehttp/streams/src/Exception/CannotAttachException.php +++ /dev/null @@ -1,4 +0,0 @@ -stream = $stream; - $msg = $msg ?: 'Could not seek the stream to position ' . $pos; - parent::__construct($msg); - } - - /** - * @return StreamInterface - */ - public function getStream() - { - return $this->stream; - } -} diff --git a/vendor/guzzlehttp/streams/src/FnStream.php b/vendor/guzzlehttp/streams/src/FnStream.php deleted file mode 100644 index 6b5872d..0000000 --- a/vendor/guzzlehttp/streams/src/FnStream.php +++ /dev/null @@ -1,147 +0,0 @@ -methods = $methods; - - // Create the functions on the class - foreach ($methods as $name => $fn) { - $this->{'_fn_' . $name} = $fn; - } - } - - /** - * Lazily determine which methods are not implemented. - * @throws \BadMethodCallException - */ - public function __get($name) - { - throw new \BadMethodCallException(str_replace('_fn_', '', $name) - . '() is not implemented in the FnStream'); - } - - /** - * The close method is called on the underlying stream only if possible. - */ - public function __destruct() - { - if (isset($this->_fn_close)) { - call_user_func($this->_fn_close); - } - } - - /** - * Adds custom functionality to an underlying stream by intercepting - * specific method calls. - * - * @param StreamInterface $stream Stream to decorate - * @param array $methods Hash of method name to a closure - * - * @return FnStream - */ - public static function decorate(StreamInterface $stream, array $methods) - { - // If any of the required methods were not provided, then simply - // proxy to the decorated stream. - foreach (array_diff(self::$slots, array_keys($methods)) as $diff) { - $methods[$diff] = [$stream, $diff]; - } - - return new self($methods); - } - - public function __toString() - { - return call_user_func($this->_fn___toString); - } - - public function close() - { - return call_user_func($this->_fn_close); - } - - public function detach() - { - return call_user_func($this->_fn_detach); - } - - public function attach($stream) - { - return call_user_func($this->_fn_attach, $stream); - } - - public function getSize() - { - return call_user_func($this->_fn_getSize); - } - - public function tell() - { - return call_user_func($this->_fn_tell); - } - - public function eof() - { - return call_user_func($this->_fn_eof); - } - - public function isSeekable() - { - return call_user_func($this->_fn_isSeekable); - } - - public function seek($offset, $whence = SEEK_SET) - { - return call_user_func($this->_fn_seek, $offset, $whence); - } - - public function isWritable() - { - return call_user_func($this->_fn_isWritable); - } - - public function write($string) - { - return call_user_func($this->_fn_write, $string); - } - - public function isReadable() - { - return call_user_func($this->_fn_isReadable); - } - - public function read($length) - { - return call_user_func($this->_fn_read, $length); - } - - public function getContents() - { - return call_user_func($this->_fn_getContents); - } - - public function getMetadata($key = null) - { - return call_user_func($this->_fn_getMetadata, $key); - } -} diff --git a/vendor/guzzlehttp/streams/src/GuzzleStreamWrapper.php b/vendor/guzzlehttp/streams/src/GuzzleStreamWrapper.php deleted file mode 100644 index 4d049a6..0000000 --- a/vendor/guzzlehttp/streams/src/GuzzleStreamWrapper.php +++ /dev/null @@ -1,117 +0,0 @@ -isReadable()) { - $mode = $stream->isWritable() ? 'r+' : 'r'; - } elseif ($stream->isWritable()) { - $mode = 'w'; - } else { - throw new \InvalidArgumentException('The stream must be readable, ' - . 'writable, or both.'); - } - - return fopen('guzzle://stream', $mode, null, stream_context_create([ - 'guzzle' => ['stream' => $stream] - ])); - } - - /** - * Registers the stream wrapper if needed - */ - public static function register() - { - if (!in_array('guzzle', stream_get_wrappers())) { - stream_wrapper_register('guzzle', __CLASS__); - } - } - - public function stream_open($path, $mode, $options, &$opened_path) - { - $options = stream_context_get_options($this->context); - - if (!isset($options['guzzle']['stream'])) { - return false; - } - - $this->mode = $mode; - $this->stream = $options['guzzle']['stream']; - - return true; - } - - public function stream_read($count) - { - return $this->stream->read($count); - } - - public function stream_write($data) - { - return (int) $this->stream->write($data); - } - - public function stream_tell() - { - return $this->stream->tell(); - } - - public function stream_eof() - { - return $this->stream->eof(); - } - - public function stream_seek($offset, $whence) - { - return $this->stream->seek($offset, $whence); - } - - public function stream_stat() - { - static $modeMap = [ - 'r' => 33060, - 'r+' => 33206, - 'w' => 33188 - ]; - - return [ - 'dev' => 0, - 'ino' => 0, - 'mode' => $modeMap[$this->mode], - 'nlink' => 0, - 'uid' => 0, - 'gid' => 0, - 'rdev' => 0, - 'size' => $this->stream->getSize() ?: 0, - 'atime' => 0, - 'mtime' => 0, - 'ctime' => 0, - 'blksize' => 0, - 'blocks' => 0 - ]; - } -} diff --git a/vendor/guzzlehttp/streams/src/InflateStream.php b/vendor/guzzlehttp/streams/src/InflateStream.php deleted file mode 100644 index 978af21..0000000 --- a/vendor/guzzlehttp/streams/src/InflateStream.php +++ /dev/null @@ -1,27 +0,0 @@ -stream = new Stream($resource); - } -} diff --git a/vendor/guzzlehttp/streams/src/LazyOpenStream.php b/vendor/guzzlehttp/streams/src/LazyOpenStream.php deleted file mode 100644 index 6242ee7..0000000 --- a/vendor/guzzlehttp/streams/src/LazyOpenStream.php +++ /dev/null @@ -1,37 +0,0 @@ -filename = $filename; - $this->mode = $mode; - } - - /** - * Creates the underlying stream lazily when required. - * - * @return StreamInterface - */ - protected function createStream() - { - return Stream::factory(Utils::open($this->filename, $this->mode)); - } -} diff --git a/vendor/guzzlehttp/streams/src/LimitStream.php b/vendor/guzzlehttp/streams/src/LimitStream.php deleted file mode 100644 index e9fad98..0000000 --- a/vendor/guzzlehttp/streams/src/LimitStream.php +++ /dev/null @@ -1,161 +0,0 @@ -stream = $stream; - $this->setLimit($limit); - $this->setOffset($offset); - } - - public function eof() - { - // Always return true if the underlying stream is EOF - if ($this->stream->eof()) { - return true; - } - - // No limit and the underlying stream is not at EOF - if ($this->limit == -1) { - return false; - } - - $tell = $this->stream->tell(); - if ($tell === false) { - return false; - } - - return $tell >= $this->offset + $this->limit; - } - - /** - * Returns the size of the limited subset of data - * {@inheritdoc} - */ - public function getSize() - { - if (null === ($length = $this->stream->getSize())) { - return null; - } elseif ($this->limit == -1) { - return $length - $this->offset; - } else { - return min($this->limit, $length - $this->offset); - } - } - - /** - * Allow for a bounded seek on the read limited stream - * {@inheritdoc} - */ - public function seek($offset, $whence = SEEK_SET) - { - if ($whence !== SEEK_SET || $offset < 0) { - return false; - } - - $offset += $this->offset; - - if ($this->limit !== -1) { - if ($offset > $this->offset + $this->limit) { - $offset = $this->offset + $this->limit; - } - } - - return $this->stream->seek($offset); - } - - /** - * Give a relative tell() - * {@inheritdoc} - */ - public function tell() - { - return $this->stream->tell() - $this->offset; - } - - /** - * Set the offset to start limiting from - * - * @param int $offset Offset to seek to and begin byte limiting from - * - * @return self - * @throws SeekException - */ - public function setOffset($offset) - { - $current = $this->stream->tell(); - - if ($current !== $offset) { - // If the stream cannot seek to the offset position, then read to it - if (!$this->stream->seek($offset)) { - if ($current > $offset) { - throw new SeekException($this, $offset); - } else { - $this->stream->read($offset - $current); - } - } - } - - $this->offset = $offset; - - return $this; - } - - /** - * Set the limit of bytes that the decorator allows to be read from the - * stream. - * - * @param int $limit Number of bytes to allow to be read from the stream. - * Use -1 for no limit. - * @return self - */ - public function setLimit($limit) - { - $this->limit = $limit; - - return $this; - } - - public function read($length) - { - if ($this->limit == -1) { - return $this->stream->read($length); - } - - // Check if the current position is less than the total allowed - // bytes + original offset - $remaining = ($this->offset + $this->limit) - $this->stream->tell(); - if ($remaining > 0) { - // Only return the amount of requested data, ensuring that the byte - // limit is not exceeded - return $this->stream->read(min($remaining, $length)); - } else { - return false; - } - } -} diff --git a/vendor/guzzlehttp/streams/src/MetadataStreamInterface.php b/vendor/guzzlehttp/streams/src/MetadataStreamInterface.php deleted file mode 100644 index c1433ad..0000000 --- a/vendor/guzzlehttp/streams/src/MetadataStreamInterface.php +++ /dev/null @@ -1,11 +0,0 @@ -stream->attach($stream); - } -} diff --git a/vendor/guzzlehttp/streams/src/NullStream.php b/vendor/guzzlehttp/streams/src/NullStream.php deleted file mode 100644 index 41ee776..0000000 --- a/vendor/guzzlehttp/streams/src/NullStream.php +++ /dev/null @@ -1,78 +0,0 @@ -source = $source; - $this->size = isset($options['size']) ? $options['size'] : null; - $this->metadata = isset($options['metadata']) ? $options['metadata'] : []; - $this->buffer = new BufferStream(); - } - - public function __toString() - { - return Utils::copyToString($this); - } - - public function close() - { - $this->detach(); - } - - public function detach() - { - $this->tellPos = false; - $this->source = null; - } - - public function attach($stream) - { - throw new CannotAttachException(); - } - - public function getSize() - { - return $this->size; - } - - public function tell() - { - return $this->tellPos; - } - - public function eof() - { - return !$this->source; - } - - public function isSeekable() - { - return false; - } - - public function seek($offset, $whence = SEEK_SET) - { - return false; - } - - public function isWritable() - { - return false; - } - - public function write($string) - { - return false; - } - - public function isReadable() - { - return true; - } - - public function read($length) - { - $data = $this->buffer->read($length); - $readLen = strlen($data); - $this->tellPos += $readLen; - $remaining = $length - $readLen; - - if ($remaining) { - $this->pump($remaining); - $data .= $this->buffer->read($remaining); - $this->tellPos += strlen($data) - $readLen; - } - - return $data; - } - - public function getContents() - { - $result = ''; - while (!$this->eof()) { - $result .= $this->read(1000000); - } - - return $result; - } - - public function getMetadata($key = null) - { - if (!$key) { - return $this->metadata; - } - - return isset($this->metadata[$key]) ? $this->metadata[$key] : null; - } - - private function pump($length) - { - if ($this->source) { - do { - $data = call_user_func($this->source, $length); - if ($data === false || $data === null) { - $this->source = null; - return; - } - $this->buffer->write($data); - $length -= strlen($data); - } while ($length > 0); - } - } -} diff --git a/vendor/guzzlehttp/streams/src/Stream.php b/vendor/guzzlehttp/streams/src/Stream.php deleted file mode 100644 index 7adbc5e..0000000 --- a/vendor/guzzlehttp/streams/src/Stream.php +++ /dev/null @@ -1,261 +0,0 @@ - [ - 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true, - 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, - 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true, - 'x+t' => true, 'c+t' => true, 'a+' => true - ], - 'write' => [ - 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, - 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true, - 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true, - 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true - ] - ]; - - /** - * Create a new stream based on the input type. - * - * This factory accepts the same associative array of options as described - * in the constructor. - * - * @param resource|string|StreamInterface $resource Entity body data - * @param array $options Additional options - * - * @return Stream - * @throws \InvalidArgumentException if the $resource arg is not valid. - */ - public static function factory($resource = '', array $options = []) - { - $type = gettype($resource); - - if ($type == 'string') { - $stream = fopen('php://temp', 'r+'); - if ($resource !== '') { - fwrite($stream, $resource); - fseek($stream, 0); - } - return new self($stream, $options); - } - - if ($type == 'resource') { - return new self($resource, $options); - } - - if ($resource instanceof StreamInterface) { - return $resource; - } - - if ($type == 'object' && method_exists($resource, '__toString')) { - return self::factory((string) $resource, $options); - } - - if (is_callable($resource)) { - return new PumpStream($resource, $options); - } - - if ($resource instanceof \Iterator) { - return new PumpStream(function () use ($resource) { - if (!$resource->valid()) { - return false; - } - $result = $resource->current(); - $resource->next(); - return $result; - }, $options); - } - - throw new \InvalidArgumentException('Invalid resource type: ' . $type); - } - - /** - * This constructor accepts an associative array of options. - * - * - size: (int) If a read stream would otherwise have an indeterminate - * size, but the size is known due to foreknownledge, then you can - * provide that size, in bytes. - * - metadata: (array) Any additional metadata to return when the metadata - * of the stream is accessed. - * - * @param resource $stream Stream resource to wrap. - * @param array $options Associative array of options. - * - * @throws \InvalidArgumentException if the stream is not a stream resource - */ - public function __construct($stream, $options = []) - { - if (!is_resource($stream)) { - throw new \InvalidArgumentException('Stream must be a resource'); - } - - if (isset($options['size'])) { - $this->size = $options['size']; - } - - $this->customMetadata = isset($options['metadata']) - ? $options['metadata'] - : []; - - $this->attach($stream); - } - - /** - * Closes the stream when the destructed - */ - public function __destruct() - { - $this->close(); - } - - public function __toString() - { - if (!$this->stream) { - return ''; - } - - $this->seek(0); - - return (string) stream_get_contents($this->stream); - } - - public function getContents() - { - return $this->stream ? stream_get_contents($this->stream) : ''; - } - - public function close() - { - if (is_resource($this->stream)) { - fclose($this->stream); - } - - $this->detach(); - } - - public function detach() - { - $result = $this->stream; - $this->stream = $this->size = $this->uri = null; - $this->readable = $this->writable = $this->seekable = false; - - return $result; - } - - public function attach($stream) - { - $this->stream = $stream; - $meta = stream_get_meta_data($this->stream); - $this->seekable = $meta['seekable']; - $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]); - $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]); - $this->uri = $this->getMetadata('uri'); - } - - public function getSize() - { - if ($this->size !== null) { - return $this->size; - } - - if (!$this->stream) { - return null; - } - - // Clear the stat cache if the stream has a URI - if ($this->uri) { - clearstatcache(true, $this->uri); - } - - $stats = fstat($this->stream); - if (isset($stats['size'])) { - $this->size = $stats['size']; - return $this->size; - } - - return null; - } - - public function isReadable() - { - return $this->readable; - } - - public function isWritable() - { - return $this->writable; - } - - public function isSeekable() - { - return $this->seekable; - } - - public function eof() - { - return !$this->stream || feof($this->stream); - } - - public function tell() - { - return $this->stream ? ftell($this->stream) : false; - } - - public function setSize($size) - { - $this->size = $size; - - return $this; - } - - public function seek($offset, $whence = SEEK_SET) - { - return $this->seekable - ? fseek($this->stream, $offset, $whence) === 0 - : false; - } - - public function read($length) - { - return $this->readable ? fread($this->stream, $length) : false; - } - - public function write($string) - { - // We can't know the size after writing anything - $this->size = null; - - return $this->writable ? fwrite($this->stream, $string) : false; - } - - public function getMetadata($key = null) - { - if (!$this->stream) { - return $key ? null : []; - } elseif (!$key) { - return $this->customMetadata + stream_get_meta_data($this->stream); - } elseif (isset($this->customMetadata[$key])) { - return $this->customMetadata[$key]; - } - - $meta = stream_get_meta_data($this->stream); - - return isset($meta[$key]) ? $meta[$key] : null; - } -} diff --git a/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php b/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php deleted file mode 100644 index 39c19c5..0000000 --- a/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php +++ /dev/null @@ -1,143 +0,0 @@ -stream = $stream; - } - - /** - * Magic method used to create a new stream if streams are not added in - * the constructor of a decorator (e.g., LazyOpenStream). - */ - public function __get($name) - { - if ($name == 'stream') { - $this->stream = $this->createStream(); - return $this->stream; - } - - throw new \UnexpectedValueException("$name not found on class"); - } - - public function __toString() - { - try { - $this->seek(0); - return $this->getContents(); - } catch (\Exception $e) { - // Really, PHP? https://bugs.php.net/bug.php?id=53648 - trigger_error('StreamDecorator::__toString exception: ' - . (string) $e, E_USER_ERROR); - return ''; - } - } - - public function getContents() - { - return Utils::copyToString($this); - } - - /** - * Allow decorators to implement custom methods - * - * @param string $method Missing method name - * @param array $args Method arguments - * - * @return mixed - */ - public function __call($method, array $args) - { - $result = call_user_func_array(array($this->stream, $method), $args); - - // Always return the wrapped object if the result is a return $this - return $result === $this->stream ? $this : $result; - } - - public function close() - { - $this->stream->close(); - } - - public function getMetadata($key = null) - { - return $this->stream->getMetadata($key); - } - - public function detach() - { - return $this->stream->detach(); - } - - public function attach($stream) - { - throw new CannotAttachException(); - } - - public function getSize() - { - return $this->stream->getSize(); - } - - public function eof() - { - return $this->stream->eof(); - } - - public function tell() - { - return $this->stream->tell(); - } - - public function isReadable() - { - return $this->stream->isReadable(); - } - - public function isWritable() - { - return $this->stream->isWritable(); - } - - public function isSeekable() - { - return $this->stream->isSeekable(); - } - - public function seek($offset, $whence = SEEK_SET) - { - return $this->stream->seek($offset, $whence); - } - - public function read($length) - { - return $this->stream->read($length); - } - - public function write($string) - { - return $this->stream->write($string); - } - - /** - * Implement in subclasses to dynamically create streams when requested. - * - * @return StreamInterface - * @throws \BadMethodCallException - */ - protected function createStream() - { - throw new \BadMethodCallException('createStream() not implemented in ' - . get_class($this)); - } -} diff --git a/vendor/guzzlehttp/streams/src/StreamInterface.php b/vendor/guzzlehttp/streams/src/StreamInterface.php deleted file mode 100644 index fd19c6f..0000000 --- a/vendor/guzzlehttp/streams/src/StreamInterface.php +++ /dev/null @@ -1,159 +0,0 @@ -eof()) { - $buf = $stream->read(1048576); - if ($buf === false) { - break; - } - $buffer .= $buf; - } - return $buffer; - } - - $len = 0; - while (!$stream->eof() && $len < $maxLen) { - $buf = $stream->read($maxLen - $len); - if ($buf === false) { - break; - } - $buffer .= $buf; - $len = strlen($buffer); - } - - return $buffer; - } - - /** - * Copy the contents of a stream into another stream until the given number - * of bytes have been read. - * - * @param StreamInterface $source Stream to read from - * @param StreamInterface $dest Stream to write to - * @param int $maxLen Maximum number of bytes to read. Pass -1 - * to read the entire stream. - */ - public static function copyToStream( - StreamInterface $source, - StreamInterface $dest, - $maxLen = -1 - ) { - if ($maxLen === -1) { - while (!$source->eof()) { - if (!$dest->write($source->read(1048576))) { - break; - } - } - return; - } - - $bytes = 0; - while (!$source->eof()) { - $buf = $source->read($maxLen - $bytes); - if (!($len = strlen($buf))) { - break; - } - $bytes += $len; - $dest->write($buf); - if ($bytes == $maxLen) { - break; - } - } - } - - /** - * Calculate a hash of a Stream - * - * @param StreamInterface $stream Stream to calculate the hash for - * @param string $algo Hash algorithm (e.g. md5, crc32, etc) - * @param bool $rawOutput Whether or not to use raw output - * - * @return string Returns the hash of the stream - * @throws SeekException - */ - public static function hash( - StreamInterface $stream, - $algo, - $rawOutput = false - ) { - $pos = $stream->tell(); - - if ($pos > 0 && !$stream->seek(0)) { - throw new SeekException($stream); - } - - $ctx = hash_init($algo); - while (!$stream->eof()) { - hash_update($ctx, $stream->read(1048576)); - } - - $out = hash_final($ctx, (bool) $rawOutput); - $stream->seek($pos); - - return $out; - } - - /** - * Read a line from the stream up to the maximum allowed buffer length - * - * @param StreamInterface $stream Stream to read from - * @param int $maxLength Maximum buffer length - * - * @return string|bool - */ - public static function readline(StreamInterface $stream, $maxLength = null) - { - $buffer = ''; - $size = 0; - - while (!$stream->eof()) { - if (false === ($byte = $stream->read(1))) { - return $buffer; - } - $buffer .= $byte; - // Break when a new line is found or the max length - 1 is reached - if ($byte == PHP_EOL || ++$size == $maxLength - 1) { - break; - } - } - - return $buffer; - } - - /** - * Alias of GuzzleHttp\Stream\Stream::factory. - * - * @param mixed $resource Resource to create - * @param array $options Associative array of stream options defined in - * {@see \GuzzleHttp\Stream\Stream::__construct} - * - * @return StreamInterface - * - * @see GuzzleHttp\Stream\Stream::factory - * @see GuzzleHttp\Stream\Stream::__construct - */ - public static function create($resource, array $options = []) - { - return Stream::factory($resource, $options); - } -} diff --git a/vendor/ircmaxell/password-compat/LICENSE.md b/vendor/ircmaxell/password-compat/LICENSE.md deleted file mode 100644 index 1efc565..0000000 --- a/vendor/ircmaxell/password-compat/LICENSE.md +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (c) 2012 Anthony Ferrara - -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. \ No newline at end of file diff --git a/vendor/ircmaxell/password-compat/composer.json b/vendor/ircmaxell/password-compat/composer.json deleted file mode 100644 index 822fd1f..0000000 --- a/vendor/ircmaxell/password-compat/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ircmaxell/password-compat", - "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash", - "keywords": ["password", "hashing"], - "homepage": "https://github.com/ircmaxell/password_compat", - "license": "MIT", - "authors": [ - { - "name": "Anthony Ferrara", - "email": "ircmaxell@php.net", - "homepage": "http://blog.ircmaxell.com" - } - ], - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "autoload": { - "files": ["lib/password.php"] - } -} diff --git a/vendor/ircmaxell/password-compat/lib/password.php b/vendor/ircmaxell/password-compat/lib/password.php deleted file mode 100644 index cc6896c..0000000 --- a/vendor/ircmaxell/password-compat/lib/password.php +++ /dev/null @@ -1,314 +0,0 @@ - - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @copyright 2012 The Authors - */ - -namespace { - - if (!defined('PASSWORD_BCRYPT')) { - /** - * PHPUnit Process isolation caches constants, but not function declarations. - * So we need to check if the constants are defined separately from - * the functions to enable supporting process isolation in userland - * code. - */ - define('PASSWORD_BCRYPT', 1); - define('PASSWORD_DEFAULT', PASSWORD_BCRYPT); - define('PASSWORD_BCRYPT_DEFAULT_COST', 10); - } - - if (!function_exists('password_hash')) { - - /** - * Hash the password using the specified algorithm - * - * @param string $password The password to hash - * @param int $algo The algorithm to use (Defined by PASSWORD_* constants) - * @param array $options The options for the algorithm to use - * - * @return string|false The hashed password, or false on error. - */ - function password_hash($password, $algo, array $options = array()) { - if (!function_exists('crypt')) { - trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING); - return null; - } - if (is_null($password) || is_int($password)) { - $password = (string) $password; - } - if (!is_string($password)) { - trigger_error("password_hash(): Password must be a string", E_USER_WARNING); - return null; - } - if (!is_int($algo)) { - trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING); - return null; - } - $resultLength = 0; - switch ($algo) { - case PASSWORD_BCRYPT: - $cost = PASSWORD_BCRYPT_DEFAULT_COST; - if (isset($options['cost'])) { - $cost = $options['cost']; - if ($cost < 4 || $cost > 31) { - trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING); - return null; - } - } - // The length of salt to generate - $raw_salt_len = 16; - // The length required in the final serialization - $required_salt_len = 22; - $hash_format = sprintf("$2y$%02d$", $cost); - // The expected length of the final crypt() output - $resultLength = 60; - break; - default: - trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING); - return null; - } - $salt_requires_encoding = false; - if (isset($options['salt'])) { - switch (gettype($options['salt'])) { - case 'NULL': - case 'boolean': - case 'integer': - case 'double': - case 'string': - $salt = (string) $options['salt']; - break; - case 'object': - if (method_exists($options['salt'], '__tostring')) { - $salt = (string) $options['salt']; - break; - } - case 'array': - case 'resource': - default: - trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING); - return null; - } - if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) { - trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING); - return null; - } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) { - $salt_requires_encoding = true; - } - } else { - $buffer = ''; - $buffer_valid = false; - if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) { - $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM); - if ($buffer) { - $buffer_valid = true; - } - } - if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) { - $buffer = openssl_random_pseudo_bytes($raw_salt_len); - if ($buffer) { - $buffer_valid = true; - } - } - if (!$buffer_valid && @is_readable('/dev/urandom')) { - $f = fopen('/dev/urandom', 'r'); - $read = PasswordCompat\binary\_strlen($buffer); - while ($read < $raw_salt_len) { - $buffer .= fread($f, $raw_salt_len - $read); - $read = PasswordCompat\binary\_strlen($buffer); - } - fclose($f); - if ($read >= $raw_salt_len) { - $buffer_valid = true; - } - } - if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) { - $bl = PasswordCompat\binary\_strlen($buffer); - for ($i = 0; $i < $raw_salt_len; $i++) { - if ($i < $bl) { - $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255)); - } else { - $buffer .= chr(mt_rand(0, 255)); - } - } - } - $salt = $buffer; - $salt_requires_encoding = true; - } - if ($salt_requires_encoding) { - // encode string with the Base64 variant used by crypt - $base64_digits = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - $bcrypt64_digits = - './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - - $base64_string = base64_encode($salt); - $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits); - } - $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len); - - $hash = $hash_format . $salt; - - $ret = crypt($password, $hash); - - if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) { - return false; - } - - return $ret; - } - - /** - * Get information about the password hash. Returns an array of the information - * that was used to generate the password hash. - * - * array( - * 'algo' => 1, - * 'algoName' => 'bcrypt', - * 'options' => array( - * 'cost' => PASSWORD_BCRYPT_DEFAULT_COST, - * ), - * ) - * - * @param string $hash The password hash to extract info from - * - * @return array The array of information about the hash. - */ - function password_get_info($hash) { - $return = array( - 'algo' => 0, - 'algoName' => 'unknown', - 'options' => array(), - ); - if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) { - $return['algo'] = PASSWORD_BCRYPT; - $return['algoName'] = 'bcrypt'; - list($cost) = sscanf($hash, "$2y$%d$"); - $return['options']['cost'] = $cost; - } - return $return; - } - - /** - * Determine if the password hash needs to be rehashed according to the options provided - * - * If the answer is true, after validating the password using password_verify, rehash it. - * - * @param string $hash The hash to test - * @param int $algo The algorithm used for new password hashes - * @param array $options The options array passed to password_hash - * - * @return boolean True if the password needs to be rehashed. - */ - function password_needs_rehash($hash, $algo, array $options = array()) { - $info = password_get_info($hash); - if ($info['algo'] != $algo) { - return true; - } - switch ($algo) { - case PASSWORD_BCRYPT: - $cost = isset($options['cost']) ? $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST; - if ($cost != $info['options']['cost']) { - return true; - } - break; - } - return false; - } - - /** - * Verify a password against a hash using a timing attack resistant approach - * - * @param string $password The password to verify - * @param string $hash The hash to verify against - * - * @return boolean If the password matches the hash - */ - function password_verify($password, $hash) { - if (!function_exists('crypt')) { - trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING); - return false; - } - $ret = crypt($password, $hash); - if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) { - return false; - } - - $status = 0; - for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) { - $status |= (ord($ret[$i]) ^ ord($hash[$i])); - } - - return $status === 0; - } - } - -} - -namespace PasswordCompat\binary { - - if (!function_exists('PasswordCompat\\binary\\_strlen')) { - - /** - * Count the number of bytes in a string - * - * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension. - * In this case, strlen() will count the number of *characters* based on the internal encoding. A - * sequence of bytes might be regarded as a single multibyte character. - * - * @param string $binary_string The input string - * - * @internal - * @return int The number of bytes - */ - function _strlen($binary_string) { - if (function_exists('mb_strlen')) { - return mb_strlen($binary_string, '8bit'); - } - return strlen($binary_string); - } - - /** - * Get a substring based on byte limits - * - * @see _strlen() - * - * @param string $binary_string The input string - * @param int $start - * @param int $length - * - * @internal - * @return string The substring - */ - function _substr($binary_string, $start, $length) { - if (function_exists('mb_substr')) { - return mb_substr($binary_string, $start, $length, '8bit'); - } - return substr($binary_string, $start, $length); - } - - /** - * Check if current PHP version is compatible with the library - * - * @return boolean the check result - */ - function check() { - static $pass = NULL; - - if (is_null($pass)) { - if (function_exists('crypt')) { - $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG'; - $test = crypt("password", $hash); - $pass = $test == $hash; - } else { - $pass = false; - } - } - return $pass; - } - - } -} \ No newline at end of file diff --git a/vendor/ircmaxell/password-compat/version-test.php b/vendor/ircmaxell/password-compat/version-test.php deleted file mode 100644 index 96f60ca..0000000 --- a/vendor/ircmaxell/password-compat/version-test.php +++ /dev/null @@ -1,6 +0,0 @@ - composer-installer.php - hhvm composer-installer.php - hhvm -v ResourceLimit.SocketDefaultTimeout=30 -v Http.SlowQueryThreshold=30000 composer.phar update --prefer-source - hhvm -v ResourceLimit.SocketDefaultTimeout=30 -v Http.SlowQueryThreshold=30000 composer.phar install --dev --prefer-source -else - composer self-update - composer update --prefer-source - composer install --dev --prefer-source -fi diff --git a/vendor/ocramius/proxy-manager/.travis.yml b/vendor/ocramius/proxy-manager/.travis.yml deleted file mode 100644 index 5f42dac..0000000 --- a/vendor/ocramius/proxy-manager/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: php - -php: - - 5.3.3 - - 5.3 - - 5.4 - - 5.5 - - 5.6 - - hhvm - - hhvm-nightly - -before_script: - - sh .travis.install.sh - -script: - - ./vendor/bin/phpunit --disallow-test-output --report-useless-tests --coverage-clover ./clover.xml --group=Coverage - - ./vendor/bin/phpunit --disallow-test-output --report-useless-tests --strict --exclude-group=Performance,Coverage - - php -n ./vendor/bin/phpunit --group=Performance - - ./vendor/bin/phpcs --standard=PSR2 ./src/ ./tests/ - -matrix: - allow_failures: - - php: hhvm - - php: hhvm-nightly - -after_script: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover ./clover.xml diff --git a/vendor/ocramius/proxy-manager/CONTRIBUTING.md b/vendor/ocramius/proxy-manager/CONTRIBUTING.md deleted file mode 100644 index d07d8dc..0000000 --- a/vendor/ocramius/proxy-manager/CONTRIBUTING.md +++ /dev/null @@ -1,35 +0,0 @@ -# Contributing - - * Coding standard for the project is [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) - * The project will follow strict [object calisthenics](http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php) - * Any contribution must provide tests for additional introduced conditions - * Any un-confirmed issue needs a failing test case before being accepted - * Pull requests must be sent from a new hotfix/feature branch, not from `master`. - -## Installation - -To install the project and run the tests, you need to clone it first: - -```sh -$ git clone git://github.com/Ocramius/ProxyManager.git -``` - -You will then need to run a composer installation: - -```sh -$ cd ProxyManager -$ curl -s https://getcomposer.org/installer | php -$ php composer.phar update -``` - -## Testing - -The PHPUnit version to be used is the one installed as a dev- dependency via composer: - -```sh -$ ./vendor/bin/phpunit -``` - -Accepted coverage for new contributions is 80%. Any contribution not satisfying this requirement -won't be merged. - diff --git a/vendor/ocramius/proxy-manager/examples/access-interceptor-scope-localizer.php b/vendor/ocramius/proxy-manager/examples/access-interceptor-scope-localizer.php deleted file mode 100644 index eb1da5b..0000000 --- a/vendor/ocramius/proxy-manager/examples/access-interceptor-scope-localizer.php +++ /dev/null @@ -1,38 +0,0 @@ -counter += 1; - - return $this; - } -} - -$factory = new AccessInterceptorScopeLocalizerFactory(); -$foo = new FluentCounter(); - -/* @var $proxy FluentCounter */ -$proxy = $factory->createProxy( - $foo, - array('fluentMethod' => function ($proxy) { echo "pre-fluentMethod #{$proxy->counter}!\n"; }), - array('fluentMethod' => function ($proxy) { echo "post-fluentMethod #{$proxy->counter}!\n"; }) -); - -$proxy->fluentMethod()->fluentMethod()->fluentMethod()->fluentMethod(); - -echo 'The proxy counter is now at ' . $proxy->counter . "\n"; -echo 'The real instance counter is now at ' . $foo->counter . "\n"; diff --git a/vendor/ocramius/proxy-manager/examples/ghost-object.php b/vendor/ocramius/proxy-manager/examples/ghost-object.php deleted file mode 100644 index b4ec216..0000000 --- a/vendor/ocramius/proxy-manager/examples/ghost-object.php +++ /dev/null @@ -1,46 +0,0 @@ -foo = (string) $foo; - } - - public function getFoo() - { - return $this->foo; - } -} - -$startTime = microtime(true); -$factory = new LazyLoadingGhostFactory(); - -for ($i = 0; $i < 1000; $i += 1) { - $proxy = $factory->createProxy( - 'Foo', - function ($proxy, $method, $parameters, & $initializer) { - $initializer = null; - $proxy->setFoo('Hello World!'); - - return true; - } - ); -} - -var_dump('time after 1000 instantiations: ' . (microtime(true) - $startTime)); - -echo $proxy->getFoo() . "\n"; - -var_dump('time after single call to doFoo: ' . (microtime(true) - $startTime)); diff --git a/vendor/ocramius/proxy-manager/examples/remote-proxy.php b/vendor/ocramius/proxy-manager/examples/remote-proxy.php deleted file mode 100644 index 97025fc..0000000 --- a/vendor/ocramius/proxy-manager/examples/remote-proxy.php +++ /dev/null @@ -1,36 +0,0 @@ -createProxy('Foo'); - -try { - var_dump($proxy->bar()); // bar remote ! -} catch (\Zend\Http\Client\Adapter\Exception\RuntimeException $error) { - echo "To run this example, please following before:\n\n\$ php -S localhost:9876 -t \"" . __DIR__ . "\"\n"; - - exit(2); -} diff --git a/vendor/ocramius/proxy-manager/examples/remote-proxy/remote-proxy-server.php b/vendor/ocramius/proxy-manager/examples/remote-proxy/remote-proxy-server.php deleted file mode 100644 index 81a742f..0000000 --- a/vendor/ocramius/proxy-manager/examples/remote-proxy/remote-proxy-server.php +++ /dev/null @@ -1,20 +0,0 @@ -setClass(new Foo(), 'Foo'); -$server->setReturnResponse(false); - -$server->handle(); diff --git a/vendor/ocramius/proxy-manager/examples/smart-reference.php b/vendor/ocramius/proxy-manager/examples/smart-reference.php deleted file mode 100644 index 8c00a3a..0000000 --- a/vendor/ocramius/proxy-manager/examples/smart-reference.php +++ /dev/null @@ -1,23 +0,0 @@ -createProxy( - new Foo(), - array('doFoo' => function () { echo "pre-foo!\n"; }), - array('doFoo' => function () { echo "post-foo!\n"; }) -); - -$proxy->doFoo(); diff --git a/vendor/ocramius/proxy-manager/examples/virtual-proxy.php b/vendor/ocramius/proxy-manager/examples/virtual-proxy.php deleted file mode 100644 index 7ee6b2e..0000000 --- a/vendor/ocramius/proxy-manager/examples/virtual-proxy.php +++ /dev/null @@ -1,39 +0,0 @@ -createProxy( - 'Foo', - function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) { - $initializer = null; - $wrappedObject = new Foo(); - - return true; - } - ); -} - -var_dump('time after 1000 instantiations: ' . (microtime(true) - $startTime)); - -$proxy->doFoo(); - -var_dump('time after single call to doFoo: ' . (microtime(true) - $startTime)); diff --git a/vendor/ocramius/proxy-manager/html-docs/access-interceptor-scope-localizer-proxy.html b/vendor/ocramius/proxy-manager/html-docs/access-interceptor-scope-localizer-proxy.html deleted file mode 100644 index dac8c93..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/access-interceptor-scope-localizer-proxy.html +++ /dev/null @@ -1,197 +0,0 @@ - - - - ProxyManager - Tuning the ProxyManager for production - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Access Interceptor Scope Localizer Proxy

- -

An access interceptor scope localizer is a smart reference proxy that allows you to dynamically define logic to be executed before or after any of the proxied object's methods' logic.

- -

It works exactly like the access interceptor value holder, with some minor differences in behavior.

- -

The working concept of an access interceptor scope localizer is to localize scope of a proxied object:

- -
-        
-class Example
-{
-    protected $foo;
-    protected $bar;
-    protected $baz;
-
-    public function doFoo()
-    {
-        // ...
-    }
-}
-
-class ExampleProxy extends Example
-{
-    public function __construct(Example $example)
-    {
-        $this->foo = & $example->foo;
-        $this->bar = & $example->bar;
-        $this->baz = & $example->baz;
-    }
-
-    public function doFoo()
-    {
-        return parent::doFoo();
-    }
-}
-        
-    
- -

This allows to create a mirror copy of the real instance, where any change in the proxy or in the real instance is reflected in both objects.

- -

The main advantage of this approach is that the proxy is now safe against fluent interfaces, which would break an access interceptor value holder instead.

-
-

Differences with access interceptor value holder:

- -
    -
  • It does NOT implement the ProxyManager\Proxy\ValueHolderInterface, since the proxy itself does not keep a reference to the original object being proxied
  • -
  • In all interceptor methods (see access interceptor value holder), the $instance passed in is the proxy itself. There is no way to gather a reference to the original object right now, and that's mainly to protect from misuse.
  • -
-
- -

Known limitations

- -
    -
  • It is NOT possible to intercept access to public properties
  • -
  • It is NOT possible to proxy interfaces, since this proxy relies on parent::method() calls. Interfaces obviously don't provide a parent method implementation.
  • -
  • calling unset on a property of an access interceptor scope localizer (or the real instance) will cause the two objects to be un-synchronized, with possible unexpected behaviour.
  • -
  • serializing or un-serializing an access interceptor scope localizer (or the real instance) will not cause the real instance (or the proxy) to be serialized or un-serialized
  • -
  • if a proxied object contains private properties, then an exception will be thrown if you use PHP < 5.4.0.
  • -
-
-

Example

- -

Here's an example of how you can create and use an access interceptor scope localizer :

- -
-        
-<?php
-
-use ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory as Factory;
-
-require_once __DIR__ . '/vendor/autoload.php';
-
-class Foo
-{
-    public function doFoo()
-    {
-        echo "Foo!\n";
-    }
-}
-
-$factory = new Factory();
-
-$proxy = $factory->createProxy(
-    new Foo(),
-    array('doFoo' => function () { echo "PreFoo!\n"; }),
-    array('doFoo' => function () { echo "PostFoo!\n"; })
-);
-
-$proxy->doFoo();
-        
-    
- -

This send something like following to your output:

- -
-        
-PreFoo!
-Foo!
-PostFoo!
-        
-    
- -

This is pretty much the same logic that you can find in access interceptor value holder.

- -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/access-interceptor-value-holder-proxy.html b/vendor/ocramius/proxy-manager/html-docs/access-interceptor-value-holder-proxy.html deleted file mode 100644 index b98e95a..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/access-interceptor-value-holder-proxy.html +++ /dev/null @@ -1,208 +0,0 @@ - - - - ProxyManager - Tuning the ProxyManager for production - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Access Interceptor Value Holder Proxy

- -

An access interceptor value holder is a smart reference proxy that allows you to dynamically define logic to be executed before or after any of the wrapped object's methods logic.

- -

It wraps around a real instance of the object to be proxied, and can be useful for things like:

- -
    -
  • caching execution of slow and heavy methods
  • -
  • log method calls
  • -
  • debugging
  • -
  • event triggering
  • -
  • handling of orthogonal logic, and AOP in general
  • -
-
-

Example

- -

Here's an example of how you can create and use an access interceptor value holder:

- -
-        
-<?php
-
-use ProxyManager\Factory\AccessInterceptorValueHolderFactory as Factory;
-
-require_once __DIR__ . '/vendor/autoload.php';
-
-class Foo
-{
-    public function doFoo()
-    {
-        echo "Foo!\n";
-    }
-}
-
-$factory = new Factory();
-
-$proxy = $factory->createProxy(
-    new Foo(),
-    array('doFoo' => function () { echo "PreFoo!\n"; }),
-    array('doFoo' => function () { echo "PostFoo!\n"; })
-);
-
-$proxy->doFoo();
-        
-    
- -

This send something like following to your output:

- -
-        
-PreFoo!
-Foo!
-PostFoo!
-        
-    
- -
-

Implementing pre- and post- access interceptors

- -

A proxy produced by the ProxyManager\Factory\AccessInterceptorValueHolderFactory implements both the ProxyManager\Proxy\ValueHolderInterface and the ProxyManager\Proxy\AccessInterceptorInterface.

- - -

Therefore, you can set an access interceptor callback by calling:

- -
-        
-$proxy->setMethodPrefixInterceptor('methodName', function () { echo 'pre'; });
-$proxy->setMethodSuffixInterceptor('methodName', function () { echo 'post'; });
-        
-    
- -

You can also listen to public properties access by attaching interceptors to __get, __set, __isset and __unset.

- -

A prefix interceptor (executed before method logic) should have following signature:

- -
-        
-/**
- * @var object $proxy       the proxy that intercepted the method call
- * @var object $instance    the wrapped instance within the proxy
- * @var string $method      name of the called method
- * @var array  $params      sorted array of parameters passed to the intercepted
- *                          method, indexed by parameter name
- * @var bool   $returnEarly flag to tell the interceptor proxy to return early, returning
- *                          the interceptor's return value instead of executing the method logic
- *
- * @return mixed
- */
-$prefixInterceptor = function ($proxy, $instance, $method, $params, & $returnEarly) {};
-        
-    
- - A suffix interceptor (executed after method logic) should have following signature: - -
-        
-/**
- * @var object $proxy       the proxy that intercepted the method call
- * @var object $instance    the wrapped instance within the proxy
- * @var string $method      name of the called method
- * @var array  $params      sorted array of parameters passed to the intercepted
- *                          method, indexed by parameter name
- * @var mixed  $returnValue the return value of the intercepted method
- * @var bool   $returnEarly flag to tell the proxy to return early, returning the interceptor's
- *                          return value instead of the value produced by the method
- *
- * @return mixed
- */
-$suffixInterceptor = function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) {};
-        
-    
- -
-

Tuning performance for production

- -

See Tuning ProxyManager for Production.

-
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/contributing.html b/vendor/ocramius/proxy-manager/html-docs/contributing.html deleted file mode 100644 index aa34320..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/contributing.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - ProxyManager - Contributing - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Contributing

- -
    -
  • Coding standard for the project is PSR-2
  • -
  • The project will follow strict object calisthenics
  • -
  • Any contribution must provide tests for additional introduced conditions
  • -
  • Any un-confirmed issue needs a failing test case before being accepted
  • -
  • Pull requests must be sent from a new hotfix/feature branch, not from master.
  • -
- - -
- -

Installation

- -

To install the project and run the tests, you need to clone it first:

- -
-        
-$ git clone git://github.com/Ocramius/ProxyManager.git
-            
-    
- -

You will then need to run a composer installation:

- -
-        
-$ cd ProxyManager
-$ curl -s https://getcomposer.org/installer | php
-$ php composer.phar update
-        
-    
- -
- -

Testing

- -

The PHPUnit version to be used is the one installed as a dev- dependency via composer:

- -
-        
-$ ./vendor/bin/phpunit
-        
-    
- -

Accepted coverage for new contributions is 80%. Any contribution not satisfying this requirement won't be merged.

- -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/copyright.html b/vendor/ocramius/proxy-manager/html-docs/copyright.html deleted file mode 100644 index 94f3fc7..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/copyright.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - ProxyManager - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

License

-

Copyright (c) 2013 Marco Pivetta

- -

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.

-
- -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/credits.html b/vendor/ocramius/proxy-manager/html-docs/credits.html deleted file mode 100644 index 33f78d2..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/credits.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - ProxyManager - Credits - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/css/styles.css b/vendor/ocramius/proxy-manager/html-docs/css/styles.css deleted file mode 100644 index ca49812..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/css/styles.css +++ /dev/null @@ -1,203 +0,0 @@ -html { font-family: sans-serif; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } -body { margin: 0; } -article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; } -audio, canvas, progress, video { display: inline-block; vertical-align: baseline; } -audio:not([controls]) { display: none; height: 0; } -[hidden], template { display: none; } -a { background: transparent; } -a:active, a:hover { outline: 0; } -abbr[title] { border-bottom: 1px dotted; } -b, strong { font-weight: bold; } -dfn { font-style: italic; } -h1 { font-size: 2em; margin: 0.67em 0; } -mark { background: #ff0; color: #000; } -small { font-size: 80%; } -sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } -sup { top: -0.5em; } -sub { bottom: -0.25em; } -img { border: 0; } -svg:not(:root) { overflow: hidden; } -figure { margin: 1em 40px; } -hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; } -pre { overflow: auto; } -code, kbd, pre, samp { font-family: monospace, monospace; font-size: 1em; } -button, input, optgroup, select, textarea { color: inherit; font: inherit; margin: 0; } -button { overflow: visible; } -button, select { text-transform: none; } -button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; cursor: pointer; } -button[disabled], html input[disabled] { cursor: default; } -button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } -input { line-height: normal; } -input[type="checkbox"], input[type="radio"] { box-sizing: border-box; padding: 0; } -input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { height: auto; } -input[type="search"] { -webkit-appearance: textfield; -moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; } -input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } -fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } -legend { border: 0; padding: 0; } -textarea { overflow: auto; } -optgroup { font-weight: bold; } -table { border-collapse: collapse; border-spacing: 0; } -td, th { padding: 0; } -h1, h2, h3, h4, h5, h6, p, ul, ol, li { margin: 0; padding: 0; line-height: normal; } -a { color: #31811D; text-decoration: none; } -a:hover { color: #2F611C; text-decoration: none; } -strong { font-weight: 600; } -h3 { margin-bottom: 1em; color: #17324f; font-weight: 400; font-size: 3em; } -h4 { margin-bottom: 1em; font-weight: 400; font-size: 1.375em; } -p { margin-bottom: 1.5em; font-size: 1.125em; } -hr { margin: 2.5em 0; padding: 0; width: 100%; height: 3px; border: 0; background: #e6eaef; } -pre code { padding: 20px; border: 1px solid #EBEBEB; background: #F5F5F5; color: #08468a; font-weight: 200; font-size: .875em; } -code { background: transparent; color: #08468a; font-size: .875em; } -form { margin: 0; } -label { display: block; color: #18324f; font-weight: 400; font-size: 1.5em; margin-bottom: 2em; } -legend { position: static; margin: 0; padding: 0; font-weight: normal; } -legend span { position: absolute; top: 0; right: 0; left: 0; display: block; padding: 7px 0; border-bottom: 1px solid #e0dede; color: #ed4a21; font-size: 18px; line-height: 1em; } - -/* Menu Sidebar*/ -.button-block { padding-top: 15px; } -.button-block .btn-1 { margin-right: 6px; } -.btn, .spy-nav a { position: relative; display: inline-block; margin: 0; padding: 0 20px; height: 57px; border: 0; vertical-align: top; text-align: center; text-transform: uppercase; font-weight: 400; font-size: 1.125em; transitionP: all .2s; line-height: 57px; } -.btn.btn-action, .spy-nav a.btn-action { background: #ee2d4d; color: #fff; } -.btn.btn-action:hover, .spy-nav a.btn-action:hover { background: #bf0f2d; } -.btn.btn-default, .spy-nav a { background: #31811D; color: #fff; } -.btn.btn-default:hover, .spy-nav a:hover { background: #2F611C; color: #fff; } -.btn.btn-text, .spy-nav a.btn-text { color: #18324f; font-weight: 600; } -.btn.btn-full, .spy-nav a { display: block; } -@media only screen and (max-width: 480px) { - .site-header{ position: fixed !important; top: 0; z-index: 999999} - .page-title-wrapper{ margin-top: 70px;} - .main-wrapper iframe{ width: 42% !important; float: left; margin-left: 8%;} - .content iframe{width: 100%; height: 100%;} -} - -.btn-top { position: relative; display: inline-block; float: right; margin: 20px 0 0; padding: 0 30px 0 50px; height: 57px; border: 2px solid ##31811D; color: #31811D; vertical-align: top; text-align: center; text-transform: uppercase; font-weight: 600; font-size: 1.125em; line-height: 53px; transition: all .2s; } -.btn-top:before { background-position: 0 -140px; width: 52px; height: 52px; position: absolute; top: 0; left: 0; content: ''; } -@media only screen and (min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 2) { .btn-top:before { background-position: 0 -140px; background-size: 152px auto; width: 52px; height: 52px; } } -.btn-top:hover { border-color: #2F611C; color: #2F611C; } -@media only screen and (max-width: 768px) { .btn-top { float: none; margin-top: 0; margin-bottom: 30px; white-space: nowrap; } } -@media only screen and (max-width: 480px) { .btn-top { font-size: 0.9em; line-height: 46px; height: 48px; padding-right: 22px; padding-left: 47px; } } - -.btn-download { float: right; padding-left: 50px; } -.btn-download:before { background-position: -18px -116px; width: 16px; height: 16px; position: absolute; top: 50%; left: 20px; margin-top: -7px; content: ''; } -@media only screen and (min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 2) { .btn-download:before { background-position: -18px -116px; background-size: 152px auto; width: 16px; height: 16px; } } - -.btn-done { float: right; padding-left: 50px; } -.btn-done:before { background-position: 0 -116px; width: 18px; height: 14px; position: absolute; top: 50%; margin-top: -7px; left: 20px; content: ''; } -@media only screen and (min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 2) { .btn-done:before { background-position: 0 -116px; background-size: 152px auto; width: 18px; height: 13.5px; margin-top: -6.75px; } } - -.btn-cancel { float: right; } - -*, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } - -html { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; min-width: 280px; } -@media only screen and (min-width: 64.063em) and (max-width: 90em) { html { min-width: 960px; } } - -body { font-size: 16px; font-family: 'Source Sans Pro', sans-serif; min-width: 290px; } -@media only screen and (max-width: 480px) { body.page-home { background-image: none; } } - -img { max-width: 100%; height: auto !important; } - -input { -webkit-appearance: none; -webkit-border-radius: 0; border-radius: 0; } - -main { overflow: hidden; } - -.clearfix:after { content: ""; display: table; clear: both; } - -.container { width: 60em; margin-left: auto; margin-right: auto; } -.container:after { content: " "; display: block; clear: both; } -@media only screen and (max-width: 1024px) { .container { margin-left: 15px; margin-right: 15px; width: auto; } } - -.content ul { padding-left: 19px; list-style-type: square; margin-top: 15px; } - -/* Menu top */ -.main-nav { float: right; } -.fixed-wrapper .main-nav { display: none; } -.active .main-nav { display: block; } -.main-nav > ul { list-style: none; } -.main-nav > ul > li { float: left; } -.main-nav > ul > li > a { display: block; padding: 22px 30px; color: #fff; text-decoration: none; text-transform: uppercase; font-weight: 600; font-size: 1.375em; line-height: 29px; transition: all .2s; } -.main-nav > ul > li > a:hover { color: #bfe5f1; background-color: #2F611C; } -.main-nav > ul > li > a.active { background-color: #2F611C; color: #fff; } -.main-nav > ul > li > a.opened { background-color: #18324f; } -@media only screen and (max-width: 600px) { .main-nav { font-size: 0.86em; } - .main-nav > ul > li > a { padding-left: 18px; padding-right: 18px; } } -@media only screen and (max-width: 480px) { .main-nav > ul > li > a { font-size: 0.95em; padding: 22px 6px; } } - -.site-header { position: relative; width: 100%; background: #31811D; } -.site-header h1 { float: left; margin: 15px 0; } -.site-header h1 a { display: block; } -.site-header h1 img { display: block; max-height: 42px; } -@media only screen and (max-width: 480px) { .site-header h1 img { max-height: 42px; } } - -.page-title-wrapper { position: relative; padding: 26px 0 55px; text-align: center; } -.page-title-wrapper .page-title { margin-top: 44px; color: #17324f; font-weight: 400; font-size: 3.75em; } -.page-title-wrapper .linguistics { padding: 0 2em 13px; border-bottom: 1px solid #D4DBE3; color: #18324f; text-transform: uppercase; font-weight: 400; font-size: 1.25em; } -@media only screen and (max-width: 768px) { .page-title-wrapper { font-size: 0.8em; } } -@media only screen and (max-width: 480px) { .page-title-wrapper { font-size: 0.65em; } } - -.site-footer { margin-top: 20px; padding-top: 50px; padding-bottom: 50px; background: #18324f; color: #7c8ea3; text-align: center; } -.site-footer .container { position: relative; } -.site-footer + .bcms-clearfix:after { content: ""; } -.about + .site-footer .main { padding-top: 150px; } -.footer-logos ul li{ list-style: none; display: inline-block;} -.footer-logos ul li a{ padding-left: 10px; padding-right: 10px} -.site-footer a{ color: white !important;} -.site-footer p { text-align: left; display: block; margin-bottom: 1.5em; font-size: 1.125em; } -@media only screen and (max-width: 1024px) { .site-footer p { margin-left: 0; } } -@media only screen and (max-width: 768px) { .site-footer p { text-align: center; margin-left: auto; } } -@media only screen and (max-width: 600px) { .site-footer { font-size: 0.9em; } } - -.main-logo { display: block; float: left; margin: 30px 0; } -.fixed-wrapper .main-logo { display: none; } -.main-logo img { display: block; } -.main-logo figure { position: relative; margin: 0; max-width: 56px; } -.main-logo figcaption { position: absolute; width: 160px; top: 20px; left: 68px; } -.active .main-logo { display: block; margin: 0; } -.active .main-logo figure { max-width: 42px; } -.active .main-logo figcaption { width: 120px; top: 15px; left: 55px; } -@media only screen and (max-width: 480px) { .main-logo figcaption { display: none; } } - -.container { width: 60em; margin-left: auto; margin-right: auto; } -.container:after { content: " "; display: block; clear: both; } -@media only screen and (max-width: 1024px) { .container { margin-left: 15px; margin-right: 15px; width: auto; } } - -.component-demo { position: relative; padding: 1px 0 0; background: #e6eaef; } -.component-demo:before { background-image: url("../img/enf.png"); } -@media only screen and (max-width: 480px) { .component-demo { padding: 40px 0 0; } } - -.component-info .container { position: relative; } -.component-info .sidebar { width: 220px; float: left; margin-top: 75px; } -.component-info .sidebar .component-meta { margin-top: 10px; font-size: 1.125em; } -.component-info .sidebar .component-meta span { white-space: nowrap; margin-bottom: 10px; padding-left: 25px; color: #18324f; } -.component-info .sidebar.sticky { position: fixed; margin-top: 38px; } -.component-info .content { width: 64.58333333%; float: right; margin-top: 60px; margin-bottom: 75px; } -.component-info .content h3 { margin-bottom: .75em; font-size: 2.75em; } -.component-info .content p { margin-bottom: 1.75em; line-height: 1.45; } -@media only screen and (max-width: 480px) { .component-info .content .section-title { font-size: 2.1em; } } -@media only screen and (max-width: 768px) { .component-info .sidebar { float: none; margin-left: auto; margin-right: auto; } - .component-info .sidebar .component-meta { margin-top: 30px; text-align: center; } - .component-info .sidebar.sticky { position: relative; margin-top: 75px; } - .component-info .content { float: none; width: 100%; } } -@media only screen and (max-width: 480px) { .component-info .content { margin-bottom: 0; } } - -.spy-nav { margin-bottom: 10px; } -.spy-nav ul { list-style: none; } -.spy-nav a { padding-top: 9px; padding-bottom: 10px; height: auto; border-bottom: 1px solid #4B8B20; text-align: left; text-transform: none; font-size: 1.375em; line-height: normal; } -.spy-nav .active a { border-bottom-color: #fff; background: #fff; color: #17324f; } -@media only screen and (max-width: 768px) { /*.spy-nav { display: none; } */} - -.main-wrapper { margin: 44px auto 44px; max-width: 600px; } -.main-wrapper label { display: block; margin-bottom: .75em; color: #3f4e5e; font-size: 1.25em; } -.main-wrapper .text-field { padding: 0 15px; width: 100%; height: 40px; border: 1px solid #CBD3DD; font-size: 1.125em; } -.main-wrapper ::-webkit-input-placeholder { color: #CBD3DD; font-style: italic; font-size: 18px; } -.main-wrapper :-moz-placeholder { color: #CBD3DD; font-style: italic; font-size: 18px; } -.main-wrapper ::-moz-placeholder { color: #CBD3DD; font-style: italic; font-size: 18px; } -.main-wrapper :-ms-input-placeholder { color: #CBD3DD; font-style: italic; font-size: 18px; } - -.page-icon-wrapper:before, .page-icon-wrapper .logo-asp:before, .page-icon-wrapper .logo-hibernate:before, .page-icon-wrapper .logo-angularjs:before, .page-icon-wrapper .logo-requirejs:before, .page-icon-wrapper .logo-reward:before, .component-demo:before {background-repeat: no-repeat; background-size: 100%; width: 92px; height: 108px; position: absolute; left: 50%; margin-left: -46px; top: 0; bottom: auto; margin-top: -28px; content: ''; } - -.container { width: 60em; margin-left: auto; margin-right: auto; } -.container:after { content: " "; display: block; clear: both; } -@media only screen and (max-width: 1024px) { .container { margin-left: 15px; margin-right: 15px; width: auto; } } - -.bcms-clearfix:after {content: ""; visibility: hidden; display: block; height: 0; clear: both; } diff --git a/vendor/ocramius/proxy-manager/html-docs/download.html b/vendor/ocramius/proxy-manager/html-docs/download.html deleted file mode 100644 index 4862ef3..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/download.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - ProxyManager - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Installation

-

The suggested installation method is via composer.

-
php composer.phar require ocramius/proxy-manager:1.0.*
-
- -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/favicon.ico b/vendor/ocramius/proxy-manager/html-docs/favicon.ico deleted file mode 100644 index 797ca03ca2873c95b28747e923d3a77a57784f0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173246 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 diff --git a/vendor/ocramius/proxy-manager/html-docs/ghost-object.html b/vendor/ocramius/proxy-manager/html-docs/ghost-object.html deleted file mode 100644 index ce7b2fc..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/ghost-object.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - ProxyManager - Ghost object - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Lazy Loading Ghost Object Proxies

- -

A lazy loading ghost object proxy is a ghost proxy that looks exactly like the real instance of the proxied subject, but which has all properties nulled before initialization.

-
- -

Lazy loading with the Ghost Object

- -

In pseudo-code, in userland, lazy loading in a ghost object looks like following:

- -
-        
-class MyObjectProxy
-{
-    private $initialized = false;
-    private $name;
-    private $surname;
-
-    public function doFoo()
-    {
-        $this->init();
-
-        // Perform doFoo routine using loaded variables
-    }
-
-    private function init()
-    {
-        if (! $this->initialized) {
-            $data          = some_logic_that_loads_data();
-
-            $this->name    = $data['name'];
-            $this->surname = $data['surname'];
-
-            $this->initialized = true;
-        }
-    }
-}
-        
-    
- -

Ghost objects work similarly to virtual proxies, but since they don't wrap around a "real" instance of the proxied subject, they are better suited for representing dataset rows.

- -
- -

When do I use a ghost object?

- -

You usually need a ghost object in cases where following applies

- -
    -
  • you are building a small data-mapper and want to lazily load data across associations in your object graph
  • -
  • you want to initialize objects representing rows in a large dataset
  • -
  • you want to compare instances of lazily initialized objects without the risk of comparing a proxy with a real subject
  • -
  • you are aware of the internal state of the object and are confident in working with its internals via reflection or direct property access
  • -
- -
- -

Usage examples

- -

ProxyManager provides a factory that creates lazy loading ghost objects. To use it, follow these steps:

- -

First of all, define your object's logic without taking care of lazy loading:

- -
-        
-namespace MyApp;
-
-class Customer
-{
-    private $name;
-    private $surname;
-
-    // just write your business logic or generally logic
-    // don't worry about how complex this object will be!
-    // don't code lazy-loading oriented optimizations in here!
-    public function getName() { return $this->name; }
-    public function setName($name) { $this->name = (string) $name; }
-    public function getSurname() { return $this->surname; }
-    public function setSurname($surname) { $this->surname = (string) $surname; }
-}
-        
-    
- -

Then use the proxy manager to create a ghost object of it. You will be responsible of setting its state during lazy loading:

- -
-        
-namespace MyApp;
-
-use ProxyManager\Factory\LazyLoadingGhostFactory;
-use ProxyManager\Proxy\LazyLoadingInterface;
-
-require_once __DIR__ . '/vendor/autoload.php';
-
-$factory     = new LazyLoadingGhostFactory();
-$initializer = function (LazyLoadingInterface $proxy, $method, array $parameters, & $initializer) {
-    $initializer   = null; // disable initialization
-
-    // load data and modify the object here
-    $proxy->setName('Agent');
-    $proxy->setSurname('Smith');
-
-    return true; // confirm that initialization occurred correctly
-};
-
-$instance = $factory->createProxy('MyApp\Customer', $initializer);
-        
-    
- -

You can now simply use your object as before:

- -
-        
-// this will just work as before
-echo $proxy->getName() . ' ' . $proxy->getSurname(); // Agent Smith
-        
-    
-
- -

Lazy Initialization

- -

As you can see, we use a closure to handle lazy initialization of the proxy instance at runtime. The initializer closure signature for ghost objects should be as following:

- -
-        
-/**
- * @var object  $proxy         the instance the ghost object proxy that is being initialized
- * @var string  $method        the name of the method that triggered lazy initialization
- * @var array   $parameters    an ordered list of parameters passed to the method that
- *                             triggered initialization, indexed by parameter name
- * @var Closure $initializer   a reference to the property that is the initializer for the
- *                             proxy. Set it to null to disable further initialization
- *
- * @return bool true on success
- */
-$initializer = function ($proxy, $method, $parameters, & $initializer) {};
-        
-    
- -

The initializer closure should usually be coded like following:

- -
-        
-$initializer = function ($proxy, $method, $parameters, & $initializer) {
-    $initializer = null; // disable initializer for this proxy instance
-
-    // modify the object with loaded data
-    $proxy->setFoo(/* ... */);
-    $proxy->setBar(/* ... */);
-
-    return true; // report success
-};
-        
-    
- -

The ProxyManager\Factory\LazyLoadingGhostFactory produces proxies that implement both the ProxyManager\Proxy\GhostObjectInterface and the ProxyManager\Proxy\LazyLoadingInterface.

- -

At any point in time, you can set a new initializer for the proxy:

- -
-        
-$proxy->setProxyInitializer($initializer);
-        
-    
- -

In your initializer, you MUST turn off any further initialization:

- -
-        
-$proxy->setProxyInitializer(null);
-        
-    
- -

or

- -
-        
-$initializer = null; // if you use the initializer passed by reference to the closure
-        
-    
-
- -

Triggering Initialization

- -

A lazy loading ghost object is initialized whenever you access any property or method of it. Any of the following interactions would trigger lazy initialization:

- -
-        
-// calling a method
-$proxy->someMethod();
-
-// reading a property
-echo $proxy->someProperty;
-
-// writing a property
-$proxy->someProperty = 'foo';
-
-// checking for existence of a property
-isset($proxy->someProperty);
-
-// removing a property
-unset($proxy->someProperty);
-
-// cloning the entire proxy
-clone $proxy;
-
-// serializing the proxy
-$unserialized = unserialize(serialize($proxy));
-        
-    
- -

Remember to call $proxy->setProxyInitializer(null); to disable initialization of your proxy, or it will happen more than once.

- -
- -

Proxying interfaces

- -

You can also generate proxies from an interface FQCN. By proxying an interface, you will only be able to access the methods defined by the interface itself, even if the wrappedObject implements more methods. This will anyway save some memory since the proxy won't contain any properties.

- -

Tuning performance for production

- -

See Tuning ProxyManager for Production.

- -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/img/block.png b/vendor/ocramius/proxy-manager/html-docs/img/block.png deleted file mode 100644 index fb8f17aaf8479d5e92fb9715d81f5f7c1b262c04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2373 zcmaJ@dpwi-A77fwhSb4Aw>6Ot+iY%atTi@SHN?W{NOpNJc59b5zo+aR+7hm)JV3&L%XwVB7%wLvzVPC8y8alAfPZn3BoGk) zBo#pmhWiOb0NexRfn>R2F>o&&3gh99!(d$CSXYc28smz_;*b~&-rWn2@q~YU5V~k0 zb__m*?Ef{E&LSYlWfDQq~0;!0l8(fUNK9mseCjuA}fru^;aHqQ%94C+n#Bl;4+|Lj0 zL}Rcxe7(Kw3xGz$Q~6>EgUDEWDe%o7}@on<~zHZ$`y1nk$T#^I=88%YMB)a_O z^WtrBVe4%=UPe{D=}Y(n*1s|ev6MHlDq@MV5(abWilAtSSQr8dh}lcP3^0J}y`BrL zLpW!UU_bcPIc6MF{*ryA5b$%0s~SkKJe~NVWNTF8Z+A|A@OejgH&icstTpz!`=R7@ z@zt^8kB5>2cfb5lLa8)AcBu6FxtRmxD)LWSUi2m6IkVqm)g6UfKsC|5dr_$;Uu0Qc zZ?m#;JO()K3^_P|+!;NyYWx29xW$7{N73HuF%EjQl$l=kpqUfIDKBjTR`s=ISHF+f zY?P02YKGaHTyCj(qZE&In%Mmd<}stLY`8qMA}z1p$}eYkgF>=mVB}bZ z9x|_Z>R@NE$yZ8EdvtAfrCo|`@f?$QV-Guvbi3*t=jUb@i@g?C&v*j?zc5~K zz;HWcwCq%4+oTG8lcHYjrPv(fYV7nrtF@@jtReAN+Xu@h)TDIPn${#m*_>WTd}#OO z_+>lhC^QrO;U`o{lOn|*gDOL17i1prwtQtu?c<#XOa~N}1|;WJZYDSnTf}?_^(M_4 z*^$u&FT8t))$2JM2us4XC}2a zhA(h1J)^Y?UevHTS4C_!>NSQ&N%QB+!9KH|b@6gDRBVeU$C=cH6E&ri&n{X^Eo_W_ zCbd8v9;pTA`)_jV;b<`s^>|1#T8q<~og39|1ST2MroOA~%HA zo^A00i~}PqU}Jq+_>e)v#!l-Sg{rPWtIOt6efvtU#%%w9pjBLA>CP^34F5*%$atCT7aL+J^PQLgbsC8rlS;aWV5&&SxC7`~7o9OF%g+ zT5cMNF@IO~*D!Cy0QTVF;T2pX)q%-zd_7{~?Y85UFAEApw(<-divi^#4|avr-cQh` zcfY=|$>{E&@UgkcOjcXjP#bzE)`rMi| zOPHcm^1;bzFVAEKS>*M2Cx(slN0M8r9Cq!D8E+Zq-OIdx>PSM}@X-|l&S8kAvW>d$ zwKk#qZT|~xj4-issz1>r(r|M7wtJa|6PpY?P2LX6q+_krVmFu~$fLxq&YhO(ZO@$B z7$`fJ{TuZ5jFvgww~=R|>Vj7Vsdo#dTOqKe*B4p7^RW1}bpOGrJ*e0F&M#EFvTP(i z{ot7+>)Hz)%WbMZ8TNihKC}8B@=8UG>Jg#8Z{c2rDQlp72O$bnq$Rc^f-pq|$MR%% zH0d0!&7!2GJ(`ZSme!G>@&fkYdH1TT>(&7$WPD&&gMZ$JznG;+#gwxagwI6}rNWXA P>wj#hlt6N=Z?y7n2#Vl( diff --git a/vendor/ocramius/proxy-manager/html-docs/img/enf.png b/vendor/ocramius/proxy-manager/html-docs/img/enf.png deleted file mode 100644 index 7e15bdda716cc1ce495de59800877f4965ce335e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3738 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 Ef{OK7t^fc4 diff --git a/vendor/ocramius/proxy-manager/html-docs/index.html b/vendor/ocramius/proxy-manager/html-docs/index.html deleted file mode 100644 index 9c0ef23..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/index.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - ProxyManager - - - - - - - - - - - - - - -
-
-
- -

Proxy Manager

-
-
- -
-
-
- - - - -
-
-
-
-
-
- - - -
-

Proxy Manager

-

This library aims at providing abstraction for generating various kinds of proxy classes.

-

If you want to learn more about proxy pattern watch this video:

- - -
-
-

Installation

-

The suggested installation method is via composer.

-
php composer.phar require ocramius/proxy-manager:1.0.*
-
- -

Lazy Loading Value Holders (Virtual Proxy)

- -

ProxyManager can generate - lazy loading value holders, - which are virtual proxies capable of saving performance and memory for objects that - require a lot of dependencies or CPU cycles to be loaded: - particularly useful when you may not always need the object, - but are constructing it anyways.

- -
-        
-$factory = new \ProxyManager\Factory\LazyLoadingValueHolderFactory();
-
-$proxy = $factory->createProxy(
-    'MyApp\HeavyComplexObject',
-    function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) {
-        $wrappedObject = new HeavyComplexObject(); // instantiation logic here
-        $initializer   = null; // turning off further lazy initialization
-
-        return true;
-    }
-);
-
-$proxy->doFoo();
-        
-    
- -

See the complete documentation about lazy loading value holders.

-
- -

Access Interceptor Value Holder

- -

An access interceptor value holder is a smart reference that allows you to execute - logic before and after a particular method is executed or a particular property is - accessed, and it allows to manipulate parameters and return values depending on - your needs.

- -
-        
-$factory = new \ProxyManager\Factory\AccessInterceptorValueHolderFactory();
-
-$proxy = $factory->createProxy(
-    new \My\Db\Connection(),
-    array('query' => function () { echo "Query being executed!\n"; }),
-    array('query' => function () { echo "Query completed!\n"; })
-);
-
-$proxy->query(); // produces "Query being executed!\nQuery completed!\n"
-        
-    
- -

See the complete documentation about access interceptor value holders.

-
- -

Access Interceptor Scope Localizer

- -

An access interceptor scope localizer works exactly like an access interceptor - value holder, but it is safe to use to proxy fluent interfaces.

- -

See the complete documentation about access interceptor scope localizer.

-
- - -

Null Objects

- -

A Null Object proxy implements the null object pattern.

- -

This kind of proxy allows you to have fallback logic in case loading of the wrapped value failed.

-
-        
-$factory = new \ProxyManager\Factory\NullObjectFactory();
-
-$proxy = $factory->createProxy('My\EntityObject');
-
-$proxy->getName(); // empty return
-        
-    
- -

A Null Object Proxy can be created from an object, a class name or an interface name:

-
-        
-$factory = new \ProxyManager\Factory\NullObjectFactory();
-
-$proxy = $factory->createProxy('My\EntityObjectInterface');
-$proxy->getName(); // empty return
-
-$proxy = $factory->createProxy($entity); // created from object
-$proxy->getName(); // empty return
-        
-    
- -

See the complete documentation about null object proxy.

- -
- -

Ghost Objects

- -

Similar to value holder, a ghost object is usually created to handle lazy loading.

- -

The difference between a value holder and a ghost object is that the ghost - object does not contain a real instance of the required object, but handles - lazy loading by initializing its own inherited properties.

- -

ProxyManager can generate - lazy loading ghost objects, - which are proxies used to save performance and memory for large datasets and - graphs representing relational data. Ghost objects are particularly useful - when building data-mappers.

- -

Additionally, the overhead introduced by ghost objects is very low when - compared to the memory and performance overhead caused by virtual proxies.

- -
-        
-$factory = new \ProxyManager\Factory\LazyLoadingGhostFactory();
-
-$proxy = $factory->createProxy(
-    'MyApp\HeavyComplexObject',
-    function ($proxy, $method, $parameters, & $initializer) {
-        $initializer   = null; // turning off further lazy initialization
-
-        // modify the proxy instance
-        $proxy->setFoo('foo');
-        $proxy->setBar('bar');
-
-        return true;
-    }
-);
-
-$proxy->doFoo();
-        
-    
- -

See the complete documentation about lazy loading ghost objects.

- -
- -

Remote Object

- -

A remote object proxy is an object that is located on a different system, - but is used as if it was available locally. There's various possible - remote proxy implementations, which could be based on xmlrpc/jsonrpc/soap/dnode/etc.

- -

This example uses the XML-RPC client of Zend Framework 2:

- -
-        
-interface FooServiceInterface
-{
-    public function foo();
-}
-
-$factory = new \ProxyManager\Factory\RemoteObjectFactory(
-    new \ProxyManager\Factory\RemoteObject\Adapter\XmlRpc(
-        new \Zend\XmlRpc\Client('https://example.com/rpc-endpoint')
-    )
-);
-
-// proxy is your remote implementation
-$proxy = $factory->createProxy('FooServiceInterface');
-
-var_dump($proxy->foo());
-        
-    
- -

See the complete documentation about remote objects.

-
- - -

Contributing

-

Please read the CONTRIBUTING contents if you wish to help out!

- -
- -

Credits

- -

The idea was originated by a talk about Proxies in PHP OOP that I gave at the @phpugffm in January 2013.

- - -
- -
-
-
- - -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/null-object.html b/vendor/ocramius/proxy-manager/html-docs/null-object.html deleted file mode 100644 index 5c2476b..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/null-object.html +++ /dev/null @@ -1,185 +0,0 @@ - - - - ProxyManager - Null object - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Null Object Proxy

-

A Null Object proxy is a null object pattern implementation. The proxy factory creates a new object with defined neutral behavior based on an other object, class name or interface.

-
- -

What is null object proxy ?

- -

In your application, when you can't return the object related to the request, the consumer of the model must check for the return value and handle the failing condition gracefully, thus generating an explosion of conditionals throughout your code. Fortunately, this seemingly-tangled situation can be sorted out simply by creating a polymorphic implementation of the domain object, which would implement the same interface as the one of the object in question, only that its methods wouldn’t do anything, therefore offloading client code from doing repetitive checks for ugly null values when the operation is executed.

- -
- -

Usage examples

- -
-        
-class UserMapper
-{   
-    private $adapter;
-
-    public function __construct(DatabaseAdapterInterface $adapter) {
-        $this->adapter = $adapter;
-    }
-
-    public function fetchById($id) {
-        $this->adapter->select("users", array("id" => $id));
-        if (!$row = $this->adapter->fetch()) {
-            return null;
-        }
-        return $this->createUser($row);
-    }
-
-    private function createUser(array $row) {
-        $user = new Entity\User($row["name"], $row["email"]);
-        $user->setId($row["id"]);
-        return $user;
-    }
-}
-        
-    
- -

If you want to remove conditionals from client code, you need to have a version of the entity conforming to the corresponding interface. With the Null Object Proxy, you can build this object :

- -
-        
-$factory = new \ProxyManager\Factory\NullObjectFactory();
-
-$nullUser = $factory->createProxy('Entity\User');
-
-var_dump($nullUser->getName()); // empty return
-        
-    
- -

You can now return a valid entity :

- -
-        
-class UserMapper
-{   
-    private $adapter;
-
-    public function __construct(DatabaseAdapterInterface $adapter) {
-        $this->adapter = $adapter;
-    }
-
-    public function fetchById($id) {
-        $this->adapter->select("users", array("id" => $id));
-        return $this->createUser($this->adapter->fetch());
-    }
-
-    private function createUser($row) {
-        if (!$row) {
-            $factory = new \ProxyManager\Factory\NullObjectFactory();
-
-            return $factory->createProxy('Entity\User');
-        }
-        $user = new Entity\User($row["name"], $row["email"]);
-        $user->setId($row["id"]);
-        return $user; 
-    }
-}
-        
-    
- - -
- -

Proxying interfaces

- -

You can also generate proxies from an interface FQCN. By proxying an interface, you will only be able to access the methods defined by the interface itself, and like with the object, the methods are empty.

- -

Tuning performance for production

- -

See Tuning ProxyManager for Production.

- -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/production.html b/vendor/ocramius/proxy-manager/html-docs/production.html deleted file mode 100644 index 39c086b..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/production.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - ProxyManager - Tuning the ProxyManager for production - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Tuning the ProxyManager for production

- -

By default, all proxy factories generate the required proxy classes at runtime.

- -

Proxy generation causes I/O operations and uses a lot of reflection, so be sure to have generated all of your proxies before deploying your code on a live system, or you may experience poor performance.

- -

You can configure ProxyManager so that it will try autoloading the proxies first. Generating them "bulk" is not yet implemented:

- -
-        
-$config = new \ProxyManager\Configuration();
-$config->setProxiesTargetDir(__DIR__ . '/my/generated/classes/cache/dir');
-
-// then register the autoloader
-spl_autoload_register($config->getProxyAutoloader());
-        
-    
- -

Generating a classmap with all your proxy classes in it will also work perfectly.

- -

Please note that all the currently implemented ProxyManager\Factory\* classes accept a ProxyManager\Configuration object as optional constructor parameter. This allows for fine-tuning of ProxyManager according to your needs.

- -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/remote-object.html b/vendor/ocramius/proxy-manager/html-docs/remote-object.html deleted file mode 100644 index 3fc627d..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/remote-object.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - ProxyManager - Remote object - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Remote Object Proxy

- -

The remote object implementation is a mechanism that enables an local object to control an other object on an other server. Each call method on the local object will do a network call to get information or execute operations on the remote object.

-
- -

What is remote object proxy ?

- -

A remote object is based on an interface. The remote interface defines the API that a consumer can call. This interface must be implemented both by the client and the RPC server.

-
- -

Adapters

- -

ZendFramework's RPC components (XmlRpc, JsonRpc & Soap) can be used easily with the remote object. You will need to require the one you need via composer, though:

- -
-        
-$ php composer.phar require zendframework/zend-xmlrpc:2.*
-$ php composer.phar require zendframework/zend-json:2.*
-$ php composer.phar require zendframework/zend-soap:2.*
-        
-    
- -

ProxyManager comes with 3 adapters:

- -
    -
  • ProxyManager\Factory\RemoteObject\Adapter\XmlRpc
  • -
  • ProxyManager\Factory\RemoteObject\Adapter\JsonRpc
  • -
  • ProxyManager\Factory\RemoteObject\Adapter\Soap
  • -
- -
- -

Usage examples

- -

RPC server side code (xmlrpc.php in your local webroot):

- -
-        
-interface FooServiceInterface
-{
-    public function foo();
-}
-
-class Foo implements FooServiceInterface
-{
-    /**
-     * Foo function
-     * @return string
-     */
-    public function foo()
-    {
-        return 'bar remote';
-    }
-}
-
-$server = new Zend\XmlRpc\Server();
-$server->setClass('Foo', 'FooServiceInterface');  // my FooServiceInterface implementation
-$server->handle();
-        
-    
- -

Client side code (proxy) :

- -
-        
-interface FooServiceInterface
-{
-    public function foo();
-}
-
-$factory = new \ProxyManager\Factory\RemoteObjectFactory(
-    new \ProxyManager\Factory\RemoteObject\Adapter\XmlRpc(
-        new \Zend\XmlRpc\Client('https://localhost/xmlrpc.php')
-    )
-);
-
-$proxy = $factory->createProxy('FooServiceInterface');
-
-var_dump($proxy->foo()); // "bar remote"
-        
-    
-
- -

Implementing custom adapters

- -

Your adapters must implement ProxyManager\Factory\RemoteObject\AdapterInterface :

- -
-        
-interface AdapterInterface
-{
-    /**
-     * Call remote object
-     *
-     * @param string $wrappedClass
-     * @param string $method
-     * @param array $params
-     *
-     * @return mixed
-     */
-    public function call($wrappedClass, $method, array $params = array());
-}
-        
-    
- -

It is very easy to create your own implementation (for RESTful web services, for example). Simply pass your own adapter instance to your factory at construction time

- -

Tuning performance for production

- -

See Tuning ProxyManager for Production.

- -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/html-docs/virtual-proxy.html b/vendor/ocramius/proxy-manager/html-docs/virtual-proxy.html deleted file mode 100644 index 5dbb038..0000000 --- a/vendor/ocramius/proxy-manager/html-docs/virtual-proxy.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - ProxyManager - Virtual Proxy - - - - - - - - - - - - - - -
-
- -
-
-
- - - - -
-
-
-
-
-
- - -
-
-

Lazy Loading Value Holder Proxy

-

A lazy loading value holder proxy is a virtual proxy that wraps and lazily initializes a "real" instance of the proxied class.

-
- -

What is lazy loading?

- -

In pseudo-code, in userland, lazy loading looks like following:

- -
-        
-class MyObjectProxy
-{
-    private $wrapped;
-
-    public function doFoo()
-    {
-        $this->init();
-
-        return $this->wrapped->doFoo();
-    }
-
-    private function init()
-    {
-        if (null === $this->wrapped) {
-            $this->wrapped = new MyObject();
-        }
-    }
-}
-    
-
- -

This code is problematic, and adds a lot of complexity that makes your unit tests' code even worse.

- -

Also, this kind of usage often ends up in coupling your code with a particular Dependency Injection Container or a framework that fetches dependencies for you. That way, further complexity is introduced, and some problems related with service location raise, as I've explained in this article.

- -

Lazy loading value holders abstract this logic for you, hiding your complex, slow, performance-impacting objects behind tiny wrappers that have their same API, and that get initialized at first usage.

- -
- -

When do I use a lazy value holder?

- -

You usually need a lazy value holder in cases where following applies

- -
    -
  • your object takes a lot of time and memory to be initialized (with all dependencies)
  • -
  • your object is not always used, and the instantiation overhead can be avoided
  • -
- -
- -

Usage examples

- -

ProxyManager provides a factory that eases instantiation of lazy loading value holders. To use it, follow these steps:

- -

First of all, define your object's logic without taking care of lazy loading:

- -
-    
-namespace MyApp;
-
-class HeavyComplexObject
-{
-    public function __construct()
-    {
-        // just write your business logic
-        // don't worry about how heavy initialization of this will be!
-    }
-
-    public function doFoo() {
-        echo "OK!"
-    }
-}
-    
-
- -

Then use the proxy manager to create a lazy version of the object (as a proxy):

- -
-    
-namespace MyApp;
-
-use ProxyManager\Factory\LazyLoadingValueHolderFactory;
-use ProxyManager\Proxy\LazyLoadingInterface;
-
-require_once __DIR__ . '/vendor/autoload.php';
-
-$factory     = new LazyLoadingValueHolderFactory();
-$initializer = function (& $wrappedObject, LazyLoadingInterface $proxy, $method, array $parameters, & $initializer) {
-    $initializer   = null; // disable initialization
-    $wrappedObject = new HeavyComplexObject(); // fill your object with values here
-
-    return true; // confirm that initialization occurred correctly
-};
-
-$instance = $factory->createProxy('MyApp\HeavyComplexObject', $initializer);
-    
-
- -

You can now simply use your object as before:

- -
-    
-// this will just work as before
-$proxy->doFoo(); // OK!
-    
-
-
- - -

Lazy Initialization

- -

As you can see, we use a closure to handle lazy initialization of the proxy instance at runtime. The initializer closure signature should be as following:

- -
-    
-/**
- * @var object  $wrappedObject the instance (passed by reference) of the wrapped object,
- *                             set it to your real object
- * @var object  $proxy         the instance proxy that is being initialized
- * @var string  $method        the name of the method that triggered lazy initialization
- * @var string  $parameters    an ordered list of parameters passed to the method that
- *                             triggered initialization, indexed by parameter name
- * @var Closure $initializer   a reference to the property that is the initializer for the
- *                             proxy. Set it to null to disable further initialization
- *
- * @return bool true on success
- */
-$initializer = function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) {};
-    
-
- -

The initializer closure should usually be coded like following:

- -
-    
-$initializer = function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) {
-    $newlyCreatedObject = new Foo(); // instantiation logic
-    $newlyCreatedObject->setBar('baz') // instantiation logic
-    $newlyCreatedObject->setBat('bam') // instantiation logic
-
-    $wrappedObject = $newlyCreatedObject; // set wrapped object in the proxy
-    $initializer   = null; // disable initializer
-
-    return true; // report success
-};
-    
-
- -

The ProxyManager\Factory\LazyLoadingValueHolderFactory produces proxies that implement both the ProxyManager\Proxy\ValueHolderInterface and the ProxyManager\Proxy\LazyLoadingInterface.

- -

At any point in time, you can set a new initializer for the proxy:

- -
$proxy->setProxyInitializer($initializer);
- -

In your initializer, you currently MUST turn off any further initialization:

- -
$proxy->setProxyInitializer(null);
- -

or

- -
$initializer = null; // if you use the initializer by reference
-
- -

Triggering Initialization

- -

A lazy loading proxy is initialized whenever you access any property or method of it. Any of the following interactions would trigger lazy initialization:

- -
-    
-// calling a method
-$proxy->someMethod();
-
-// reading a property
-echo $proxy->someProperty;
-
-// writing a property
-$proxy->someProperty = 'foo';
-
-// checking for existence of a property
-isset($proxy->someProperty);
-
-// removing a property
-unset($proxy->someProperty);
-
-// cloning the entire proxy
-clone $proxy;
-
-// serializing the proxy
-$unserialized = serialize(unserialize($proxy));
-    
-
- -

Remember to call $proxy->setProxyInitializer(null); to disable initialization of your proxy, or it will happen more than once.

- - - - - - - - -
- -

Proxying interfaces

- -

You can also generate proxies from an interface FQCN. By proxying an interface, you will only be able to access the methods defined by the interface itself, even if the wrappedObject implements more methods. This will anyway save some memory since the proxy won't contain useless inherited properties.

- -

Tuning performance for production

- -

See Tuning ProxyManager for Production.

- - - -
- - -
- - diff --git a/vendor/ocramius/proxy-manager/index.html b/vendor/ocramius/proxy-manager/index.html deleted file mode 100644 index da417f7..0000000 --- a/vendor/ocramius/proxy-manager/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/vendor/ocramius/proxy-manager/phpdox.xml.dist b/vendor/ocramius/proxy-manager/phpdox.xml.dist deleted file mode 100644 index 6cbf78b..0000000 --- a/vendor/ocramius/proxy-manager/phpdox.xml.dist +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - diff --git a/vendor/ocramius/proxy-manager/phpmd.xml.dist b/vendor/ocramius/proxy-manager/phpmd.xml.dist deleted file mode 100644 index ae91e86..0000000 --- a/vendor/ocramius/proxy-manager/phpmd.xml.dist +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - diff --git a/vendor/ocramius/proxy-manager/phpunit.xml.dist b/vendor/ocramius/proxy-manager/phpunit.xml.dist deleted file mode 100644 index b595427..0000000 --- a/vendor/ocramius/proxy-manager/phpunit.xml.dist +++ /dev/null @@ -1,25 +0,0 @@ - - - - ./tests/ProxyManagerTest - - - ./tests/language-feature-scripts - - - - ./src - - - diff --git a/vendor/ocramius/proxy-manager/proxy-manager.png b/vendor/ocramius/proxy-manager/proxy-manager.png deleted file mode 100644 index 0ab1c6e2c5da324a9a4729aa24e591901b819173..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19203 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 diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/Factory/AbstractLazyFactory.php b/vendor/ocramius/proxy-manager/src/ProxyManager/Factory/AbstractLazyFactory.php deleted file mode 100644 index 690bfa1..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/Factory/AbstractLazyFactory.php +++ /dev/null @@ -1,46 +0,0 @@ - - * @license MIT - */ -abstract class AbstractLazyFactory extends AbstractBaseFactory -{ - /** - * Creates a new lazy proxy instance of the given class with - * the given initializer - * - * @param string $className name of the class to be proxied - * @param \Closure $initializer initializer to be passed to the proxy - * - * @return \ProxyManager\Proxy\LazyLoadingInterface - */ - public function createProxy($className, Closure $initializer) - { - $proxyClassName = $this->generateProxy($className); - - return new $proxyClassName($initializer); - } -} diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/Generator/ParameterGenerator.php b/vendor/ocramius/proxy-manager/src/ProxyManager/Generator/ParameterGenerator.php deleted file mode 100644 index 7960d42..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/Generator/ParameterGenerator.php +++ /dev/null @@ -1,149 +0,0 @@ - - * @license MIT - */ -class ParameterGenerator extends ZendParameterGenerator -{ - /** - * @override - uses `static` to instantiate the parameter - * - * {@inheritDoc} - */ - public static function fromReflection(ParameterReflection $reflectionParameter) - { - /* @var $param self */ - $param = new static(); - - $param->setName($reflectionParameter->getName()); - $param->setPosition($reflectionParameter->getPosition()); - - $type = self::extractParameterType($reflectionParameter); - - if (null !== $type) { - $param->setType($type); - } - - self::setOptionalParameter($param, $reflectionParameter); - - $param->setPassedByReference($reflectionParameter->isPassedByReference()); - - return $param; - } - - /** - * Retrieves the type of a reflection parameter (null if none is found) - * - * @param ParameterReflection $reflectionParameter - * - * @return string|null - */ - private static function extractParameterType(ParameterReflection $reflectionParameter) - { - if ($reflectionParameter->isArray()) { - return 'array'; - } - - if (method_exists($reflectionParameter, 'isCallable') && $reflectionParameter->isCallable()) { - return 'callable'; - } - - if ($typeClass = $reflectionParameter->getClass()) { - return $typeClass->getName(); - } - - return null; - } - - /** - * @return string - */ - public function generate() - { - return $this->getGeneratedType() - . (true === $this->passedByReference ? '&' : '') - . '$' . $this->name - . $this->generateDefaultValue(); - } - - /** - * @return string - */ - private function generateDefaultValue() - { - if (null === $this->defaultValue) { - return ''; - } - - $defaultValue = $this->defaultValue instanceof ValueGenerator - ? $this->defaultValue - : new ValueGenerator($this->defaultValue); - - $defaultValue->setOutputMode(ValueGenerator::OUTPUT_SINGLE_LINE); - - return ' = ' . $defaultValue; - } - - /** - * Retrieves the generated parameter type - * - * @return string - */ - private function getGeneratedType() - { - if (! $this->type || in_array($this->type, static::$simple)) { - return ''; - } - - if ('array' === $this->type || 'callable' === $this->type) { - return $this->type . ' '; - } - - return '\\' . trim($this->type, '\\') . ' '; - } - - /** - * Set the default value for a parameter (if it is optional) - * - * @param ZendParameterGenerator $parameterGenerator - * @param ParameterReflection $reflectionParameter - */ - private static function setOptionalParameter( - ZendParameterGenerator $parameterGenerator, - ParameterReflection $reflectionParameter - ) { - if ($reflectionParameter->isOptional()) { - try { - $parameterGenerator->setDefaultValue($reflectionParameter->getDefaultValue()); - } catch (ReflectionException $e) { - $parameterGenerator->setDefaultValue(null); - } - } - } -} diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Constructor.php b/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Constructor.php deleted file mode 100644 index 3770a16..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Constructor.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @license MIT - */ -class Constructor extends MethodGenerator -{ - /** - * Constructor - */ - public function __construct( - ReflectionClass $originalClass, - PropertyGenerator $prefixInterceptors, - PropertyGenerator $suffixInterceptors - ) { - parent::__construct('__construct'); - - $localizedObject = new ParameterGenerator('localizedObject'); - $prefix = new ParameterGenerator('prefixInterceptors'); - $suffix = new ParameterGenerator('suffixInterceptors'); - - $localizedObject->setType($originalClass->getName()); - $prefix->setDefaultValue(array()); - $suffix->setDefaultValue(array()); - $prefix->setType('array'); - $suffix->setType('array'); - - $this->setParameter($localizedObject); - $this->setParameter($prefix); - $this->setParameter($suffix); - - $localizedProperties = array(); - - foreach ($originalClass->getProperties() as $originalProperty) { - if ((! method_exists('Closure', 'bind')) && $originalProperty->isPrivate()) { - // @codeCoverageIgnoreStart - throw UnsupportedProxiedClassException::unsupportedLocalizedReflectionProperty($originalProperty); - // @codeCoverageIgnoreEnd - } - - $propertyName = $originalProperty->getName(); - - if ($originalProperty->isPrivate()) { - $localizedProperties[] = "\\Closure::bind(function () use (\$localizedObject) {\n " - . '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";\n" - . '}, $this, ' . var_export($originalProperty->getDeclaringClass()->getName(), true) - . ')->__invoke();'; - } else { - $localizedProperties[] = '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";"; - } - } - - $this->setDocblock( - "@override constructor to setup interceptors\n\n" - . "@param \\" . $originalClass->getName() . " \$localizedObject\n" - . "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n" - . "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic" - ); - $this->setBody( - (empty($localizedProperties) ? '' : implode("\n\n", $localizedProperties) . "\n\n") - . '$this->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n" - . '$this->' . $suffixInterceptors->getName() . " = \$suffixInterceptors;" - ); - } -} diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Constructor.php b/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Constructor.php deleted file mode 100644 index 925ee6b..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Constructor.php +++ /dev/null @@ -1,79 +0,0 @@ - - * @license MIT - */ -class Constructor extends MethodGenerator -{ - /** - * Constructor - */ - public function __construct( - ReflectionClass $originalClass, - PropertyGenerator $valueHolder, - PropertyGenerator $prefixInterceptors, - PropertyGenerator $suffixInterceptors - ) { - parent::__construct('__construct'); - - $prefix = new ParameterGenerator('prefixInterceptors'); - $suffix = new ParameterGenerator('suffixInterceptors'); - - $prefix->setDefaultValue(array()); - $suffix->setDefaultValue(array()); - $prefix->setType('array'); - $suffix->setType('array'); - - $this->setParameter(new ParameterGenerator('wrappedObject')); - $this->setParameter($prefix); - $this->setParameter($suffix); - - /* @var $publicProperties \ReflectionProperty[] */ - $publicProperties = $originalClass->getProperties(ReflectionProperty::IS_PUBLIC); - $unsetProperties = array(); - - foreach ($publicProperties as $publicProperty) { - $unsetProperties[] = '$this->' . $publicProperty->getName(); - } - - $this->setDocblock( - "@override constructor to setup interceptors\n\n" - . "@param \\" . $originalClass->getName() . " \$wrappedObject\n" - . "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n" - . "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic" - ); - $this->setBody( - ($unsetProperties ? 'unset(' . implode(', ', $unsetProperties) . ");\n\n" : '') - . '$this->' . $valueHolder->getName() . " = \$wrappedObject;\n" - . '$this->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n" - . '$this->' . $suffixInterceptors->getName() . " = \$suffixInterceptors;" - ); - } -} diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/LazyLoading/MethodGenerator/Constructor.php b/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/LazyLoading/MethodGenerator/Constructor.php deleted file mode 100644 index 224370b..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/LazyLoading/MethodGenerator/Constructor.php +++ /dev/null @@ -1,58 +0,0 @@ - - * @license MIT - */ -class Constructor extends MethodGenerator -{ - /** - * Constructor - */ - public function __construct(ReflectionClass $originalClass, PropertyGenerator $initializerProperty) - { - parent::__construct('__construct'); - - $this->setParameter(new ParameterGenerator('initializer')); - - /* @var $publicProperties \ReflectionProperty[] */ - $publicProperties = $originalClass->getProperties(ReflectionProperty::IS_PUBLIC); - $unsetProperties = array(); - - foreach ($publicProperties as $publicProperty) { - $unsetProperties[] = '$this->' . $publicProperty->getName(); - } - - $this->setDocblock("@override constructor for lazy initialization\n\n@param \\Closure|null \$initializer"); - $this->setBody( - ($unsetProperties ? 'unset(' . implode(', ', $unsetProperties) . ");\n\n" : '') - . '$this->' . $initializerProperty->getName() . ' = $initializer;' - ); - } -} diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/LazyLoadingMethodInterceptor.php b/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/LazyLoadingMethodInterceptor.php deleted file mode 100644 index d511a48..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/LazyLoadingMethodInterceptor.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @license MIT - */ -class LazyLoadingMethodInterceptor extends MethodGenerator -{ - /** - * @param \Zend\Code\Reflection\MethodReflection $originalMethod - * @param \Zend\Code\Generator\PropertyGenerator $initializerProperty - * @param \Zend\Code\Generator\MethodGenerator $callInitializer - * - * @return LazyLoadingMethodInterceptor|static - */ - public static function generateMethod( - MethodReflection $originalMethod, - PropertyGenerator $initializerProperty, - ZendMethodGenerator $callInitializer - ) { - /* @var $method self */ - $method = static::fromReflection($originalMethod); - $parameters = $originalMethod->getParameters(); - $methodName = $originalMethod->getName(); - $initializerParams = array(); - $forwardedParams = array(); - - foreach ($parameters as $parameter) { - $parameterName = $parameter->getName(); - $initializerParams[] = var_export($parameterName, true) . ' => $' . $parameterName; - $forwardedParams[] = '$' . $parameterName; - } - - $method->setBody( - '$this->' . $initializerProperty->getName() - . ' && $this->' . $callInitializer->getName() - . '(' . var_export($methodName, true) - . ', array(' . implode(', ', $initializerParams) . "));\n\n" - . 'return parent::' - . $methodName . '(' . implode(', ', $forwardedParams) . ');' - ); - $method->setDocblock('{@inheritDoc}'); - - return $method; - } -} diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/NullObject/MethodGenerator/Constructor.php b/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/NullObject/MethodGenerator/Constructor.php deleted file mode 100644 index 7f4c4ce..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/NullObject/MethodGenerator/Constructor.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @license MIT - */ -class Constructor extends MethodGenerator -{ - /** - * Constructor - * - * @param ReflectionClass $originalClass Reflection of the class to proxy - */ - public function __construct(ReflectionClass $originalClass) - { - parent::__construct('__construct'); - - /* @var $publicProperties \ReflectionProperty[] */ - $publicProperties = $originalClass->getProperties(ReflectionProperty::IS_PUBLIC); - $nullableProperties = array(); - - foreach ($publicProperties as $publicProperty) { - $nullableProperties[] = '$this->' . $publicProperty->getName() . ' = null;'; - } - - $this->setDocblock("@override constructor for null object initialization"); - if ($nullableProperties) { - $this->setBody(implode("\n", $nullableProperties)); - } - } -} diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/PropertyGenerator/PublicPropertiesDefaults.php b/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/PropertyGenerator/PublicPropertiesDefaults.php deleted file mode 100644 index 55822f3..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/PropertyGenerator/PublicPropertiesDefaults.php +++ /dev/null @@ -1,58 +0,0 @@ - - * @license MIT - */ -class PublicPropertiesDefaults extends PropertyGenerator -{ - /** - * @var bool[] - */ - private $publicProperties = array(); - - /** - * @param \ReflectionClass $originalClass - */ - public function __construct(ReflectionClass $originalClass) - { - parent::__construct(UniqueIdentifierGenerator::getIdentifier('publicPropertiesDefaults')); - - $defaults = $originalClass->getDefaultProperties(); - - foreach ($originalClass->getProperties(ReflectionProperty::IS_PUBLIC) as $publicProperty) { - $name = $publicProperty->getName(); - $this->publicProperties[$name] = $defaults[$name]; - } - - $this->setDefaultValue($this->publicProperties); - $this->setVisibility(self::VISIBILITY_PRIVATE); - $this->setStatic(true); - $this->setDocblock('@var mixed[] map of default property values of the parent class'); - } -} diff --git a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/Constructor.php b/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/Constructor.php deleted file mode 100644 index d1fcb89..0000000 --- a/vendor/ocramius/proxy-manager/src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/Constructor.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @license MIT - */ -class Constructor extends MethodGenerator -{ - /** - * Constructor - * - * @param ReflectionClass $originalClass Reflection of the class to proxy - * @param PropertyGenerator $adapter Adapter property - */ - public function __construct(ReflectionClass $originalClass, PropertyGenerator $adapter) - { - parent::__construct('__construct'); - - $adapterName = $adapter->getName(); - - $this->setParameter(new ParameterGenerator($adapterName, 'ProxyManager\Factory\RemoteObject\AdapterInterface')); - - $this->setDocblock( - '@override constructor for remote object control\n\n' - . '@param \\ProxyManager\\Factory\\RemoteObject\\AdapterInterface \$adapter' - ); - - $body = '$this->' . $adapterName . ' = $' . $adapterName . ';'; - - foreach ($originalClass->getProperties() as $property) { - if ($property->isPublic() && ! $property->isStatic()) { - $body .= "\nunset(\$this->" . $property->getName() . ');'; - } - } - - $this->setBody($body); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Autoloader/AutoloaderTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Autoloader/AutoloaderTest.php deleted file mode 100644 index aba8cf0..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Autoloader/AutoloaderTest.php +++ /dev/null @@ -1,133 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Autoloader\Autoloader - * @group Coverage - */ -class AutoloaderTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \ProxyManager\Autoloader\Autoloader - */ - protected $autoloader; - - /** - * @var \ProxyManager\FileLocator\FileLocatorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $fileLocator; - - /** - * @var \ProxyManager\Inflector\ClassNameInflectorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $classNameInflector; - - /** - * @covers \ProxyManager\Autoloader\Autoloader::__construct - */ - public function setUp() - { - $this->fileLocator = $this->getMock('ProxyManager\\FileLocator\\FileLocatorInterface'); - $this->classNameInflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - $this->autoloader = new Autoloader($this->fileLocator, $this->classNameInflector); - } - - /** - * @covers \ProxyManager\Autoloader\Autoloader::__invoke - */ - public function testWillNotAutoloadUserClasses() - { - $className = 'Foo\\' . UniqueIdentifierGenerator::getIdentifier('Bar'); - $this - ->classNameInflector - ->expects($this->once()) - ->method('isProxyClassName') - ->with($className) - ->will($this->returnValue(false)); - - $this->assertFalse($this->autoloader->__invoke($className)); - } - - /** - * @covers \ProxyManager\Autoloader\Autoloader::__invoke - */ - public function testWillNotAutoloadNonExistingClass() - { - $className = 'Foo\\' . UniqueIdentifierGenerator::getIdentifier('Bar'); - $this - ->classNameInflector - ->expects($this->once()) - ->method('isProxyClassName') - ->with($className) - ->will($this->returnValue(true)); - $this - ->fileLocator - ->expects($this->once()) - ->method('getProxyFileName') - ->will($this->returnValue(__DIR__ . '/non-existing')); - - $this->assertFalse($this->autoloader->__invoke($className)); - } - - /** - * @covers \ProxyManager\Autoloader\Autoloader::__invoke - */ - public function testWillNotAutoloadExistingClass() - { - $this->assertFalse($this->autoloader->__invoke(__CLASS__)); - } - - /** - * @covers \ProxyManager\Autoloader\Autoloader::__invoke - */ - public function testWillAutoloadExistingFile() - { - $namespace = 'Foo'; - $className = UniqueIdentifierGenerator::getIdentifier('Bar'); - $fqcn = $namespace . '\\' . $className; - $fileName = sys_get_temp_dir() . '/foo_' . uniqid() . '.php'; - - file_put_contents($fileName, 'classNameInflector - ->expects($this->once()) - ->method('isProxyClassName') - ->with($fqcn) - ->will($this->returnValue(true)); - $this - ->fileLocator - ->expects($this->once()) - ->method('getProxyFileName') - ->will($this->returnValue($fileName)); - - $this->assertTrue($this->autoloader->__invoke($fqcn)); - $this->assertTrue(class_exists($fqcn, false)); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ConfigurationTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ConfigurationTest.php deleted file mode 100644 index 17ea451..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ConfigurationTest.php +++ /dev/null @@ -1,183 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ConfigurationTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \ProxyManager\Configuration - */ - protected $configuration; - - /** - * {@inheritDoc} - */ - public function setUp() - { - $this->configuration = new Configuration(); - } - - /** - * @covers \ProxyManager\Configuration::getProxiesNamespace - * @covers \ProxyManager\Configuration::setProxiesNamespace - */ - public function testGetSetProxiesNamespace() - { - $this->assertSame( - 'ProxyManagerGeneratedProxy', - $this->configuration->getProxiesNamespace(), - 'Default setting check for BC' - ); - - $this->configuration->setProxiesNamespace('foo'); - $this->assertSame('foo', $this->configuration->getProxiesNamespace()); - } - - /** - * @covers \ProxyManager\Configuration::getClassNameInflector - * @covers \ProxyManager\Configuration::setClassNameInflector - */ - public function testSetGetClassNameInflector() - { - $this->assertInstanceOf( - 'ProxyManager\\Inflector\\ClassNameInflectorInterface', - $this->configuration->getClassNameInflector() - ); - - /* @var $inflector \ProxyManager\Inflector\ClassNameInflectorInterface */ - $inflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - - $this->configuration->setClassNameInflector($inflector); - $this->assertSame($inflector, $this->configuration->getClassNameInflector()); - } - - /** - * @covers \ProxyManager\Configuration::getGeneratorStrategy - * @covers \ProxyManager\Configuration::setGeneratorStrategy - */ - public function testSetGetGeneratorStrategy() - { - - $this->assertInstanceOf( - 'ProxyManager\\GeneratorStrategy\\GeneratorStrategyInterface', - $this->configuration->getGeneratorStrategy() - ); - - /* @var $strategy \ProxyManager\GeneratorStrategy\GeneratorStrategyInterface */ - $strategy = $this->getMock('ProxyManager\\GeneratorStrategy\\GeneratorStrategyInterface'); - - $this->configuration->setGeneratorStrategy($strategy); - $this->assertSame($strategy, $this->configuration->getGeneratorStrategy()); - } - - /** - * @covers \ProxyManager\Configuration::getProxiesTargetDir - * @covers \ProxyManager\Configuration::setProxiesTargetDir - */ - public function testSetGetProxiesTargetDir() - { - $this->assertTrue(is_dir($this->configuration->getProxiesTargetDir())); - - $this->configuration->setProxiesTargetDir(__DIR__); - $this->assertSame(__DIR__, $this->configuration->getProxiesTargetDir()); - } - - /** - * @covers \ProxyManager\Configuration::getProxyAutoloader - * @covers \ProxyManager\Configuration::setProxyAutoloader - */ - public function testSetGetProxyAutoloader() - { - $this->assertInstanceOf( - 'ProxyManager\\Autoloader\\AutoloaderInterface', - $this->configuration->getProxyAutoloader() - ); - - /* @var $autoloader \ProxyManager\Autoloader\AutoloaderInterface */ - $autoloader = $this->getMock('ProxyManager\\Autoloader\\AutoloaderInterface'); - - $this->configuration->setProxyAutoloader($autoloader); - $this->assertSame($autoloader, $this->configuration->getProxyAutoloader()); - } - - /** - * @covers \ProxyManager\Configuration::getSignatureGenerator - * @covers \ProxyManager\Configuration::setSignatureGenerator - */ - public function testSetGetSignatureGenerator() - { - $this->assertInstanceOf( - 'ProxyManager\\Signature\\SignatureGeneratorInterface', - $this->configuration->getSignatureGenerator() - ); - - /* @var $signatureGenerator \ProxyManager\Signature\SignatureGeneratorInterface */ - $signatureGenerator = $this->getMock('ProxyManager\\Signature\\SignatureGeneratorInterface'); - - $this->configuration->setSignatureGenerator($signatureGenerator); - $this->assertSame($signatureGenerator, $this->configuration->getSignatureGenerator()); - } - - /** - * @covers \ProxyManager\Configuration::getSignatureChecker - * @covers \ProxyManager\Configuration::setSignatureChecker - */ - public function testSetGetSignatureChecker() - { - $this->assertInstanceOf( - 'ProxyManager\\Signature\\SignatureCheckerInterface', - $this->configuration->getSignatureChecker() - ); - - /* @var $signatureChecker \ProxyManager\Signature\SignatureCheckerInterface */ - $signatureChecker = $this->getMock('ProxyManager\\Signature\\SignatureCheckerInterface'); - - $this->configuration->setSignatureChecker($signatureChecker); - $this->assertSame($signatureChecker, $this->configuration->getSignatureChecker()); - } - - /** - * @covers \ProxyManager\Configuration::getClassSignatureGenerator - * @covers \ProxyManager\Configuration::setClassSignatureGenerator - */ - public function testSetGetClassSignatureGenerator() - { - $this->assertInstanceOf( - 'ProxyManager\\Signature\\ClassSignatureGeneratorInterface', - $this->configuration->getClassSignatureGenerator() - ); - - /* @var $classSignatureGenerator \ProxyManager\Signature\ClassSignatureGeneratorInterface */ - $classSignatureGenerator = $this->getMock('ProxyManager\\Signature\\ClassSignatureGeneratorInterface'); - - $this->configuration->setClassSignatureGenerator($classSignatureGenerator); - $this->assertSame($classSignatureGenerator, $this->configuration->getClassSignatureGenerator()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/DisabledMethodExceptionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/DisabledMethodExceptionTest.php deleted file mode 100644 index 5dc574e..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/DisabledMethodExceptionTest.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Exception\DisabledMethodException - * @group Coverage - */ -class DisabledMethodExceptionTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\Exception\DisabledMethodException::disabledMethod - */ - public function testProxyDirectoryNotFound() - { - $exception = DisabledMethodException::disabledMethod('foo::bar'); - - $this->assertSame('Method "foo::bar" is forcefully disabled', $exception->getMessage()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/FileNotWritableExceptionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/FileNotWritableExceptionTest.php deleted file mode 100644 index 915b8f1..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/FileNotWritableExceptionTest.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Exception\FileNotWritableException - * @group Coverage - */ -class FileNotWritableExceptionTest extends PHPUnit_Framework_TestCase -{ - public function testFromInvalidMoveOperation() - { - $exception = FileNotWritableException::fromInvalidMoveOperation('/tmp/a', '/tmp/b'); - - $this->assertInstanceOf('ProxyManager\\Exception\\FileNotWritableException', $exception); - $this->assertSame( - 'Could not move file "/tmp/a" to location "/tmp/b": either the source file is not readable,' - . ' or the destination is not writable', - $exception->getMessage() - ); - } - - public function testFromNotWritableLocationWithNonFilePath() - { - $exception = FileNotWritableException::fromNonWritableLocation(__DIR__); - - $this->assertInstanceOf('ProxyManager\\Exception\\FileNotWritableException', $exception); - $this->assertSame( - 'Could not write to path "' . __DIR__ . '": exists and is not a file', - $exception->getMessage() - ); - } - - public function testFromNotWritableLocationWithNonWritablePath() - { - $path = sys_get_temp_dir() . '/' . uniqid('FileNotWritableExceptionTestNonWritable', true); - - mkdir($path, 0555); - - $exception = FileNotWritableException::fromNonWritableLocation($path . '/foo'); - - $this->assertInstanceOf('ProxyManager\\Exception\\FileNotWritableException', $exception); - $this->assertSame( - 'Could not write to path "' . $path . '/foo": is not writable', - $exception->getMessage() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/InvalidProxiedClassExceptionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/InvalidProxiedClassExceptionTest.php deleted file mode 100644 index 0656dad..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/InvalidProxiedClassExceptionTest.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Exception\InvalidProxiedClassException - * @group Coverage - */ -class InvalidProxiedClassExceptionTest extends PHPUnit_Framework_TestCase -{ - public function testInterfaceNotSupported() - { - $this->assertSame( - 'Provided interface "ProxyManagerTestAsset\BaseInterface" cannot be proxied', - InvalidProxiedClassException::interfaceNotSupported( - new ReflectionClass('ProxyManagerTestAsset\BaseInterface') - )->getMessage() - ); - } - - public function testFinalClassNotSupported() - { - $this->assertSame( - 'Provided class "ProxyManagerTestAsset\FinalClass" is final and cannot be proxied', - InvalidProxiedClassException::finalClassNotSupported( - new ReflectionClass('ProxyManagerTestAsset\FinalClass') - )->getMessage() - ); - } - - public function testAbstractProtectedMethodsNotSupported() - { - $this->assertSame( - 'Provided class "ProxyManagerTestAsset\ClassWithAbstractProtectedMethod" has following protected abstract' - . ' methods, and therefore cannot be proxied:' . "\n" - . 'ProxyManagerTestAsset\ClassWithAbstractProtectedMethod::protectedAbstractMethod', - InvalidProxiedClassException::abstractProtectedMethodsNotSupported( - new ReflectionClass('ProxyManagerTestAsset\ClassWithAbstractProtectedMethod') - )->getMessage() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/InvalidProxyDirectoryExceptionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/InvalidProxyDirectoryExceptionTest.php deleted file mode 100644 index 71edab1..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/InvalidProxyDirectoryExceptionTest.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Exception\InvalidProxyDirectoryException - * @group Coverage - */ -class InvalidProxyDirectoryExceptionTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\Exception\InvalidProxyDirectoryException::proxyDirectoryNotFound - */ - public function testProxyDirectoryNotFound() - { - $exception = InvalidProxyDirectoryException::proxyDirectoryNotFound('foo/bar'); - - $this->assertSame('Provided directory "foo/bar" does not exist', $exception->getMessage()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/UnsupportedProxiedClassExceptionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/UnsupportedProxiedClassExceptionTest.php deleted file mode 100644 index 68977c8..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Exception/UnsupportedProxiedClassExceptionTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Exception\UnsupportedProxiedClassException - * @group Coverage - */ -class UnsupportedProxiedClassExceptionTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\Exception\UnsupportedProxiedClassException::unsupportedLocalizedReflectionProperty - */ - public function testUnsupportedLocalizedReflectionProperty() - { - $this->assertSame( - 'Provided reflection property "property0" of class "ProxyManagerTestAsset\ClassWithPrivateProperties" ' - . 'is private and cannot be localized in PHP 5.3', - UnsupportedProxiedClassException::unsupportedLocalizedReflectionProperty( - new ReflectionProperty('ProxyManagerTestAsset\ClassWithPrivateProperties', 'property0') - )->getMessage() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AbstractBaseFactoryTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AbstractBaseFactoryTest.php deleted file mode 100644 index 2c1b759..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AbstractBaseFactoryTest.php +++ /dev/null @@ -1,158 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Factory\AbstractBaseFactory - * @group Coverage - */ -class AbstractBaseFactoryTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \ProxyManager\Factory\AbstractBaseFactory - */ - private $factory; - - /** - * @var \ProxyManager\ProxyGenerator\ProxyGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $generator; - - /** - * @var \ProxyManager\Inflector\ClassNameInflectorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $classNameInflector; - - /** - * @var \ProxyManager\GeneratorStrategy\GeneratorStrategyInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $generatorStrategy; - - /** - * @var \ProxyManager\Autoloader\AutoloaderInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $proxyAutoloader; - - /** - * @var \ProxyManager\Signature\SignatureCheckerInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $signatureChecker; - - /** - * @var \ProxyManager\Signature\ClassSignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $classSignatureGenerator; - - /** - * {@inheritDoc} - */ - public function setUp() - { - $configuration = $this->getMock('ProxyManager\\Configuration'); - $this->generator = $this->getMock('ProxyManager\\ProxyGenerator\\ProxyGeneratorInterface'); - $this->classNameInflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - $this->generatorStrategy = $this->getMock('ProxyManager\\GeneratorStrategy\\GeneratorStrategyInterface'); - $this->proxyAutoloader = $this->getMock('ProxyManager\\Autoloader\\AutoloaderInterface'); - $this->signatureChecker = $this->getMock('ProxyManager\\Signature\\SignatureCheckerInterface'); - $this->classSignatureGenerator = $this->getMock('ProxyManager\\Signature\\ClassSignatureGeneratorInterface'); - - $configuration - ->expects($this->any()) - ->method('getClassNameInflector') - ->will($this->returnValue($this->classNameInflector)); - - $configuration - ->expects($this->any()) - ->method('getGeneratorStrategy') - ->will($this->returnValue($this->generatorStrategy)); - - $configuration - ->expects($this->any()) - ->method('getProxyAutoloader') - ->will($this->returnValue($this->proxyAutoloader)); - - $configuration - ->expects($this->any()) - ->method('getSignatureChecker') - ->will($this->returnValue($this->signatureChecker)); - - $configuration - ->expects($this->any()) - ->method('getClassSignatureGenerator') - ->will($this->returnValue($this->classSignatureGenerator)); - - $this - ->classNameInflector - ->expects($this->any()) - ->method('getUserClassName') - ->will($this->returnValue('stdClass')); - - $this->factory = $this->getMockForAbstractClass( - 'ProxyManager\\Factory\\AbstractBaseFactory', - array($configuration) - ); - - $this->factory->expects($this->any())->method('getGenerator')->will($this->returnValue($this->generator)); - } - - public function testGeneratesClass() - { - $generateProxy = new ReflectionMethod($this->factory, 'generateProxy'); - - $generateProxy->setAccessible(true); - $generatedClass = UniqueIdentifierGenerator::getIdentifier('fooBar'); - - $this - ->classNameInflector - ->expects($this->any()) - ->method('getProxyClassName') - ->with('stdClass') - ->will($this->returnValue($generatedClass)); - - $this - ->generatorStrategy - ->expects($this->once()) - ->method('generate') - ->with($this->isInstanceOf('Zend\\Code\\Generator\\ClassGenerator')); - $this - ->proxyAutoloader - ->expects($this->once()) - ->method('__invoke') - ->with($generatedClass) - ->will($this->returnCallback(function ($className) { - eval('class ' . $className . ' {}'); - })); - - $this->signatureChecker->expects($this->atLeastOnce())->method('checkSignature'); - $this->classSignatureGenerator->expects($this->once())->method('addSignature')->will($this->returnArgument(0)); - - $this->assertSame($generatedClass, $generateProxy->invoke($this->factory, 'stdClass')); - $this->assertTrue(class_exists($generatedClass, false)); - $this->assertSame($generatedClass, $generateProxy->invoke($this->factory, 'stdClass')); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AccessInterceptorScopeLocalizerFactoryTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AccessInterceptorScopeLocalizerFactoryTest.php deleted file mode 100644 index ce10d0c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AccessInterceptorScopeLocalizerFactoryTest.php +++ /dev/null @@ -1,199 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class AccessInterceptorScopeLocalizerFactoryTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $inflector; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $signatureChecker; - - /** - * @var \ProxyManager\Signature\ClassSignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $classSignatureGenerator; - - /** - * @var \ProxyManager\Configuration|\PHPUnit_Framework_MockObject_MockObject - */ - protected $config; - - /** - * {@inheritDoc} - */ - public function setUp() - { - $this->config = $this->getMock('ProxyManager\\Configuration'); - $this->inflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - $this->signatureChecker = $this->getMock('ProxyManager\\Signature\\SignatureCheckerInterface'); - $this->classSignatureGenerator = $this->getMock('ProxyManager\\Signature\\ClassSignatureGeneratorInterface'); - - $this - ->config - ->expects($this->any()) - ->method('getClassNameInflector') - ->will($this->returnValue($this->inflector)); - - $this - ->config - ->expects($this->any()) - ->method('getSignatureChecker') - ->will($this->returnValue($this->signatureChecker)); - - $this - ->config - ->expects($this->any()) - ->method('getClassSignatureGenerator') - ->will($this->returnValue($this->classSignatureGenerator)); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory::__construct - */ - public function testWithOptionalFactory() - { - $factory = new AccessInterceptorValueHolderFactory(); - $this->assertAttributeNotEmpty('configuration', $factory); - $this->assertAttributeInstanceOf('ProxyManager\Configuration', 'configuration', $factory); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory::__construct - * @covers \ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory::createProxy - * @covers \ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory::getGenerator - */ - public function testWillSkipAutoGeneration() - { - $instance = new stdClass(); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with('stdClass') - ->will($this->returnValue('ProxyManagerTestAsset\\AccessInterceptorValueHolderMock')); - - $factory = new AccessInterceptorScopeLocalizerFactory($this->config); - /* @var $proxy \ProxyManagerTestAsset\AccessInterceptorValueHolderMock */ - $proxy = $factory->createProxy($instance, array('foo'), array('bar')); - - $this->assertInstanceOf('ProxyManagerTestAsset\\AccessInterceptorValueHolderMock', $proxy); - $this->assertSame($instance, $proxy->instance); - $this->assertSame(array('foo'), $proxy->prefixInterceptors); - $this->assertSame(array('bar'), $proxy->suffixInterceptors); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory::__construct - * @covers \ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory::createProxy - * @covers \ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory::getGenerator - * - * NOTE: serious mocking going on in here (a class is generated on-the-fly) - careful - */ - public function testWillTryAutoGeneration() - { - $instance = new stdClass(); - $proxyClassName = UniqueIdentifierGenerator::getIdentifier('bar'); - $generator = $this->getMock('ProxyManager\GeneratorStrategy\\GeneratorStrategyInterface'); - $autoloader = $this->getMock('ProxyManager\\Autoloader\\AutoloaderInterface'); - - $this->config->expects($this->any())->method('getGeneratorStrategy')->will($this->returnValue($generator)); - $this->config->expects($this->any())->method('getProxyAutoloader')->will($this->returnValue($autoloader)); - - $generator - ->expects($this->once()) - ->method('generate') - ->with( - $this->callback( - function (ClassGenerator $targetClass) use ($proxyClassName) { - return $targetClass->getName() === $proxyClassName; - } - ) - ); - - // simulate autoloading - $autoloader - ->expects($this->once()) - ->method('__invoke') - ->with($proxyClassName) - ->will( - $this->returnCallback( - function () use ($proxyClassName) { - eval( - 'class ' . $proxyClassName - . ' extends \\ProxyManagerTestAsset\\AccessInterceptorValueHolderMock {}' - ); - } - ) - ); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with('stdClass') - ->will($this->returnValue($proxyClassName)); - - $this - ->inflector - ->expects($this->once()) - ->method('getUserClassName') - ->with('stdClass') - ->will($this->returnValue('ProxyManagerTestAsset\\LazyLoadingMock')); - - $this->signatureChecker->expects($this->atLeastOnce())->method('checkSignature'); - $this->classSignatureGenerator->expects($this->once())->method('addSignature')->will($this->returnArgument(0)); - - $factory = new AccessInterceptorScopeLocalizerFactory($this->config); - /* @var $proxy \ProxyManagerTestAsset\AccessInterceptorValueHolderMock */ - $proxy = $factory->createProxy($instance, array('foo'), array('bar')); - - $this->assertInstanceOf($proxyClassName, $proxy); - $this->assertSame($instance, $proxy->instance); - $this->assertSame(array('foo'), $proxy->prefixInterceptors); - $this->assertSame(array('bar'), $proxy->suffixInterceptors); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AccessInterceptorValueHolderFactoryTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AccessInterceptorValueHolderFactoryTest.php deleted file mode 100644 index a9a881c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/AccessInterceptorValueHolderFactoryTest.php +++ /dev/null @@ -1,198 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class AccessInterceptorValueHolderFactoryTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $inflector; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $signatureChecker; - - /** - * @var \ProxyManager\Signature\ClassSignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $classSignatureGenerator; - - /** - * @var \ProxyManager\Configuration|\PHPUnit_Framework_MockObject_MockObject - */ - protected $config; - - /** - * {@inheritDoc} - */ - public function setUp() - { - $this->config = $this->getMock('ProxyManager\\Configuration'); - $this->inflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - $this->signatureChecker = $this->getMock('ProxyManager\\Signature\\SignatureCheckerInterface'); - $this->classSignatureGenerator = $this->getMock('ProxyManager\\Signature\\ClassSignatureGeneratorInterface'); - - $this - ->config - ->expects($this->any()) - ->method('getClassNameInflector') - ->will($this->returnValue($this->inflector)); - - $this - ->config - ->expects($this->any()) - ->method('getSignatureChecker') - ->will($this->returnValue($this->signatureChecker)); - - $this - ->config - ->expects($this->any()) - ->method('getClassSignatureGenerator') - ->will($this->returnValue($this->classSignatureGenerator)); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\AccessInterceptorValueHolderFactory::__construct - */ - public function testWithOptionalFactory() - { - $factory = new AccessInterceptorValueHolderFactory(); - $this->assertAttributeNotEmpty('configuration', $factory); - $this->assertAttributeInstanceOf('ProxyManager\Configuration', 'configuration', $factory); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\AccessInterceptorValueHolderFactory::__construct - * @covers \ProxyManager\Factory\AccessInterceptorValueHolderFactory::createProxy - * @covers \ProxyManager\Factory\AccessInterceptorValueHolderFactory::getGenerator - */ - public function testWillSkipAutoGeneration() - { - $instance = new stdClass(); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with('stdClass') - ->will($this->returnValue('ProxyManagerTestAsset\\AccessInterceptorValueHolderMock')); - - $factory = new AccessInterceptorValueHolderFactory($this->config); - /* @var $proxy \ProxyManagerTestAsset\AccessInterceptorValueHolderMock */ - $proxy = $factory->createProxy($instance, array('foo'), array('bar')); - - $this->assertInstanceOf('ProxyManagerTestAsset\\AccessInterceptorValueHolderMock', $proxy); - $this->assertSame($instance, $proxy->instance); - $this->assertSame(array('foo'), $proxy->prefixInterceptors); - $this->assertSame(array('bar'), $proxy->suffixInterceptors); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\AccessInterceptorValueHolderFactory::__construct - * @covers \ProxyManager\Factory\AccessInterceptorValueHolderFactory::createProxy - * @covers \ProxyManager\Factory\AccessInterceptorValueHolderFactory::getGenerator - * - * NOTE: serious mocking going on in here (a class is generated on-the-fly) - careful - */ - public function testWillTryAutoGeneration() - { - $instance = new stdClass(); - $proxyClassName = UniqueIdentifierGenerator::getIdentifier('bar'); - $generator = $this->getMock('ProxyManager\GeneratorStrategy\\GeneratorStrategyInterface'); - $autoloader = $this->getMock('ProxyManager\\Autoloader\\AutoloaderInterface'); - - $this->config->expects($this->any())->method('getGeneratorStrategy')->will($this->returnValue($generator)); - $this->config->expects($this->any())->method('getProxyAutoloader')->will($this->returnValue($autoloader)); - - $generator - ->expects($this->once()) - ->method('generate') - ->with( - $this->callback( - function (ClassGenerator $targetClass) use ($proxyClassName) { - return $targetClass->getName() === $proxyClassName; - } - ) - ); - - // simulate autoloading - $autoloader - ->expects($this->once()) - ->method('__invoke') - ->with($proxyClassName) - ->will( - $this->returnCallback( - function () use ($proxyClassName) { - eval( - 'class ' . $proxyClassName - . ' extends \\ProxyManagerTestAsset\\AccessInterceptorValueHolderMock {}' - ); - } - ) - ); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with('stdClass') - ->will($this->returnValue($proxyClassName)); - - $this - ->inflector - ->expects($this->once()) - ->method('getUserClassName') - ->with('stdClass') - ->will($this->returnValue('ProxyManagerTestAsset\\LazyLoadingMock')); - - $this->signatureChecker->expects($this->atLeastOnce())->method('checkSignature'); - $this->classSignatureGenerator->expects($this->once())->method('addSignature')->will($this->returnArgument(0)); - - $factory = new AccessInterceptorValueHolderFactory($this->config); - /* @var $proxy \ProxyManagerTestAsset\AccessInterceptorValueHolderMock */ - $proxy = $factory->createProxy($instance, array('foo'), array('bar')); - - $this->assertInstanceOf($proxyClassName, $proxy); - $this->assertSame($instance, $proxy->instance); - $this->assertSame(array('foo'), $proxy->prefixInterceptors); - $this->assertSame(array('bar'), $proxy->suffixInterceptors); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/LazyLoadingGhostFactoryTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/LazyLoadingGhostFactoryTest.php deleted file mode 100644 index 2089f58..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/LazyLoadingGhostFactoryTest.php +++ /dev/null @@ -1,193 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class LazyLoadingGhostFactoryTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $inflector; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $signatureChecker; - - /** - * @var \ProxyManager\Signature\ClassSignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $classSignatureGenerator; - - /** - * @var \ProxyManager\Configuration|\PHPUnit_Framework_MockObject_MockObject - */ - protected $config; - - /** - * {@inheritDoc} - */ - public function setUp() - { - $this->config = $this->getMock('ProxyManager\\Configuration'); - $this->inflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - $this->signatureChecker = $this->getMock('ProxyManager\\Signature\\SignatureCheckerInterface'); - $this->classSignatureGenerator = $this->getMock('ProxyManager\\Signature\\ClassSignatureGeneratorInterface'); - - $this - ->config - ->expects($this->any()) - ->method('getClassNameInflector') - ->will($this->returnValue($this->inflector)); - - $this - ->config - ->expects($this->any()) - ->method('getSignatureChecker') - ->will($this->returnValue($this->signatureChecker)); - - $this - ->config - ->expects($this->any()) - ->method('getClassSignatureGenerator') - ->will($this->returnValue($this->classSignatureGenerator)); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\LazyLoadingGhostFactory::__construct - */ - public function testWithOptionalFactory() - { - $factory = new LazyLoadingGhostFactory(); - $this->assertAttributeNotEmpty('configuration', $factory); - $this->assertAttributeInstanceOf('ProxyManager\Configuration', 'configuration', $factory); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\LazyLoadingGhostFactory::__construct - * @covers \ProxyManager\Factory\LazyLoadingGhostFactory::createProxy - */ - public function testWillSkipAutoGeneration() - { - $className = UniqueIdentifierGenerator::getIdentifier('foo'); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with($className) - ->will($this->returnValue('ProxyManagerTestAsset\\LazyLoadingMock')); - - $factory = new LazyLoadingGhostFactory($this->config); - $initializer = function () { - }; - /* @var $proxy \ProxyManagerTestAsset\LazyLoadingMock */ - $proxy = $factory->createProxy($className, $initializer); - - $this->assertInstanceOf('ProxyManagerTestAsset\\LazyLoadingMock', $proxy); - $this->assertSame($initializer, $proxy->initializer); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\LazyLoadingGhostFactory::__construct - * @covers \ProxyManager\Factory\LazyLoadingGhostFactory::createProxy - * @covers \ProxyManager\Factory\LazyLoadingGhostFactory::getGenerator - * - * NOTE: serious mocking going on in here (a class is generated on-the-fly) - careful - */ - public function testWillTryAutoGeneration() - { - $className = UniqueIdentifierGenerator::getIdentifier('foo'); - $proxyClassName = UniqueIdentifierGenerator::getIdentifier('bar'); - $generator = $this->getMock('ProxyManager\\GeneratorStrategy\\GeneratorStrategyInterface'); - $autoloader = $this->getMock('ProxyManager\\Autoloader\\AutoloaderInterface'); - - $this->config->expects($this->any())->method('getGeneratorStrategy')->will($this->returnValue($generator)); - $this->config->expects($this->any())->method('getProxyAutoloader')->will($this->returnValue($autoloader)); - - $generator - ->expects($this->once()) - ->method('generate') - ->with( - $this->callback( - function (ClassGenerator $targetClass) use ($proxyClassName) { - return $targetClass->getName() === $proxyClassName; - } - ) - ); - - // simulate autoloading - $autoloader - ->expects($this->once()) - ->method('__invoke') - ->with($proxyClassName) - ->will( - $this->returnCallback( - function () use ($proxyClassName) { - eval('class ' . $proxyClassName . ' extends \\ProxyManagerTestAsset\\LazyLoadingMock {}'); - } - ) - ); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with($className) - ->will($this->returnValue($proxyClassName)); - - $this - ->inflector - ->expects($this->once()) - ->method('getUserClassName') - ->with($className) - ->will($this->returnValue('ProxyManagerTestAsset\\LazyLoadingMock')); - - $this->signatureChecker->expects($this->atLeastOnce())->method('checkSignature'); - $this->classSignatureGenerator->expects($this->once())->method('addSignature')->will($this->returnArgument(0)); - - $factory = new LazyLoadingGhostFactory($this->config); - $initializer = function () { - }; - /* @var $proxy \ProxyManagerTestAsset\LazyLoadingMock */ - $proxy = $factory->createProxy($className, $initializer); - - $this->assertInstanceOf($proxyClassName, $proxy); - $this->assertSame($initializer, $proxy->initializer); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/LazyLoadingValueHolderFactoryTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/LazyLoadingValueHolderFactoryTest.php deleted file mode 100644 index 31c0f3b..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/LazyLoadingValueHolderFactoryTest.php +++ /dev/null @@ -1,193 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class LazyLoadingValueHolderFactoryTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $inflector; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $signatureChecker; - - /** - * @var \ProxyManager\Signature\ClassSignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $classSignatureGenerator; - - /** - * @var \ProxyManager\Configuration|\PHPUnit_Framework_MockObject_MockObject - */ - protected $config; - - /** - * {@inheritDoc} - */ - public function setUp() - { - $this->config = $this->getMock('ProxyManager\\Configuration'); - $this->inflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - $this->signatureChecker = $this->getMock('ProxyManager\\Signature\\SignatureCheckerInterface'); - $this->classSignatureGenerator = $this->getMock('ProxyManager\\Signature\\ClassSignatureGeneratorInterface'); - - $this - ->config - ->expects($this->any()) - ->method('getClassNameInflector') - ->will($this->returnValue($this->inflector)); - - $this - ->config - ->expects($this->any()) - ->method('getSignatureChecker') - ->will($this->returnValue($this->signatureChecker)); - - $this - ->config - ->expects($this->any()) - ->method('getClassSignatureGenerator') - ->will($this->returnValue($this->classSignatureGenerator)); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\LazyLoadingValueHolderFactory::__construct - */ - public function testWithOptionalFactory() - { - $factory = new LazyLoadingValueHolderFactory(); - $this->assertAttributeNotEmpty('configuration', $factory); - $this->assertAttributeInstanceOf('ProxyManager\Configuration', 'configuration', $factory); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\LazyLoadingValueHolderFactory::__construct - * @covers \ProxyManager\Factory\LazyLoadingValueHolderFactory::createProxy - */ - public function testWillSkipAutoGeneration() - { - $className = UniqueIdentifierGenerator::getIdentifier('foo'); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with($className) - ->will($this->returnValue('ProxyManagerTestAsset\\LazyLoadingMock')); - - $factory = new LazyLoadingValueHolderFactory($this->config); - $initializer = function () { - }; - /* @var $proxy \ProxyManagerTestAsset\LazyLoadingMock */ - $proxy = $factory->createProxy($className, $initializer); - - $this->assertInstanceOf('ProxyManagerTestAsset\\LazyLoadingMock', $proxy); - $this->assertSame($initializer, $proxy->initializer); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\LazyLoadingValueHolderFactory::__construct - * @covers \ProxyManager\Factory\LazyLoadingValueHolderFactory::createProxy - * @covers \ProxyManager\Factory\LazyLoadingValueHolderFactory::getGenerator - * - * NOTE: serious mocking going on in here (a class is generated on-the-fly) - careful - */ - public function testWillTryAutoGeneration() - { - $className = UniqueIdentifierGenerator::getIdentifier('foo'); - $proxyClassName = UniqueIdentifierGenerator::getIdentifier('bar'); - $generator = $this->getMock('ProxyManager\\GeneratorStrategy\\GeneratorStrategyInterface'); - $autoloader = $this->getMock('ProxyManager\\Autoloader\\AutoloaderInterface'); - - $this->config->expects($this->any())->method('getGeneratorStrategy')->will($this->returnValue($generator)); - $this->config->expects($this->any())->method('getProxyAutoloader')->will($this->returnValue($autoloader)); - - $generator - ->expects($this->once()) - ->method('generate') - ->with( - $this->callback( - function (ClassGenerator $targetClass) use ($proxyClassName) { - return $targetClass->getName() === $proxyClassName; - } - ) - ); - - // simulate autoloading - $autoloader - ->expects($this->once()) - ->method('__invoke') - ->with($proxyClassName) - ->will( - $this->returnCallback( - function () use ($proxyClassName) { - eval('class ' . $proxyClassName . ' extends \\ProxyManagerTestAsset\\LazyLoadingMock {}'); - } - ) - ); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with($className) - ->will($this->returnValue($proxyClassName)); - - $this - ->inflector - ->expects($this->once()) - ->method('getUserClassName') - ->with($className) - ->will($this->returnValue('ProxyManagerTestAsset\\LazyLoadingMock')); - - $this->signatureChecker->expects($this->atLeastOnce())->method('checkSignature'); - $this->classSignatureGenerator->expects($this->once())->method('addSignature')->will($this->returnArgument(0)); - - $factory = new LazyLoadingValueHolderFactory($this->config); - $initializer = function () { - }; - /* @var $proxy \ProxyManagerTestAsset\LazyLoadingMock */ - $proxy = $factory->createProxy($className, $initializer); - - $this->assertInstanceOf($proxyClassName, $proxy); - $this->assertSame($initializer, $proxy->initializer); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/NullObjectFactoryTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/NullObjectFactoryTest.php deleted file mode 100644 index ef3f2a7..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/NullObjectFactoryTest.php +++ /dev/null @@ -1,180 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class NullObjectFactoryTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $inflector; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $signatureChecker; - - /** - * @var \ProxyManager\Signature\ClassSignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $classSignatureGenerator; - - /** - * @var \ProxyManager\Configuration|\PHPUnit_Framework_MockObject_MockObject - */ - protected $config; - - /** - * {@inheritDoc} - */ - public function setUp() - { - $this->config = $this->getMock('ProxyManager\\Configuration'); - $this->inflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - $this->signatureChecker = $this->getMock('ProxyManager\\Signature\\SignatureCheckerInterface'); - $this->classSignatureGenerator = $this->getMock('ProxyManager\\Signature\\ClassSignatureGeneratorInterface'); - - $this - ->config - ->expects($this->any()) - ->method('getClassNameInflector') - ->will($this->returnValue($this->inflector)); - - $this - ->config - ->expects($this->any()) - ->method('getSignatureChecker') - ->will($this->returnValue($this->signatureChecker)); - - $this - ->config - ->expects($this->any()) - ->method('getClassSignatureGenerator') - ->will($this->returnValue($this->classSignatureGenerator)); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\NullObjectFactory::__construct - * @covers \ProxyManager\Factory\NullObjectFactory::createProxy - * @covers \ProxyManager\Factory\NullObjectFactory::getGenerator - */ - public function testWillSkipAutoGeneration() - { - $instance = new stdClass(); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with('stdClass') - ->will($this->returnValue('ProxyManagerTestAsset\\NullObjectMock')); - - $factory = new NullObjectFactory($this->config); - /* @var $proxy \ProxyManagerTestAsset\NullObjectMock */ - $proxy = $factory->createProxy($instance); - - $this->assertInstanceOf('ProxyManagerTestAsset\\NullObjectMock', $proxy); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\NullObjectFactory::__construct - * @covers \ProxyManager\Factory\NullObjectFactory::createProxy - * @covers \ProxyManager\Factory\NullObjectFactory::getGenerator - * - * NOTE: serious mocking going on in here (a class is generated on-the-fly) - careful - */ - public function testWillTryAutoGeneration() - { - $instance = new stdClass(); - $proxyClassName = UniqueIdentifierGenerator::getIdentifier('bar'); - $generator = $this->getMock('ProxyManager\GeneratorStrategy\\GeneratorStrategyInterface'); - $autoloader = $this->getMock('ProxyManager\\Autoloader\\AutoloaderInterface'); - - $this->config->expects($this->any())->method('getGeneratorStrategy')->will($this->returnValue($generator)); - $this->config->expects($this->any())->method('getProxyAutoloader')->will($this->returnValue($autoloader)); - - $generator - ->expects($this->once()) - ->method('generate') - ->with( - $this->callback( - function (ClassGenerator $targetClass) use ($proxyClassName) { - return $targetClass->getName() === $proxyClassName; - } - ) - ); - - // simulate autoloading - $autoloader - ->expects($this->once()) - ->method('__invoke') - ->with($proxyClassName) - ->will( - $this->returnCallback( - function () use ($proxyClassName) { - eval( - 'class ' . $proxyClassName - . ' extends \\ProxyManagerTestAsset\\NullObjectMock {}' - ); - } - ) - ); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with('stdClass') - ->will($this->returnValue($proxyClassName)); - - $this - ->inflector - ->expects($this->once()) - ->method('getUserClassName') - ->with('stdClass') - ->will($this->returnValue('ProxyManagerTestAsset\\NullObjectMock')); - - $this->signatureChecker->expects($this->atLeastOnce())->method('checkSignature'); - $this->classSignatureGenerator->expects($this->once())->method('addSignature')->will($this->returnArgument(0)); - - $factory = new NullObjectFactory($this->config); - /* @var $proxy \ProxyManagerTestAsset\NullObjectMock */ - $proxy = $factory->createProxy($instance); - - $this->assertInstanceOf($proxyClassName, $proxy); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/BaseAdapterTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/BaseAdapterTest.php deleted file mode 100644 index df70ce8..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/BaseAdapterTest.php +++ /dev/null @@ -1,101 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class BaseAdapterTest extends PHPUnit_Framework_TestCase -{ - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\RemoteObject\Adapter\BaseAdapter::__construct - * @covers \ProxyManager\Factory\RemoteObject\Adapter\BaseAdapter::call - * @covers \ProxyManager\Factory\RemoteObject\Adapter\Soap::getServiceName - */ - public function testBaseAdapter() - { - $client = $this - ->getMockBuilder('Zend\Server\Client') - ->setMethods(array('call')) - ->getMock(); - - $adapter = $this->getMockForAbstractClass( - 'ProxyManager\\Factory\\RemoteObject\\Adapter\\BaseAdapter', - array($client) - ); - - $client - ->expects($this->once()) - ->method('call') - ->with('foobarbaz', array('tab' => 'taz')) - ->will($this->returnValue('baz')); - - $adapter - ->expects($this->once()) - ->method('getServiceName') - ->with('foo', 'bar') - ->will($this->returnValue('foobarbaz')); - - $this->assertSame('baz', $adapter->call('foo', 'bar', array('tab' => 'taz'))); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\RemoteObject\Adapter\BaseAdapter::__construct - * @covers \ProxyManager\Factory\RemoteObject\Adapter\BaseAdapter::call - * @covers \ProxyManager\Factory\RemoteObject\Adapter\Soap::getServiceName - */ - public function testBaseAdapterWithServiceMap() - { - $client = $this - ->getMockBuilder('Zend\Server\Client') - ->setMethods(array('call')) - ->getMock(); - - $adapter = $this->getMockForAbstractClass( - 'ProxyManager\\Factory\\RemoteObject\\Adapter\\BaseAdapter', - array($client, array('foobarbaz' => 'mapped')) - ); - - $client - ->expects($this->once()) - ->method('call') - ->with('mapped', array('tab' => 'taz')) - ->will($this->returnValue('baz')); - - $adapter - ->expects($this->once()) - ->method('getServiceName') - ->with('foo', 'bar') - ->will($this->returnValue('foobarbaz')); - - $this->assertSame('baz', $adapter->call('foo', 'bar', array('tab' => 'taz'))); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/JsonRpcTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/JsonRpcTest.php deleted file mode 100644 index 66e80d7..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/JsonRpcTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class JsonRpcTest extends PHPUnit_Framework_TestCase -{ - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\RemoteObject\Adapter\JsonRpc::__construct - * @covers \ProxyManager\Factory\RemoteObject\Adapter\JsonRpc::getServiceName - */ - public function testCanBuildAdapterWithJsonRpcClient() - { - $client = $this - ->getMockBuilder('Zend\Server\Client') - ->setMethods(array('call')) - ->getMock(); - - $adapter = new JsonRpc($client); - - $client - ->expects($this->once()) - ->method('call') - ->with('foo.bar', array('tab' => 'taz')) - ->will($this->returnValue('baz')); - - $this->assertSame('baz', $adapter->call('foo', 'bar', array('tab' => 'taz'))); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/SoapTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/SoapTest.php deleted file mode 100644 index fe93e00..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/SoapTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class SoapTest extends PHPUnit_Framework_TestCase -{ - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\RemoteObject\Adapter\Soap::__construct - * @covers \ProxyManager\Factory\RemoteObject\Adapter\Soap::getServiceName - */ - public function testCanBuildAdapterWithSoapRpcClient() - { - $client = $this - ->getMockBuilder('Zend\Server\Client') - ->setMethods(array('call')) - ->getMock(); - - $adapter = new Soap($client); - - $client - ->expects($this->once()) - ->method('call') - ->with('bar', array('tab' => 'taz')) - ->will($this->returnValue('baz')); - - $this->assertSame('baz', $adapter->call('foo', 'bar', array('tab' => 'taz'))); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/XmlRpcTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/XmlRpcTest.php deleted file mode 100644 index d795e40..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObject/Adapter/XmlRpcTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class XmlRpcTest extends PHPUnit_Framework_TestCase -{ - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\RemoteObject\Adapter\XmlRpc::__construct - * @covers \ProxyManager\Factory\RemoteObject\Adapter\XmlRpc::getServiceName - */ - public function testCanBuildAdapterWithXmlRpcClient() - { - $client = $this - ->getMockBuilder('Zend\Server\Client') - ->setMethods(array('call')) - ->getMock(); - - $adapter = new XmlRpc($client); - - $client - ->expects($this->once()) - ->method('call') - ->with('foo.bar', array('tab' => 'taz')) - ->will($this->returnValue('baz')); - - $this->assertSame('baz', $adapter->call('foo', 'bar', array('tab' => 'taz'))); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObjectFactoryTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObjectFactoryTest.php deleted file mode 100644 index a7385e0..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Factory/RemoteObjectFactoryTest.php +++ /dev/null @@ -1,178 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class RemoteObjectFactoryTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $inflector; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $signatureChecker; - - /** - * @var \ProxyManager\Signature\ClassSignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $classSignatureGenerator; - - /** - * @var \ProxyManager\Configuration|\PHPUnit_Framework_MockObject_MockObject - */ - protected $config; - - /** - * {@inheritDoc} - */ - public function setUp() - { - $this->config = $this->getMock('ProxyManager\\Configuration'); - $this->inflector = $this->getMock('ProxyManager\\Inflector\\ClassNameInflectorInterface'); - $this->signatureChecker = $this->getMock('ProxyManager\\Signature\\SignatureCheckerInterface'); - $this->classSignatureGenerator = $this->getMock('ProxyManager\\Signature\\ClassSignatureGeneratorInterface'); - - $this - ->config - ->expects($this->any()) - ->method('getClassNameInflector') - ->will($this->returnValue($this->inflector)); - - $this - ->config - ->expects($this->any()) - ->method('getSignatureChecker') - ->will($this->returnValue($this->signatureChecker)); - - $this - ->config - ->expects($this->any()) - ->method('getClassSignatureGenerator') - ->will($this->returnValue($this->classSignatureGenerator)); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\RemoteObjectFactory::__construct - * @covers \ProxyManager\Factory\RemoteObjectFactory::createProxy - * @covers \ProxyManager\Factory\RemoteObjectFactory::getGenerator - */ - public function testWillSkipAutoGeneration() - { - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with('ProxyManagerTestAsset\\BaseInterface') - ->will($this->returnValue('StdClass')); - - $adapter = $this->getMock('ProxyManager\Factory\RemoteObject\AdapterInterface'); - $factory = new RemoteObjectFactory($adapter, $this->config); - /* @var $proxy \stdClass */ - $proxy = $factory->createProxy('ProxyManagerTestAsset\\BaseInterface', $adapter); - - $this->assertInstanceOf('stdClass', $proxy); - } - - /** - * {@inheritDoc} - * - * @covers \ProxyManager\Factory\RemoteObjectFactory::__construct - * @covers \ProxyManager\Factory\RemoteObjectFactory::createProxy - * @covers \ProxyManager\Factory\RemoteObjectFactory::getGenerator - * - * NOTE: serious mocking going on in here (a class is generated on-the-fly) - careful - */ - public function testWillTryAutoGeneration() - { - $proxyClassName = UniqueIdentifierGenerator::getIdentifier('bar'); - $generator = $this->getMock('ProxyManager\GeneratorStrategy\\GeneratorStrategyInterface'); - $autoloader = $this->getMock('ProxyManager\\Autoloader\\AutoloaderInterface'); - - $this->config->expects($this->any())->method('getGeneratorStrategy')->will($this->returnValue($generator)); - $this->config->expects($this->any())->method('getProxyAutoloader')->will($this->returnValue($autoloader)); - - $generator - ->expects($this->once()) - ->method('generate') - ->with( - $this->callback( - function (ClassGenerator $targetClass) use ($proxyClassName) { - return $targetClass->getName() === $proxyClassName; - } - ) - ); - - // simulate autoloading - $autoloader - ->expects($this->once()) - ->method('__invoke') - ->with($proxyClassName) - ->will( - $this->returnCallback( - function () use ($proxyClassName) { - eval( - 'class ' . $proxyClassName - . ' extends stdClass {}' - ); - } - ) - ); - - $this - ->inflector - ->expects($this->once()) - ->method('getProxyClassName') - ->with('ProxyManagerTestAsset\\BaseInterface') - ->will($this->returnValue($proxyClassName)); - - $this - ->inflector - ->expects($this->once()) - ->method('getUserClassName') - ->with('ProxyManagerTestAsset\\BaseInterface') - ->will($this->returnValue('stdClass')); - - $this->signatureChecker->expects($this->atLeastOnce())->method('checkSignature'); - $this->classSignatureGenerator->expects($this->once())->method('addSignature')->will($this->returnArgument(0)); - - $adapter = $this->getMock('ProxyManager\Factory\RemoteObject\AdapterInterface'); - $factory = new RemoteObjectFactory($adapter, $this->config); - /* @var $proxy \stdClass */ - $proxy = $factory->createProxy('ProxyManagerTestAsset\\BaseInterface', $adapter); - - $this->assertInstanceOf($proxyClassName, $proxy); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/FileLocator/FileLocatorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/FileLocator/FileLocatorTest.php deleted file mode 100644 index 92991a0..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/FileLocator/FileLocatorTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class FileLocatorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\FileLocator\FileLocator::__construct - * @covers \ProxyManager\FileLocator\FileLocator::getProxyFileName - */ - public function testGetProxyFileName() - { - $locator = new FileLocator(__DIR__); - - $this->assertSame(__DIR__ . DIRECTORY_SEPARATOR . 'FooBarBaz.php', $locator->getProxyFileName('Foo\\Bar\\Baz')); - $this->assertSame(__DIR__ . DIRECTORY_SEPARATOR . 'Foo_Bar_Baz.php', $locator->getProxyFileName('Foo_Bar_Baz')); - } - - /** - * @covers \ProxyManager\FileLocator\FileLocator::__construct - */ - public function testRejectsNonExistingDirectory() - { - $this->setExpectedException('ProxyManager\\Exception\\InvalidProxyDirectoryException'); - new FileLocator(__DIR__ . '/non-existing'); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/AccessInterceptorScopeLocalizerFunctionalTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/AccessInterceptorScopeLocalizerFunctionalTest.php deleted file mode 100644 index 2e8984d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/AccessInterceptorScopeLocalizerFunctionalTest.php +++ /dev/null @@ -1,388 +0,0 @@ - - * @license MIT - * - * @group Functional - * @coversNothing - */ -class AccessInterceptorScopeLocalizerFunctionalTest extends PHPUnit_Framework_TestCase -{ - /** - * {@inheritDoc} - */ - public static function setUpBeforeClass() - { - if (! method_exists('Closure', 'bind')) { - throw new PHPUnit_Framework_SkippedTestError( - 'PHP 5.3 doesn\'t support scope localization of private properties' - ); - } - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCalls($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface */ - $proxy = new $proxyName($instance); - - $this->assertProxySynchronized($instance, $proxy); - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - - $listener = $this->getMock('stdClass', array('__invoke')); - $listener - ->expects($this->once()) - ->method('__invoke') - ->with($proxy, $proxy, $method, $params, false); - - $proxy->setMethodPrefixInterceptor( - $method, - function ($proxy, $instance, $method, $params, & $returnEarly) use ($listener) { - $listener->__invoke($proxy, $instance, $method, $params, $returnEarly); - } - ); - - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - - $random = uniqid(); - - $proxy->setMethodPrefixInterceptor( - $method, - function ($proxy, $instance, $method, $params, & $returnEarly) use ($random) { - $returnEarly = true; - - return $random; - } - ); - - $this->assertSame($random, call_user_func_array(array($proxy, $method), $params)); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsWithSuffixListener($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface */ - $proxy = new $proxyName($instance); - $listener = $this->getMock('stdClass', array('__invoke')); - $listener - ->expects($this->once()) - ->method('__invoke') - ->with($proxy, $proxy, $method, $params, $expectedValue, false); - - $proxy->setMethodSuffixInterceptor( - $method, - function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) use ($listener) { - $listener->__invoke($proxy, $instance, $method, $params, $returnValue, $returnEarly); - } - ); - - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - - $random = uniqid(); - - $proxy->setMethodSuffixInterceptor( - $method, - function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) use ($random) { - $returnEarly = true; - - return $random; - } - ); - - $this->assertSame($random, call_user_func_array(array($proxy, $method), $params)); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterUnSerialization($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface */ - $proxy = unserialize(serialize(new $proxyName($instance))); - - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterCloning($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface */ - $proxy = new $proxyName($instance); - $cloned = clone $proxy; - - $this->assertProxySynchronized($instance, $proxy); - $this->assertSame($expectedValue, call_user_func_array(array($cloned, $method), $params)); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyReadAccess($instance, $proxy, $publicProperty, $propertyValue) - { - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface */ - $this->assertSame($propertyValue, $proxy->$publicProperty); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyWriteAccess($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface */ - $newValue = uniqid(); - $proxy->$publicProperty = $newValue; - - $this->assertSame($newValue, $proxy->$publicProperty); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyExistence($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface */ - $this->assertSame(isset($instance->$publicProperty), isset($proxy->$publicProperty)); - $this->assertProxySynchronized($instance, $proxy); - - $instance->$publicProperty = null; - $this->assertFalse(isset($proxy->$publicProperty)); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyUnset($instance, $proxy, $publicProperty) - { - $this->markTestSkipped('It is currently not possible to synchronize properties un-setting'); - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface */ - unset($proxy->$publicProperty); - - $this->assertFalse(isset($instance->$publicProperty)); - $this->assertFalse(isset($proxy->$publicProperty)); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * Verifies that accessing a public property containing an array behaves like in a normal context - */ - public function testCanWriteToArrayKeysInPublicProperty() - { - $instance = new ClassWithPublicArrayProperty(); - $className = get_class($instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicArrayProperty */ - $proxy = new $proxyName($instance); - - $proxy->arrayProperty['foo'] = 'bar'; - - $this->assertSame('bar', $proxy->arrayProperty['foo']); - - $proxy->arrayProperty = array('tab' => 'taz'); - - $this->assertSame(array('tab' => 'taz'), $proxy->arrayProperty); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * Verifies that public properties retrieved via `__get` don't get modified in the object state - */ - public function testWillNotModifyRetrievedPublicProperties() - { - $instance = new ClassWithPublicProperties(); - $className = get_class($instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName($instance); - $variable = $proxy->property0; - - $this->assertSame('property0', $variable); - - $variable = 'foo'; - - $this->assertSame('property0', $proxy->property0); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * Verifies that public properties references retrieved via `__get` modify in the object state - */ - public function testWillModifyByRefRetrievedPublicProperties() - { - $instance = new ClassWithPublicProperties(); - $className = get_class($instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName($instance); - $variable = & $proxy->property0; - - $this->assertSame('property0', $variable); - - $variable = 'foo'; - - $this->assertSame('foo', $proxy->property0); - $this->assertProxySynchronized($instance, $proxy); - } - - /** - * Generates a proxy for the given class name, and retrieves its class name - * - * @param string $parentClassName - * - * @return string - * - * @throws UnsupportedProxiedClassException - */ - private function generateProxy($parentClassName) - { - $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo'); - $generator = new AccessInterceptorScopeLocalizerGenerator(); - $generatedClass = new ClassGenerator($generatedClassName); - $strategy = new EvaluatingGeneratorStrategy(); - - $generator->generate(new ReflectionClass($parentClassName), $generatedClass); - $strategy->generate($generatedClass); - - return $generatedClassName; - } - - /** - * Generates a list of object | invoked method | parameters | expected result - * - * @return array - */ - public function getProxyMethods() - { - $selfHintParam = new ClassWithSelfHint(); - - $data = array( - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicMethod', - array(), - 'publicMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicTypeHintedMethod', - array('param' => new \stdClass()), - 'publicTypeHintedMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicByReferenceMethod', - array(), - 'publicByReferenceMethodDefault' - ), - ); - - if (PHP_VERSION_ID >= 50401) { - // PHP < 5.4.1 misbehaves, throwing strict standards, see https://bugs.php.net/bug.php?id=60573 - $data[] = array( - 'ProxyManagerTestAsset\\ClassWithSelfHint', - new ClassWithSelfHint(), - 'selfHintMethod', - array('parameter' => $selfHintParam), - $selfHintParam - ); - } - - return $data; - } - - /** - * Generates proxies and instances with a public property to feed to the property accessor methods - * - * @return array - */ - public function getPropertyAccessProxies() - { - $instance1 = new BaseClass(); - $proxyName1 = $this->generateProxy(get_class($instance1)); - - return array( - array( - $instance1, - new $proxyName1($instance1), - 'publicProperty', - 'publicPropertyDefault', - ), - ); - } - - /** - * @param object $instance - * @param AccessInterceptorInterface $proxy - */ - private function assertProxySynchronized($instance, AccessInterceptorInterface $proxy) - { - $reflectionClass = new ReflectionClass($instance); - - foreach ($reflectionClass->getProperties() as $property) { - $property->setAccessible(true); - - $this->assertSame( - $property->getValue($instance), - $property->getValue($proxy), - 'Property "' . $property->getName() . '" is synchronized between instance and proxy' - ); - } - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/AccessInterceptorValueHolderFunctionalTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/AccessInterceptorValueHolderFunctionalTest.php deleted file mode 100644 index 7740e2e..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/AccessInterceptorValueHolderFunctionalTest.php +++ /dev/null @@ -1,360 +0,0 @@ - - * @license MIT - * - * @group Functional - * @coversNothing - */ -class AccessInterceptorValueHolderFunctionalTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getProxyMethods - */ - public function testMethodCalls($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */ - $proxy = new $proxyName($instance); - - $this->assertSame($instance, $proxy->getWrappedValueHolderValue()); - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - - $listener = $this->getMock('stdClass', array('__invoke')); - $listener - ->expects($this->once()) - ->method('__invoke') - ->with($proxy, $instance, $method, $params, false); - - $proxy->setMethodPrefixInterceptor( - $method, - function ($proxy, $instance, $method, $params, & $returnEarly) use ($listener) { - $listener->__invoke($proxy, $instance, $method, $params, $returnEarly); - } - ); - - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - - $random = uniqid(); - - $proxy->setMethodPrefixInterceptor( - $method, - function ($proxy, $instance, $method, $params, & $returnEarly) use ($random) { - $returnEarly = true; - - return $random; - } - ); - - $this->assertSame($random, call_user_func_array(array($proxy, $method), $params)); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsWithSuffixListener($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */ - $proxy = new $proxyName($instance); - $listener = $this->getMock('stdClass', array('__invoke')); - $listener - ->expects($this->once()) - ->method('__invoke') - ->with($proxy, $instance, $method, $params, $expectedValue, false); - - $proxy->setMethodSuffixInterceptor( - $method, - function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) use ($listener) { - $listener->__invoke($proxy, $instance, $method, $params, $returnValue, $returnEarly); - } - ); - - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - - $random = uniqid(); - - $proxy->setMethodSuffixInterceptor( - $method, - function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) use ($random) { - $returnEarly = true; - - return $random; - } - ); - - $this->assertSame($random, call_user_func_array(array($proxy, $method), $params)); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterUnSerialization($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */ - $proxy = unserialize(serialize(new $proxyName($instance))); - - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - $this->assertEquals($instance, $proxy->getWrappedValueHolderValue()); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterCloning($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */ - $proxy = new $proxyName($instance); - $cloned = clone $proxy; - - $this->assertNotSame($proxy->getWrappedValueHolderValue(), $cloned->getWrappedValueHolderValue()); - $this->assertSame($expectedValue, call_user_func_array(array($cloned, $method), $params)); - $this->assertEquals($instance, $cloned->getWrappedValueHolderValue()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyReadAccess($instance, $proxy, $publicProperty, $propertyValue) - { - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */ - $this->assertSame($propertyValue, $proxy->$publicProperty); - $this->assertEquals($instance, $proxy->getWrappedValueHolderValue()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyWriteAccess($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */ - $newValue = uniqid(); - $proxy->$publicProperty = $newValue; - - $this->assertSame($newValue, $proxy->$publicProperty); - $this->assertSame($newValue, $proxy->getWrappedValueHolderValue()->$publicProperty); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyExistence($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */ - $this->assertSame(isset($instance->$publicProperty), isset($proxy->$publicProperty)); - $this->assertEquals($instance, $proxy->getWrappedValueHolderValue()); - - $proxy->getWrappedValueHolderValue()->$publicProperty = null; - $this->assertFalse(isset($proxy->$publicProperty)); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyUnset($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */ - $instance = $proxy->getWrappedValueHolderValue() ? $proxy->getWrappedValueHolderValue() : $instance; - unset($proxy->$publicProperty); - - $this->assertFalse(isset($instance->$publicProperty)); - $this->assertFalse(isset($proxy->$publicProperty)); - } - - /** - * Verifies that accessing a public property containing an array behaves like in a normal context - */ - public function testCanWriteToArrayKeysInPublicProperty() - { - $instance = new ClassWithPublicArrayProperty(); - $className = get_class($instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicArrayProperty */ - $proxy = new $proxyName($instance); - - $proxy->arrayProperty['foo'] = 'bar'; - - $this->assertSame('bar', $proxy->arrayProperty['foo']); - - $proxy->arrayProperty = array('tab' => 'taz'); - - $this->assertSame(array('tab' => 'taz'), $proxy->arrayProperty); - } - - /** - * Verifies that public properties retrieved via `__get` don't get modified in the object state - */ - public function testWillNotModifyRetrievedPublicProperties() - { - $instance = new ClassWithPublicProperties(); - $className = get_class($instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName($instance); - $variable = $proxy->property0; - - $this->assertSame('property0', $variable); - - $variable = 'foo'; - - $this->assertSame('property0', $proxy->property0); - } - - /** - * Verifies that public properties references retrieved via `__get` modify in the object state - */ - public function testWillModifyByRefRetrievedPublicProperties() - { - $instance = new ClassWithPublicProperties(); - $className = get_class($instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName($instance); - $variable = & $proxy->property0; - - $this->assertSame('property0', $variable); - - $variable = 'foo'; - - $this->assertSame('foo', $proxy->property0); - } - - /** - * Generates a proxy for the given class name, and retrieves its class name - * - * @param string $parentClassName - * - * @return string - */ - private function generateProxy($parentClassName) - { - $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo'); - $generator = new AccessInterceptorValueHolderGenerator(); - $generatedClass = new ClassGenerator($generatedClassName); - $strategy = new EvaluatingGeneratorStrategy(); - - $generator->generate(new ReflectionClass($parentClassName), $generatedClass); - $strategy->generate($generatedClass); - - return $generatedClassName; - } - - /** - * Generates a list of object | invoked method | parameters | expected result - * - * @return array - */ - public function getProxyMethods() - { - $selfHintParam = new ClassWithSelfHint(); - - $data = array( - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicMethod', - array(), - 'publicMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicTypeHintedMethod', - array('param' => new \stdClass()), - 'publicTypeHintedMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicByReferenceMethod', - array(), - 'publicByReferenceMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseInterface', - new BaseClass(), - 'publicMethod', - array(), - 'publicMethodDefault' - ), - ); - - if (PHP_VERSION_ID >= 50401) { - // PHP < 5.4.1 misbehaves, throwing strict standards, see https://bugs.php.net/bug.php?id=60573 - $data[] = array( - 'ProxyManagerTestAsset\\ClassWithSelfHint', - new ClassWithSelfHint(), - 'selfHintMethod', - array('parameter' => $selfHintParam), - $selfHintParam - ); - } - - return $data; - } - - /** - * Generates proxies and instances with a public property to feed to the property accessor methods - * - * @return array - */ - public function getPropertyAccessProxies() - { - $instance1 = new BaseClass(); - $proxyName1 = $this->generateProxy(get_class($instance1)); - $instance2 = new BaseClass(); - $proxyName2 = $this->generateProxy(get_class($instance2)); - - return array( - array( - $instance1, - new $proxyName1($instance1), - 'publicProperty', - 'publicPropertyDefault', - ), - array( - $instance2, - unserialize(serialize(new $proxyName2($instance2))), - 'publicProperty', - 'publicPropertyDefault', - ), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/BaseLazyLoadingPerformanceTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/BaseLazyLoadingPerformanceTest.php deleted file mode 100644 index d00fa41..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/BaseLazyLoadingPerformanceTest.php +++ /dev/null @@ -1,196 +0,0 @@ - - * @license MIT - * - * @group Performance - * @coversNothing - */ -abstract class BaseLazyLoadingPerformanceTest extends BasePerformanceTest -{ - /** - * @param string $className - * @param object[] $instances - * @param \ProxyManager\Proxy\LazyLoadingInterface[] $proxies - * @param string $methodName - * @param array $parameters - */ - protected function profileMethodAccess($className, array $instances, array $proxies, $methodName, array $parameters) - { - $iterations = count($instances); - - $this->startCapturing(); - - foreach ($instances as $instance) { - call_user_func_array(array($instance, $methodName), $parameters); - } - - $baseProfile = $this->endCapturing( - $iterations . ' calls to ' . $className . '#' . $methodName . ': %fms / %fKb' - ); - $this->startCapturing(); - - foreach ($proxies as $proxy) { - call_user_func_array(array($proxy, $methodName), $parameters); - } - - $proxyProfile = $this->endCapturing( - $iterations . ' calls to proxied ' . $className . '#' . $methodName . ': %fms / %fKb' - ); - $this->compareProfile($baseProfile, $proxyProfile); - } - - /** - * @param string $className - * @param object[] $instances - * @param \ProxyManager\Proxy\LazyLoadingInterface[] $proxies - * @param string $property - */ - protected function profilePropertyWrites($className, array $instances, array $proxies, $property) - { - $iterations = count($instances); - - $this->startCapturing(); - - foreach ($instances as $instance) { - $instance->$property = 'foo'; - } - - $baseProfile = $this->endCapturing( - $iterations . ' writes of ' . $className . '::' . $property . ': %fms / %fKb' - ); - $this->startCapturing(); - - foreach ($proxies as $proxy) { - $proxy->$property = 'foo'; - } - - $proxyProfile = $this->endCapturing( - $iterations . ' writes of proxied ' . $className . '::' . $property . ': %fms / %fKb' - ); - $this->compareProfile($baseProfile, $proxyProfile); - } - - /** - * @param string $className - * @param object[] $instances - * @param \ProxyManager\Proxy\LazyLoadingInterface[] $proxies - * @param string $property - */ - protected function profilePropertyReads($className, array $instances, array $proxies, $property) - { - $iterations = count($instances); - - $this->startCapturing(); - - foreach ($instances as $instance) { - $instance->$property; - } - - $baseProfile = $this->endCapturing( - $iterations . ' reads of ' . $className . '::' . $property . ': %fms / %fKb' - ); - $this->startCapturing(); - - foreach ($proxies as $proxy) { - $proxy->$property; - } - - $proxyProfile = $this->endCapturing( - $iterations . ' reads of proxied ' . $className . '::' . $property . ': %fms / %fKb' - ); - $this->compareProfile($baseProfile, $proxyProfile); - } - - /** - * @param string $className - * @param object[] $instances - * @param \ProxyManager\Proxy\LazyLoadingInterface[] $proxies - * @param string $property - */ - protected function profilePropertyIsset($className, array $instances, array $proxies, $property) - { - $iterations = count($instances); - - $this->startCapturing(); - - foreach ($instances as $instance) { - isset($instance->$property); - } - - $baseProfile = $this->endCapturing( - $iterations . ' isset of ' . $className . '::' . $property . ': %fms / %fKb' - ); - $this->startCapturing(); - - foreach ($proxies as $proxy) { - isset($proxy->$property); - } - - $proxyProfile = $this->endCapturing( - $iterations . ' isset of proxied ' . $className . '::' . $property . ': %fms / %fKb' - ); - $this->compareProfile($baseProfile, $proxyProfile); - } - - /** - * @param string $className - * @param object[] $instances - * @param \ProxyManager\Proxy\LazyLoadingInterface[] $proxies - * @param string $property - */ - protected function profilePropertyUnset($className, array $instances, array $proxies, $property) - { - $iterations = count($instances); - - $this->startCapturing(); - - foreach ($instances as $instance) { - unset($instance->$property); - } - - $baseProfile = $this->endCapturing( - $iterations . ' unset of ' . $className . '::' . $property . ': %fms / %fKb' - ); - $this->startCapturing(); - - foreach ($proxies as $proxy) { - unset($proxy->$property); - } - - $proxyProfile = $this->endCapturing( - $iterations . ' unset of proxied ' . $className . '::' . $property . ': %fms / %fKb' - ); - $this->compareProfile($baseProfile, $proxyProfile); - } - - /** - * Generates a proxy for the given class name, and retrieves its class name - * - * @param string $parentClassName - * - * @return string - */ - abstract protected function generateProxy($parentClassName); -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/BasePerformanceTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/BasePerformanceTest.php deleted file mode 100644 index b9dc803..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/BasePerformanceTest.php +++ /dev/null @@ -1,101 +0,0 @@ - - * @license MIT - * - * @group Performance - * @coversNothing - */ -abstract class BasePerformanceTest extends PHPUnit_Framework_TestCase -{ - /** - * @var float time when last capture was started - */ - private $startTime = 0; - - /** - * @var int bytes when last capture was started - */ - private $startMemory = 0; - - /** - * {@inheritDoc} - */ - public static function setUpBeforeClass() - { - $header = "Performance test - " . get_called_class() . ":"; - - echo "\n\n" . str_repeat('=', strlen($header)) . "\n" . $header . "\n\n"; - } - - /** - * Start profiler snapshot - */ - protected function startCapturing() - { - $this->startMemory = memory_get_usage(); - $this->startTime = microtime(true); - } - - /** - * Echo current profiler output - * - * @param string $messageTemplate - * - * @return array - */ - protected function endCapturing($messageTemplate) - { - $time = microtime(true) - $this->startTime; - $memory = memory_get_usage() - $this->startMemory; - - if (gc_enable()) { - gc_collect_cycles(); - } - - echo sprintf($messageTemplate, $time, $memory / 1024) . "\n"; - - return array( - 'time' => $time, - 'memory' => $memory - ); - } - - /** - * Display comparison between two profiles - * - * @param array $baseProfile - * @param array $proxyProfile - */ - protected function compareProfile(array $baseProfile, array $proxyProfile) - { - $baseMemory = max(1, $baseProfile['memory']); - $timeOverhead = (($proxyProfile['time'] / $baseProfile['time']) - 1) * 100; - $memoryOverhead = (($proxyProfile['memory'] / $baseMemory) - 1) * 100; - - echo sprintf('Comparison time / memory: %.2f%% / %.2f%%', $timeOverhead, $memoryOverhead) . "\n\n"; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/FatalPreventionFunctionalTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/FatalPreventionFunctionalTest.php deleted file mode 100644 index 290d52b..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/FatalPreventionFunctionalTest.php +++ /dev/null @@ -1,171 +0,0 @@ - - * @license MIT - * - * @group Functional - * @coversNothing - */ -class FatalPreventionFunctionalTest extends PHPUnit_Framework_TestCase -{ - private $template = <<<'PHP' -generate(new ReflectionClass($className), $generatedClass); - $classSignatureGenerator->addSignature($generatedClass, array('eval tests')); - $generatorStrategy->generate($generatedClass); -} catch (ProxyManager\Exception\ExceptionInterface $e) { -} catch (ReflectionException $e) { -} - -echo 'SUCCESS: ' . %s; -PHP; - - /** - * Verifies that code generation and evaluation will not cause fatals with any given class - * - * @param string $generatorClass an instantiable class (no arguments) implementing - * the {@see \ProxyManager\ProxyGenerator\ProxyGeneratorInterface} - * @param string $className a valid (existing/autoloadable) class name - * - * @dataProvider getTestedClasses - */ - public function testCodeGeneration($generatorClass, $className) - { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM is just too slow for this kind of test right now.'); - } - - if (PHP_VERSION_ID < 50401) { - $this->markTestSkipped('Can\'t run this test suite on php < 5.4.1'); - } - - $runner = PHPUnit_Util_PHP::factory(); - - $code = sprintf( - $this->template, - var_export(realpath(__DIR__ . '/../../../vendor/autoload.php'), true), - var_export($className, true), - $generatorClass, - var_export($className, true) - ); - - $result = $runner->runJob($code, array('-n')); - - if (('SUCCESS: ' . $className) !== $result['stdout']) { - $this->fail(sprintf( - "Crashed with class '%s' and generator '%s'.\n\nStdout:\n%s\nStderr:\n%s\nGenerated code:\n%s'", - $generatorClass, - $className, - $result['stdout'], - $result['stderr'], - $code - )); - } - - $this->assertSame('SUCCESS: ' . $className, $result['stdout']); - } - - /** - * @return string[][] - */ - public function getTestedClasses() - { - $that = $this; - - return call_user_func_array( - 'array_merge', - array_map( - function ($generator) use ($that) { - return array_map( - function ($class) use ($generator) { - return array($generator, $class); - }, - $that->getProxyTestedClasses() - ); - }, - array( - 'ProxyManager\\ProxyGenerator\\AccessInterceptorScopeLocalizerGenerator', - 'ProxyManager\\ProxyGenerator\\AccessInterceptorValueHolderGenerator', - 'ProxyManager\\ProxyGenerator\\LazyLoadingGhostGenerator', - 'ProxyManager\\ProxyGenerator\\LazyLoadingValueHolderGenerator', - 'ProxyManager\\ProxyGenerator\\NullObjectGenerator', - 'ProxyManager\\ProxyGenerator\\RemoteObjectGenerator', - ) - ) - ); - } - - /** - * @private (public only for PHP 5.3 compatibility) - * - * @return string[] - */ - public function getProxyTestedClasses() - { - $skippedPaths = array( - realpath(__DIR__ . '/../../src'), - realpath(__DIR__ . '/../../vendor'), - realpath(__DIR__ . '/../../tests/ProxyManagerTest'), - ); - - return array_filter( - get_declared_classes(), - function ($className) use ($skippedPaths) { - $reflectionClass = new ReflectionClass($className); - $fileName = $reflectionClass->getFileName(); - - if (! $fileName) { - return false; - } - - $realPath = realpath($fileName); - - foreach ($skippedPaths as $skippedPath) { - if (0 === strpos($realPath, $skippedPath)) { - // skip classes defined within ProxyManager, vendor or the test suite - return false; - } - } - - return true; - } - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingGhostFunctionalTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingGhostFunctionalTest.php deleted file mode 100644 index a6690f1..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingGhostFunctionalTest.php +++ /dev/null @@ -1,441 +0,0 @@ - - * @license MIT - * - * @group Functional - * @coversNothing - */ -class LazyLoadingGhostFunctionalTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getProxyMethods - */ - public function testMethodCalls($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface|BaseClass */ - $proxy = new $proxyName($this->createInitializer($className, $instance)); - - $this->assertFalse($proxy->isProxyInitialized()); - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - $this->assertTrue($proxy->isProxyInitialized()); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterUnSerialization($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface|BaseClass */ - $proxy = unserialize(serialize(new $proxyName($this->createInitializer($className, $instance)))); - - $this->assertTrue($proxy->isProxyInitialized()); - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterCloning($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface|BaseClass */ - $proxy = new $proxyName($this->createInitializer($className, $instance)); - $cloned = clone $proxy; - - $this->assertTrue($cloned->isProxyInitialized()); - $this->assertSame($expectedValue, call_user_func_array(array($cloned, $method), $params)); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyReadAccess($instance, $proxy, $publicProperty, $propertyValue) - { - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface */ - $this->assertSame($propertyValue, $proxy->$publicProperty); - $this->assertTrue($proxy->isProxyInitialized()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyWriteAccess($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface */ - $newValue = uniqid(); - $proxy->$publicProperty = $newValue; - - $this->assertTrue($proxy->isProxyInitialized()); - $this->assertSame($newValue, $proxy->$publicProperty); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyExistence($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface */ - $this->assertSame(isset($instance->$publicProperty), isset($proxy->$publicProperty)); - $this->assertTrue($proxy->isProxyInitialized()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyAbsence($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface */ - $proxy->$publicProperty = null; - $this->assertFalse(isset($proxy->$publicProperty)); - $this->assertTrue($proxy->isProxyInitialized()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyUnset($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface */ - - unset($proxy->$publicProperty); - - $this->assertTrue($proxy->isProxyInitialized()); - $this->assertTrue(isset($instance->$publicProperty)); - $this->assertFalse(isset($proxy->$publicProperty)); - } - - /** - * Verifies that accessing a public property containing an array behaves like in a normal context - */ - public function testCanWriteToArrayKeysInPublicProperty() - { - $instance = new ClassWithPublicArrayProperty(); - $className = get_class($instance); - $initializer = $this->createInitializer($className, $instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicArrayProperty */ - $proxy = new $proxyName($initializer); - - $proxy->arrayProperty['foo'] = 'bar'; - - $this->assertSame('bar', $proxy->arrayProperty['foo']); - - $proxy->arrayProperty = array('tab' => 'taz'); - - $this->assertSame(array('tab' => 'taz'), $proxy->arrayProperty); - } - - /** - * Verifies that public properties retrieved via `__get` don't get modified in the object itself - */ - public function testWillNotModifyRetrievedPublicProperties() - { - $instance = new ClassWithPublicProperties(); - $className = get_class($instance); - $initializer = $this->createInitializer($className, $instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName($initializer); - $variable = $proxy->property0; - - $this->assertSame('property0', $variable); - - $variable = 'foo'; - - $this->assertSame('property0', $proxy->property0); - } - - /** - * Verifies that public properties references retrieved via `__get` modify in the object state - */ - public function testWillModifyByRefRetrievedPublicProperties() - { - $instance = new ClassWithPublicProperties(); - $className = get_class($instance); - $initializer = $this->createInitializer($className, $instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName($initializer); - $variable = & $proxy->property0; - - $this->assertSame('property0', $variable); - - $variable = 'foo'; - - $this->assertSame('foo', $proxy->property0); - } - - public function testKeepsInitializerWhenNotOverwitten() - { - $instance = new BaseClass(); - $proxyName = $this->generateProxy(get_class($instance)); - $initializer = function () { - }; - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface */ - $proxy = new $proxyName($initializer); - - $proxy->initializeProxy(); - - $this->assertSame($initializer, $proxy->getProxyInitializer()); - } - - /** - * Verifies that public properties are not being initialized multiple times - */ - public function testKeepsInitializedPublicProperties() - { - $instance = new BaseClass(); - $proxyName = $this->generateProxy(get_class($instance)); - $initializer = function (BaseClass $proxy, $method, $parameters, & $initializer) { - $initializer = null; - $proxy->publicProperty = 'newValue'; - }; - /* @var $proxy \ProxyManager\Proxy\GhostObjectInterface|BaseClass */ - $proxy = new $proxyName($initializer); - - $proxy->initializeProxy(); - $this->assertSame('newValue', $proxy->publicProperty); - - $proxy->publicProperty = 'otherValue'; - - $proxy->initializeProxy(); - - $this->assertSame('otherValue', $proxy->publicProperty); - } - - /** - * Verifies that properties' default values are preserved - */ - public function testPublicPropertyDefaultWillBePreserved() - { - $instance = new ClassWithPublicProperties(); - $proxyName = $this->generateProxy(get_class($instance)); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName(function () { - }); - - $this->assertSame('property0', $proxy->property0); - } - - /** - * Verifies that protected properties' default values are preserved - */ - public function testProtectedPropertyDefaultWillBePreserved() - { - $instance = new ClassWithProtectedProperties(); - $proxyName = $this->generateProxy(get_class($instance)); - /* @var $proxy ClassWithProtectedProperties */ - $proxy = new $proxyName(function () { - }); - - // Check protected property via reflection - $reflectionProperty = new ReflectionProperty($instance, 'property0'); - $reflectionProperty->setAccessible(true); - - $this->assertSame('property0', $reflectionProperty->getValue($proxy)); - } - - /** - * Verifies that private properties' default values are preserved - */ - public function testPrivatePropertyDefaultWillBePreserved() - { - $instance = new ClassWithPrivateProperties(); - $proxyName = $this->generateProxy(get_class($instance)); - /* @var $proxy ClassWithPrivateProperties */ - $proxy = new $proxyName(function () { - }); - - // Check protected property via reflection - $reflectionProperty = new ReflectionProperty($instance, 'property0'); - $reflectionProperty->setAccessible(true); - - $this->assertSame('property0', $reflectionProperty->getValue($proxy)); - } - - /** - * Generates a proxy for the given class name, and retrieves its class name - * - * @param string $parentClassName - * - * @return string - */ - private function generateProxy($parentClassName) - { - $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo'); - $generator = new LazyLoadingGhostGenerator(); - $generatedClass = new ClassGenerator($generatedClassName); - $strategy = new EvaluatingGeneratorStrategy(); - - $generator->generate(new ReflectionClass($parentClassName), $generatedClass); - $strategy->generate($generatedClass); - - return $generatedClassName; - } - - /** - * @param string $className - * @param object $realInstance - * @param Mock $initializerMatcher - * - * @return \Closure - */ - private function createInitializer($className, $realInstance, Mock $initializerMatcher = null) - { - if (null === $initializerMatcher) { - $initializerMatcher = $this->getMock('stdClass', array('__invoke')); - - $initializerMatcher - ->expects($this->once()) - ->method('__invoke') - ->with( - $this->logicalAnd( - $this->isInstanceOf('ProxyManager\\Proxy\\GhostObjectInterface'), - $this->isInstanceOf($className) - ) - ); - } - - $initializerMatcher = $initializerMatcher ?: $this->getMock('stdClass', array('__invoke')); - - return function ( - GhostObjectInterface $proxy, - $method, - $params, - & $initializer - ) use ( - $initializerMatcher, - $realInstance - ) { - $initializer = null; - $reflectionClass = new ReflectionClass($realInstance); - - foreach ($reflectionClass->getProperties() as $property) { - $property->setAccessible(true); - $property->setValue($proxy, $property->getValue($realInstance)); - } - - $initializerMatcher->__invoke($proxy, $method, $params); - }; - } - - /** - * Generates a list of object | invoked method | parameters | expected result - * - * @return array - */ - public function getProxyMethods() - { - $selfHintParam = new ClassWithSelfHint(); - - $data = array( - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicMethod', - array(), - 'publicMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicTypeHintedMethod', - array(new \stdClass()), - 'publicTypeHintedMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicByReferenceMethod', - array(), - 'publicByReferenceMethodDefault' - ), - ); - - if (PHP_VERSION_ID >= 50401) { - // PHP < 5.4.1 misbehaves, throwing strict standards, see https://bugs.php.net/bug.php?id=60573 - $data[] = array( - 'ProxyManagerTestAsset\\ClassWithSelfHint', - new ClassWithSelfHint(), - 'selfHintMethod', - array('parameter' => $selfHintParam), - $selfHintParam - ); - } - - return $data; - } - - /** - * Generates proxies and instances with a public property to feed to the property accessor methods - * - * @return array - */ - public function getPropertyAccessProxies() - { - $instance1 = new BaseClass(); - $proxyName1 = $this->generateProxy(get_class($instance1)); - $instance2 = new BaseClass(); - $proxyName2 = $this->generateProxy(get_class($instance2)); - - return array( - array( - $instance1, - new $proxyName1($this->createInitializer('ProxyManagerTestAsset\\BaseClass', $instance1)), - 'publicProperty', - 'publicPropertyDefault', - ), - array( - $instance2, - unserialize( - serialize(new $proxyName2($this->createInitializer('ProxyManagerTestAsset\\BaseClass', $instance2))) - ), - 'publicProperty', - 'publicPropertyDefault', - ), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingGhostPerformanceTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingGhostPerformanceTest.php deleted file mode 100644 index 21b9f49..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingGhostPerformanceTest.php +++ /dev/null @@ -1,160 +0,0 @@ - - * @license MIT - * - * @group Performance - * @coversNothing - */ -class LazyLoadingGhostPerformanceTest extends BaseLazyLoadingPerformanceTest -{ - /** - * @outputBuffering - * @dataProvider getTestedClasses - * - * @param string $className - * @param array $methods - * @param array $properties - * @param \ReflectionProperty[] $reflectionProperties - * - * @return void - */ - public function testProxyInstantiationPerformance( - $className, - array $methods, - array $properties, - array $reflectionProperties - ) { - $proxyName = $this->generateProxy($className); - $iterations = 20000; - $instances = array(); - /* @var $proxies \ProxyManager\Proxy\GhostObjectInterface[] */ - $proxies = array(); - $realInstance = new $className(); - $initializer = function ( - GhostObjectInterface $proxy, - $method, - $params, - & $initializer - ) use ( - $reflectionProperties, - $realInstance - ) { - $initializer = null; - - foreach ($reflectionProperties as $reflectionProperty) { - $reflectionProperty->setValue($proxy, $reflectionProperty->getValue($realInstance)); - } - - return true; - }; - - $this->startCapturing(); - - for ($i = 0; $i < $iterations; $i += 1) { - $instances[] = new $className(); - } - - $baseProfile = $this->endCapturing( - 'Instantiation for ' . $iterations . ' objects of type ' . $className . ': %fms / %fKb' - ); - $this->startCapturing(); - - for ($i = 0; $i < $iterations; $i += 1) { - $proxies[] = new $proxyName($initializer); - } - - $proxyProfile = $this->endCapturing( - 'Instantiation for ' . $iterations . ' proxies of type ' . $className . ': %fms / %fKb' - ); - $this->compareProfile($baseProfile, $proxyProfile); - $this->startCapturing(); - - foreach ($proxies as $proxy) { - $proxy->initializeProxy(); - } - - $this->endCapturing('Initialization of ' . $iterations . ' proxies of type ' . $className . ': %fms / %fKb'); - - foreach ($methods as $methodName => $parameters) { - $this->profileMethodAccess($className, $instances, $proxies, $methodName, $parameters); - } - - foreach ($properties as $property) { - $this->profilePropertyWrites($className, $instances, $proxies, $property); - $this->profilePropertyReads($className, $instances, $proxies, $property); - $this->profilePropertyIsset($className, $instances, $proxies, $property); - $this->profilePropertyUnset($className, $instances, $proxies, $property); - } - } - - /** - * @return array - */ - public function getTestedClasses() - { - $testedClasses = array( - array('stdClass', array(), array()), - array('ProxyManagerTestAsset\\BaseClass', array('publicMethod' => array()), array('publicProperty')), - ); - - foreach ($testedClasses as $key => $testedClass) { - $reflectionProperties = array(); - $reflectionClass = new ReflectionClass($testedClass[0]); - - foreach ($reflectionClass->getProperties() as $property) { - $property->setAccessible(true); - - $reflectionProperties[$property->getName()] = $property; - } - - $testedClasses[$key][] = $reflectionProperties; - } - - return $testedClasses; - } - - /** - * {@inheritDoc} - */ - protected function generateProxy($parentClassName) - { - $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo'); - $generator = new LazyLoadingGhostGenerator(); - $generatedClass = new ClassGenerator($generatedClassName); - $strategy = new EvaluatingGeneratorStrategy(); - - $generator->generate(new ReflectionClass($parentClassName), $generatedClass); - $strategy->generate($generatedClass); - - return $generatedClassName; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingValueHolderFunctionalTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingValueHolderFunctionalTest.php deleted file mode 100644 index a638760..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingValueHolderFunctionalTest.php +++ /dev/null @@ -1,386 +0,0 @@ - - * @license MIT - * - * @group Functional - * @coversNothing - */ -class LazyLoadingValueHolderFunctionalTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getProxyMethods - */ - public function testMethodCalls($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\VirtualProxyInterface|BaseClass */ - $proxy = new $proxyName($this->createInitializer($className, $instance)); - - $this->assertFalse($proxy->isProxyInitialized()); - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - $this->assertTrue($proxy->isProxyInitialized()); - $this->assertSame($instance, $proxy->getWrappedValueHolderValue()); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterUnSerialization($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\VirtualProxyInterface|BaseClass */ - $proxy = unserialize(serialize(new $proxyName($this->createInitializer($className, $instance)))); - - $this->assertTrue($proxy->isProxyInitialized()); - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - $this->assertEquals($instance, $proxy->getWrappedValueHolderValue()); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterCloning($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\VirtualProxyInterface|BaseClass */ - $proxy = new $proxyName($this->createInitializer($className, $instance)); - $cloned = clone $proxy; - - $this->assertTrue($cloned->isProxyInitialized()); - $this->assertNotSame($proxy->getWrappedValueHolderValue(), $cloned->getWrappedValueHolderValue()); - $this->assertSame($expectedValue, call_user_func_array(array($cloned, $method), $params)); - $this->assertEquals($instance, $cloned->getWrappedValueHolderValue()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyReadAccess($instance, $proxy, $publicProperty, $propertyValue) - { - /* @var $proxy \ProxyManager\Proxy\VirtualProxyInterface|BaseClass */ - $this->assertSame($propertyValue, $proxy->$publicProperty); - $this->assertTrue($proxy->isProxyInitialized()); - $this->assertEquals($instance, $proxy->getWrappedValueHolderValue()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyWriteAccess($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\VirtualProxyInterface|BaseClass */ - $newValue = uniqid(); - $proxy->$publicProperty = $newValue; - - $this->assertTrue($proxy->isProxyInitialized()); - $this->assertSame($newValue, $proxy->$publicProperty); - $this->assertSame($newValue, $proxy->getWrappedValueHolderValue()->$publicProperty); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyExistence($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\VirtualProxyInterface|BaseClass */ - $this->assertSame(isset($instance->$publicProperty), isset($proxy->$publicProperty)); - $this->assertTrue($proxy->isProxyInitialized()); - $this->assertEquals($instance, $proxy->getWrappedValueHolderValue()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyAbsence($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\VirtualProxyInterface|BaseClass */ - $instance = $proxy->getWrappedValueHolderValue() ? $proxy->getWrappedValueHolderValue() : $instance; - $instance->$publicProperty = null; - $this->assertFalse(isset($proxy->$publicProperty)); - $this->assertTrue($proxy->isProxyInitialized()); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyUnset($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\VirtualProxyInterface|BaseClass */ - $instance = $proxy->getWrappedValueHolderValue() ? $proxy->getWrappedValueHolderValue() : $instance; - unset($proxy->$publicProperty); - - $this->assertTrue($proxy->isProxyInitialized()); - - $this->assertFalse(isset($instance->$publicProperty)); - $this->assertFalse(isset($proxy->$publicProperty)); - } - - /** - * Verifies that accessing a public property containing an array behaves like in a normal context - */ - public function testCanWriteToArrayKeysInPublicProperty() - { - $instance = new ClassWithPublicArrayProperty(); - $className = get_class($instance); - $initializer = $this->createInitializer($className, $instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicArrayProperty */ - $proxy = new $proxyName($initializer); - - $proxy->arrayProperty['foo'] = 'bar'; - - $this->assertSame('bar', $proxy->arrayProperty['foo']); - - $proxy->arrayProperty = array('tab' => 'taz'); - - $this->assertSame(array('tab' => 'taz'), $proxy->arrayProperty); - } - - /** - * Verifies that public properties retrieved via `__get` don't get modified in the object itself - */ - public function testWillNotModifyRetrievedPublicProperties() - { - $instance = new ClassWithPublicProperties(); - $className = get_class($instance); - $initializer = $this->createInitializer($className, $instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName($initializer); - $variable = $proxy->property0; - - $this->assertSame('property0', $variable); - - $variable = 'foo'; - - $this->assertSame('property0', $proxy->property0); - } - - /** - * Verifies that public properties references retrieved via `__get` modify in the object state - */ - public function testWillModifyByRefRetrievedPublicProperties() - { - $instance = new ClassWithPublicProperties(); - $className = get_class($instance); - $initializer = $this->createInitializer($className, $instance); - $proxyName = $this->generateProxy($className); - /* @var $proxy ClassWithPublicProperties */ - $proxy = new $proxyName($initializer); - $variable = & $proxy->property0; - - $this->assertSame('property0', $variable); - - $variable = 'foo'; - - $this->assertSame('foo', $proxy->property0); - } - - /** - * @group 16 - * - * Verifies that initialization of a value holder proxy may happen multiple times - */ - public function testWillAllowMultipleProxyInitialization() - { - $proxyClass = $this->generateProxy('ProxyManagerTestAsset\\BaseClass'); - $counter = 0; - $initializer = function (& $wrappedInstance) use (& $counter) { - $wrappedInstance = new BaseClass(); - - $wrappedInstance->publicProperty = (string) ($counter += 1); - }; - - /* @var $proxy BaseClass */ - $proxy = new $proxyClass($initializer); - - $this->assertSame('1', $proxy->publicProperty); - $this->assertSame('2', $proxy->publicProperty); - $this->assertSame('3', $proxy->publicProperty); - } - - /** - * Generates a proxy for the given class name, and retrieves its class name - * - * @param string $parentClassName - * - * @return string - */ - private function generateProxy($parentClassName) - { - $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo'); - $generator = new LazyLoadingValueHolderGenerator(); - $generatedClass = new ClassGenerator($generatedClassName); - $strategy = new EvaluatingGeneratorStrategy(); - - $generator->generate(new ReflectionClass($parentClassName), $generatedClass); - $strategy->generate($generatedClass); - - return $generatedClassName; - } - - /** - * @param string $className - * @param object $realInstance - * @param Mock $initializerMatcher - * - * @return \Closure - */ - private function createInitializer($className, $realInstance, Mock $initializerMatcher = null) - { - if (null === $initializerMatcher) { - $initializerMatcher = $this->getMock('stdClass', array('__invoke')); - - $initializerMatcher - ->expects($this->once()) - ->method('__invoke') - ->with( - $this->logicalAnd( - $this->isInstanceOf('ProxyManager\\Proxy\\VirtualProxyInterface'), - $this->isInstanceOf($className) - ), - $realInstance - ); - } - - $initializerMatcher = $initializerMatcher ?: $this->getMock('stdClass', array('__invoke')); - - return function ( - & $wrappedObject, - VirtualProxyInterface $proxy, - $method, - $params, - & $initializer - ) use ( - $initializerMatcher, - $realInstance - ) { - $initializer = null; - $wrappedObject = $realInstance; - - $initializerMatcher->__invoke($proxy, $wrappedObject, $method, $params); - }; - } - - /** - * Generates a list of object | invoked method | parameters | expected result - * - * @return array - */ - public function getProxyMethods() - { - $selfHintParam = new ClassWithSelfHint(); - - $data = array( - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicMethod', - array(), - 'publicMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicTypeHintedMethod', - array(new \stdClass()), - 'publicTypeHintedMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicByReferenceMethod', - array(), - 'publicByReferenceMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseInterface', - new BaseClass(), - 'publicMethod', - array(), - 'publicMethodDefault' - ), - ); - - if (PHP_VERSION_ID >= 50401) { - // PHP < 5.4.1 misbehaves, throwing strict standards, see https://bugs.php.net/bug.php?id=60573 - $data[] = array( - 'ProxyManagerTestAsset\\ClassWithSelfHint', - new ClassWithSelfHint(), - 'selfHintMethod', - array('parameter' => $selfHintParam), - $selfHintParam - ); - } - - return $data; - } - - /** - * Generates proxies and instances with a public property to feed to the property accessor methods - * - * @return array - */ - public function getPropertyAccessProxies() - { - $instance1 = new BaseClass(); - $proxyName1 = $this->generateProxy(get_class($instance1)); - $instance2 = new BaseClass(); - $proxyName2 = $this->generateProxy(get_class($instance2)); - - return array( - array( - $instance1, - new $proxyName1($this->createInitializer('ProxyManagerTestAsset\\BaseClass', $instance1)), - 'publicProperty', - 'publicPropertyDefault', - ), - array( - $instance2, - unserialize( - serialize(new $proxyName2($this->createInitializer('ProxyManagerTestAsset\\BaseClass', $instance2))) - ), - 'publicProperty', - 'publicPropertyDefault', - ), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingValueHolderPerformanceTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingValueHolderPerformanceTest.php deleted file mode 100644 index 1279526..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/LazyLoadingValueHolderPerformanceTest.php +++ /dev/null @@ -1,134 +0,0 @@ - - * @license MIT - * - * @group Performance - * @coversNothing - */ -class LazyLoadingValueHolderPerformanceTest extends BaseLazyLoadingPerformanceTest -{ - /** - * @outputBuffering - * @dataProvider getTestedClasses - * - * @param string $className - * @param array $methods - * @param array $properties - * - * @return void - */ - public function testProxyInstantiationPerformance($className, array $methods, array $properties) - { - $proxyName = $this->generateProxy($className); - $iterations = 20000; - $instances = array(); - /* @var $proxies \ProxyManager\Proxy\VirtualProxyInterface[] */ - $proxies = array(); - $initializer = function ( - & $valueHolder, - VirtualProxyInterface $proxy, - $method, - $params, - & $initializer - ) use ($className) { - $initializer = null; - $valueHolder = new $className(); - - return true; - }; - - $this->startCapturing(); - - for ($i = 0; $i < $iterations; $i += 1) { - $instances[] = new $className(); - } - - $baseProfile = $this->endCapturing( - 'Instantiation for ' . $iterations . ' objects of type ' . $className . ': %fms / %fKb' - ); - $this->startCapturing(); - - for ($i = 0; $i < $iterations; $i += 1) { - $proxies[] = new $proxyName($initializer); - } - - $proxyProfile = $this->endCapturing( - 'Instantiation for ' . $iterations . ' proxies of type ' . $className . ': %fms / %fKb' - ); - $this->compareProfile($baseProfile, $proxyProfile); - $this->startCapturing(); - - foreach ($proxies as $proxy) { - $proxy->initializeProxy(); - } - - $this->endCapturing('Initialization of ' . $iterations . ' proxies of type ' . $className . ': %fms / %fKb'); - - foreach ($methods as $methodName => $parameters) { - $this->profileMethodAccess($className, $instances, $proxies, $methodName, $parameters); - } - - foreach ($properties as $property) { - $this->profilePropertyWrites($className, $instances, $proxies, $property); - $this->profilePropertyReads($className, $instances, $proxies, $property); - $this->profilePropertyIsset($className, $instances, $proxies, $property); - $this->profilePropertyUnset($className, $instances, $proxies, $property); - } - } - - /** - * @return array - */ - public function getTestedClasses() - { - return array( - array('stdClass', array(), array()), - array('ProxyManagerTestAsset\\BaseClass', array('publicMethod' => array()), array('publicProperty')), - ); - } - - /** - * {@inheritDoc} - */ - protected function generateProxy($parentClassName) - { - $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo'); - $generator = new LazyLoadingValueHolderGenerator(); - $generatedClass = new ClassGenerator($generatedClassName); - $strategy = new EvaluatingGeneratorStrategy(); - - $generator->generate(new ReflectionClass($parentClassName), $generatedClass); - $strategy->generate($generatedClass); - - return $generatedClassName; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/MultipleProxyGenerationTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/MultipleProxyGenerationTest.php deleted file mode 100644 index 00be47d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/MultipleProxyGenerationTest.php +++ /dev/null @@ -1,123 +0,0 @@ - - * @license MIT - * - * @link https://github.com/Ocramius/ProxyManager/issues/10 - * - * @group Functional - * @group issue-10 - * @coversNothing - */ -class MultipleProxyGenerationTest extends PHPUnit_Framework_TestCase -{ - /** - * Verifies that proxies generated from different factories will retain their specific implementation - * and won't conflict - * - * @dataProvider getTestedClasses - */ - public function testCanGenerateMultipleDifferentProxiesForSameClass($className) - { - $skipScopeLocalizerTests = false; - $ghostProxyFactory = new LazyLoadingGhostFactory(); - $virtualProxyFactory = new LazyLoadingValueHolderFactory(); - $accessInterceptorFactory = new AccessInterceptorValueHolderFactory(); - $accessInterceptorScopeLocalizerFactory = new AccessInterceptorScopeLocalizerFactory(); - $initializer = function () { - }; - - $reflectionClass = new ReflectionClass($className); - - if ((! method_exists('Closure', 'bind')) && $reflectionClass->getProperties(ReflectionProperty::IS_PRIVATE)) { - $skipScopeLocalizerTests = true; - } - - $generated = array( - $ghostProxyFactory->createProxy($className, $initializer), - $virtualProxyFactory->createProxy($className, $initializer), - $accessInterceptorFactory->createProxy(new $className()), - ); - - if (! $skipScopeLocalizerTests) { - $generated[] = $accessInterceptorScopeLocalizerFactory->createProxy(new $className()); - } - - foreach ($generated as $key => $proxy) { - $this->assertInstanceOf($className, $proxy); - - foreach ($generated as $comparedKey => $comparedProxy) { - if ($comparedKey === $key) { - continue; - } - - $this->assertNotSame(get_class($comparedProxy), get_class($proxy)); - } - } - - $this->assertInstanceOf('ProxyManager\Proxy\GhostObjectInterface', $generated[0]); - $this->assertInstanceOf('ProxyManager\Proxy\VirtualProxyInterface', $generated[1]); - $this->assertInstanceOf('ProxyManager\Proxy\AccessInterceptorInterface', $generated[2]); - $this->assertInstanceOf('ProxyManager\Proxy\ValueHolderInterface', $generated[2]); - - if (! $skipScopeLocalizerTests) { - $this->assertInstanceOf('ProxyManager\Proxy\AccessInterceptorInterface', $generated[3]); - } - } - - /** - * @return string[][] - */ - public function getTestedClasses() - { - $data = array( - array('ProxyManagerTestAsset\\BaseClass'), - array('ProxyManagerTestAsset\\ClassWithMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithFinalMethods'), - array('ProxyManagerTestAsset\\ClassWithFinalMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithByRefMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithMixedProperties'), - array('ProxyManagerTestAsset\\ClassWithPrivateProperties'), - array('ProxyManagerTestAsset\\ClassWithProtectedProperties'), - array('ProxyManagerTestAsset\\ClassWithPublicProperties'), - array('ProxyManagerTestAsset\\EmptyClass'), - array('ProxyManagerTestAsset\\HydratedObject'), - ); - - if (PHP_VERSION_ID >= 50401) { - // PHP < 5.4.1 misbehaves, throwing strict standards, see https://bugs.php.net/bug.php?id=60573 - $data[] = array('ProxyManagerTestAsset\\ClassWithSelfHint'); - } - - return $data; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/NullObjectFunctionalTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/NullObjectFunctionalTest.php deleted file mode 100644 index adfeae5..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/NullObjectFunctionalTest.php +++ /dev/null @@ -1,223 +0,0 @@ - - * @license MIT - * - * @group Functional - * @coversNothing - */ -class NullObjectFunctionalTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getProxyMethods - */ - public function testMethodCalls($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\NullObjectInterface */ - $proxy = new $proxyName(); - - $this->assertSame(null, call_user_func_array(array($proxy, $method), $params)); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterUnSerialization($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - /* @var $proxy \ProxyManager\Proxy\NullObjectInterface */ - $proxy = unserialize(serialize(new $proxyName())); - - $this->assertSame(null, call_user_func_array(array($proxy, $method), $params)); - } - - /** - * @dataProvider getProxyMethods - */ - public function testMethodCallsAfterCloning($className, $instance, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($className); - - /* @var $proxy \ProxyManager\Proxy\NullObjectInterface */ - $proxy = new $proxyName(); - $cloned = clone $proxy; - - $this->assertSame(null, call_user_func_array(array($cloned, $method), $params)); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyReadAccess($instance, $proxy, $publicProperty, $propertyValue) - { - /* @var $proxy \ProxyManager\Proxy\NullObjectInterface */ - $this->assertSame(null, $proxy->$publicProperty); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyWriteAccess($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\NullObjectInterface */ - $newValue = uniqid(); - $proxy->$publicProperty = $newValue; - - $this->assertSame($newValue, $proxy->$publicProperty); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyExistence($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\NullObjectInterface */ - $this->assertSame(null, $proxy->$publicProperty); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testPropertyUnset($instance, $proxy, $publicProperty) - { - /* @var $proxy \ProxyManager\Proxy\NullObjectInterface */ - unset($proxy->$publicProperty); - - $this->assertTrue(isset($instance->$publicProperty)); - $this->assertFalse(isset($proxy->$publicProperty)); - } - - /** - * Generates a proxy for the given class name, and retrieves its class name - * - * @param string $parentClassName - * - * @return string - */ - private function generateProxy($parentClassName) - { - $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo'); - $generator = new NullObjectGenerator(); - $generatedClass = new ClassGenerator($generatedClassName); - $strategy = new EvaluatingGeneratorStrategy(); - - $generator->generate(new ReflectionClass($parentClassName), $generatedClass); - $strategy->generate($generatedClass); - - return $generatedClassName; - } - - /** - * Generates a list of object | invoked method | parameters | expected result - * - * @return array - */ - public function getProxyMethods() - { - $selfHintParam = new ClassWithSelfHint(); - - $data = array( - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicMethod', - array(), - 'publicMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicTypeHintedMethod', - array('param' => new \stdClass()), - 'publicTypeHintedMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseClass', - new BaseClass(), - 'publicByReferenceMethod', - array(), - 'publicByReferenceMethodDefault' - ), - array( - 'ProxyManagerTestAsset\\BaseInterface', - new BaseClass(), - 'publicMethod', - array(), - 'publicMethodDefault' - ), - ); - - if (PHP_VERSION_ID >= 50401) { - // PHP < 5.4.1 misbehaves, throwing strict standards, see https://bugs.php.net/bug.php?id=60573 - $data[] = array( - 'ProxyManagerTestAsset\\ClassWithSelfHint', - new ClassWithSelfHint(), - 'selfHintMethod', - array('parameter' => $selfHintParam), - $selfHintParam - ); - } - - return $data; - } - - /** - * Generates proxies and instances with a public property to feed to the property accessor methods - * - * @return array - */ - public function getPropertyAccessProxies() - { - $instance1 = new BaseClass(); - $proxyName1 = $this->generateProxy(get_class($instance1)); - $instance2 = new BaseClass(); - $proxyName2 = $this->generateProxy(get_class($instance2)); - - return array( - array( - $instance1, - new $proxyName1($instance1), - 'publicProperty', - 'publicPropertyDefault', - ), - array( - $instance2, - unserialize(serialize(new $proxyName2($instance2))), - 'publicProperty', - 'publicPropertyDefault', - ), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/RemoteObjectFunctionalTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/RemoteObjectFunctionalTest.php deleted file mode 100644 index b5d9c95..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Functional/RemoteObjectFunctionalTest.php +++ /dev/null @@ -1,231 +0,0 @@ - - * @license MIT - * - * @group Functional - * @coversNothing - */ -class RemoteObjectFunctionalTest extends PHPUnit_Framework_TestCase -{ - /** - * @param mixed $expectedValue - * @param string $method - * @param array $params - * - * @return XmlRpcAdapter - */ - protected function getXmlRpcAdapter($expectedValue, $method, array $params) - { - $client = $this - ->getMockBuilder('Zend\Server\Client') - ->setMethods(array('call')) - ->getMock(); - - $client - ->expects($this->any()) - ->method('call') - ->with($this->stringEndsWith($method), $params) - ->will($this->returnValue($expectedValue)); - - $adapter = new XmlRpcAdapter( - $client, - array( - 'ProxyManagerTestAsset\RemoteProxy\Foo.foo' - => 'ProxyManagerTestAsset\RemoteProxy\FooServiceInterface.foo' - ) - ); - - return $adapter; - } - - /** - * @param mixed $expectedValue - * @param string $method - * @param array $params - * - * @return JsonRpcAdapter - */ - protected function getJsonRpcAdapter($expectedValue, $method, array $params) - { - $client = $this - ->getMockBuilder('Zend\Server\Client') - ->setMethods(array('call')) - ->getMock(); - - $client - ->expects($this->any()) - ->method('call') - ->with($this->stringEndsWith($method), $params) - ->will($this->returnValue($expectedValue)); - - $adapter = new JsonRpcAdapter( - $client, - array( - 'ProxyManagerTestAsset\RemoteProxy\Foo.foo' - => 'ProxyManagerTestAsset\RemoteProxy\FooServiceInterface.foo' - ) - ); - - return $adapter; - } - - /** - * @dataProvider getProxyMethods - */ - public function testXmlRpcMethodCalls($instanceOrClassname, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($instanceOrClassname); - - /* @var $proxy \ProxyManager\Proxy\RemoteObjectInterface */ - $proxy = new $proxyName($this->getXmlRpcAdapter($expectedValue, $method, $params)); - - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - } - - /** - * @dataProvider getProxyMethods - */ - public function testJsonRpcMethodCalls($instanceOrClassname, $method, $params, $expectedValue) - { - $proxyName = $this->generateProxy($instanceOrClassname); - - /* @var $proxy \ProxyManager\Proxy\RemoteObjectInterface */ - $proxy = new $proxyName($this->getJsonRpcAdapter($expectedValue, $method, $params)); - - $this->assertSame($expectedValue, call_user_func_array(array($proxy, $method), $params)); - } - - /** - * @dataProvider getPropertyAccessProxies - */ - public function testJsonRpcPropertyReadAccess($instanceOrClassname, $publicProperty, $propertyValue) - { - $proxyName = $this->generateProxy($instanceOrClassname); - - /* @var $proxy \ProxyManager\Proxy\RemoteObjectInterface */ - $proxy = new $proxyName( - $this->getJsonRpcAdapter($propertyValue, '__get', array($publicProperty)) - ); - - /* @var $proxy \ProxyManager\Proxy\NullObjectInterface */ - $this->assertSame($propertyValue, $proxy->$publicProperty); - } - - /** - * Generates a proxy for the given class name, and retrieves its class name - * - * @param string $parentClassName - * - * @return string - */ - private function generateProxy($parentClassName) - { - $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo'); - $generator = new RemoteObjectGenerator(); - $generatedClass = new ClassGenerator($generatedClassName); - $strategy = new EvaluatingGeneratorStrategy(); - - $generator->generate(new ReflectionClass($parentClassName), $generatedClass); - $strategy->generate($generatedClass); - - return $generatedClassName; - } - - /** - * Generates a list of object | invoked method | parameters | expected result - * - * @return array - */ - public function getProxyMethods() - { - $selfHintParam = new ClassWithSelfHint(); - - $data = array( - array( - 'ProxyManagerTestAsset\RemoteProxy\FooServiceInterface', - 'foo', - array(), - 'bar remote' - ), - array( - 'ProxyManagerTestAsset\RemoteProxy\Foo', - 'foo', - array(), - 'bar remote' - ), - array( - new Foo(), - 'foo', - array(), - 'bar remote' - ), - array( - 'ProxyManagerTestAsset\RemoteProxy\BazServiceInterface', - 'baz', - array('baz'), - 'baz remote' - ), - ); - - if (PHP_VERSION_ID >= 50401) { - // PHP < 5.4.1 misbehaves, throwing strict standards, see https://bugs.php.net/bug.php?id=60573 - $data[] = array( - new ClassWithSelfHint(), - 'selfHintMethod', - array($selfHintParam), - $selfHintParam - ); - } - - return $data; - } - - /** - * Generates proxies and instances with a public property to feed to the property accessor methods - * - * @return array - */ - public function getPropertyAccessProxies() - { - return array( - array( - 'ProxyManagerTestAsset\RemoteProxy\FooServiceInterface', - 'publicProperty', - 'publicProperty remote', - ), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/ClassGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/ClassGeneratorTest.php deleted file mode 100644 index c00f849..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/ClassGeneratorTest.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ClassGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\Generator\ClassGenerator::setExtendedClass - */ - public function testExtendedClassesAreFQCNs() - { - $desiredFqcn = '\\stdClass'; - $classNameInputs = array('stdClass', '\\stdClass\\'); - - foreach ($classNameInputs as $className) { - $classGenerator = new ClassGenerator(); - $classGenerator->setExtendedClass($className); - - $this->assertEquals($desiredFqcn, $classGenerator->getExtendedClass()); - } - } - - /** - * @covers \ProxyManager\Generator\ClassGenerator::setImplementedInterfaces - */ - public function testImplementedInterfacesAreFQCNs() - { - $desiredFqcns = array('\\Countable'); - $interfaceNameInputs = array(array('Countable'), array('\\Countable\\')); - - foreach ($interfaceNameInputs as $interfaceNames) { - $classGenerator = new ClassGenerator(); - $classGenerator->setImplementedInterfaces($interfaceNames); - - $this->assertEquals($desiredFqcns, $classGenerator->getImplementedInterfaces()); - } - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/MagicMethodGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/MagicMethodGeneratorTest.php deleted file mode 100644 index c5ae31a..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/MagicMethodGeneratorTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicMethodGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\Generator\MagicMethodGenerator::__construct - */ - public function testGeneratesCorrectByRefReturnValue() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithByRefMagicMethods'); - $magicMethod = new MagicMethodGenerator($reflection, '__get', array('name')); - - $this->assertTrue($magicMethod->returnsReference()); - } - - /** - * @covers \ProxyManager\Generator\MagicMethodGenerator::__construct - */ - public function testGeneratesCorrectByValReturnValue() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $magicMethod = new MagicMethodGenerator($reflection, '__get', array('name')); - - $this->assertFalse($magicMethod->returnsReference()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/MethodGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/MethodGeneratorTest.php deleted file mode 100644 index 4c2306a..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/MethodGeneratorTest.php +++ /dev/null @@ -1,97 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Generator\MethodGenerator - * @group Coverage - */ -class MethodGeneratorTest extends PHPUnit_Framework_TestCase -{ - public function testGenerateSimpleMethod() - { - $methodGenerator = new MethodGenerator(); - - $methodGenerator->setReturnsReference(true); - $methodGenerator->setName('methodName'); - $methodGenerator->setVisibility('protected'); - $methodGenerator->setBody('/* body */'); - $methodGenerator->setDocBlock('docBlock'); - $methodGenerator->setParameter(new ParameterGenerator('foo')); - - $this->assertSame(true, $methodGenerator->returnsReference()); - $this->assertStringMatchesFormat( - '%a/**%adocBlock%a*/%aprotected function & methodName($foo)%a{%a/* body */%a}', - $methodGenerator->generate() - ); - } - - /** - * Verify that building from reflection works - */ - public function testGenerateFromReflection() - { - $method = MethodGenerator::fromReflection(new MethodReflection(__CLASS__, __FUNCTION__)); - - $this->assertSame(__FUNCTION__, $method->getName()); - $this->assertSame(MethodGenerator::VISIBILITY_PUBLIC, $method->getVisibility()); - $this->assertFalse($method->isStatic()); - $this->assertSame('Verify that building from reflection works', $method->getDocBlock()->getShortDescription()); - - $method = MethodGenerator::fromReflection( - new MethodReflection('ProxyManagerTestAsset\\BaseClass', 'protectedMethod') - ); - - $this->assertSame(MethodGenerator::VISIBILITY_PROTECTED, $method->getVisibility()); - - $method = MethodGenerator::fromReflection( - new MethodReflection('ProxyManagerTestAsset\\BaseClass', 'privateMethod') - ); - - $this->assertSame(MethodGenerator::VISIBILITY_PRIVATE, $method->getVisibility()); - } - - public function testGeneratedParametersFromReflection() - { - $method = MethodGenerator::fromReflection(new MethodReflection( - 'ProxyManagerTestAsset\\BaseClass', - 'publicTypeHintedMethod' - )); - - $this->assertSame('publicTypeHintedMethod', $method->getName()); - - $parameters = $method->getParameters(); - - $this->assertCount(1, $parameters); - - $param = $parameters['param']; - - $this->assertSame('stdClass', $param->getType()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/ParameterGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/ParameterGeneratorTest.php deleted file mode 100644 index a67f225..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/ParameterGeneratorTest.php +++ /dev/null @@ -1,146 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Generator\ParameterGenerator - * @group Coverage - */ -class ParameterGeneratorTest extends PHPUnit_Framework_TestCase -{ - public function testGeneratesProperTypeHint() - { - $generator = new ParameterGenerator('foo'); - - $generator->setType('array'); - $this->assertSame('array $foo', $generator->generate()); - - $generator->setType('stdClass'); - $this->assertSame('\\stdClass $foo', $generator->generate()); - - $generator->setType('\\fooClass'); - $this->assertSame('\\fooClass $foo', $generator->generate()); - } - - public function testGeneratesMethodWithCallableType() - { - if (PHP_VERSION_ID < 50400) { - $this->markTestSkipped('`callable` is only supported in PHP >=5.4.0'); - } - - $generator = new ParameterGenerator(); - - $generator->setType('callable'); - $generator->setName('foo'); - - $this->assertSame('callable $foo', $generator->generate()); - } - - public function testVisitMethodWithCallable() - { - if (PHP_VERSION_ID < 50400) { - $this->markTestSkipped('`callable` is only supported in PHP >=5.4.0'); - } - - $parameter = new ParameterReflection( - array('ProxyManagerTestAsset\\CallableTypeHintClass', 'callableTypeHintMethod'), - 'parameter' - ); - - $generator = ParameterGenerator::fromReflection($parameter); - - $this->assertSame('callable', $generator->getType()); - } - - public function testReadsParameterDefaults() - { - $parameter = ParameterGenerator::fromReflection(new ParameterReflection( - array( - 'ProxyManagerTestAsset\\ClassWithMethodWithDefaultParameters', - 'publicMethodWithDefaults' - ), - 'parameter' - )); - - /* @var $defaultValue \Zend\Code\Generator\ValueGenerator */ - $defaultValue = $parameter->getDefaultValue(); - - $this->assertInstanceOf('Zend\\Code\\Generator\\ValueGenerator', $defaultValue); - $this->assertSame(array('foo'), $defaultValue->getValue()); - - $this->assertStringMatchesFormat('array%a$parameter%a=%aarray(\'foo\')', $parameter->generate()); - } - - public function testReadsParameterTypeHint() - { - $parameter = ParameterGenerator::fromReflection(new ParameterReflection( - array('ProxyManagerTestAsset\\BaseClass', 'publicTypeHintedMethod'), - 'param' - )); - - $this->assertSame('stdClass', $parameter->getType()); - } - - public function testGeneratesParameterPassedByReference() - { - $parameter = new ParameterGenerator('foo'); - - $parameter->setPassedByReference(true); - - $this->assertStringMatchesFormat('&%A$foo', $parameter->generate()); - } - - public function testGeneratesDefaultParameterForInternalPhpClasses() - { - $parameter = ParameterGenerator::fromReflection(new ParameterReflection( - array( - 'Phar', - 'compress' - ), - 1 - )); - - $this->assertSame('null', strtolower((string) $parameter->getDefaultValue())); - } - - public function testGeneratedParametersAreProperlyEscaped() - { - $parameter = new ParameterGenerator(); - - $parameter->setName('foo'); - $parameter->setDefaultValue('\'bar\\baz'); - - $this->assertThat( - $parameter->generate(), - $this->logicalOr( - $this->equalTo('$foo = \'\\\'bar\\baz\''), - $this->equalTo('$foo = \'\\\'bar\\\\baz\'') - ) - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/Util/ClassGeneratorUtilsTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/Util/ClassGeneratorUtilsTest.php deleted file mode 100644 index cf52546..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/Util/ClassGeneratorUtilsTest.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @license MIT - * - * @covers ProxyManager\Generator\Util\ClassGeneratorUtils - */ -class ClassGeneratorUtilsTest extends PHPUnit_Framework_TestCase -{ - public function testCantAddAFinalMethod() - { - $classGenerator = $this->getMock('Zend\\Code\\Generator\\ClassGenerator'); - $methodGenerator = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - - $methodGenerator - ->expects($this->once()) - ->method('getName') - ->willReturn('foo'); - - $classGenerator - ->expects($this->never()) - ->method('addMethodFromGenerator'); - - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithFinalMethods'); - - ClassGeneratorUtils::addMethodIfNotFinal($reflection, $classGenerator, $methodGenerator); - } - - public function testCanAddANotFinalMethod() - { - $classGenerator = $this->getMock('Zend\\Code\\Generator\\ClassGenerator'); - $methodGenerator = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - - $methodGenerator - ->expects($this->once()) - ->method('getName') - ->willReturn('publicMethod'); - - $classGenerator - ->expects($this->once()) - ->method('addMethodFromGenerator'); - - $reflection = new ReflectionClass('ProxyManagerTestAsset\\BaseClass'); - - ClassGeneratorUtils::addMethodIfNotFinal($reflection, $classGenerator, $methodGenerator); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/Util/UniqueIdentifierGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/Util/UniqueIdentifierGeneratorTest.php deleted file mode 100644 index 5f4e8ec..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Generator/Util/UniqueIdentifierGeneratorTest.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class UniqueIdentifierGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getBaseIdentifierNames - * - * @covers \ProxyManager\Generator\Util\UniqueIdentifierGenerator::getIdentifier - */ - public function testGeneratesUniqueIdentifiers($name) - { - $this->assertNotSame( - UniqueIdentifierGenerator::getIdentifier($name), - UniqueIdentifierGenerator::getIdentifier($name) - ); - } - - /** - * @dataProvider getBaseIdentifierNames - * - * @covers \ProxyManager\Generator\Util\UniqueIdentifierGenerator::getIdentifier - */ - public function testGeneratesValidIdentifiers($name) - { - $this->assertRegExp( - '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]+$/', - UniqueIdentifierGenerator::getIdentifier($name) - ); - } - - /** - * Data provider generating identifier names to be checked - * - * @return string[][] - */ - public function getBaseIdentifierNames() - { - return array( - array(''), - array('1'), - array('foo'), - array('Foo'), - array('bar'), - array('Bar'), - array('foo_bar'), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/BaseGeneratorStrategyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/BaseGeneratorStrategyTest.php deleted file mode 100644 index d2366a2..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/BaseGeneratorStrategyTest.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class BaseGeneratorStrategyTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\GeneratorStrategy\BaseGeneratorStrategy::generate - */ - public function testGenerate() - { - $strategy = new BaseGeneratorStrategy(); - $className = UniqueIdentifierGenerator::getIdentifier('Foo'); - $classGenerator = new ClassGenerator($className); - $generated = $strategy->generate($classGenerator); - - $this->assertGreaterThan(0, strpos($generated, $className)); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/EvaluatingGeneratorStrategyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/EvaluatingGeneratorStrategyTest.php deleted file mode 100644 index 90d22ce..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/EvaluatingGeneratorStrategyTest.php +++ /dev/null @@ -1,69 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class EvaluatingGeneratorStrategyTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy::generate - * @covers \ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy::__construct - */ - public function testGenerate() - { - $strategy = new EvaluatingGeneratorStrategy(); - $className = UniqueIdentifierGenerator::getIdentifier('Foo'); - $classGenerator = new ClassGenerator($className); - $generated = $strategy->generate($classGenerator); - - $this->assertGreaterThan(0, strpos($generated, $className)); - $this->assertTrue(class_exists($className, false)); - } - - /** - * @covers \ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy::generate - * @covers \ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy::__construct - */ - public function testGenerateWithDisabledEval() - { - if (! ini_get('suhosin.executor.disable_eval')) { - $this->markTestSkipped('Ini setting "suhosin.executor.disable_eval" is needed to run this test'); - } - - $strategy = new EvaluatingGeneratorStrategy(); - $className = 'Foo' . uniqid(); - $classGenerator = new ClassGenerator($className); - $generated = $strategy->generate($classGenerator); - - $this->assertGreaterThan(0, strpos($generated, $className)); - $this->assertTrue(class_exists($className, false)); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/FileWriterGeneratorStrategyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/FileWriterGeneratorStrategyTest.php deleted file mode 100644 index 03eef8a..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/GeneratorStrategy/FileWriterGeneratorStrategyTest.php +++ /dev/null @@ -1,148 +0,0 @@ - - * @license MIT - * - * @group Coverage - * - * Note: this test generates temporary files that are not deleted - */ -class FileWriterGeneratorStrategyTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy::__construct - * @covers \ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy::generate - */ - public function testGenerate() - { - /* @var $locator \ProxyManager\FileLocator\FileLocatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - $locator = $this->getMock('ProxyManager\\FileLocator\\FileLocatorInterface'); - $generator = new FileWriterGeneratorStrategy($locator); - $tmpFile = sys_get_temp_dir() . '/' . uniqid('FileWriterGeneratorStrategyTest', true) . '.php'; - $namespace = 'Foo'; - $className = UniqueIdentifierGenerator::getIdentifier('Bar'); - $fqcn = $namespace . '\\' . $className; - - $locator - ->expects($this->any()) - ->method('getProxyFileName') - ->with($fqcn) - ->will($this->returnValue($tmpFile)); - - $body = $generator->generate(new ClassGenerator($fqcn)); - - $this->assertGreaterThan(0, strpos($body, $className)); - $this->assertFalse(class_exists($fqcn, false)); - $this->assertTrue(file_exists($tmpFile)); - - require $tmpFile; - - $this->assertTrue(class_exists($fqcn, false)); - } - - public function testGenerateWillFailIfTmpFileCannotBeWrittenToDisk() - { - $tmpDirPath = sys_get_temp_dir() . '/' . uniqid('nonWritable', true); - - mkdir($tmpDirPath, 0555, true); - - /* @var $locator \ProxyManager\FileLocator\FileLocatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - $locator = $this->getMock('ProxyManager\\FileLocator\\FileLocatorInterface'); - $generator = new FileWriterGeneratorStrategy($locator); - $tmpFile = $tmpDirPath . '/' . uniqid('FileWriterGeneratorStrategyFailedFileWriteTest', true) . '.php'; - $namespace = 'Foo'; - $className = UniqueIdentifierGenerator::getIdentifier('Bar'); - $fqcn = $namespace . '\\' . $className; - - $locator - ->expects($this->any()) - ->method('getProxyFileName') - ->with($fqcn) - ->will($this->returnValue($tmpFile)); - - $this->setExpectedException('ProxyManager\\Exception\\FileNotWritableException'); - $generator->generate(new ClassGenerator($fqcn)); - } - - public function testGenerateWillFailIfTmpFileCannotBeMovedToFinalDestination() - { - /* @var $locator \ProxyManager\FileLocator\FileLocatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - $locator = $this->getMock('ProxyManager\\FileLocator\\FileLocatorInterface'); - $generator = new FileWriterGeneratorStrategy($locator); - $tmpFile = sys_get_temp_dir() . '/' . uniqid('FileWriterGeneratorStrategyFailedFileMoveTest', true) . '.php'; - $namespace = 'Foo'; - $className = UniqueIdentifierGenerator::getIdentifier('Bar'); - $fqcn = $namespace . '\\' . $className; - - $locator - ->expects($this->any()) - ->method('getProxyFileName') - ->with($fqcn) - ->will($this->returnValue($tmpFile)); - - mkdir($tmpFile); - - $this->setExpectedException('ProxyManager\\Exception\\FileNotWritableException'); - $generator->generate(new ClassGenerator($fqcn)); - } - - public function testWhenFailingAllTemporaryFilesAreRemoved() - { - $tmpDirPath = sys_get_temp_dir() . '/' . uniqid('noTempFilesLeftBehind', true); - - mkdir($tmpDirPath); - - /* @var $locator \ProxyManager\FileLocator\FileLocatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - $locator = $this->getMock('ProxyManager\\FileLocator\\FileLocatorInterface'); - $generator = new FileWriterGeneratorStrategy($locator); - $tmpFile = $tmpDirPath . '/' . uniqid('FileWriterGeneratorStrategyFailedFileMoveTest', true) . '.php'; - $namespace = 'Foo'; - $className = UniqueIdentifierGenerator::getIdentifier('Bar'); - $fqcn = $namespace . '\\' . $className; - - $locator - ->expects($this->any()) - ->method('getProxyFileName') - ->with($fqcn) - ->will($this->returnValue($tmpFile)); - - mkdir($tmpFile); - - try { - $generator->generate(new ClassGenerator($fqcn)); - - $this->fail('An exception was supposed to be thrown'); - } catch (FileNotWritableException $exception) { - rmdir($tmpFile); - - $this->assertEquals(array('.', '..'), scandir($tmpDirPath)); - } - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/ClassNameInflectorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/ClassNameInflectorTest.php deleted file mode 100644 index b95d7f2..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/ClassNameInflectorTest.php +++ /dev/null @@ -1,161 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ClassNameInflectorTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getClassNames - * - * @covers \ProxyManager\Inflector\ClassNameInflector::__construct - * @covers \ProxyManager\Inflector\ClassNameInflector::getUserClassName - * @covers \ProxyManager\Inflector\ClassNameInflector::getProxyClassName - * @covers \ProxyManager\Inflector\ClassNameInflector::isProxyClassName - */ - public function testInflector($realClassName, $proxyClassName) - { - $inflector = new ClassNameInflector('ProxyNS'); - - $this->assertFalse($inflector->isProxyClassName($realClassName)); - $this->assertTrue($inflector->isProxyClassName($proxyClassName)); - $this->assertStringMatchesFormat($realClassName, $inflector->getUserClassName($realClassName)); - $this->assertStringMatchesFormat($proxyClassName, $inflector->getProxyClassName($proxyClassName)); - $this->assertStringMatchesFormat($proxyClassName, $inflector->getProxyClassName($realClassName)); - $this->assertStringMatchesFormat($realClassName, $inflector->getUserClassName($proxyClassName)); - } - - /** - * @covers \ProxyManager\Inflector\ClassNameInflector::getProxyClassName - */ - public function testGeneratesSameClassNameWithSameParameters() - { - $inflector = new ClassNameInflector('ProxyNS'); - - $this->assertSame($inflector->getProxyClassName('Foo\\Bar'), $inflector->getProxyClassName('Foo\\Bar')); - $this->assertSame( - $inflector->getProxyClassName('Foo\\Bar', array('baz' => 'tab')), - $inflector->getProxyClassName('Foo\\Bar', array('baz' => 'tab')) - ); - $this->assertSame( - $inflector->getProxyClassName('Foo\\Bar', array('tab' => 'baz')), - $inflector->getProxyClassName('Foo\\Bar', array('tab' => 'baz')) - ); - } - - /** - * @covers \ProxyManager\Inflector\ClassNameInflector::getProxyClassName - */ - public function testGeneratesDifferentClassNameWithDifferentParameters() - { - $inflector = new ClassNameInflector('ProxyNS'); - - $this->assertNotSame( - $inflector->getProxyClassName('Foo\\Bar'), - $inflector->getProxyClassName('Foo\\Bar', array('foo' => 'bar')) - ); - $this->assertNotSame( - $inflector->getProxyClassName('Foo\\Bar', array('baz' => 'tab')), - $inflector->getProxyClassName('Foo\\Bar', array('tab' => 'baz')) - ); - $this->assertNotSame( - $inflector->getProxyClassName('Foo\\Bar', array('foo' => 'bar', 'tab' => 'baz')), - $inflector->getProxyClassName('Foo\\Bar', array('foo' => 'bar')) - ); - $this->assertNotSame( - $inflector->getProxyClassName('Foo\\Bar', array('foo' => 'bar', 'tab' => 'baz')), - $inflector->getProxyClassName('Foo\\Bar', array('tab' => 'baz', 'foo' => 'bar')) - ); - } - - /** - * @covers \ProxyManager\Inflector\ClassNameInflector::getProxyClassName - */ - public function testGeneratesCorrectClassNameWhenGivenLeadingBackslash() - { - $inflector = new ClassNameInflector('ProxyNS'); - - $this->assertSame( - $inflector->getProxyClassName('\\Foo\\Bar', array('tab' => 'baz')), - $inflector->getProxyClassName('Foo\\Bar', array('tab' => 'baz')) - ); - } - - /** - * @covers \ProxyManager\Inflector\ClassNameInflector::getProxyClassName - * - * @dataProvider getClassAndParametersCombinations - * - * @param string $className - * @param array $parameters - */ - public function testClassNameIsValidClassIdentifier($className, array $parameters) - { - $inflector = new ClassNameInflector('ProxyNS'); - - $this->assertRegExp( - '/([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]+)(\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]+)*/', - $inflector->getProxyClassName($className, $parameters), - 'Class name string is a valid class identifier' - ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function getClassNames() - { - return array( - array('Foo', 'ProxyNS\\' . ClassNameInflectorInterface::PROXY_MARKER . '\\Foo\\%s'), - array('Foo\\Bar', 'ProxyNS\\' . ClassNameInflectorInterface::PROXY_MARKER . '\\Foo\\Bar\\%s'), - ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function getClassAndParametersCombinations() - { - return array( - array('Foo', array()), - array('Foo\\Bar', array()), - array('Foo', array(null)), - array('Foo\\Bar', array(null)), - array('Foo', array('foo' => 'bar')), - array('Foo\\Bar', array('foo' => 'bar')), - array('Foo', array("\0" => "very \0 bad")), - array('Foo\\Bar', array("\0" => "very \0 bad")), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/Util/ParameterEncoderTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/Util/ParameterEncoderTest.php deleted file mode 100644 index 1acd28e..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/Util/ParameterEncoderTest.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ParameterEncoderTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getParameters - * - * @covers \ProxyManager\Inflector\Util\ParameterEncoder::encodeParameters - */ - public function testGeneratesValidClassName(array $parameters) - { - $encoder = new ParameterEncoder(); - - $this->assertRegExp( - '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]+/', - $encoder->encodeParameters($parameters), - 'Encoded string is a valid class identifier' - ); - } - - /** - * @return array - */ - public function getParameters() - { - return array( - array(array()), - array(array('foo' => 'bar')), - array(array('bar' => 'baz')), - array(array(null)), - array(array(null, null)), - array(array('bar' => null)), - array(array('bar' => 12345)), - array(array('foo' => 'bar', 'bar' => 'baz')), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/Util/ParameterHasherTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/Util/ParameterHasherTest.php deleted file mode 100644 index 22bf68d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Inflector/Util/ParameterHasherTest.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ParameterHasherTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getParameters - * - * @covers \ProxyManager\Inflector\Util\ParameterHasher::hashParameters - */ - public function testGeneratesValidClassName(array $parameters, $expectedHash) - { - $encoder = new ParameterHasher(); - - $this->assertSame($expectedHash, $encoder->hashParameters($parameters)); - } - - /** - * @return array - */ - public function getParameters() - { - return array( - array(array(), '40cd750bba9870f18aada2478b24840a'), - array(array('foo' => 'bar'), '49a3696adf0fbfacc12383a2d7400d51'), - array(array('bar' => 'baz'), '6ed41c8a63c1571554ecaeb998198757'), - array(array(null), '38017a839aaeb8ff1a658fce9af6edd3'), - array(array(null, null), '12051f9a58288e5328ad748881cc4e00'), - array(array('bar' => null), '0dbb112e1c4e6e4126232de2daa2d660'), - array(array('bar' => 12345), 'eb6291ea4973741bf9b6571f49b4ffd2'), - array(array('foo' => 'bar', 'bar' => 'baz'), '4447ff857f244d24c31bd84d7a855eda'), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AbstractProxyGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AbstractProxyGeneratorTest.php deleted file mode 100644 index 307aafc..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AbstractProxyGeneratorTest.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -abstract class AbstractProxyGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getTestedImplementations - * - * Verifies that generated code is valid and implements expected interfaces - */ - public function testGeneratesValidCode($className) - { - $generator = $this->getProxyGenerator(); - $generatedClassName = UniqueIdentifierGenerator::getIdentifier('AbstractProxyGeneratorTest'); - $generatedClass = new ClassGenerator($generatedClassName); - $originalClass = new ReflectionClass($className); - $generatorStrategy = new EvaluatingGeneratorStrategy(); - - $generator->generate($originalClass, $generatedClass); - $generatorStrategy->generate($generatedClass); - - $generatedReflection = new ReflectionClass($generatedClassName); - - if ($originalClass->isInterface()) { - $this->assertTrue($generatedReflection->implementsInterface($className)); - } else { - $this->assertSame($originalClass->getName(), $generatedReflection->getParentClass()->getName()); - } - - $this->assertSame($generatedClassName, $generatedReflection->getName()); - - foreach ($this->getExpectedImplementedInterfaces() as $interface) { - $this->assertTrue($generatedReflection->implementsInterface($interface)); - } - } - - /** - * Retrieve a new generator instance - * - * @return \ProxyManager\ProxyGenerator\ProxyGeneratorInterface - */ - abstract protected function getProxyGenerator(); - - /** - * Retrieve interfaces that should be implemented by the generated code - * - * @return string[] - */ - abstract protected function getExpectedImplementedInterfaces(); - - /** - * @return array - */ - public function getTestedImplementations() - { - return array( - array('ProxyManagerTestAsset\\BaseClass'), - array('ProxyManagerTestAsset\\ClassWithMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithByRefMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithMixedProperties'), - array('ProxyManagerTestAsset\\BaseInterface'), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/MagicWakeupTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/MagicWakeupTest.php deleted file mode 100644 index a5c5bec..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/MagicWakeupTest.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicWakeupTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\MagicWakeup::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass( - 'ProxyManagerTestAsset\\ProxyGenerator\\LazyLoading\\MethodGenerator\\ClassWithTwoPublicProperties' - ); - - $magicWakeup = new MagicWakeup($reflection); - - $this->assertSame('__wakeup', $magicWakeup->getName()); - $this->assertCount(0, $magicWakeup->getParameters()); - $this->assertSame("unset(\$this->bar, \$this->baz);", $magicWakeup->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\MagicWakeup::__construct - */ - public function testBodyStructureWithoutPublicProperties() - { - $magicWakeup = new MagicWakeup(new ReflectionClass('ProxyManagerTestAsset\\EmptyClass')); - - $this->assertSame('__wakeup', $magicWakeup->getName()); - $this->assertCount(0, $magicWakeup->getParameters()); - $this->assertEmpty($magicWakeup->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodPrefixInterceptorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodPrefixInterceptorTest.php deleted file mode 100644 index e35c993..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodPrefixInterceptorTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class SetMethodPrefixInterceptorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\SetMethodPrefixInterceptor::__construct - */ - public function testBodyStructure() - { - $suffix = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $suffix->expects($this->once())->method('getName')->will($this->returnValue('foo')); - - $setter = new SetMethodPrefixInterceptor($suffix); - - $this->assertSame('setMethodPrefixInterceptor', $setter->getName()); - $this->assertCount(2, $setter->getParameters()); - $this->assertSame('$this->foo[$methodName] = $prefixInterceptor;', $setter->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodSuffixInterceptorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodSuffixInterceptorTest.php deleted file mode 100644 index db65647..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodSuffixInterceptorTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class SetMethodSuffixInterceptorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\SetMethodSuffixInterceptor::__construct - */ - public function testBodyStructure() - { - $suffix = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $suffix->expects($this->once())->method('getName')->will($this->returnValue('foo')); - - $setter = new SetMethodSuffixInterceptor($suffix); - - $this->assertSame('setMethodSuffixInterceptor', $setter->getName()); - $this->assertCount(2, $setter->getParameters()); - $this->assertSame('$this->foo[$methodName] = $suffixInterceptor;', $setter->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodPrefixInterceptorsTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodPrefixInterceptorsTest.php deleted file mode 100644 index 9b6de3d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodPrefixInterceptorsTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\AccessInterceptor\PropertyGenerator\MethodPrefixInterceptors - * @group Coverage - */ -class MethodPrefixInterceptorsTest extends AbstractUniquePropertyNameTest -{ - /** - * {@inheritDoc} - */ - protected function createProperty() - { - return new MethodPrefixInterceptors(); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodSuffixInterceptorsTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodSuffixInterceptorsTest.php deleted file mode 100644 index 7515bad..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodSuffixInterceptorsTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\AccessInterceptor\PropertyGenerator\MethodSuffixInterceptors - * @group Coverage - */ -class MethodSuffixInterceptorsTest extends AbstractUniquePropertyNameTest -{ - /** - * {@inheritDoc} - */ - protected function createProperty() - { - return new MethodSuffixInterceptors(); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/ConstructorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/ConstructorTest.php deleted file mode 100644 index a1b5c12..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/ConstructorTest.php +++ /dev/null @@ -1,207 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ConstructorTest extends PHPUnit_Framework_TestCase -{ - private $prefixInterceptors; - private $suffixInterceptors; - public function setUp() - { - $this->prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $this->suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $this->prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $this->suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Constructor::__construct - */ - public function testSignature() - { - $constructor = new Constructor( - new ReflectionClass('ProxyManagerTestAsset\\ClassWithProtectedProperties'), - $this->prefixInterceptors, - $this->suffixInterceptors - ); - $this->assertSame('__construct', $constructor->getName()); - - $parameters = $constructor->getParameters(); - - $this->assertCount(3, $parameters); - - $this->assertSame( - 'ProxyManagerTestAsset\\ClassWithProtectedProperties', - $parameters['localizedObject']->getType() - ); - $this->assertSame('array', $parameters['prefixInterceptors']->getType()); - $this->assertSame('array', $parameters['suffixInterceptors']->getType()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Constructor::__construct - */ - public function testBodyStructure() - { - $constructor = new Constructor( - new ReflectionClass('ProxyManagerTestAsset\\ClassWithPublicProperties'), - $this->prefixInterceptors, - $this->suffixInterceptors - ); - - $this->assertSame( - '$this->property0 = & $localizedObject->property0; - -$this->property1 = & $localizedObject->property1; - -$this->property2 = & $localizedObject->property2; - -$this->property3 = & $localizedObject->property3; - -$this->property4 = & $localizedObject->property4; - -$this->property5 = & $localizedObject->property5; - -$this->property6 = & $localizedObject->property6; - -$this->property7 = & $localizedObject->property7; - -$this->property8 = & $localizedObject->property8; - -$this->property9 = & $localizedObject->property9; - -$this->pre = $prefixInterceptors; -$this->post = $suffixInterceptors;', - $constructor->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Constructor::__construct - */ - public function testBodyStructureWithProtectedProperties() - { - $constructor = new Constructor( - new ReflectionClass('ProxyManagerTestAsset\\ClassWithProtectedProperties'), - $this->prefixInterceptors, - $this->suffixInterceptors - ); - - $this->assertSame( - '$this->property0 = & $localizedObject->property0; - -$this->property1 = & $localizedObject->property1; - -$this->property2 = & $localizedObject->property2; - -$this->property3 = & $localizedObject->property3; - -$this->property4 = & $localizedObject->property4; - -$this->property5 = & $localizedObject->property5; - -$this->property6 = & $localizedObject->property6; - -$this->property7 = & $localizedObject->property7; - -$this->property8 = & $localizedObject->property8; - -$this->property9 = & $localizedObject->property9; - -$this->pre = $prefixInterceptors; -$this->post = $suffixInterceptors;', - $constructor->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Constructor::__construct - */ - public function testBodyStructureWithPrivateProperties() - { - if (! method_exists('Closure', 'bind')) { - $this->setExpectedException('ProxyManager\Exception\UnsupportedProxiedClassException'); - } - - $constructor = new Constructor( - new ReflectionClass('ProxyManagerTestAsset\\ClassWithPrivateProperties'), - $this->prefixInterceptors, - $this->suffixInterceptors - ); - - $this->assertSame( - '\Closure::bind(function () use ($localizedObject) { - $this->property0 = & $localizedObject->property0; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property1 = & $localizedObject->property1; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property2 = & $localizedObject->property2; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property3 = & $localizedObject->property3; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property4 = & $localizedObject->property4; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property5 = & $localizedObject->property5; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property6 = & $localizedObject->property6; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property7 = & $localizedObject->property7; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property8 = & $localizedObject->property8; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -\Closure::bind(function () use ($localizedObject) { - $this->property9 = & $localizedObject->property9; -}, $this, \'ProxyManagerTestAsset\\\\ClassWithPrivateProperties\')->__invoke(); - -$this->pre = $prefixInterceptors; -$this->post = $suffixInterceptors;', - $constructor->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/InterceptedMethodTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/InterceptedMethodTest.php deleted file mode 100644 index 207359f..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/InterceptedMethodTest.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\InterceptedMethod - * @group Coverage - */ -class InterceptedMethodTest extends PHPUnit_Framework_TestCase -{ - public function testBodyStructure() - { - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $method = InterceptedMethod::generateMethod( - new MethodReflection('ProxyManagerTestAsset\\BaseClass', 'publicByReferenceParameterMethod'), - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertInstanceOf('ProxyManager\\Generator\\MethodGenerator', $method); - - $this->assertSame('publicByReferenceParameterMethod', $method->getName()); - $this->assertCount(2, $method->getParameters()); - $this->assertGreaterThan( - 0, - strpos( - $method->getBody(), - '$returnValue = parent::publicByReferenceParameterMethod($param, $byRefParam);' - ) - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicCloneTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicCloneTest.php deleted file mode 100644 index df4f49e..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicCloneTest.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicCloneTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicClone::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicClone = new MagicClone($reflection, $prefixInterceptors, $suffixInterceptors); - - $this->assertSame('__clone', $magicClone->getName()); - $this->assertCount(0, $magicClone->getParameters()); - $this->assertStringMatchesFormat("%a\n\n\$returnValue = null;\n\n%a", $magicClone->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicClone::__construct - */ - public function testBodyStructureWithInheritedMethod() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicClone = new MagicClone($reflection, $prefixInterceptors, $suffixInterceptors); - - $this->assertSame('__clone', $magicClone->getName()); - $this->assertCount(0, $magicClone->getParameters()); - $this->assertStringMatchesFormat("%a\n\n\$returnValue = parent::__clone();\n\n%a", $magicClone->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicGetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicGetTest.php deleted file mode 100644 index ed67bb0..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicGetTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicGetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicGet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicGet( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__get', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = & $accessor();%a', $magicGet->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicGet::__construct - */ - public function testBodyStructureWithInheritedMethod() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicGet( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__get', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = & parent::__get($name);%a', $magicGet->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicIssetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicIssetTest.php deleted file mode 100644 index 0dabe4c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicIssetTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicIssetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicIsset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicIsset( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__isset', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = $accessor();%a', $magicGet->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicIsset::__construct - */ - public function testBodyStructureWithInheritedMethod() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicIsset( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__isset', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = & parent::__isset($name);%a', $magicGet->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSetTest.php deleted file mode 100644 index 25d3070..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSetTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicSet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicSet( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__set', $magicGet->getName()); - $this->assertCount(2, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = & $accessor();%a', $magicGet->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicSet::__construct - */ - public function testBodyStructureWithInheritedMethod() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicSet( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__set', $magicGet->getName()); - $this->assertCount(2, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = & parent::__set($name, $value);%a', $magicGet->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSleepTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSleepTest.php deleted file mode 100644 index 98e401b..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSleepTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSleepTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicSleep::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicSleep( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__sleep', $magicGet->getName()); - $this->assertEmpty($magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = array_keys((array) $this);%a', $magicGet->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicSleep::__construct - */ - public function testBodyStructureWithInheritedMethod() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicSleep( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__sleep', $magicGet->getName()); - $this->assertEmpty($magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = & parent::__sleep();%a', $magicGet->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicUnsetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicUnsetTest.php deleted file mode 100644 index 822fda5..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicUnsetTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicUnsetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicUnset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicUnset( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__unset', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = $accessor();%a', $magicGet->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicUnset::__construct - */ - public function testBodyStructureWithInheritedMethod() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicGet = new MagicUnset( - $reflection, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame('__unset', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%a$returnValue = & parent::__unset($name);%a', $magicGet->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Util/InterceptorGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Util/InterceptorGeneratorTest.php deleted file mode 100644 index 7e54c70..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Util/InterceptorGeneratorTest.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class InterceptorGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Util\InterceptorGenerator - */ - public function testInterceptorGenerator() - { - $method = $this->getMock('ProxyManager\\Generator\\MethodGenerator'); - $bar = $this->getMock('ProxyManager\\Generator\\ParameterGenerator'); - $baz = $this->getMock('ProxyManager\\Generator\\ParameterGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $bar->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $baz->expects($this->any())->method('getName')->will($this->returnValue('baz')); - $method->expects($this->any())->method('getName')->will($this->returnValue('fooMethod')); - $method->expects($this->any())->method('getParameters')->will($this->returnValue(array($bar, $baz))); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $body = InterceptorGenerator::createInterceptedMethodBody( - '$returnValue = "foo";', - $method, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame( - 'if (isset($this->pre[\'fooMethod\'])) {' . "\n" - . ' $returnEarly = false;' . "\n" - . ' $prefixReturnValue = $this->pre[\'fooMethod\']->__invoke($this, $this, \'fooMethod\', ' - . 'array(\'bar\' => $bar, \'baz\' => $baz), $returnEarly);' . "\n\n" - . ' if ($returnEarly) {' . "\n" - . ' return $prefixReturnValue;' . "\n" - . ' }' . "\n" - . '}' . "\n\n" - . '$returnValue = "foo";' . "\n\n" - . 'if (isset($this->post[\'fooMethod\'])) {' . "\n" - . ' $returnEarly = false;' . "\n" - . ' $suffixReturnValue = $this->post[\'fooMethod\']->__invoke($this, $this, \'fooMethod\', ' - . 'array(\'bar\' => $bar, \'baz\' => $baz), $returnValue, $returnEarly);' . "\n\n" - . ' if ($returnEarly) {' . "\n" - . ' return $suffixReturnValue;' . "\n" - . ' }' . "\n" - . '}' . "\n\n" - . 'return $returnValue;', - $body - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizerTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizerTest.php deleted file mode 100644 index bd6af22..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizerTest.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizerGenerator - * @group Coverage - */ -class AccessInterceptorScopeLocalizerTest extends AbstractProxyGeneratorTest -{ - /** - * @dataProvider getTestedImplementations - * - * {@inheritDoc} - */ - public function testGeneratesValidCode($className) - { - $reflectionClass = new ReflectionClass($className); - - if ($reflectionClass->isInterface()) { - // @todo interfaces *may* be proxied by deferring property localization to the constructor (no hardcoding) - $this->setExpectedException('ProxyManager\Exception\InvalidProxiedClassException'); - - return parent::testGeneratesValidCode($className); - } - - if ((! method_exists('Closure', 'bind')) - && $reflectionClass->getProperties(ReflectionProperty::IS_PRIVATE) - ) { - $this->setExpectedException('ProxyManager\Exception\UnsupportedProxiedClassException'); - } - - return parent::testGeneratesValidCode($className); - } - - /** - * {@inheritDoc} - */ - protected function getProxyGenerator() - { - return new AccessInterceptorScopeLocalizerGenerator(); - } - - /** - * {@inheritDoc} - */ - protected function getExpectedImplementedInterfaces() - { - return array('ProxyManager\\Proxy\\AccessInterceptorInterface'); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/LazyLoading/MethodGenerator/ConstructorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/LazyLoading/MethodGenerator/ConstructorTest.php deleted file mode 100644 index e4209c1..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/LazyLoading/MethodGenerator/ConstructorTest.php +++ /dev/null @@ -1,69 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ConstructorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoading\MethodGenerator\Constructor::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $reflection = new ReflectionClass( - 'ProxyManagerTestAsset\\ProxyGenerator\\LazyLoading\\MethodGenerator\\ClassWithTwoPublicProperties' - ); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $constructor = new Constructor($reflection, $initializer); - - $this->assertSame('__construct', $constructor->getName()); - $this->assertCount(1, $constructor->getParameters()); - $this->assertSame("unset(\$this->bar, \$this->baz);\n\n\$this->foo = \$initializer;", $constructor->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoading\MethodGenerator\Constructor::__construct - */ - public function testBodyStructureWithoutPublicProperties() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $constructor = new Constructor(new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'), $initializer); - - $this->assertSame('__construct', $constructor->getName()); - $this->assertCount(1, $constructor->getParameters()); - $this->assertSame("\$this->foo = \$initializer;", $constructor->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/ConstructorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/ConstructorTest.php deleted file mode 100644 index 97f7175..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/ConstructorTest.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ConstructorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Constructor::__construct - */ - public function testBodyStructure() - { - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $reflection = new ReflectionClass( - 'ProxyManagerTestAsset\\ProxyGenerator\\LazyLoading\\MethodGenerator\\ClassWithTwoPublicProperties' - ); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $constructor = new Constructor($reflection, $valueHolder, $prefixInterceptors, $suffixInterceptors); - - $this->assertSame('__construct', $constructor->getName()); - $this->assertCount(3, $constructor->getParameters()); - $this->assertSame( - "unset(\$this->bar, \$this->baz);\n\n\$this->foo = \$wrappedObject;\n\$this->pre = \$prefixInterceptors;" - . "\n\$this->post = \$suffixInterceptors;", - $constructor->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Constructor::__construct - */ - public function testBodyStructureWithoutPublicProperties() - { - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $constructor = new Constructor($reflection, $valueHolder, $prefixInterceptors, $suffixInterceptors); - - $this->assertSame('__construct', $constructor->getName()); - $this->assertCount(3, $constructor->getParameters()); - $this->assertSame( - "\$this->foo = \$wrappedObject;\n\$this->pre = \$prefixInterceptors;" - . "\n\$this->post = \$suffixInterceptors;", - $constructor->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/InterceptedMethodTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/InterceptedMethodTest.php deleted file mode 100644 index 41b5bfb..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/InterceptedMethodTest.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\InterceptedMethod::generateMethod - * @group Coverage - */ -class InterceptedMethodTest extends PHPUnit_Framework_TestCase -{ - public function testBodyStructure() - { - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $method = InterceptedMethod::generateMethod( - new MethodReflection('ProxyManagerTestAsset\\BaseClass', 'publicByReferenceParameterMethod'), - $valueHolder, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertInstanceOf('ProxyManager\\Generator\\MethodGenerator', $method); - - $this->assertSame('publicByReferenceParameterMethod', $method->getName()); - $this->assertCount(2, $method->getParameters()); - $this->assertGreaterThan( - 0, - strpos( - $method->getBody(), - '$returnValue = $this->foo->publicByReferenceParameterMethod($param, $byRefParam);' - ) - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicCloneTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicCloneTest.php deleted file mode 100644 index 72a7763..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicCloneTest.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicCloneTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicClone::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $magicClone = new MagicClone($reflection, $valueHolder, $prefixInterceptors, $suffixInterceptors); - - $this->assertSame('__clone', $magicClone->getName()); - $this->assertCount(0, $magicClone->getParameters()); - $this->assertSame( - '$this->bar = clone $this->bar;' . "\n\n" - . 'foreach ($this->pre as $key => $value) {' . "\n" - . ' $this->pre[$key] = clone $value;' . "\n" - . '}' . "\n\n" - . 'foreach ($this->post as $key => $value) {' . "\n" - . ' $this->post[$key] = clone $value;' . "\n" - . '}', - $magicClone->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicGetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicGetTest.php deleted file mode 100644 index 0ca38de..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicGetTest.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicGetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicGet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - $publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - - $magicGet = new MagicGet( - $reflection, - $valueHolder, - $prefixInterceptors, - $suffixInterceptors, - $publicProperties - ); - - $this->assertSame('__get', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat('%A$returnValue = & $this->bar->$name;%A', $magicGet->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicIssetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicIssetTest.php deleted file mode 100644 index 5f34baf..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicIssetTest.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicIssetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicIsset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - $publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - - $magicIsset = new MagicIsset( - $reflection, - $valueHolder, - $prefixInterceptors, - $suffixInterceptors, - $publicProperties - ); - - $this->assertSame('__isset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertGreaterThan(0, strpos($magicIsset->getBody(), '$returnValue = isset($this->bar->$name);')); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicSetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicSetTest.php deleted file mode 100644 index 93da0b9..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicSetTest.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicSet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - $publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - - $magicSet = new MagicSet( - $reflection, - $valueHolder, - $prefixInterceptors, - $suffixInterceptors, - $publicProperties - ); - - $this->assertSame('__set', $magicSet->getName()); - $this->assertCount(2, $magicSet->getParameters()); - $this->assertGreaterThan(0, strpos($magicSet->getBody(), '$returnValue = ($this->bar->$name = $value);')); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicUnsetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicUnsetTest.php deleted file mode 100644 index 0433ff6..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicUnsetTest.php +++ /dev/null @@ -1,69 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicUnsetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicUnset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - $publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - - $magicUnset = new MagicUnset( - $reflection, - $valueHolder, - $prefixInterceptors, - $suffixInterceptors, - $publicProperties - ); - - $this->assertSame('__unset', $magicUnset->getName()); - $this->assertCount(1, $magicUnset->getParameters()); - $this->assertGreaterThan( - 0, - strpos($magicUnset->getBody(), 'unset($this->bar->$name);') - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Util/InterceptorGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Util/InterceptorGeneratorTest.php deleted file mode 100644 index bb5c461..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Util/InterceptorGeneratorTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class InterceptorGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Util\InterceptorGenerator - */ - public function testInterceptorGenerator() - { - $method = $this->getMock('ProxyManager\\Generator\\MethodGenerator'); - $bar = $this->getMock('ProxyManager\\Generator\\ParameterGenerator'); - $baz = $this->getMock('ProxyManager\\Generator\\ParameterGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $prefixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $suffixInterceptors = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $bar->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $baz->expects($this->any())->method('getName')->will($this->returnValue('baz')); - $method->expects($this->any())->method('getName')->will($this->returnValue('fooMethod')); - $method->expects($this->any())->method('getParameters')->will($this->returnValue(array($bar, $baz))); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $prefixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('pre')); - $suffixInterceptors->expects($this->any())->method('getName')->will($this->returnValue('post')); - - $body = InterceptorGenerator::createInterceptedMethodBody( - '$returnValue = "foo";', - $method, - $valueHolder, - $prefixInterceptors, - $suffixInterceptors - ); - - $this->assertSame( - 'if (isset($this->pre[\'fooMethod\'])) {' . "\n" - . ' $returnEarly = false;' . "\n" - . ' $prefixReturnValue = $this->pre[\'fooMethod\']->__invoke($this, $this->foo, \'fooMethod\', ' - . 'array(\'bar\' => $bar, \'baz\' => $baz), $returnEarly);' . "\n\n" - . ' if ($returnEarly) {' . "\n" - . ' return $prefixReturnValue;' . "\n" - . ' }' . "\n" - . '}' . "\n\n" - . '$returnValue = "foo";' . "\n\n" - . 'if (isset($this->post[\'fooMethod\'])) {' . "\n" - . ' $returnEarly = false;' . "\n" - . ' $suffixReturnValue = $this->post[\'fooMethod\']->__invoke($this, $this->foo, \'fooMethod\', ' - . 'array(\'bar\' => $bar, \'baz\' => $baz), $returnValue, $returnEarly);' . "\n\n" - . ' if ($returnEarly) {' . "\n" - . ' return $suffixReturnValue;' . "\n" - . ' }' . "\n" - . '}' . "\n\n" - . 'return $returnValue;', - $body - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolderTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolderTest.php deleted file mode 100644 index 1b7d806..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorValueHolderTest.php +++ /dev/null @@ -1,52 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\AccessInterceptorValueHolderGenerator - * @group Coverage - */ -class AccessInterceptorValueHolderTest extends AbstractProxyGeneratorTest -{ - /** - * {@inheritDoc} - */ - protected function getProxyGenerator() - { - return new AccessInterceptorValueHolderGenerator(); - } - - /** - * {@inheritDoc} - */ - protected function getExpectedImplementedInterfaces() - { - return array( - 'ProxyManager\\Proxy\\AccessInterceptorInterface', - 'ProxyManager\\Proxy\\ValueHolderInterface', - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Assertion/CanProxyAssertionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Assertion/CanProxyAssertionTest.php deleted file mode 100644 index 1c9003f..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Assertion/CanProxyAssertionTest.php +++ /dev/null @@ -1,113 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\Assertion\CanProxyAssertion - * @group Coverage - */ -class CanProxyAssertionTest extends PHPUnit_Framework_TestCase -{ - public function testDeniesFinalClasses() - { - $this->setExpectedException('ProxyManager\Exception\InvalidProxiedClassException'); - - CanProxyAssertion::assertClassCanBeProxied(new ReflectionClass('ProxyManagerTestAsset\\FinalClass')); - } - - public function testDeniesClassesWithAbstractProtectedMethods() - { - $this->setExpectedException('ProxyManager\Exception\InvalidProxiedClassException'); - - CanProxyAssertion::assertClassCanBeProxied(new ReflectionClass( - 'ProxyManagerTestAsset\\ClassWithAbstractProtectedMethod' - )); - } - - public function testAllowsInterfaceByDefault() - { - CanProxyAssertion::assertClassCanBeProxied(new ReflectionClass( - 'ProxyManagerTestAsset\\BaseInterface' - )); - - $this->assertTrue(true); // not nice, but assertions are just fail-checks, no real code executed - } - - public function testDeniesInterfaceIfSpecified() - { - $this->setExpectedException('ProxyManager\Exception\InvalidProxiedClassException'); - - CanProxyAssertion::assertClassCanBeProxied(new ReflectionClass('ProxyManagerTestAsset\\BaseInterface'), false); - } - - /** - * @param string $className - * - * @dataProvider validClasses - */ - public function testAllowedClass($className) - { - CanProxyAssertion::assertClassCanBeProxied(new ReflectionClass($className)); - - $this->assertTrue(true); // not nice, but assertions are just fail-checks, no real code executed - } - - public function testDisallowsConstructor() - { - $this->setExpectedException('BadMethodCallException'); - - new CanProxyAssertion(); - } - - /** - * @return string[][] - */ - public function validClasses() - { - return array( - array('ProxyManagerTestAsset\AccessInterceptorValueHolderMock'), - array('ProxyManagerTestAsset\BaseClass'), - array('ProxyManagerTestAsset\BaseInterface'), - array('ProxyManagerTestAsset\CallableTypeHintClass'), - array('ProxyManagerTestAsset\ClassWithByRefMagicMethods'), - array('ProxyManagerTestAsset\ClassWithFinalMagicMethods'), - array('ProxyManagerTestAsset\ClassWithFinalMethods'), - array('ProxyManagerTestAsset\ClassWithMethodWithDefaultParameters'), - array('ProxyManagerTestAsset\ClassWithMixedProperties'), - array('ProxyManagerTestAsset\ClassWithPrivateProperties'), - array('ProxyManagerTestAsset\ClassWithProtectedProperties'), - array('ProxyManagerTestAsset\ClassWithPublicProperties'), - array('ProxyManagerTestAsset\ClassWithPublicArrayProperty'), - array('ProxyManagerTestAsset\ClassWithSelfHint'), - array('ProxyManagerTestAsset\EmptyClass'), - array('ProxyManagerTestAsset\HydratedObject'), - array('ProxyManagerTestAsset\LazyLoadingMock'), - array('ProxyManagerTestAsset\NullObjectMock'), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/CallInitializerTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/CallInitializerTest.php deleted file mode 100644 index 3fbd81d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/CallInitializerTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class CallInitializerTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\CallInitializer::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $propertiesDefaults = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $initializationTracker = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('init')); - $propertiesDefaults->expects($this->any())->method('getName')->will($this->returnValue('props')); - $initializationTracker->expects($this->any())->method('getName')->will($this->returnValue('track')); - - $callInitializer = new CallInitializer($initializer, $propertiesDefaults, $initializationTracker); - - $this->assertStringMatchesFormat( - '%Aif ($this->track || ! $this->init) {%areturn;%a}%a' - . '$this->track = true;%a' - . 'foreach (self::$props as $key => $default) {%a' - . '$this->$key = $default;%a' - . '$this->init->__invoke(%a);%a' - . '$this->track = false;', - $callInitializer->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/GetProxyInitializerTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/GetProxyInitializerTest.php deleted file mode 100644 index 32936b9..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/GetProxyInitializerTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class GetProxyInitializerTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\GetProxyInitializer::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $getter = new GetProxyInitializer($initializer); - - $this->assertSame('getProxyInitializer', $getter->getName()); - $this->assertCount(0, $getter->getParameters()); - $this->assertSame('return $this->foo;', $getter->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/InitializeProxyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/InitializeProxyTest.php deleted file mode 100644 index 27e1e2d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/InitializeProxyTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class InitializeProxyTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\InitializeProxy::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $initCall = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $initCall->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $initializeProxy = new InitializeProxy($initializer, $initCall); - - $this->assertSame('initializeProxy', $initializeProxy->getName()); - $this->assertCount(0, $initializeProxy->getParameters()); - $this->assertSame( - 'return $this->foo && $this->bar(\'initializeProxy\', array());', - $initializeProxy->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/IsProxyInitializedTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/IsProxyInitializedTest.php deleted file mode 100644 index f82dae9..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/IsProxyInitializedTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class IsProxyInitializedTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\IsProxyInitialized::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $isProxyInitialized = new IsProxyInitialized($initializer); - - $this->assertSame('isProxyInitialized', $isProxyInitialized->getName()); - $this->assertCount(0, $isProxyInitialized->getParameters()); - $this->assertSame('return ! $this->foo;', $isProxyInitialized->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/LazyLoadingMethodInterceptorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/LazyLoadingMethodInterceptorTest.php deleted file mode 100644 index db5e3af..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/LazyLoadingMethodInterceptorTest.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class LazyLoadingMethodInterceptorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\LazyLoadingMethodInterceptor - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $initCall = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $initCall->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $reflection = new MethodReflection('ProxyManagerTestAsset\\BaseClass', 'publicByReferenceParameterMethod'); - $method = LazyLoadingMethodInterceptor::generateMethod($reflection, $initializer, $initCall); - - $this->assertSame('publicByReferenceParameterMethod', $method->getName()); - $this->assertCount(2, $method->getParameters()); - $this->assertSame( - "\$this->foo && \$this->bar('publicByReferenceParameterMethod', " - . "array('param' => \$param, 'byRefParam' => \$byRefParam));\n\n" - . "return parent::publicByReferenceParameterMethod(\$param, \$byRefParam);", - $method->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\LazyLoadingMethodInterceptor - */ - public function testBodyStructureWithoutParameters() - { - $reflectionMethod = new MethodReflection(__CLASS__, 'testBodyStructureWithoutParameters'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $initCall = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $initCall->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $method = LazyLoadingMethodInterceptor::generateMethod($reflectionMethod, $initializer, $initCall); - - $this->assertSame('testBodyStructureWithoutParameters', $method->getName()); - $this->assertCount(0, $method->getParameters()); - $this->assertSame( - "\$this->foo && \$this->bar('testBodyStructureWithoutParameters', array());\n\n" - . "return parent::testBodyStructureWithoutParameters();", - $method->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicCloneTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicCloneTest.php deleted file mode 100644 index 4cb2271..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicCloneTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicCloneTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicClone::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $initCall = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $initCall->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicClone = new MagicClone($reflection, $initializer, $initCall); - - $this->assertSame('__clone', $magicClone->getName()); - $this->assertCount(0, $magicClone->getParameters()); - $this->assertSame( - "\$this->foo && \$this->bar('__clone', array());", - $magicClone->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php deleted file mode 100644 index 6f2a7c0..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php +++ /dev/null @@ -1,124 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicGetTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \Zend\Code\Generator\PropertyGenerator|\PHPUnit_Framework_MockObject_MockObject - */ - protected $initializer; - - /** - * @var \Zend\Code\Generator\MethodGenerator|\PHPUnit_Framework_MockObject_MockObject - */ - protected $initMethod; - - /** - * @var \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap|\PHPUnit_Framework_MockObject_MockObject - */ - protected $publicProperties; - - /** - * {@inheritDoc} - */ - protected function setUp() - { - $this->initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $this->initMethod = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - $this->publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $this->initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $this->initMethod->expects($this->any())->method('getName')->will($this->returnValue('baz')); - $this->publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - $this->publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $magicGet = new MagicGet($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__get', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->baz('__get', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return \$this->\$name;\n}\n\n" - . "%a", - $magicGet->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet::__construct - */ - public function testBodyStructureWithPublicProperties() - { - $reflection = new ReflectionClass( - 'ProxyManagerTestAsset\\ProxyGenerator\\LazyLoading\\MethodGenerator\\ClassWithTwoPublicProperties' - ); - - $magicGet = new MagicGet($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__get', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->baz('__get', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return \$this->\$name;\n}\n\n" - . "%a", - $magicGet->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet::__construct - */ - public function testBodyStructureWithOverriddenMagicGet() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $magicGet = new MagicGet($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__get', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertSame( - "\$this->foo && \$this->baz('__get', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return \$this->\$name;\n}\n\n" - . "return parent::__get(\$name);", - $magicGet->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicIssetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicIssetTest.php deleted file mode 100644 index fa9bb4b..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicIssetTest.php +++ /dev/null @@ -1,123 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicIssetTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \Zend\Code\Generator\PropertyGenerator|\PHPUnit_Framework_MockObject_MockObject - */ - protected $initializer; - - /** - * @var \Zend\Code\Generator\MethodGenerator|\PHPUnit_Framework_MockObject_MockObject - */ - protected $initMethod; - - /** - * @var \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap|\PHPUnit_Framework_MockObject_MockObject - */ - protected $publicProperties; - - /** - * {@inheritDoc} - */ - protected function setUp() - { - $this->initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $this->initMethod = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - $this->publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $this->initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $this->initMethod->expects($this->any())->method('getName')->will($this->returnValue('baz')); - $this->publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - $this->publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicIsset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $magicIsset = new MagicIsset($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__isset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->baz('__isset', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return isset(\$this->\$name);\n}\n\n" - . "%areturn %s;", - $magicIsset->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicIsset::__construct - */ - public function testBodyStructureWithPublicProperties() - { - $reflection = new ReflectionClass( - 'ProxyManagerTestAsset\\ProxyGenerator\\LazyLoading\\MethodGenerator\\ClassWithTwoPublicProperties' - ); - $magicIsset = new MagicIsset($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__isset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->baz('__isset', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return isset(\$this->\$name);\n}\n\n" - . "%areturn %s;", - $magicIsset->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicIsset::__construct - */ - public function testBodyStructureWithOverriddenMagicGet() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $magicIsset = new MagicIsset($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__isset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertSame( - "\$this->foo && \$this->baz('__isset', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return isset(\$this->\$name);\n}\n\n" - . "return parent::__isset(\$name);", - $magicIsset->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSetTest.php deleted file mode 100644 index 00b7ad9..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSetTest.php +++ /dev/null @@ -1,124 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSetTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \Zend\Code\Generator\PropertyGenerator|\PHPUnit_Framework_MockObject_MockObject - */ - protected $initializer; - - /** - * @var \Zend\Code\Generator\MethodGenerator|\PHPUnit_Framework_MockObject_MockObject - */ - protected $initMethod; - - /** - * @var \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap|\PHPUnit_Framework_MockObject_MockObject - */ - protected $publicProperties; - - /** - * {@inheritDoc} - */ - protected function setUp() - { - $this->initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $this->initMethod = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - $this->publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $this->initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $this->initMethod->expects($this->any())->method('getName')->will($this->returnValue('baz')); - $this->publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - $this->publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicSet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $magicSet = new MagicSet($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__set', $magicSet->getName()); - $this->assertCount(2, $magicSet->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->baz('__set', array('name' => \$name, 'value' => \$value));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return (\$this->\$name = \$value);\n}\n\n" - . "%areturn %s;", - $magicSet->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicSet::__construct - */ - public function testBodyStructureWithPublicProperties() - { - $reflection = new ReflectionClass( - 'ProxyManagerTestAsset\\ProxyGenerator\\LazyLoading\\MethodGenerator\\ClassWithTwoPublicProperties' - ); - - $magicSet = new MagicSet($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__set', $magicSet->getName()); - $this->assertCount(2, $magicSet->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->baz('__set', array('name' => \$name, 'value' => \$value));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return (\$this->\$name = \$value);\n}\n\n" - . "%areturn %s;", - $magicSet->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicSet::__construct - */ - public function testBodyStructureWithOverriddenMagicGet() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $magicSet = new MagicSet($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__set', $magicSet->getName()); - $this->assertCount(2, $magicSet->getParameters()); - $this->assertSame( - "\$this->foo && \$this->baz('__set', array('name' => \$name, 'value' => \$value));\n\n" - . "if (isset(self::\$bar[\$name])) {\n return (\$this->\$name = \$value);\n}\n\n" - . "return parent::__set(\$name, \$value);", - $magicSet->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSleepTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSleepTest.php deleted file mode 100644 index 7329e61..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSleepTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSleepTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicSleep::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $initMethod = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $initMethod->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicSleep = new MagicSleep($reflection, $initializer, $initMethod); - - $this->assertSame('__sleep', $magicSleep->getName()); - $this->assertCount(0, $magicSleep->getParameters()); - $this->assertSame( - "\$this->foo && \$this->bar('__sleep', array());" - . "\n\nreturn array_keys((array) \$this);", - $magicSleep->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicUnsetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicUnsetTest.php deleted file mode 100644 index 5e3ba4e..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicUnsetTest.php +++ /dev/null @@ -1,124 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicUnsetTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \Zend\Code\Generator\PropertyGenerator|\PHPUnit_Framework_MockObject_MockObject - */ - protected $initializer; - - /** - * @var \Zend\Code\Generator\MethodGenerator|\PHPUnit_Framework_MockObject_MockObject - */ - protected $initMethod; - - /** - * @var \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap|\PHPUnit_Framework_MockObject_MockObject - */ - protected $publicProperties; - - /** - * {@inheritDoc} - */ - protected function setUp() - { - $this->initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $this->initMethod = $this->getMock('Zend\\Code\\Generator\\MethodGenerator'); - $this->publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $this->initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $this->initMethod->expects($this->any())->method('getName')->will($this->returnValue('baz')); - $this->publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - $this->publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicUnset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $magicIsset = new MagicUnset($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__unset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->baz('__unset', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n unset(\$this->\$name);\n\n return;\n}" - . "%areturn %s;", - $magicIsset->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicUnset::__construct - */ - public function testBodyStructureWithPublicProperties() - { - $reflection = new ReflectionClass( - 'ProxyManagerTestAsset\\ProxyGenerator\\LazyLoading\\MethodGenerator\\ClassWithTwoPublicProperties' - ); - - $magicIsset = new MagicUnset($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__unset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->baz('__unset', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n unset(\$this->\$name);\n\n return;\n}" - . "%areturn %s;", - $magicIsset->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicUnset::__construct - */ - public function testBodyStructureWithOverriddenMagicGet() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMagicMethods'); - $magicIsset = new MagicUnset($reflection, $this->initializer, $this->initMethod, $this->publicProperties); - - $this->assertSame('__unset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertSame( - "\$this->foo && \$this->baz('__unset', array('name' => \$name));\n\n" - . "if (isset(self::\$bar[\$name])) {\n unset(\$this->\$name);\n\n return;\n}\n\n" - . "return parent::__unset(\$name);", - $magicIsset->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/SetProxyInitializerTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/SetProxyInitializerTest.php deleted file mode 100644 index 71fcdbf..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/SetProxyInitializerTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class SetProxyInitializerTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\SetProxyInitializer::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $setter = new SetProxyInitializer($initializer); - $parameters = $setter->getParameters(); - - $this->assertSame('setProxyInitializer', $setter->getName()); - $this->assertCount(1, $parameters); - - /* @var $initializer \ProxyManager\Generator\ParameterGenerator */ - $initializer = array_shift($parameters); - - $this->assertInstanceOf('ProxyManager\\Generator\\ParameterGenerator', $initializer); - $this->assertSame('initializer', $initializer->getName()); - $this->assertSame('$this->foo = $initializer;', $setter->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializationTrackerTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializationTrackerTest.php deleted file mode 100644 index 62caf49..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializationTrackerTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializationTracker - * @group Coverage - */ -class InitializationTrackerTest extends AbstractUniquePropertyNameTest -{ - /** - * {@inheritDoc} - */ - protected function createProperty() - { - return new InitializationTracker(); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializerPropertyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializerPropertyTest.php deleted file mode 100644 index c5f1ea1..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializerPropertyTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializerProperty - * @group Coverage - */ -class InitializerPropertyTest extends AbstractUniquePropertyNameTest -{ - /** - * {@inheritDoc} - */ - protected function createProperty() - { - return new InitializerProperty(); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhostGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhostGeneratorTest.php deleted file mode 100644 index 8eb5443..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhostGeneratorTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhostGenerator - * @group Coverage - */ -class LazyLoadingGhostGeneratorTest extends AbstractProxyGeneratorTest -{ - /** - * {@inheritDoc} - */ - protected function getProxyGenerator() - { - return new LazyLoadingGhostGenerator(); - } - - /** - * {@inheritDoc} - */ - protected function getExpectedImplementedInterfaces() - { - return array('ProxyManager\\Proxy\\GhostObjectInterface'); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/GetProxyInitializerTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/GetProxyInitializerTest.php deleted file mode 100644 index 31fd029..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/GetProxyInitializerTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class GetProxyInitializerTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\GetProxyInitializer::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $getter = new GetProxyInitializer($initializer); - - $this->assertSame('getProxyInitializer', $getter->getName()); - $this->assertCount(0, $getter->getParameters()); - $this->assertSame('return $this->foo;', $getter->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/InitializeProxyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/InitializeProxyTest.php deleted file mode 100644 index dfbcb4c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/InitializeProxyTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class InitializeProxyTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\InitializeProxy::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $initializeProxy = new InitializeProxy($initializer, $valueHolder); - - $this->assertSame('initializeProxy', $initializeProxy->getName()); - $this->assertCount(0, $initializeProxy->getParameters()); - $this->assertSame( - 'return $this->foo && $this->foo->__invoke($this->bar, $this, \'initializeProxy\', array(), $this->foo);', - $initializeProxy->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/IsProxyInitializedTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/IsProxyInitializedTest.php deleted file mode 100644 index 2b65f28..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/IsProxyInitializedTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class IsProxyInitializedTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\IsProxyInitialized::__construct - */ - public function testBodyStructure() - { - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $isProxyInitialized = new IsProxyInitialized($valueHolder); - - $this->assertSame('isProxyInitialized', $isProxyInitialized->getName()); - $this->assertCount(0, $isProxyInitialized->getParameters()); - $this->assertSame('return null !== $this->bar;', $isProxyInitialized->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/LazyLoadingMethodInterceptorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/LazyLoadingMethodInterceptorTest.php deleted file mode 100644 index f6f5d0c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/LazyLoadingMethodInterceptorTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class LazyLoadingMethodInterceptorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\LazyLoadingMethodInterceptor - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $reflection = new MethodReflection('ProxyManagerTestAsset\\BaseClass', 'publicByReferenceParameterMethod'); - $method = LazyLoadingMethodInterceptor::generateMethod($reflection, $initializer, $valueHolder); - - $this->assertSame('publicByReferenceParameterMethod', $method->getName()); - $this->assertCount(2, $method->getParameters()); - $this->assertSame( - "\$this->foo && \$this->foo->__invoke(\$this->bar, \$this, 'publicByReferenceParameterMethod', " - . "array('param' => \$param, 'byRefParam' => \$byRefParam), \$this->foo);\n\n" - . "return \$this->bar->publicByReferenceParameterMethod(\$param, \$byRefParam);", - $method->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\LazyLoadingMethodInterceptor - */ - public function testBodyStructureWithoutParameters() - { - $reflectionMethod = new MethodReflection(__CLASS__, 'testBodyStructureWithoutParameters'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $method = LazyLoadingMethodInterceptor::generateMethod($reflectionMethod, $initializer, $valueHolder); - - $this->assertSame('testBodyStructureWithoutParameters', $method->getName()); - $this->assertCount(0, $method->getParameters()); - $this->assertSame( - "\$this->foo && \$this->foo->__invoke(\$this->bar, \$this, " - . "'testBodyStructureWithoutParameters', array(), \$this->foo);\n\n" - . "return \$this->bar->testBodyStructureWithoutParameters();", - $method->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicCloneTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicCloneTest.php deleted file mode 100644 index dea429c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicCloneTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicCloneTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\MagicClone::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicClone = new MagicClone($reflection, $initializer, $valueHolder); - - $this->assertSame('__clone', $magicClone->getName()); - $this->assertCount(0, $magicClone->getParameters()); - $this->assertSame( - "\$this->foo && \$this->foo->__invoke(\$this->bar, \$this, " - . "'__clone', array(), \$this->foo);\n\n\$this->bar = clone \$this->bar;", - $magicClone->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicGetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicGetTest.php deleted file mode 100644 index bc3a61c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicGetTest.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicGetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\MagicGet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - $publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicGet = new MagicGet($reflection, $initializer, $valueHolder, $publicProperties); - - $this->assertSame('__get', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->foo->__invoke(\$this->bar, \$this, '__get', array('name' => \$name)" - . ", \$this->foo);\n\n" - . "if (isset(self::\$bar[\$name])) {\n return \$this->bar->\$name;\n}" - . "%areturn %s;", - $magicGet->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicIssetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicIssetTest.php deleted file mode 100644 index 751840d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicIssetTest.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicIssetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\MagicIsset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - $publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicIsset = new MagicIsset($reflection, $initializer, $valueHolder, $publicProperties); - - $this->assertSame('__isset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->foo->__invoke(\$this->bar, \$this, '__isset', array('name' => \$name)" - . ", \$this->foo);\n\n" - . "if (isset(self::\$bar[\$name])) {\n return isset(\$this->bar->\$name);\n}" - . "%areturn %s;", - $magicIsset->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSetTest.php deleted file mode 100644 index dba5b49..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSetTest.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\MagicSet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - $publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicSet = new MagicSet($reflection, $initializer, $valueHolder, $publicProperties); - - $this->assertSame('__set', $magicSet->getName()); - $this->assertCount(2, $magicSet->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->foo->__invoke(\$this->bar, \$this, " - . "'__set', array('name' => \$name, 'value' => \$value), \$this->foo);\n\n" - . "if (isset(self::\$bar[\$name])) {\n return (\$this->bar->\$name = \$value);\n}" - . "%areturn %s;", - $magicSet->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSleepTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSleepTest.php deleted file mode 100644 index 978eeb7..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSleepTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSleepTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\MagicSleep::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicSleep = new MagicSleep($reflection, $initializer, $valueHolder); - - $this->assertSame('__sleep', $magicSleep->getName()); - $this->assertCount(0, $magicSleep->getParameters()); - $this->assertSame( - "\$this->foo && \$this->foo->__invoke(\$this->bar, \$this, '__sleep', array(), \$this->foo);" - . "\n\nreturn array('bar');", - $magicSleep->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicUnsetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicUnsetTest.php deleted file mode 100644 index e94ee3b..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicUnsetTest.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicUnsetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\MagicUnset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $publicProperties = $this - ->getMockBuilder('ProxyManager\\ProxyGenerator\\PropertyGenerator\\PublicPropertiesMap') - ->disableOriginalConstructor() - ->getMock(); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - $publicProperties->expects($this->any())->method('isEmpty')->will($this->returnValue(false)); - $publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicIsset = new MagicUnset($reflection, $initializer, $valueHolder, $publicProperties); - - $this->assertSame('__unset', $magicIsset->getName()); - $this->assertCount(1, $magicIsset->getParameters()); - $this->assertStringMatchesFormat( - "\$this->foo && \$this->foo->__invoke(\$this->bar, \$this, '__unset', array('name' => \$name)" - . ", \$this->foo);\n\n" - . "if (isset(self::\$bar[\$name])) {\n unset(\$this->bar->\$name);\n\n return;\n}" - . "%areturn %s;", - $magicIsset->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/SetProxyInitializerTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/SetProxyInitializerTest.php deleted file mode 100644 index d70bf2c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/SetProxyInitializerTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class SetProxyInitializerTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator\SetProxyInitializer::__construct - */ - public function testBodyStructure() - { - $initializer = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $setter = new SetProxyInitializer($initializer); - $parameters = $setter->getParameters(); - - $this->assertSame('setProxyInitializer', $setter->getName()); - $this->assertCount(1, $parameters); - - /* @var $initializer \ProxyManager\Generator\ParameterGenerator */ - $initializer = array_shift($parameters); - - $this->assertInstanceOf('ProxyManager\\Generator\\ParameterGenerator', $initializer); - $this->assertSame('initializer', $initializer->getName()); - $this->assertSame('$this->foo = $initializer;', $setter->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/InitializerPropertyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/InitializerPropertyTest.php deleted file mode 100644 index c292e20..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/InitializerPropertyTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\PropertyGenerator\InitializerProperty - * @group Coverage - */ -class InitializerPropertyTest extends AbstractUniquePropertyNameTest -{ - /** - * {@inheritDoc} - */ - protected function createProperty() - { - return new InitializerProperty(); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/ValueHolderPropertyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/ValueHolderPropertyTest.php deleted file mode 100644 index 63a16a7..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/ValueHolderPropertyTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolder\PropertyGenerator\ValueHolderProperty - * @group Coverage - */ -class ValueHolderPropertyTest extends AbstractUniquePropertyNameTest -{ - /** - * {@inheritDoc} - */ - protected function createProperty() - { - return new ValueHolderProperty(); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolderGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolderGeneratorTest.php deleted file mode 100644 index 683e2c9..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingValueHolderGeneratorTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator - * @group Coverage - */ -class LazyLoadingValueHolderGeneratorTest extends AbstractProxyGeneratorTest -{ - /** - * {@inheritDoc} - */ - protected function getProxyGenerator() - { - return new LazyLoadingValueHolderGenerator(); - } - - /** - * {@inheritDoc} - */ - protected function getExpectedImplementedInterfaces() - { - return array('ProxyManager\\Proxy\\VirtualProxyInterface'); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObject/MethodGenerator/ConstructorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObject/MethodGenerator/ConstructorTest.php deleted file mode 100644 index 7fad56d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObject/MethodGenerator/ConstructorTest.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ConstructorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\NullObject\MethodGenerator\Constructor::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMixedProperties'); - $constructor = new Constructor($reflection); - - $this->assertSame('__construct', $constructor->getName()); - $this->assertCount(0, $constructor->getParameters()); - $this->assertSame( - "\$this->publicProperty0 = null;\n\$this->publicProperty1 = null;\n\$this->publicProperty2 = null;", - $constructor->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\NullObject\MethodGenerator\Constructor::__construct - */ - public function testBodyStructureWithoutPublicProperties() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithPrivateProperties'); - $constructor = new Constructor($reflection); - - $this->assertSame('__construct', $constructor->getName()); - $this->assertCount(0, $constructor->getParameters()); - $body = $constructor->getBody(); - $this->assertTrue(empty($body)); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObject/MethodGenerator/NullObjectMethodInterceptorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObject/MethodGenerator/NullObjectMethodInterceptorTest.php deleted file mode 100644 index 31202a1..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObject/MethodGenerator/NullObjectMethodInterceptorTest.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class NullObjectMethodInterceptorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\NullObject\MethodGenerator\NullObjectMethodInterceptor - */ - public function testBodyStructure() - { - $reflection = new MethodReflection('ProxyManagerTestAsset\\BaseClass', 'publicByReferenceParameterMethod'); - $method = NullObjectMethodInterceptor::generateMethod($reflection); - - $this->assertSame('publicByReferenceParameterMethod', $method->getName()); - $this->assertCount(2, $method->getParameters()); - $this->assertSame("", $method->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\NullObject\MethodGenerator\NullObjectMethodInterceptor - */ - public function testBodyStructureWithoutParameters() - { - $reflectionMethod = new MethodReflection(__CLASS__, 'testBodyStructureWithoutParameters'); - - $method = NullObjectMethodInterceptor::generateMethod($reflectionMethod); - - $this->assertSame('testBodyStructureWithoutParameters', $method->getName()); - $this->assertCount(0, $method->getParameters()); - $this->assertSame("", $method->getBody()); - } - - /** - * @covers \ProxyManager\ProxyGenerator\NullObject\MethodGenerator\NullObjectMethodInterceptor - */ - public function testBodyStructureWithoutByRefReturn() - { - $reflectionMethod = new MethodReflection('ProxyManagerTestAsset\BaseClass', 'publicByReferenceMethod'); - - $method = NullObjectMethodInterceptor::generateMethod($reflectionMethod); - - $this->assertSame('publicByReferenceMethod', $method->getName()); - $this->assertCount(0, $method->getParameters()); - $this->assertStringMatchesFormat("\$ref%s = null;\nreturn \$ref%s;", $method->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObjectGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObjectGeneratorTest.php deleted file mode 100644 index 11a6cbd..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/NullObjectGeneratorTest.php +++ /dev/null @@ -1,113 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\NullObjectGenerator - * @group Coverage - */ -class NullObjectGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getTestedImplementations - * - * Verifies that generated code is valid and implements expected interfaces - */ - public function testGeneratesValidCode($className) - { - $generator = $this->getProxyGenerator(); - $generatedClassName = UniqueIdentifierGenerator::getIdentifier('AbstractProxyGeneratorTest'); - $generatedClass = new ClassGenerator($generatedClassName); - $originalClass = new ReflectionClass($className); - $generatorStrategy = new EvaluatingGeneratorStrategy(); - - $generator->generate($originalClass, $generatedClass); - $generatorStrategy->generate($generatedClass); - - $generatedReflection = new ReflectionClass($generatedClassName); - - if ($originalClass->isInterface()) { - $this->assertTrue($generatedReflection->implementsInterface($className)); - } - - $this->assertSame($generatedClassName, $generatedReflection->getName()); - - foreach ($this->getExpectedImplementedInterfaces() as $interface) { - $this->assertTrue($generatedReflection->implementsInterface($interface)); - } - - $proxyGenerated = new $generatedClassName(); - - foreach ($generatedReflection->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { - $this->assertNull($proxyGenerated->$property); - } - - /** @var \ReflectionMethod $method */ - foreach ($generatedReflection->getMethods(ReflectionProperty::IS_PUBLIC) as $method) { - if ($method->getNumberOfParameters() == 0) { - $this->assertNull(call_user_func(array($proxyGenerated, $method->getName()))); - } - } - } - - /** - * {@inheritDoc} - */ - protected function getProxyGenerator() - { - return new NullObjectGenerator(); - } - - /** - * {@inheritDoc} - */ - protected function getExpectedImplementedInterfaces() - { - return array( - 'ProxyManager\\Proxy\\NullObjectInterface', - ); - } - - /** - * @return array - */ - public function getTestedImplementations() - { - return array( - array('ProxyManagerTestAsset\\BaseClass'), - array('ProxyManagerTestAsset\\ClassWithMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithByRefMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithMixedProperties'), - array('ProxyManagerTestAsset\\BaseInterface'), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/AbstractUniquePropertyNameTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/AbstractUniquePropertyNameTest.php deleted file mode 100644 index f3cd8ad..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/AbstractUniquePropertyNameTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -abstract class AbstractUniquePropertyNameTest extends PHPUnit_Framework_TestCase -{ - /** - * Verifies that a given property name is unique across two different instantiations of the property - */ - public function testUniqueProperty() - { - $property1 = $this->createProperty(); - $property2 = $this->createProperty(); - - $this->assertSame($property1->getName(), $property1->getName()); - $this->assertNotEquals($property1->getName(), $property2->getName()); - } - - /** - * @return \Zend\Code\Generator\PropertyGenerator - */ - abstract protected function createProperty(); -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/PublicPropertiesDefaultsTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/PublicPropertiesDefaultsTest.php deleted file mode 100644 index c714675..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/PublicPropertiesDefaultsTest.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesDefaults - * @group Coverage - */ -class PublicPropertiesDefaultsTest extends PHPUnit_Framework_TestCase -{ - public function testEmptyClass() - { - $publicProperties = new PublicPropertiesDefaults(new ReflectionClass('ProxyManagerTestAsset\\EmptyClass')); - - $this->assertInternalType('array', $publicProperties->getDefaultValue()->getValue()); - $this->assertEmpty($publicProperties->getDefaultValue()->getValue()); - $this->assertTrue($publicProperties->isStatic()); - $this->assertSame(PublicPropertiesDefaults::VISIBILITY_PRIVATE, $publicProperties->getVisibility()); - } - - public function testClassWithPublicProperties() - { - $publicProperties = new PublicPropertiesDefaults( - new ReflectionClass('ProxyManagerTestAsset\\ClassWithPublicProperties') - ); - - $this->assertInternalType('array', $publicProperties->getDefaultValue()->getValue()); - $this->assertCount(10, $publicProperties->getDefaultValue()->getValue()); - $this->assertTrue($publicProperties->isStatic()); - $this->assertSame(PublicPropertiesDefaults::VISIBILITY_PRIVATE, $publicProperties->getVisibility()); - } - - public function testBaseClass() - { - $publicProperties = new PublicPropertiesDefaults( - new ReflectionClass('ProxyManagerTestAsset\\BaseClass') - ); - - $this->assertInternalType('array', $publicProperties->getDefaultValue()->getValue()); - $this->assertSame( - array('publicProperty' => 'publicPropertyDefault'), - $publicProperties->getDefaultValue()->getValue() - ); - $this->assertTrue($publicProperties->isStatic()); - $this->assertSame(PublicPropertiesDefaults::VISIBILITY_PRIVATE, $publicProperties->getVisibility()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/PublicPropertiesMapTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/PublicPropertiesMapTest.php deleted file mode 100644 index a916762..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/PropertyGenerator/PublicPropertiesMapTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap - * @group Coverage - */ -class PublicPropertiesMapTest extends PHPUnit_Framework_TestCase -{ - public function testEmptyClass() - { - $publicProperties = new PublicPropertiesMap(new ReflectionClass('ProxyManagerTestAsset\\EmptyClass')); - - $this->assertInternalType('array', $publicProperties->getDefaultValue()->getValue()); - $this->assertEmpty($publicProperties->getDefaultValue()->getValue()); - $this->assertTrue($publicProperties->isStatic()); - $this->assertSame('private', $publicProperties->getVisibility()); - $this->assertTrue($publicProperties->isEmpty()); - } - - public function testClassWithPublicProperties() - { - $publicProperties = new PublicPropertiesMap( - new ReflectionClass('ProxyManagerTestAsset\\ClassWithPublicProperties') - ); - - $this->assertInternalType('array', $publicProperties->getDefaultValue()->getValue()); - $this->assertCount(10, $publicProperties->getDefaultValue()->getValue()); - $this->assertTrue($publicProperties->isStatic()); - $this->assertSame('private', $publicProperties->getVisibility()); - $this->assertFalse($publicProperties->isEmpty()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/ConstructorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/ConstructorTest.php deleted file mode 100644 index f1c9da0..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/ConstructorTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class ConstructorTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\RemoteObject\MethodGenerator\Constructor::__construct - */ - public function testBodyStructure() - { - $adapter = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $adapter->expects($this->any())->method('getName')->will($this->returnValue('adapter')); - - $reflection = new ReflectionClass('ProxyManagerTestAsset\\ClassWithMixedProperties'); - $constructor = new Constructor($reflection, $adapter); - - $this->assertSame('__construct', $constructor->getName()); - $this->assertCount(1, $constructor->getParameters()); - $this->assertSame( - "\$this->adapter = \$adapter;\nunset(\$this->publicProperty0);" - . "\nunset(\$this->publicProperty1);\nunset(\$this->publicProperty2);", - $constructor->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicGetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicGetTest.php deleted file mode 100644 index 096a891..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicGetTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicGetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\RemoteObject\MethodGenerator\MagicGet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $adapter = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $adapter->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $magicGet = new MagicGet($reflection, $adapter); - - $this->assertSame('__get', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat( - '$return = $this->foo->call(\'ProxyManagerTestAsset\\\EmptyClass\', \'__get\', array($name));' - . "\n\nreturn \$return;", - $magicGet->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicIssetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicIssetTest.php deleted file mode 100644 index 23ba337..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicIssetTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicIssetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\RemoteObject\MethodGenerator\MagicIsset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $adapter = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $adapter->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $magicGet = new MagicIsset($reflection, $adapter); - - $this->assertSame('__isset', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat( - '$return = $this->foo->call(\'ProxyManagerTestAsset\\\EmptyClass\', \'__isset\', array($name));' - . "\n\nreturn \$return;", - $magicGet->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicSetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicSetTest.php deleted file mode 100644 index 6034b99..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicSetTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\RemoteObject\MethodGenerator\MagicSet::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $adapter = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $adapter->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $magicGet = new MagicSet($reflection, $adapter); - - $this->assertSame('__set', $magicGet->getName()); - $this->assertCount(2, $magicGet->getParameters()); - $this->assertStringMatchesFormat( - '$return = $this->foo->call(\'ProxyManagerTestAsset\\\EmptyClass\', \'__set\', array($name, $value));' - . "\n\nreturn \$return;", - $magicGet->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicUnsetTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicUnsetTest.php deleted file mode 100644 index a3f186f..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/MagicUnsetTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicUnsetTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\RemoteObject\MethodGenerator\MagicUnset::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $adapter = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $adapter->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $magicGet = new MagicUnset($reflection, $adapter); - - $this->assertSame('__unset', $magicGet->getName()); - $this->assertCount(1, $magicGet->getParameters()); - $this->assertStringMatchesFormat( - '$return = $this->foo->call(\'ProxyManagerTestAsset\\\EmptyClass\', \'__unset\', array($name));' - . "\n\nreturn \$return;", - $magicGet->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/RemoteObjectMethodTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/RemoteObjectMethodTest.php deleted file mode 100644 index 1c41a4f..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/MethodGenerator/RemoteObjectMethodTest.php +++ /dev/null @@ -1,116 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class RemoteObjectMethodTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\RemoteObject\MethodGenerator\RemoteObjectMethod - */ - public function testBodyStructureWithParameters() - { - $adapter = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $adapter->expects($this->any())->method('getName')->will($this->returnValue('adapter')); - - $reflectionMethod = new MethodReflection( - 'ProxyManagerTestAsset\\BaseClass', - 'publicByReferenceParameterMethod' - ); - - $method = RemoteObjectMethod::generateMethod( - $reflectionMethod, - $adapter, - new ReflectionClass('Zend\\Code\\Generator\\PropertyGenerator') - ); - - $this->assertSame('publicByReferenceParameterMethod', $method->getName()); - $this->assertCount(2, $method->getParameters()); - $this->assertSame( - '$return = $this->adapter->call(\'Zend\\\Code\\\Generator\\\PropertyGenerator\', ' - . '\'publicByReferenceParameterMethod\', array($param, $byRefParam));' - . "\n\nreturn \$return;", - $method->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\RemoteObject\MethodGenerator\RemoteObjectMethod - */ - public function testBodyStructureWithArrayParameter() - { - $adapter = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $adapter->expects($this->any())->method('getName')->will($this->returnValue('adapter')); - - $reflectionMethod = new MethodReflection('ProxyManagerTestAsset\\BaseClass', 'publicArrayHintedMethod'); - - $method = RemoteObjectMethod::generateMethod( - $reflectionMethod, - $adapter, - new ReflectionClass('Zend\\Code\\Generator\\PropertyGenerator') - ); - - $this->assertSame('publicArrayHintedMethod', $method->getName()); - $this->assertCount(1, $method->getParameters()); - $this->assertSame( - '$return = $this->adapter->call(\'Zend\\\Code\\\Generator\\\PropertyGenerator\', ' - . '\'publicArrayHintedMethod\', array($param));' - . "\n\nreturn \$return;", - $method->getBody() - ); - } - - /** - * @covers \ProxyManager\ProxyGenerator\RemoteObject\MethodGenerator\RemoteObjectMethod - */ - public function testBodyStructureWithoutParameters() - { - $adapter = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - $adapter->expects($this->any())->method('getName')->will($this->returnValue('adapter')); - - $reflectionMethod = new MethodReflection(__CLASS__, 'testBodyStructureWithoutParameters'); - - $method = RemoteObjectMethod::generateMethod( - $reflectionMethod, - $adapter, - new ReflectionClass('Zend\\Code\\Generator\\PropertyGenerator') - ); - - $this->assertSame('testBodyStructureWithoutParameters', $method->getName()); - $this->assertCount(0, $method->getParameters()); - $this->assertSame( - '$return = $this->adapter->call(\'Zend\\\Code\\\Generator\\\PropertyGenerator\', ' - . '\'testBodyStructureWithoutParameters\', array());' - . "\n\nreturn \$return;", - $method->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/PropertyGenerator/AdapterPropertyTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/PropertyGenerator/AdapterPropertyTest.php deleted file mode 100644 index d7e9cc9..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObject/PropertyGenerator/AdapterPropertyTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\RemoteObject\PropertyGenerator\AdapterProperty - * @group Coverage - */ -class AdapterPropertyTest extends AbstractUniquePropertyNameTest -{ - /** - * {@inheritDoc} - */ - protected function createProperty() - { - return new AdapterProperty(); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObjectGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObjectGeneratorTest.php deleted file mode 100644 index 961c226..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/RemoteObjectGeneratorTest.php +++ /dev/null @@ -1,103 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\RemoteObjectGenerator - * @group Coverage - */ -class RemoteObjectGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getTestedImplementations - * - * Verifies that generated code is valid and implements expected interfaces - */ - public function testGeneratesValidCode($className) - { - $generator = $this->getProxyGenerator(); - $generatedClassName = UniqueIdentifierGenerator::getIdentifier('AbstractProxyGeneratorTest'); - $generatedClass = new ClassGenerator($generatedClassName); - $originalClass = new ReflectionClass($className); - $generatorStrategy = new EvaluatingGeneratorStrategy(); - - $generator->generate($originalClass, $generatedClass); - $generatorStrategy->generate($generatedClass); - - $generatedReflection = new ReflectionClass($generatedClassName); - - if ($originalClass->isInterface()) { - $this->assertTrue($generatedReflection->implementsInterface($className)); - } else { - $this->assertEmpty( - array_diff($originalClass->getInterfaceNames(), $generatedReflection->getInterfaceNames()) - ); - } - - $this->assertSame($generatedClassName, $generatedReflection->getName()); - - foreach ($this->getExpectedImplementedInterfaces() as $interface) { - $this->assertTrue($generatedReflection->implementsInterface($interface)); - } - } - - /** - * {@inheritDoc} - */ - protected function getProxyGenerator() - { - return new RemoteObjectGenerator(); - } - - /** - * {@inheritDoc} - */ - protected function getExpectedImplementedInterfaces() - { - return array( - 'ProxyManager\\Proxy\\RemoteObjectInterface', - ); - } - - /** - * @return array - */ - public function getTestedImplementations() - { - return array( - array('ProxyManagerTestAsset\\BaseClass'), - array('ProxyManagerTestAsset\\ClassWithMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithByRefMagicMethods'), - array('ProxyManagerTestAsset\\ClassWithMixedProperties'), - array('ProxyManagerTestAsset\\BaseInterface'), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Util/ProxiedMethodsFilterTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Util/ProxiedMethodsFilterTest.php deleted file mode 100644 index 89bbb6a..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Util/ProxiedMethodsFilterTest.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\Util\ProxiedMethodsFilter - * @group Coverage - */ -class ProxiedMethodsFilterTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider expectedMethods - */ - public function testFiltering(ReflectionClass $reflectionClass, $excludes, array $expectedMethods) - { - if (is_array($excludes)) { - $filtered = ProxiedMethodsFilter::getProxiedMethods($reflectionClass, $excludes); - } else { - $filtered = ProxiedMethodsFilter::getProxiedMethods($reflectionClass); - } - - foreach ($filtered as $method) { - $this->assertInstanceOf('ReflectionMethod', $method); - } - - $keys = array_map( - function (ReflectionMethod $method) { - return $method->getName(); - }, - $filtered - ); - - sort($keys); - sort($expectedMethods); - - $this->assertSame($keys, $expectedMethods); - } - - /** - * @return array[][] - */ - public function expectedMethods() - { - return array( - array( - new ReflectionClass('ProxyManagerTestAsset\\BaseClass'), - null, - array( - 'publicArrayHintedMethod', - 'publicByReferenceMethod', - 'publicByReferenceParameterMethod', - 'publicMethod', - 'publicTypeHintedMethod', - ), - ), - array( - new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'), - null, - array(), - ), - array( - new ReflectionClass('ProxyManagerTestAsset\\LazyLoadingMock'), - null, - array(), - ), - array( - new ReflectionClass('ProxyManagerTestAsset\\LazyLoadingMock'), - array(), - array(), - ), - array( - new ReflectionClass('ProxyManagerTestAsset\\HydratedObject'), - array('doFoo'), - array('__get'), - ), - array( - new ReflectionClass('ProxyManagerTestAsset\\HydratedObject'), - array('Dofoo'), - array('__get'), - ), - array( - new ReflectionClass('ProxyManagerTestAsset\\HydratedObject'), - array(), - array('doFoo', '__get'), - ), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Util/PublicScopeSimulatorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Util/PublicScopeSimulatorTest.php deleted file mode 100644 index e5271ff..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/Util/PublicScopeSimulatorTest.php +++ /dev/null @@ -1,133 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\ProxyGenerator\Util\PublicScopeSimulator - * @group Coverage - */ -class PublicScopeSimulatorTest extends PHPUnit_Framework_TestCase -{ - public function testSimpleGet() - { - $code = PublicScopeSimulator::getPublicAccessSimulationCode( - PublicScopeSimulator::OPERATION_GET, - 'foo', - null, - null, - 'bar' - ); - - $this->assertStringMatchesFormat('%a{%areturn $%s->$foo;%a}%a$bar = %s;', $code); - } - - public function testSimpleSet() - { - $code = PublicScopeSimulator::getPublicAccessSimulationCode( - PublicScopeSimulator::OPERATION_SET, - 'foo', - 'baz', - null, - 'bar' - ); - - $this->assertStringMatchesFormat('%a{%areturn $%s->$foo = $baz;%a}%a$bar = %s;', $code); - } - - public function testSimpleIsset() - { - $code = PublicScopeSimulator::getPublicAccessSimulationCode( - PublicScopeSimulator::OPERATION_ISSET, - 'foo', - null, - null, - 'bar' - ); - - $this->assertStringMatchesFormat('%a{%areturn isset($%s->$foo);%a}%a$bar = %s;', $code); - } - - public function testSimpleUnset() - { - $code = PublicScopeSimulator::getPublicAccessSimulationCode( - PublicScopeSimulator::OPERATION_UNSET, - 'foo', - null, - null, - 'bar' - ); - - $this->assertStringMatchesFormat('%a{%aunset($%s->$foo);%a}%a$bar = %s;', $code); - } - - public function testSetRequiresValueParameterName() - { - $this->setExpectedException('InvalidArgumentException'); - - PublicScopeSimulator::getPublicAccessSimulationCode( - PublicScopeSimulator::OPERATION_SET, - 'foo', - null, - null, - 'bar' - ); - } - - public function testDelegatesToValueHolderWhenAvailable() - { - $code = PublicScopeSimulator::getPublicAccessSimulationCode( - PublicScopeSimulator::OPERATION_SET, - 'foo', - 'baz', - new PropertyGenerator('valueHolder'), - 'bar' - ); - - $this->assertStringMatchesFormat( - '%A$targetObject = $this->valueHolder;%a{%areturn $%s->$foo = $baz;%a}%a$bar = %s;', - $code - ); - } - - public function testSetRequiresValidOperation() - { - $this->setExpectedException('InvalidArgumentException'); - - PublicScopeSimulator::getPublicAccessSimulationCode('invalid', 'foo'); - } - - public function testWillReturnDirectlyWithNoReturnParam() - { - $code = PublicScopeSimulator::getPublicAccessSimulationCode( - PublicScopeSimulator::OPERATION_GET, - 'foo' - ); - - $this->assertStringMatchesFormat('%a{%areturn $%s->$foo;%a}%areturn %s;', $code); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/ValueHolder/MethodGenerator/GetWrappedValueHolderValueTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/ValueHolder/MethodGenerator/GetWrappedValueHolderValueTest.php deleted file mode 100644 index b7acb31..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/ValueHolder/MethodGenerator/GetWrappedValueHolderValueTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class GetWrappedValueHolderValueTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\ValueHolder\MethodGenerator\GetWrappedValueHolderValue::__construct - */ - public function testBodyStructure() - { - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('foo')); - - $getter = new GetWrappedValueHolderValue($valueHolder); - - $this->assertSame('getWrappedValueHolderValue', $getter->getName()); - $this->assertCount(0, $getter->getParameters()); - $this->assertSame('return $this->foo;', $getter->getBody()); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/ValueHolder/MethodGenerator/MagicSleepTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/ValueHolder/MethodGenerator/MagicSleepTest.php deleted file mode 100644 index f2b1596..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/ProxyGenerator/ValueHolder/MethodGenerator/MagicSleepTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license MIT - * - * @group Coverage - */ -class MagicSleepTest extends PHPUnit_Framework_TestCase -{ - /** - * @covers \ProxyManager\ProxyGenerator\ValueHolder\MethodGenerator\MagicSleep::__construct - */ - public function testBodyStructure() - { - $reflection = new ReflectionClass('ProxyManagerTestAsset\\EmptyClass'); - $valueHolder = $this->getMock('Zend\\Code\\Generator\\PropertyGenerator'); - - $valueHolder->expects($this->any())->method('getName')->will($this->returnValue('bar')); - - $magicSleep = new MagicSleep($reflection, $valueHolder); - - $this->assertSame('__sleep', $magicSleep->getName()); - $this->assertCount(0, $magicSleep->getParameters()); - $this->assertSame( - "return array('bar');", - $magicSleep->getBody() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/ClassSignatureGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/ClassSignatureGeneratorTest.php deleted file mode 100644 index 95ffbdd..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/ClassSignatureGeneratorTest.php +++ /dev/null @@ -1,87 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Signature\ClassSignatureGenerator - * @group Coverage - */ -class ClassSignatureGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @var \ProxyManager\Signature\SignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $signatureGenerator; - - /** - * @var ClassSignatureGenerator - */ - private $classSignatureGenerator; - - /** - * {@inheritDoc} - */ - protected function setUp() - { - $this->signatureGenerator = $this->getMock('ProxyManager\\Signature\\SignatureGeneratorInterface'); - $this->classSignatureGenerator = new ClassSignatureGenerator($this->signatureGenerator); - } - - public function testAddSignature() - { - /* @var $classGenerator \PHPUnit_Framework_MockObject_MockObject|\Zend\Code\Generator\ClassGenerator */ - $classGenerator = $this->getMock('Zend\\Code\\Generator\\ClassGenerator'); - - $classGenerator - ->expects($this->once()) - ->method('addPropertyFromGenerator') - ->with($this->callback(function (PropertyGenerator $property) { - return $property->getName() === 'signaturePropertyName' - && $property->isStatic() - && $property->getVisibility() === 'private' - && $property->getDefaultValue()->getValue() === 'valid-signature'; - })); - - $this - ->signatureGenerator - ->expects($this->any()) - ->method('generateSignature') - ->with(array('foo' => 'bar')) - ->will($this->returnValue('valid-signature')); - - $this - ->signatureGenerator - ->expects($this->any()) - ->method('generateSignatureKey') - ->with(array('foo' => 'bar')) - ->will($this->returnValue('PropertyName')); - - - $this->classSignatureGenerator->addSignature($classGenerator, array('foo' => 'bar')); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/Exception/InvalidSignatureExceptionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/Exception/InvalidSignatureExceptionTest.php deleted file mode 100644 index d587fc0..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/Exception/InvalidSignatureExceptionTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Signature\Exception\InvalidSignatureException - * @group Coverage - */ -class InvalidSignatureExceptionTest extends PHPUnit_Framework_TestCase -{ - public function testFromInvalidSignature() - { - $exception = InvalidSignatureException::fromInvalidSignature( - new ReflectionClass(__CLASS__), - array('foo' => 'bar', 'baz' => 'tab'), - 'blah', - 'expected-signature' - ); - - $this->assertInstanceOf( - 'ProxyManager\Signature\Exception\InvalidSignatureException', - $exception - ); - - $this->assertSame( - 'Found signature "blah" for class "' - . __CLASS__ - . '" does not correspond to expected signature "expected-signature" for 2 parameters', - $exception->getMessage() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/Exception/MissingSignatureExceptionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/Exception/MissingSignatureExceptionTest.php deleted file mode 100644 index 2d8a0d8..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/Exception/MissingSignatureExceptionTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Signature\Exception\MissingSignatureException - * @group Coverage - */ -class MissingSignatureExceptionTest extends PHPUnit_Framework_TestCase -{ - public function testFromMissingSignature() - { - $exception = MissingSignatureException::fromMissingSignature( - new ReflectionClass(__CLASS__), - array('foo' => 'bar', 'baz' => 'tab'), - 'expected-signature' - ); - - $this->assertInstanceOf( - 'ProxyManager\Signature\Exception\MissingSignatureException', - $exception - ); - - $this->assertSame( - 'No signature found for class "' - . __CLASS__ - . '", expected signature "expected-signature" for 2 parameters', - $exception->getMessage() - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/SignatureCheckerTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/SignatureCheckerTest.php deleted file mode 100644 index 0fa13f9..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/SignatureCheckerTest.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Signature\SignatureChecker - * @group Coverage - */ -class SignatureCheckerTest extends PHPUnit_Framework_TestCase -{ - /** - * @var string - */ - protected $signatureExample = 'valid-signature'; - - /** - * @var SignatureChecker - */ - private $signatureChecker; - - /** - * @var \ProxyManager\Signature\SignatureGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $signatureGenerator; - - /** - * {@inheritDoc} - */ - protected function setUp() - { - $this->signatureGenerator = $this->getMock('ProxyManager\Signature\SignatureGeneratorInterface'); - $this->signatureChecker = new SignatureChecker($this->signatureGenerator); - } - - public function testCheckSignatureWithValidKey() - { - $this - ->signatureGenerator - ->expects($this->atLeastOnce()) - ->method('generateSignatureKey') - ->with(array('foo' => 'bar')) - ->will($this->returnValue('Example')); - $this - ->signatureGenerator - ->expects($this->atLeastOnce()) - ->method('generateSignature') - ->with(array('foo' => 'bar')) - ->will($this->returnValue('valid-signature')); - - $this->signatureChecker->checkSignature(new ReflectionClass($this), array('foo' => 'bar')); - } - - public function testCheckSignatureWithInvalidKey() - { - $this - ->signatureGenerator - ->expects($this->any()) - ->method('generateSignatureKey') - ->with(array('foo' => 'bar')) - ->will($this->returnValue('InvalidKey')); - $this - ->signatureGenerator - ->expects($this->any()) - ->method('generateSignature') - ->with(array('foo' => 'bar')) - ->will($this->returnValue('valid-signature')); - - $this->setExpectedException('ProxyManager\Signature\Exception\MissingSignatureException'); - - $this->signatureChecker->checkSignature(new ReflectionClass($this), array('foo' => 'bar')); - } - - public function testCheckSignatureWithInvalidValue() - { - $this - ->signatureGenerator - ->expects($this->any()) - ->method('generateSignatureKey') - ->with(array('foo' => 'bar')) - ->will($this->returnValue('Example')); - $this - ->signatureGenerator - ->expects($this->any()) - ->method('generateSignature') - ->with(array('foo' => 'bar')) - ->will($this->returnValue('invalid-signature')); - - $this->setExpectedException('ProxyManager\Signature\Exception\InvalidSignatureException'); - - $this->signatureChecker->checkSignature(new ReflectionClass($this), array('foo' => 'bar')); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/SignatureGeneratorTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/SignatureGeneratorTest.php deleted file mode 100644 index 5ad93d6..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/Signature/SignatureGeneratorTest.php +++ /dev/null @@ -1,116 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Signature\SignatureGenerator - * @group Coverage - */ -class SignatureGeneratorTest extends PHPUnit_Framework_TestCase -{ - /** - * @var SignatureGenerator - */ - private $signatureGenerator; - - /** - * {@inheritDoc} - */ - protected function setUp() - { - $this->signatureGenerator = new SignatureGenerator; - } - - /** - * @param array $parameters - * @param string $expected - * - * @dataProvider signatures - */ - public function testGenerateSignature(array $parameters, $expected) - { - $this->assertSame($expected, $this->signatureGenerator->generateSignature($parameters)); - } - - /** - * @param array $parameters - * @param string $expected - * - * @dataProvider signatureKeys - */ - public function testGenerateSignatureKey(array $parameters, $expected) - { - $this->assertSame($expected, $this->signatureGenerator->generateSignatureKey($parameters)); - } - - /** - * Data provider. - * - * @return array[] - */ - public function signatures() - { - return array( - array( - array(), - 'YTowOnt9' - ), - array( - array('foo' => 'bar'), - 'YToxOntzOjM6ImZvbyI7czozOiJiYXIiO30=' - ), - array( - array('foo' => 'bar', 'baz' => 'tab'), - 'YToyOntzOjM6ImZvbyI7czozOiJiYXIiO3M6MzoiYmF6IjtzOjM6InRhYiI7fQ==' - ), - array( - array('bar'), - 'YToxOntpOjA7czozOiJiYXIiO30=' - ), - array( - array('bar', 'baz'), - 'YToyOntpOjA7czozOiJiYXIiO2k6MTtzOjM6ImJheiI7fQ==' - ), - ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function signatureKeys() - { - return array( - array(array(), '40cd750bba9870f18aada2478b24840a'), - array(array('foo' => 'bar'), '49a3696adf0fbfacc12383a2d7400d51'), - array(array('foo' => 'bar', 'baz' => 'tab'), '3f3cabbf33bae82b0711205c913a8fa0'), - array(array('bar'), '6fc5f617053f53f56b4734453ec86daa'), - array(array('bar', 'baz'), 'b9f31192ffbb4aa958cd1c5f88540c1e'), - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/VersionTest.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/VersionTest.php deleted file mode 100644 index 84f1261..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTest/VersionTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - * - * @covers \ProxyManager\Version - * @group Coverage - */ -class VersionTest extends PHPUnit_Framework_TestCase -{ - public function testVersionNumberIsSemverCompliant() - { - $this->assertRegExp( - '/\d+\.\d+\.\d+(-(ALPHA|BETA|RC(\d+)?|DEV))?/i', - Version::VERSION - ); - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/AccessInterceptorValueHolderMock.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/AccessInterceptorValueHolderMock.php deleted file mode 100644 index 8324d97..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/AccessInterceptorValueHolderMock.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @license MIT - */ -class AccessInterceptorValueHolderMock -{ - /** - * @var mixed - */ - public $instance; - - /** - * @var mixed - */ - public $prefixInterceptors; - - /** - * @var mixed - */ - public $suffixInterceptors; - - /** - * @param mixed $instance - * @param mixed $prefixInterceptors - * @param mixed $suffixInterceptors - */ - public function __construct($instance, $prefixInterceptors, $suffixInterceptors) - { - $this->instance = $instance; - $this->prefixInterceptors = $prefixInterceptors; - $this->suffixInterceptors = $suffixInterceptors; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/BaseClass.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/BaseClass.php deleted file mode 100644 index 4d58a11..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/BaseClass.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @license MIT - */ -class BaseClass implements BaseInterface -{ - /** - * @var string - */ - public $publicProperty = 'publicPropertyDefault'; - - /** - * @var string - */ - protected $protectedProperty = 'protectedPropertyDefault'; - - /** - * @var string - */ - private $privateProperty = 'privatePropertyDefault'; - - /** - * @return string - */ - public function publicMethod() - { - return 'publicMethodDefault'; - } - - /** - * @return string - */ - protected function protectedMethod() - { - return 'protectedMethodDefault'; - } - - /** - * @return string - */ - private function privateMethod() - { - return 'privateMethodDefault'; - } - - /** - * @param \stdClass $param - * - * @return string - */ - public function publicTypeHintedMethod(\stdClass $param) - { - return 'publicTypeHintedMethodDefault'; - } - - /** - * @param array $param - * - * @return string - */ - public function publicArrayHintedMethod(array $param) - { - return 'publicArrayHintedMethodDefault'; - } - - /** - * @return string - */ - public function & publicByReferenceMethod() - { - $returnValue = 'publicByReferenceMethodDefault'; - - return $returnValue; - } - - /** - * @param mixed $param - * @param mixed $byRefParam - * - * @return string - */ - public function publicByReferenceParameterMethod($param, & $byRefParam) - { - return 'publicByReferenceParameterMethodDefault'; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/BaseInterface.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/BaseInterface.php deleted file mode 100644 index 27aeda5..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/BaseInterface.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @license MIT - */ -interface BaseInterface -{ - /** - * @return string - */ - public function publicMethod(); -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/CallableTypeHintClass.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/CallableTypeHintClass.php deleted file mode 100644 index 4a65595..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/CallableTypeHintClass.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @license MIT - */ -class CallableTypeHintClass -{ - /** - * @param callable $parameter - * - * @return callable - */ - public function callableTypeHintMethod(callable $parameter) - { - return $parameter; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithAbstractProtectedMethod.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithAbstractProtectedMethod.php deleted file mode 100644 index 1ba3a5c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithAbstractProtectedMethod.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @license MIT - */ -abstract class ClassWithAbstractProtectedMethod -{ - /** - * @return void - */ - abstract protected function protectedAbstractMethod(); -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithByRefMagicMethods.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithByRefMagicMethods.php deleted file mode 100644 index 6f0ab5d..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithByRefMagicMethods.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @license MIT - */ -class ClassWithByRefMagicMethods -{ - /** - * {@inheritDoc} - */ - public function & __set($name, $value) - { - return array($name => $value); - } - - /** - * {@inheritDoc} - */ - public function & __get($name) - { - return $name; - } - - /** - * {@inheritDoc} - */ - public function & __isset($name) - { - return (bool) $name; - } - - /** - * {@inheritDoc} - */ - public function & __unset($name) - { - return (bool) $name; - } - - /** - * {@inheritDoc} - */ - public function & __sleep() - { - } - - /** - * {@inheritDoc} - */ - public function & __wakeup() - { - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithFinalMagicMethods.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithFinalMagicMethods.php deleted file mode 100644 index d42204b..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithFinalMagicMethods.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @license MIT - */ -class ClassWithFinalMagicMethods -{ - /** - * {@inheritDoc} - */ - final public function __construct() - { - } - - /** - * {@inheritDoc} - */ - final public function __set($name, $value) - { - return array($name => $value); - } - - /** - * {@inheritDoc} - */ - final public function __get($name) - { - return $name; - } - - /** - * {@inheritDoc} - */ - final public function __isset($name) - { - return (bool) $name; - } - - /** - * {@inheritDoc} - */ - final public function __unset($name) - { - return (bool) $name; - } - - /** - * {@inheritDoc} - */ - final public function __sleep() - { - } - - /** - * {@inheritDoc} - */ - final public function __wakeup() - { - } - - /** - * {@inheritDoc} - */ - final public function __clone() - { - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithFinalMethods.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithFinalMethods.php deleted file mode 100644 index a7c0154..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithFinalMethods.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @license MIT - */ -class ClassWithFinalMethods extends PHPUnit_Framework_TestCase -{ - final public function foo() - { - } - - final private function bar() - { - } - - final protected function baz() - { - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMagicMethods.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMagicMethods.php deleted file mode 100644 index 2bd26e5..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMagicMethods.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @license MIT - */ -class ClassWithMagicMethods -{ - /** - * {@inheritDoc} - */ - public function __set($name, $value) - { - return array($name => $value); - } - - /** - * {@inheritDoc} - */ - public function __get($name) - { - return $name; - } - - /** - * {@inheritDoc} - */ - public function __isset($name) - { - return (bool) $name; - } - - /** - * {@inheritDoc} - */ - public function __unset($name) - { - return (bool) $name; - } - - /** - * {@inheritDoc} - */ - public function __sleep() - { - } - - /** - * {@inheritDoc} - */ - public function __wakeup() - { - } - - /** - * {@inheritDoc} - */ - public function __clone() - { - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMethodWithDefaultParameters.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMethodWithDefaultParameters.php deleted file mode 100644 index fa6134a..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMethodWithDefaultParameters.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @license MIT - */ -class ClassWithMethodWithDefaultParameters -{ - /** - * @param array $parameter - * - * @return string - */ - public function publicMethodWithDefaults(array $parameter = array('foo')) - { - return 'defaultValue'; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMixedProperties.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMixedProperties.php deleted file mode 100644 index 3ebf27c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithMixedProperties.php +++ /dev/null @@ -1,46 +0,0 @@ - - * @license MIT - */ -class ClassWithMixedProperties -{ - public $publicProperty0 = 'publicProperty0'; - - public $publicProperty1 = 'publicProperty1'; - - public $publicProperty2 = 'publicProperty2'; - - protected $protectedProperty0 = 'protectedProperty0'; - - protected $protectedProperty1 = 'protectedProperty1'; - - protected $protectedProperty2 = 'protectedProperty2'; - - private $privateProperty0 = 'privateProperty0'; - - private $privateProperty1 = 'privateProperty1'; - - private $privateProperty2 = 'privateProperty2'; -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPrivateProperties.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPrivateProperties.php deleted file mode 100644 index 96a7a93..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPrivateProperties.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @license MIT - */ -class ClassWithPrivateProperties -{ - private $property0 = 'property0'; - - private $property1 = 'property1'; - - private $property2 = 'property2'; - - private $property3 = 'property3'; - - private $property4 = 'property4'; - - private $property5 = 'property5'; - - private $property6 = 'property6'; - - private $property7 = 'property7'; - - private $property8 = 'property8'; - - private $property9 = 'property9'; -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithProtectedProperties.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithProtectedProperties.php deleted file mode 100644 index ad600d1..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithProtectedProperties.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @license MIT - */ -class ClassWithProtectedProperties -{ - protected $property0 = 'property0'; - - protected $property1 = 'property1'; - - protected $property2 = 'property2'; - - protected $property3 = 'property3'; - - protected $property4 = 'property4'; - - protected $property5 = 'property5'; - - protected $property6 = 'property6'; - - protected $property7 = 'property7'; - - protected $property8 = 'property8'; - - protected $property9 = 'property9'; -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPublicArrayProperty.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPublicArrayProperty.php deleted file mode 100644 index af68ceb..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPublicArrayProperty.php +++ /dev/null @@ -1,31 +0,0 @@ - - * @license MIT - */ -class ClassWithPublicArrayProperty -{ - public $arrayProperty = array(); -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPublicProperties.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPublicProperties.php deleted file mode 100644 index d36ea8c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithPublicProperties.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @license MIT - */ -class ClassWithPublicProperties -{ - public $property0 = 'property0'; - - public $property1 = 'property1'; - - public $property2 = 'property2'; - - public $property3 = 'property3'; - - public $property4 = 'property4'; - - public $property5 = 'property5'; - - public $property6 = 'property6'; - - public $property7 = 'property7'; - - public $property8 = 'property8'; - - public $property9 = 'property9'; -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithSelfHint.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithSelfHint.php deleted file mode 100644 index 37d342c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ClassWithSelfHint.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @license MIT - */ -class ClassWithSelfHint -{ - /** - * @param self $parameter - * - * @return self - */ - public function selfHintMethod(self $parameter) - { - return $parameter; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/EmptyClass.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/EmptyClass.php deleted file mode 100644 index e74a0f7..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/EmptyClass.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @license MIT - */ -class EmptyClass -{ -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/FinalClass.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/FinalClass.php deleted file mode 100644 index 4b818d6..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/FinalClass.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @license MIT - */ -final class FinalClass -{ -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/HydratedObject.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/HydratedObject.php deleted file mode 100644 index 198bf6c..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/HydratedObject.php +++ /dev/null @@ -1,60 +0,0 @@ - - * @license MIT - */ -class HydratedObject -{ - /** - * @var mixed - */ - public $foo = 1; - - /** - * @var mixed - */ - protected $bar = 2; - - /** - * @var mixed - */ - private $baz = 3; - - /** - * Method to be disabled - */ - public function doFoo() - { - } - - /** - * @param string $name - * - * @return mixed - */ - public function __get($name) - { - return $this->$name; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/LazyLoadingMock.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/LazyLoadingMock.php deleted file mode 100644 index b199f8f..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/LazyLoadingMock.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @license MIT - */ -class LazyLoadingMock -{ - /** - * @var mixed - */ - public $initializer; - - /** - * @param mixed $initializer - */ - public function __construct($initializer) - { - $this->initializer = $initializer; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/NullObjectMock.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/NullObjectMock.php deleted file mode 100644 index b747f3b..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/NullObjectMock.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @license MIT - */ -class NullObjectMock -{ -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ProxyGenerator/LazyLoading/MethodGenerator/ClassWithTwoPublicProperties.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ProxyGenerator/LazyLoading/MethodGenerator/ClassWithTwoPublicProperties.php deleted file mode 100644 index bb34b58..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/ProxyGenerator/LazyLoading/MethodGenerator/ClassWithTwoPublicProperties.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @license MIT - */ -class ClassWithTwoPublicProperties -{ - /** - * @var mixed - */ - public $bar; - - /** - * @var mixed - */ - public $baz; -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/BazServiceInterface.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/BazServiceInterface.php deleted file mode 100644 index 08df058..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/BazServiceInterface.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @license MIT - */ -interface BazServiceInterface -{ - /** - * @param string $param - * - * @return string - */ - public function baz($param); -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/Foo.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/Foo.php deleted file mode 100644 index 9304f70..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/Foo.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @license MIT - */ -class Foo implements FooServiceInterface, BazServiceInterface -{ - /** - * @return string - */ - public function foo() - { - return 'bar remote'; - } - - /** - * @param string $param - * - * @return string - */ - public function baz($param) - { - return $param . ' remote'; - } - - /** - * @param string $name - * - * @return string - */ - public function __get($name) - { - return $name . ' remote'; - } -} diff --git a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/FooServiceInterface.php b/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/FooServiceInterface.php deleted file mode 100644 index af0b764..0000000 --- a/vendor/ocramius/proxy-manager/tests/ProxyManagerTestAsset/RemoteProxy/FooServiceInterface.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @license MIT - */ -interface FooServiceInterface -{ - /** - * @return string - */ - public function foo(); -} diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/README.md b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/README.md deleted file mode 100644 index f641e6d..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## Integration tests for PHP language features of proxies - -Since proxies are quire complex code, this directory is dedicated -to integration tests that are supposed to cause fatal errors or -failures in general that are hard to handle in traditional -PHPUnit test cases. - -You may find a guide on how to write `.phpt` tests on the -[PHP QA website](http://qa.php.net/write-test.php). \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-isset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-isset.phpt deleted file mode 100644 index b820fa1..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-isset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow private property direct isset check ---FILE-- -createProxy(new Kitchen()); - -var_dump(isset($proxy->sweets)); -?> ---EXPECT-- -bool(false) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-read.phpt deleted file mode 100644 index 0dff2c7..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-read.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow private property direct read ---FILE-- -createProxy(new Kitchen()); - -$proxy->sweets; -?> ---EXPECTF-- -%SFatal error: Cannot access private property %s::$sweets in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-unset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-unset.phpt deleted file mode 100644 index e6e6eeb..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-unset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow private property direct unset ---FILE-- -createProxy(new Kitchen()); - -unset($proxy->sweets); -?> ---EXPECTF-- -%SFatal error: Cannot %s property %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-write.phpt deleted file mode 100644 index e87d520..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-private-property-write.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow private property direct write ---FILE-- -createProxy(new Kitchen()); - -$proxy->sweets = 'stolen'; -?> ---EXPECTF-- -%SFatal error: Cannot access %s property%S in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-isset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-isset.phpt deleted file mode 100644 index e277887..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-isset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow protected property direct isset check ---FILE-- -createProxy(new Kitchen()); - -var_dump(isset($proxy->sweets)); -?> ---EXPECT-- -bool(false) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-read.phpt deleted file mode 100644 index ed579f5..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-read.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow protected property direct read ---FILE-- -createProxy(new Kitchen()); - -$proxy->sweets; -?> ---EXPECTF-- -%SFatal error: Cannot access protected property %s::$sweets in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-unset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-unset.phpt deleted file mode 100644 index d8fcd49..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-unset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow protected property direct unset ---FILE-- -createProxy(new Kitchen()); - -unset($proxy->sweets); -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-write.phpt deleted file mode 100644 index f288b0b..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-denies-protected-property-write.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow protected property direct write ---FILE-- -createProxy(new Kitchen()); - -$proxy->sweets = 'stolen'; -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-isset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-isset.phpt deleted file mode 100644 index d9eef67..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-isset.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow private property direct isset check ---SKIPIF-- - ---FILE-- -createProxy(new Kitchen()); - -var_dump(isset($proxy->sweets)); -?> ---EXPECT-- -bool(false) diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-read.phpt deleted file mode 100644 index 18a6c95..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-read.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow private property direct read ---SKIPIF-- - ---FILE-- -createProxy(new Kitchen()); - -$proxy->sweets; -?> ---EXPECTF-- -%SFatal error: Cannot access private property %s::$sweets in %s on line %d diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-unset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-unset.phpt deleted file mode 100644 index 92a64e2..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-unset.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow private property direct unset ---SKIPIF-- - ---FILE-- -createProxy(new Kitchen()); - -unset($proxy->sweets); -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-write.phpt deleted file mode 100644 index a0b3cc1..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-private-property-write.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow private property direct write ---SKIPIF-- - ---FILE-- -createProxy(new Kitchen()); - -$proxy->sweets = 'stolen'; -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-isset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-isset.phpt deleted file mode 100644 index f5de693..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-isset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow protected property direct isset check ---FILE-- -createProxy(new Kitchen()); - -var_dump(isset($proxy->sweets)); -?> ---EXPECT-- -bool(false) diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-read.phpt deleted file mode 100644 index c97b091..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-read.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow protected property direct read ---FILE-- -createProxy(new Kitchen()); - -$proxy->sweets; -?> ---EXPECTF-- -%SFatal error: Cannot access protected property %s::$sweets in %s on line %d diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-unset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-unset.phpt deleted file mode 100644 index 91cc4f9..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-unset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow protected property direct unset ---FILE-- -createProxy(new Kitchen()); - -unset($proxy->sweets); -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-write.phpt deleted file mode 100644 index 97da739..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-scope-localizer-denies-protected-property-write.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated access interceptors disallow protected property direct write ---FILE-- -createProxy(new Kitchen()); - -$proxy->sweets = 'stolen'; -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-with-cache.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-with-cache.phpt deleted file mode 100644 index 0a180b2..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/access-interceptor-with-cache.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -Verifies that access interceptor proxy file is generated ---FILE-- -setProxiesTargetDir(__DIR__ . '/cache'); -$fileLocator = new \ProxyManager\FileLocator\FileLocator($configuration->getProxiesTargetDir()); -$configuration->setGeneratorStrategy( - new \ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy($fileLocator) -); - -$factory = new \ProxyManager\Factory\AccessInterceptorValueHolderFactory($configuration); - -$proxy = $factory->createProxy(new Kitchen()); - -$filename = $fileLocator->getProxyFileName(get_class($proxy)); -var_dump(file_exists($filename)); - -$proxy = $factory->createProxy(new Kitchen()); - -var_dump(file_exists($filename)); -@unlink($filename); - -?> ---EXPECT-- -bool(true) -bool(true) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/cache/README.md b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/cache/README.md deleted file mode 100644 index dcb0d38..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/cache/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Integration tests for PHP language features of proxies - -This folder is used for the caches \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/init.php b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/init.php deleted file mode 100644 index ce6cffc..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/init.php +++ /dev/null @@ -1,10 +0,0 @@ -setGeneratorStrategy(new EvaluatingGeneratorStrategy()); diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-allows-inexisting-magic-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-allows-inexisting-magic-property-read.phpt deleted file mode 100644 index 2f318c7..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-allows-inexisting-magic-property-read.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow reading non-existing properties via direct read ---FILE-- -createProxy('Kitchen', function () {}); - -echo $proxy->nonExisting; -?> ---EXPECTF-- -nonExisting \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-allows-inexisting-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-allows-inexisting-property-write.phpt deleted file mode 100644 index e815d0f..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-allows-inexisting-property-write.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow reading non-existing properties via direct read ---FILE-- -createProxy('Kitchen', function () {}); - -$proxy->nonExisting = 'I do not exist'; -echo $proxy->nonExisting; -?> ---EXPECTF-- -I do not exist \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-inexisting-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-inexisting-property-read.phpt deleted file mode 100644 index 0b0267b..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-inexisting-property-read.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow reading non-existing properties via direct read ---FILE-- -createProxy('Kitchen', function () {}); - -$proxy->nonExisting; -?> ---EXPECTF-- -%SNotice: Undefined property: Kitchen::$nonExisting in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-isset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-isset.phpt deleted file mode 100644 index 05f741c..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-isset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow private property direct isset check ---FILE-- -createProxy('Kitchen', function () {}); - -var_dump(isset($proxy->sweets)); -?> ---EXPECT-- -bool(false) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-read.phpt deleted file mode 100644 index cdb0d09..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-read.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow private property direct read ---FILE-- -createProxy('Kitchen', function () {}); - -$proxy->sweets; -?> ---EXPECTF-- -%SFatal error: Cannot access private property %s::$sweets in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-unset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-unset.phpt deleted file mode 100644 index 18580aa..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-unset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow private property direct unset ---FILE-- -createProxy('Kitchen', function () {}); - -unset($proxy->sweets); -?> ---EXPECTF-- -%SFatal error: Cannot %s property %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-write.phpt deleted file mode 100644 index a081d71..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-private-property-write.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow private property direct write ---FILE-- -createProxy('Kitchen', function () {}); - -$proxy->sweets = 'stolen'; -?> ---EXPECTF-- -%SFatal error: Cannot access %s property%S in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-isset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-isset.phpt deleted file mode 100644 index 8fa8485..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-isset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow protected property direct isset check ---FILE-- -createProxy('Kitchen', function () {}); - -var_dump(isset($proxy->sweets)); -?> ---EXPECT-- -bool(false) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-read.phpt deleted file mode 100644 index e71bb30..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-read.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow protected property direct read ---FILE-- -createProxy('Kitchen', function () {}); - -$proxy->sweets; -?> ---EXPECTF-- -%SFatal error: Cannot access protected property %s::$sweets in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-unset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-unset.phpt deleted file mode 100644 index 6e742a1..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-unset.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow protected property direct unset ---FILE-- -createProxy('Kitchen', function () {}); - -unset($proxy->sweets); -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-write.phpt deleted file mode 100644 index 580f5a5..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-denies-protected-property-write.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated lazy loading ghost objects disallow protected property direct write ---FILE-- -createProxy('Kitchen', function () {}); - -$proxy->sweets = 'stolen'; -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-with-cache.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-with-cache.phpt deleted file mode 100644 index 7a60948..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-ghost-with-cache.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -Verifies that lazy loading ghost proxy file is generated ---FILE-- -setProxiesTargetDir(__DIR__ . '/cache'); -$fileLocator = new \ProxyManager\FileLocator\FileLocator($configuration->getProxiesTargetDir()); -$configuration->setGeneratorStrategy( - new \ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy($fileLocator) -); - -$factory = new \ProxyManager\Factory\LazyLoadingGhostFactory($configuration); - -$proxy = $factory->createProxy('Kitchen', function () {}); - -$filename = $fileLocator->getProxyFileName(get_class($proxy)); -var_dump(file_exists($filename)); - -$proxy = $factory->createProxy('Kitchen', function () {}); - -var_dump(file_exists($filename)); -@unlink($filename); - -?> ---EXPECT-- -bool(true) -bool(true) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-isset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-isset.phpt deleted file mode 100644 index 14e7989..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-isset.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated lazy loading value holders disallow private property direct isset check ---FILE-- -createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -var_dump(isset($proxy->sweets)); -?> ---EXPECT-- -bool(false) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-read.phpt deleted file mode 100644 index 7631ec9..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-read.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated lazy loading value holders disallow private property direct read ---FILE-- -createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -$proxy->sweets; -?> ---EXPECTF-- -%SFatal error: Cannot access private property %s::$sweets in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-unset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-unset.phpt deleted file mode 100644 index 1454f78..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-unset.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated lazy loading value holders disallow private property direct unset ---FILE-- -createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -unset($proxy->sweets); -?> ---EXPECTF-- -%SFatal error: Cannot %s property %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-write.phpt deleted file mode 100644 index 6b90e2f..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-private-property-write.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated lazy loading value holders disallow private property direct write ---FILE-- -createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -$proxy->sweets = 'stolen'; -?> ---EXPECTF-- -%SFatal error: Cannot access %s property %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-isset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-isset.phpt deleted file mode 100644 index d33c0ba..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-isset.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated lazy loading value holders disallow protected property direct isset check ---FILE-- -createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -var_dump(isset($proxy->sweets)); -?> ---EXPECT-- -bool(false) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-read.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-read.phpt deleted file mode 100644 index 6f2df1d..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-read.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated lazy loading value holders disallow protected property direct read ---FILE-- -createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -$proxy->sweets; -?> ---EXPECTF-- -%SFatal error: Cannot access protected property %s::$sweets in %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-unset.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-unset.phpt deleted file mode 100644 index 238a50f..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-unset.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated lazy loading value holders disallow protected property direct unset ---FILE-- -createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -unset($proxy->sweets); -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-write.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-write.phpt deleted file mode 100644 index f8c2cac..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-denies-protected-property-write.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated lazy loading value holders disallow protected property direct write ---FILE-- -createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -$proxy->sweets = 'stolen'; -?> ---EXPECTF-- -%SFatal error: Cannot %s property%sin %s on line %d \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-internal-php-classes.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-internal-php-classes.phpt deleted file mode 100644 index 2a5a777..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-internal-php-classes.phpt +++ /dev/null @@ -1,31 +0,0 @@ ---TEST-- -Verifies that lazy loading value holder factory can generate proxy for PHP core classes. ---FILE-- -createProxy('Phar', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new PharMock(); - }) - ->compress('Lazy Loaded!'); - -?> ---EXPECT-- -Lazy Loaded! \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-with-cache.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-with-cache.phpt deleted file mode 100644 index 06afe47..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/lazy-loading-value-holder-with-cache.phpt +++ /dev/null @@ -1,40 +0,0 @@ ---TEST-- -Verifies that lazy loading value holder proxy file is generated ---FILE-- -setProxiesTargetDir(__DIR__ . '/cache'); -$fileLocator = new \ProxyManager\FileLocator\FileLocator($configuration->getProxiesTargetDir()); -$configuration->setGeneratorStrategy( - new \ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy($fileLocator) -); - -$factory = new \ProxyManager\Factory\LazyLoadingValueHolderFactory($configuration); - -$proxy = $factory->createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -$filename = $fileLocator->getProxyFileName(get_class($proxy)); -var_dump(file_exists($filename)); - -$proxy = $factory->createProxy('Kitchen', function (& $wrapped, $proxy, $method, array $parameters, & $initializer) { - $initializer = null; - $wrapped = new Kitchen(); -}); - -var_dump(file_exists($filename)); -@unlink($filename); - -?> ---EXPECT-- -bool(true) -bool(true) \ No newline at end of file diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/null-object-public-function-empty.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/null-object-public-function-empty.phpt deleted file mode 100644 index 2453ea5..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/null-object-public-function-empty.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -Verifies that generated null object disallow public function ---FILE-- -createProxy('Kitchen'); - -var_dump($proxy->foo()); -?> ---EXPECT-- -NULL diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/null-object-public-property-empty.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/null-object-public-property-empty.phpt deleted file mode 100644 index 9da1a41..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/null-object-public-property-empty.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Verifies that generated null object disallow public function ---FILE-- -createProxy('Kitchen'); - -var_dump($proxy->foo); -?> ---EXPECT-- -NULL diff --git a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/remote-object-json-adapter-denies-unknow-method.phpt b/vendor/ocramius/proxy-manager/tests/language-feature-scripts/remote-object-json-adapter-denies-unknow-method.phpt deleted file mode 100644 index 1910a34..0000000 --- a/vendor/ocramius/proxy-manager/tests/language-feature-scripts/remote-object-json-adapter-denies-unknow-method.phpt +++ /dev/null @@ -1,43 +0,0 @@ ---TEST-- -Verifies that generated remote object can call public property ---FILE-- -createProxy('ProxyManagerTestAsset\RemoteProxy\FooServiceInterface'); - -var_dump($proxy->foo()); -var_dump($proxy->unknown()); -?> ---EXPECTF-- -string(3) "baz" - -%SFatal error: Call to undefined method %s::unknown%S in %s on line %d diff --git a/vendor/paragonie/random_compat/RATIONALE.md b/vendor/paragonie/random_compat/RATIONALE.md deleted file mode 100644 index a6e7307..0000000 --- a/vendor/paragonie/random_compat/RATIONALE.md +++ /dev/null @@ -1,42 +0,0 @@ -## Rationale (Design Decisions) - -### Reasoning Behind the Order of Preferred Random Data Sources - -The order is: - - 1. `libsodium if available` - 2. `fread() /dev/urandom if available` - 3. `mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM)` - 4. `COM('CAPICOM.Utilities.1')->GetRandom()` - 5. `openssl_random_pseudo_bytes()` - -If libsodium is available, we get random data from it. This is the preferred -method on all OSes, but libsodium is not very widely installed, so other -fallbacks are available. - -Next, we read `/dev/urandom` (if it exists). This is the preferred file to read -for random data for cryptographic purposes for BSD and Linux. This step -is skipped on Windows, because someone could create a `C:\dev\urandom` -file and PHP would helpfully (but insecurely) return bytes from it. - -Despite [strongly urging people not to use mcrypt in their projects](https://paragonie.com/blog/2015/05/if-you-re-typing-word-mcrypt-into-your-code-you-re-doing-it-wrong) -(because libmcrypt is abandonware and the API puts too much responsibility on the -implementor) we prioritize `mcrypt_create_iv()` with `MCRYPT_DEV_URANDOM` above -the remaining implementations. - -The reason is simple: `mcrypt_create_iv()` is part of PHP's `ext/mcrypt` code, -and is not part `libmcrypt`. It actually does the right thing: - - * On Unix-based operating systems, it reads from `/dev/urandom` which - (unlike `/dev/random`) is the sane and correct thing to do. - * On Windows, it reads from `CryptGenRandom`, which is an exclusively Windows - way to get random bytes. - -If we're on Windows and don't have access to `mcrypt`, we use `CAPICOM.Utilities.1`. - -Finally, we use `openssl_random_pseudo_bytes()` **as a last resort**, due to -[PHP bug #70014](https://bugs.php.net/bug.php?id=70014). Internally, this -function calls `RAND_pseudo_bytes()`, which has been [deprecated](https://github.com/paragonie/random_compat/issues/5) -by the OpenSSL team. Furthermore, [it might silently return weak random data](https://github.com/paragonie/random_compat/issues/6#issuecomment-119564973) -if it is called before OpenSSL's **userspace** CSPRNG is seeded. Also, -[you want the OS CSPRNG, not a userspace CSPRNG](http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/). diff --git a/vendor/paragonie/random_compat/lib/byte_safe_strings.php b/vendor/paragonie/random_compat/lib/byte_safe_strings.php deleted file mode 100644 index 6de294f..0000000 --- a/vendor/paragonie/random_compat/lib/byte_safe_strings.php +++ /dev/null @@ -1,181 +0,0 @@ - RandomCompat_strlen($binary_string)) { - return ''; - } - - return (string) mb_substr($binary_string, $start, $length, '8bit'); - } - - } else { - - /** - * substr() implementation that isn't brittle to mbstring.func_overload - * - * This version just uses the default substr() - * - * @param string $binary_string - * @param int $start - * @param int $length (optional) - * - * @throws TypeError - * - * @return string - */ - function RandomCompat_substr($binary_string, $start, $length = null) - { - if (!is_string($binary_string)) { - throw new TypeError( - 'RandomCompat_substr(): First argument should be a string' - ); - } - - if (!is_int($start)) { - throw new TypeError( - 'RandomCompat_substr(): Second argument should be an integer' - ); - } - - if ($length !== null) { - if (!is_int($length)) { - throw new TypeError( - 'RandomCompat_substr(): Third argument should be an integer, or omitted' - ); - } - - return (string) substr($binary_string, $start, $length); - } - - return (string) substr($binary_string, $start); - } - } -} diff --git a/vendor/paragonie/random_compat/lib/cast_to_int.php b/vendor/paragonie/random_compat/lib/cast_to_int.php deleted file mode 100644 index dc4048c..0000000 --- a/vendor/paragonie/random_compat/lib/cast_to_int.php +++ /dev/null @@ -1,74 +0,0 @@ - operators might accidentally let a float - * through. - * - * @param int|float $number The number we want to convert to an int - * @param boolean $fail_open Set to true to not throw an exception - * - * @return float|int - * - * @throws TypeError - */ - function RandomCompat_intval($number, $fail_open = false) - { - if (is_int($number) || is_float($number)) { - $number += 0; - } elseif (is_numeric($number)) { - $number += 0; - } - - if ( - is_float($number) - && - $number > ~PHP_INT_MAX - && - $number < PHP_INT_MAX - ) { - $number = (int) $number; - } - - if (is_int($number)) { - return (int) $number; - } elseif (!$fail_open) { - throw new TypeError( - 'Expected an integer.' - ); - } - return $number; - } -} diff --git a/vendor/paragonie/random_compat/lib/error_polyfill.php b/vendor/paragonie/random_compat/lib/error_polyfill.php deleted file mode 100644 index 17ece7b..0000000 --- a/vendor/paragonie/random_compat/lib/error_polyfill.php +++ /dev/null @@ -1,49 +0,0 @@ -GetRandom($bytes, 0)); - if (RandomCompat_strlen($buf) >= $bytes) { - /** - * Return our random entropy buffer here: - */ - return RandomCompat_substr($buf, 0, $bytes); - } - ++$execCount; - } while ($execCount < $bytes); - - /** - * If we reach here, PHP has failed us. - */ - throw new Exception( - 'Could not gather sufficient random data' - ); - } -} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php deleted file mode 100644 index 8bf7034..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php +++ /dev/null @@ -1,150 +0,0 @@ - 0); - - /** - * Is our result valid? - */ - if ($buf !== false) { - if (RandomCompat_strlen($buf) === $bytes) { - /** - * Return our random entropy buffer here: - */ - return $buf; - } - } - } - - /** - * If we reach here, PHP has failed us. - */ - throw new Exception( - 'Error reading from source device' - ); - } -} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php deleted file mode 100644 index 7d32b21..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php +++ /dev/null @@ -1,88 +0,0 @@ - 2147483647) { - $buf = ''; - for ($i = 0; $i < $bytes; $i += 1073741824) { - $n = ($bytes - $i) > 1073741824 - ? 1073741824 - : $bytes - $i; - $buf .= \Sodium\randombytes_buf($n); - } - } else { - $buf = \Sodium\randombytes_buf($bytes); - } - - if ($buf !== false) { - if (RandomCompat_strlen($buf) === $bytes) { - return $buf; - } - } - - /** - * If we reach here, PHP has failed us. - */ - throw new Exception( - 'Could not gather sufficient random data' - ); - } -} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php deleted file mode 100644 index ba93c40..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php +++ /dev/null @@ -1,92 +0,0 @@ - 2147483647) { - for ($i = 0; $i < $bytes; $i += 1073741824) { - $n = ($bytes - $i) > 1073741824 - ? 1073741824 - : $bytes - $i; - $buf .= Sodium::randombytes_buf($n); - } - } else { - $buf .= Sodium::randombytes_buf($bytes); - } - - if (is_string($buf)) { - if (RandomCompat_strlen($buf) === $bytes) { - return $buf; - } - } - - /** - * If we reach here, PHP has failed us. - */ - throw new Exception( - 'Could not gather sufficient random data' - ); - } -} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php deleted file mode 100644 index 3bce91a..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php +++ /dev/null @@ -1,77 +0,0 @@ - operators might accidentally let a float - * through. - */ - - try { - $min = RandomCompat_intval($min); - } catch (TypeError $ex) { - throw new TypeError( - 'random_int(): $min must be an integer' - ); - } - - try { - $max = RandomCompat_intval($max); - } catch (TypeError $ex) { - throw new TypeError( - 'random_int(): $max must be an integer' - ); - } - - /** - * Now that we've verified our weak typing system has given us an integer, - * let's validate the logic then we can move forward with generating random - * integers along a given range. - */ - if ($min > $max) { - throw new Error( - 'Minimum value must be less than or equal to the maximum value' - ); - } - - if ($max === $min) { - return $min; - } - - /** - * Initialize variables to 0 - * - * We want to store: - * $bytes => the number of random bytes we need - * $mask => an integer bitmask (for use with the &) operator - * so we can minimize the number of discards - */ - $attempts = $bits = $bytes = $mask = $valueShift = 0; - - /** - * At this point, $range is a positive number greater than 0. It might - * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to - * a float and we will lose some precision. - */ - $range = $max - $min; - - /** - * Test for integer overflow: - */ - if (!is_int($range)) { - - /** - * Still safely calculate wider ranges. - * Provided by @CodesInChaos, @oittaa - * - * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 - * - * We use ~0 as a mask in this case because it generates all 1s - * - * @ref https://eval.in/400356 (32-bit) - * @ref http://3v4l.org/XX9r5 (64-bit) - */ - $bytes = PHP_INT_SIZE; - $mask = ~0; - - } else { - - /** - * $bits is effectively ceil(log($range, 2)) without dealing with - * type juggling - */ - while ($range > 0) { - if ($bits % 8 === 0) { - ++$bytes; - } - ++$bits; - $range >>= 1; - $mask = $mask << 1 | 1; - } - $valueShift = $min; - } - - $val = 0; - /** - * Now that we have our parameters set up, let's begin generating - * random integers until one falls between $min and $max - */ - do { - /** - * The rejection probability is at most 0.5, so this corresponds - * to a failure probability of 2^-128 for a working RNG - */ - if ($attempts > 128) { - throw new Exception( - 'random_int: RNG is broken - too many rejections' - ); - } - - /** - * Let's grab the necessary number of random bytes - */ - $randomByteString = random_bytes($bytes); - - /** - * Let's turn $randomByteString into an integer - * - * This uses bitwise operators (<< and |) to build an integer - * out of the values extracted from ord() - * - * Example: [9F] | [6D] | [32] | [0C] => - * 159 + 27904 + 3276800 + 201326592 => - * 204631455 - */ - $val &= 0; - for ($i = 0; $i < $bytes; ++$i) { - $val |= ord($randomByteString[$i]) << ($i * 8); - } - - /** - * Apply mask - */ - $val &= $mask; - $val += $valueShift; - - ++$attempts; - /** - * If $val overflows to a floating point number, - * ... or is larger than $max, - * ... or smaller than $min, - * then try again. - */ - } while (!is_int($val) || $val > $max || $val < $min); - - return (int)$val; - } -} diff --git a/vendor/react/promise/LICENSE b/vendor/react/promise/LICENSE deleted file mode 100644 index 5919d20..0000000 --- a/vendor/react/promise/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2012-2016 Jan Sorgalla - -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. diff --git a/vendor/react/promise/composer.json b/vendor/react/promise/composer.json deleted file mode 100644 index 2fc4809..0000000 --- a/vendor/react/promise/composer.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "react/promise", - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "license": "MIT", - "authors": [ - {"name": "Jan Sorgalla", "email": "jsorgalla@gmail.com"} - ], - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "autoload": { - "psr-4": { - "React\\Promise\\": "src/" - }, - "files": ["src/functions_include.php"] - }, - "autoload-dev": { - "psr-4": { - "React\\Promise\\": "tests/fixtures" - } - }, - "keywords": [ - "promise", - "promises" - ] -} diff --git a/vendor/react/promise/src/CancellablePromiseInterface.php b/vendor/react/promise/src/CancellablePromiseInterface.php deleted file mode 100644 index 896db2d..0000000 --- a/vendor/react/promise/src/CancellablePromiseInterface.php +++ /dev/null @@ -1,11 +0,0 @@ -started) { - return; - } - - $this->started = true; - $this->drain(); - } - - public function enqueue($cancellable) - { - if (!\method_exists($cancellable, 'then') || !\method_exists($cancellable, 'cancel')) { - return; - } - - $length = \array_push($this->queue, $cancellable); - - if ($this->started && 1 === $length) { - $this->drain(); - } - } - - private function drain() - { - for ($i = key($this->queue); isset($this->queue[$i]); $i++) { - $cancellable = $this->queue[$i]; - - $exception = null; - - try { - $cancellable->cancel(); - } catch (\Throwable $exception) { - } catch (\Exception $exception) { - } - - unset($this->queue[$i]); - - if ($exception) { - throw $exception; - } - } - - $this->queue = []; - } -} diff --git a/vendor/react/promise/src/Deferred.php b/vendor/react/promise/src/Deferred.php deleted file mode 100644 index 3ca034b..0000000 --- a/vendor/react/promise/src/Deferred.php +++ /dev/null @@ -1,65 +0,0 @@ -canceller = $canceller; - } - - public function promise() - { - if (null === $this->promise) { - $this->promise = new Promise(function ($resolve, $reject, $notify) { - $this->resolveCallback = $resolve; - $this->rejectCallback = $reject; - $this->notifyCallback = $notify; - }, $this->canceller); - $this->canceller = null; - } - - return $this->promise; - } - - public function resolve($value = null) - { - $this->promise(); - - \call_user_func($this->resolveCallback, $value); - } - - public function reject($reason = null) - { - $this->promise(); - - \call_user_func($this->rejectCallback, $reason); - } - - /** - * @deprecated 2.6.0 Progress support is deprecated and should not be used anymore. - * @param mixed $update - */ - public function notify($update = null) - { - $this->promise(); - - \call_user_func($this->notifyCallback, $update); - } - - /** - * @deprecated 2.2.0 - * @see Deferred::notify() - */ - public function progress($update = null) - { - $this->notify($update); - } -} diff --git a/vendor/react/promise/src/Exception/LengthException.php b/vendor/react/promise/src/Exception/LengthException.php deleted file mode 100644 index 775c48d..0000000 --- a/vendor/react/promise/src/Exception/LengthException.php +++ /dev/null @@ -1,7 +0,0 @@ -value = $value; - } - - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - if (null === $onFulfilled) { - return $this; - } - - try { - return resolve($onFulfilled($this->value)); - } catch (\Throwable $exception) { - return new RejectedPromise($exception); - } catch (\Exception $exception) { - return new RejectedPromise($exception); - } - } - - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - if (null === $onFulfilled) { - return; - } - - $result = $onFulfilled($this->value); - - if ($result instanceof ExtendedPromiseInterface) { - $result->done(); - } - } - - public function otherwise(callable $onRejected) - { - return $this; - } - - public function always(callable $onFulfilledOrRejected) - { - return $this->then(function ($value) use ($onFulfilledOrRejected) { - return resolve($onFulfilledOrRejected())->then(function () use ($value) { - return $value; - }); - }); - } - - public function progress(callable $onProgress) - { - return $this; - } - - public function cancel() - { - } -} diff --git a/vendor/react/promise/src/LazyPromise.php b/vendor/react/promise/src/LazyPromise.php deleted file mode 100644 index 7546524..0000000 --- a/vendor/react/promise/src/LazyPromise.php +++ /dev/null @@ -1,63 +0,0 @@ -factory = $factory; - } - - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - return $this->promise()->then($onFulfilled, $onRejected, $onProgress); - } - - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - return $this->promise()->done($onFulfilled, $onRejected, $onProgress); - } - - public function otherwise(callable $onRejected) - { - return $this->promise()->otherwise($onRejected); - } - - public function always(callable $onFulfilledOrRejected) - { - return $this->promise()->always($onFulfilledOrRejected); - } - - public function progress(callable $onProgress) - { - return $this->promise()->progress($onProgress); - } - - public function cancel() - { - return $this->promise()->cancel(); - } - - /** - * @internal - * @see Promise::settle() - */ - public function promise() - { - if (null === $this->promise) { - try { - $this->promise = resolve(\call_user_func($this->factory)); - } catch (\Throwable $exception) { - $this->promise = new RejectedPromise($exception); - } catch (\Exception $exception) { - $this->promise = new RejectedPromise($exception); - } - } - - return $this->promise; - } -} diff --git a/vendor/react/promise/src/Promise.php b/vendor/react/promise/src/Promise.php deleted file mode 100644 index 33759e6..0000000 --- a/vendor/react/promise/src/Promise.php +++ /dev/null @@ -1,256 +0,0 @@ -canceller = $canceller; - - // Explicitly overwrite arguments with null values before invoking - // resolver function. This ensure that these arguments do not show up - // in the stack trace in PHP 7+ only. - $cb = $resolver; - $resolver = $canceller = null; - $this->call($cb); - } - - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - if (null !== $this->result) { - return $this->result->then($onFulfilled, $onRejected, $onProgress); - } - - if (null === $this->canceller) { - return new static($this->resolver($onFulfilled, $onRejected, $onProgress)); - } - - // This promise has a canceller, so we create a new child promise which - // has a canceller that invokes the parent canceller if all other - // followers are also cancelled. We keep a reference to this promise - // instance for the static canceller function and clear this to avoid - // keeping a cyclic reference between parent and follower. - $parent = $this; - ++$parent->requiredCancelRequests; - - return new static( - $this->resolver($onFulfilled, $onRejected, $onProgress), - static function () use (&$parent) { - if (++$parent->cancelRequests >= $parent->requiredCancelRequests) { - $parent->cancel(); - } - - $parent = null; - } - ); - } - - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - if (null !== $this->result) { - return $this->result->done($onFulfilled, $onRejected, $onProgress); - } - - $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected) { - $promise - ->done($onFulfilled, $onRejected); - }; - - if ($onProgress) { - $this->progressHandlers[] = $onProgress; - } - } - - public function otherwise(callable $onRejected) - { - return $this->then(null, static function ($reason) use ($onRejected) { - if (!_checkTypehint($onRejected, $reason)) { - return new RejectedPromise($reason); - } - - return $onRejected($reason); - }); - } - - public function always(callable $onFulfilledOrRejected) - { - return $this->then(static function ($value) use ($onFulfilledOrRejected) { - return resolve($onFulfilledOrRejected())->then(function () use ($value) { - return $value; - }); - }, static function ($reason) use ($onFulfilledOrRejected) { - return resolve($onFulfilledOrRejected())->then(function () use ($reason) { - return new RejectedPromise($reason); - }); - }); - } - - public function progress(callable $onProgress) - { - return $this->then(null, null, $onProgress); - } - - public function cancel() - { - if (null === $this->canceller || null !== $this->result) { - return; - } - - $canceller = $this->canceller; - $this->canceller = null; - - $this->call($canceller); - } - - private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) { - if ($onProgress) { - $progressHandler = static function ($update) use ($notify, $onProgress) { - try { - $notify($onProgress($update)); - } catch (\Throwable $e) { - $notify($e); - } catch (\Exception $e) { - $notify($e); - } - }; - } else { - $progressHandler = $notify; - } - - $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) { - $promise - ->then($onFulfilled, $onRejected) - ->done($resolve, $reject, $progressHandler); - }; - - $this->progressHandlers[] = $progressHandler; - }; - } - - private function reject($reason = null) - { - if (null !== $this->result) { - return; - } - - $this->settle(reject($reason)); - } - - private function settle(ExtendedPromiseInterface $promise) - { - $promise = $this->unwrap($promise); - - if ($promise === $this) { - $promise = new RejectedPromise( - new \LogicException('Cannot resolve a promise with itself.') - ); - } - - $handlers = $this->handlers; - - $this->progressHandlers = $this->handlers = []; - $this->result = $promise; - $this->canceller = null; - - foreach ($handlers as $handler) { - $handler($promise); - } - } - - private function unwrap($promise) - { - $promise = $this->extract($promise); - - while ($promise instanceof self && null !== $promise->result) { - $promise = $this->extract($promise->result); - } - - return $promise; - } - - private function extract($promise) - { - if ($promise instanceof LazyPromise) { - $promise = $promise->promise(); - } - - return $promise; - } - - private function call(callable $cb) - { - // Explicitly overwrite argument with null value. This ensure that this - // argument does not show up in the stack trace in PHP 7+ only. - $callback = $cb; - $cb = null; - - // Use reflection to inspect number of arguments expected by this callback. - // We did some careful benchmarking here: Using reflection to avoid unneeded - // function arguments is actually faster than blindly passing them. - // Also, this helps avoiding unnecessary function arguments in the call stack - // if the callback creates an Exception (creating garbage cycles). - if (\is_array($callback)) { - $ref = new \ReflectionMethod($callback[0], $callback[1]); - } elseif (\is_object($callback) && !$callback instanceof \Closure) { - $ref = new \ReflectionMethod($callback, '__invoke'); - } else { - $ref = new \ReflectionFunction($callback); - } - $args = $ref->getNumberOfParameters(); - - try { - if ($args === 0) { - $callback(); - } else { - // Keep references to this promise instance for the static resolve/reject functions. - // By using static callbacks that are not bound to this instance - // and passing the target promise instance by reference, we can - // still execute its resolving logic and still clear this - // reference when settling the promise. This helps avoiding - // garbage cycles if any callback creates an Exception. - // These assumptions are covered by the test suite, so if you ever feel like - // refactoring this, go ahead, any alternative suggestions are welcome! - $target =& $this; - $progressHandlers =& $this->progressHandlers; - - $callback( - static function ($value = null) use (&$target) { - if ($target !== null) { - $target->settle(resolve($value)); - $target = null; - } - }, - static function ($reason = null) use (&$target) { - if ($target !== null) { - $target->reject($reason); - $target = null; - } - }, - static function ($update = null) use (&$progressHandlers) { - foreach ($progressHandlers as $handler) { - $handler($update); - } - } - ); - } - } catch (\Throwable $e) { - $target = null; - $this->reject($e); - } catch (\Exception $e) { - $target = null; - $this->reject($e); - } - } -} diff --git a/vendor/react/promise/src/PromiseInterface.php b/vendor/react/promise/src/PromiseInterface.php deleted file mode 100644 index fcd763d..0000000 --- a/vendor/react/promise/src/PromiseInterface.php +++ /dev/null @@ -1,14 +0,0 @@ -reason = $reason; - } - - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - if (null === $onRejected) { - return $this; - } - - try { - return resolve($onRejected($this->reason)); - } catch (\Throwable $exception) { - return new RejectedPromise($exception); - } catch (\Exception $exception) { - return new RejectedPromise($exception); - } - } - - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - if (null === $onRejected) { - throw UnhandledRejectionException::resolve($this->reason); - } - - $result = $onRejected($this->reason); - - if ($result instanceof self) { - throw UnhandledRejectionException::resolve($result->reason); - } - - if ($result instanceof ExtendedPromiseInterface) { - $result->done(); - } - } - - public function otherwise(callable $onRejected) - { - if (!_checkTypehint($onRejected, $this->reason)) { - return $this; - } - - return $this->then(null, $onRejected); - } - - public function always(callable $onFulfilledOrRejected) - { - return $this->then(null, function ($reason) use ($onFulfilledOrRejected) { - return resolve($onFulfilledOrRejected())->then(function () use ($reason) { - return new RejectedPromise($reason); - }); - }); - } - - public function progress(callable $onProgress) - { - return $this; - } - - public function cancel() - { - } -} diff --git a/vendor/react/promise/src/UnhandledRejectionException.php b/vendor/react/promise/src/UnhandledRejectionException.php deleted file mode 100644 index e7fe2f7..0000000 --- a/vendor/react/promise/src/UnhandledRejectionException.php +++ /dev/null @@ -1,31 +0,0 @@ -reason = $reason; - - $message = \sprintf('Unhandled Rejection: %s', \json_encode($reason)); - - parent::__construct($message, 0); - } - - public function getReason() - { - return $this->reason; - } -} diff --git a/vendor/react/promise/src/functions.php b/vendor/react/promise/src/functions.php deleted file mode 100644 index c549e4e..0000000 --- a/vendor/react/promise/src/functions.php +++ /dev/null @@ -1,246 +0,0 @@ -then($resolve, $reject, $notify); - }, $canceller); - } - - return new FulfilledPromise($promiseOrValue); -} - -function reject($promiseOrValue = null) -{ - if ($promiseOrValue instanceof PromiseInterface) { - return resolve($promiseOrValue)->then(function ($value) { - return new RejectedPromise($value); - }); - } - - return new RejectedPromise($promiseOrValue); -} - -function all($promisesOrValues) -{ - return map($promisesOrValues, function ($val) { - return $val; - }); -} - -function race($promisesOrValues) -{ - $cancellationQueue = new CancellationQueue(); - $cancellationQueue->enqueue($promisesOrValues); - - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue) { - resolve($promisesOrValues) - ->done(function ($array) use ($cancellationQueue, $resolve, $reject, $notify) { - if (!is_array($array) || !$array) { - $resolve(); - return; - } - - foreach ($array as $promiseOrValue) { - $cancellationQueue->enqueue($promiseOrValue); - - resolve($promiseOrValue) - ->done($resolve, $reject, $notify); - } - }, $reject, $notify); - }, $cancellationQueue); -} - -function any($promisesOrValues) -{ - return some($promisesOrValues, 1) - ->then(function ($val) { - return \array_shift($val); - }); -} - -function some($promisesOrValues, $howMany) -{ - $cancellationQueue = new CancellationQueue(); - $cancellationQueue->enqueue($promisesOrValues); - - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue) { - resolve($promisesOrValues) - ->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify) { - if (!\is_array($array) || $howMany < 1) { - $resolve([]); - return; - } - - $len = \count($array); - - if ($len < $howMany) { - throw new Exception\LengthException( - \sprintf( - 'Input array must contain at least %d item%s but contains only %s item%s.', - $howMany, - 1 === $howMany ? '' : 's', - $len, - 1 === $len ? '' : 's' - ) - ); - } - - $toResolve = $howMany; - $toReject = ($len - $toResolve) + 1; - $values = []; - $reasons = []; - - foreach ($array as $i => $promiseOrValue) { - $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) { - if ($toResolve < 1 || $toReject < 1) { - return; - } - - $values[$i] = $val; - - if (0 === --$toResolve) { - $resolve($values); - } - }; - - $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) { - if ($toResolve < 1 || $toReject < 1) { - return; - } - - $reasons[$i] = $reason; - - if (0 === --$toReject) { - $reject($reasons); - } - }; - - $cancellationQueue->enqueue($promiseOrValue); - - resolve($promiseOrValue) - ->done($fulfiller, $rejecter, $notify); - } - }, $reject, $notify); - }, $cancellationQueue); -} - -function map($promisesOrValues, callable $mapFunc) -{ - $cancellationQueue = new CancellationQueue(); - $cancellationQueue->enqueue($promisesOrValues); - - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue) { - resolve($promisesOrValues) - ->done(function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify) { - if (!\is_array($array) || !$array) { - $resolve([]); - return; - } - - $toResolve = \count($array); - $values = []; - - foreach ($array as $i => $promiseOrValue) { - $cancellationQueue->enqueue($promiseOrValue); - $values[$i] = null; - - resolve($promiseOrValue) - ->then($mapFunc) - ->done( - function ($mapped) use ($i, &$values, &$toResolve, $resolve) { - $values[$i] = $mapped; - - if (0 === --$toResolve) { - $resolve($values); - } - }, - $reject, - $notify - ); - } - }, $reject, $notify); - }, $cancellationQueue); -} - -function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null) -{ - $cancellationQueue = new CancellationQueue(); - $cancellationQueue->enqueue($promisesOrValues); - - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue) { - resolve($promisesOrValues) - ->done(function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify) { - if (!\is_array($array)) { - $array = []; - } - - $total = \count($array); - $i = 0; - - // Wrap the supplied $reduceFunc with one that handles promises and then - // delegates to the supplied. - $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $cancellationQueue, $total, &$i) { - $cancellationQueue->enqueue($val); - - return $current - ->then(function ($c) use ($reduceFunc, $total, &$i, $val) { - return resolve($val) - ->then(function ($value) use ($reduceFunc, $total, &$i, $c) { - return $reduceFunc($c, $value, $i++, $total); - }); - }); - }; - - $cancellationQueue->enqueue($initialValue); - - \array_reduce($array, $wrappedReduceFunc, resolve($initialValue)) - ->done($resolve, $reject, $notify); - }, $reject, $notify); - }, $cancellationQueue); -} - -// Internal functions -function _checkTypehint(callable $callback, $object) -{ - if (!\is_object($object)) { - return true; - } - - if (\is_array($callback)) { - $callbackReflection = new \ReflectionMethod($callback[0], $callback[1]); - } elseif (\is_object($callback) && !$callback instanceof \Closure) { - $callbackReflection = new \ReflectionMethod($callback, '__invoke'); - } else { - $callbackReflection = new \ReflectionFunction($callback); - } - - $parameters = $callbackReflection->getParameters(); - - if (!isset($parameters[0])) { - return true; - } - - $expectedException = $parameters[0]; - - if (!$expectedException->getClass()) { - return true; - } - - return $expectedException->getClass()->isInstance($object); -} diff --git a/vendor/react/promise/src/functions_include.php b/vendor/react/promise/src/functions_include.php deleted file mode 100644 index bd0c54f..0000000 --- a/vendor/react/promise/src/functions_include.php +++ /dev/null @@ -1,5 +0,0 @@ -normalizer = new TemplateNormalizer; - $this->normalizer->clear(); - $this->normalizer->append('MergeConsecutiveCopyOf'); - $this->normalizer->append('MergeIdenticalConditionalBranches'); - $this->normalizer->append('OptimizeNestedConditionals'); - $this->normalizer->append('RemoveLivePreviewAttributes'); - } - public function optimizeTemplate($template) - { - return $this->normalizer->normalizeTemplate($template); - } -} \ No newline at end of file diff --git a/vendor/symfony/config/Definition/ReferenceDumper.php b/vendor/symfony/config/Definition/ReferenceDumper.php deleted file mode 100644 index 047b258..0000000 --- a/vendor/symfony/config/Definition/ReferenceDumper.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Definition; - -@trigger_error('The '.__NAMESPACE__.'\ReferenceDumper class is deprecated since Symfony 2.4 and will be removed in 3.0. Use the Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper class instead.', E_USER_DEPRECATED); - -use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper; - -/** - * @deprecated since version 2.4, to be removed in 3.0. - * Use {@link \Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper} instead. - */ -class ReferenceDumper extends YamlReferenceDumper -{ -} diff --git a/vendor/symfony/config/Resource/BCResourceInterfaceChecker.php b/vendor/symfony/config/Resource/BCResourceInterfaceChecker.php deleted file mode 100644 index 64c9309..0000000 --- a/vendor/symfony/config/Resource/BCResourceInterfaceChecker.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Resource; - -/** - * Resource checker for the ResourceInterface. Exists for BC. - * - * @author Matthias Pigulla - * - * @deprecated since 2.8, to be removed in 3.0. - */ -class BCResourceInterfaceChecker extends SelfCheckingResourceChecker -{ - public function supports(ResourceInterface $metadata) - { - /* As all resources must be instanceof ResourceInterface, - we support them all. */ - return true; - } - - public function isFresh(ResourceInterface $resource, $timestamp) - { - @trigger_error(sprintf('The class "%s" is performing resource checking through ResourceInterface::isFresh(), which is deprecated since Symfony 2.8 and will be removed in 3.0', \get_class($resource)), E_USER_DEPRECATED); - - return parent::isFresh($resource, $timestamp); // For now, $metadata features the isFresh() method, so off we go (quack quack) - } -} diff --git a/vendor/symfony/console/Helper/DialogHelper.php b/vendor/symfony/console/Helper/DialogHelper.php deleted file mode 100644 index 87a5a0c..0000000 --- a/vendor/symfony/console/Helper/DialogHelper.php +++ /dev/null @@ -1,502 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console\Helper; - -use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Console\Formatter\OutputFormatterStyle; -use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\OutputInterface; - -/** - * The Dialog class provides helpers to interact with the user. - * - * @author Fabien Potencier - * - * @deprecated since version 2.5, to be removed in 3.0. - * Use {@link \Symfony\Component\Console\Helper\QuestionHelper} instead. - */ -class DialogHelper extends InputAwareHelper -{ - private $inputStream; - private static $shell; - private static $stty; - - public function __construct($triggerDeprecationError = true) - { - if ($triggerDeprecationError) { - @trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since Symfony 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED); - } - } - - /** - * Asks the user to select a value. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param array $choices List of choices to pick from - * @param bool|string $default The default answer if the user enters nothing - * @param bool|int $attempts Max number of times to ask before giving up (false by default, which means infinite) - * @param string $errorMessage Message which will be shown if invalid value from choice list would be picked - * @param bool $multiselect Select more than one value separated by comma - * - * @return int|string|array The selected value or values (the key of the choices array) - * - * @throws InvalidArgumentException - */ - public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - $width = max(array_map('strlen', array_keys($choices))); - - $messages = (array) $question; - foreach ($choices as $key => $value) { - $messages[] = sprintf(" [%-{$width}s] %s", $key, $value); - } - - $output->writeln($messages); - - $result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage, $multiselect) { - // Collapse all spaces. - $selectedChoices = str_replace(' ', '', $picked); - - if ($multiselect) { - // Check for a separated comma values - if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) { - throw new InvalidArgumentException(sprintf($errorMessage, $picked)); - } - $selectedChoices = explode(',', $selectedChoices); - } else { - $selectedChoices = array($picked); - } - - $multiselectChoices = array(); - - foreach ($selectedChoices as $value) { - if (empty($choices[$value])) { - throw new InvalidArgumentException(sprintf($errorMessage, $value)); - } - $multiselectChoices[] = $value; - } - - if ($multiselect) { - return $multiselectChoices; - } - - return $picked; - }, $attempts, $default); - - return $result; - } - - /** - * Asks a question to the user. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param string $default The default answer if none is given by the user - * @param array $autocomplete List of values to autocomplete - * - * @return string The user answer - * - * @throws RuntimeException If there is no data to read in the input stream - */ - public function ask(OutputInterface $output, $question, $default = null, array $autocomplete = null) - { - if ($this->input && !$this->input->isInteractive()) { - return $default; - } - - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - $output->write($question); - - $inputStream = $this->inputStream ?: STDIN; - - if (null === $autocomplete || !$this->hasSttyAvailable()) { - $ret = fgets($inputStream, 4096); - if (false === $ret) { - throw new RuntimeException('Aborted'); - } - $ret = trim($ret); - } else { - $ret = ''; - - $i = 0; - $ofs = -1; - $matches = $autocomplete; - $numMatches = \count($matches); - - $sttyMode = shell_exec('stty -g'); - - // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) - shell_exec('stty -icanon -echo'); - - // Add highlighted text style - $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); - - // Read a keypress - while (!feof($inputStream)) { - $c = fread($inputStream, 1); - - // Backspace Character - if ("\177" === $c) { - if (0 === $numMatches && 0 !== $i) { - --$i; - // Move cursor backwards - $output->write("\033[1D"); - } - - if (0 === $i) { - $ofs = -1; - $matches = $autocomplete; - $numMatches = \count($matches); - } else { - $numMatches = 0; - } - - // Pop the last character off the end of our string - $ret = substr($ret, 0, $i); - } elseif ("\033" === $c) { - // Did we read an escape sequence? - $c .= fread($inputStream, 2); - - // A = Up Arrow. B = Down Arrow - if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { - if ('A' === $c[2] && -1 === $ofs) { - $ofs = 0; - } - - if (0 === $numMatches) { - continue; - } - - $ofs += ('A' === $c[2]) ? -1 : 1; - $ofs = ($numMatches + $ofs) % $numMatches; - } - } elseif (\ord($c) < 32) { - if ("\t" === $c || "\n" === $c) { - if ($numMatches > 0 && -1 !== $ofs) { - $ret = $matches[$ofs]; - // Echo out remaining chars for current match - $output->write(substr($ret, $i)); - $i = \strlen($ret); - } - - if ("\n" === $c) { - $output->write($c); - break; - } - - $numMatches = 0; - } - - continue; - } else { - $output->write($c); - $ret .= $c; - ++$i; - - $numMatches = 0; - $ofs = 0; - - foreach ($autocomplete as $value) { - // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) - if (0 === strpos($value, $ret) && $i !== \strlen($value)) { - $matches[$numMatches++] = $value; - } - } - } - - // Erase characters from cursor to end of line - $output->write("\033[K"); - - if ($numMatches > 0 && -1 !== $ofs) { - // Save cursor position - $output->write("\0337"); - // Write highlighted text - $output->write(''.substr($matches[$ofs], $i).''); - // Restore cursor position - $output->write("\0338"); - } - } - - // Reset stty so it behaves normally again - shell_exec(sprintf('stty %s', $sttyMode)); - } - - return \strlen($ret) > 0 ? $ret : $default; - } - - /** - * Asks a confirmation to the user. - * - * The question will be asked until the user answers by nothing, yes, or no. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param bool $default The default answer if the user enters nothing - * - * @return bool true if the user has confirmed, false otherwise - */ - public function askConfirmation(OutputInterface $output, $question, $default = true) - { - $answer = 'z'; - while ($answer && !\in_array(strtolower($answer[0]), array('y', 'n'))) { - $answer = $this->ask($output, $question); - } - - if (false === $default) { - return $answer && 'y' == strtolower($answer[0]); - } - - return !$answer || 'y' == strtolower($answer[0]); - } - - /** - * Asks a question to the user, the response is hidden. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question - * @param bool $fallback In case the response can not be hidden, whether to fallback on non-hidden question or not - * - * @return string The answer - * - * @throws RuntimeException In case the fallback is deactivated and the response can not be hidden - */ - public function askHiddenResponse(OutputInterface $output, $question, $fallback = true) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - if ('\\' === \DIRECTORY_SEPARATOR) { - $exe = __DIR__.'/../Resources/bin/hiddeninput.exe'; - - // handle code running from a phar - if ('phar:' === substr(__FILE__, 0, 5)) { - $tmpExe = sys_get_temp_dir().'/hiddeninput.exe'; - copy($exe, $tmpExe); - $exe = $tmpExe; - } - - $output->write($question); - $value = rtrim(shell_exec($exe)); - $output->writeln(''); - - if (isset($tmpExe)) { - unlink($tmpExe); - } - - return $value; - } - - if ($this->hasSttyAvailable()) { - $output->write($question); - - $sttyMode = shell_exec('stty -g'); - - shell_exec('stty -echo'); - $value = fgets($this->inputStream ?: STDIN, 4096); - shell_exec(sprintf('stty %s', $sttyMode)); - - if (false === $value) { - throw new RuntimeException('Aborted'); - } - - $value = trim($value); - $output->writeln(''); - - return $value; - } - - if (false !== $shell = $this->getShell()) { - $output->write($question); - $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword'; - $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd); - $value = rtrim(shell_exec($command)); - $output->writeln(''); - - return $value; - } - - if ($fallback) { - return $this->ask($output, $question); - } - - throw new RuntimeException('Unable to hide the response'); - } - - /** - * Asks for a value and validates the response. - * - * The validator receives the data to validate. It must return the - * validated data when the data is valid and throw an exception - * otherwise. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param callable $validator A PHP callback - * @param int|false $attempts Max number of times to ask before giving up (false by default, which means infinite) - * @param string $default The default answer if none is given by the user - * @param array $autocomplete List of values to autocomplete - * - * @return mixed - * - * @throws \Exception When any of the validators return an error - */ - public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null, array $autocomplete = null) - { - $that = $this; - - $interviewer = function () use ($output, $question, $default, $autocomplete, $that) { - return $that->ask($output, $question, $default, $autocomplete); - }; - - return $this->validateAttempts($interviewer, $output, $validator, $attempts); - } - - /** - * Asks for a value, hide and validates the response. - * - * The validator receives the data to validate. It must return the - * validated data when the data is valid and throw an exception - * otherwise. - * - * @param OutputInterface $output An Output instance - * @param string|array $question The question to ask - * @param callable $validator A PHP callback - * @param int|false $attempts Max number of times to ask before giving up (false by default, which means infinite) - * @param bool $fallback In case the response can not be hidden, whether to fallback on non-hidden question or not - * - * @return string The response - * - * @throws \Exception When any of the validators return an error - * @throws RuntimeException In case the fallback is deactivated and the response can not be hidden - */ - public function askHiddenResponseAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $fallback = true) - { - $that = $this; - - $interviewer = function () use ($output, $question, $fallback, $that) { - return $that->askHiddenResponse($output, $question, $fallback); - }; - - return $this->validateAttempts($interviewer, $output, $validator, $attempts); - } - - /** - * Sets the input stream to read from when interacting with the user. - * - * This is mainly useful for testing purpose. - * - * @param resource $stream The input stream - */ - public function setInputStream($stream) - { - $this->inputStream = $stream; - } - - /** - * Returns the helper's input stream. - * - * @return resource|null The input stream or null if the default STDIN is used - */ - public function getInputStream() - { - return $this->inputStream; - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'dialog'; - } - - /** - * Return a valid Unix shell. - * - * @return string|bool The valid shell name, false in case no valid shell is found - */ - private function getShell() - { - if (null !== self::$shell) { - return self::$shell; - } - - self::$shell = false; - - if (file_exists('/usr/bin/env')) { - // handle other OSs with bash/zsh/ksh/csh if available to hide the answer - $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null"; - foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) { - if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) { - self::$shell = $sh; - break; - } - } - } - - return self::$shell; - } - - private function hasSttyAvailable() - { - if (null !== self::$stty) { - return self::$stty; - } - - exec('stty 2>&1', $output, $exitcode); - - return self::$stty = 0 === $exitcode; - } - - /** - * Validate an attempt. - * - * @param callable $interviewer A callable that will ask for a question and return the result - * @param OutputInterface $output An Output instance - * @param callable $validator A PHP callback - * @param int|false $attempts Max number of times to ask before giving up; false will ask infinitely - * - * @return string The validated response - * - * @throws \Exception In case the max number of attempts has been reached and no valid response has been given - */ - private function validateAttempts($interviewer, OutputInterface $output, $validator, $attempts) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - $e = null; - while (false === $attempts || $attempts--) { - if (null !== $e) { - $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($e->getMessage(), 'error')); - } - - try { - return \call_user_func($validator, $interviewer()); - } catch (\Exception $e) { - } - } - - throw $e; - } -} diff --git a/vendor/symfony/console/Helper/ProgressHelper.php b/vendor/symfony/console/Helper/ProgressHelper.php deleted file mode 100644 index 4596f17..0000000 --- a/vendor/symfony/console/Helper/ProgressHelper.php +++ /dev/null @@ -1,469 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console\Helper; - -use Symfony\Component\Console\Exception\LogicException; -use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\NullOutput; -use Symfony\Component\Console\Output\OutputInterface; - -/** - * The Progress class provides helpers to display progress output. - * - * @author Chris Jones - * @author Fabien Potencier - * - * @deprecated since version 2.5, to be removed in 3.0 - * Use {@link ProgressBar} instead. - */ -class ProgressHelper extends Helper -{ - const FORMAT_QUIET = ' %percent%%'; - const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%'; - const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%'; - const FORMAT_QUIET_NOMAX = ' %current%'; - const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]'; - const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%'; - - // options - private $barWidth = 28; - private $barChar = '='; - private $emptyBarChar = '-'; - private $progressChar = '>'; - private $format = null; - private $redrawFreq = 1; - - private $lastMessagesLength; - private $barCharOriginal; - - /** - * @var OutputInterface - */ - private $output; - - /** - * Current step. - * - * @var int - */ - private $current; - - /** - * Maximum number of steps. - * - * @var int - */ - private $max; - - /** - * Start time of the progress bar. - * - * @var int - */ - private $startTime; - - /** - * List of formatting variables. - * - * @var array - */ - private $defaultFormatVars = array( - 'current', - 'max', - 'bar', - 'percent', - 'elapsed', - ); - - /** - * Available formatting variables. - * - * @var array - */ - private $formatVars; - - /** - * Stored format part widths (used for padding). - * - * @var array - */ - private $widths = array( - 'current' => 4, - 'max' => 4, - 'percent' => 3, - 'elapsed' => 6, - ); - - /** - * Various time formats. - * - * @var array - */ - private $timeFormats = array( - array(0, '???'), - array(2, '1 sec'), - array(59, 'secs', 1), - array(60, '1 min'), - array(3600, 'mins', 60), - array(5400, '1 hr'), - array(86400, 'hrs', 3600), - array(129600, '1 day'), - array(604800, 'days', 86400), - ); - - public function __construct($triggerDeprecationError = true) - { - if ($triggerDeprecationError) { - @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\ProgressBar class instead.', E_USER_DEPRECATED); - } - } - - /** - * Sets the progress bar width. - * - * @param int $size The progress bar size - */ - public function setBarWidth($size) - { - $this->barWidth = (int) $size; - } - - /** - * Sets the bar character. - * - * @param string $char A character - */ - public function setBarCharacter($char) - { - $this->barChar = $char; - } - - /** - * Sets the empty bar character. - * - * @param string $char A character - */ - public function setEmptyBarCharacter($char) - { - $this->emptyBarChar = $char; - } - - /** - * Sets the progress bar character. - * - * @param string $char A character - */ - public function setProgressCharacter($char) - { - $this->progressChar = $char; - } - - /** - * Sets the progress bar format. - * - * @param string $format The format - */ - public function setFormat($format) - { - $this->format = $format; - } - - /** - * Sets the redraw frequency. - * - * @param int $freq The frequency in steps - */ - public function setRedrawFrequency($freq) - { - $this->redrawFreq = (int) $freq; - } - - /** - * Starts the progress output. - * - * @param OutputInterface $output An Output instance - * @param int|null $max Maximum steps - */ - public function start(OutputInterface $output, $max = null) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - $this->startTime = time(); - $this->current = 0; - $this->max = (int) $max; - - // Disabling output when it does not support ANSI codes as it would result in a broken display anyway. - $this->output = $output->isDecorated() ? $output : new NullOutput(); - $this->lastMessagesLength = 0; - $this->barCharOriginal = ''; - - if (null === $this->format) { - switch ($output->getVerbosity()) { - case OutputInterface::VERBOSITY_QUIET: - $this->format = self::FORMAT_QUIET_NOMAX; - if ($this->max > 0) { - $this->format = self::FORMAT_QUIET; - } - break; - case OutputInterface::VERBOSITY_VERBOSE: - case OutputInterface::VERBOSITY_VERY_VERBOSE: - case OutputInterface::VERBOSITY_DEBUG: - $this->format = self::FORMAT_VERBOSE_NOMAX; - if ($this->max > 0) { - $this->format = self::FORMAT_VERBOSE; - } - break; - default: - $this->format = self::FORMAT_NORMAL_NOMAX; - if ($this->max > 0) { - $this->format = self::FORMAT_NORMAL; - } - break; - } - } - - $this->initialize(); - } - - /** - * Advances the progress output X steps. - * - * @param int $step Number of steps to advance - * @param bool $redraw Whether to redraw or not - * - * @throws LogicException - */ - public function advance($step = 1, $redraw = false) - { - $this->setCurrent($this->current + $step, $redraw); - } - - /** - * Sets the current progress. - * - * @param int $current The current progress - * @param bool $redraw Whether to redraw or not - * - * @throws LogicException - */ - public function setCurrent($current, $redraw = false) - { - if (null === $this->startTime) { - throw new LogicException('You must start the progress bar before calling setCurrent().'); - } - - $current = (int) $current; - - if ($current < $this->current) { - throw new LogicException('You can\'t regress the progress bar'); - } - - if (0 === $this->current) { - $redraw = true; - } - - $prevPeriod = (int) ($this->current / $this->redrawFreq); - - $this->current = $current; - - $currPeriod = (int) ($this->current / $this->redrawFreq); - if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) { - $this->display(); - } - } - - /** - * Outputs the current progress string. - * - * @param bool $finish Forces the end result - * - * @throws LogicException - */ - public function display($finish = false) - { - if (null === $this->startTime) { - throw new LogicException('You must start the progress bar before calling display().'); - } - - $message = $this->format; - foreach ($this->generate($finish) as $name => $value) { - $message = str_replace("%{$name}%", $value, $message); - } - $this->overwrite($this->output, $message); - } - - /** - * Removes the progress bar from the current line. - * - * This is useful if you wish to write some output - * while a progress bar is running. - * Call display() to show the progress bar again. - */ - public function clear() - { - $this->overwrite($this->output, ''); - } - - /** - * Finishes the progress output. - */ - public function finish() - { - if (null === $this->startTime) { - throw new LogicException('You must start the progress bar before calling finish().'); - } - - if (null !== $this->startTime) { - if (!$this->max) { - $this->barChar = $this->barCharOriginal; - $this->display(true); - } - $this->startTime = null; - $this->output->writeln(''); - $this->output = null; - } - } - - /** - * Initializes the progress helper. - */ - private function initialize() - { - $this->formatVars = array(); - foreach ($this->defaultFormatVars as $var) { - if (false !== strpos($this->format, "%{$var}%")) { - $this->formatVars[$var] = true; - } - } - - if ($this->max > 0) { - $this->widths['max'] = $this->strlen($this->max); - $this->widths['current'] = $this->widths['max']; - } else { - $this->barCharOriginal = $this->barChar; - $this->barChar = $this->emptyBarChar; - } - } - - /** - * Generates the array map of format variables to values. - * - * @param bool $finish Forces the end result - * - * @return array Array of format vars and values - */ - private function generate($finish = false) - { - $vars = array(); - $percent = 0; - if ($this->max > 0) { - $percent = (float) $this->current / $this->max; - } - - if (isset($this->formatVars['bar'])) { - if ($this->max > 0) { - $completeBars = floor($percent * $this->barWidth); - } else { - if (!$finish) { - $completeBars = floor($this->current % $this->barWidth); - } else { - $completeBars = $this->barWidth; - } - } - - $emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar); - $bar = str_repeat($this->barChar, $completeBars); - if ($completeBars < $this->barWidth) { - $bar .= $this->progressChar; - $bar .= str_repeat($this->emptyBarChar, $emptyBars); - } - - $vars['bar'] = $bar; - } - - if (isset($this->formatVars['elapsed'])) { - $elapsed = time() - $this->startTime; - $vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT); - } - - if (isset($this->formatVars['current'])) { - $vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT); - } - - if (isset($this->formatVars['max'])) { - $vars['max'] = $this->max; - } - - if (isset($this->formatVars['percent'])) { - $vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT); - } - - return $vars; - } - - /** - * Converts seconds into human-readable format. - * - * @param int $secs Number of seconds - * - * @return string Time in readable format - */ - private function humaneTime($secs) - { - $text = ''; - foreach ($this->timeFormats as $format) { - if ($secs < $format[0]) { - if (2 == \count($format)) { - $text = $format[1]; - break; - } else { - $text = ceil($secs / $format[2]).' '.$format[1]; - break; - } - } - } - - return $text; - } - - /** - * Overwrites a previous message to the output. - * - * @param OutputInterface $output An Output instance - * @param string $message The message - */ - private function overwrite(OutputInterface $output, $message) - { - $length = $this->strlen($message); - - // append whitespace to match the last line's length - if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) { - $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); - } - - // carriage return - $output->write("\x0D"); - $output->write($message); - - $this->lastMessagesLength = $this->strlen($message); - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'progress'; - } -} diff --git a/vendor/symfony/console/Helper/TableHelper.php b/vendor/symfony/console/Helper/TableHelper.php deleted file mode 100644 index 3d2095a..0000000 --- a/vendor/symfony/console/Helper/TableHelper.php +++ /dev/null @@ -1,264 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console\Helper; - -use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Output\NullOutput; -use Symfony\Component\Console\Output\OutputInterface; - -/** - * Provides helpers to display table output. - * - * @author Саша Стаменковић - * @author Fabien Potencier - * - * @deprecated since version 2.5, to be removed in 3.0 - * Use {@link Table} instead. - */ -class TableHelper extends Helper -{ - const LAYOUT_DEFAULT = 0; - const LAYOUT_BORDERLESS = 1; - const LAYOUT_COMPACT = 2; - - private $table; - - public function __construct($triggerDeprecationError = true) - { - if ($triggerDeprecationError) { - @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\Table class instead.', E_USER_DEPRECATED); - } - - $this->table = new Table(new NullOutput()); - } - - /** - * Sets table layout type. - * - * @param int $layout self::LAYOUT_* - * - * @return $this - * - * @throws InvalidArgumentException when the table layout is not known - */ - public function setLayout($layout) - { - switch ($layout) { - case self::LAYOUT_BORDERLESS: - $this->table->setStyle('borderless'); - break; - - case self::LAYOUT_COMPACT: - $this->table->setStyle('compact'); - break; - - case self::LAYOUT_DEFAULT: - $this->table->setStyle('default'); - break; - - default: - throw new InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout)); - } - - return $this; - } - - public function setHeaders(array $headers) - { - $this->table->setHeaders($headers); - - return $this; - } - - public function setRows(array $rows) - { - $this->table->setRows($rows); - - return $this; - } - - public function addRows(array $rows) - { - $this->table->addRows($rows); - - return $this; - } - - public function addRow(array $row) - { - $this->table->addRow($row); - - return $this; - } - - public function setRow($column, array $row) - { - $this->table->setRow($column, $row); - - return $this; - } - - /** - * Sets padding character, used for cell padding. - * - * @param string $paddingChar - * - * @return $this - */ - public function setPaddingChar($paddingChar) - { - $this->table->getStyle()->setPaddingChar($paddingChar); - - return $this; - } - - /** - * Sets horizontal border character. - * - * @param string $horizontalBorderChar - * - * @return $this - */ - public function setHorizontalBorderChar($horizontalBorderChar) - { - $this->table->getStyle()->setHorizontalBorderChar($horizontalBorderChar); - - return $this; - } - - /** - * Sets vertical border character. - * - * @param string $verticalBorderChar - * - * @return $this - */ - public function setVerticalBorderChar($verticalBorderChar) - { - $this->table->getStyle()->setVerticalBorderChar($verticalBorderChar); - - return $this; - } - - /** - * Sets crossing character. - * - * @param string $crossingChar - * - * @return $this - */ - public function setCrossingChar($crossingChar) - { - $this->table->getStyle()->setCrossingChar($crossingChar); - - return $this; - } - - /** - * Sets header cell format. - * - * @param string $cellHeaderFormat - * - * @return $this - */ - public function setCellHeaderFormat($cellHeaderFormat) - { - $this->table->getStyle()->setCellHeaderFormat($cellHeaderFormat); - - return $this; - } - - /** - * Sets row cell format. - * - * @param string $cellRowFormat - * - * @return $this - */ - public function setCellRowFormat($cellRowFormat) - { - $this->table->getStyle()->setCellHeaderFormat($cellRowFormat); - - return $this; - } - - /** - * Sets row cell content format. - * - * @param string $cellRowContentFormat - * - * @return $this - */ - public function setCellRowContentFormat($cellRowContentFormat) - { - $this->table->getStyle()->setCellRowContentFormat($cellRowContentFormat); - - return $this; - } - - /** - * Sets table border format. - * - * @param string $borderFormat - * - * @return $this - */ - public function setBorderFormat($borderFormat) - { - $this->table->getStyle()->setBorderFormat($borderFormat); - - return $this; - } - - /** - * Sets cell padding type. - * - * @param int $padType STR_PAD_* - * - * @return $this - */ - public function setPadType($padType) - { - $this->table->getStyle()->setPadType($padType); - - return $this; - } - - /** - * Renders table to output. - * - * Example: - * +---------------+-----------------------+------------------+ - * | ISBN | Title | Author | - * +---------------+-----------------------+------------------+ - * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | - * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | - * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | - * +---------------+-----------------------+------------------+ - */ - public function render(OutputInterface $output) - { - $p = new \ReflectionProperty($this->table, 'output'); - $p->setAccessible(true); - $p->setValue($this->table, $output); - - $this->table->render(); - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'table'; - } -} diff --git a/vendor/symfony/console/Shell.php b/vendor/symfony/console/Shell.php deleted file mode 100644 index 5d23e20..0000000 --- a/vendor/symfony/console/Shell.php +++ /dev/null @@ -1,229 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console; - -use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Console\Input\StringInput; -use Symfony\Component\Console\Output\ConsoleOutput; -use Symfony\Component\Process\PhpExecutableFinder; -use Symfony\Component\Process\ProcessBuilder; - -/** - * A Shell wraps an Application to add shell capabilities to it. - * - * Support for history and completion only works with a PHP compiled - * with readline support (either --with-readline or --with-libedit) - * - * @deprecated since version 2.8, to be removed in 3.0. - * - * @author Fabien Potencier - * @author Martin Hasoň - */ -class Shell -{ - private $application; - private $history; - private $output; - private $hasReadline; - private $processIsolation = false; - - /** - * If there is no readline support for the current PHP executable - * a \RuntimeException exception is thrown. - */ - public function __construct(Application $application) - { - @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - - $this->hasReadline = \function_exists('readline'); - $this->application = $application; - $this->history = getenv('HOME').'/.history_'.$application->getName(); - $this->output = new ConsoleOutput(); - } - - /** - * Runs the shell. - */ - public function run() - { - $this->application->setAutoExit(false); - $this->application->setCatchExceptions(true); - - if ($this->hasReadline) { - readline_read_history($this->history); - readline_completion_function(array($this, 'autocompleter')); - } - - $this->output->writeln($this->getHeader()); - $php = null; - if ($this->processIsolation) { - $finder = new PhpExecutableFinder(); - $php = $finder->find(); - $this->output->writeln(<<<'EOF' -Running with process isolation, you should consider this: - * each command is executed as separate process, - * commands don't support interactivity, all params must be passed explicitly, - * commands output is not colorized. - -EOF - ); - } - - while (true) { - $command = $this->readline(); - - if (false === $command) { - $this->output->writeln("\n"); - - break; - } - - if ($this->hasReadline) { - readline_add_history($command); - readline_write_history($this->history); - } - - if ($this->processIsolation) { - $pb = new ProcessBuilder(); - - $process = $pb - ->add($php) - ->add($_SERVER['argv'][0]) - ->add($command) - ->inheritEnvironmentVariables(true) - ->getProcess() - ; - - $output = $this->output; - $process->run(function ($type, $data) use ($output) { - $output->writeln($data); - }); - - $ret = $process->getExitCode(); - } else { - $ret = $this->application->run(new StringInput($command), $this->output); - } - - if (0 !== $ret) { - $this->output->writeln(sprintf('The command terminated with an error status (%s)', $ret)); - } - } - } - - /** - * Returns the shell header. - * - * @return string The header string - */ - protected function getHeader() - { - return <<{$this->application->getName()} shell ({$this->application->getVersion()}). - -At the prompt, type help for some help, -or list to get a list of available commands. - -To exit the shell, type ^D. - -EOF; - } - - /** - * Renders a prompt. - * - * @return string The prompt - */ - protected function getPrompt() - { - // using the formatter here is required when using readline - return $this->output->getFormatter()->format($this->application->getName().' > '); - } - - protected function getOutput() - { - return $this->output; - } - - protected function getApplication() - { - return $this->application; - } - - /** - * Tries to return autocompletion for the current entered text. - * - * @param string $text The last segment of the entered text - * - * @return bool|array A list of guessed strings or true - */ - private function autocompleter($text) - { - $info = readline_info(); - $text = substr($info['line_buffer'], 0, $info['end']); - - if ($info['point'] !== $info['end']) { - return true; - } - - // task name? - if (false === strpos($text, ' ') || !$text) { - return array_keys($this->application->all()); - } - - // options and arguments? - try { - $command = $this->application->find(substr($text, 0, strpos($text, ' '))); - } catch (\Exception $e) { - return true; - } - - $list = array('--help'); - foreach ($command->getDefinition()->getOptions() as $option) { - $list[] = '--'.$option->getName(); - } - - return $list; - } - - /** - * Reads a single line from standard input. - * - * @return string The single line from standard input - */ - private function readline() - { - if ($this->hasReadline) { - $line = readline($this->getPrompt()); - } else { - $this->output->write($this->getPrompt()); - $line = fgets(STDIN, 1024); - $line = (false === $line || '' === $line) ? false : rtrim($line); - } - - return $line; - } - - public function getProcessIsolation() - { - return $this->processIsolation; - } - - public function setProcessIsolation($processIsolation) - { - $this->processIsolation = (bool) $processIsolation; - - if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) { - throw new RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.'); - } - } -} diff --git a/vendor/symfony/debug/Exception/DummyException.php b/vendor/symfony/debug/Exception/DummyException.php deleted file mode 100644 index 1b9082b..0000000 --- a/vendor/symfony/debug/Exception/DummyException.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Exception; - -@trigger_error('The '.__NAMESPACE__.'\DummyException class is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED); - -/** - * @author Fabien Potencier - * - * @deprecated since version 2.5, to be removed in 3.0. - */ -class DummyException extends \ErrorException -{ -} diff --git a/vendor/symfony/dependency-injection/ContainerAware.php b/vendor/symfony/dependency-injection/ContainerAware.php deleted file mode 100644 index f3f2a50..0000000 --- a/vendor/symfony/dependency-injection/ContainerAware.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection; - -/** - * A simple implementation of ContainerAwareInterface. - * - * @author Fabien Potencier - * - * @deprecated since version 2.8, to be removed in 3.0. Use the ContainerAwareTrait instead. - */ -abstract class ContainerAware implements ContainerAwareInterface -{ - /** - * @var ContainerInterface - */ - protected $container; - - /** - * {@inheritdoc} - */ - public function setContainer(ContainerInterface $container = null) - { - $this->container = $container; - } -} diff --git a/vendor/symfony/dependency-injection/Exception/InactiveScopeException.php b/vendor/symfony/dependency-injection/Exception/InactiveScopeException.php deleted file mode 100644 index 6b3dd3e..0000000 --- a/vendor/symfony/dependency-injection/Exception/InactiveScopeException.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Exception; - -/** - * This exception is thrown when you try to create a service of an inactive scope. - * - * @author Johannes M. Schmitt - */ -class InactiveScopeException extends RuntimeException -{ - private $serviceId; - private $scope; - - public function __construct($serviceId, $scope, \Exception $previous = null) - { - parent::__construct(sprintf('You cannot create a service ("%s") of an inactive scope ("%s").', $serviceId, $scope), 0, $previous); - - $this->serviceId = $serviceId; - $this->scope = $scope; - } - - public function getServiceId() - { - return $this->serviceId; - } - - public function getScope() - { - return $this->scope; - } -} diff --git a/vendor/symfony/dependency-injection/Exception/ScopeCrossingInjectionException.php b/vendor/symfony/dependency-injection/Exception/ScopeCrossingInjectionException.php deleted file mode 100644 index 661fbab..0000000 --- a/vendor/symfony/dependency-injection/Exception/ScopeCrossingInjectionException.php +++ /dev/null @@ -1,65 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Exception; - -/** - * This exception is thrown when the a scope crossing injection is detected. - * - * @author Johannes M. Schmitt - */ -class ScopeCrossingInjectionException extends RuntimeException -{ - private $sourceServiceId; - private $sourceScope; - private $destServiceId; - private $destScope; - - public function __construct($sourceServiceId, $sourceScope, $destServiceId, $destScope, \Exception $previous = null) - { - parent::__construct(sprintf( - 'Scope Crossing Injection detected: The definition "%s" references the service "%s" which belongs to another scope hierarchy. ' - .'This service might not be available consistently. Generally, it is safer to either move the definition "%s" to scope "%s", or ' - .'declare "%s" as a child scope of "%s". If you can be sure that the other scope is always active, you can set the reference to strict=false to get rid of this error.', - $sourceServiceId, - $destServiceId, - $sourceServiceId, - $destScope, - $sourceScope, - $destScope - ), 0, $previous); - - $this->sourceServiceId = $sourceServiceId; - $this->sourceScope = $sourceScope; - $this->destServiceId = $destServiceId; - $this->destScope = $destScope; - } - - public function getSourceServiceId() - { - return $this->sourceServiceId; - } - - public function getSourceScope() - { - return $this->sourceScope; - } - - public function getDestServiceId() - { - return $this->destServiceId; - } - - public function getDestScope() - { - return $this->destScope; - } -} diff --git a/vendor/symfony/dependency-injection/Exception/ScopeWideningInjectionException.php b/vendor/symfony/dependency-injection/Exception/ScopeWideningInjectionException.php deleted file mode 100644 index 86a6684..0000000 --- a/vendor/symfony/dependency-injection/Exception/ScopeWideningInjectionException.php +++ /dev/null @@ -1,64 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Exception; - -/** - * Thrown when a scope widening injection is detected. - * - * @author Johannes M. Schmitt - */ -class ScopeWideningInjectionException extends RuntimeException -{ - private $sourceServiceId; - private $sourceScope; - private $destServiceId; - private $destScope; - - public function __construct($sourceServiceId, $sourceScope, $destServiceId, $destScope, \Exception $previous = null) - { - parent::__construct(sprintf( - 'Scope Widening Injection detected: The definition "%s" references the service "%s" which belongs to a narrower scope. ' - .'Generally, it is safer to either move "%s" to scope "%s" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "%s" each time it is needed. ' - .'In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error.', - $sourceServiceId, - $destServiceId, - $sourceServiceId, - $destScope, - $destServiceId - ), 0, $previous); - - $this->sourceServiceId = $sourceServiceId; - $this->sourceScope = $sourceScope; - $this->destServiceId = $destServiceId; - $this->destScope = $destScope; - } - - public function getSourceServiceId() - { - return $this->sourceServiceId; - } - - public function getSourceScope() - { - return $this->sourceScope; - } - - public function getDestServiceId() - { - return $this->destServiceId; - } - - public function getDestScope() - { - return $this->destScope; - } -} diff --git a/vendor/symfony/dependency-injection/IntrospectableContainerInterface.php b/vendor/symfony/dependency-injection/IntrospectableContainerInterface.php deleted file mode 100644 index 4aa0059..0000000 --- a/vendor/symfony/dependency-injection/IntrospectableContainerInterface.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection; - -/** - * IntrospectableContainerInterface defines additional introspection functionality - * for containers, allowing logic to be implemented based on a Container's state. - * - * @author Evan Villemez - * - * @deprecated since version 2.8, to be merged with ContainerInterface in 3.0. - */ -interface IntrospectableContainerInterface extends ContainerInterface -{ - /** - * Check for whether or not a service has been initialized. - * - * @param string $id - * - * @return bool true if the service has been initialized, false otherwise - */ - public function initialized($id); -} diff --git a/vendor/symfony/dependency-injection/Scope.php b/vendor/symfony/dependency-injection/Scope.php deleted file mode 100644 index b0b8ed6..0000000 --- a/vendor/symfony/dependency-injection/Scope.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection; - -/** - * Scope class. - * - * @author Johannes M. Schmitt - * - * @deprecated since version 2.8, to be removed in 3.0. - */ -class Scope implements ScopeInterface -{ - private $name; - private $parentName; - - public function __construct($name, $parentName = ContainerInterface::SCOPE_CONTAINER) - { - $this->name = $name; - $this->parentName = $parentName; - } - - public function getName() - { - return $this->name; - } - - public function getParentName() - { - return $this->parentName; - } -} diff --git a/vendor/symfony/dependency-injection/ScopeInterface.php b/vendor/symfony/dependency-injection/ScopeInterface.php deleted file mode 100644 index 11b1097..0000000 --- a/vendor/symfony/dependency-injection/ScopeInterface.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection; - -/** - * Scope Interface. - * - * @author Johannes M. Schmitt - * - * @deprecated since version 2.8, to be removed in 3.0. - */ -interface ScopeInterface -{ - public function getName(); - - public function getParentName(); -} diff --git a/vendor/symfony/dependency-injection/SimpleXMLElement.php b/vendor/symfony/dependency-injection/SimpleXMLElement.php deleted file mode 100644 index bb985ac..0000000 --- a/vendor/symfony/dependency-injection/SimpleXMLElement.php +++ /dev/null @@ -1,116 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection; - -@trigger_error('The '.__NAMESPACE__.'\SimpleXMLElement class is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED); - -use Symfony\Component\Config\Util\XmlUtils; -use Symfony\Component\ExpressionLanguage\Expression; - -/** - * SimpleXMLElement class. - * - * @author Fabien Potencier - * - * @deprecated since version 2.5, to be removed in 3.0. - */ -class SimpleXMLElement extends \SimpleXMLElement -{ - /** - * Converts an attribute as a PHP type. - * - * @param string $name - * - * @return mixed - */ - public function getAttributeAsPhp($name) - { - return self::phpize($this[$name]); - } - - /** - * Returns arguments as valid PHP types. - * - * @param string $name - * @param bool $lowercase - * - * @return mixed - */ - public function getArgumentsAsPhp($name, $lowercase = true) - { - $arguments = array(); - foreach ($this->$name as $arg) { - if (isset($arg['name'])) { - $arg['key'] = (string) $arg['name']; - } - $key = isset($arg['key']) ? (string) $arg['key'] : (!$arguments ? 0 : max(array_keys($arguments)) + 1); - - // parameter keys are case insensitive - if ('parameter' == $name && $lowercase) { - $key = strtolower($key); - } - - // this is used by DefinitionDecorator to overwrite a specific - // argument of the parent definition - if (isset($arg['index'])) { - $key = 'index_'.$arg['index']; - } - - switch ($arg['type']) { - case 'service': - $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; - if (isset($arg['on-invalid']) && 'ignore' == $arg['on-invalid']) { - $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; - } elseif (isset($arg['on-invalid']) && 'null' == $arg['on-invalid']) { - $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; - } - - if (isset($arg['strict'])) { - $strict = self::phpize($arg['strict']); - } else { - $strict = true; - } - - $arguments[$key] = new Reference((string) $arg['id'], $invalidBehavior, $strict); - break; - case 'expression': - $arguments[$key] = new Expression((string) $arg); - break; - case 'collection': - $arguments[$key] = $arg->getArgumentsAsPhp($name, false); - break; - case 'string': - $arguments[$key] = (string) $arg; - break; - case 'constant': - $arguments[$key] = \constant((string) $arg); - break; - default: - $arguments[$key] = self::phpize($arg); - } - } - - return $arguments; - } - - /** - * Converts an xml value to a PHP type. - * - * @param mixed $value - * - * @return mixed - */ - public static function phpize($value) - { - return XmlUtils::phpize($value); - } -} diff --git a/vendor/symfony/finder/Adapter/AbstractAdapter.php b/vendor/symfony/finder/Adapter/AbstractAdapter.php deleted file mode 100644 index 1a1647c..0000000 --- a/vendor/symfony/finder/Adapter/AbstractAdapter.php +++ /dev/null @@ -1,240 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Adapter; - -@trigger_error('The '.__NAMESPACE__.'\AbstractAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED); - -/** - * Interface for finder engine implementations. - * - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. Use Finder instead. - */ -abstract class AbstractAdapter implements AdapterInterface -{ - protected $followLinks = false; - protected $mode = 0; - protected $minDepth = 0; - protected $maxDepth = PHP_INT_MAX; - protected $exclude = array(); - protected $names = array(); - protected $notNames = array(); - protected $contains = array(); - protected $notContains = array(); - protected $sizes = array(); - protected $dates = array(); - protected $filters = array(); - protected $sort = false; - protected $paths = array(); - protected $notPaths = array(); - protected $ignoreUnreadableDirs = false; - - private static $areSupported = array(); - - /** - * {@inheritdoc} - */ - public function isSupported() - { - $name = $this->getName(); - - if (!array_key_exists($name, self::$areSupported)) { - self::$areSupported[$name] = $this->canBeUsed(); - } - - return self::$areSupported[$name]; - } - - /** - * {@inheritdoc} - */ - public function setFollowLinks($followLinks) - { - $this->followLinks = $followLinks; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setMode($mode) - { - $this->mode = $mode; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setDepths(array $depths) - { - $this->minDepth = 0; - $this->maxDepth = PHP_INT_MAX; - - foreach ($depths as $comparator) { - switch ($comparator->getOperator()) { - case '>': - $this->minDepth = $comparator->getTarget() + 1; - break; - case '>=': - $this->minDepth = $comparator->getTarget(); - break; - case '<': - $this->maxDepth = $comparator->getTarget() - 1; - break; - case '<=': - $this->maxDepth = $comparator->getTarget(); - break; - default: - $this->minDepth = $this->maxDepth = $comparator->getTarget(); - } - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setExclude(array $exclude) - { - $this->exclude = $exclude; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setNames(array $names) - { - $this->names = $names; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setNotNames(array $notNames) - { - $this->notNames = $notNames; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setContains(array $contains) - { - $this->contains = $contains; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setNotContains(array $notContains) - { - $this->notContains = $notContains; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setSizes(array $sizes) - { - $this->sizes = $sizes; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setDates(array $dates) - { - $this->dates = $dates; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setFilters(array $filters) - { - $this->filters = $filters; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setSort($sort) - { - $this->sort = $sort; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setPath(array $paths) - { - $this->paths = $paths; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setNotPath(array $notPaths) - { - $this->notPaths = $notPaths; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function ignoreUnreadableDirs($ignore = true) - { - $this->ignoreUnreadableDirs = (bool) $ignore; - - return $this; - } - - /** - * Returns whether the adapter is supported in the current environment. - * - * This method should be implemented in all adapters. Do not implement - * isSupported in the adapters as the generic implementation provides a cache - * layer. - * - * @see isSupported() - * - * @return bool Whether the adapter is supported - */ - abstract protected function canBeUsed(); -} diff --git a/vendor/symfony/finder/Adapter/AbstractFindAdapter.php b/vendor/symfony/finder/Adapter/AbstractFindAdapter.php deleted file mode 100644 index ef45869..0000000 --- a/vendor/symfony/finder/Adapter/AbstractFindAdapter.php +++ /dev/null @@ -1,325 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Adapter; - -@trigger_error('The '.__NAMESPACE__.'\AbstractFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED); - -use Symfony\Component\Finder\Comparator\DateComparator; -use Symfony\Component\Finder\Comparator\NumberComparator; -use Symfony\Component\Finder\Exception\AccessDeniedException; -use Symfony\Component\Finder\Expression\Expression; -use Symfony\Component\Finder\Iterator; -use Symfony\Component\Finder\Shell\Command; -use Symfony\Component\Finder\Shell\Shell; - -/** - * Shell engine implementation using GNU find command. - * - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. Use Finder instead. - */ -abstract class AbstractFindAdapter extends AbstractAdapter -{ - protected $shell; - - public function __construct() - { - $this->shell = new Shell(); - } - - /** - * {@inheritdoc} - */ - public function searchInDirectory($dir) - { - // having "/../" in path make find fail - $dir = realpath($dir); - - // searching directories containing or not containing strings leads to no result - if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) { - return new Iterator\FilePathsIterator(array(), $dir); - } - - $command = Command::create(); - $find = $this->buildFindCommand($command, $dir); - - if ($this->followLinks) { - $find->add('-follow'); - } - - $find->add('-mindepth')->add($this->minDepth + 1); - - if (PHP_INT_MAX !== $this->maxDepth) { - $find->add('-maxdepth')->add($this->maxDepth + 1); - } - - if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) { - $find->add('-type d'); - } elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) { - $find->add('-type f'); - } - - $this->buildNamesFiltering($find, $this->names); - $this->buildNamesFiltering($find, $this->notNames, true); - $this->buildPathsFiltering($find, $dir, $this->paths); - $this->buildPathsFiltering($find, $dir, $this->notPaths, true); - $this->buildSizesFiltering($find, $this->sizes); - $this->buildDatesFiltering($find, $this->dates); - - $useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs'); - $useSort = \is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut'); - - if ($useGrep && ($this->contains || $this->notContains)) { - $grep = $command->ins('grep'); - $this->buildContentFiltering($grep, $this->contains); - $this->buildContentFiltering($grep, $this->notContains, true); - } - - if ($useSort) { - $this->buildSorting($command, $this->sort); - } - - $command->setErrorHandler( - $this->ignoreUnreadableDirs - // If directory is unreadable and finder is set to ignore it, `stderr` is ignored. - ? function ($stderr) { } - : function ($stderr) { throw new AccessDeniedException($stderr); } - ); - - $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute()); - $iterator = new Iterator\FilePathsIterator($paths, $dir); - - if ($this->exclude) { - $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude); - } - - if (!$useGrep && ($this->contains || $this->notContains)) { - $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains); - } - - if ($this->filters) { - $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); - } - - if (!$useSort && $this->sort) { - $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort); - $iterator = $iteratorAggregate->getIterator(); - } - - return $iterator; - } - - /** - * {@inheritdoc} - */ - protected function canBeUsed() - { - return $this->shell->testCommand('find'); - } - - /** - * @param Command $command - * @param string $dir - * - * @return Command - */ - protected function buildFindCommand(Command $command, $dir) - { - return $command - ->ins('find') - ->add('find ') - ->arg($dir) - ->add('-noleaf'); // the -noleaf option is required for filesystems that don't follow the '.' and '..' conventions - } - - /** - * @param Command $command - * @param string[] $names - * @param bool $not - */ - private function buildNamesFiltering(Command $command, array $names, $not = false) - { - if (0 === \count($names)) { - return; - } - - $command->add($not ? '-not' : null)->cmd('('); - - foreach ($names as $i => $name) { - $expr = Expression::create($name); - - // Find does not support expandable globs ("*.{a,b}" syntax). - if ($expr->isGlob() && $expr->getGlob()->isExpandable()) { - $expr = Expression::create($expr->getGlob()->toRegex(false)); - } - - // Fixes 'not search' and 'full path matching' regex problems. - // - Jokers '.' are replaced by [^/]. - // - We add '[^/]*' before and after regex (if no ^|$ flags are present). - if ($expr->isRegex()) { - $regex = $expr->getRegex(); - $regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*') - ->setStartFlag(false) - ->setStartJoker(true) - ->replaceJokers('[^/]'); - if (!$regex->hasEndFlag() || $regex->hasEndJoker()) { - $regex->setEndJoker(false)->append('[^/]*'); - } - } - - $command - ->add($i > 0 ? '-or' : null) - ->add($expr->isRegex() - ? ($expr->isCaseSensitive() ? '-regex' : '-iregex') - : ($expr->isCaseSensitive() ? '-name' : '-iname') - ) - ->arg($expr->renderPattern()); - } - - $command->cmd(')'); - } - - /** - * @param Command $command - * @param string $dir - * @param string[] $paths - * @param bool $not - */ - private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false) - { - if (0 === \count($paths)) { - return; - } - - $command->add($not ? '-not' : null)->cmd('('); - - foreach ($paths as $i => $path) { - $expr = Expression::create($path); - - // Find does not support expandable globs ("*.{a,b}" syntax). - if ($expr->isGlob() && $expr->getGlob()->isExpandable()) { - $expr = Expression::create($expr->getGlob()->toRegex(false)); - } - - // Fixes 'not search' regex problems. - if ($expr->isRegex()) { - $regex = $expr->getRegex(); - $regex->prepend($regex->hasStartFlag() ? preg_quote($dir).\DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag()); - } else { - $expr->prepend('*')->append('*'); - } - - $command - ->add($i > 0 ? '-or' : null) - ->add($expr->isRegex() - ? ($expr->isCaseSensitive() ? '-regex' : '-iregex') - : ($expr->isCaseSensitive() ? '-path' : '-ipath') - ) - ->arg($expr->renderPattern()); - } - - $command->cmd(')'); - } - - /** - * @param Command $command - * @param NumberComparator[] $sizes - */ - private function buildSizesFiltering(Command $command, array $sizes) - { - foreach ($sizes as $i => $size) { - $command->add($i > 0 ? '-and' : null); - - switch ($size->getOperator()) { - case '<=': - $command->add('-size -'.($size->getTarget() + 1).'c'); - break; - case '>=': - $command->add('-size +'.($size->getTarget() - 1).'c'); - break; - case '>': - $command->add('-size +'.$size->getTarget().'c'); - break; - case '!=': - $command->add('-size -'.$size->getTarget().'c'); - $command->add('-size +'.$size->getTarget().'c'); - break; - case '<': - default: - $command->add('-size -'.$size->getTarget().'c'); - } - } - } - - /** - * @param Command $command - * @param DateComparator[] $dates - */ - private function buildDatesFiltering(Command $command, array $dates) - { - foreach ($dates as $i => $date) { - $command->add($i > 0 ? '-and' : null); - - $mins = (int) round((time() - $date->getTarget()) / 60); - - if (0 > $mins) { - // mtime is in the future - $command->add(' -mmin -0'); - // we will have no result so we don't need to continue - return; - } - - switch ($date->getOperator()) { - case '<=': - $command->add('-mmin +'.($mins - 1)); - break; - case '>=': - $command->add('-mmin -'.($mins + 1)); - break; - case '>': - $command->add('-mmin -'.$mins); - break; - case '!=': - $command->add('-mmin +'.$mins.' -or -mmin -'.$mins); - break; - case '<': - default: - $command->add('-mmin +'.$mins); - } - } - } - - /** - * @param Command $command - * @param string $sort - * - * @throws \InvalidArgumentException - */ - private function buildSorting(Command $command, $sort) - { - $this->buildFormatSorting($command, $sort); - } - - /** - * @param Command $command - * @param string $sort - */ - abstract protected function buildFormatSorting(Command $command, $sort); - - /** - * @param Command $command - * @param array $contains - * @param bool $not - */ - abstract protected function buildContentFiltering(Command $command, array $contains, $not = false); -} diff --git a/vendor/symfony/finder/Adapter/AdapterInterface.php b/vendor/symfony/finder/Adapter/AdapterInterface.php deleted file mode 100644 index 8d8fb07..0000000 --- a/vendor/symfony/finder/Adapter/AdapterInterface.php +++ /dev/null @@ -1,124 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Adapter; - -/** - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. - */ -interface AdapterInterface -{ - /** - * @param bool $followLinks - * - * @return $this - */ - public function setFollowLinks($followLinks); - - /** - * @param int $mode - * - * @return $this - */ - public function setMode($mode); - - /** - * @return $this - */ - public function setExclude(array $exclude); - - /** - * @return $this - */ - public function setDepths(array $depths); - - /** - * @return $this - */ - public function setNames(array $names); - - /** - * @return $this - */ - public function setNotNames(array $notNames); - - /** - * @return $this - */ - public function setContains(array $contains); - - /** - * @return $this - */ - public function setNotContains(array $notContains); - - /** - * @return $this - */ - public function setSizes(array $sizes); - - /** - * @return $this - */ - public function setDates(array $dates); - - /** - * @return $this - */ - public function setFilters(array $filters); - - /** - * @param \Closure|int $sort - * - * @return $this - */ - public function setSort($sort); - - /** - * @return $this - */ - public function setPath(array $paths); - - /** - * @return $this - */ - public function setNotPath(array $notPaths); - - /** - * @param bool $ignore - * - * @return $this - */ - public function ignoreUnreadableDirs($ignore = true); - - /** - * @param string $dir - * - * @return \Iterator Result iterator - */ - public function searchInDirectory($dir); - - /** - * Tests adapter support for current platform. - * - * @return bool - */ - public function isSupported(); - - /** - * Returns adapter name. - * - * @return string - */ - public function getName(); -} diff --git a/vendor/symfony/finder/Adapter/BsdFindAdapter.php b/vendor/symfony/finder/Adapter/BsdFindAdapter.php deleted file mode 100644 index f6e4303..0000000 --- a/vendor/symfony/finder/Adapter/BsdFindAdapter.php +++ /dev/null @@ -1,107 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Adapter; - -@trigger_error('The '.__NAMESPACE__.'\BsdFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED); - -use Symfony\Component\Finder\Expression\Expression; -use Symfony\Component\Finder\Iterator\SortableIterator; -use Symfony\Component\Finder\Shell\Command; -use Symfony\Component\Finder\Shell\Shell; - -/** - * Shell engine implementation using BSD find command. - * - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. Use Finder instead. - */ -class BsdFindAdapter extends AbstractFindAdapter -{ - /** - * {@inheritdoc} - */ - public function getName() - { - return 'bsd_find'; - } - - /** - * {@inheritdoc} - */ - protected function canBeUsed() - { - return \in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed(); - } - - /** - * {@inheritdoc} - */ - protected function buildFormatSorting(Command $command, $sort) - { - switch ($sort) { - case SortableIterator::SORT_BY_NAME: - $command->ins('sort')->add('| sort'); - - return; - case SortableIterator::SORT_BY_TYPE: - $format = '%HT'; - break; - case SortableIterator::SORT_BY_ACCESSED_TIME: - $format = '%a'; - break; - case SortableIterator::SORT_BY_CHANGED_TIME: - $format = '%c'; - break; - case SortableIterator::SORT_BY_MODIFIED_TIME: - $format = '%m'; - break; - default: - throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort)); - } - - $command - ->add('-print0 | xargs -0 stat -f') - ->arg($format.'%t%N') - ->add('| sort | cut -f 2'); - } - - /** - * {@inheritdoc} - */ - protected function buildFindCommand(Command $command, $dir) - { - parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1); - - return $command; - } - - /** - * {@inheritdoc} - */ - protected function buildContentFiltering(Command $command, array $contains, $not = false) - { - foreach ($contains as $contain) { - $expr = Expression::create($contain); - - // todo: avoid forking process for each $pattern by using multiple -e options - $command - ->add('| grep -v \'^$\'') - ->add('| xargs -I{} grep -I') - ->add($expr->isCaseSensitive() ? null : '-i') - ->add($not ? '-L' : '-l') - ->add('-Ee')->arg($expr->renderPattern()) - ->add('{}') - ; - } - } -} diff --git a/vendor/symfony/finder/Adapter/GnuFindAdapter.php b/vendor/symfony/finder/Adapter/GnuFindAdapter.php deleted file mode 100644 index 140c566..0000000 --- a/vendor/symfony/finder/Adapter/GnuFindAdapter.php +++ /dev/null @@ -1,108 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Adapter; - -@trigger_error('The '.__NAMESPACE__.'\GnuFindAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED); - -use Symfony\Component\Finder\Expression\Expression; -use Symfony\Component\Finder\Iterator\SortableIterator; -use Symfony\Component\Finder\Shell\Command; -use Symfony\Component\Finder\Shell\Shell; - -/** - * Shell engine implementation using GNU find command. - * - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. Use Finder instead. - */ -class GnuFindAdapter extends AbstractFindAdapter -{ - /** - * {@inheritdoc} - */ - public function getName() - { - return 'gnu_find'; - } - - /** - * {@inheritdoc} - */ - protected function buildFormatSorting(Command $command, $sort) - { - switch ($sort) { - case SortableIterator::SORT_BY_NAME: - $command->ins('sort')->add('| sort'); - - return; - case SortableIterator::SORT_BY_TYPE: - $format = '%y'; - break; - case SortableIterator::SORT_BY_ACCESSED_TIME: - $format = '%A@'; - break; - case SortableIterator::SORT_BY_CHANGED_TIME: - $format = '%C@'; - break; - case SortableIterator::SORT_BY_MODIFIED_TIME: - $format = '%T@'; - break; - default: - throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort)); - } - - $command - ->get('find') - ->add('-printf') - ->arg($format.' %h/%f\\n') - ->add('| sort | cut') - ->arg('-d ') - ->arg('-f2-') - ; - } - - /** - * {@inheritdoc} - */ - protected function canBeUsed() - { - return Shell::TYPE_UNIX === $this->shell->getType() && parent::canBeUsed(); - } - - /** - * {@inheritdoc} - */ - protected function buildFindCommand(Command $command, $dir) - { - return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended'); - } - - /** - * {@inheritdoc} - */ - protected function buildContentFiltering(Command $command, array $contains, $not = false) - { - foreach ($contains as $contain) { - $expr = Expression::create($contain); - - // todo: avoid forking process for each $pattern by using multiple -e options - $command - ->add('| xargs -I{} -r grep -I') - ->add($expr->isCaseSensitive() ? null : '-i') - ->add($not ? '-L' : '-l') - ->add('-Ee')->arg($expr->renderPattern()) - ->add('{}') - ; - } - } -} diff --git a/vendor/symfony/finder/Adapter/PhpAdapter.php b/vendor/symfony/finder/Adapter/PhpAdapter.php deleted file mode 100644 index c2fb66c..0000000 --- a/vendor/symfony/finder/Adapter/PhpAdapter.php +++ /dev/null @@ -1,101 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Adapter; - -@trigger_error('The '.__NAMESPACE__.'\PhpAdapter class is deprecated since Symfony 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED); - -use Symfony\Component\Finder\Iterator; - -/** - * PHP finder engine implementation. - * - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. Use Finder instead. - */ -class PhpAdapter extends AbstractAdapter -{ - /** - * {@inheritdoc} - */ - public function searchInDirectory($dir) - { - $flags = \RecursiveDirectoryIterator::SKIP_DOTS; - - if ($this->followLinks) { - $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS; - } - - $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); - - if ($this->exclude) { - $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude); - } - - $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); - - if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) { - $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth); - } - - if ($this->mode) { - $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode); - } - - if ($this->names || $this->notNames) { - $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames); - } - - if ($this->contains || $this->notContains) { - $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains); - } - - if ($this->sizes) { - $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes); - } - - if ($this->dates) { - $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates); - } - - if ($this->filters) { - $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); - } - - if ($this->paths || $this->notPaths) { - $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths); - } - - if ($this->sort) { - $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort); - $iterator = $iteratorAggregate->getIterator(); - } - - return $iterator; - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'php'; - } - - /** - * {@inheritdoc} - */ - protected function canBeUsed() - { - return true; - } -} diff --git a/vendor/symfony/finder/Exception/AdapterFailureException.php b/vendor/symfony/finder/Exception/AdapterFailureException.php deleted file mode 100644 index 594940a..0000000 --- a/vendor/symfony/finder/Exception/AdapterFailureException.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Exception; - -@trigger_error('The '.__NAMESPACE__.'\AdapterFailureException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -use Symfony\Component\Finder\Adapter\AdapterInterface; - -/** - * Base exception for all adapter failures. - * - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. - */ -class AdapterFailureException extends \RuntimeException implements ExceptionInterface -{ - private $adapter; - - /** - * @param AdapterInterface $adapter - * @param string|null $message - * @param \Exception|null $previous - */ - public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null) - { - $this->adapter = $adapter; - parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous); - } - - /** - * {@inheritdoc} - */ - public function getAdapter() - { - return $this->adapter; - } -} diff --git a/vendor/symfony/finder/Exception/OperationNotPermitedException.php b/vendor/symfony/finder/Exception/OperationNotPermitedException.php deleted file mode 100644 index 4c66858..0000000 --- a/vendor/symfony/finder/Exception/OperationNotPermitedException.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Exception; - -@trigger_error('The '.__NAMESPACE__.'\OperationNotPermitedException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -/** - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. - */ -class OperationNotPermitedException extends AdapterFailureException -{ -} diff --git a/vendor/symfony/finder/Exception/ShellCommandFailureException.php b/vendor/symfony/finder/Exception/ShellCommandFailureException.php deleted file mode 100644 index db85e68..0000000 --- a/vendor/symfony/finder/Exception/ShellCommandFailureException.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Exception; - -@trigger_error('The '.__NAMESPACE__.'\ShellCommandFailureException class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -use Symfony\Component\Finder\Adapter\AdapterInterface; -use Symfony\Component\Finder\Shell\Command; - -/** - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. - */ -class ShellCommandFailureException extends AdapterFailureException -{ - private $command; - - public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null) - { - $this->command = $command; - parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous); - } - - /** - * @return Command - */ - public function getCommand() - { - return $this->command; - } -} diff --git a/vendor/symfony/finder/Expression/Expression.php b/vendor/symfony/finder/Expression/Expression.php deleted file mode 100644 index e83c771..0000000 --- a/vendor/symfony/finder/Expression/Expression.php +++ /dev/null @@ -1,148 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Expression; - -@trigger_error('The '.__NAMESPACE__.'\Expression class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -/** - * @author Jean-François Simon - */ -class Expression implements ValueInterface -{ - const TYPE_REGEX = 1; - const TYPE_GLOB = 2; - - /** - * @var ValueInterface - */ - private $value; - - /** - * @param string $expr - * - * @return self - */ - public static function create($expr) - { - return new self($expr); - } - - /** - * @param string $expr - */ - public function __construct($expr) - { - try { - $this->value = Regex::create($expr); - } catch (\InvalidArgumentException $e) { - $this->value = new Glob($expr); - } - } - - /** - * @return string - */ - public function __toString() - { - return $this->render(); - } - - /** - * {@inheritdoc} - */ - public function render() - { - return $this->value->render(); - } - - /** - * {@inheritdoc} - */ - public function renderPattern() - { - return $this->value->renderPattern(); - } - - /** - * @return bool - */ - public function isCaseSensitive() - { - return $this->value->isCaseSensitive(); - } - - /** - * @return int - */ - public function getType() - { - return $this->value->getType(); - } - - /** - * {@inheritdoc} - */ - public function prepend($expr) - { - $this->value->prepend($expr); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function append($expr) - { - $this->value->append($expr); - - return $this; - } - - /** - * @return bool - */ - public function isRegex() - { - return self::TYPE_REGEX === $this->value->getType(); - } - - /** - * @return bool - */ - public function isGlob() - { - return self::TYPE_GLOB === $this->value->getType(); - } - - /** - * @return Glob - * - * @throws \LogicException - */ - public function getGlob() - { - if (self::TYPE_GLOB !== $this->value->getType()) { - throw new \LogicException('Regex can\'t be transformed to glob.'); - } - - return $this->value; - } - - /** - * @return Regex - */ - public function getRegex() - { - return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex(); - } -} diff --git a/vendor/symfony/finder/Expression/Glob.php b/vendor/symfony/finder/Expression/Glob.php deleted file mode 100644 index e80578e..0000000 --- a/vendor/symfony/finder/Expression/Glob.php +++ /dev/null @@ -1,108 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Expression; - -@trigger_error('The '.__NAMESPACE__.'\Glob class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -use Symfony\Component\Finder\Glob as FinderGlob; - -/** - * @author Jean-François Simon - */ -class Glob implements ValueInterface -{ - private $pattern; - - /** - * @param string $pattern - */ - public function __construct($pattern) - { - $this->pattern = $pattern; - } - - /** - * {@inheritdoc} - */ - public function render() - { - return $this->pattern; - } - - /** - * {@inheritdoc} - */ - public function renderPattern() - { - return $this->pattern; - } - - /** - * {@inheritdoc} - */ - public function getType() - { - return Expression::TYPE_GLOB; - } - - /** - * {@inheritdoc} - */ - public function isCaseSensitive() - { - return true; - } - - /** - * {@inheritdoc} - */ - public function prepend($expr) - { - $this->pattern = $expr.$this->pattern; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function append($expr) - { - $this->pattern .= $expr; - - return $this; - } - - /** - * Tests if glob is expandable ("*.{a,b}" syntax). - * - * @return bool - */ - public function isExpandable() - { - return false !== strpos($this->pattern, '{') - && false !== strpos($this->pattern, '}'); - } - - /** - * @param bool $strictLeadingDot - * @param bool $strictWildcardSlash - * - * @return Regex - */ - public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true) - { - $regex = FinderGlob::toRegex($this->pattern, $strictLeadingDot, $strictWildcardSlash, ''); - - return new Regex($regex); - } -} diff --git a/vendor/symfony/finder/Expression/Regex.php b/vendor/symfony/finder/Expression/Regex.php deleted file mode 100644 index 2f1ab3d..0000000 --- a/vendor/symfony/finder/Expression/Regex.php +++ /dev/null @@ -1,321 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Expression; - -@trigger_error('The '.__NAMESPACE__.'\Regex class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -/** - * @author Jean-François Simon - */ -class Regex implements ValueInterface -{ - const START_FLAG = '^'; - const END_FLAG = '$'; - const BOUNDARY = '~'; - const JOKER = '.*'; - const ESCAPING = '\\'; - - /** - * @var string - */ - private $pattern; - - /** - * @var string - */ - private $options; - - /** - * @var bool - */ - private $startFlag; - - /** - * @var bool - */ - private $endFlag; - - /** - * @var bool - */ - private $startJoker; - - /** - * @var bool - */ - private $endJoker; - - /** - * @param string $expr - * - * @return self - * - * @throws \InvalidArgumentException - */ - public static function create($expr) - { - if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) { - $start = substr($m[1], 0, 1); - $end = substr($m[1], -1); - - if ( - ($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start)) - || ('{' === $start && '}' === $end) - || ('(' === $start && ')' === $end) - ) { - return new self(substr($m[1], 1, -1), $m[2], $end); - } - } - - throw new \InvalidArgumentException('Given expression is not a regex.'); - } - - /** - * @param string $pattern - * @param string $options - * @param string $delimiter - */ - public function __construct($pattern, $options = '', $delimiter = null) - { - if (null !== $delimiter) { - // removes delimiter escaping - $pattern = str_replace('\\'.$delimiter, $delimiter, $pattern); - } - - $this->parsePattern($pattern); - $this->options = $options; - } - - /** - * @return string - */ - public function __toString() - { - return $this->render(); - } - - /** - * {@inheritdoc} - */ - public function render() - { - return self::BOUNDARY - .$this->renderPattern() - .self::BOUNDARY - .$this->options; - } - - /** - * {@inheritdoc} - */ - public function renderPattern() - { - return ($this->startFlag ? self::START_FLAG : '') - .($this->startJoker ? self::JOKER : '') - .str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern) - .($this->endJoker ? self::JOKER : '') - .($this->endFlag ? self::END_FLAG : ''); - } - - /** - * {@inheritdoc} - */ - public function isCaseSensitive() - { - return !$this->hasOption('i'); - } - - /** - * {@inheritdoc} - */ - public function getType() - { - return Expression::TYPE_REGEX; - } - - /** - * {@inheritdoc} - */ - public function prepend($expr) - { - $this->pattern = $expr.$this->pattern; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function append($expr) - { - $this->pattern .= $expr; - - return $this; - } - - /** - * @param string $option - * - * @return bool - */ - public function hasOption($option) - { - return false !== strpos($this->options, $option); - } - - /** - * @param string $option - * - * @return $this - */ - public function addOption($option) - { - if (!$this->hasOption($option)) { - $this->options .= $option; - } - - return $this; - } - - /** - * @param string $option - * - * @return $this - */ - public function removeOption($option) - { - $this->options = str_replace($option, '', $this->options); - - return $this; - } - - /** - * @param bool $startFlag - * - * @return $this - */ - public function setStartFlag($startFlag) - { - $this->startFlag = $startFlag; - - return $this; - } - - /** - * @return bool - */ - public function hasStartFlag() - { - return $this->startFlag; - } - - /** - * @param bool $endFlag - * - * @return $this - */ - public function setEndFlag($endFlag) - { - $this->endFlag = (bool) $endFlag; - - return $this; - } - - /** - * @return bool - */ - public function hasEndFlag() - { - return $this->endFlag; - } - - /** - * @param bool $startJoker - * - * @return $this - */ - public function setStartJoker($startJoker) - { - $this->startJoker = $startJoker; - - return $this; - } - - /** - * @return bool - */ - public function hasStartJoker() - { - return $this->startJoker; - } - - /** - * @param bool $endJoker - * - * @return $this - */ - public function setEndJoker($endJoker) - { - $this->endJoker = (bool) $endJoker; - - return $this; - } - - /** - * @return bool - */ - public function hasEndJoker() - { - return $this->endJoker; - } - - /** - * @return $this - */ - public function replaceJokers($replacement) - { - $replace = function ($subject) use ($replacement) { - $subject = $subject[0]; - $replace = 0 === substr_count($subject, '\\') % 2; - - return $replace ? str_replace('.', $replacement, $subject) : $subject; - }; - - $this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern); - - return $this; - } - - /** - * @param string $pattern - */ - private function parsePattern($pattern) - { - if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) { - $pattern = substr($pattern, 1); - } - - if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) { - $pattern = substr($pattern, 2); - } - - if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) { - $pattern = substr($pattern, 0, -1); - } - - if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) { - $pattern = substr($pattern, 0, -2); - } - - $this->pattern = $pattern; - } -} diff --git a/vendor/symfony/finder/Expression/ValueInterface.php b/vendor/symfony/finder/Expression/ValueInterface.php deleted file mode 100644 index 08ede14..0000000 --- a/vendor/symfony/finder/Expression/ValueInterface.php +++ /dev/null @@ -1,62 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Expression; - -@trigger_error('The '.__NAMESPACE__.'\ValueInterface interface is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -/** - * @author Jean-François Simon - */ -interface ValueInterface -{ - /** - * Renders string representation of expression. - * - * @return string - */ - public function render(); - - /** - * Renders string representation of pattern. - * - * @return string - */ - public function renderPattern(); - - /** - * Returns value case sensitivity. - * - * @return bool - */ - public function isCaseSensitive(); - - /** - * Returns expression type. - * - * @return int - */ - public function getType(); - - /** - * @param string $expr - * - * @return $this - */ - public function prepend($expr); - - /** - * @param string $expr - * - * @return $this - */ - public function append($expr); -} diff --git a/vendor/symfony/finder/Iterator/FilePathsIterator.php b/vendor/symfony/finder/Iterator/FilePathsIterator.php deleted file mode 100644 index 9c4e5c4..0000000 --- a/vendor/symfony/finder/Iterator/FilePathsIterator.php +++ /dev/null @@ -1,135 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -@trigger_error('The '.__NAMESPACE__.'\FilePathsIterator class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -use Symfony\Component\Finder\SplFileInfo; - -/** - * Iterate over shell command result. - * - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. - */ -class FilePathsIterator extends \ArrayIterator -{ - /** - * @var string - */ - private $baseDir; - - /** - * @var int - */ - private $baseDirLength; - - /** - * @var string - */ - private $subPath; - - /** - * @var string - */ - private $subPathname; - - /** - * @var SplFileInfo - */ - private $current; - - /** - * @param array $paths List of paths returned by shell command - * @param string $baseDir Base dir for relative path building - */ - public function __construct(array $paths, $baseDir) - { - $this->baseDir = $baseDir; - $this->baseDirLength = \strlen($baseDir); - - parent::__construct($paths); - } - - /** - * @param string $name - * @param array $arguments - * - * @return mixed - */ - public function __call($name, array $arguments) - { - return \call_user_func_array(array($this->current(), $name), $arguments); - } - - /** - * Return an instance of SplFileInfo with support for relative paths. - * - * @return SplFileInfo File information - */ - public function current() - { - return $this->current; - } - - /** - * @return string - */ - public function key() - { - return $this->current->getPathname(); - } - - public function next() - { - parent::next(); - $this->buildProperties(); - } - - public function rewind() - { - parent::rewind(); - $this->buildProperties(); - } - - /** - * @return string - */ - public function getSubPath() - { - return $this->subPath; - } - - /** - * @return string - */ - public function getSubPathname() - { - return $this->subPathname; - } - - private function buildProperties() - { - $absolutePath = parent::current(); - - if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) { - $this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\'); - $dir = \dirname($this->subPathname); - $this->subPath = '.' === $dir ? '' : $dir; - } else { - $this->subPath = $this->subPathname = ''; - } - - $this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname); - } -} diff --git a/vendor/symfony/finder/Shell/Command.php b/vendor/symfony/finder/Shell/Command.php deleted file mode 100644 index 8219078..0000000 --- a/vendor/symfony/finder/Shell/Command.php +++ /dev/null @@ -1,278 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Shell; - -@trigger_error('The '.__NAMESPACE__.'\Command class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -/** - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. - */ -class Command -{ - private $parent; - private $bits = array(); - private $labels = array(); - - /** - * @var \Closure|null - */ - private $errorHandler; - - public function __construct(Command $parent = null) - { - $this->parent = $parent; - } - - /** - * Returns command as string. - * - * @return string - */ - public function __toString() - { - return $this->join(); - } - - /** - * Creates a new Command instance. - * - * @return self - */ - public static function create(Command $parent = null) - { - return new self($parent); - } - - /** - * Escapes special chars from input. - * - * @param string $input A string to escape - * - * @return string The escaped string - */ - public static function escape($input) - { - return escapeshellcmd($input); - } - - /** - * Quotes input. - * - * @param string $input An argument string - * - * @return string The quoted string - */ - public static function quote($input) - { - return escapeshellarg($input); - } - - /** - * Appends a string or a Command instance. - * - * @param string|Command $bit - * - * @return $this - */ - public function add($bit) - { - $this->bits[] = $bit; - - return $this; - } - - /** - * Prepends a string or a command instance. - * - * @param string|Command $bit - * - * @return $this - */ - public function top($bit) - { - array_unshift($this->bits, $bit); - - foreach ($this->labels as $label => $index) { - ++$this->labels[$label]; - } - - return $this; - } - - /** - * Appends an argument, will be quoted. - * - * @param string $arg - * - * @return $this - */ - public function arg($arg) - { - $this->bits[] = self::quote($arg); - - return $this; - } - - /** - * Appends escaped special command chars. - * - * @param string $esc - * - * @return $this - */ - public function cmd($esc) - { - $this->bits[] = self::escape($esc); - - return $this; - } - - /** - * Inserts a labeled command to feed later. - * - * @param string $label The unique label - * - * @return self|string - * - * @throws \RuntimeException If label already exists - */ - public function ins($label) - { - if (isset($this->labels[$label])) { - throw new \RuntimeException(sprintf('Label "%s" already exists.', $label)); - } - - $this->bits[] = self::create($this); - $this->labels[$label] = \count($this->bits) - 1; - - return $this->bits[$this->labels[$label]]; - } - - /** - * Retrieves a previously labeled command. - * - * @param string $label - * - * @return self|string - * - * @throws \RuntimeException - */ - public function get($label) - { - if (!isset($this->labels[$label])) { - throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label)); - } - - return $this->bits[$this->labels[$label]]; - } - - /** - * Returns parent command (if any). - * - * @return self - * - * @throws \RuntimeException If command has no parent - */ - public function end() - { - if (null === $this->parent) { - throw new \RuntimeException('Calling end on root command doesn\'t make sense.'); - } - - return $this->parent; - } - - /** - * Counts bits stored in command. - * - * @return int The bits count - */ - public function length() - { - return \count($this->bits); - } - - /** - * @return $this - */ - public function setErrorHandler(\Closure $errorHandler) - { - $this->errorHandler = $errorHandler; - - return $this; - } - - /** - * @return \Closure|null - */ - public function getErrorHandler() - { - return $this->errorHandler; - } - - /** - * Executes current command. - * - * @return array The command result - * - * @throws \RuntimeException - */ - public function execute() - { - if (null === $errorHandler = $this->errorHandler) { - exec($this->join(), $output); - } else { - $process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes); - $output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY); - - if ($error = stream_get_contents($pipes[2])) { - $errorHandler($error); - } - - proc_close($process); - } - - return $output ?: array(); - } - - /** - * Joins bits. - * - * @return string - */ - public function join() - { - return implode(' ', array_filter( - array_map(function ($bit) { - return $bit instanceof Command ? $bit->join() : ($bit ?: null); - }, $this->bits), - function ($bit) { return null !== $bit; } - )); - } - - /** - * Insert a string or a Command instance before the bit at given position $index (index starts from 0). - * - * @param string|Command $bit - * @param int $index - * - * @return $this - */ - public function addAtIndex($bit, $index) - { - array_splice($this->bits, $index, 0, $bit instanceof self ? array($bit) : $bit); - - return $this; - } -} diff --git a/vendor/symfony/finder/Shell/Shell.php b/vendor/symfony/finder/Shell/Shell.php deleted file mode 100644 index fa6ca4b..0000000 --- a/vendor/symfony/finder/Shell/Shell.php +++ /dev/null @@ -1,101 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Shell; - -@trigger_error('The '.__NAMESPACE__.'\Shell class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED); - -/** - * @author Jean-François Simon - * - * @deprecated since 2.8, to be removed in 3.0. - */ -class Shell -{ - const TYPE_UNIX = 1; - const TYPE_DARWIN = 2; - const TYPE_CYGWIN = 3; - const TYPE_WINDOWS = 4; - const TYPE_BSD = 5; - - /** - * @var string|null - */ - private $type; - - /** - * Returns guessed OS type. - * - * @return int - */ - public function getType() - { - if (null === $this->type) { - $this->type = $this->guessType(); - } - - return $this->type; - } - - /** - * Tests if a command is available. - * - * @param string $command - * - * @return bool - */ - public function testCommand($command) - { - if (!\function_exists('exec')) { - return false; - } - - // todo: find a better way (command could not be available) - $testCommand = 'which '; - if (self::TYPE_WINDOWS === $this->type) { - $testCommand = 'where '; - } - - $command = escapeshellcmd($command); - - exec($testCommand.$command, $output, $code); - - return 0 === $code && \count($output) > 0; - } - - /** - * Guesses OS type. - * - * @return int - */ - private function guessType() - { - $os = strtolower(PHP_OS); - - if (false !== strpos($os, 'cygwin')) { - return self::TYPE_CYGWIN; - } - - if (false !== strpos($os, 'darwin')) { - return self::TYPE_DARWIN; - } - - if (false !== strpos($os, 'bsd')) { - return self::TYPE_BSD; - } - - if (0 === strpos($os, 'win')) { - return self::TYPE_WINDOWS; - } - - return self::TYPE_UNIX; - } -} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/LegacyPdoSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/LegacyPdoSessionHandler.php deleted file mode 100644 index ea11d60..0000000 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/LegacyPdoSessionHandler.php +++ /dev/null @@ -1,268 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; - -@trigger_error('The '.__NAMESPACE__.'\LegacyPdoSessionHandler class is deprecated since Symfony 2.6 and will be removed in 3.0. Use the Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler class instead.', E_USER_DEPRECATED); - -/** - * Session handler using a PDO connection to read and write data. - * - * Session data is a binary string that can contain non-printable characters like the null byte. - * For this reason this handler base64 encodes the data to be able to save it in a character column. - * - * This version of the PdoSessionHandler does NOT implement locking. So concurrent requests to the - * same session can result in data loss due to race conditions. - * - * @author Fabien Potencier - * @author Michael Williams - * @author Tobias Schultze - * - * @deprecated since version 2.6, to be removed in 3.0. Use - * {@link PdoSessionHandler} instead. - */ -class LegacyPdoSessionHandler implements \SessionHandlerInterface -{ - private $pdo; - - /** - * @var string Table name - */ - private $table; - - /** - * @var string Column for session id - */ - private $idCol; - - /** - * @var string Column for session data - */ - private $dataCol; - - /** - * @var string Column for timestamp - */ - private $timeCol; - - /** - * Constructor. - * - * List of available options: - * * db_table: The name of the table [required] - * * db_id_col: The column where to store the session id [default: sess_id] - * * db_data_col: The column where to store the session data [default: sess_data] - * * db_time_col: The column where to store the timestamp [default: sess_time] - * - * @param \PDO $pdo A \PDO instance - * @param array $dbOptions An associative array of DB options - * - * @throws \InvalidArgumentException When "db_table" option is not provided - */ - public function __construct(\PDO $pdo, array $dbOptions = array()) - { - if (!array_key_exists('db_table', $dbOptions)) { - throw new \InvalidArgumentException('You must provide the "db_table" option for a PdoSessionStorage.'); - } - if (\PDO::ERRMODE_EXCEPTION !== $pdo->getAttribute(\PDO::ATTR_ERRMODE)) { - throw new \InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION))', __CLASS__)); - } - - $this->pdo = $pdo; - $dbOptions = array_merge(array( - 'db_id_col' => 'sess_id', - 'db_data_col' => 'sess_data', - 'db_time_col' => 'sess_time', - ), $dbOptions); - - $this->table = $dbOptions['db_table']; - $this->idCol = $dbOptions['db_id_col']; - $this->dataCol = $dbOptions['db_data_col']; - $this->timeCol = $dbOptions['db_time_col']; - } - - /** - * {@inheritdoc} - */ - public function open($savePath, $sessionName) - { - return true; - } - - /** - * {@inheritdoc} - */ - public function close() - { - return true; - } - - /** - * {@inheritdoc} - */ - public function destroy($sessionId) - { - // delete the record associated with this id - $sql = "DELETE FROM $this->table WHERE $this->idCol = :id"; - - try { - $stmt = $this->pdo->prepare($sql); - $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $stmt->execute(); - } catch (\PDOException $e) { - throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e); - } - - return true; - } - - /** - * {@inheritdoc} - */ - public function gc($maxlifetime) - { - // delete the session records that have expired - $sql = "DELETE FROM $this->table WHERE $this->timeCol < :time"; - - try { - $stmt = $this->pdo->prepare($sql); - $stmt->bindValue(':time', time() - $maxlifetime, \PDO::PARAM_INT); - $stmt->execute(); - } catch (\PDOException $e) { - throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e); - } - - return true; - } - - /** - * {@inheritdoc} - */ - public function read($sessionId) - { - $sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id"; - - try { - $stmt = $this->pdo->prepare($sql); - $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $stmt->execute(); - - // We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed - $sessionRows = $stmt->fetchAll(\PDO::FETCH_NUM); - - if ($sessionRows) { - return base64_decode($sessionRows[0][0]); - } - - return ''; - } catch (\PDOException $e) { - throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e); - } - } - - /** - * {@inheritdoc} - */ - public function write($sessionId, $data) - { - $encoded = base64_encode($data); - - try { - // We use a single MERGE SQL query when supported by the database. - $mergeSql = $this->getMergeSql(); - - if (null !== $mergeSql) { - $mergeStmt = $this->pdo->prepare($mergeSql); - $mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); - $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT); - $mergeStmt->execute(); - - return true; - } - - $updateStmt = $this->pdo->prepare( - "UPDATE $this->table SET $this->dataCol = :data, $this->timeCol = :time WHERE $this->idCol = :id" - ); - $updateStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $updateStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); - $updateStmt->bindValue(':time', time(), \PDO::PARAM_INT); - $updateStmt->execute(); - - // When MERGE is not supported, like in Postgres, we have to use this approach that can result in - // duplicate key errors when the same session is written simultaneously. We can just catch such an - // error and re-execute the update. This is similar to a serializable transaction with retry logic - // on serialization failures but without the overhead and without possible false positives due to - // longer gap locking. - if (!$updateStmt->rowCount()) { - try { - $insertStmt = $this->pdo->prepare( - "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)" - ); - $insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR); - $insertStmt->bindValue(':time', time(), \PDO::PARAM_INT); - $insertStmt->execute(); - } catch (\PDOException $e) { - // Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys - if (0 === strpos($e->getCode(), '23')) { - $updateStmt->execute(); - } else { - throw $e; - } - } - } - } catch (\PDOException $e) { - throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e); - } - - return true; - } - - /** - * Returns a merge/upsert (i.e. insert or update) SQL query when supported by the database. - * - * @return string|null The SQL string or null when not supported - */ - private function getMergeSql() - { - $driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); - - switch ($driver) { - case 'mysql': - return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ". - "ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->timeCol = VALUES($this->timeCol)"; - case 'oci': - // DUAL is Oracle specific dummy table - return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) ". - "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ". - "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->timeCol = :time"; - case 'sqlsrv' === $driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='): - // MERGE is only available since SQL Server 2008 and must be terminated by semicolon - // It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx - return "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = :id) ". - "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ". - "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->timeCol = :time;"; - case 'sqlite': - return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"; - } - } - - /** - * Return a PDO instance. - * - * @return \PDO - */ - protected function getConnection() - { - return $this->pdo; - } -} diff --git a/vendor/symfony/http-kernel/Debug/ErrorHandler.php b/vendor/symfony/http-kernel/Debug/ErrorHandler.php deleted file mode 100644 index a9c0178..0000000 --- a/vendor/symfony/http-kernel/Debug/ErrorHandler.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Debug; - -@trigger_error('The '.__NAMESPACE__.'\ErrorHandler class is deprecated since Symfony 2.3 and will be removed in 3.0. Use the Symfony\Component\Debug\ErrorHandler class instead.', E_USER_DEPRECATED); - -use Symfony\Component\Debug\ErrorHandler as DebugErrorHandler; - -/** - * ErrorHandler. - * - * @author Fabien Potencier - * - * @deprecated since version 2.3, to be removed in 3.0. Use the same class from the Debug component instead. - */ -class ErrorHandler extends DebugErrorHandler -{ -} diff --git a/vendor/symfony/http-kernel/Debug/ExceptionHandler.php b/vendor/symfony/http-kernel/Debug/ExceptionHandler.php deleted file mode 100644 index 7a8955d..0000000 --- a/vendor/symfony/http-kernel/Debug/ExceptionHandler.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Debug; - -@trigger_error('The '.__NAMESPACE__.'\ExceptionHandler class is deprecated since Symfony 2.3 and will be removed in 3.0. Use the Symfony\Component\Debug\ExceptionHandler class instead.', E_USER_DEPRECATED); - -use Symfony\Component\Debug\ExceptionHandler as DebugExceptionHandler; - -/** - * ExceptionHandler converts an exception to a Response object. - * - * @author Fabien Potencier - * - * @deprecated since version 2.3, to be removed in 3.0. Use the same class from the Debug component instead. - */ -class ExceptionHandler extends DebugExceptionHandler -{ -} diff --git a/vendor/symfony/http-kernel/DependencyInjection/ContainerAwareHttpKernel.php b/vendor/symfony/http-kernel/DependencyInjection/ContainerAwareHttpKernel.php deleted file mode 100644 index b1db5f3..0000000 --- a/vendor/symfony/http-kernel/DependencyInjection/ContainerAwareHttpKernel.php +++ /dev/null @@ -1,85 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\DependencyInjection; - -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Scope; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; -use Symfony\Component\HttpKernel\HttpKernel; -use Symfony\Component\HttpKernel\HttpKernelInterface; - -/** - * Adds a managed request scope. - * - * @author Fabien Potencier - * @author Johannes M. Schmitt - * - * @deprecated since version 2.7, to be removed in 3.0. - */ -class ContainerAwareHttpKernel extends HttpKernel -{ - protected $container; - - /** - * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance - * @param ContainerInterface $container A ContainerInterface instance - * @param ControllerResolverInterface $controllerResolver A ControllerResolverInterface instance - * @param RequestStack $requestStack A stack for master/sub requests - * @param bool $triggerDeprecation Whether or not to trigger the deprecation warning for the ContainerAwareHttpKernel - */ - public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack = null, $triggerDeprecation = true) - { - parent::__construct($dispatcher, $controllerResolver, $requestStack); - - if ($triggerDeprecation) { - @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.7 and will be removed in 3.0. Use the Symfony\Component\HttpKernel\HttpKernel class instead.', E_USER_DEPRECATED); - } - - $this->container = $container; - - // the request scope might have been created before (see FrameworkBundle) - if (!$container->hasScope('request')) { - $container->addScope(new Scope('request')); - } - } - - /** - * {@inheritdoc} - */ - public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) - { - $this->container->enterScope('request'); - $this->container->set('request', $request, 'request'); - - try { - $response = parent::handle($request, $type, $catch); - } catch (\Exception $e) { - $this->container->set('request', null, 'request'); - $this->container->leaveScope('request'); - - throw $e; - } catch (\Throwable $e) { - $this->container->set('request', null, 'request'); - $this->container->leaveScope('request'); - - throw $e; - } - - $this->container->set('request', null, 'request'); - $this->container->leaveScope('request'); - - return $response; - } -} diff --git a/vendor/symfony/http-kernel/DependencyInjection/RegisterListenersPass.php b/vendor/symfony/http-kernel/DependencyInjection/RegisterListenersPass.php deleted file mode 100644 index 06a2e40..0000000 --- a/vendor/symfony/http-kernel/DependencyInjection/RegisterListenersPass.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\DependencyInjection; - -@trigger_error('The '.__NAMESPACE__.'\RegisterListenersPass is deprecated since Symfony 2.5 and will be removed in 3.0. Use the Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass class instead.', E_USER_DEPRECATED); - -use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass as BaseRegisterListenersPass; - -/** - * Compiler pass to register tagged services for an event dispatcher. - * - * @deprecated since version 2.5, to be removed in 3.0. Use the Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass class instead. - */ -class RegisterListenersPass extends BaseRegisterListenersPass -{ -} diff --git a/vendor/symfony/http-kernel/EventListener/ErrorsLoggerListener.php b/vendor/symfony/http-kernel/EventListener/ErrorsLoggerListener.php deleted file mode 100644 index 10f2d6c..0000000 --- a/vendor/symfony/http-kernel/EventListener/ErrorsLoggerListener.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\EventListener; - -@trigger_error('The '.__NAMESPACE__.'\ErrorsLoggerListener class is deprecated since Symfony 2.6 and will be removed in 3.0. Use the Symfony\Component\HttpKernel\EventListener\DebugHandlersListener class instead.', E_USER_DEPRECATED); - -use Psr\Log\LoggerInterface; -use Symfony\Component\Debug\ErrorHandler; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpKernel\KernelEvents; - -/** - * Injects the logger into the ErrorHandler, so that it can log various errors. - * - * @author Colin Frei - * @author Konstantin Myakshin - * - * @deprecated since version 2.6, to be removed in 3.0. Use the DebugHandlersListener class instead. - */ -class ErrorsLoggerListener implements EventSubscriberInterface -{ - private $channel; - private $logger; - - public function __construct($channel, LoggerInterface $logger = null) - { - $this->channel = $channel; - $this->logger = $logger; - } - - public function injectLogger() - { - if (null !== $this->logger) { - ErrorHandler::setLogger($this->logger, $this->channel); - $this->logger = null; - } - } - - public static function getSubscribedEvents() - { - return array(KernelEvents::REQUEST => array('injectLogger', 2048)); - } -} diff --git a/vendor/symfony/http-kernel/EventListener/EsiListener.php b/vendor/symfony/http-kernel/EventListener/EsiListener.php deleted file mode 100644 index 3deaf65..0000000 --- a/vendor/symfony/http-kernel/EventListener/EsiListener.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\EventListener; - -@trigger_error('The '.__NAMESPACE__.'\EsiListener class is deprecated since Symfony 2.6 and will be removed in 3.0. Use the Symfony\Component\HttpKernel\EventListener\SurrogateListener class instead.', E_USER_DEPRECATED); - -/** - * EsiListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for ESI. - * - * @author Fabien Potencier - * - * @deprecated since version 2.6, to be removed in 3.0. Use SurrogateListener instead - */ -class EsiListener extends SurrogateListener -{ -} diff --git a/vendor/symfony/http-kernel/Exception/FatalErrorException.php b/vendor/symfony/http-kernel/Exception/FatalErrorException.php deleted file mode 100644 index 0360ac0..0000000 --- a/vendor/symfony/http-kernel/Exception/FatalErrorException.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Exception; - -@trigger_error('The '.__NAMESPACE__.'\FatalErrorException class is deprecated since Symfony 2.3 and will be removed in 3.0. Use the Symfony\Component\Debug\Exception\FatalErrorException class instead.', E_USER_DEPRECATED); - -/* - * Fatal Error Exception. - * - * @author Konstanton Myakshin - * - * @deprecated since version 2.3, to be removed in 3.0. Use the same class from the Debug component instead. - */ -class_exists('Symfony\Component\Debug\Exception\FatalErrorException'); diff --git a/vendor/symfony/http-kernel/Exception/FlattenException.php b/vendor/symfony/http-kernel/Exception/FlattenException.php deleted file mode 100644 index 9ef7abb..0000000 --- a/vendor/symfony/http-kernel/Exception/FlattenException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Exception; - -@trigger_error('The '.__NAMESPACE__.'\FlattenException class is deprecated since Symfony 2.3 and will be removed in 3.0. Use the Symfony\Component\Debug\Exception\FlattenException class instead.', E_USER_DEPRECATED); - -/* - * FlattenException wraps a PHP Exception to be able to serialize it. - * - * Basically, this class removes all objects from the trace. - * - * @author Fabien Potencier - * - * @deprecated since version 2.3, to be removed in 3.0. Use the same class from the Debug component instead. - */ -class_exists('Symfony\Component\Debug\Exception\FlattenException'); diff --git a/vendor/symfony/http-kernel/HttpCache/EsiResponseCacheStrategy.php b/vendor/symfony/http-kernel/HttpCache/EsiResponseCacheStrategy.php deleted file mode 100644 index 41096bb..0000000 --- a/vendor/symfony/http-kernel/HttpCache/EsiResponseCacheStrategy.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * This code is partially based on the Rack-Cache library by Ryan Tomayko, - * which is released under the MIT license. - * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\HttpCache; - -@trigger_error('The '.__NAMESPACE__.'\EsiResponseCacheStrategy class is deprecated since Symfony 2.6 and will be removed in 3.0. Use the Symfony\Component\HttpKernel\HttpCache\ResponseCacheStrategy class instead.', E_USER_DEPRECATED); - -/** - * EsiResponseCacheStrategy knows how to compute the Response cache HTTP header - * based on the different ESI response cache headers. - * - * This implementation changes the master response TTL to the smallest TTL received - * or force validation if one of the ESI has validation cache strategy. - * - * @author Fabien Potencier - * - * @deprecated since version 2.6, to be removed in 3.0. Use ResponseCacheStrategy instead - */ -class EsiResponseCacheStrategy extends ResponseCacheStrategy implements EsiResponseCacheStrategyInterface -{ -} diff --git a/vendor/symfony/http-kernel/HttpCache/EsiResponseCacheStrategyInterface.php b/vendor/symfony/http-kernel/HttpCache/EsiResponseCacheStrategyInterface.php deleted file mode 100644 index 5388e99..0000000 --- a/vendor/symfony/http-kernel/HttpCache/EsiResponseCacheStrategyInterface.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * This code is partially based on the Rack-Cache library by Ryan Tomayko, - * which is released under the MIT license. - * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\HttpCache; - -/** - * ResponseCacheStrategyInterface implementations know how to compute the - * Response cache HTTP header based on the different response cache headers. - * - * @author Fabien Potencier - * - * @deprecated since version 2.6, to be removed in 3.0. Use ResponseCacheStrategyInterface instead. - */ -interface EsiResponseCacheStrategyInterface extends ResponseCacheStrategyInterface -{ -} diff --git a/vendor/symfony/http-kernel/Log/LoggerInterface.php b/vendor/symfony/http-kernel/Log/LoggerInterface.php deleted file mode 100644 index cad38e5..0000000 --- a/vendor/symfony/http-kernel/Log/LoggerInterface.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Log; - -use Psr\Log\LoggerInterface as PsrLogger; - -/** - * LoggerInterface. - * - * @author Fabien Potencier - * - * @deprecated since version 2.2, to be removed in 3.0. Type-hint \Psr\Log\LoggerInterface instead. - */ -interface LoggerInterface extends PsrLogger -{ - /** - * @deprecated since version 2.2, to be removed in 3.0. Use emergency() which is PSR-3 compatible. - */ - public function emerg($message, array $context = array()); - - /** - * @deprecated since version 2.2, to be removed in 3.0. Use critical() which is PSR-3 compatible. - */ - public function crit($message, array $context = array()); - - /** - * @deprecated since version 2.2, to be removed in 3.0. Use error() which is PSR-3 compatible. - */ - public function err($message, array $context = array()); - - /** - * @deprecated since version 2.2, to be removed in 3.0. Use warning() which is PSR-3 compatible. - */ - public function warn($message, array $context = array()); -} diff --git a/vendor/symfony/http-kernel/Log/NullLogger.php b/vendor/symfony/http-kernel/Log/NullLogger.php deleted file mode 100644 index 18b938d..0000000 --- a/vendor/symfony/http-kernel/Log/NullLogger.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Log; - -@trigger_error('The '.__NAMESPACE__.'\NullLogger class is deprecated since Symfony 2.2 and will be removed in 3.0. Use the Psr\Log\NullLogger class instead from the psr/log Composer package.', E_USER_DEPRECATED); - -use Psr\Log\NullLogger as PsrNullLogger; - -/** - * NullLogger. - * - * @author Fabien Potencier - */ -class NullLogger extends PsrNullLogger implements LoggerInterface -{ - public function emerg($message, array $context = array()) - { - @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.2 and will be removed in 3.0. You should use the new emergency() method instead, which is PSR-3 compatible.', E_USER_DEPRECATED); - } - - public function crit($message, array $context = array()) - { - @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.2 and will be removed in 3.0. You should use the new critical() method instead, which is PSR-3 compatible.', E_USER_DEPRECATED); - } - - public function err($message, array $context = array()) - { - @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.2 and will be removed in 3.0. You should use the new error() method instead, which is PSR-3 compatible.', E_USER_DEPRECATED); - } - - public function warn($message, array $context = array()) - { - @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.2 and will be removed in 3.0. You should use the new warning() method instead, which is PSR-3 compatible.', E_USER_DEPRECATED); - } -} diff --git a/vendor/symfony/http-kernel/Profiler/BaseMemcacheProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/BaseMemcacheProfilerStorage.php deleted file mode 100644 index d990e98..0000000 --- a/vendor/symfony/http-kernel/Profiler/BaseMemcacheProfilerStorage.php +++ /dev/null @@ -1,313 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Profiler; - -@trigger_error('The '.__NAMESPACE__.'\BaseMemcacheProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED); - -/** - * Base Memcache storage for profiling information in a Memcache. - * - * @author Andrej Hudec - * - * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0. - * Use {@link FileProfilerStorage} instead. - */ -abstract class BaseMemcacheProfilerStorage implements ProfilerStorageInterface -{ - const TOKEN_PREFIX = 'sf_profiler_'; - - protected $dsn; - protected $lifetime; - - /** - * @param string $dsn A data source name - * @param string $username - * @param string $password - * @param int $lifetime The lifetime to use for the purge - */ - public function __construct($dsn, $username = '', $password = '', $lifetime = 86400) - { - $this->dsn = $dsn; - $this->lifetime = (int) $lifetime; - } - - /** - * {@inheritdoc} - */ - public function find($ip, $url, $limit, $method, $start = null, $end = null) - { - $indexName = $this->getIndexName(); - - $indexContent = $this->getValue($indexName); - if (!$indexContent) { - return array(); - } - - $profileList = explode("\n", $indexContent); - $result = array(); - - foreach ($profileList as $item) { - if (0 === $limit) { - break; - } - - if ('' == $item) { - continue; - } - - $values = explode("\t", $item, 7); - list($itemToken, $itemIp, $itemMethod, $itemUrl, $itemTime, $itemParent) = $values; - $statusCode = isset($values[6]) ? $values[6] : null; - - $itemTime = (int) $itemTime; - - if ($ip && false === strpos($itemIp, $ip) || $url && false === strpos($itemUrl, $url) || $method && false === strpos($itemMethod, $method)) { - continue; - } - - if (!empty($start) && $itemTime < $start) { - continue; - } - - if (!empty($end) && $itemTime > $end) { - continue; - } - - $result[$itemToken] = array( - 'token' => $itemToken, - 'ip' => $itemIp, - 'method' => $itemMethod, - 'url' => $itemUrl, - 'time' => $itemTime, - 'parent' => $itemParent, - 'status_code' => $statusCode, - ); - --$limit; - } - - usort($result, function ($a, $b) { - if ($a['time'] === $b['time']) { - return 0; - } - - return $a['time'] > $b['time'] ? -1 : 1; - }); - - return $result; - } - - /** - * {@inheritdoc} - */ - public function purge() - { - // delete only items from index - $indexName = $this->getIndexName(); - - $indexContent = $this->getValue($indexName); - - if (!$indexContent) { - return false; - } - - $profileList = explode("\n", $indexContent); - - foreach ($profileList as $item) { - if ('' == $item) { - continue; - } - - if (false !== $pos = strpos($item, "\t")) { - $this->delete($this->getItemName(substr($item, 0, $pos))); - } - } - - return $this->delete($indexName); - } - - /** - * {@inheritdoc} - */ - public function read($token) - { - if (empty($token)) { - return false; - } - - $profile = $this->getValue($this->getItemName($token)); - - if (false !== $profile) { - $profile = $this->createProfileFromData($token, $profile); - } - - return $profile; - } - - /** - * {@inheritdoc} - */ - public function write(Profile $profile) - { - $data = array( - 'token' => $profile->getToken(), - 'parent' => $profile->getParentToken(), - 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()), - 'data' => $profile->getCollectors(), - 'ip' => $profile->getIp(), - 'method' => $profile->getMethod(), - 'url' => $profile->getUrl(), - 'time' => $profile->getTime(), - ); - - $profileIndexed = false !== $this->getValue($this->getItemName($profile->getToken())); - - if ($this->setValue($this->getItemName($profile->getToken()), $data, $this->lifetime)) { - if (!$profileIndexed) { - // Add to index - $indexName = $this->getIndexName(); - - $indexRow = implode("\t", array( - $profile->getToken(), - $profile->getIp(), - $profile->getMethod(), - $profile->getUrl(), - $profile->getTime(), - $profile->getParentToken(), - $profile->getStatusCode(), - ))."\n"; - - return $this->appendValue($indexName, $indexRow, $this->lifetime); - } - - return true; - } - - return false; - } - - /** - * Retrieve item from the memcache server. - * - * @param string $key - * - * @return mixed - */ - abstract protected function getValue($key); - - /** - * Store an item on the memcache server under the specified key. - * - * @param string $key - * @param mixed $value - * @param int $expiration - * - * @return bool - */ - abstract protected function setValue($key, $value, $expiration = 0); - - /** - * Delete item from the memcache server. - * - * @param string $key - * - * @return bool - */ - abstract protected function delete($key); - - /** - * Append data to an existing item on the memcache server. - * - * @param string $key - * @param string $value - * @param int $expiration - * - * @return bool - */ - abstract protected function appendValue($key, $value, $expiration = 0); - - private function createProfileFromData($token, $data, $parent = null) - { - $profile = new Profile($token); - $profile->setIp($data['ip']); - $profile->setMethod($data['method']); - $profile->setUrl($data['url']); - $profile->setTime($data['time']); - $profile->setCollectors($data['data']); - - if (!$parent && $data['parent']) { - $parent = $this->read($data['parent']); - } - - if ($parent) { - $profile->setParent($parent); - } - - foreach ($data['children'] as $token) { - if (!$token) { - continue; - } - - if (!$childProfileData = $this->getValue($this->getItemName($token))) { - continue; - } - - $profile->addChild($this->createProfileFromData($token, $childProfileData, $profile)); - } - - return $profile; - } - - /** - * Get item name. - * - * @param string $token - * - * @return string - */ - private function getItemName($token) - { - $name = self::TOKEN_PREFIX.$token; - - if ($this->isItemNameValid($name)) { - return $name; - } - - return false; - } - - /** - * Get name of index. - * - * @return string - */ - private function getIndexName() - { - $name = self::TOKEN_PREFIX.'index'; - - if ($this->isItemNameValid($name)) { - return $name; - } - - return false; - } - - private function isItemNameValid($name) - { - $length = \strlen($name); - - if ($length > 250) { - throw new \RuntimeException(sprintf('The memcache item key "%s" is too long (%s bytes). Allowed maximum size is 250 bytes.', $name, $length)); - } - - return true; - } -} diff --git a/vendor/symfony/http-kernel/Profiler/MemcacheProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/MemcacheProfilerStorage.php deleted file mode 100644 index 6578ebf..0000000 --- a/vendor/symfony/http-kernel/Profiler/MemcacheProfilerStorage.php +++ /dev/null @@ -1,112 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Profiler; - -@trigger_error('The '.__NAMESPACE__.'\MemcacheProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED); - -/** - * Memcache Profiler Storage. - * - * @author Andrej Hudec - * - * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0. - * Use {@link FileProfilerStorage} instead. - */ -class MemcacheProfilerStorage extends BaseMemcacheProfilerStorage -{ - /** - * @var \Memcache - */ - private $memcache; - - /** - * Internal convenience method that returns the instance of the Memcache. - * - * @return \Memcache - * - * @throws \RuntimeException - */ - protected function getMemcache() - { - if (null === $this->memcache) { - if (!preg_match('#^memcache://(?(?=\[.*\])\[(.*)\]|(.*)):(.*)$#', $this->dsn, $matches)) { - throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Memcache with an invalid dsn "%s". The expected format is "memcache://[host]:port".', $this->dsn)); - } - - $host = $matches[1] ?: $matches[2]; - $port = $matches[3]; - - $memcache = new \Memcache(); - $memcache->addServer($host, $port); - - $this->memcache = $memcache; - } - - return $this->memcache; - } - - /** - * Set instance of the Memcache. - * - * @param \Memcache $memcache - */ - public function setMemcache($memcache) - { - $this->memcache = $memcache; - } - - /** - * {@inheritdoc} - */ - protected function getValue($key) - { - return $this->getMemcache()->get($key); - } - - /** - * {@inheritdoc} - */ - protected function setValue($key, $value, $expiration = 0) - { - return $this->getMemcache()->set($key, $value, false, time() + $expiration); - } - - /** - * {@inheritdoc} - */ - protected function delete($key) - { - return $this->getMemcache()->delete($key); - } - - /** - * {@inheritdoc} - */ - protected function appendValue($key, $value, $expiration = 0) - { - $memcache = $this->getMemcache(); - - if (method_exists($memcache, 'append')) { - // Memcache v3.0 - if (!$result = $memcache->append($key, $value, false, $expiration)) { - return $memcache->set($key, $value, false, $expiration); - } - - return $result; - } - - // simulate append in Memcache <3.0 - $content = $memcache->get($key); - - return $memcache->set($key, $content.$value, false, $expiration); - } -} diff --git a/vendor/symfony/http-kernel/Profiler/MemcachedProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/MemcachedProfilerStorage.php deleted file mode 100644 index edf6ff1..0000000 --- a/vendor/symfony/http-kernel/Profiler/MemcachedProfilerStorage.php +++ /dev/null @@ -1,108 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Profiler; - -@trigger_error('The '.__NAMESPACE__.'\MemcachedProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED); - -/** - * Memcached Profiler Storage. - * - * @author Andrej Hudec - * - * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0. - * Use {@link FileProfilerStorage} instead. - */ -class MemcachedProfilerStorage extends BaseMemcacheProfilerStorage -{ - /** - * @var \Memcached - */ - private $memcached; - - /** - * Internal convenience method that returns the instance of the Memcached. - * - * @return \Memcached - * - * @throws \RuntimeException - */ - protected function getMemcached() - { - if (null === $this->memcached) { - if (!preg_match('#^memcached://(?(?=\[.*\])\[(.*)\]|(.*)):(.*)$#', $this->dsn, $matches)) { - throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Memcached with an invalid dsn "%s". The expected format is "memcached://[host]:port".', $this->dsn)); - } - - $host = $matches[1] ?: $matches[2]; - $port = $matches[3]; - - $memcached = new \Memcached(); - - // disable compression to allow appending - $memcached->setOption(\Memcached::OPT_COMPRESSION, false); - - $memcached->addServer($host, $port); - - $this->memcached = $memcached; - } - - return $this->memcached; - } - - /** - * Set instance of the Memcached. - * - * @param \Memcached $memcached - */ - public function setMemcached($memcached) - { - $this->memcached = $memcached; - } - - /** - * {@inheritdoc} - */ - protected function getValue($key) - { - return $this->getMemcached()->get($key); - } - - /** - * {@inheritdoc} - */ - protected function setValue($key, $value, $expiration = 0) - { - return $this->getMemcached()->set($key, $value, time() + $expiration); - } - - /** - * {@inheritdoc} - */ - protected function delete($key) - { - return $this->getMemcached()->delete($key); - } - - /** - * {@inheritdoc} - */ - protected function appendValue($key, $value, $expiration = 0) - { - $memcached = $this->getMemcached(); - - if (!$result = $memcached->append($key, $value)) { - return $memcached->set($key, $value, $expiration); - } - - return $result; - } -} diff --git a/vendor/symfony/http-kernel/Profiler/MongoDbProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/MongoDbProfilerStorage.php deleted file mode 100644 index 19970f9..0000000 --- a/vendor/symfony/http-kernel/Profiler/MongoDbProfilerStorage.php +++ /dev/null @@ -1,257 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Profiler; - -@trigger_error('The '.__NAMESPACE__.'\MongoDbProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED); - -/** - * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0. - * Use {@link FileProfilerStorage} instead. - */ -class MongoDbProfilerStorage implements ProfilerStorageInterface -{ - protected $dsn; - protected $lifetime; - private $mongo; - - /** - * @param string $dsn A data source name - * @param string $username Not used - * @param string $password Not used - * @param int $lifetime The lifetime to use for the purge - */ - public function __construct($dsn, $username = '', $password = '', $lifetime = 86400) - { - $this->dsn = $dsn; - $this->lifetime = (int) $lifetime; - } - - /** - * {@inheritdoc} - */ - public function find($ip, $url, $limit, $method, $start = null, $end = null) - { - $cursor = $this->getMongo()->find($this->buildQuery($ip, $url, $method, $start, $end), array('_id', 'parent', 'ip', 'method', 'url', 'time', 'status_code'))->sort(array('time' => -1))->limit($limit); - - $tokens = array(); - foreach ($cursor as $profile) { - $tokens[] = $this->getData($profile); - } - - return $tokens; - } - - /** - * {@inheritdoc} - */ - public function purge() - { - $this->getMongo()->remove(array()); - } - - /** - * {@inheritdoc} - */ - public function read($token) - { - $profile = $this->getMongo()->findOne(array('_id' => $token, 'data' => array('$exists' => true))); - - if (null !== $profile) { - $profile = $this->createProfileFromData($this->getData($profile)); - } - - return $profile; - } - - /** - * {@inheritdoc} - */ - public function write(Profile $profile) - { - $this->cleanup(); - - $record = array( - '_id' => $profile->getToken(), - 'parent' => $profile->getParentToken(), - 'data' => base64_encode(serialize($profile->getCollectors())), - 'ip' => $profile->getIp(), - 'method' => $profile->getMethod(), - 'url' => $profile->getUrl(), - 'time' => $profile->getTime(), - 'status_code' => $profile->getStatusCode(), - ); - - $result = $this->getMongo()->update(array('_id' => $profile->getToken()), array_filter($record, function ($v) { return !empty($v); }), array('upsert' => true)); - - return (bool) (isset($result['ok']) ? $result['ok'] : $result); - } - - /** - * Internal convenience method that returns the instance of the MongoDB Collection. - * - * @return \MongoCollection - * - * @throws \RuntimeException - */ - protected function getMongo() - { - if (null !== $this->mongo) { - return $this->mongo; - } - - if (!$parsedDsn = $this->parseDsn($this->dsn)) { - throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use MongoDB with an invalid dsn "%s". The expected format is "mongodb://[user:pass@]host/database/collection"', $this->dsn)); - } - - list($server, $database, $collection) = $parsedDsn; - $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? '\Mongo' : '\MongoClient'; - $mongo = new $mongoClass($server); - - return $this->mongo = $mongo->selectCollection($database, $collection); - } - - /** - * @return Profile - */ - protected function createProfileFromData(array $data) - { - $profile = $this->getProfile($data); - - if ($data['parent']) { - $parent = $this->getMongo()->findOne(array('_id' => $data['parent'], 'data' => array('$exists' => true))); - if ($parent) { - $profile->setParent($this->getProfile($this->getData($parent))); - } - } - - $profile->setChildren($this->readChildren($data['token'])); - - return $profile; - } - - /** - * @param string $token - * - * @return Profile[] An array of Profile instances - */ - protected function readChildren($token) - { - $profiles = array(); - - $cursor = $this->getMongo()->find(array('parent' => $token, 'data' => array('$exists' => true))); - foreach ($cursor as $d) { - $profiles[] = $this->getProfile($this->getData($d)); - } - - return $profiles; - } - - protected function cleanup() - { - $this->getMongo()->remove(array('time' => array('$lt' => time() - $this->lifetime))); - } - - /** - * @param string $ip - * @param string $url - * @param string $method - * @param int $start - * @param int $end - * - * @return array - */ - private function buildQuery($ip, $url, $method, $start, $end) - { - $query = array(); - - if (!empty($ip)) { - $query['ip'] = $ip; - } - - if (!empty($url)) { - $query['url'] = $url; - } - - if (!empty($method)) { - $query['method'] = $method; - } - - if (!empty($start) || !empty($end)) { - $query['time'] = array(); - } - - if (!empty($start)) { - $query['time']['$gte'] = $start; - } - - if (!empty($end)) { - $query['time']['$lte'] = $end; - } - - return $query; - } - - /** - * @return array - */ - private function getData(array $data) - { - return array( - 'token' => $data['_id'], - 'parent' => isset($data['parent']) ? $data['parent'] : null, - 'ip' => isset($data['ip']) ? $data['ip'] : null, - 'method' => isset($data['method']) ? $data['method'] : null, - 'url' => isset($data['url']) ? $data['url'] : null, - 'time' => isset($data['time']) ? $data['time'] : null, - 'data' => isset($data['data']) ? $data['data'] : null, - 'status_code' => isset($data['status_code']) ? $data['status_code'] : null, - ); - } - - /** - * @return Profile - */ - private function getProfile(array $data) - { - $profile = new Profile($data['token']); - $profile->setIp($data['ip']); - $profile->setMethod($data['method']); - $profile->setUrl($data['url']); - $profile->setTime($data['time']); - $profile->setCollectors(unserialize(base64_decode($data['data']))); - - return $profile; - } - - /** - * @param string $dsn - * - * @return array|null Array($server, $database, $collection) - */ - private function parseDsn($dsn) - { - if (!preg_match('#^(mongodb://.*)/(.*)/(.*)$#', $dsn, $matches)) { - return; - } - - $server = $matches[1]; - $database = $matches[2]; - $collection = $matches[3]; - preg_match('#^mongodb://(([^:]+):?(.*)(?=@))?@?([^/]*)(.*)$#', $server, $matchesServer); - - if ('' == $matchesServer[5] && '' != $matches[2]) { - $server .= '/'.$matches[2]; - } - - return array($server, $database, $collection); - } -} diff --git a/vendor/symfony/http-kernel/Profiler/MysqlProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/MysqlProfilerStorage.php deleted file mode 100644 index 086aa87..0000000 --- a/vendor/symfony/http-kernel/Profiler/MysqlProfilerStorage.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Profiler; - -@trigger_error('The '.__NAMESPACE__.'\MysqlProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED); - -/** - * A ProfilerStorage for Mysql. - * - * @author Jan Schumann - * - * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0. - * Use {@link FileProfilerStorage} instead. - */ -class MysqlProfilerStorage extends PdoProfilerStorage -{ - /** - * {@inheritdoc} - */ - protected function initDb() - { - if (null === $this->db) { - if (0 !== strpos($this->dsn, 'mysql')) { - throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Mysql with an invalid dsn "%s". The expected format is "mysql:dbname=database_name;host=host_name".', $this->dsn)); - } - - if (!class_exists('PDO') || !\in_array('mysql', \PDO::getAvailableDrivers(), true)) { - throw new \RuntimeException('You need to enable PDO_Mysql extension for the profiler to run properly.'); - } - - $db = new \PDO($this->dsn, $this->username, $this->password); - $db->exec('CREATE TABLE IF NOT EXISTS sf_profiler_data (token VARCHAR(255) PRIMARY KEY, data LONGTEXT, ip VARCHAR(64), method VARCHAR(6), url VARCHAR(255), time INTEGER UNSIGNED, parent VARCHAR(255), created_at INTEGER UNSIGNED, status_code SMALLINT UNSIGNED, KEY (created_at), KEY (ip), KEY (method), KEY (url), KEY (parent))'); - - $this->db = $db; - } - - return $this->db; - } - - /** - * {@inheritdoc} - */ - protected function buildCriteria($ip, $url, $start, $end, $limit, $method) - { - $criteria = array(); - $args = array(); - - if ($ip = preg_replace('/[^\d\.]/', '', $ip)) { - $criteria[] = 'ip LIKE :ip'; - $args[':ip'] = '%'.$ip.'%'; - } - - if ($url) { - $criteria[] = 'url LIKE :url'; - $args[':url'] = '%'.addcslashes($url, '%_\\').'%'; - } - - if ($method) { - $criteria[] = 'method = :method'; - $args[':method'] = $method; - } - - if (!empty($start)) { - $criteria[] = 'time >= :start'; - $args[':start'] = $start; - } - - if (!empty($end)) { - $criteria[] = 'time <= :end'; - $args[':end'] = $end; - } - - return array($criteria, $args); - } -} diff --git a/vendor/symfony/http-kernel/Profiler/PdoProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/PdoProfilerStorage.php deleted file mode 100644 index e5f8bc7..0000000 --- a/vendor/symfony/http-kernel/Profiler/PdoProfilerStorage.php +++ /dev/null @@ -1,265 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Profiler; - -@trigger_error('The '.__NAMESPACE__.'\PdoProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED); - -/** - * Base PDO storage for profiling information in a PDO database. - * - * @author Fabien Potencier - * @author Jan Schumann - * - * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0. - * Use {@link FileProfilerStorage} instead. - */ -abstract class PdoProfilerStorage implements ProfilerStorageInterface -{ - protected $dsn; - protected $username; - protected $password; - protected $lifetime; - protected $db; - - /** - * @param string $dsn A data source name - * @param string $username The username for the database - * @param string $password The password for the database - * @param int $lifetime The lifetime to use for the purge - */ - public function __construct($dsn, $username = '', $password = '', $lifetime = 86400) - { - $this->dsn = $dsn; - $this->username = $username; - $this->password = $password; - $this->lifetime = (int) $lifetime; - } - - /** - * {@inheritdoc} - */ - public function find($ip, $url, $limit, $method, $start = null, $end = null) - { - if (null === $start) { - $start = 0; - } - - if (null === $end) { - $end = time(); - } - - list($criteria, $args) = $this->buildCriteria($ip, $url, $start, $end, $limit, $method); - - $criteria = $criteria ? 'WHERE '.implode(' AND ', $criteria) : ''; - - $db = $this->initDb(); - $tokens = $this->fetch($db, 'SELECT token, ip, method, url, time, parent, status_code FROM sf_profiler_data '.$criteria.' ORDER BY time DESC LIMIT '.((int) $limit), $args); - $this->close($db); - - return $tokens; - } - - /** - * {@inheritdoc} - */ - public function read($token) - { - $db = $this->initDb(); - $args = array(':token' => $token); - $data = $this->fetch($db, 'SELECT data, parent, ip, method, url, time FROM sf_profiler_data WHERE token = :token LIMIT 1', $args); - $this->close($db); - if (isset($data[0]['data'])) { - return $this->createProfileFromData($token, $data[0]); - } - } - - /** - * {@inheritdoc} - */ - public function write(Profile $profile) - { - $db = $this->initDb(); - $args = array( - ':token' => $profile->getToken(), - ':parent' => $profile->getParentToken(), - ':data' => base64_encode(serialize($profile->getCollectors())), - ':ip' => $profile->getIp(), - ':method' => $profile->getMethod(), - ':url' => $profile->getUrl(), - ':time' => $profile->getTime(), - ':created_at' => time(), - ':status_code' => $profile->getStatusCode(), - ); - - try { - if ($this->has($profile->getToken())) { - $this->exec($db, 'UPDATE sf_profiler_data SET parent = :parent, data = :data, ip = :ip, method = :method, url = :url, time = :time, created_at = :created_at, status_code = :status_code WHERE token = :token', $args); - } else { - $this->exec($db, 'INSERT INTO sf_profiler_data (token, parent, data, ip, method, url, time, created_at, status_code) VALUES (:token, :parent, :data, :ip, :method, :url, :time, :created_at, :status_code)', $args); - } - $this->cleanup(); - $status = true; - } catch (\Exception $e) { - $status = false; - } - - $this->close($db); - - return $status; - } - - /** - * {@inheritdoc} - */ - public function purge() - { - $db = $this->initDb(); - $this->exec($db, 'DELETE FROM sf_profiler_data'); - $this->close($db); - } - - /** - * Build SQL criteria to fetch records by ip and url. - * - * @param string $ip The IP - * @param string $url The URL - * @param string $start The start period to search from - * @param string $end The end period to search to - * @param string $limit The maximum number of tokens to return - * @param string $method The request method - * - * @return array An array with (criteria, args) - */ - abstract protected function buildCriteria($ip, $url, $start, $end, $limit, $method); - - /** - * Initializes the database. - * - * @throws \RuntimeException When the requested database driver is not installed - */ - abstract protected function initDb(); - - protected function cleanup() - { - $db = $this->initDb(); - $this->exec($db, 'DELETE FROM sf_profiler_data WHERE created_at < :time', array(':time' => time() - $this->lifetime)); - $this->close($db); - } - - protected function exec($db, $query, array $args = array()) - { - $stmt = $this->prepareStatement($db, $query); - - foreach ($args as $arg => $val) { - $stmt->bindValue($arg, $val, \is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR); - } - $success = $stmt->execute(); - if (!$success) { - throw new \RuntimeException(sprintf('Error executing query "%s"', $query)); - } - } - - protected function prepareStatement($db, $query) - { - try { - $stmt = $db->prepare($query); - } catch (\Exception $e) { - $stmt = false; - } - - if (false === $stmt) { - throw new \RuntimeException('The database cannot successfully prepare the statement'); - } - - return $stmt; - } - - protected function fetch($db, $query, array $args = array()) - { - $stmt = $this->prepareStatement($db, $query); - - foreach ($args as $arg => $val) { - $stmt->bindValue($arg, $val, \is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR); - } - $stmt->execute(); - - return $stmt->fetchAll(\PDO::FETCH_ASSOC); - } - - protected function close($db) - { - } - - protected function createProfileFromData($token, $data, $parent = null) - { - $profile = new Profile($token); - $profile->setIp($data['ip']); - $profile->setMethod($data['method']); - $profile->setUrl($data['url']); - $profile->setTime($data['time']); - $profile->setCollectors(unserialize(base64_decode($data['data']))); - - if (!$parent && !empty($data['parent'])) { - $parent = $this->read($data['parent']); - } - - if ($parent) { - $profile->setParent($parent); - } - - $profile->setChildren($this->readChildren($token, $profile)); - - return $profile; - } - - /** - * Reads the child profiles for the given token. - * - * @param string $token The parent token - * @param string $parent The parent instance - * - * @return Profile[] An array of Profile instance - */ - protected function readChildren($token, $parent) - { - $db = $this->initDb(); - $data = $this->fetch($db, 'SELECT token, data, ip, method, url, time FROM sf_profiler_data WHERE parent = :token', array(':token' => $token)); - $this->close($db); - - if (!$data) { - return array(); - } - - $profiles = array(); - foreach ($data as $d) { - $profiles[] = $this->createProfileFromData($d['token'], $d, $parent); - } - - return $profiles; - } - - /** - * Returns whether data for the given token already exists in storage. - * - * @param string $token The profile token - * - * @return string - */ - protected function has($token) - { - $db = $this->initDb(); - $tokenExists = $this->fetch($db, 'SELECT 1 FROM sf_profiler_data WHERE token = :token LIMIT 1', array(':token' => $token)); - $this->close($db); - - return !empty($tokenExists); - } -} diff --git a/vendor/symfony/http-kernel/Profiler/RedisProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/RedisProfilerStorage.php deleted file mode 100644 index 6d3d967..0000000 --- a/vendor/symfony/http-kernel/Profiler/RedisProfilerStorage.php +++ /dev/null @@ -1,395 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Profiler; - -@trigger_error('The '.__NAMESPACE__.'\RedisProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED); - -/** - * RedisProfilerStorage stores profiling information in Redis. - * - * @author Andrej Hudec - * @author Stephane PY - * - * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0. - * Use {@link FileProfilerStorage} instead. - */ -class RedisProfilerStorage implements ProfilerStorageInterface -{ - const TOKEN_PREFIX = 'sf_profiler_'; - - const REDIS_OPT_SERIALIZER = 1; - const REDIS_OPT_PREFIX = 2; - const REDIS_SERIALIZER_NONE = 0; - const REDIS_SERIALIZER_PHP = 1; - - protected $dsn; - protected $lifetime; - - /** - * @var \Redis - */ - private $redis; - - /** - * @param string $dsn A data source name - * @param string $username Not used - * @param string $password Not used - * @param int $lifetime The lifetime to use for the purge - */ - public function __construct($dsn, $username = '', $password = '', $lifetime = 86400) - { - $this->dsn = $dsn; - $this->lifetime = (int) $lifetime; - } - - /** - * {@inheritdoc} - */ - public function find($ip, $url, $limit, $method, $start = null, $end = null) - { - $indexName = $this->getIndexName(); - - if (!$indexContent = $this->getValue($indexName, self::REDIS_SERIALIZER_NONE)) { - return array(); - } - - $profileList = array_reverse(explode("\n", $indexContent)); - $result = array(); - - foreach ($profileList as $item) { - if (0 === $limit) { - break; - } - - if ('' == $item) { - continue; - } - - $values = explode("\t", $item, 7); - list($itemToken, $itemIp, $itemMethod, $itemUrl, $itemTime, $itemParent) = $values; - $statusCode = isset($values[6]) ? $values[6] : null; - - $itemTime = (int) $itemTime; - - if ($ip && false === strpos($itemIp, $ip) || $url && false === strpos($itemUrl, $url) || $method && false === strpos($itemMethod, $method)) { - continue; - } - - if (!empty($start) && $itemTime < $start) { - continue; - } - - if (!empty($end) && $itemTime > $end) { - continue; - } - - $result[] = array( - 'token' => $itemToken, - 'ip' => $itemIp, - 'method' => $itemMethod, - 'url' => $itemUrl, - 'time' => $itemTime, - 'parent' => $itemParent, - 'status_code' => $statusCode, - ); - --$limit; - } - - return $result; - } - - /** - * {@inheritdoc} - */ - public function purge() - { - // delete only items from index - $indexName = $this->getIndexName(); - - $indexContent = $this->getValue($indexName, self::REDIS_SERIALIZER_NONE); - - if (!$indexContent) { - return false; - } - - $profileList = explode("\n", $indexContent); - - $result = array(); - - foreach ($profileList as $item) { - if ('' == $item) { - continue; - } - - if (false !== $pos = strpos($item, "\t")) { - $result[] = $this->getItemName(substr($item, 0, $pos)); - } - } - - $result[] = $indexName; - - return $this->delete($result); - } - - /** - * {@inheritdoc} - */ - public function read($token) - { - if (empty($token)) { - return false; - } - - $profile = $this->getValue($this->getItemName($token), self::REDIS_SERIALIZER_PHP); - - if (false !== $profile) { - $profile = $this->createProfileFromData($token, $profile); - } - - return $profile; - } - - /** - * {@inheritdoc} - */ - public function write(Profile $profile) - { - $data = array( - 'token' => $profile->getToken(), - 'parent' => $profile->getParentToken(), - 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()), - 'data' => $profile->getCollectors(), - 'ip' => $profile->getIp(), - 'method' => $profile->getMethod(), - 'url' => $profile->getUrl(), - 'time' => $profile->getTime(), - ); - - $profileIndexed = false !== $this->getValue($this->getItemName($profile->getToken())); - - if ($this->setValue($this->getItemName($profile->getToken()), $data, $this->lifetime, self::REDIS_SERIALIZER_PHP)) { - if (!$profileIndexed) { - // Add to index - $indexName = $this->getIndexName(); - - $indexRow = implode("\t", array( - $profile->getToken(), - $profile->getIp(), - $profile->getMethod(), - $profile->getUrl(), - $profile->getTime(), - $profile->getParentToken(), - $profile->getStatusCode(), - ))."\n"; - - return $this->appendValue($indexName, $indexRow, $this->lifetime); - } - - return true; - } - - return false; - } - - /** - * Internal convenience method that returns the instance of Redis. - * - * @return \Redis - * - * @throws \RuntimeException - */ - protected function getRedis() - { - if (null === $this->redis) { - $data = parse_url($this->dsn); - - if (false === $data || !isset($data['scheme']) || 'redis' !== $data['scheme'] || !isset($data['host']) || !isset($data['port'])) { - throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Redis with an invalid dsn "%s". The minimal expected format is "redis://[host]:port".', $this->dsn)); - } - - if (!\extension_loaded('redis')) { - throw new \RuntimeException('RedisProfilerStorage requires that the redis extension is loaded.'); - } - - $redis = new \Redis(); - $redis->connect($data['host'], $data['port']); - - if (isset($data['path'])) { - $redis->select(substr($data['path'], 1)); - } - - if (isset($data['pass'])) { - $redis->auth($data['pass']); - } - - $redis->setOption(self::REDIS_OPT_PREFIX, self::TOKEN_PREFIX); - - $this->redis = $redis; - } - - return $this->redis; - } - - /** - * Set instance of the Redis. - * - * @param \Redis $redis - */ - public function setRedis($redis) - { - $this->redis = $redis; - } - - private function createProfileFromData($token, $data, $parent = null) - { - $profile = new Profile($token); - $profile->setIp($data['ip']); - $profile->setMethod($data['method']); - $profile->setUrl($data['url']); - $profile->setTime($data['time']); - $profile->setCollectors($data['data']); - - if (!$parent && $data['parent']) { - $parent = $this->read($data['parent']); - } - - if ($parent) { - $profile->setParent($parent); - } - - foreach ($data['children'] as $token) { - if (!$token) { - continue; - } - - if (!$childProfileData = $this->getValue($this->getItemName($token), self::REDIS_SERIALIZER_PHP)) { - continue; - } - - $profile->addChild($this->createProfileFromData($token, $childProfileData, $profile)); - } - - return $profile; - } - - /** - * Gets the item name. - * - * @param string $token - * - * @return string - */ - private function getItemName($token) - { - $name = $token; - - if ($this->isItemNameValid($name)) { - return $name; - } - - return false; - } - - /** - * Gets the name of the index. - * - * @return string - */ - private function getIndexName() - { - $name = 'index'; - - if ($this->isItemNameValid($name)) { - return $name; - } - - return false; - } - - private function isItemNameValid($name) - { - $length = \strlen($name); - - if ($length > 2147483648) { - throw new \RuntimeException(sprintf('The Redis item key "%s" is too long (%s bytes). Allowed maximum size is 2^31 bytes.', $name, $length)); - } - - return true; - } - - /** - * Retrieves an item from the Redis server. - * - * @param string $key - * @param int $serializer - * - * @return mixed - */ - private function getValue($key, $serializer = self::REDIS_SERIALIZER_NONE) - { - $redis = $this->getRedis(); - $redis->setOption(self::REDIS_OPT_SERIALIZER, $serializer); - - return $redis->get($key); - } - - /** - * Stores an item on the Redis server under the specified key. - * - * @param string $key - * @param mixed $value - * @param int $expiration - * @param int $serializer - * - * @return bool - */ - private function setValue($key, $value, $expiration = 0, $serializer = self::REDIS_SERIALIZER_NONE) - { - $redis = $this->getRedis(); - $redis->setOption(self::REDIS_OPT_SERIALIZER, $serializer); - - return $redis->setex($key, $expiration, $value); - } - - /** - * Appends data to an existing item on the Redis server. - * - * @param string $key - * @param string $value - * @param int $expiration - * - * @return bool - */ - private function appendValue($key, $value, $expiration = 0) - { - $redis = $this->getRedis(); - $redis->setOption(self::REDIS_OPT_SERIALIZER, self::REDIS_SERIALIZER_NONE); - - if ($redis->exists($key)) { - $redis->append($key, $value); - - return $redis->setTimeout($key, $expiration); - } - - return $redis->setex($key, $expiration, $value); - } - - /** - * Removes the specified keys. - * - * @return bool - */ - private function delete(array $keys) - { - return (bool) $this->getRedis()->delete($keys); - } -} diff --git a/vendor/symfony/http-kernel/Profiler/SqliteProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/SqliteProfilerStorage.php deleted file mode 100644 index 549c27e..0000000 --- a/vendor/symfony/http-kernel/Profiler/SqliteProfilerStorage.php +++ /dev/null @@ -1,144 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Profiler; - -@trigger_error('The '.__NAMESPACE__.'\SqliteProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED); - -/** - * SqliteProfilerStorage stores profiling information in a SQLite database. - * - * @author Fabien Potencier - * - * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0. - * Use {@link FileProfilerStorage} instead. - */ -class SqliteProfilerStorage extends PdoProfilerStorage -{ - /** - * @throws \RuntimeException When neither of SQLite3 or PDO_SQLite extension is enabled - */ - protected function initDb() - { - if (null === $this->db || $this->db instanceof \SQLite3) { - if (0 !== strpos($this->dsn, 'sqlite')) { - throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Sqlite with an invalid dsn "%s". The expected format is "sqlite:/path/to/the/db/file".', $this->dsn)); - } - if (class_exists('SQLite3')) { - $db = new \SQLite3(substr($this->dsn, 7, \strlen($this->dsn)), \SQLITE3_OPEN_READWRITE | \SQLITE3_OPEN_CREATE); - if (method_exists($db, 'busyTimeout')) { - // busyTimeout only exists for PHP >= 5.3.3 - $db->busyTimeout(1000); - } - } elseif (class_exists('PDO') && \in_array('sqlite', \PDO::getAvailableDrivers(), true)) { - $db = new \PDO($this->dsn); - } else { - throw new \RuntimeException('You need to enable either the SQLite3 or PDO_SQLite extension for the profiler to run properly.'); - } - - $db->exec('PRAGMA temp_store=MEMORY; PRAGMA journal_mode=MEMORY;'); - $db->exec('CREATE TABLE IF NOT EXISTS sf_profiler_data (token STRING, data STRING, ip STRING, method STRING, url STRING, time INTEGER, parent STRING, created_at INTEGER, status_code INTEGER)'); - $db->exec('CREATE INDEX IF NOT EXISTS data_created_at ON sf_profiler_data (created_at)'); - $db->exec('CREATE INDEX IF NOT EXISTS data_ip ON sf_profiler_data (ip)'); - $db->exec('CREATE INDEX IF NOT EXISTS data_method ON sf_profiler_data (method)'); - $db->exec('CREATE INDEX IF NOT EXISTS data_url ON sf_profiler_data (url)'); - $db->exec('CREATE INDEX IF NOT EXISTS data_parent ON sf_profiler_data (parent)'); - $db->exec('CREATE UNIQUE INDEX IF NOT EXISTS data_token ON sf_profiler_data (token)'); - - $this->db = $db; - } - - return $this->db; - } - - protected function exec($db, $query, array $args = array()) - { - if ($db instanceof \SQLite3) { - $stmt = $this->prepareStatement($db, $query); - foreach ($args as $arg => $val) { - $stmt->bindValue($arg, $val, \is_int($val) ? \SQLITE3_INTEGER : \SQLITE3_TEXT); - } - - $res = $stmt->execute(); - if (false === $res) { - throw new \RuntimeException(sprintf('Error executing SQLite query "%s"', $query)); - } - $res->finalize(); - } else { - parent::exec($db, $query, $args); - } - } - - protected function fetch($db, $query, array $args = array()) - { - $return = array(); - - if ($db instanceof \SQLite3) { - $stmt = $this->prepareStatement($db, $query); - foreach ($args as $arg => $val) { - $stmt->bindValue($arg, $val, \is_int($val) ? \SQLITE3_INTEGER : \SQLITE3_TEXT); - } - $res = $stmt->execute(); - while ($row = $res->fetchArray(\SQLITE3_ASSOC)) { - $return[] = $row; - } - $res->finalize(); - $stmt->close(); - } else { - $return = parent::fetch($db, $query, $args); - } - - return $return; - } - - /** - * {@inheritdoc} - */ - protected function buildCriteria($ip, $url, $start, $end, $limit, $method) - { - $criteria = array(); - $args = array(); - - if ($ip = preg_replace('/[^\d\.]/', '', $ip)) { - $criteria[] = 'ip LIKE :ip'; - $args[':ip'] = '%'.$ip.'%'; - } - - if ($url) { - $criteria[] = 'url LIKE :url ESCAPE "\"'; - $args[':url'] = '%'.addcslashes($url, '%_\\').'%'; - } - - if ($method) { - $criteria[] = 'method = :method'; - $args[':method'] = $method; - } - - if (!empty($start)) { - $criteria[] = 'time >= :start'; - $args[':start'] = $start; - } - - if (!empty($end)) { - $criteria[] = 'time <= :end'; - $args[':end'] = $end; - } - - return array($criteria, $args); - } - - protected function close($db) - { - if ($db instanceof \SQLite3) { - $db->close(); - } - } -} diff --git a/vendor/symfony/polyfill-php54/LICENSE b/vendor/symfony/polyfill-php54/LICENSE deleted file mode 100644 index 4cd8bdd..0000000 --- a/vendor/symfony/polyfill-php54/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015-2019 Fabien Potencier - -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. diff --git a/vendor/symfony/polyfill-php54/Php54.php b/vendor/symfony/polyfill-php54/Php54.php deleted file mode 100644 index 5fe232c..0000000 --- a/vendor/symfony/polyfill-php54/Php54.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Polyfill\Php54; - -/** - * @author Nicolas Grekas - * - * @internal - */ -final class Php54 -{ - public static function hex2bin($data) - { - $len = \strlen($data); - - if (null === $len) { - return; - } - if ($len % 2) { - trigger_error('hex2bin(): Hexadecimal input string must have an even length', E_USER_WARNING); - - return false; - } - - return pack('H*', $data); - } -} diff --git a/vendor/symfony/polyfill-php54/README.md b/vendor/symfony/polyfill-php54/README.md deleted file mode 100644 index d5dd463..0000000 --- a/vendor/symfony/polyfill-php54/README.md +++ /dev/null @@ -1,17 +0,0 @@ -Symfony Polyfill / Php54 -======================== - -This component provides functions unavailable in releases prior to PHP 5.4: - -- [`trait_exists`](http://php.net/trait_exists) -- [`class_uses`](http://php.net/class_uses) -- [`hex2bin`](http://php.net/hex2bin) -- [`session_register_shutdown`](http://php.net/session_register_shutdown) - -More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). - -License -======= - -This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php54/Resources/stubs/CallbackFilterIterator.php b/vendor/symfony/polyfill-php54/Resources/stubs/CallbackFilterIterator.php deleted file mode 100644 index b69db3d..0000000 --- a/vendor/symfony/polyfill-php54/Resources/stubs/CallbackFilterIterator.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -class CallbackFilterIterator extends FilterIterator -{ - private $iterator; - private $callback; - - public function __construct(Iterator $iterator, $callback) - { - $this->iterator = $iterator; - $this->callback = $callback; - parent::__construct($iterator); - } - - public function accept() - { - return call_user_func($this->callback, $this->current(), $this->key(), $this->iterator); - } -} diff --git a/vendor/symfony/polyfill-php54/Resources/stubs/RecursiveCallbackFilterIterator.php b/vendor/symfony/polyfill-php54/Resources/stubs/RecursiveCallbackFilterIterator.php deleted file mode 100644 index 63afd38..0000000 --- a/vendor/symfony/polyfill-php54/Resources/stubs/RecursiveCallbackFilterIterator.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -class RecursiveCallbackFilterIterator extends CallbackFilterIterator implements RecursiveIterator -{ - private $iterator; - private $callback; - - public function __construct(RecursiveIterator $iterator, $callback) - { - $this->iterator = $iterator; - $this->callback = $callback; - parent::__construct($iterator, $callback); - } - - public function hasChildren() - { - return $this->iterator->hasChildren(); - } - - public function getChildren() - { - return new static($this->iterator->getChildren(), $this->callback); - } -} diff --git a/vendor/symfony/polyfill-php54/Resources/stubs/SessionHandlerInterface.php b/vendor/symfony/polyfill-php54/Resources/stubs/SessionHandlerInterface.php deleted file mode 100644 index 9baa7bc..0000000 --- a/vendor/symfony/polyfill-php54/Resources/stubs/SessionHandlerInterface.php +++ /dev/null @@ -1,102 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * SessionHandlerInterface for PHP < 5.4. - * - * The order in which these methods are invoked by PHP are: - * 1. open [session_start] - * 2. read - * 3. gc [optional depending on probability settings: gc_probability / gc_divisor] - * 4. destroy [optional when session_regenerate_id(true) is used] - * 5. write [session_write_close] or destroy [session_destroy] - * 6. close - * - * Extensive documentation can be found at php.net, see links: - * - * @see http://php.net/sessionhandlerinterface - * @see http://php.net/session.customhandler - * @see http://php.net/session-set-save-handler - * - * @author Drak - * @author Tobias Schultze - */ -interface SessionHandlerInterface -{ - /** - * Re-initializes existing session, or creates a new one. - * - * @see http://php.net/sessionhandlerinterface.open - * - * @param string $savePath Save path - * @param string $sessionName Session name, see http://php.net/function.session-name.php - * - * @return bool true on success, false on failure - */ - public function open($savePath, $sessionName); - - /** - * Closes the current session. - * - * @see http://php.net/sessionhandlerinterface.close - * - * @return bool true on success, false on failure - */ - public function close(); - - /** - * Reads the session data. - * - * @see http://php.net/sessionhandlerinterface.read - * - * @param string $sessionId Session ID, see http://php.net/function.session-id - * - * @return string Same session data as passed in write() or empty string when non-existent or on failure - */ - public function read($sessionId); - - /** - * Writes the session data to the storage. - * - * Care, the session ID passed to write() can be different from the one previously - * received in read() when the session ID changed due to session_regenerate_id(). - * - * @see http://php.net/sessionhandlerinterface.write - * - * @param string $sessionId Session ID , see http://php.net/function.session-id - * @param string $data Serialized session data to save - * - * @return bool true on success, false on failure - */ - public function write($sessionId, $data); - - /** - * Destroys a session. - * - * @see http://php.net/sessionhandlerinterface.destroy - * - * @param string $sessionId Session ID, see http://php.net/function.session-id - * - * @return bool true on success, false on failure - */ - public function destroy($sessionId); - - /** - * Cleans up expired sessions (garbage collection). - * - * @see http://php.net/sessionhandlerinterface.gc - * - * @param string|int $maxlifetime Sessions that have not updated for the last maxlifetime seconds will be removed - * - * @return bool true on success, false on failure - */ - public function gc($maxlifetime); -} diff --git a/vendor/symfony/polyfill-php54/bootstrap.php b/vendor/symfony/polyfill-php54/bootstrap.php deleted file mode 100644 index d72c199..0000000 --- a/vendor/symfony/polyfill-php54/bootstrap.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -use Symfony\Polyfill\Php54 as p; - -if (PHP_VERSION_ID < 50400) { - if (!function_exists('trait_exists')) { - function trait_exists($class, $autoload = true) { return $autoload && \class_exists($class, $autoload) && false; } - } - if (!function_exists('class_uses')) { - function class_uses($class, $autoload = true) - { - if (\is_object($class) || \class_exists($class, $autoload) || \interface_exists($class, false)) { - return array(); - } - - return false; - } - } - if (!function_exists('hex2bin')) { - function hex2bin($data) { return p\Php54::hex2bin($data); } - } - if (!function_exists('session_register_shutdown')) { - function session_register_shutdown() { register_shutdown_function('session_write_close'); } - } -} diff --git a/vendor/symfony/polyfill-php54/composer.json b/vendor/symfony/polyfill-php54/composer.json deleted file mode 100644 index fd2ec53..0000000 --- a/vendor/symfony/polyfill-php54/composer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "symfony/polyfill-php54", - "type": "library", - "description": "Symfony polyfill backporting some PHP 5.4+ features to lower PHP versions", - "keywords": ["polyfill", "shim", "compatibility", "portable"], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": ">=5.3.3" - }, - "autoload": { - "psr-4": { "Symfony\\Polyfill\\Php54\\": "" }, - "files": [ "bootstrap.php" ], - "classmap": [ "Resources/stubs" ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - } -} diff --git a/vendor/symfony/polyfill-php55/LICENSE b/vendor/symfony/polyfill-php55/LICENSE deleted file mode 100644 index 4cd8bdd..0000000 --- a/vendor/symfony/polyfill-php55/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015-2019 Fabien Potencier - -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. diff --git a/vendor/symfony/polyfill-php55/Php55.php b/vendor/symfony/polyfill-php55/Php55.php deleted file mode 100644 index f5cb483..0000000 --- a/vendor/symfony/polyfill-php55/Php55.php +++ /dev/null @@ -1,89 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Polyfill\Php55; - -/** - * @internal - */ -final class Php55 -{ - public static function boolval($val) - { - return (bool) $val; - } - - public static function json_last_error_msg() - { - switch (json_last_error()) { - case JSON_ERROR_NONE: return 'No error'; - case JSON_ERROR_DEPTH: return 'Maximum stack depth exceeded'; - case JSON_ERROR_STATE_MISMATCH: return 'State mismatch (invalid or malformed JSON)'; - case JSON_ERROR_CTRL_CHAR: return 'Control character error, possibly incorrectly encoded'; - case JSON_ERROR_SYNTAX: return 'Syntax error'; - case JSON_ERROR_UTF8: return 'Malformed UTF-8 characters, possibly incorrectly encoded'; - default: return 'Unknown error'; - } - } - - /** - * @author Sebastiaan Stok - * @author Scott - */ - public static function hash_pbkdf2($algorithm, $password, $salt, $iterations, $length = 0, $rawOutput = false) - { - // Pre-hash for optimization if password length > hash length - $hashLength = \strlen(hash($algorithm, '', true)); - switch ($algorithm) { - case 'sha224': - case 'sha256': - $blockSize = 64; - break; - case 'sha384': - case 'sha512': - $blockSize = 128; - break; - default: - $blockSize = $hashLength; - break; - } - if ($length < 1) { - $length = $hashLength; - if (!$rawOutput) { - $length <<= 1; - } - } - - // Number of blocks needed to create the derived key - $blocks = ceil($length / $hashLength); - $digest = ''; - if (\strlen($password) > $blockSize) { - $password = hash($algorithm, $password, true); - } - - for ($i = 1; $i <= $blocks; ++$i) { - $ib = $block = hash_hmac($algorithm, $salt.pack('N', $i), $password, true); - - // Iterations - for ($j = 1; $j < $iterations; ++$j) { - $ib ^= ($block = hash_hmac($algorithm, $block, $password, true)); - } - - $digest .= $ib; - } - - if (!$rawOutput) { - $digest = bin2hex($digest); - } - - return substr($digest, 0, $length); - } -} diff --git a/vendor/symfony/polyfill-php55/Php55ArrayColumn.php b/vendor/symfony/polyfill-php55/Php55ArrayColumn.php deleted file mode 100644 index bb9b36a..0000000 --- a/vendor/symfony/polyfill-php55/Php55ArrayColumn.php +++ /dev/null @@ -1,64 +0,0 @@ - - * - * 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. - */ - -namespace Symfony\Polyfill\Php55; - -/** - * @internal - */ -final class Php55ArrayColumn -{ - public static function array_column(array $input, $columnKey, $indexKey = null) - { - $output = array(); - - foreach ($input as $row) { - $key = $value = null; - $keySet = $valueSet = false; - - if (null !== $indexKey && array_key_exists($indexKey, $row)) { - $keySet = true; - $key = (string) $row[$indexKey]; - } - - if (null === $columnKey) { - $valueSet = true; - $value = $row; - } elseif (\is_array($row) && \array_key_exists($columnKey, $row)) { - $valueSet = true; - $value = $row[$columnKey]; - } - - if ($valueSet) { - if ($keySet) { - $output[$key] = $value; - } else { - $output[] = $value; - } - } - } - - return $output; - } -} diff --git a/vendor/symfony/polyfill-php55/README.md b/vendor/symfony/polyfill-php55/README.md deleted file mode 100644 index 3e432e4..0000000 --- a/vendor/symfony/polyfill-php55/README.md +++ /dev/null @@ -1,18 +0,0 @@ -Symfony Polyfill / Php55 -======================== - -This component provides functions unavailable in releases prior to PHP 5.5: - -- [`boolval`](http://php.net/boolval) -- [`json_last_error_msg`](http://php.net/json_last_error_msg) -- [`array_column`](http://php.net/array_column) -- [`hash_pbkdf2`](http://php.net/hash_pbkdf2) -- `password_*` functions (from [ircmaxell/password_compat](https://github.com/ircmaxell/password_compat)) - -More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). - -License -======= - -This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php55/bootstrap.php b/vendor/symfony/polyfill-php55/bootstrap.php deleted file mode 100644 index 5e634fe..0000000 --- a/vendor/symfony/polyfill-php55/bootstrap.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -use Symfony\Polyfill\Php55 as p; - -if (PHP_VERSION_ID < 50500) { - if (!function_exists('boolval')) { - function boolval($val) { return p\Php55::boolval($val); } - } - if (!function_exists('json_last_error_msg')) { - function json_last_error_msg() { return p\Php55::json_last_error_msg(); } - } - if (!function_exists('array_column')) { - function array_column($array, $columnKey, $indexKey = null) { return p\Php55ArrayColumn::array_column($array, $columnKey, $indexKey); } - } - if (!function_exists('hash_pbkdf2')) { - function hash_pbkdf2($algorithm, $password, $salt, $iterations, $length = 0, $rawOutput = false) { return p\Php55::hash_pbkdf2($algorithm, $password, $salt, $iterations, $length, $rawOutput); } - } -} diff --git a/vendor/symfony/polyfill-php55/composer.json b/vendor/symfony/polyfill-php55/composer.json deleted file mode 100644 index c2dfd80..0000000 --- a/vendor/symfony/polyfill-php55/composer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "symfony/polyfill-php55", - "type": "library", - "description": "Symfony polyfill backporting some PHP 5.5+ features to lower PHP versions", - "keywords": ["polyfill", "shim", "compatibility", "portable"], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": ">=5.3.3", - "ircmaxell/password-compat": "~1.0" - }, - "autoload": { - "psr-4": { "Symfony\\Polyfill\\Php55\\": "" }, - "files": [ "bootstrap.php" ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - } -} diff --git a/vendor/symfony/routing/Matcher/ApacheUrlMatcher.php b/vendor/symfony/routing/Matcher/ApacheUrlMatcher.php deleted file mode 100644 index 1f17cee..0000000 --- a/vendor/symfony/routing/Matcher/ApacheUrlMatcher.php +++ /dev/null @@ -1,124 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Routing\Matcher; - -@trigger_error('The '.__NAMESPACE__.'\ApacheUrlMatcher class is deprecated since Symfony 2.5 and will be removed in 3.0. It\'s hard to replicate the behaviour of the PHP implementation and the performance gains are minimal.', E_USER_DEPRECATED); - -use Symfony\Component\Routing\Exception\MethodNotAllowedException; - -/** - * ApacheUrlMatcher matches URL based on Apache mod_rewrite matching (see ApacheMatcherDumper). - * - * @deprecated since version 2.5, to be removed in 3.0. - * The performance gains are minimal and it's very hard to replicate - * the behavior of PHP implementation. - * - * @author Fabien Potencier - * @author Arnaud Le Blanc - */ -class ApacheUrlMatcher extends UrlMatcher -{ - /** - * Tries to match a URL based on Apache mod_rewrite matching. - * - * Returns false if no route matches the URL. - * - * @param string $pathinfo The pathinfo to be parsed - * - * @return array An array of parameters - * - * @throws MethodNotAllowedException If the current method is not allowed - */ - public function match($pathinfo) - { - $parameters = array(); - $defaults = array(); - $allow = array(); - $route = null; - - foreach ($this->denormalizeValues($_SERVER) as $key => $value) { - $name = $key; - - // skip non-routing variables - // this improves performance when $_SERVER contains many usual - // variables like HTTP_*, DOCUMENT_ROOT, REQUEST_URI, ... - if (false === strpos($name, '_ROUTING_')) { - continue; - } - - while (0 === strpos($name, 'REDIRECT_')) { - $name = substr($name, 9); - } - - // expect _ROUTING__ - // or _ROUTING_ - - if (0 !== strpos($name, '_ROUTING_')) { - continue; - } - if (false !== $pos = strpos($name, '_', 9)) { - $type = substr($name, 9, $pos - 9); - $name = substr($name, $pos + 1); - } else { - $type = substr($name, 9); - } - - if ('param' === $type) { - if ('' !== $value) { - $parameters[$name] = $value; - } - } elseif ('default' === $type) { - $defaults[$name] = $value; - } elseif ('route' === $type) { - $route = $value; - } elseif ('allow' === $type) { - $allow[] = $name; - } - - unset($_SERVER[$key]); - } - - if (null !== $route) { - $parameters['_route'] = $route; - - return $this->mergeDefaults($parameters, $defaults); - } elseif (0 < \count($allow)) { - throw new MethodNotAllowedException($allow); - } else { - return parent::match($pathinfo); - } - } - - /** - * Denormalizes an array of values. - * - * @param string[] $values - * - * @return array - */ - private function denormalizeValues(array $values) - { - $normalizedValues = array(); - foreach ($values as $key => $value) { - if (preg_match('~^(.*)\[(\d+)\]$~', $key, $matches)) { - if (!isset($normalizedValues[$matches[1]])) { - $normalizedValues[$matches[1]] = array(); - } - $normalizedValues[$matches[1]][(int) $matches[2]] = $value; - } else { - $normalizedValues[$key] = $value; - } - } - - return $normalizedValues; - } -} diff --git a/vendor/symfony/routing/Matcher/Dumper/ApacheMatcherDumper.php b/vendor/symfony/routing/Matcher/Dumper/ApacheMatcherDumper.php deleted file mode 100644 index 6027069..0000000 --- a/vendor/symfony/routing/Matcher/Dumper/ApacheMatcherDumper.php +++ /dev/null @@ -1,272 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Routing\Matcher\Dumper; - -@trigger_error('The '.__NAMESPACE__.'\ApacheMatcherDumper class is deprecated since Symfony 2.5 and will be removed in 3.0. It\'s hard to replicate the behaviour of the PHP implementation and the performance gains are minimal.', E_USER_DEPRECATED); - -use Symfony\Component\Routing\Route; - -/** - * Dumps a set of Apache mod_rewrite rules. - * - * @deprecated since version 2.5, to be removed in 3.0. - * The performance gains are minimal and it's very hard to replicate - * the behavior of PHP implementation. - * - * @author Fabien Potencier - * @author Kris Wallsmith - */ -class ApacheMatcherDumper extends MatcherDumper -{ - /** - * Dumps a set of Apache mod_rewrite rules. - * - * Available options: - * - * * script_name: The script name (app.php by default) - * * base_uri: The base URI ("" by default) - * - * @return string A string to be used as Apache rewrite rules - * - * @throws \LogicException When the route regex is invalid - */ - public function dump(array $options = array()) - { - $options = array_merge(array( - 'script_name' => 'app.php', - 'base_uri' => '', - ), $options); - - $options['script_name'] = self::escape($options['script_name'], ' ', '\\'); - - $rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]"); - $methodVars = array(); - $hostRegexUnique = 0; - $prevHostRegex = ''; - - foreach ($this->getRoutes()->all() as $name => $route) { - if ($route->getCondition()) { - throw new \LogicException(sprintf('Unable to dump the routes for Apache as route "%s" has a condition.', $name)); - } - - $compiledRoute = $route->compile(); - $hostRegex = $compiledRoute->getHostRegex(); - - if (null !== $hostRegex && $prevHostRegex !== $hostRegex) { - $prevHostRegex = $hostRegex; - ++$hostRegexUnique; - - $rule = array(); - - $regex = $this->regexToApacheRegex($hostRegex); - $regex = self::escape($regex, ' ', '\\'); - - $rule[] = sprintf('RewriteCond %%{HTTP:Host} %s', $regex); - - $variables = array(); - $variables[] = sprintf('E=__ROUTING_host_%s:1', $hostRegexUnique); - - foreach ($compiledRoute->getHostVariables() as $i => $variable) { - $variables[] = sprintf('E=__ROUTING_host_%s_%s:%%%d', $hostRegexUnique, $variable, $i + 1); - } - - $variables = implode(',', $variables); - - $rule[] = sprintf('RewriteRule .? - [%s]', $variables); - - $rules[] = implode("\n", $rule); - } - - $rules[] = $this->dumpRoute($name, $route, $options, $hostRegexUnique); - - $methodVars = array_merge($methodVars, $route->getMethods()); - } - if (0 < \count($methodVars)) { - $rule = array('# 405 Method Not Allowed'); - $methodVars = array_values(array_unique($methodVars)); - if (\in_array('GET', $methodVars) && !\in_array('HEAD', $methodVars)) { - $methodVars[] = 'HEAD'; - } - foreach ($methodVars as $i => $methodVar) { - $rule[] = sprintf('RewriteCond %%{ENV:_ROUTING__allow_%s} =1%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : ''); - } - $rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']); - - $rules[] = implode("\n", $rule); - } - - return implode("\n\n", $rules)."\n"; - } - - /** - * Dumps a single route. - * - * @param string $name Route name - * @param Route $route The route - * @param array $options Options - * @param bool $hostRegexUnique Unique identifier for the host regex - * - * @return string The compiled route - */ - private function dumpRoute($name, $route, array $options, $hostRegexUnique) - { - $compiledRoute = $route->compile(); - - // prepare the apache regex - $regex = $this->regexToApacheRegex($compiledRoute->getRegex()); - $regex = '^'.self::escape(preg_quote($options['base_uri']).substr($regex, 1), ' ', '\\'); - - $methods = $this->getRouteMethods($route); - - $hasTrailingSlash = (!$methods || \in_array('HEAD', $methods)) && '/$' === substr($regex, -2) && '^/$' !== $regex; - - $variables = array('E=_ROUTING_route:'.$name); - foreach ($compiledRoute->getHostVariables() as $variable) { - $variables[] = sprintf('E=_ROUTING_param_%s:%%{ENV:__ROUTING_host_%s_%s}', $variable, $hostRegexUnique, $variable); - } - foreach ($compiledRoute->getPathVariables() as $i => $variable) { - $variables[] = 'E=_ROUTING_param_'.$variable.':%'.($i + 1); - } - foreach ($this->normalizeValues($route->getDefaults()) as $key => $value) { - $variables[] = 'E=_ROUTING_default_'.$key.':'.strtr($value, array( - ':' => '\\:', - '=' => '\\=', - '\\' => '\\\\', - ' ' => '\\ ', - )); - } - $variables = implode(',', $variables); - - $rule = array("# $name"); - - // method mismatch - if (0 < \count($methods)) { - $allow = array(); - foreach ($methods as $method) { - $allow[] = 'E=_ROUTING_allow_'.$method.':1'; - } - - if ($compiledRoute->getHostRegex()) { - $rule[] = sprintf('RewriteCond %%{ENV:__ROUTING_host_%s} =1', $hostRegexUnique); - } - - $rule[] = "RewriteCond %{REQUEST_URI} $regex"; - $rule[] = sprintf('RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]', implode('|', $methods)); - $rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow)); - } - - // redirect with trailing slash appended - if ($hasTrailingSlash) { - if ($compiledRoute->getHostRegex()) { - $rule[] = sprintf('RewriteCond %%{ENV:__ROUTING_host_%s} =1', $hostRegexUnique); - } - - $rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$'; - $rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]'; - } - - // the main rule - - if ($compiledRoute->getHostRegex()) { - $rule[] = sprintf('RewriteCond %%{ENV:__ROUTING_host_%s} =1', $hostRegexUnique); - } - - $rule[] = "RewriteCond %{REQUEST_URI} $regex"; - $rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]"; - - return implode("\n", $rule); - } - - /** - * Returns methods allowed for a route. - * - * @return array The methods - */ - private function getRouteMethods(Route $route) - { - $methods = $route->getMethods(); - - // GET and HEAD are equivalent - if (\in_array('GET', $methods) && !\in_array('HEAD', $methods)) { - $methods[] = 'HEAD'; - } - - return $methods; - } - - /** - * Converts a regex to make it suitable for mod_rewrite. - * - * @param string $regex The regex - * - * @return string The converted regex - */ - private function regexToApacheRegex($regex) - { - $regexPatternEnd = strrpos($regex, $regex[0]); - - return preg_replace('/\?P<.+?>/', '', substr($regex, 1, $regexPatternEnd - 1)); - } - - /** - * Escapes a string. - * - * @param string $string The string to be escaped - * @param string $char The character to be escaped - * @param string $with The character to be used for escaping - * - * @return string The escaped string - */ - private static function escape($string, $char, $with) - { - $escaped = false; - $output = ''; - foreach (str_split($string) as $symbol) { - if ($escaped) { - $output .= $symbol; - $escaped = false; - continue; - } - if ($symbol === $char) { - $output .= $with.$char; - continue; - } - if ($symbol === $with) { - $escaped = true; - } - $output .= $symbol; - } - - return $output; - } - - /** - * Normalizes an array of values. - * - * @return string[] - */ - private function normalizeValues(array $values) - { - $normalizedValues = array(); - foreach ($values as $key => $value) { - if (\is_array($value)) { - foreach ($value as $index => $bit) { - $normalizedValues[sprintf('%s[%s]', $key, $index)] = $bit; - } - } else { - $normalizedValues[$key] = (string) $value; - } - } - - return $normalizedValues; - } -} diff --git a/vendor/symfony/routing/Matcher/Dumper/DumperPrefixCollection.php b/vendor/symfony/routing/Matcher/Dumper/DumperPrefixCollection.php deleted file mode 100644 index f736f75..0000000 --- a/vendor/symfony/routing/Matcher/Dumper/DumperPrefixCollection.php +++ /dev/null @@ -1,105 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Routing\Matcher\Dumper; - -/** - * Prefix tree of routes preserving routes order. - * - * @author Arnaud Le Blanc - * - * @internal - */ -class DumperPrefixCollection extends DumperCollection -{ - /** - * @var string - */ - private $prefix = ''; - - /** - * Returns the prefix. - * - * @return string The prefix - */ - public function getPrefix() - { - return $this->prefix; - } - - /** - * Sets the prefix. - * - * @param string $prefix The prefix - */ - public function setPrefix($prefix) - { - $this->prefix = $prefix; - } - - /** - * Adds a route in the tree. - * - * @return self - * - * @throws \LogicException - */ - public function addPrefixRoute(DumperRoute $route) - { - $prefix = $route->getRoute()->compile()->getStaticPrefix(); - - for ($collection = $this; null !== $collection; $collection = $collection->getParent()) { - // Same prefix, add to current leave - if ($collection->prefix === $prefix) { - $collection->add($route); - - return $collection; - } - - // Prefix starts with route's prefix - if ('' === $collection->prefix || 0 === strpos($prefix, $collection->prefix)) { - $child = new self(); - $child->setPrefix(substr($prefix, 0, \strlen($collection->prefix) + 1)); - $collection->add($child); - - return $child->addPrefixRoute($route); - } - } - - // Reached only if the root has a non empty prefix - throw new \LogicException('The collection root must not have a prefix'); - } - - /** - * Merges nodes whose prefix ends with a slash. - * - * Children of a node whose prefix ends with a slash are moved to the parent node - */ - public function mergeSlashNodes() - { - $children = array(); - - foreach ($this as $child) { - if ($child instanceof self) { - $child->mergeSlashNodes(); - if ('/' === substr($child->prefix, -1)) { - $children = array_merge($children, $child->all()); - } else { - $children[] = $child; - } - } else { - $children[] = $child; - } - } - - $this->setAll($children); - } -} diff --git a/vendor/symfony/twig-bridge/Node/FormEnctypeNode.php b/vendor/symfony/twig-bridge/Node/FormEnctypeNode.php deleted file mode 100644 index 14811e6..0000000 --- a/vendor/symfony/twig-bridge/Node/FormEnctypeNode.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Twig\Node; - -/** - * @author Bernhard Schussek - * - * @deprecated since version 2.3, to be removed in 3.0. Use the helper "form_start()" instead. - */ -class FormEnctypeNode extends SearchAndRenderBlockNode -{ -} diff --git a/vendor/twig/twig/lib/Twig/Autoloader.php b/vendor/twig/twig/lib/Twig/Autoloader.php deleted file mode 100644 index e34e214..0000000 --- a/vendor/twig/twig/lib/Twig/Autoloader.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * @deprecated since 1.21 and will be removed in 2.0. Use Composer instead. 2.0. - */ -class Twig_Autoloader -{ - /** - * Registers Twig_Autoloader as an SPL autoloader. - * - * @param bool $prepend whether to prepend the autoloader or not - */ - public static function register($prepend = false) - { - @trigger_error('Using Twig_Autoloader is deprecated since version 1.21. Use Composer instead.', E_USER_DEPRECATED); - - spl_autoload_register([__CLASS__, 'autoload'], true, $prepend); - } - - /** - * Handles autoloading of classes. - * - * @param string $class a class name - */ - public static function autoload($class) - { - if (0 !== strpos($class, 'Twig')) { - return; - } - - if (is_file($file = __DIR__.'/../'.str_replace(['_', "\0"], ['/', ''], $class).'.php')) { - require $file; - } elseif (is_file($file = __DIR__.'/../../src/'.str_replace(['Twig\\', '\\', "\0"], ['', '/', ''], $class).'.php')) { - require $file; - } - } -} diff --git a/vendor/twig/twig/lib/Twig/CompilerInterface.php b/vendor/twig/twig/lib/Twig/CompilerInterface.php deleted file mode 100644 index 42872c9..0000000 --- a/vendor/twig/twig/lib/Twig/CompilerInterface.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_CompilerInterface -{ - /** - * Compiles a node. - * - * @return $this - */ - public function compile(Twig_NodeInterface $node); - - /** - * Gets the current PHP code after compilation. - * - * @return string The PHP code - */ - public function getSource(); -} diff --git a/vendor/twig/twig/lib/Twig/Filter/Function.php b/vendor/twig/twig/lib/Twig/Filter/Function.php deleted file mode 100644 index 011d4cc..0000000 --- a/vendor/twig/twig/lib/Twig/Filter/Function.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Filter_Function extends Twig_Filter -{ - protected $function; - - public function __construct($function, array $options = []) - { - $options['callable'] = $function; - - parent::__construct($options); - - $this->function = $function; - } - - public function compile() - { - return $this->function; - } -} diff --git a/vendor/twig/twig/lib/Twig/Filter/Method.php b/vendor/twig/twig/lib/Twig/Filter/Method.php deleted file mode 100644 index 5cd0628..0000000 --- a/vendor/twig/twig/lib/Twig/Filter/Method.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Filter_Method extends Twig_Filter -{ - protected $extension; - protected $method; - - public function __construct(ExtensionInterface $extension, $method, array $options = []) - { - $options['callable'] = [$extension, $method]; - - parent::__construct($options); - - $this->extension = $extension; - $this->method = $method; - } - - public function compile() - { - return sprintf('$this->env->getExtension(\'%s\')->%s', \get_class($this->extension), $this->method); - } -} diff --git a/vendor/twig/twig/lib/Twig/Filter/Node.php b/vendor/twig/twig/lib/Twig/Filter/Node.php deleted file mode 100644 index 8bb2899..0000000 --- a/vendor/twig/twig/lib/Twig/Filter/Node.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Filter_Node extends Twig_Filter -{ - protected $class; - - public function __construct($class, array $options = []) - { - parent::__construct($options); - - $this->class = $class; - } - - public function getClass() - { - return $this->class; - } - - public function compile() - { - } -} diff --git a/vendor/twig/twig/lib/Twig/FilterCallableInterface.php b/vendor/twig/twig/lib/Twig/FilterCallableInterface.php deleted file mode 100644 index 091ca97..0000000 --- a/vendor/twig/twig/lib/Twig/FilterCallableInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_FilterCallableInterface -{ - public function getCallable(); -} diff --git a/vendor/twig/twig/lib/Twig/FilterInterface.php b/vendor/twig/twig/lib/Twig/FilterInterface.php deleted file mode 100644 index 9b85f97..0000000 --- a/vendor/twig/twig/lib/Twig/FilterInterface.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_FilterInterface -{ - /** - * Compiles a filter. - * - * @return string The PHP code for the filter - */ - public function compile(); - - public function needsEnvironment(); - - public function needsContext(); - - public function getSafe(Node $filterArgs); - - public function getPreservesSafety(); - - public function getPreEscape(); - - public function setArguments($arguments); - - public function getArguments(); -} diff --git a/vendor/twig/twig/lib/Twig/Function/Function.php b/vendor/twig/twig/lib/Twig/Function/Function.php deleted file mode 100644 index 605d8d3..0000000 --- a/vendor/twig/twig/lib/Twig/Function/Function.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Function_Function extends Twig_Function -{ - protected $function; - - public function __construct($function, array $options = []) - { - $options['callable'] = $function; - - parent::__construct($options); - - $this->function = $function; - } - - public function compile() - { - return $this->function; - } -} diff --git a/vendor/twig/twig/lib/Twig/Function/Method.php b/vendor/twig/twig/lib/Twig/Function/Method.php deleted file mode 100644 index 9e472c5..0000000 --- a/vendor/twig/twig/lib/Twig/Function/Method.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Function_Method extends Twig_Function -{ - protected $extension; - protected $method; - - public function __construct(ExtensionInterface $extension, $method, array $options = []) - { - $options['callable'] = [$extension, $method]; - - parent::__construct($options); - - $this->extension = $extension; - $this->method = $method; - } - - public function compile() - { - return sprintf('$this->env->getExtension(\'%s\')->%s', \get_class($this->extension), $this->method); - } -} diff --git a/vendor/twig/twig/lib/Twig/Function/Node.php b/vendor/twig/twig/lib/Twig/Function/Node.php deleted file mode 100644 index 8148ec3..0000000 --- a/vendor/twig/twig/lib/Twig/Function/Node.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Function_Node extends Twig_Function -{ - protected $class; - - public function __construct($class, array $options = []) - { - parent::__construct($options); - - $this->class = $class; - } - - public function getClass() - { - return $this->class; - } - - public function compile() - { - } -} diff --git a/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php b/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php deleted file mode 100644 index abc83ea..0000000 --- a/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_FunctionCallableInterface -{ - public function getCallable(); -} diff --git a/vendor/twig/twig/lib/Twig/FunctionInterface.php b/vendor/twig/twig/lib/Twig/FunctionInterface.php deleted file mode 100644 index 915d6cc..0000000 --- a/vendor/twig/twig/lib/Twig/FunctionInterface.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_FunctionInterface -{ - /** - * Compiles a function. - * - * @return string The PHP code for the function - */ - public function compile(); - - public function needsEnvironment(); - - public function needsContext(); - - public function getSafe(Node $filterArgs); - - public function setArguments($arguments); - - public function getArguments(); -} diff --git a/vendor/twig/twig/lib/Twig/LexerInterface.php b/vendor/twig/twig/lib/Twig/LexerInterface.php deleted file mode 100644 index cc04f68..0000000 --- a/vendor/twig/twig/lib/Twig/LexerInterface.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_LexerInterface -{ - /** - * Tokenizes a source code. - * - * @param string|Source $code The source code - * @param string $name A unique identifier for the source code - * - * @return TokenStream - * - * @throws SyntaxError When the code is syntactically wrong - */ - public function tokenize($code, $name = null); -} diff --git a/vendor/twig/twig/lib/Twig/Loader/String.php b/vendor/twig/twig/lib/Twig/Loader/String.php deleted file mode 100644 index 348af0c..0000000 --- a/vendor/twig/twig/lib/Twig/Loader/String.php +++ /dev/null @@ -1,63 +0,0 @@ - - */ -class Twig_Loader_String implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface -{ - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', \get_class($this)), E_USER_DEPRECATED); - - return $name; - } - - public function getSourceContext($name) - { - return new Source($name, $name); - } - - public function exists($name) - { - return true; - } - - public function getCacheKey($name) - { - return $name; - } - - public function isFresh($name, $time) - { - return true; - } -} diff --git a/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php b/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php deleted file mode 100644 index 9b8927a..0000000 --- a/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * @deprecated since 1.23 and will be removed in 2.0. - */ -class Twig_Node_Expression_ExtensionReference extends AbstractExpression -{ - public function __construct($name, $lineno, $tag = null) - { - parent::__construct([], ['name' => $name], $lineno, $tag); - } - - public function compile(Compiler $compiler) - { - $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name'))); - } -} diff --git a/vendor/twig/twig/lib/Twig/Node/SetTemp.php b/vendor/twig/twig/lib/Twig/Node/SetTemp.php deleted file mode 100644 index 211ab4e..0000000 --- a/vendor/twig/twig/lib/Twig/Node/SetTemp.php +++ /dev/null @@ -1,11 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_NodeInterface extends \Countable, \IteratorAggregate -{ - /** - * Compiles the node to PHP. - */ - public function compile(Compiler $compiler); - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getLine(); - - public function getNodeTag(); -} diff --git a/vendor/twig/twig/lib/Twig/ParserInterface.php b/vendor/twig/twig/lib/Twig/ParserInterface.php deleted file mode 100644 index 96e9aaa..0000000 --- a/vendor/twig/twig/lib/Twig/ParserInterface.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_ParserInterface -{ - /** - * Converts a token stream to a node tree. - * - * @return ModuleNode - * - * @throws SyntaxError When the token stream is syntactically or semantically wrong - */ - public function parse(TokenStream $stream); -} diff --git a/vendor/twig/twig/lib/Twig/TemplateInterface.php b/vendor/twig/twig/lib/Twig/TemplateInterface.php deleted file mode 100644 index 0f767b8..0000000 --- a/vendor/twig/twig/lib/Twig/TemplateInterface.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_TemplateInterface -{ - const ANY_CALL = 'any'; - const ARRAY_CALL = 'array'; - const METHOD_CALL = 'method'; - - /** - * Renders the template with the given context and returns it as string. - * - * @param array $context An array of parameters to pass to the template - * - * @return string The rendered template - */ - public function render(array $context); - - /** - * Displays the template with the given context. - * - * @param array $context An array of parameters to pass to the template - * @param array $blocks An array of blocks to pass to the template - */ - public function display(array $context, array $blocks = []); - - /** - * Returns the bound environment for this template. - * - * @return Environment - */ - public function getEnvironment(); -} diff --git a/vendor/twig/twig/lib/Twig/Test/Function.php b/vendor/twig/twig/lib/Twig/Test/Function.php deleted file mode 100644 index a789c40..0000000 --- a/vendor/twig/twig/lib/Twig/Test/Function.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Test_Function extends Twig_Test -{ - protected $function; - - public function __construct($function, array $options = []) - { - $options['callable'] = $function; - - parent::__construct($options); - - $this->function = $function; - } - - public function compile() - { - return $this->function; - } -} diff --git a/vendor/twig/twig/lib/Twig/Test/Method.php b/vendor/twig/twig/lib/Twig/Test/Method.php deleted file mode 100644 index 3559f34..0000000 --- a/vendor/twig/twig/lib/Twig/Test/Method.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Test_Method extends Twig_Test -{ - protected $extension; - protected $method; - - public function __construct(ExtensionInterface $extension, $method, array $options = []) - { - $options['callable'] = [$extension, $method]; - - parent::__construct($options); - - $this->extension = $extension; - $this->method = $method; - } - - public function compile() - { - return sprintf('$this->env->getExtension(\'%s\')->%s', \get_class($this->extension), $this->method); - } -} diff --git a/vendor/twig/twig/lib/Twig/Test/Node.php b/vendor/twig/twig/lib/Twig/Test/Node.php deleted file mode 100644 index 6b5de15..0000000 --- a/vendor/twig/twig/lib/Twig/Test/Node.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Test_Node extends Twig_Test -{ - protected $class; - - public function __construct($class, array $options = []) - { - parent::__construct($options); - - $this->class = $class; - } - - public function getClass() - { - return $this->class; - } - - public function compile() - { - } -} diff --git a/vendor/twig/twig/lib/Twig/TestCallableInterface.php b/vendor/twig/twig/lib/Twig/TestCallableInterface.php deleted file mode 100644 index 51ecb9a..0000000 --- a/vendor/twig/twig/lib/Twig/TestCallableInterface.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_TestCallableInterface -{ - public function getCallable(); -} diff --git a/vendor/twig/twig/lib/Twig/TestInterface.php b/vendor/twig/twig/lib/Twig/TestInterface.php deleted file mode 100644 index 9166407..0000000 --- a/vendor/twig/twig/lib/Twig/TestInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_TestInterface -{ - /** - * Compiles a test. - * - * @return string The PHP code for the test - */ - public function compile(); -} diff --git a/vendor/twig/twig/lib/Twig/TokenParserBroker.php b/vendor/twig/twig/lib/Twig/TokenParserBroker.php deleted file mode 100644 index 8cca809..0000000 --- a/vendor/twig/twig/lib/Twig/TokenParserBroker.php +++ /dev/null @@ -1,122 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface -{ - protected $parser; - protected $parsers = []; - protected $brokers = []; - - /** - * @param array|\Traversable $parsers A \Traversable of Twig_TokenParserInterface instances - * @param array|\Traversable $brokers A \Traversable of Twig_TokenParserBrokerInterface instances - * @param bool $triggerDeprecationError - */ - public function __construct($parsers = [], $brokers = [], $triggerDeprecationError = true) - { - if ($triggerDeprecationError) { - @trigger_error('The '.__CLASS__.' class is deprecated since version 1.12 and will be removed in 2.0.', E_USER_DEPRECATED); - } - - foreach ($parsers as $parser) { - if (!$parser instanceof TokenParserInterface) { - throw new \LogicException('$parsers must a an array of Twig_TokenParserInterface.'); - } - $this->parsers[$parser->getTag()] = $parser; - } - foreach ($brokers as $broker) { - if (!$broker instanceof Twig_TokenParserBrokerInterface) { - throw new \LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface.'); - } - $this->brokers[] = $broker; - } - } - - public function addTokenParser(TokenParserInterface $parser) - { - $this->parsers[$parser->getTag()] = $parser; - } - - public function removeTokenParser(TokenParserInterface $parser) - { - $name = $parser->getTag(); - if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) { - unset($this->parsers[$name]); - } - } - - public function addTokenParserBroker(self $broker) - { - $this->brokers[] = $broker; - } - - public function removeTokenParserBroker(self $broker) - { - if (false !== $pos = array_search($broker, $this->brokers)) { - unset($this->brokers[$pos]); - } - } - - /** - * Gets a suitable TokenParser for a tag. - * - * First looks in parsers, then in brokers. - * - * @param string $tag A tag name - * - * @return TokenParserInterface|null A Twig_TokenParserInterface or null if no suitable TokenParser was found - */ - public function getTokenParser($tag) - { - if (isset($this->parsers[$tag])) { - return $this->parsers[$tag]; - } - $broker = end($this->brokers); - while (false !== $broker) { - $parser = $broker->getTokenParser($tag); - if (null !== $parser) { - return $parser; - } - $broker = prev($this->brokers); - } - } - - public function getParsers() - { - return $this->parsers; - } - - public function getParser() - { - return $this->parser; - } - - public function setParser(Twig_ParserInterface $parser) - { - $this->parser = $parser; - foreach ($this->parsers as $tokenParser) { - $tokenParser->setParser($parser); - } - foreach ($this->brokers as $broker) { - $broker->setParser($parser); - } - } -} diff --git a/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php b/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php deleted file mode 100644 index f369264..0000000 --- a/vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.php +++ /dev/null @@ -1,46 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_TokenParserBrokerInterface -{ - /** - * Gets a TokenParser suitable for a tag. - * - * @param string $tag A tag name - * - * @return TokenParserInterface|null A Twig_TokenParserInterface or null if no suitable TokenParser was found - */ - public function getTokenParser($tag); - - /** - * Calls Twig\TokenParser\TokenParserInterface::setParser on all parsers the implementation knows of. - */ - public function setParser(Twig_ParserInterface $parser); - - /** - * Gets the Twig_ParserInterface. - * - * @return Twig_ParserInterface|null A Twig_ParserInterface instance or null - */ - public function getParser(); -} diff --git a/vendor/twig/twig/src/Node/SetTempNode.php b/vendor/twig/twig/src/Node/SetTempNode.php deleted file mode 100644 index 918fb99..0000000 --- a/vendor/twig/twig/src/Node/SetTempNode.php +++ /dev/null @@ -1,44 +0,0 @@ - $name], $lineno); - } - - public function compile(Compiler $compiler) - { - $name = $this->getAttribute('name'); - $compiler - ->addDebugInfo($this) - ->write('if (isset($context[') - ->string($name) - ->raw('])) { $_') - ->raw($name) - ->raw('_ = $context[') - ->repr($name) - ->raw(']; } else { $_') - ->raw($name) - ->raw("_ = null; }\n") - ; - } -} - -class_alias('Twig\Node\SetTempNode', 'Twig_Node_SetTemp'); diff --git a/vendor/zendframework/zend-eventmanager/src/GlobalEventManager.php b/vendor/zendframework/zend-eventmanager/src/GlobalEventManager.php deleted file mode 100644 index 336b69c..0000000 --- a/vendor/zendframework/zend-eventmanager/src/GlobalEventManager.php +++ /dev/null @@ -1,141 +0,0 @@ -trigger($event, $context, $argv, $callback); - } - - /** - * Trigger listeners until return value of one causes a callback to evaluate - * to true. - * - * @param string $event - * @param string|object $context - * @param array|object $argv - * @param callable $callback - * @return ResponseCollection - * @deprecated Please use trigger() - */ - public static function triggerUntil($event, $context, $argv, $callback) - { - trigger_error( - 'This method is deprecated and will be removed in the future. Please use trigger() instead.', - E_USER_DEPRECATED - ); - return static::trigger($event, $context, $argv, $callback); - } - - /** - * Attach a listener to an event - * - * @param string $event - * @param callable $callback - * @param int $priority - * @return CallbackHandler - */ - public static function attach($event, $callback, $priority = 1) - { - return static::getEventCollection()->attach($event, $callback, $priority); - } - - /** - * Detach a callback from a listener - * - * @param CallbackHandler $listener - * @return bool - */ - public static function detach(CallbackHandler $listener) - { - return static::getEventCollection()->detach($listener); - } - - /** - * Retrieve list of events this object manages - * - * @return array - */ - public static function getEvents() - { - return static::getEventCollection()->getEvents(); - } - - /** - * Retrieve all listeners for a given event - * - * @param string $event - * @return PriorityQueue|array - */ - public static function getListeners($event) - { - return static::getEventCollection()->getListeners($event); - } - - /** - * Clear all listeners for a given event - * - * @param string $event - * @return void - */ - public static function clearListeners($event) - { - static::getEventCollection()->clearListeners($event); - } -} diff --git a/vendor/zendframework/zend-eventmanager/src/ProvidesEvents.php b/vendor/zendframework/zend-eventmanager/src/ProvidesEvents.php deleted file mode 100644 index edb19c1..0000000 --- a/vendor/zendframework/zend-eventmanager/src/ProvidesEvents.php +++ /dev/null @@ -1,23 +0,0 @@ -=5.3.23" - }, - "require-dev": { - "zendframework/zend-config": "~2.5", - "zendframework/zend-eventmanager": "~2.5", - "zendframework/zend-inputfilter": "~2.5", - "zendframework/zend-serializer": "~2.5", - "zendframework/zend-servicemanager": "~2.5", - "zendframework/zend-filter": "~2.5", - "fabpot/php-cs-fixer": "1.7.*", - "phpunit/PHPUnit": "~4.0" - }, - "suggest": { - "zendframework/zend-eventmanager": "To support aggregate hydrator usage", - "zendframework/zend-serializer": "Zend\\Serializer component", - "zendframework/zend-servicemanager": "To support hydrator plugin manager usage", - "zendframework/zend-filter": "To support naming strategy hydrator usage" - }, - "minimum-stability": "dev", - "prefer-stable": true, - "extra": { - "branch-alias": { - "dev-master": "2.5-dev", - "dev-develop": "2.6-dev" - } - }, - "autoload-dev": { - "psr-4": { - "ZendTest\\Stdlib\\": "test/" - } - } -} diff --git a/vendor/zendframework/zend-stdlib/src/AbstractOptions.php b/vendor/zendframework/zend-stdlib/src/AbstractOptions.php deleted file mode 100644 index aaa1dd2..0000000 --- a/vendor/zendframework/zend-stdlib/src/AbstractOptions.php +++ /dev/null @@ -1,176 +0,0 @@ -setFromArray($options); - } - } - - /** - * Set one or more configuration properties - * - * @param array|Traversable|AbstractOptions $options - * @throws Exception\InvalidArgumentException - * @return AbstractOptions Provides fluent interface - */ - public function setFromArray($options) - { - if ($options instanceof self) { - $options = $options->toArray(); - } - - if (!is_array($options) && !$options instanceof Traversable) { - throw new Exception\InvalidArgumentException( - sprintf( - 'Parameter provided to %s must be an %s, %s or %s', - __METHOD__, - 'array', - 'Traversable', - 'Zend\Stdlib\AbstractOptions' - ) - ); - } - - foreach ($options as $key => $value) { - $this->__set($key, $value); - } - - return $this; - } - - /** - * Cast to array - * - * @return array - */ - public function toArray() - { - $array = array(); - $transform = function ($letters) { - $letter = array_shift($letters); - return '_' . strtolower($letter); - }; - foreach ($this as $key => $value) { - if ($key === '__strictMode__') { - continue; - } - $normalizedKey = preg_replace_callback('/([A-Z])/', $transform, $key); - $array[$normalizedKey] = $value; - } - return $array; - } - - /** - * Set a configuration property - * - * @see ParameterObject::__set() - * @param string $key - * @param mixed $value - * @throws Exception\BadMethodCallException - * @return void - */ - public function __set($key, $value) - { - $setter = 'set' . str_replace('_', '', $key); - - if (is_callable(array($this, $setter))) { - $this->{$setter}($value); - - return; - } - - if ($this->__strictMode__) { - throw new Exception\BadMethodCallException(sprintf( - 'The option "%s" does not have a callable "%s" ("%s") setter method which must be defined', - $key, - 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))), - $setter - )); - } - } - - /** - * Get a configuration property - * - * @see ParameterObject::__get() - * @param string $key - * @throws Exception\BadMethodCallException - * @return mixed - */ - public function __get($key) - { - $getter = 'get' . str_replace('_', '', $key); - - if (is_callable(array($this, $getter))) { - return $this->{$getter}(); - } - - throw new Exception\BadMethodCallException(sprintf( - 'The option "%s" does not have a callable "%s" getter method which must be defined', - $key, - 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))) - )); - } - - /** - * Test if a configuration property is null - * @see ParameterObject::__isset() - * @param string $key - * @return bool - */ - public function __isset($key) - { - $getter = 'get' . str_replace('_', '', $key); - - return method_exists($this, $getter) && null !== $this->__get($key); - } - - /** - * Set a configuration property to NULL - * - * @see ParameterObject::__unset() - * @param string $key - * @throws Exception\InvalidArgumentException - * @return void - */ - public function __unset($key) - { - try { - $this->__set($key, null); - } catch (Exception\BadMethodCallException $e) { - throw new Exception\InvalidArgumentException( - 'The class property $' . $key . ' cannot be unset as' - . ' NULL is an invalid value for it', - 0, - $e - ); - } - } -} diff --git a/vendor/zendframework/zend-stdlib/src/ArrayObject.php b/vendor/zendframework/zend-stdlib/src/ArrayObject.php deleted file mode 100644 index 44145c8..0000000 --- a/vendor/zendframework/zend-stdlib/src/ArrayObject.php +++ /dev/null @@ -1,432 +0,0 @@ -setFlags($flags); - $this->storage = $input; - $this->setIteratorClass($iteratorClass); - $this->protectedProperties = array_keys(get_object_vars($this)); - } - - /** - * Returns whether the requested key exists - * - * @param mixed $key - * @return bool - */ - public function __isset($key) - { - if ($this->flag == self::ARRAY_AS_PROPS) { - return $this->offsetExists($key); - } - if (in_array($key, $this->protectedProperties)) { - throw new Exception\InvalidArgumentException('$key is a protected property, use a different key'); - } - - return isset($this->$key); - } - - /** - * Sets the value at the specified key to value - * - * @param mixed $key - * @param mixed $value - * @return void - */ - public function __set($key, $value) - { - if ($this->flag == self::ARRAY_AS_PROPS) { - return $this->offsetSet($key, $value); - } - if (in_array($key, $this->protectedProperties)) { - throw new Exception\InvalidArgumentException('$key is a protected property, use a different key'); - } - $this->$key = $value; - } - - /** - * Unsets the value at the specified key - * - * @param mixed $key - * @return void - */ - public function __unset($key) - { - if ($this->flag == self::ARRAY_AS_PROPS) { - return $this->offsetUnset($key); - } - if (in_array($key, $this->protectedProperties)) { - throw new Exception\InvalidArgumentException('$key is a protected property, use a different key'); - } - unset($this->$key); - } - - /** - * Returns the value at the specified key by reference - * - * @param mixed $key - * @return mixed - */ - public function &__get($key) - { - $ret = null; - if ($this->flag == self::ARRAY_AS_PROPS) { - $ret =& $this->offsetGet($key); - - return $ret; - } - if (in_array($key, $this->protectedProperties)) { - throw new Exception\InvalidArgumentException('$key is a protected property, use a different key'); - } - - return $this->$key; - } - - /** - * Appends the value - * - * @param mixed $value - * @return void - */ - public function append($value) - { - $this->storage[] = $value; - } - - /** - * Sort the entries by value - * - * @return void - */ - public function asort() - { - asort($this->storage); - } - - /** - * Get the number of public properties in the ArrayObject - * - * @return int - */ - public function count() - { - return count($this->storage); - } - - /** - * Exchange the array for another one. - * - * @param array|ArrayObject $data - * @return array - */ - public function exchangeArray($data) - { - if (!is_array($data) && !is_object($data)) { - throw new Exception\InvalidArgumentException('Passed variable is not an array or object, using empty array instead'); - } - - if (is_object($data) && ($data instanceof self || $data instanceof \ArrayObject)) { - $data = $data->getArrayCopy(); - } - if (!is_array($data)) { - $data = (array) $data; - } - - $storage = $this->storage; - - $this->storage = $data; - - return $storage; - } - - /** - * Creates a copy of the ArrayObject. - * - * @return array - */ - public function getArrayCopy() - { - return $this->storage; - } - - /** - * Gets the behavior flags. - * - * @return int - */ - public function getFlags() - { - return $this->flag; - } - - /** - * Create a new iterator from an ArrayObject instance - * - * @return \Iterator - */ - public function getIterator() - { - $class = $this->iteratorClass; - - return new $class($this->storage); - } - - /** - * Gets the iterator classname for the ArrayObject. - * - * @return string - */ - public function getIteratorClass() - { - return $this->iteratorClass; - } - - /** - * Sort the entries by key - * - * @return void - */ - public function ksort() - { - ksort($this->storage); - } - - /** - * Sort an array using a case insensitive "natural order" algorithm - * - * @return void - */ - public function natcasesort() - { - natcasesort($this->storage); - } - - /** - * Sort entries using a "natural order" algorithm - * - * @return void - */ - public function natsort() - { - natsort($this->storage); - } - - /** - * Returns whether the requested key exists - * - * @param mixed $key - * @return bool - */ - public function offsetExists($key) - { - return isset($this->storage[$key]); - } - - /** - * Returns the value at the specified key - * - * @param mixed $key - * @return mixed - */ - public function &offsetGet($key) - { - $ret = null; - if (!$this->offsetExists($key)) { - return $ret; - } - $ret =& $this->storage[$key]; - - return $ret; - } - - /** - * Sets the value at the specified key to value - * - * @param mixed $key - * @param mixed $value - * @return void - */ - public function offsetSet($key, $value) - { - $this->storage[$key] = $value; - } - - /** - * Unsets the value at the specified key - * - * @param mixed $key - * @return void - */ - public function offsetUnset($key) - { - if ($this->offsetExists($key)) { - unset($this->storage[$key]); - } - } - - /** - * Serialize an ArrayObject - * - * @return string - */ - public function serialize() - { - return serialize(get_object_vars($this)); - } - - /** - * Sets the behavior flags - * - * @param int $flags - * @return void - */ - public function setFlags($flags) - { - $this->flag = $flags; - } - - /** - * Sets the iterator classname for the ArrayObject - * - * @param string $class - * @return void - */ - public function setIteratorClass($class) - { - if (class_exists($class)) { - $this->iteratorClass = $class; - - return ; - } - - if (strpos($class, '\\') === 0) { - $class = '\\' . $class; - if (class_exists($class)) { - $this->iteratorClass = $class; - - return ; - } - } - - throw new Exception\InvalidArgumentException('The iterator class does not exist'); - } - - /** - * Sort the entries with a user-defined comparison function and maintain key association - * - * @param callable $function - * @return void - */ - public function uasort($function) - { - if (is_callable($function)) { - uasort($this->storage, $function); - } - } - - /** - * Sort the entries by keys using a user-defined comparison function - * - * @param callable $function - * @return void - */ - public function uksort($function) - { - if (is_callable($function)) { - uksort($this->storage, $function); - } - } - - /** - * Unserialize an ArrayObject - * - * @param string $data - * @return void - */ - public function unserialize($data) - { - $ar = unserialize($data); - $this->protectedProperties = array_keys(get_object_vars($this)); - - $this->setFlags($ar['flag']); - $this->exchangeArray($ar['storage']); - $this->setIteratorClass($ar['iteratorClass']); - - foreach ($ar as $k => $v) { - switch ($k) { - case 'flag': - $this->setFlags($v); - break; - case 'storage': - $this->exchangeArray($v); - break; - case 'iteratorClass': - $this->setIteratorClass($v); - break; - case 'protectedProperties': - continue; - default: - $this->__set($k, $v); - } - } - } -} diff --git a/vendor/zendframework/zend-stdlib/src/ArraySerializableInterface.php b/vendor/zendframework/zend-stdlib/src/ArraySerializableInterface.php deleted file mode 100644 index dcf8471..0000000 --- a/vendor/zendframework/zend-stdlib/src/ArraySerializableInterface.php +++ /dev/null @@ -1,28 +0,0 @@ -getArrayCopy(); - return new ArrayIterator(array_reverse($array)); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/ArrayUtils.php b/vendor/zendframework/zend-stdlib/src/ArrayUtils.php deleted file mode 100644 index 3545054..0000000 --- a/vendor/zendframework/zend-stdlib/src/ArrayUtils.php +++ /dev/null @@ -1,335 +0,0 @@ - 0; - } - - /** - * Test whether an array contains one or more integer keys - * - * @param mixed $value - * @param bool $allowEmpty Should an empty array() return true - * @return bool - */ - public static function hasIntegerKeys($value, $allowEmpty = false) - { - if (!is_array($value)) { - return false; - } - - if (!$value) { - return $allowEmpty; - } - - return count(array_filter(array_keys($value), 'is_int')) > 0; - } - - /** - * Test whether an array contains one or more numeric keys. - * - * A numeric key can be one of the following: - * - an integer 1, - * - a string with a number '20' - * - a string with negative number: '-1000' - * - a float: 2.2120, -78.150999 - * - a string with float: '4000.99999', '-10.10' - * - * @param mixed $value - * @param bool $allowEmpty Should an empty array() return true - * @return bool - */ - public static function hasNumericKeys($value, $allowEmpty = false) - { - if (!is_array($value)) { - return false; - } - - if (!$value) { - return $allowEmpty; - } - - return count(array_filter(array_keys($value), 'is_numeric')) > 0; - } - - /** - * Test whether an array is a list - * - * A list is a collection of values assigned to continuous integer keys - * starting at 0 and ending at count() - 1. - * - * For example: - * - * $list = array('a', 'b', 'c', 'd'); - * $list = array( - * 0 => 'foo', - * 1 => 'bar', - * 2 => array('foo' => 'baz'), - * ); - * - * - * @param mixed $value - * @param bool $allowEmpty Is an empty list a valid list? - * @return bool - */ - public static function isList($value, $allowEmpty = false) - { - if (!is_array($value)) { - return false; - } - - if (!$value) { - return $allowEmpty; - } - - return (array_values($value) === $value); - } - - /** - * Test whether an array is a hash table. - * - * An array is a hash table if: - * - * 1. Contains one or more non-integer keys, or - * 2. Integer keys are non-continuous or misaligned (not starting with 0) - * - * For example: - * - * $hash = array( - * 'foo' => 15, - * 'bar' => false, - * ); - * $hash = array( - * 1995 => 'Birth of PHP', - * 2009 => 'PHP 5.3.0', - * 2012 => 'PHP 5.4.0', - * ); - * $hash = array( - * 'formElement, - * 'options' => array( 'debug' => true ), - * ); - * - * - * @param mixed $value - * @param bool $allowEmpty Is an empty array() a valid hash table? - * @return bool - */ - public static function isHashTable($value, $allowEmpty = false) - { - if (!is_array($value)) { - return false; - } - - if (!$value) { - return $allowEmpty; - } - - return (array_values($value) !== $value); - } - - /** - * Checks if a value exists in an array. - * - * Due to "foo" == 0 === TRUE with in_array when strict = false, an option - * has been added to prevent this. When $strict = 0/false, the most secure - * non-strict check is implemented. if $strict = -1, the default in_array - * non-strict behaviour is used. - * - * @param mixed $needle - * @param array $haystack - * @param int|bool $strict - * @return bool - */ - public static function inArray($needle, array $haystack, $strict = false) - { - if (!$strict) { - if (is_int($needle) || is_float($needle)) { - $needle = (string) $needle; - } - if (is_string($needle)) { - foreach ($haystack as &$h) { - if (is_int($h) || is_float($h)) { - $h = (string) $h; - } - } - } - } - return in_array($needle, $haystack, $strict); - } - - /** - * Convert an iterator to an array. - * - * Converts an iterator to an array. The $recursive flag, on by default, - * hints whether or not you want to do so recursively. - * - * @param array|Traversable $iterator The array or Traversable object to convert - * @param bool $recursive Recursively check all nested structures - * @throws Exception\InvalidArgumentException if $iterator is not an array or a Traversable object - * @return array - */ - public static function iteratorToArray($iterator, $recursive = true) - { - if (!is_array($iterator) && !$iterator instanceof Traversable) { - throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable object'); - } - - if (!$recursive) { - if (is_array($iterator)) { - return $iterator; - } - - return iterator_to_array($iterator); - } - - if (method_exists($iterator, 'toArray')) { - return $iterator->toArray(); - } - - $array = array(); - foreach ($iterator as $key => $value) { - if (is_scalar($value)) { - $array[$key] = $value; - continue; - } - - if ($value instanceof Traversable) { - $array[$key] = static::iteratorToArray($value, $recursive); - continue; - } - - if (is_array($value)) { - $array[$key] = static::iteratorToArray($value, $recursive); - continue; - } - - $array[$key] = $value; - } - - return $array; - } - - /** - * Merge two arrays together. - * - * If an integer key exists in both arrays and preserveNumericKeys is false, the value - * from the second array will be appended to the first array. If both values are arrays, they - * are merged together, else the value of the second array overwrites the one of the first array. - * - * @param array $a - * @param array $b - * @param bool $preserveNumericKeys - * @return array - */ - public static function merge(array $a, array $b, $preserveNumericKeys = false) - { - foreach ($b as $key => $value) { - if ($value instanceof MergeReplaceKeyInterface) { - $a[$key] = $value->getData(); - } elseif (isset($a[$key]) || array_key_exists($key, $a)) { - if ($value instanceof MergeRemoveKey) { - unset($a[$key]); - } elseif (!$preserveNumericKeys && is_int($key)) { - $a[] = $value; - } elseif (is_array($value) && is_array($a[$key])) { - $a[$key] = static::merge($a[$key], $value, $preserveNumericKeys); - } else { - $a[$key] = $value; - } - } else { - if (!$value instanceof MergeRemoveKey) { - $a[$key] = $value; - } - } - } - - return $a; - } - - /** - * Compatibility Method for array_filter on <5.6 systems - * - * @param array $data - * @param callable $callback - * @param null|int $flag - * @return array - */ - public static function filter(array $data, $callback, $flag = null) - { - if (! is_callable($callback)) { - throw new Exception\InvalidArgumentException(sprintf( - 'Second parameter of %s must be callable', - __METHOD__ - )); - } - - if (version_compare(PHP_VERSION, '5.6.0') >= 0) { - return array_filter($data, $callback, $flag); - } - - $output = array(); - foreach ($data as $key => $value) { - $params = array($value); - - if ($flag === static::ARRAY_FILTER_USE_BOTH) { - $params[] = $key; - } - - if ($flag === static::ARRAY_FILTER_USE_KEY) { - $params = array($key); - } - - $response = call_user_func_array($callback, $params); - if ($response) { - $output[$key] = $value; - } - } - - return $output; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeRemoveKey.php b/vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeRemoveKey.php deleted file mode 100644 index 7c4d097..0000000 --- a/vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeRemoveKey.php +++ /dev/null @@ -1,14 +0,0 @@ -data = $data; - } - - /** - * {@inheritDoc} - */ - public function getData() - { - return $this->data; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeReplaceKeyInterface.php b/vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeReplaceKeyInterface.php deleted file mode 100644 index 725cf11..0000000 --- a/vendor/zendframework/zend-stdlib/src/ArrayUtils/MergeReplaceKeyInterface.php +++ /dev/null @@ -1,21 +0,0 @@ -metadata = $metadata; - $this->registerCallback($callback); - } - - /** - * Registers the callback provided in the constructor - * - * @param callable $callback - * @throws Exception\InvalidCallbackException - * @return void - */ - protected function registerCallback($callback) - { - if (!is_callable($callback)) { - throw new Exception\InvalidCallbackException('Invalid callback provided; not callable'); - } - - $this->callback = $callback; - } - - /** - * Retrieve registered callback - * - * @return callable - */ - public function getCallback() - { - return $this->callback; - } - - /** - * Invoke handler - * - * @param array $args Arguments to pass to callback - * @return mixed - */ - public function call(array $args = array()) - { - $callback = $this->getCallback(); - - // Minor performance tweak, if the callback gets called more than once - if (!isset(static::$isPhp54)) { - static::$isPhp54 = version_compare(PHP_VERSION, '5.4.0rc1', '>='); - } - - $argCount = count($args); - - if (static::$isPhp54 && is_string($callback)) { - $result = $this->validateStringCallbackFor54($callback); - - if ($result !== true && $argCount <= 3) { - $callback = $result; - // Minor performance tweak, if the callback gets called more - // than once - $this->callback = $result; - } - } - - // Minor performance tweak; use call_user_func() until > 3 arguments - // reached - switch ($argCount) { - case 0: - if (static::$isPhp54) { - return $callback(); - } - return call_user_func($callback); - case 1: - if (static::$isPhp54) { - return $callback(array_shift($args)); - } - return call_user_func($callback, array_shift($args)); - case 2: - $arg1 = array_shift($args); - $arg2 = array_shift($args); - if (static::$isPhp54) { - return $callback($arg1, $arg2); - } - return call_user_func($callback, $arg1, $arg2); - case 3: - $arg1 = array_shift($args); - $arg2 = array_shift($args); - $arg3 = array_shift($args); - if (static::$isPhp54) { - return $callback($arg1, $arg2, $arg3); - } - return call_user_func($callback, $arg1, $arg2, $arg3); - default: - return call_user_func_array($callback, $args); - } - } - - /** - * Invoke as functor - * - * @return mixed - */ - public function __invoke() - { - return $this->call(func_get_args()); - } - - /** - * Get all callback metadata - * - * @return array - */ - public function getMetadata() - { - return $this->metadata; - } - - /** - * Retrieve a single metadatum - * - * @param string $name - * @return mixed - */ - public function getMetadatum($name) - { - if (array_key_exists($name, $this->metadata)) { - return $this->metadata[$name]; - } - return; - } - - /** - * Validate a static method call - * - * Validates that a static method call in PHP 5.4 will actually work - * - * @param string $callback - * @return true|array - * @throws Exception\InvalidCallbackException if invalid - */ - protected function validateStringCallbackFor54($callback) - { - if (!strstr($callback, '::')) { - return true; - } - - list($class, $method) = explode('::', $callback, 2); - - if (!class_exists($class)) { - throw new Exception\InvalidCallbackException(sprintf( - 'Static method call "%s" refers to a class that does not exist', - $callback - )); - } - - $r = new ReflectionClass($class); - if (!$r->hasMethod($method)) { - throw new Exception\InvalidCallbackException(sprintf( - 'Static method call "%s" refers to a method that does not exist', - $callback - )); - } - $m = $r->getMethod($method); - if (!$m->isStatic()) { - throw new Exception\InvalidCallbackException(sprintf( - 'Static method call "%s" refers to a method that is not static', - $callback - )); - } - - // returning a non boolean value may not be nice for a validate method, - // but that allows the usage of a static string callback without using - // the call_user_func function. - return array($class, $method); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/DateTime.php b/vendor/zendframework/zend-stdlib/src/DateTime.php deleted file mode 100644 index cdab67d..0000000 --- a/vendor/zendframework/zend-stdlib/src/DateTime.php +++ /dev/null @@ -1,47 +0,0 @@ - GLOB_MARK, - self::GLOB_NOSORT => GLOB_NOSORT, - self::GLOB_NOCHECK => GLOB_NOCHECK, - self::GLOB_NOESCAPE => GLOB_NOESCAPE, - self::GLOB_BRACE => GLOB_BRACE, - self::GLOB_ONLYDIR => GLOB_ONLYDIR, - self::GLOB_ERR => GLOB_ERR, - ); - - $globFlags = 0; - - foreach ($flagMap as $internalFlag => $globFlag) { - if ($flags & $internalFlag) { - $globFlags |= $globFlag; - } - } - } else { - $globFlags = 0; - } - - ErrorHandler::start(); - $res = glob($pattern, $globFlags); - $err = ErrorHandler::stop(); - if ($res === false) { - throw new Exception\RuntimeException("glob('{$pattern}', {$globFlags}) failed", 0, $err); - } - return $res; - } - - /** - * Expand braces manually, then use the system glob. - * - * @param string $pattern - * @param int $flags - * @return array - * @throws Exception\RuntimeException - */ - protected static function fallbackGlob($pattern, $flags) - { - if (!$flags & self::GLOB_BRACE) { - return static::systemGlob($pattern, $flags); - } - - $flags &= ~self::GLOB_BRACE; - $length = strlen($pattern); - $paths = array(); - - if ($flags & self::GLOB_NOESCAPE) { - $begin = strpos($pattern, '{'); - } else { - $begin = 0; - - while (true) { - if ($begin === $length) { - $begin = false; - break; - } elseif ($pattern[$begin] === '\\' && ($begin + 1) < $length) { - $begin++; - } elseif ($pattern[$begin] === '{') { - break; - } - - $begin++; - } - } - - if ($begin === false) { - return static::systemGlob($pattern, $flags); - } - - $next = static::nextBraceSub($pattern, $begin + 1, $flags); - - if ($next === null) { - return static::systemGlob($pattern, $flags); - } - - $rest = $next; - - while ($pattern[$rest] !== '}') { - $rest = static::nextBraceSub($pattern, $rest + 1, $flags); - - if ($rest === null) { - return static::systemGlob($pattern, $flags); - } - } - - $p = $begin + 1; - - while (true) { - $subPattern = substr($pattern, 0, $begin) - . substr($pattern, $p, $next - $p) - . substr($pattern, $rest + 1); - - $result = static::fallbackGlob($subPattern, $flags | self::GLOB_BRACE); - - if ($result) { - $paths = array_merge($paths, $result); - } - - if ($pattern[$next] === '}') { - break; - } - - $p = $next + 1; - $next = static::nextBraceSub($pattern, $p, $flags); - } - - return array_unique($paths); - } - - /** - * Find the end of the sub-pattern in a brace expression. - * - * @param string $pattern - * @param int $begin - * @param int $flags - * @return int|null - */ - protected static function nextBraceSub($pattern, $begin, $flags) - { - $length = strlen($pattern); - $depth = 0; - $current = $begin; - - while ($current < $length) { - if (!$flags & self::GLOB_NOESCAPE && $pattern[$current] === '\\') { - if (++$current === $length) { - break; - } - - $current++; - } else { - if (($pattern[$current] === '}' && $depth-- === 0) || ($pattern[$current] === ',' && $depth === 0)) { - break; - } elseif ($pattern[$current++] === '{') { - $depth++; - } - } - } - - return ($current < $length ? $current : null); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Guard/AllGuardsTrait.php b/vendor/zendframework/zend-stdlib/src/Guard/AllGuardsTrait.php deleted file mode 100644 index 95bc516..0000000 --- a/vendor/zendframework/zend-stdlib/src/Guard/AllGuardsTrait.php +++ /dev/null @@ -1,20 +0,0 @@ -strategies = new ArrayObject(); - $this->filterComposite = new FilterComposite(); - } - - /** - * Gets the strategy with the given name. - * - * @param string $name The name of the strategy to get. - * - * @throws \Zend\Stdlib\Exception\InvalidArgumentException - * @return StrategyInterface - */ - public function getStrategy($name) - { - if (isset($this->strategies[$name])) { - return $this->strategies[$name]; - } - - if (!isset($this->strategies['*'])) { - throw new Exception\InvalidArgumentException(sprintf( - '%s: no strategy by name of "%s", and no wildcard strategy present', - __METHOD__, - $name - )); - } - - return $this->strategies['*']; - } - - /** - * Checks if the strategy with the given name exists. - * - * @param string $name The name of the strategy to check for. - * @return bool - */ - public function hasStrategy($name) - { - return array_key_exists($name, $this->strategies) - || array_key_exists('*', $this->strategies); - } - - /** - * Adds the given strategy under the given name. - * - * @param string $name The name of the strategy to register. - * @param StrategyInterface $strategy The strategy to register. - * @return HydratorInterface - */ - public function addStrategy($name, StrategyInterface $strategy) - { - $this->strategies[$name] = $strategy; - return $this; - } - - /** - * Removes the strategy with the given name. - * - * @param string $name The name of the strategy to remove. - * @return HydratorInterface - */ - public function removeStrategy($name) - { - unset($this->strategies[$name]); - return $this; - } - - /** - * Converts a value for extraction. If no strategy exists the plain value is returned. - * - * @param string $name The name of the strategy to use. - * @param mixed $value The value that should be converted. - * @param mixed $object The object is optionally provided as context. - * @return mixed - */ - public function extractValue($name, $value, $object = null) - { - if ($this->hasStrategy($name)) { - $strategy = $this->getStrategy($name); - $value = $strategy->extract($value, $object); - } - return $value; - } - - /** - * Converts a value for hydration. If no strategy exists the plain value is returned. - * - * @param string $name The name of the strategy to use. - * @param mixed $value The value that should be converted. - * @param array $data The whole data is optionally provided as context. - * @return mixed - */ - public function hydrateValue($name, $value, $data = null) - { - if ($this->hasStrategy($name)) { - $strategy = $this->getStrategy($name); - $value = $strategy->hydrate($value, $data); - } - return $value; - } - - /** - * Convert a name for extraction. If no naming strategy exists, the plain value is returned. - * - * @param string $name The name to convert. - * @param null $object The object is optionally provided as context. - * @return mixed - */ - public function extractName($name, $object = null) - { - if ($this->hasNamingStrategy()) { - $name = $this->getNamingStrategy()->extract($name, $object); - } - return $name; - } - - /** - * Converts a value for hydration. If no naming strategy exists, the plain value is returned. - * - * @param string $name The name to convert. - * @param array $data The whole data is optionally provided as context. - * @return mixed - */ - public function hydrateName($name, $data = null) - { - if ($this->hasNamingStrategy()) { - $name = $this->getNamingStrategy()->hydrate($name, $data); - } - return $name; - } - - /** - * Get the filter instance - * - * @return Filter\FilterComposite - */ - public function getFilter() - { - return $this->filterComposite; - } - - /** - * Add a new filter to take care of what needs to be hydrated. - * To exclude e.g. the method getServiceLocator: - * - * - * $composite->addFilter("servicelocator", - * function ($property) { - * list($class, $method) = explode('::', $property); - * if ($method === 'getServiceLocator') { - * return false; - * } - * return true; - * }, FilterComposite::CONDITION_AND - * ); - * - * - * @param string $name Index in the composite - * @param callable|Filter\FilterInterface $filter - * @param int $condition - * @return Filter\FilterComposite - */ - public function addFilter($name, $filter, $condition = FilterComposite::CONDITION_OR) - { - return $this->filterComposite->addFilter($name, $filter, $condition); - } - - /** - * Check whether a specific filter exists at key $name or not - * - * @param string $name Index in the composite - * @return bool - */ - public function hasFilter($name) - { - return $this->filterComposite->hasFilter($name); - } - - /** - * Remove a filter from the composition. - * To not extract "has" methods, you simply need to unregister it - * - * - * $filterComposite->removeFilter('has'); - * - * - * @param $name - * @return Filter\FilterComposite - */ - public function removeFilter($name) - { - return $this->filterComposite->removeFilter($name); - } - - /** - * Adds the given naming strategy - * - * @param NamingStrategyInterface $strategy The naming to register. - * @return self - */ - public function setNamingStrategy(NamingStrategyInterface $strategy) - { - $this->namingStrategy = $strategy; - - return $this; - } - - /** - * Gets the naming strategy. - * - * @return NamingStrategyInterface - */ - public function getNamingStrategy() - { - return $this->namingStrategy; - } - - /** - * Checks if a naming strategy exists. - * - * @return bool - */ - public function hasNamingStrategy() - { - return isset($this->namingStrategy); - } - - /** - * Removes the naming strategy - * - * @return self - */ - public function removeNamingStrategy() - { - $this->namingStrategy = null; - - return $this; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/AggregateHydrator.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/AggregateHydrator.php deleted file mode 100644 index 38a868e..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/AggregateHydrator.php +++ /dev/null @@ -1,85 +0,0 @@ -getEventManager()->attachAggregate(new HydratorListener($hydrator), $priority); - } - - /** - * {@inheritDoc} - */ - public function extract($object) - { - $event = new ExtractEvent($this, $object); - - $this->getEventManager()->trigger($event); - - return $event->getExtractedData(); - } - - /** - * {@inheritDoc} - */ - public function hydrate(array $data, $object) - { - $event = new HydrateEvent($this, $object, $data); - - $this->getEventManager()->trigger($event); - - return $event->getHydratedObject(); - } - - /** - * {@inheritDoc} - */ - public function setEventManager(EventManagerInterface $eventManager) - { - $eventManager->setIdentifiers(array(__CLASS__, get_class($this))); - - $this->eventManager = $eventManager; - } - - /** - * {@inheritDoc} - */ - public function getEventManager() - { - if (null === $this->eventManager) { - $this->setEventManager(new EventManager()); - } - - return $this->eventManager; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/ExtractEvent.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/ExtractEvent.php deleted file mode 100644 index b13bc5c..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/ExtractEvent.php +++ /dev/null @@ -1,98 +0,0 @@ -target = $target; - $this->extractionObject = $extractionObject; - } - - /** - * Retrieves the object from which data is extracted - * - * @return object - */ - public function getExtractionObject() - { - return $this->extractionObject; - } - - /** - * @param object $extractionObject - * - * @return void - */ - public function setExtractionObject($extractionObject) - { - $this->extractionObject = $extractionObject; - } - - /** - * Retrieves the data that has been extracted - * - * @return array - */ - public function getExtractedData() - { - return $this->extractedData; - } - - /** - * @param array $extractedData - * - * @return void - */ - public function setExtractedData(array $extractedData) - { - $this->extractedData = $extractedData; - } - - /** - * Merge provided data with the extracted data - * - * @param array $additionalData - * - * @return void - */ - public function mergeExtractedData(array $additionalData) - { - $this->extractedData = array_merge($this->extractedData, $additionalData); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/HydrateEvent.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/HydrateEvent.php deleted file mode 100644 index a7c91ee..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/HydrateEvent.php +++ /dev/null @@ -1,84 +0,0 @@ -target = $target; - $this->hydratedObject = $hydratedObject; - $this->hydrationData = $hydrationData; - } - - /** - * Retrieves the object that is being hydrated - * - * @return object - */ - public function getHydratedObject() - { - return $this->hydratedObject; - } - - /** - * @param object $hydratedObject - */ - public function setHydratedObject($hydratedObject) - { - $this->hydratedObject = $hydratedObject; - } - - /** - * Retrieves the data that is being used for hydration - * - * @return array - */ - public function getHydrationData() - { - return $this->hydrationData; - } - - /** - * @param array $hydrationData - */ - public function setHydrationData(array $hydrationData) - { - $this->hydrationData = $hydrationData; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/HydratorListener.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/HydratorListener.php deleted file mode 100644 index 1c25ff3..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Aggregate/HydratorListener.php +++ /dev/null @@ -1,80 +0,0 @@ -hydrator = $hydrator; - } - - /** - * {@inheritDoc} - */ - public function attach(EventManagerInterface $events, $priority = 1) - { - $this->listeners[] = $events->attach(HydrateEvent::EVENT_HYDRATE, array($this, 'onHydrate'), $priority); - $this->listeners[] = $events->attach(ExtractEvent::EVENT_EXTRACT, array($this, 'onExtract'), $priority); - } - - /** - * Callback to be used when {@see \Zend\Stdlib\Hydrator\Aggregate\HydrateEvent::EVENT_HYDRATE} is triggered - * - * @param \Zend\Stdlib\Hydrator\Aggregate\HydrateEvent $event - * - * @return object - * - * @internal - */ - public function onHydrate(HydrateEvent $event) - { - $object = $this->hydrator->hydrate($event->getHydrationData(), $event->getHydratedObject()); - - $event->setHydratedObject($object); - - return $object; - } - - /** - * Callback to be used when {@see \Zend\Stdlib\Hydrator\Aggregate\ExtractEvent::EVENT_EXTRACT} is triggered - * - * @param \Zend\Stdlib\Hydrator\Aggregate\ExtractEvent $event - * - * @return array - * - * @internal - */ - public function onExtract(ExtractEvent $event) - { - $data = $this->hydrator->extract($event->getExtractionObject()); - - $event->mergeExtractedData($data); - - return $data; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/ArraySerializable.php b/vendor/zendframework/zend-stdlib/src/Hydrator/ArraySerializable.php deleted file mode 100644 index 4f4ab2a..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/ArraySerializable.php +++ /dev/null @@ -1,83 +0,0 @@ -getArrayCopy(); - $filter = $this->getFilter(); - - foreach ($data as $name => $value) { - if (!$filter->filter($name)) { - unset($data[$name]); - continue; - } - $extractedName = $this->extractName($name, $object); - // replace the original key with extracted, if differ - if ($extractedName !== $name) { - unset($data[$name]); - $name = $extractedName; - } - $data[$name] = $this->extractValue($name, $value, $object); - } - - return $data; - } - - /** - * Hydrate an object - * - * Hydrates an object by passing $data to either its exchangeArray() or - * populate() method. - * - * @param array $data - * @param object $object - * @return object - * @throws Exception\BadMethodCallException for an $object not implementing exchangeArray() or populate() - */ - public function hydrate(array $data, $object) - { - $replacement = array(); - foreach ($data as $key => $value) { - $name = $this->hydrateName($key, $data); - $replacement[$name] = $this->hydrateValue($name, $value, $data); - } - - if (is_callable(array($object, 'exchangeArray'))) { - $object->exchangeArray($replacement); - } elseif (is_callable(array($object, 'populate'))) { - $object->populate($replacement); - } else { - throw new Exception\BadMethodCallException( - sprintf('%s expects the provided object to implement exchangeArray() or populate()', __METHOD__) - ); - } - return $object; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/ClassMethods.php b/vendor/zendframework/zend-stdlib/src/Hydrator/ClassMethods.php deleted file mode 100644 index 4edb1f4..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/ClassMethods.php +++ /dev/null @@ -1,274 +0,0 @@ -setUnderscoreSeparatedKeys($underscoreSeparatedKeys); - - $this->callableMethodFilter = new OptionalParametersFilter(); - - $this->filterComposite->addFilter('is', new IsFilter()); - $this->filterComposite->addFilter('has', new HasFilter()); - $this->filterComposite->addFilter('get', new GetFilter()); - $this->filterComposite->addFilter('parameter', new OptionalParametersFilter(), FilterComposite::CONDITION_AND); - } - - /** - * @param array|Traversable $options - * @return ClassMethods - * @throws Exception\InvalidArgumentException - */ - public function setOptions($options) - { - if ($options instanceof Traversable) { - $options = ArrayUtils::iteratorToArray($options); - } elseif (!is_array($options)) { - throw new Exception\InvalidArgumentException( - 'The options parameter must be an array or a Traversable' - ); - } - if (isset($options['underscoreSeparatedKeys'])) { - $this->setUnderscoreSeparatedKeys($options['underscoreSeparatedKeys']); - } - - return $this; - } - - /** - * @param bool $underscoreSeparatedKeys - * @return ClassMethods - */ - public function setUnderscoreSeparatedKeys($underscoreSeparatedKeys) - { - $this->underscoreSeparatedKeys = (bool) $underscoreSeparatedKeys; - - if ($this->underscoreSeparatedKeys) { - $this->setNamingStrategy(new UnderscoreNamingStrategy); - } elseif ($this->getNamingStrategy() instanceof UnderscoreNamingStrategy) { - $this->removeNamingStrategy(); - } - - return $this; - } - - /** - * @return bool - */ - public function getUnderscoreSeparatedKeys() - { - return $this->underscoreSeparatedKeys; - } - - /** - * Extract values from an object with class methods - * - * Extracts the getter/setter of the given $object. - * - * @param object $object - * @return array - * @throws Exception\BadMethodCallException for a non-object $object - */ - public function extract($object) - { - if (!is_object($object)) { - throw new Exception\BadMethodCallException(sprintf( - '%s expects the provided $object to be a PHP object)', - __METHOD__ - )); - } - - $objectClass = get_class($object); - - // reset the hydrator's hydrator's cache for this object, as the filter may be per-instance - if ($object instanceof FilterProviderInterface) { - $this->extractionMethodsCache[$objectClass] = null; - } - - // pass 1 - finding out which properties can be extracted, with which methods (populate hydration cache) - if (! isset($this->extractionMethodsCache[$objectClass])) { - $this->extractionMethodsCache[$objectClass] = array(); - $filter = $this->filterComposite; - $methods = get_class_methods($object); - - if ($object instanceof FilterProviderInterface) { - $filter = new FilterComposite( - array($object->getFilter()), - array(new MethodMatchFilter('getFilter')) - ); - } - - foreach ($methods as $method) { - $methodFqn = $objectClass . '::' . $method; - - if (! ($filter->filter($methodFqn) && $this->callableMethodFilter->filter($methodFqn))) { - continue; - } - - $attribute = $method; - - if (strpos($method, 'get') === 0) { - $attribute = substr($method, 3); - if (!property_exists($object, $attribute)) { - $attribute = lcfirst($attribute); - } - } - - $this->extractionMethodsCache[$objectClass][$method] = $attribute; - } - } - - $values = array(); - - // pass 2 - actually extract data - foreach ($this->extractionMethodsCache[$objectClass] as $methodName => $attributeName) { - $realAttributeName = $this->extractName($attributeName, $object); - $values[$realAttributeName] = $this->extractValue($realAttributeName, $object->$methodName(), $object); - } - - return $values; - } - - /** - * Hydrate an object by populating getter/setter methods - * - * Hydrates an object by getter/setter methods of the object. - * - * @param array $data - * @param object $object - * @return object - * @throws Exception\BadMethodCallException for a non-object $object - */ - public function hydrate(array $data, $object) - { - if (!is_object($object)) { - throw new Exception\BadMethodCallException(sprintf( - '%s expects the provided $object to be a PHP object)', - __METHOD__ - )); - } - - $objectClass = get_class($object); - - foreach ($data as $property => $value) { - $propertyFqn = $objectClass . '::$' . $property; - - if (! isset($this->hydrationMethodsCache[$propertyFqn])) { - $setterName = 'set' . ucfirst($this->hydrateName($property, $data)); - - $this->hydrationMethodsCache[$propertyFqn] = is_callable(array($object, $setterName)) - ? $setterName - : false; - } - - if ($this->hydrationMethodsCache[$propertyFqn]) { - $object->{$this->hydrationMethodsCache[$propertyFqn]}($this->hydrateValue($property, $value, $data)); - } - } - - return $object; - } - - /** - * {@inheritDoc} - */ - public function addFilter($name, $filter, $condition = FilterComposite::CONDITION_OR) - { - $this->resetCaches(); - - return parent::addFilter($name, $filter, $condition); - } - - /** - * {@inheritDoc} - */ - public function removeFilter($name) - { - $this->resetCaches(); - - return parent::removeFilter($name); - } - - /** - * {@inheritDoc} - */ - public function setNamingStrategy(NamingStrategyInterface $strategy) - { - $this->resetCaches(); - - return parent::setNamingStrategy($strategy); - } - - /** - * {@inheritDoc} - */ - public function removeNamingStrategy() - { - $this->resetCaches(); - - return parent::removeNamingStrategy(); - } - - /** - * Reset all local hydration/extraction caches - */ - private function resetCaches() - { - $this->hydrationMethodsCache = $this->extractionMethodsCache = array(); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/DelegatingHydrator.php b/vendor/zendframework/zend-stdlib/src/Hydrator/DelegatingHydrator.php deleted file mode 100644 index db234d3..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/DelegatingHydrator.php +++ /dev/null @@ -1,57 +0,0 @@ -hydrators = $hydrators; - } - - /** - * {@inheritdoc} - */ - public function hydrate(array $data, $object) - { - return $this->getHydrator($object)->hydrate($data, $object); - } - - /** - * {@inheritdoc} - */ - public function extract($object) - { - return $this->getHydrator($object)->extract($object); - } - - /** - * Gets hydrator of an object - * - * @param object $object - * @return HydratorInterface - */ - protected function getHydrator($object) - { - return $this->hydrators->get(get_class($object)); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/DelegatingHydratorFactory.php b/vendor/zendframework/zend-stdlib/src/Hydrator/DelegatingHydratorFactory.php deleted file mode 100644 index c3a0da2..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/DelegatingHydratorFactory.php +++ /dev/null @@ -1,29 +0,0 @@ -orFilter = new ArrayObject($orFilter); - $this->andFilter = new ArrayObject($andFilter); - } - - /** - * Add a filter to the composite. Has to be indexed with $name in - * order to identify a specific filter. - * - * This example will exclude all methods from the hydration, that starts with 'getService' - * - * $composite->addFilter('exclude', - * function ($method) { - * if (preg_match('/^getService/', $method) { - * return false; - * } - * return true; - * }, FilterComposite::CONDITION_AND - * ); - * - * - * @param string $name - * @param callable|FilterInterface $filter - * @param int $condition Can be either FilterComposite::CONDITION_OR or FilterComposite::CONDITION_AND - * @throws InvalidArgumentException - * @return FilterComposite - */ - public function addFilter($name, $filter, $condition = self::CONDITION_OR) - { - if (!is_callable($filter) && !($filter instanceof FilterInterface)) { - throw new InvalidArgumentException( - 'The value of ' . $name . ' should be either a callable or ' . - 'an instance of Zend\Stdlib\Hydrator\Filter\FilterInterface' - ); - } - - if ($condition === self::CONDITION_OR) { - $this->orFilter[$name] = $filter; - } elseif ($condition === self::CONDITION_AND) { - $this->andFilter[$name] = $filter; - } - - return $this; - } - - /** - * Remove a filter from the composition - * - * @param $name string Identifier for the filter - * @return FilterComposite - */ - public function removeFilter($name) - { - if (isset($this->orFilter[$name])) { - unset($this->orFilter[$name]); - } - - if (isset($this->andFilter[$name])) { - unset($this->andFilter[$name]); - } - - return $this; - } - - /** - * Check if $name has a filter registered - * - * @param $name string Identifier for the filter - * @return bool - */ - public function hasFilter($name) - { - return isset($this->orFilter[$name]) || isset($this->andFilter[$name]); - } - - /** - * Filter the composite based on the AND and OR condition - * Will return true if one from the "or conditions" and all from - * the "and condition" returns true. Otherwise false - * - * @param $property string Parameter will be e.g. Parent\Namespace\Class::method - * @return bool - */ - public function filter($property) - { - $andCount = count($this->andFilter); - $orCount = count($this->orFilter); - // return true if no filters are registered - if ($orCount === 0 && $andCount === 0) { - return true; - } elseif ($orCount === 0 && $andCount !== 0) { - $returnValue = true; - } else { - $returnValue = false; - } - - // Check if 1 from the or filters return true - foreach ($this->orFilter as $filter) { - if (is_callable($filter)) { - if ($filter($property) === true) { - $returnValue = true; - break; - } - continue; - } else { - if ($filter->filter($property) === true) { - $returnValue = true; - break; - } - } - } - - // Check if all of the and condition return true - foreach ($this->andFilter as $filter) { - if (is_callable($filter)) { - if ($filter($property) === false) { - return false; - } - continue; - } else { - if ($filter->filter($property) === false) { - return false; - } - } - } - - return $returnValue; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/FilterInterface.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/FilterInterface.php deleted file mode 100644 index 16df098..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/FilterInterface.php +++ /dev/null @@ -1,21 +0,0 @@ -method = $method; - $this->exclude = $exclude; - } - - public function filter($property) - { - $pos = strpos($property, '::'); - if ($pos !== false) { - $pos += 2; - } else { - $pos = 0; - } - if (substr($property, $pos) === $this->method) { - return !$this->exclude; - } - return $this->exclude; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/NumberOfParameterFilter.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/NumberOfParameterFilter.php deleted file mode 100644 index 1254b63..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/NumberOfParameterFilter.php +++ /dev/null @@ -1,49 +0,0 @@ -numberOfParameters = (int) $numberOfParameters; - } - - /** - * @param string $property the name of the property - * @return bool - * @throws InvalidArgumentException - */ - public function filter($property) - { - try { - $reflectionMethod = new ReflectionMethod($property); - } catch (ReflectionException $exception) { - throw new InvalidArgumentException( - "Method $property doesn't exist" - ); - } - - return $reflectionMethod->getNumberOfParameters() === $this->numberOfParameters; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/OptionalParametersFilter.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/OptionalParametersFilter.php deleted file mode 100644 index ccd67ca..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Filter/OptionalParametersFilter.php +++ /dev/null @@ -1,54 +0,0 @@ -getParameters(), - function (ReflectionParameter $parameter) { - return ! $parameter->isOptional(); - } - ); - - return static::$propertiesCache[$property] = empty($mandatoryParameters); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/FilterEnabledInterface.php b/vendor/zendframework/zend-stdlib/src/Hydrator/FilterEnabledInterface.php deleted file mode 100644 index 380aade..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/FilterEnabledInterface.php +++ /dev/null @@ -1,63 +0,0 @@ - - * $composite->addFilter( - * "servicelocator", - * function ($property) { - * list($class, $method) = explode('::', $property); - * if ($method === 'getServiceLocator') { - * return false; - * } - * return true; - * }, - * FilterComposite::CONDITION_AND - * ); - * - * - * @param string $name Index in the composite - * @param callable|FilterInterface $filter - * @param int $condition - * @return FilterComposite - */ - public function addFilter($name, $filter, $condition = FilterComposite::CONDITION_OR); - - /** - * Check whether a specific filter exists at key $name or not - * - * @param string $name Index in the composite - * @return bool - */ - public function hasFilter($name); - - /** - * Remove a filter from the composition. - * To not extract "has" methods, you simply need to unregister it - * - * - * $filterComposite->removeFilter('has'); - * - * - * @param $name - * @return FilterComposite - */ - public function removeFilter($name); -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/HydrationInterface.php b/vendor/zendframework/zend-stdlib/src/Hydrator/HydrationInterface.php deleted file mode 100644 index e7deff4..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/HydrationInterface.php +++ /dev/null @@ -1,22 +0,0 @@ -hydrator = $hydrator; - - return $this; - } - - /** - * Retrieve hydrator - * - * @param void - * @return null|HydratorInterface - * @access public - */ - public function getHydrator() - { - return $this->hydrator; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/HydratorInterface.php b/vendor/zendframework/zend-stdlib/src/Hydrator/HydratorInterface.php deleted file mode 100644 index bc9983d..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/HydratorInterface.php +++ /dev/null @@ -1,16 +0,0 @@ - 'Zend\Stdlib\Hydrator\DelegatingHydrator', - ); - - /** - * Default set of adapters - * - * @var array - */ - protected $invokableClasses = array( - 'arrayserializable' => 'Zend\Stdlib\Hydrator\ArraySerializable', - 'classmethods' => 'Zend\Stdlib\Hydrator\ClassMethods', - 'objectproperty' => 'Zend\Stdlib\Hydrator\ObjectProperty', - 'reflection' => 'Zend\Stdlib\Hydrator\Reflection' - ); - - /** - * Default factory-based adapters - * - * @var array - */ - protected $factories = array( - 'Zend\Stdlib\Hydrator\DelegatingHydrator' => 'Zend\Stdlib\Hydrator\DelegatingHydratorFactory', - ); - - /** - * {@inheritDoc} - */ - public function validatePlugin($plugin) - { - if ($plugin instanceof HydratorInterface) { - // we're okay - return; - } - - throw new Exception\RuntimeException(sprintf( - 'Plugin of type %s is invalid; must implement Zend\Stdlib\Hydrator\HydratorInterface', - (is_object($plugin) ? get_class($plugin) : gettype($plugin)) - )); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/ArrayMapNamingStrategy.php b/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/ArrayMapNamingStrategy.php deleted file mode 100644 index 962303a..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/ArrayMapNamingStrategy.php +++ /dev/null @@ -1,51 +0,0 @@ -extractionMap = $extractionMap; - $this->hydrationMap = array_flip($extractionMap); - } - - /** - * {@inheritDoc} - */ - public function hydrate($name) - { - return isset($this->hydrationMap[$name]) ? $this->hydrationMap[$name] : $name; - } - - /** - * {@inheritDoc} - */ - public function extract($name) - { - return isset($this->extractionMap[$name]) ? $this->extractionMap[$name] : $name; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/CompositeNamingStrategy.php b/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/CompositeNamingStrategy.php deleted file mode 100644 index 0887e92..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/CompositeNamingStrategy.php +++ /dev/null @@ -1,64 +0,0 @@ -namingStrategies = array_map( - function (NamingStrategyInterface $strategy) { - // this callback is here only to ensure type-safety - return $strategy; - }, - $strategies - ); - - $this->defaultNamingStrategy = $defaultNamingStrategy ?: new IdentityNamingStrategy(); - } - - /** - * {@inheritDoc} - */ - public function extract($name) - { - $strategy = isset($this->namingStrategies[$name]) - ? $this->namingStrategies[$name] - : $this->defaultNamingStrategy; - - return $strategy->extract($name); - } - - /** - * {@inheritDoc} - */ - public function hydrate($name) - { - $strategy = isset($this->namingStrategies[$name]) - ? $this->namingStrategies[$name] - : $this->defaultNamingStrategy; - - return $strategy->hydrate($name); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/IdentityNamingStrategy.php b/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/IdentityNamingStrategy.php deleted file mode 100644 index ee4b328..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/IdentityNamingStrategy.php +++ /dev/null @@ -1,29 +0,0 @@ -mapping = $mapping; - $this->reverse = $reverse ?: $this->flipMapping($mapping); - } - - /** - * Safelly flip mapping array. - * - * @param array $array Array to flip - * @return array Flipped array - * @throws InvalidArgumentException - */ - protected function flipMapping(array $array) - { - array_walk($array, function ($value) { - if (!is_string($value) && !is_int($value)) { - throw new InvalidArgumentException('Mapping array can\'t be flipped because of invalid value'); - } - }); - - return array_flip($array); - } - - /** - * Converts the given name so that it can be extracted by the hydrator. - * - * @param string $name The original name - * @return mixed The hydrated name - */ - public function hydrate($name) - { - if (array_key_exists($name, $this->mapping)) { - return $this->mapping[$name]; - } - - return $name; - } - - /** - * Converts the given name so that it can be hydrated by the hydrator. - * - * @param string $name The original name - * @return mixed The extracted name - */ - public function extract($name) - { - if (array_key_exists($name, $this->reverse)) { - return $this->reverse[$name]; - } - - return $name; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/NamingStrategyInterface.php b/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/NamingStrategyInterface.php deleted file mode 100644 index ff99385..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategy/NamingStrategyInterface.php +++ /dev/null @@ -1,37 +0,0 @@ -getUnderscoreToStudlyCaseFilter()->filter($name); - } - - /** - * Remove capitalized letters and prepend underscores. - * - * @param string $name - * @return string - */ - public function extract($name) - { - return $this->getCamelCaseToUnderscoreFilter()->filter($name); - } - - /** - * @return FilterChain - */ - protected function getUnderscoreToStudlyCaseFilter() - { - if (static::$underscoreToStudlyCaseFilter instanceof FilterChain) { - return static::$underscoreToStudlyCaseFilter; - } - - $filter = new FilterChain(); - - $filter->attachByName('WordUnderscoreToStudlyCase'); - - return static::$underscoreToStudlyCaseFilter = $filter; - } - - /** - * @return FilterChain - */ - protected function getCamelCaseToUnderscoreFilter() - { - if (static::$camelCaseToUnderscoreFilter instanceof FilterChain) { - return static::$camelCaseToUnderscoreFilter; - } - - $filter = new FilterChain(); - - $filter->attachByName('WordCamelCaseToUnderscore'); - $filter->attachByName('StringToLower'); - - return static::$camelCaseToUnderscoreFilter = $filter; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategyEnabledInterface.php b/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategyEnabledInterface.php deleted file mode 100644 index f9c6288..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/NamingStrategyEnabledInterface.php +++ /dev/null @@ -1,44 +0,0 @@ -getFilter(); - - foreach ($data as $name => $value) { - // Filter keys, removing any we don't want - if (! $filter->filter($name)) { - unset($data[$name]); - continue; - } - - // Replace name if extracted differ - $extracted = $this->extractName($name, $object); - - if ($extracted !== $name) { - unset($data[$name]); - $name = $extracted; - } - - $data[$name] = $this->extractValue($name, $value, $object); - } - - return $data; - } - - /** - * {@inheritDoc} - * - * Hydrate an object by populating public properties - * - * Hydrates an object by setting public properties of the object. - * - * @throws Exception\BadMethodCallException for a non-object $object - */ - public function hydrate(array $data, $object) - { - if (!is_object($object)) { - throw new Exception\BadMethodCallException( - sprintf('%s expects the provided $object to be a PHP object)', __METHOD__) - ); - } - - $properties = & self::$skippedPropertiesCache[get_class($object)]; - - if (! isset($properties)) { - $reflection = new ReflectionClass($object); - $properties = array_fill_keys( - array_map( - function (ReflectionProperty $property) { - return $property->getName(); - }, - $reflection->getProperties( - ReflectionProperty::IS_PRIVATE - + ReflectionProperty::IS_PROTECTED - + ReflectionProperty::IS_STATIC - ) - ), - true - ); - } - - foreach ($data as $name => $value) { - $property = $this->hydrateName($name, $data); - - if (isset($properties[$property])) { - continue; - } - - $object->$property = $this->hydrateValue($property, $value, $data); - } - - return $object; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Reflection.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Reflection.php deleted file mode 100644 index ea8e2d2..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Reflection.php +++ /dev/null @@ -1,95 +0,0 @@ -extractName($property->getName(), $object); - if (!$this->filterComposite->filter($propertyName)) { - continue; - } - - $value = $property->getValue($object); - $result[$propertyName] = $this->extractValue($propertyName, $value, $object); - } - - return $result; - } - - /** - * Hydrate $object with the provided $data. - * - * @param array $data - * @param object $object - * @return object - */ - public function hydrate(array $data, $object) - { - $reflProperties = self::getReflProperties($object); - foreach ($data as $key => $value) { - $name = $this->hydrateName($key, $data); - if (isset($reflProperties[$name])) { - $reflProperties[$name]->setValue($object, $this->hydrateValue($name, $value, $data)); - } - } - return $object; - } - - /** - * Get a reflection properties from in-memory cache and lazy-load if - * class has not been loaded. - * - * @param string|object $input - * @throws Exception\InvalidArgumentException - * @return \ReflectionProperty[] - */ - protected static function getReflProperties($input) - { - if (is_object($input)) { - $input = get_class($input); - } elseif (!is_string($input)) { - throw new Exception\InvalidArgumentException('Input must be a string or an object.'); - } - - if (isset(static::$reflProperties[$input])) { - return static::$reflProperties[$input]; - } - - static::$reflProperties[$input] = array(); - $reflClass = new ReflectionClass($input); - $reflProperties = $reflClass->getProperties(); - - foreach ($reflProperties as $property) { - $property->setAccessible(true); - static::$reflProperties[$input][$property->getName()] = $property; - } - - return static::$reflProperties[$input]; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/BooleanStrategy.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/BooleanStrategy.php deleted file mode 100644 index 3c29231..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/BooleanStrategy.php +++ /dev/null @@ -1,106 +0,0 @@ -trueValue = $trueValue; - $this->falseValue = $falseValue; - } - - /** - * Converts the given value so that it can be extracted by the hydrator. - * - * @param bool $value The original value. - * @throws InvalidArgumentException - * @return int|string Returns the value that should be extracted. - */ - public function extract($value) - { - if (!is_bool($value)) { - throw new InvalidArgumentException(sprintf( - 'Unable to extract. Expected bool. %s was given.', - is_object($value) ? get_class($value) : gettype($value) - )); - } - - return $value === true ? $this->trueValue : $this->falseValue; - } - - /** - * Converts the given value so that it can be hydrated by the hydrator. - * - * @param int|string $value The original value. - * @throws InvalidArgumentException - * @return bool Returns the value that should be hydrated. - */ - public function hydrate($value) - { - if (!is_string($value) && !is_int($value)) { - throw new InvalidArgumentException(sprintf( - 'Unable to hydrate. Expected string or int. %s was given.', - is_object($value) ? get_class($value) : gettype($value) - )); - } - - if ($value === $this->trueValue) { - return true; - } - - if ($value === $this->falseValue) { - return false; - } - - throw new InvalidArgumentException(sprintf( - 'Unexpected value %s can\'t be hydrated. Expect %s or %s as Value.', - $value, - $this->trueValue, - $this->falseValue - )); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/ClosureStrategy.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/ClosureStrategy.php deleted file mode 100644 index bf456a7..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/ClosureStrategy.php +++ /dev/null @@ -1,102 +0,0 @@ -addStrategy('category', new ClosureStrategy( - * function (Category $value) { - * return (int) $value->id; - * }, - * function ($value) { - * return new Category((int) $value); - * } - * )); - * - * @param callable $extractFunc - anonymous function, that extract values - * from object - * @param callable $hydrateFunc - anonymous function, that hydrate values - * into object - */ - public function __construct($extractFunc = null, $hydrateFunc = null) - { - if (isset($extractFunc)) { - if (!is_callable($extractFunc)) { - throw new \Exception('$extractFunc must be callable'); - } - - $this->extractFunc = $extractFunc; - } else { - $this->extractFunc = function ($value) { - return $value; - }; - } - - if (isset($hydrateFunc)) { - if (!is_callable($hydrateFunc)) { - throw new \Exception('$hydrateFunc must be callable'); - } - - $this->hydrateFunc = $hydrateFunc; - } else { - $this->hydrateFunc = function ($value) { - return $value; - }; - } - } - - /** - * Converts the given value so that it can be extracted by the hydrator. - * - * @param mixed $value The original value. - * @param array $object The object is optionally provided as context. - * @return mixed Returns the value that should be extracted. - */ - public function extract($value, $object = null) - { - $func = $this->extractFunc; - - return $func($value, $object); - } - - /** - * Converts the given value so that it can be hydrated by the hydrator. - * - * @param mixed $value The original value. - * @param array $data The whole data is optionally provided as context. - * @return mixed Returns the value that should be hydrated. - */ - public function hydrate($value, $data = null) - { - $func = $this->hydrateFunc; - - return $func($value, $data); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/DateTimeFormatterStrategy.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/DateTimeFormatterStrategy.php deleted file mode 100644 index 62d92c5..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/DateTimeFormatterStrategy.php +++ /dev/null @@ -1,80 +0,0 @@ -format = (string) $format; - $this->timezone = $timezone; - } - - /** - * {@inheritDoc} - * - * Converts to date time string - * - * @param mixed|DateTime $value - * - * @return mixed|string - */ - public function extract($value) - { - if ($value instanceof DateTime) { - return $value->format($this->format); - } - - return $value; - } - - /** - * Converts date time string to DateTime instance for injecting to object - * - * {@inheritDoc} - * - * @param mixed|string $value - * - * @return mixed|DateTime - */ - public function hydrate($value) - { - if ($value === '' || $value === null) { - return; - } - - if ($this->timezone) { - $hydrated = DateTime::createFromFormat($this->format, $value, $this->timezone); - } else { - $hydrated = DateTime::createFromFormat($this->format, $value); - } - - return $hydrated ?: $value; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/DefaultStrategy.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/DefaultStrategy.php deleted file mode 100644 index b2c5c29..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/DefaultStrategy.php +++ /dev/null @@ -1,35 +0,0 @@ -setValueDelimiter($delimiter); - - $this->explodeLimit = ($explodeLimit === null) ? null : (int) $explodeLimit; - } - - /** - * Sets the delimiter string that the values will be split upon - * - * @param string $delimiter - * @return self - */ - private function setValueDelimiter($delimiter) - { - if (!is_string($delimiter)) { - throw new Exception\InvalidArgumentException(sprintf( - '%s expects Delimiter to be string, %s provided instead', - __METHOD__, - is_object($delimiter) ? get_class($delimiter) : gettype($delimiter) - )); - } - - if (empty($delimiter)) { - throw new Exception\InvalidArgumentException('Delimiter cannot be empty.'); - } - - $this->valueDelimiter = $delimiter; - } - - /** - * {@inheritDoc} - * - * Split a string by delimiter - * - * @param string|null $value - * - * @return string[] - * - * @throws Exception\InvalidArgumentException - */ - public function hydrate($value) - { - if (null === $value) { - return array(); - } - - if (!(is_string($value) || is_numeric($value))) { - throw new Exception\InvalidArgumentException(sprintf( - '%s expects argument 1 to be string, %s provided instead', - __METHOD__, - is_object($value) ? get_class($value) : gettype($value) - )); - } - - if ($this->explodeLimit !== null) { - return explode($this->valueDelimiter, $value, $this->explodeLimit); - } - - return explode($this->valueDelimiter, $value); - } - - /** - * {@inheritDoc} - * - * Join array elements with delimiter - * - * @param string[] $value The original value. - * - * @return string|null - */ - public function extract($value) - { - if (!is_array($value)) { - throw new Exception\InvalidArgumentException(sprintf( - '%s expects argument 1 to be array, %s provided instead', - __METHOD__, - is_object($value) ? get_class($value) : gettype($value) - )); - } - - return empty($value) ? null : implode($this->valueDelimiter, $value); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/SerializableStrategy.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/SerializableStrategy.php deleted file mode 100644 index 260efa3..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/SerializableStrategy.php +++ /dev/null @@ -1,123 +0,0 @@ -setSerializer($serializer); - if ($serializerOptions) { - $this->setSerializerOptions($serializerOptions); - } - } - - /** - * Serialize the given value so that it can be extracted by the hydrator. - * - * @param mixed $value The original value. - * @return mixed Returns the value that should be extracted. - */ - public function extract($value) - { - $serializer = $this->getSerializer(); - return $serializer->serialize($value); - } - - /** - * Unserialize the given value so that it can be hydrated by the hydrator. - * - * @param mixed $value The original value. - * @return mixed Returns the value that should be hydrated. - */ - public function hydrate($value) - { - $serializer = $this->getSerializer(); - return $serializer->unserialize($value); - } - - /** - * Set serializer - * - * @param string|SerializerAdapter $serializer - * @return SerializableStrategy - */ - public function setSerializer($serializer) - { - if (!is_string($serializer) && !$serializer instanceof SerializerAdapter) { - throw new InvalidArgumentException(sprintf( - '%s expects either a string serializer name or Zend\Serializer\Adapter\AdapterInterface instance; ' - . 'received "%s"', - __METHOD__, - (is_object($serializer) ? get_class($serializer) : gettype($serializer)) - )); - } - $this->serializer = $serializer; - return $this; - } - - /** - * Get serializer - * - * @return SerializerAdapter - */ - public function getSerializer() - { - if (is_string($this->serializer)) { - $options = $this->getSerializerOptions(); - $this->setSerializer(SerializerFactory::factory($this->serializer, $options)); - } elseif (null === $this->serializer) { - $this->setSerializer(SerializerFactory::getDefaultAdapter()); - } - - return $this->serializer; - } - - /** - * Set configuration options for instantiating a serializer adapter - * - * @param mixed $serializerOptions - * @return SerializableStrategy - */ - public function setSerializerOptions($serializerOptions) - { - $this->serializerOptions = $serializerOptions; - return $this; - } - - /** - * Get configuration options for instantiating a serializer adapter - * - * @return mixed - */ - public function getSerializerOptions() - { - return $this->serializerOptions; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/StrategyChain.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/StrategyChain.php deleted file mode 100644 index a9316bb..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/StrategyChain.php +++ /dev/null @@ -1,73 +0,0 @@ -extractionStrategies = array_map( - function (StrategyInterface $strategy) { - // this callback is here only to ensure type-safety - return $strategy; - }, - $extractionStrategies - ); - - $this->hydrationStrategies = array_reverse($extractionStrategies); - } - - /** - * {@inheritDoc} - */ - public function extract($value) - { - foreach ($this->extractionStrategies as $strategy) { - $value = $strategy->extract($value); - } - - return $value; - } - - /** - * {@inheritDoc} - */ - public function hydrate($value) - { - foreach ($this->hydrationStrategies as $strategy) { - $value = $strategy->hydrate($value); - } - - return $value; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/StrategyInterface.php b/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/StrategyInterface.php deleted file mode 100644 index 562ec4b..0000000 --- a/vendor/zendframework/zend-stdlib/src/Hydrator/Strategy/StrategyInterface.php +++ /dev/null @@ -1,34 +0,0 @@ -metadata[$spec] = $value; - return $this; - } - if (!is_array($spec) && !$spec instanceof Traversable) { - throw new Exception\InvalidArgumentException(sprintf( - 'Expected a string, array, or Traversable argument in first position; received "%s"', - (is_object($spec) ? get_class($spec) : gettype($spec)) - )); - } - foreach ($spec as $key => $value) { - $this->metadata[$key] = $value; - } - return $this; - } - - /** - * Retrieve all metadata or a single metadatum as specified by key - * - * @param null|string|int $key - * @param null|mixed $default - * @throws Exception\InvalidArgumentException - * @return mixed - */ - public function getMetadata($key = null, $default = null) - { - if (null === $key) { - return $this->metadata; - } - - if (!is_scalar($key)) { - throw new Exception\InvalidArgumentException('Non-scalar argument provided for key'); - } - - if (array_key_exists($key, $this->metadata)) { - return $this->metadata[$key]; - } - - return $default; - } - - /** - * Set message content - * - * @param mixed $value - * @return Message - */ - public function setContent($value) - { - $this->content = $value; - return $this; - } - - /** - * Get message content - * - * @return mixed - */ - public function getContent() - { - return $this->content; - } - - /** - * @return string - */ - public function toString() - { - $request = ''; - foreach ($this->getMetadata() as $key => $value) { - $request .= sprintf( - "%s: %s\r\n", - (string) $key, - (string) $value - ); - } - $request .= "\r\n" . $this->getContent(); - return $request; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/MessageInterface.php b/vendor/zendframework/zend-stdlib/src/MessageInterface.php deleted file mode 100644 index 28d8857..0000000 --- a/vendor/zendframework/zend-stdlib/src/MessageInterface.php +++ /dev/null @@ -1,44 +0,0 @@ -exchangeArray($values); - } - - /** - * Populate from query string - * - * @param string $string - * @return void - */ - public function fromString($string) - { - $array = array(); - parse_str($string, $array); - $this->fromArray($array); - } - - /** - * Serialize to native PHP array - * - * @return array - */ - public function toArray() - { - return $this->getArrayCopy(); - } - - /** - * Serialize to query string - * - * @return string - */ - public function toString() - { - return http_build_query($this); - } - - /** - * Retrieve by key - * - * Returns null if the key does not exist. - * - * @param string $name - * @return mixed - */ - public function offsetGet($name) - { - if ($this->offsetExists($name)) { - return parent::offsetGet($name); - } - return; - } - - /** - * @param string $name - * @param mixed $default optional default value - * @return mixed - */ - public function get($name, $default = null) - { - if ($this->offsetExists($name)) { - return parent::offsetGet($name); - } - return $default; - } - - /** - * @param string $name - * @param mixed $value - * @return Parameters - */ - public function set($name, $value) - { - $this[$name] = $value; - return $this; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/ParametersInterface.php b/vendor/zendframework/zend-stdlib/src/ParametersInterface.php deleted file mode 100644 index feeda58..0000000 --- a/vendor/zendframework/zend-stdlib/src/ParametersInterface.php +++ /dev/null @@ -1,86 +0,0 @@ -sorted = false; - $this->count++; - - $this->items[$name] = array( - 'data' => $value, - 'priority' => (int) $priority, - 'serial' => $this->serial++, - ); - } - - /** - * @param string $name - * @param int $priority - * - * @return $this - * - * @throws \Exception - */ - public function setPriority($name, $priority) - { - if (!isset($this->items[$name])) { - throw new \Exception("item $name not found"); - } - - $this->items[$name]['priority'] = (int) $priority; - $this->sorted = false; - - return $this; - } - - /** - * Remove a item. - * - * @param string $name - * @return void - */ - public function remove($name) - { - if (isset($this->items[$name])) { - $this->count--; - } - - unset($this->items[$name]); - } - - /** - * Remove all items. - * - * @return void - */ - public function clear() - { - $this->items = array(); - $this->serial = 0; - $this->count = 0; - $this->sorted = false; - } - - /** - * Get a item. - * - * @param string $name - * @return mixed - */ - public function get($name) - { - if (!isset($this->items[$name])) { - return; - } - - return $this->items[$name]['data']; - } - - /** - * Sort all items. - * - * @return void - */ - protected function sort() - { - if (!$this->sorted) { - uasort($this->items, array($this, 'compare')); - $this->sorted = true; - } - } - - /** - * Compare the priority of two items. - * - * @param array $item1, - * @param array $item2 - * @return int - */ - protected function compare(array $item1, array $item2) - { - return ($item1['priority'] === $item2['priority']) - ? ($item1['serial'] > $item2['serial'] ? -1 : 1) * $this->isLIFO - : ($item1['priority'] > $item2['priority'] ? -1 : 1); - } - - /** - * Get/Set serial order mode - * - * @param bool|null $flag - * - * @return bool - */ - public function isLIFO($flag = null) - { - if ($flag !== null) { - $isLifo = $flag === true ? 1 : -1; - - if ($isLifo !== $this->isLIFO) { - $this->isLIFO = $isLifo; - $this->sorted = false; - } - } - - return 1 === $this->isLIFO; - } - - /** - * {@inheritDoc} - */ - public function rewind() - { - $this->sort(); - reset($this->items); - } - - /** - * {@inheritDoc} - */ - public function current() - { - $this->sorted || $this->sort(); - $node = current($this->items); - - return $node ? $node['data'] : false; - } - - /** - * {@inheritDoc} - */ - public function key() - { - $this->sorted || $this->sort(); - return key($this->items); - } - - /** - * {@inheritDoc} - */ - public function next() - { - $node = next($this->items); - - return $node ? $node['data'] : false; - } - - /** - * {@inheritDoc} - */ - public function valid() - { - return current($this->items) !== false; - } - - /** - * @return self - */ - public function getIterator() - { - return clone $this; - } - - /** - * {@inheritDoc} - */ - public function count() - { - return $this->count; - } - - /** - * Return list as array - * - * @param int $flag - * - * @return array - */ - public function toArray($flag = self::EXTR_DATA) - { - $this->sort(); - - if ($flag == self::EXTR_BOTH) { - return $this->items; - } - - return array_map( - function ($item) use ($flag) { - return ($flag == PriorityList::EXTR_PRIORITY) ? $item['priority'] : $item['data']; - }, - $this->items - ); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/PriorityQueue.php b/vendor/zendframework/zend-stdlib/src/PriorityQueue.php deleted file mode 100644 index 1baf44e..0000000 --- a/vendor/zendframework/zend-stdlib/src/PriorityQueue.php +++ /dev/null @@ -1,301 +0,0 @@ -items[] = array( - 'data' => $data, - 'priority' => $priority, - ); - $this->getQueue()->insert($data, $priority); - return $this; - } - - /** - * Remove an item from the queue - * - * This is different than {@link extract()}; its purpose is to dequeue an - * item. - * - * This operation is potentially expensive, as it requires - * re-initialization and re-population of the inner queue. - * - * Note: this removes the first item matching the provided item found. If - * the same item has been added multiple times, it will not remove other - * instances. - * - * @param mixed $datum - * @return bool False if the item was not found, true otherwise. - */ - public function remove($datum) - { - $found = false; - foreach ($this->items as $key => $item) { - if ($item['data'] === $datum) { - $found = true; - break; - } - } - if ($found) { - unset($this->items[$key]); - $this->queue = null; - - if (!$this->isEmpty()) { - $queue = $this->getQueue(); - foreach ($this->items as $item) { - $queue->insert($item['data'], $item['priority']); - } - } - return true; - } - return false; - } - - /** - * Is the queue empty? - * - * @return bool - */ - public function isEmpty() - { - return (0 === $this->count()); - } - - /** - * How many items are in the queue? - * - * @return int - */ - public function count() - { - return count($this->items); - } - - /** - * Peek at the top node in the queue, based on priority. - * - * @return mixed - */ - public function top() - { - return $this->getIterator()->top(); - } - - /** - * Extract a node from the inner queue and sift up - * - * @return mixed - */ - public function extract() - { - return $this->getQueue()->extract(); - } - - /** - * Retrieve the inner iterator - * - * SplPriorityQueue acts as a heap, which typically implies that as items - * are iterated, they are also removed. This does not work for situations - * where the queue may be iterated multiple times. As such, this class - * aggregates the values, and also injects an SplPriorityQueue. This method - * retrieves the inner queue object, and clones it for purposes of - * iteration. - * - * @return SplPriorityQueue - */ - public function getIterator() - { - $queue = $this->getQueue(); - return clone $queue; - } - - /** - * Serialize the data structure - * - * @return string - */ - public function serialize() - { - return serialize($this->items); - } - - /** - * Unserialize a string into a PriorityQueue object - * - * Serialization format is compatible with {@link Zend\Stdlib\SplPriorityQueue} - * - * @param string $data - * @return void - */ - public function unserialize($data) - { - foreach (unserialize($data) as $item) { - $this->insert($item['data'], $item['priority']); - } - } - - /** - * Serialize to an array - * - * By default, returns only the item data, and in the order registered (not - * sorted). You may provide one of the EXTR_* flags as an argument, allowing - * the ability to return priorities or both data and priority. - * - * @param int $flag - * @return array - */ - public function toArray($flag = self::EXTR_DATA) - { - switch ($flag) { - case self::EXTR_BOTH: - return $this->items; - case self::EXTR_PRIORITY: - return array_map(function ($item) { - return $item['priority']; - }, $this->items); - case self::EXTR_DATA: - default: - return array_map(function ($item) { - return $item['data']; - }, $this->items); - } - } - - /** - * Specify the internal queue class - * - * Please see {@link getIterator()} for details on the necessity of an - * internal queue class. The class provided should extend SplPriorityQueue. - * - * @param string $class - * @return PriorityQueue - */ - public function setInternalQueueClass($class) - { - $this->queueClass = (string) $class; - return $this; - } - - /** - * Does the queue contain the given datum? - * - * @param mixed $datum - * @return bool - */ - public function contains($datum) - { - foreach ($this->items as $item) { - if ($item['data'] === $datum) { - return true; - } - } - return false; - } - - /** - * Does the queue have an item with the given priority? - * - * @param int $priority - * @return bool - */ - public function hasPriority($priority) - { - foreach ($this->items as $item) { - if ($item['priority'] === $priority) { - return true; - } - } - return false; - } - - /** - * Get the inner priority queue instance - * - * @throws Exception\DomainException - * @return SplPriorityQueue - */ - protected function getQueue() - { - if (null === $this->queue) { - $this->queue = new $this->queueClass(); - if (!$this->queue instanceof \SplPriorityQueue) { - throw new Exception\DomainException(sprintf( - 'PriorityQueue expects an internal queue of type SplPriorityQueue; received "%s"', - get_class($this->queue) - )); - } - } - return $this->queue; - } - - /** - * Add support for deep cloning - * - * @return void - */ - public function __clone() - { - if (null !== $this->queue) { - $this->queue = clone $this->queue; - } - } -} diff --git a/vendor/zendframework/zend-stdlib/src/Request.php b/vendor/zendframework/zend-stdlib/src/Request.php deleted file mode 100644 index 7c08403..0000000 --- a/vendor/zendframework/zend-stdlib/src/Request.php +++ /dev/null @@ -1,15 +0,0 @@ -serial--); - } - parent::insert($datum, $priority); - } - - /** - * Serialize to an array - * - * Array will be priority => data pairs - * - * @return array - */ - public function toArray() - { - $array = array(); - foreach (clone $this as $item) { - $array[] = $item; - } - return $array; - } - - /** - * Serialize - * - * @return string - */ - public function serialize() - { - $clone = clone $this; - $clone->setExtractFlags(self::EXTR_BOTH); - - $data = array(); - foreach ($clone as $item) { - $data[] = $item; - } - - return serialize($data); - } - - /** - * Deserialize - * - * @param string $data - * @return void - */ - public function unserialize($data) - { - foreach (unserialize($data) as $item) { - $this->insert($item['data'], $item['priority']); - } - } -} diff --git a/vendor/zendframework/zend-stdlib/src/SplQueue.php b/vendor/zendframework/zend-stdlib/src/SplQueue.php deleted file mode 100644 index 029bc9f..0000000 --- a/vendor/zendframework/zend-stdlib/src/SplQueue.php +++ /dev/null @@ -1,55 +0,0 @@ -toArray()); - } - - /** - * Unserialize - * - * @param string $data - * @return void - */ - public function unserialize($data) - { - foreach (unserialize($data) as $item) { - $this->push($item); - } - } -} diff --git a/vendor/zendframework/zend-stdlib/src/SplStack.php b/vendor/zendframework/zend-stdlib/src/SplStack.php deleted file mode 100644 index fac77a5..0000000 --- a/vendor/zendframework/zend-stdlib/src/SplStack.php +++ /dev/null @@ -1,55 +0,0 @@ -toArray()); - } - - /** - * Unserialize - * - * @param string $data - * @return void - */ - public function unserialize($data) - { - foreach (unserialize($data) as $item) { - $this->unshift($item); - } - } -} diff --git a/vendor/zendframework/zend-stdlib/src/StringUtils.php b/vendor/zendframework/zend-stdlib/src/StringUtils.php deleted file mode 100644 index 9bbb4a4..0000000 --- a/vendor/zendframework/zend-stdlib/src/StringUtils.php +++ /dev/null @@ -1,187 +0,0 @@ -setEncoding($encoding, $convertEncoding); - return $wrapper; - } - } - - throw new Exception\RuntimeException( - 'No wrapper found supporting "' . $encoding . '"' - . (($convertEncoding !== null) ? ' and "' . $convertEncoding . '"' : '') - ); - } - - /** - * Get a list of all known single-byte character encodings - * - * @return string[] - */ - public static function getSingleByteEncodings() - { - return static::$singleByteEncodings; - } - - /** - * Check if a given encoding is a known single-byte character encoding - * - * @param string $encoding - * @return bool - */ - public static function isSingleByteEncoding($encoding) - { - return in_array(strtoupper($encoding), static::$singleByteEncodings); - } - - /** - * Check if a given string is valid UTF-8 encoded - * - * @param string $str - * @return bool - */ - public static function isValidUtf8($str) - { - return is_string($str) && ($str === '' || preg_match('/^./su', $str) == 1); - } - - /** - * Is PCRE compiled with Unicode support? - * - * @return bool - */ - public static function hasPcreUnicodeSupport() - { - if (static::$hasPcreUnicodeSupport === null) { - ErrorHandler::start(); - static::$hasPcreUnicodeSupport = defined('PREG_BAD_UTF8_OFFSET_ERROR') && preg_match('/\pL/u', 'a') == 1; - ErrorHandler::stop(); - } - return static::$hasPcreUnicodeSupport; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/StringWrapper/AbstractStringWrapper.php b/vendor/zendframework/zend-stdlib/src/StringWrapper/AbstractStringWrapper.php deleted file mode 100644 index 3e395cc..0000000 --- a/vendor/zendframework/zend-stdlib/src/StringWrapper/AbstractStringWrapper.php +++ /dev/null @@ -1,269 +0,0 @@ -convertEncoding = $convertEncodingUpper; - } else { - $this->convertEncoding = null; - } - $this->encoding = $encodingUpper; - - return $this; - } - - /** - * Get the defined character encoding to work with - * - * @return string - * @throws Exception\LogicException If no encoding was defined - */ - public function getEncoding() - { - return $this->encoding; - } - - /** - * Get the defined character encoding to convert to - * - * @return string|null - */ - public function getConvertEncoding() - { - return $this->convertEncoding; - } - - /** - * Convert a string from defined character encoding to the defined convert encoding - * - * @param string $str - * @param bool $reverse - * @return string|false - */ - public function convert($str, $reverse = false) - { - $encoding = $this->getEncoding(); - $convertEncoding = $this->getConvertEncoding(); - if ($convertEncoding === null) { - throw new Exception\LogicException( - 'No convert encoding defined' - ); - } - - if ($encoding === $convertEncoding) { - return $str; - } - - $from = $reverse ? $convertEncoding : $encoding; - $to = $reverse ? $encoding : $convertEncoding; - throw new Exception\RuntimeException(sprintf( - 'Converting from "%s" to "%s" isn\'t supported by this string wrapper', - $from, - $to - )); - } - - /** - * Wraps a string to a given number of characters - * - * @param string $string - * @param int $width - * @param string $break - * @param bool $cut - * @return string|false - */ - public function wordWrap($string, $width = 75, $break = "\n", $cut = false) - { - $string = (string) $string; - if ($string === '') { - return ''; - } - - $break = (string) $break; - if ($break === '') { - throw new Exception\InvalidArgumentException('Break string cannot be empty'); - } - - $width = (int) $width; - if ($width === 0 && $cut) { - throw new Exception\InvalidArgumentException('Cannot force cut when width is zero'); - } - - if (StringUtils::isSingleByteEncoding($this->getEncoding())) { - return wordwrap($string, $width, $break, $cut); - } - - $stringWidth = $this->strlen($string); - $breakWidth = $this->strlen($break); - - $result = ''; - $lastStart = $lastSpace = 0; - - for ($current = 0; $current < $stringWidth; $current++) { - $char = $this->substr($string, $current, 1); - - $possibleBreak = $char; - if ($breakWidth !== 1) { - $possibleBreak = $this->substr($string, $current, $breakWidth); - } - - if ($possibleBreak === $break) { - $result .= $this->substr($string, $lastStart, $current - $lastStart + $breakWidth); - $current += $breakWidth - 1; - $lastStart = $lastSpace = $current + 1; - continue; - } - - if ($char === ' ') { - if ($current - $lastStart >= $width) { - $result .= $this->substr($string, $lastStart, $current - $lastStart) . $break; - $lastStart = $current + 1; - } - - $lastSpace = $current; - continue; - } - - if ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) { - $result .= $this->substr($string, $lastStart, $current - $lastStart) . $break; - $lastStart = $lastSpace = $current; - continue; - } - - if ($current - $lastStart >= $width && $lastStart < $lastSpace) { - $result .= $this->substr($string, $lastStart, $lastSpace - $lastStart) . $break; - $lastStart = $lastSpace = $lastSpace + 1; - continue; - } - } - - if ($lastStart !== $current) { - $result .= $this->substr($string, $lastStart, $current - $lastStart); - } - - return $result; - } - - /** - * Pad a string to a certain length with another string - * - * @param string $input - * @param int $padLength - * @param string $padString - * @param int $padType - * @return string - */ - public function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT) - { - if (StringUtils::isSingleByteEncoding($this->getEncoding())) { - return str_pad($input, $padLength, $padString, $padType); - } - - $lengthOfPadding = $padLength - $this->strlen($input); - if ($lengthOfPadding <= 0) { - return $input; - } - - $padStringLength = $this->strlen($padString); - if ($padStringLength === 0) { - return $input; - } - - $repeatCount = floor($lengthOfPadding / $padStringLength); - - if ($padType === STR_PAD_BOTH) { - $repeatCountLeft = $repeatCountRight = ($repeatCount - $repeatCount % 2) / 2; - - $lastStringLength = $lengthOfPadding - 2 * $repeatCountLeft * $padStringLength; - $lastStringLeftLength = $lastStringRightLength = floor($lastStringLength / 2); - $lastStringRightLength += $lastStringLength % 2; - - $lastStringLeft = $this->substr($padString, 0, $lastStringLeftLength); - $lastStringRight = $this->substr($padString, 0, $lastStringRightLength); - - return str_repeat($padString, $repeatCountLeft) . $lastStringLeft - . $input - . str_repeat($padString, $repeatCountRight) . $lastStringRight; - } - - $lastString = $this->substr($padString, 0, $lengthOfPadding % $padStringLength); - - if ($padType === STR_PAD_LEFT) { - return str_repeat($padString, $repeatCount) . $lastString . $input; - } - - return $input . str_repeat($padString, $repeatCount) . $lastString; - } -} diff --git a/vendor/zendframework/zend-stdlib/src/StringWrapper/Iconv.php b/vendor/zendframework/zend-stdlib/src/StringWrapper/Iconv.php deleted file mode 100644 index 04930ff..0000000 --- a/vendor/zendframework/zend-stdlib/src/StringWrapper/Iconv.php +++ /dev/null @@ -1,289 +0,0 @@ -getEncoding()); - } - - /** - * Returns the portion of string specified by the start and length parameters - * - * @param string $str - * @param int $offset - * @param int|null $length - * @return string|false - */ - public function substr($str, $offset = 0, $length = null) - { - return iconv_substr($str, $offset, $length, $this->getEncoding()); - } - - /** - * Find the position of the first occurrence of a substring in a string - * - * @param string $haystack - * @param string $needle - * @param int $offset - * @return int|false - */ - public function strpos($haystack, $needle, $offset = 0) - { - return iconv_strpos($haystack, $needle, $offset, $this->getEncoding()); - } - - /** - * Convert a string from defined encoding to the defined convert encoding - * - * @param string $str - * @param bool $reverse - * @return string|false - */ - public function convert($str, $reverse = false) - { - $encoding = $this->getEncoding(); - $convertEncoding = $this->getConvertEncoding(); - if ($convertEncoding === null) { - throw new Exception\LogicException( - 'No convert encoding defined' - ); - } - - if ($encoding === $convertEncoding) { - return $str; - } - - $fromEncoding = $reverse ? $convertEncoding : $encoding; - $toEncoding = $reverse ? $encoding : $convertEncoding; - - // automatically add "//IGNORE" to not stop converting on invalid characters - // invalid characters triggers a notice anyway - return iconv($fromEncoding, $toEncoding . '//IGNORE', $str); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/StringWrapper/Intl.php b/vendor/zendframework/zend-stdlib/src/StringWrapper/Intl.php deleted file mode 100644 index 1b01277..0000000 --- a/vendor/zendframework/zend-stdlib/src/StringWrapper/Intl.php +++ /dev/null @@ -1,88 +0,0 @@ -getEncoding()); - } - - /** - * Returns the portion of string specified by the start and length parameters - * - * @param string $str - * @param int $offset - * @param int|null $length - * @return string|false - */ - public function substr($str, $offset = 0, $length = null) - { - return mb_substr($str, $offset, $length, $this->getEncoding()); - } - - /** - * Find the position of the first occurrence of a substring in a string - * - * @param string $haystack - * @param string $needle - * @param int $offset - * @return int|false - */ - public function strpos($haystack, $needle, $offset = 0) - { - return mb_strpos($haystack, $needle, $offset, $this->getEncoding()); - } - - /** - * Convert a string from defined encoding to the defined convert encoding - * - * @param string $str - * @param bool $reverse - * @return string|false - */ - public function convert($str, $reverse = false) - { - $encoding = $this->getEncoding(); - $convertEncoding = $this->getConvertEncoding(); - - if ($convertEncoding === null) { - throw new Exception\LogicException( - 'No convert encoding defined' - ); - } - - if ($encoding === $convertEncoding) { - return $str; - } - - $fromEncoding = $reverse ? $convertEncoding : $encoding; - $toEncoding = $reverse ? $encoding : $convertEncoding; - return mb_convert_encoding($str, $toEncoding, $fromEncoding); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/StringWrapper/Native.php b/vendor/zendframework/zend-stdlib/src/StringWrapper/Native.php deleted file mode 100644 index 38b3c10..0000000 --- a/vendor/zendframework/zend-stdlib/src/StringWrapper/Native.php +++ /dev/null @@ -1,134 +0,0 @@ -convertEncoding = $encodingUpper; - } - - if ($convertEncoding !== null) { - if ($encodingUpper !== strtoupper($convertEncoding)) { - throw new Exception\InvalidArgumentException( - 'Wrapper doesn\'t support to convert between character encodings' - ); - } - - $this->convertEncoding = $encodingUpper; - } else { - $this->convertEncoding = null; - } - $this->encoding = $encodingUpper; - - return $this; - } - - /** - * Returns the length of the given string - * - * @param string $str - * @return int|false - */ - public function strlen($str) - { - return strlen($str); - } - - /** - * Returns the portion of string specified by the start and length parameters - * - * @param string $str - * @param int $offset - * @param int|null $length - * @return string|false - */ - public function substr($str, $offset = 0, $length = null) - { - return substr($str, $offset, $length); - } - - /** - * Find the position of the first occurrence of a substring in a string - * - * @param string $haystack - * @param string $needle - * @param int $offset - * @return int|false - */ - public function strpos($haystack, $needle, $offset = 0) - { - return strpos($haystack, $needle, $offset); - } -} diff --git a/vendor/zendframework/zend-stdlib/src/StringWrapper/StringWrapperInterface.php b/vendor/zendframework/zend-stdlib/src/StringWrapper/StringWrapperInterface.php deleted file mode 100644 index f25b325..0000000 --- a/vendor/zendframework/zend-stdlib/src/StringWrapper/StringWrapperInterface.php +++ /dev/null @@ -1,111 +0,0 @@ -

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 diff --git a/images/avatars/gallery/Civils_F/Civil_F_29.png b/images/avatars/gallery/Civils_F/Civil_F_29.png deleted file mode 100644 index fb483b1c3faa8263f497b4d1d78bab56f0ead887..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31705 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 diff --git a/images/avatars/gallery/Civils_F/Civil_F_30.png b/images/avatars/gallery/Civils_F/Civil_F_30.png deleted file mode 100644 index 5337b644dc85c552f79f45f002464d88b09fdc41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36515 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 z 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 VxCAwp@g@KO002ovPDHLkV1kO}a1Q_g diff --git a/images/avatars/gallery/Civils_F/Civil_F_7.png b/images/avatars/gallery/Civils_F/Civil_F_7.png deleted file mode 100644 index f12b85c88b88993fddd039f59944f01aa891c444..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22962 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 diff --git a/images/avatars/gallery/Civils_F/Civil_F_8.png b/images/avatars/gallery/Civils_F/Civil_F_8.png deleted file mode 100644 index b6a76d30079e31f959e53e59d36d5744f664b33b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26070 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 diff --git a/images/avatars/gallery/Civils_F/Civil_F_9.png b/images/avatars/gallery/Civils_F/Civil_F_9.png deleted file mode 100644 index 0f2a6c1f4a99fbdc2f77b4ff271302138d8a0d84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24651 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 z≺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 QMgRZ+07*qoM6N<$f}FfPDgXcg diff --git a/images/avatars/gallery/Civils_H/Civil_H_10.png b/images/avatars/gallery/Civils_H/Civil_H_10.png deleted file mode 100644 index be2d8967219a1c88be53770c40ef47d5988001b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29858 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 D1C|5# diff --git a/images/avatars/gallery/Civils_H/Civil_H_11.png b/images/avatars/gallery/Civils_H/Civil_H_11.png deleted file mode 100644 index ce324e33421771140545bbe9f3da1807ec643064..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30178 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 bgR=hzeI8v;eJ@)l00000NkvXXu0mjf&uKZ= diff --git a/images/avatars/gallery/Civils_H/Civil_H_12.png b/images/avatars/gallery/Civils_H/Civil_H_12.png deleted file mode 100644 index 7aca8bfc4e184872a8533ede3bd871eb7c07f48d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29944 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_13.png b/images/avatars/gallery/Civils_H/Civil_H_13.png deleted file mode 100644 index 85b30df19adf61f1e88a14f8b3f88ae542bdeee8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28112 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_14.png b/images/avatars/gallery/Civils_H/Civil_H_14.png deleted file mode 100644 index 6c4a6691cfe85d47bf27ea00c065c21ea81d936d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30359 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%0AUzO9v8vvz|A0D4hBurwHwbrLy_R~Se##w;uj&O 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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_17.png b/images/avatars/gallery/Civils_H/Civil_H_17.png deleted file mode 100644 index 5e9dcce3af9b190a6f8621545a96a872874f5eab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29710 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�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 diff --git a/images/avatars/gallery/Civils_H/Civil_H_18.png b/images/avatars/gallery/Civils_H/Civil_H_18.png deleted file mode 100644 index d79d375c7ae6c92dc4a48e7334e7e80c3e866b40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26073 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¯V`zE*)Q@lR({Tu!< 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